summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi7
-rw-r--r--guix/transformations.scm74
-rw-r--r--tests/transformations.scm32
3 files changed, 68 insertions, 45 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index 84f7064faf..535c8cdfc3 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -12364,14 +12364,15 @@ one provided by the distribution.  The example below downloads
 the @code{ed} package:
 
 @example
-guix build ed --with-source=mirror://gnu/ed/ed-1.7.tar.gz
+guix build ed --with-source=mirror://gnu/ed/ed-1.4.tar.gz
 @end example
 
 As a developer, @option{--with-source} makes it easy to test release
-candidates:
+candidates, and even to test their impact on packages that depend on
+them:
 
 @example
-guix build guile --with-source=../guile-2.0.9.219-e1bb7.tar.xz
+guix build elogind --with-source=@dots{}/shepherd-0.9.0rc1.tar.gz 
 @end example
 
 @dots{} or to build from a checkout in a pristine environment:
diff --git a/guix/transformations.scm b/guix/transformations.scm
index 411c4014cb..be2d31b8c7 100644
--- a/guix/transformations.scm
+++ b/guix/transformations.scm
@@ -129,42 +129,46 @@ the new package's version number from URI."
 ;;; Transformations.
 ;;;
 
-(define (transform-package-source sources)
-  "Return a transformation procedure that replaces package sources with the
-matching URIs given in SOURCES."
-  (define new-sources
-    (map (lambda (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))
+(define (evaluate-source-replacement-specs specs)
+  "Parse SPECS, a list of strings like \"guile=/tmp/guile-4.2.tar.gz\" or just
+\"/tmp/guile-4.2.tar.gz\" and return a list of package spec/procedure pairs as
+expected by 'package-input-rewriting/spec'.  Raise an error if an element of
+SPECS uses invalid syntax."
+  (define not-equal
+    (char-set-complement (char-set #\=)))
 
-  (lambda (obj)
-    (let loop ((sources  new-sources)
-               (result   '()))
-      (match obj
-        ((? package? p)
-         (match (assoc-ref sources (package-name p))
-           ((version source)
-            (package-with-source p source version))
-           (#f
-            p)))
-        (_
-         obj)))))
+  (map (lambda (spec)
+         (match (string-tokenize spec not-equal)
+           ((uri)
+            (let* ((base (tarball-base-name (basename uri)))
+                   (name (hyphen-package-name->name+version base)))
+              (cons name
+                    (lambda (old)
+                      (package-with-source old uri)))))
+           ((spec uri)
+            (let-values (((name version)
+                          (package-name->name+version spec)))
+              ;; Note: Here VERSION is used as the version string of the new
+              ;; package rather than as part of the spec of the package being
+              ;; targeted.
+              (cons name
+                    (lambda (old)
+                      (package-with-source old uri version)))))
+           (_
+            (raise (formatted-message
+                    (G_ "invalid source replacement specification: ~s")
+                    spec)))))
+       specs))
+
+(define (transform-package-source replacement-specs)
+  "Return a transformation procedure that replaces package sources with the
+matching URIs given in REPLACEMENT-SPECS."
+  (let* ((replacements (evaluate-source-replacement-specs replacement-specs))
+         (rewrite      (package-input-rewriting/spec replacements)))
+    (lambda (obj)
+      (if (package? obj)
+          (rewrite obj)
+          obj))))
 
 (define (evaluate-replacement-specs specs proc)
   "Parse SPECS, a list of strings like \"guile=guile@2.1\" and return a list
diff --git a/tests/transformations.scm b/tests/transformations.scm
index dbfe523518..47b1fc650d 100644
--- a/tests/transformations.scm
+++ b/tests/transformations.scm
@@ -103,16 +103,11 @@
                                           "sha256" f))))))))))
 
 (test-assert "options->transformation, with-source, no matches"
-  ;; When a transformation in not applicable, a warning must be raised.
   (let* ((p (dummy-package "foobar"))
          (s (search-path %load-path "guix.scm"))
          (t (options->transformation `((with-source . ,s)))))
-    (let* ((port (open-output-string))
-           (new  (parameterize ((guix-warning-port port))
-                   (t p))))
-      (and (eq? new p)
-           (string-contains (get-output-string port)
-                            "had no effect")))))
+    (eq? (package-source (t p))
+         (package-source p))))
 
 (test-assert "options->transformation, with-source, PKG=URI"
   (let* ((p (dummy-package "foo"))
@@ -147,6 +142,29 @@
                        (add-to-store store (basename s) #t
                                      "sha256" s)))))))
 
+(test-assert "options->transformation, with-source, in depth"
+  (let* ((p0 (dummy-package "foo" (version "0.0")))
+         (s  (search-path %load-path "guix.scm"))
+         (f  (string-append "foo@42.0=" s))
+         (t  (options->transformation `((with-source . ,f))))
+         (p1 (dummy-package "bar" (inputs (list p0))))
+         (p2 (dummy-package "baz" (inputs (list p1)))))
+    (with-store store
+      (let ((new (t p2)))
+        (and (not (eq? new p2))
+             (match (package-inputs new)
+               ((("bar" p1*))
+                (match (package-inputs p1*)
+                  ((("foo" p0*))
+                   (and (not (eq? p0* p0))
+                        (string=? (package-name p0*) (package-name p0))
+                        (string=? (package-version p0*) "42.0")
+                        (string=? (add-to-store store (basename s) #t
+                                                "sha256" s)
+                                  (run-with-store store
+                                    (lower-object
+                                     (package-source p0*))))))))))))))
+
 (test-assert "options->transformation, with-input"
   (let* ((p (dummy-package "guix.scm"
               (inputs `(("foo" ,(specification->package "coreutils"))