Subject: [PATCH] Re: ‘guix package’ should lock the profile

From: Julien Lepiller <[email-masked]>
Date: Fri, 25 Oct 2019 21:44:51 +0200

Le Tue, 25 Jun 2019 16:10:22 +0200,
Ludovic Courtès <[email-masked]> a écrit :

> The article at
> <https://distrowatch.com/weekly.php?issue=20190624#guixsd> mentions
> things like:
> 
>   For instance, after installing Icecat, I installed a few other
> desktop programs and then found Icecat had disappeared from my path
> again.
> 
> It’s likely that the person ran several ‘guix package’ commands in
> parallel, and that one undoed the effects of the other.
> 
> Julien suggested that ‘guix package’ could grab a lock file, and I
> guess it could simply error out when the lock is already taken.
> 
> Ludo’.

Hi!

attached is a patch for guix package to grab a lock file. Note that I'm
using flock, so it won't work on NFS shares. The other option would be
to use fcntl but guile doesn't seem to implement the locking function
from it.
>From 987e9711f1fa6bfd270e48ee5624f69696e7e5c4 Mon Sep 17 00:00:00 2001
From: Julien Lepiller <[email-masked]>
Date: Fri, 25 Oct 2019 21:39:21 +0200
Subject: [PATCH] guix: package: lock profiles when processing them.

* guix/scripts/package.scm (process-actions): Get a per-profile lock to
prevent concurrent actions on profiles.
---
 guix/scripts/package.scm | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 1a58d43e5c..e4f0f416f5 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -876,7 +876,17 @@ processed, #f otherwise."
                      (package-version item)
                      (manifest-entry-version entry))))))
 
-  ;; First, process roll-backs, generation removals, etc.
+  ;; First, acquire a lock on the profile, to ensure only one guix process
+  ;; is modifying it at a time.
+  (define lock-file (open (string-append profile ".lock") O_CREAT))
+  (catch 'system-error
+    (lambda _
+      (flock lock-file (logior LOCK_EX LOCK_NB)))
+    (lambda (key . args)
+      (leave (G_ "profile ~a is being locked by another guix process.~%")
+                 profile)))
+
+  ;; Then, process roll-backs, generation removals, etc.
   (for-each (match-lambda
               ((key . arg)
                (and=> (assoc-ref %actions key)
@@ -905,7 +915,10 @@ processed, #f otherwise."
                              #:allow-collisions? allow-collisions?
                              #:bootstrap? bootstrap?
                              #:use-substitutes? substitutes?
-                             #:dry-run? dry-run?))))
+                             #:dry-run? dry-run?)))
+
+  ;; Finaly, close the lock file
+  (close lock-file))
 
 
 ;;;
-- 
2.22.0