summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi16
-rw-r--r--guix/scripts/build.scm85
-rw-r--r--tests/scripts-build.scm29
3 files changed, 94 insertions, 36 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 94d4d8f92d..4e83c76be7 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -5430,14 +5430,20 @@ without having to type in the definitions of package variants
 @table @code
 
 @item --with-source=@var{source}
-Use @var{source} as the source of the corresponding package.
+@itemx --with-source=@var{package}=@var{source}
+@itemx --with-source=@var{package}@@@var{version}=@var{source}
+Use @var{source} as the source of @var{package}, and @var{version} as
+its version number.
 @var{source} must be a file name or a URL, as for @command{guix
 download} (@pxref{Invoking guix download}).
 
-The ``corresponding package'' is taken to be the one specified on the
-command line the name of which matches the base of @var{source}---e.g.,
+When @var{package} is omitted,
+it is taken to be the package name specified on the
+command line that matches the base of @var{source}---e.g.,
 if @var{source} is @code{/src/guile-2.0.10.tar.gz}, the corresponding
-package is @code{guile}.  Likewise, the version string is inferred from
+package is @code{guile}.
+
+Likewise, when @var{version} is omitted, the version string is inferred from
 @var{source}; in the previous example, it is @code{2.0.10}.
 
 This option allows users to try out versions of packages other than the
@@ -5460,7 +5466,7 @@ guix build guile --with-source=../guile-2.0.9.219-e1bb7.tar.xz
 
 @example
 $ git clone git://git.sv.gnu.org/guix.git
-$ guix build guix --with-source=./guix
+$ guix build guix --with-source=guix@@1.0=./guix
 @end example
 
 @item --with-input=@var{package}=@var{replacement}
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 0571b874f1..57f2d82c5c 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -25,9 +25,12 @@
   #:use-module (guix packages)
   #:use-module (guix grafts)
 
+  #:use-module (guix utils)
+
   ;; Use the procedure that destructures "NAME-VERSION" forms.
-  #:use-module ((guix utils) #:hide (package-name->name+version))
-  #:use-module ((guix build utils) #:select (package-name->name+version))
+  #:use-module ((guix build utils)
+                #:select ((package-name->name+version
+                           . hyphen-package-name->name+version)))
 
   #:use-module (guix monads)
   #:use-module (guix gexp)
@@ -127,33 +130,37 @@ found.  Return #f if no build log was found."
 (define register-root*
   (store-lift register-root))
 
-(define (package-with-source store p uri)
+(define (numeric-extension? file-name)
+  "Return true if FILE-NAME ends with digits."
+  (string-every char-set:hex-digit (file-extension file-name)))
+
+(define (tarball-base-name file-name)
+  "Return the \"base\" of FILE-NAME, removing '.tar.gz' or similar
+extensions."
+  ;; TODO: Factorize.
+  (cond ((not (file-extension file-name))
+         file-name)
+        ((numeric-extension? file-name)
+         file-name)
+        ((string=? (file-extension file-name) "tar")
+         (file-sans-extension file-name))
+        ((file-extension file-name)
+         =>
+         (match-lambda
+           ("scm" file-name)
+           (else  (tarball-base-name (file-sans-extension file-name)))))
+        (else
+         file-name)))
+
+(define* (package-with-source store p uri #:optional version)
   "Return a package based on P but with its source taken from URI.  Extract
 the new package's version number from URI."
-  (define (numeric-extension? file-name)
-    ;; Return true if FILE-NAME ends with digits.
-    (string-every char-set:hex-digit (file-extension file-name)))
-
-  (define (tarball-base-name file-name)
-    ;; Return the "base" of FILE-NAME, removing '.tar.gz' or similar
-    ;; extensions.
-    ;; TODO: Factorize.
-    (cond ((not (file-extension file-name))
-           file-name)
-          ((numeric-extension? file-name)
-           file-name)
-          ((string=? (file-extension file-name) "tar")
-           (file-sans-extension file-name))
-          ((file-extension file-name)
-           (tarball-base-name (file-sans-extension file-name)))
-          (else
-           file-name)))
-
   (let ((base (tarball-base-name (basename uri))))
-    (let-values (((name version)
-                  (package-name->name+version base)))
+    (let-values (((_ version*)
+                  (hyphen-package-name->name+version base)))
       (package (inherit p)
-               (version (or version (package-version p)))
+               (version (or version version*
+                            (package-version p)))
 
                ;; Use #:recursive? #t to allow for directories.
                (source (download-to-store store uri
@@ -173,8 +180,23 @@ the new package's version number from URI."
 matching URIs given in SOURCES."
   (define new-sources
     (map (lambda (uri)
-           (cons (package-name->name+version (basename uri))
-                 uri))
+           (match (string-index uri #\=)
+             (#f
+              ;; Determine the package name and version from URI.
+              (call-with-values
+                  (lambda ()
+                    (hyphen-package-name->name+version
+                     (tarball-base-name (basename uri))))
+                (lambda (name version)
+                  (list name version uri))))
+             (index
+              ;; What's before INDEX is a "PKG@VER" or "PKG" spec.
+              (call-with-values
+                  (lambda ()
+                    (package-name->name+version (string-take uri index)))
+                (lambda (name version)
+                  (list name version
+                        (string-drop uri (+ 1 index))))))))
          sources))
 
   (lambda (store obj)
@@ -182,10 +204,11 @@ matching URIs given in SOURCES."
                (result   '()))
       (match obj
         ((? package? p)
-         (let ((source (assoc-ref sources (package-name p))))
-           (if source
-               (package-with-source store p source)
-               p)))
+         (match (assoc-ref sources (package-name p))
+           ((version source)
+            (package-with-source store p source version))
+           (#f
+            p)))
         (_
          obj)))))
 
diff --git a/tests/scripts-build.scm b/tests/scripts-build.scm
index a408ea6f8d..190426ed06 100644
--- a/tests/scripts-build.scm
+++ b/tests/scripts-build.scm
@@ -96,6 +96,35 @@
              (string-contains (get-output-string port)
                               "had no effect"))))))
 
+(test-assert "options->transformation, with-source, PKG=URI"
+  (let* ((p (dummy-package "foo"))
+         (s (search-path %load-path "guix.scm"))
+         (f (string-append "foo=" s))
+         (t (options->transformation `((with-source . ,f)))))
+    (with-store store
+      (let ((new (t store p)))
+        (and (not (eq? new p))
+             (string=? (package-name new) (package-name p))
+             (string=? (package-version new)
+                       (package-version p))
+             (string=? (package-source new)
+                       (add-to-store store (basename s) #t
+                                     "sha256" s)))))))
+
+(test-assert "options->transformation, with-source, PKG@VER=URI"
+  (let* ((p (dummy-package "foo"))
+         (s (search-path %load-path "guix.scm"))
+         (f (string-append "foo@42.0=" s))
+         (t (options->transformation `((with-source . ,f)))))
+    (with-store store
+      (let ((new (t store p)))
+        (and (not (eq? new p))
+             (string=? (package-name new) (package-name p))
+             (string=? (package-version new) "42.0")
+             (string=? (package-source new)
+                       (add-to-store store (basename s) #t
+                                     "sha256" s)))))))
+
 (test-assert "options->transformation, with-input"
   (let* ((p (dummy-package "guix.scm"
               (inputs `(("foo" ,(specification->package "coreutils"))