guix: package: lock profiles when processing them.

* guix/scripts/package.scm (process-actions): Get a per-profile lock to
prevent concurrent actions on profiles.
* tests/guix-package.sh: Add test.
This commit is contained in:
Julien Lepiller 2019-10-25 21:39:21 +02:00
parent f49e913188
commit b1fb663404
No known key found for this signature in database
GPG key ID: 43111F4520086A0C
2 changed files with 46 additions and 28 deletions

View file

@ -42,6 +42,8 @@ (define-module (guix scripts package)
#:autoload (guix store roots) (gc-roots) #:autoload (guix store roots) (gc-roots)
#:use-module ((guix build utils) #:use-module ((guix build utils)
#:select (directory-exists? mkdir-p)) #:select (directory-exists? mkdir-p))
#:use-module ((guix build syscalls)
#:select (with-file-lock/no-wait))
#:use-module (ice-9 format) #:use-module (ice-9 format)
#:use-module (ice-9 match) #:use-module (ice-9 match)
#:use-module (ice-9 regex) #:use-module (ice-9 regex)
@ -876,36 +878,44 @@ (define (transform-entry entry)
(package-version item) (package-version item)
(manifest-entry-version entry)))))) (manifest-entry-version entry))))))
;; First, process roll-backs, generation removals, etc.
(for-each (match-lambda
((key . arg)
(and=> (assoc-ref %actions key)
(lambda (proc)
(proc store profile arg opts
#:dry-run? dry-run?)))))
opts)
;; Then, process normal package removal/installation/upgrade. ;; First, acquire a lock on the profile, to ensure only one guix process
(let* ((manifest (profile-manifest profile)) ;; is modifying it at a time.
(step1 (options->removable opts manifest (with-file-lock/no-wait (string-append profile ".lock")
(manifest-transaction))) (lambda (key . args)
(step2 (options->installable opts manifest step1)) (leave (G_ "profile ~a is locked by another process~%")
(step3 (manifest-transaction profile))
(inherit step2)
(install (map transform-entry
(manifest-transaction-install step2)))))
(new (manifest-perform-transaction manifest step3)))
(warn-about-old-distro) ;; Then, process roll-backs, generation removals, etc.
(for-each (match-lambda
((key . arg)
(and=> (assoc-ref %actions key)
(lambda (proc)
(proc store profile arg opts
#:dry-run? dry-run?)))))
opts)
(unless (manifest-transaction-null? step3) ;; Then, process normal package removal/installation/upgrade.
(show-manifest-transaction store manifest step3 (let* ((manifest (profile-manifest profile))
#:dry-run? dry-run?) (step1 (options->removable opts manifest
(build-and-use-profile store profile new (manifest-transaction)))
#:allow-collisions? allow-collisions? (step2 (options->installable opts manifest step1))
#:bootstrap? bootstrap? (step3 (manifest-transaction
#:use-substitutes? substitutes? (inherit step2)
#:dry-run? dry-run?)))) (install (map transform-entry
(manifest-transaction-install step2)))))
(new (manifest-perform-transaction manifest step3)))
(warn-about-old-distro)
(unless (manifest-transaction-null? step3)
(show-manifest-transaction store manifest step3
#:dry-run? dry-run?)
(build-and-use-profile store profile new
#:allow-collisions? allow-collisions?
#:bootstrap? bootstrap?
#:use-substitutes? substitutes?
#:dry-run? dry-run?)))))
;;; ;;;

View file

@ -33,7 +33,7 @@ profile="t-profile-$$"
tmpfile="t-guix-package-file-$$" tmpfile="t-guix-package-file-$$"
rm -f "$profile" "$tmpfile" rm -f "$profile" "$tmpfile"
trap 'rm -f "$profile" "$profile-"[0-9]* "$tmpfile"; rm -rf "$module_dir" t-home-'"$$" EXIT trap 'rm -f "$profile" "$profile.lock" "$profile-"[0-9]* "$tmpfile"; rm -rf "$module_dir" t-home-'"$$" EXIT
# Use `-e' with a non-package expression. # Use `-e' with a non-package expression.
if guix package --bootstrap -e +; if guix package --bootstrap -e +;
@ -452,3 +452,11 @@ rm -rf "$module_dir"
# Make sure we can see user profiles. # Make sure we can see user profiles.
guix package --list-profiles | grep "$profile" guix package --list-profiles | grep "$profile"
guix package --list-profiles | grep '\.guix-profile' guix package --list-profiles | grep '\.guix-profile'
# Make sure we can properly lock a profile.
mkdir "$module_dir"
echo '(sleep 60)' > "$module_dir/manifest.scm"
guix package -m "$module_dir/manifest.scm" -p "$module_dir/profile" &
pid=$!
if guix install emacs -p "$module_dir/profile"; then kill $pid; false; else true; fi
kill $pid