all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Maxime Devos <maximedevos@telenet.be>
To: 53144@debbugs.gnu.org
Cc: Maxime Devos <maximedevos@telenet.be>
Subject: [bug#53144] [PATCH 12/13] import: Add 'latest-git' updater.
Date: Sun,  9 Jan 2022 19:10:14 +0000	[thread overview]
Message-ID: <20220109191015.33058-12-maximedevos@telenet.be> (raw)
In-Reply-To: <20220109191015.33058-1-maximedevos@telenet.be>

* Makefile.am (MODULES, SCM_TESTS): Register new files.
* doc/guix.texi (Invoking guix refresh): Document it.
* guix/import/latest-git.scm: New importer file.
* guix/upstream.scm (increment-git-version): New procedure.
* tests/import-latest-git.scm: New test file.
---
 Makefile.am                 |   2 +
 doc/guix.texi               |  17 +++
 guix/import/latest-git.scm  | 104 ++++++++++++++++++
 guix/upstream.scm           |   9 ++
 tests/import-latest-git.scm | 204 ++++++++++++++++++++++++++++++++++++
 5 files changed, 336 insertions(+)
 create mode 100644 guix/import/latest-git.scm
 create mode 100644 tests/import-latest-git.scm

diff --git a/Makefile.am b/Makefile.am
index d6aabac261..e380c7c83d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -267,6 +267,7 @@ MODULES =					\
   guix/import/json.scm				\
   guix/import/kde.scm				\
   guix/import/launchpad.scm   			\
+  guix/import/latest-git.scm			\
   guix/import/minetest.scm   			\
   guix/import/opam.scm				\
   guix/import/print.scm				\
@@ -482,6 +483,7 @@ SCM_TESTS =					\
   tests/hackage.scm				\
   tests/home-import.scm				\
   tests/import-git.scm				\
+  tests/import-latest-git.scm			\
   tests/import-utils.scm			\
   tests/inferior.scm				\
   tests/lint.scm				\
diff --git a/doc/guix.texi b/doc/guix.texi
index 5c1b9adb87..58ccc75ccf 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -12619,6 +12619,23 @@ property to @code{#t}.
       (release-tag-version-delimiter . ":"))))
 @end lisp
 
+@item latest-git
+@cindex latest-git
+@cindex with-latest-git-commit
+another updater for packages hosted on Git repositories.  The difference
+with @code{generic-git} is that it always choses the latest commit, even
+when it does not have a version tag.  As this practice should remain
+exceptional (@pxref{Version Numbers}), packages have to opt-in this
+updater, by using @code{git-version} to construct the version number and
+setting the @code{with-latest-git-commit} package property.
+
+Usually, it can be simply be set to @code{#true} to use the latest Git
+commit on the default branch---i.e., HEAD in Git parlance.  If this is
+not desired, for example if upstream has a branch that is considered
+‘stable’, it can be set to the name of a reference to take commits from.
+For example, to take commits from a branch named @code{stable}, the
+property @code{with-latest-git-commit} needs to be set to
+@code{refs/heads/stable}.
 
 @end table
 
diff --git a/guix/import/latest-git.scm b/guix/import/latest-git.scm
new file mode 100644
index 0000000000..208f112153
--- /dev/null
+++ b/guix/import/latest-git.scm
@@ -0,0 +1,104 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix import latest-git)
+  #:use-module (guix packages)
+  #:use-module (guix upstream)
+  #:use-module (guix ui)
+  #:use-module (guix git)
+  #:use-module (guix git-download)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-26)
+  #:export (%latest-git-updater))
+
+(define (check-valid-with-latest-git-commit? package value)
+  "Verify that VALUE is a valid value for the 'with-latest-git-commit'
+package property of PACKAGE.  If so, return #true.  Otherwise, emit a
+warning and return #false.  It is assumed VALUE is not false."
+  (or (string? value)
+      (eq? #true value)
+      (begin
+        (warning (or (package-field-location package 'properties)
+                     (package-location package))
+                 (G_ "Package ~a has an invalid 'with-latest-git-commit' \
+property.~%")
+                 (package-name package))
+        #false)))
+
+(define (with-latest-git-commit? package)
+  "Return true if PACKAGE is hosted on a Git repository and it is requested
+that the latest Git commit is used even when not formally released."
+  (match (package-source package)
+    ((? origin? origin)
+     (and (decompose-git-version (package-version package))
+          (eq? (origin-method origin) git-fetch)
+          (git-reference? (origin-uri origin))
+          (and=> (assq-ref (package-properties package)
+                           'with-latest-git-commit)
+                 (cut check-valid-with-latest-git-commit? package <>))))
+    (_ #f)))
+
+(define (latest-commit-reference-name package)
+  "Return the name of the reference that is expected to hold the latest Git
+commit to use as source code."
+  (match (assq-ref (package-properties package) 'with-latest-git-commit)
+    ('#true "HEAD")
+    ((? string? reference) reference)))
+
+(define (latest-git-upstream package)
+  "Return an <upstream-source> for the latest git commit of PACKAGE.
+If the reference pointing to the latest git commit has been deleted,
+return #false instead."
+  (let* ((name (package-name package))
+         (old-version (package-version package))
+         (old-reference (origin-uri (package-source package)))
+         (reference-name (latest-commit-reference-name package))
+         (commit (lookup-reference (git-reference-url old-reference)
+                                   reference-name)))
+    (if commit
+        (upstream-source
+         (package name)
+         (version
+          ;; See 'oid->commit' in (guix git) for why not string=?.
+          ;; Don't increment the revision if the commit remains the same.
+          (if (string-prefix? commit (git-reference-commit old-reference))
+              old-version
+              (increment-git-version old-version commit)))
+         (urls (git-reference
+                (inherit old-reference)
+                (commit commit))))
+        (begin
+          (warning (package-location package)
+                   (G_ "Cannot update ~a because the reference ~a of ~a has \
+disappeared.~%")
+                   (package-name package)
+                   reference-name
+                   (let ((maybe-hyperlink
+                          (if (supports-hyperlinks? (guix-warning-port))
+                              hyperlink
+                              (lambda (x y) x)))
+                         (url (git-reference-url old-reference)))
+                     (maybe-hyperlink url url)))
+          #false))))
+
+(define %latest-git-updater
+  (upstream-updater
+   (name 'latest-git)
+   (description "Updater for packages using latest Git commit")
+   (pred with-latest-git-commit?)
+   (latest latest-git-upstream)))
diff --git a/guix/upstream.scm b/guix/upstream.scm
index 6b65147356..a9211fe45b 100644
--- a/guix/upstream.scm
+++ b/guix/upstream.scm
@@ -64,6 +64,7 @@ (define-module (guix upstream)
             decompose-git-version
             maybe-git-version->revision
             maybe-git-versions->revision-replacements ; for tests
+            increment-git-version
 
             upstream-updater
             upstream-updater?
@@ -281,6 +282,14 @@ (define (maybe-git-versions->revision-replacements old new)
            . ,(object->string `(revision ,new-revision))))
         '())))
 
+(define (increment-git-version old-git-version commit)
+  "Increment the revision in OLD-GIT-VERSION by one, replacing the commit
+by COMMIT.  It is assumed OLD-GIT-VERSION is a result of 'git-version'."
+  (let-values (((old-base-version revision old-commit)
+                (decompose-git-version old-git-version)))
+    (git-version old-base-version
+                 (number->string (+ 1 (string->number revision))) commit)))
+
 \f
 
 ;;;
diff --git a/tests/import-latest-git.scm b/tests/import-latest-git.scm
new file mode 100644
index 0000000000..d0dc149ff8
--- /dev/null
+++ b/tests/import-latest-git.scm
@@ -0,0 +1,204 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (test-import-latest-git)
+  #:use-module (git)
+  #:use-module (guix git)
+  #:use-module (guix tests)
+  #:use-module (guix packages)
+  #:use-module (guix import latest-git)
+  #:use-module (guix upstream)
+  #:use-module (guix git-download)
+  #:use-module (guix hg-download)
+  #:use-module (guix tests git)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-64))
+
+(test-begin "git")
+
+(define latest-git-upstream
+  (upstream-updater-latest %latest-git-updater))
+
+(define with-latest-git-commit?
+  (upstream-updater-predicate %latest-git-updater))
+
+(define* (make-package directory base-version revision commit
+                       #:optional (properties
+                                   '((with-latest-git-commit . #true))))
+  (dummy-package "test-package"
+                 (version (git-version base-version revision commit))
+                 (source
+                  (origin
+                    (method git-fetch)
+                    (uri (git-reference
+                          (url (string-append "file://" directory))
+                          (commit commit)))
+                    (sha256 #f)))
+                 (properties properties)))
+
+(define (find-commit-as-string repository query)
+  (oid->string (commit-id (find-commit repository query))))
+
+(unless (which (git-command)) (test-skip 1))
+(test-equal "latest-git: an update"
+  '(#true #true #true)
+  (with-temporary-git-repository directory
+      '((add "a.txt" "A")
+        (commit "First commit")
+        (add "b.txt" "B")
+        (commit "Second commit"))
+    (with-repository directory repository
+      (let* ((old-commit
+              (find-commit-as-string repository "First commit"))
+             (new-commit
+              (find-commit-as-string repository "Second commit"))
+             (package (make-package directory "1.0" "0" old-commit))
+             (update (latest-git-upstream package)))
+        (list (with-latest-git-commit? package)
+              (string=? (upstream-source-version update)
+                        (git-version "1.0" "1" new-commit))
+              ;; See 'oid->commit in (guix git) for why not string=?.
+              (string-prefix?
+               (git-reference-commit (upstream-source-urls update))
+               new-commit))))))
+
+(unless (which (git-command)) (test-skip 1))
+(test-equal "latest-git: no new commit, no new revision"
+  '(#true #true #true)
+  (with-temporary-git-repository directory
+      '((add "a.txt" "A")
+        (commit "First commit"))
+    (with-repository directory repository
+      (let* ((commit
+              (find-commit-as-string repository "First commit"))
+             (package (make-package directory "1.0" "0" commit))
+             (update (latest-git-upstream package)))
+        ;; 'update' being #false would work as well.
+        (list (with-latest-git-commit? package)
+              (string=? (upstream-source-version update)
+                        (package-version package))
+              (string-prefix?
+               (git-reference-commit (upstream-source-urls update))
+               commit))))))
+
+(unless (which (git-command)) (test-skip 1))
+(test-equal "latest-git: non-HEAD commits ignored"
+  '(#true #true #true)
+  (with-temporary-git-repository directory
+      '((add "a.txt" "A")
+        (commit "First commit")
+        (tag "let-me-be-head")
+        (branch "dev")
+        (checkout "dev")
+        (add "b.txt" "B")
+        (commit "Not ready for distribution!")
+        (checkout "let-me-be-head"))
+    (with-repository directory repository
+      (let* ((commit
+              (find-commit-as-string repository "First commit"))
+             (package (make-package directory "1.0" "0" commit))
+             (update (latest-git-upstream package)))
+        (list (with-latest-git-commit? package)
+              (string=? (upstream-source-version update)
+                        (package-version package))
+              (string-prefix?
+               (git-reference-commit (upstream-source-urls update))
+               commit))))))
+
+(unless (which (git-command)) (test-skip 1))
+(test-equal "latest-git: non-HEAD branches can be chosen"
+  '(#true #true #true)
+  (with-temporary-git-repository directory
+      '((checkout "stable-for-distros" orphan)
+        (add "a.txt" "A")
+        (commit "First commit")
+        (add "b.txt" "B")
+        (commit "Here's a bugfix.")
+        (branch "unstable")
+        (checkout "unstable")
+        (add "c.txt" "C")
+        ;; This commit may not be chosen.
+        (commit "New feature, needs more work before distributing."))
+    (with-repository directory repository
+      (let* ((old-commit
+              (find-commit-as-string repository "First commit"))
+             (new-commit
+              (find-commit-as-string repository "Here's a bugfix"))
+             (properties
+              '((with-latest-git-commit . "refs/heads/stable-for-distros")))
+             (package (make-package directory "1.0" "0" old-commit properties))
+             (update (latest-git-upstream package)))
+        (list (with-latest-git-commit? package)
+              (string=? (upstream-source-version update)
+                        (git-version "1.0" "1" new-commit))
+              (string-prefix?
+               (git-reference-commit (upstream-source-urls update))
+               new-commit))))))
+
+(unless (which (git-command)) (test-skip 1))
+(test-equal "latest-git: deleted references handled gracefully"
+  #false
+  (with-temporary-git-repository directory
+      '((add "a.txt" "A")
+        (commit "First commit"))
+    (with-repository directory repository
+      (let* ((properties
+              '((with-latest-git-commit . "refs/heads/I-do-not-exist")))
+             (package (make-package directory "1.0" "0" "cabba9e" properties)))
+        (latest-git-upstream package)))))
+
+(test-equal "with-latest-git-commit?"
+  '(#true #false #true #true #false #false)
+  (map (lambda (properties)
+         (with-latest-git-commit?
+          (make-package "/dev/null" "1.0" "0" "cabba9e" properties)))
+       (list '((with-latest-git-commit . #true)) ; defaults to HEAD
+             '() ; packages have to opt-in, so #false
+             '((with-latest-git-commit . "HEAD")) ; explicit HEAD is ok
+             '((with-latest-git-commit . "refs/heads/main")) ; another branch
+             '((with-latest-git-commit . #xf00ba3)) ; bogus
+             '((irrelevant . #true)))))
+
+(test-equal "with-latest-git-commit?: not for other VCS"
+  #false
+  (with-latest-git-commit?
+   (package
+     (inherit (make-package "/dev/null" "1.0.0" "0" "cabba9e"))
+     (source
+      (origin
+        (method hg-fetch)
+        (uri (hg-reference
+              (url "https://foo")
+              (changeset "foo")))
+        (sha256 #false))))))
+
+(test-equal "with-latest-git-commit?: only if there's source code"
+  #false
+  (with-latest-git-commit?
+   (package
+     (inherit (make-package "/dev/null" "1.0.0" "0" "cabba9e"))
+     (source #false))))
+
+(test-equal "with-latest-git-commit?: only for git-version"
+  #false
+  (with-latest-git-commit?
+   (package
+     (inherit (make-package "/dev/null" "1.0.0" "0" "cabba9e"))
+     (version "1.0.0"))))
+
+(test-end "git")
-- 
2.34.0





  parent reply	other threads:[~2022-01-09 19:12 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-09 19:08 [bug#53144] [PATCH 0/13] Make more git-using packages auto-updatable Maxime Devos
2022-01-09 19:10 ` [bug#53144] [PATCH 01/13] doc: Give some tips on Minetest packaging Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 02/13] gnu: minetest-ethereal: Follow new versioning conventions Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 03/13] gnu: minetest-mesecons: " Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 04/13] gnu: minetest-throwing: " Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 05/13] gnu: minetest: Remove obsolete comments about version numbers Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 06/13] gnu: minetest-ethereal: Update to 2022-01-05 Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 07/13] gnu: minetest-mesecons: Update to 2021-11-28 Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 08/13] gnu: minetest-mobs: Update to 2022-01-03 Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 09/13] doc: Document the Minetest importer Maxime Devos
2022-01-09 19:10   ` [bug#53144] [PATCH 10/13] upstream: Support incrementing the revision of 'git-version' Maxime Devos
2022-01-18 17:33     ` [bug#53144] [PATCH 0/13] Make more git-using packages auto-updatable Ludovic Courtès
2022-01-09 19:10   ` [bug#53144] [PATCH 11/13] git: Support resolving references without cloning Maxime Devos
2022-01-18 17:39     ` [bug#53144] [PATCH 0/13] Make more git-using packages auto-updatable Ludovic Courtès
2022-04-03 11:47       ` Maxime Devos
2022-01-09 19:10   ` Maxime Devos [this message]
2022-01-18 17:45     ` Ludovic Courtès
2022-01-09 19:10   ` [bug#53144] [PATCH 13/13] gnu: minetest-throwing-arrows: Use 'latest-git' updater Maxime Devos
2022-01-09 21:15   ` [bug#53144] [PATCH 01/13] doc: Give some tips on Minetest packaging Liliana Marie Prikler
2022-01-09 23:29     ` Maxime Devos
2022-01-10 21:29       ` Liliana Marie Prikler
2022-01-18 17:30   ` [bug#53144] [PATCH 0/13] Make more git-using packages auto-updatable Ludovic Courtès
     [not found] ` <handler.53144.B.164175531629466.ack@debbugs.gnu.org>
2022-01-09 19:49   ` [bug#53144] Acknowledgement ([PATCH 0/13] Make more git-using packages auto-updatable) Maxime Devos
2022-06-06 15:15 ` [bug#53144] [PATCH 0/13] Make more git-using packages auto-updatable Maxime Devos

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220109191015.33058-12-maximedevos@telenet.be \
    --to=maximedevos@telenet.be \
    --cc=53144@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.