diff options
Diffstat (limited to 'guix')
-rw-r--r-- | guix/build-system/trivial.scm | 10 | ||||
-rw-r--r-- | guix/scripts/package.scm | 287 |
2 files changed, 193 insertions, 104 deletions
diff --git a/guix/build-system/trivial.scm b/guix/build-system/trivial.scm index 3c5031c4bd..f91997d1e9 100644 --- a/guix/build-system/trivial.scm +++ b/guix/build-system/trivial.scm @@ -42,7 +42,10 @@ search-paths) "Run build expression BUILDER, an expression, for SYSTEM. SOURCE is ignored." - (build-expression->derivation store name system builder inputs + (build-expression->derivation store name system builder + (if source + `(("source" ,source) ,@inputs) + inputs) #:outputs outputs #:modules modules #:guile-for-build @@ -54,7 +57,10 @@ ignored." search-paths native-search-paths) "Like `trivial-build', but in a cross-compilation context." (build-expression->derivation store name system builder - (append native-inputs inputs) + (let ((inputs (append native-inputs inputs))) + (if source + `(("source" ,source) ,@inputs) + inputs)) #:outputs outputs #:modules modules #:guile-for-build diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm index 66505f172f..5c7c165cbb 100644 --- a/guix/scripts/package.scm +++ b/guix/scripts/package.scm @@ -214,6 +214,25 @@ all of PACKAGES, a list of name/version/output/path/deps tuples." (compose string->number (cut match:substring <> 1))) 0)) +(define (link-to-empty-profile generation) + "Link GENERATION, a string, to the empty profile." + (let* ((drv (profile-derivation (%store) '())) + (prof (derivation->output-path drv "out"))) + (when (not (build-derivations (%store) (list drv))) + (leave (_ "failed to build the empty profile~%"))) + + (switch-symlinks generation prof))) + +(define (switch-to-previous-generation profile) + "Atomically switch PROFILE to the previous generation." + (let* ((number (generation-number profile)) + (previous-number (previous-generation-number profile number)) + (previous-generation (format #f "~a-~a-link" + profile previous-number))) + (format #t (_ "switching from generation ~a to ~a~%") + number previous-number) + (switch-symlinks profile previous-generation))) + (define (roll-back profile) "Roll back to the previous generation of PROFILE." (let* ((number (generation-number profile)) @@ -221,38 +240,30 @@ all of PACKAGES, a list of name/version/output/path/deps tuples." (previous-generation (format #f "~a-~a-link" profile previous-number)) (manifest (string-append previous-generation "/manifest"))) - - (define (switch-link) - ;; Atomically switch PROFILE to the previous generation. - (format #t (_ "switching from generation ~a to ~a~%") - number previous-number) - (switch-symlinks profile previous-generation)) - - (cond ((not (file-exists? profile)) ; invalid profile - (leave (_ "profile `~a' does not exist~%") + (cond ((not (file-exists? profile)) ; invalid profile + (leave (_ "profile '~a' does not exist~%") profile)) - ((zero? number) ; empty profile + ((zero? number) ; empty profile (format (current-error-port) (_ "nothing to do: already at the empty profile~%"))) - ((or (zero? previous-number) ; going to emptiness + ((or (zero? previous-number) ; going to emptiness (not (file-exists? previous-generation))) - (let* ((drv (profile-derivation (%store) '())) - (prof (derivation->output-path drv "out"))) - (when (not (build-derivations (%store) (list drv))) - (leave (_ "failed to build the empty profile~%"))) - - (switch-symlinks previous-generation prof) - (switch-link))) - (else (switch-link))))) ; anything else + (link-to-empty-profile previous-generation) + (switch-to-previous-generation profile)) + (else + (switch-to-previous-generation profile))))) ; anything else (define (generation-time profile number) "Return the creation time of a generation in the UTC format." (make-time time-utc 0 (stat:ctime (stat (format #f "~a-~a-link" profile number))))) -(define* (matching-generations str #:optional (profile %current-profile)) +(define* (matching-generations str #:optional (profile %current-profile) + #:key (duration-relation <=)) "Return the list of available generations matching a pattern in STR. See -'string->generations' and 'string->duration' for the list of valid patterns." +'string->generations' and 'string->duration' for the list of valid patterns. +When STR is a duration pattern, return all the generations whose ctime has +DURATION-RELATION with the current time." (define (valid-generations lst) (define (valid-generation? n) (any (cut = n <>) (generation-numbers profile))) @@ -301,7 +312,7 @@ all of PACKAGES, a list of name/version/output/path/deps tuples." (subtract-duration (time-at-midnight (current-time)) duration)))) (delete #f (map (lambda (x) - (and (<= s (cdr x)) + (and (duration-relation s (cdr x)) (first x))) generation-ctime-alist)))))) @@ -511,6 +522,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (display (_ " -l, --list-generations[=PATTERN] list generations matching PATTERN")) + (display (_ " + -d, --delete-generations[=PATTERN] + delete generations matching PATTERN")) (newline) (display (_ " -p, --profile=PROFILE use PROFILE instead of the user's default profile")) @@ -574,6 +588,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n")) (lambda (opt name arg result) (cons `(query list-generations ,(or arg "")) result))) + (option '(#\d "delete-generations") #f #t + (lambda (opt name arg result) + (alist-cons 'delete-generations (or arg "") + result))) (option '("search-paths") #f #f (lambda (opt name arg result) (cons `(query search-paths) result))) @@ -824,85 +842,150 @@ more information.~%")) install)))) (_ #f))) + (define current-generation-number + (generation-number profile)) + + (define (display-and-delete number) + (let ((generation (format #f "~a-~a-link" profile number))) + (unless (zero? number) + (format #t (_ "deleting ~a~%") generation) + (delete-file generation)))) + + (define (delete-generation number) + (let* ((previous-number (previous-generation-number profile number)) + (previous-generation (format #f "~a-~a-link" + profile previous-number))) + (cond ((zero? number)) ; do not delete generation 0 + ((and (= number current-generation-number) + (not (file-exists? previous-generation))) + (link-to-empty-profile previous-generation) + (switch-to-previous-generation profile) + (display-and-delete number)) + ((= number current-generation-number) + (roll-back profile) + (display-and-delete number)) + (else + (display-and-delete number))))) + ;; First roll back if asked to. - (if (and (assoc-ref opts 'roll-back?) (not dry-run?)) - (begin - (roll-back profile) - (process-actions (alist-delete 'roll-back? opts))) - (let* ((installed (manifest-packages (profile-manifest profile))) - (upgrade-regexps (filter-map (match-lambda - (('upgrade . regexp) - (make-regexp (or regexp ""))) - (_ #f)) - opts)) - (upgrade (if (null? upgrade-regexps) - '() - (let ((newest (find-newest-available-packages))) - (filter-map (match-lambda - ((name version output path _) - (and (any (cut regexp-exec <> name) - upgrade-regexps) - (upgradeable? name version path) - (find-package name - (or output "out")))) - (_ #f)) - installed)))) - (install (append - upgrade - (filter-map (match-lambda - (('install . (? package? p)) - (package->tuple p)) - (('install . (? store-path?)) - #f) - (('install . package) - (find-package package)) - (_ #f)) - opts))) - (drv (filter-map (match-lambda - ((name version sub-drv - (? package? package) - (deps ...)) - (check-package-freshness package) - (package-derivation (%store) package)) - (_ #f)) - install)) - (install* (append - (filter-map (match-lambda - (('install . (? package? p)) - #f) - (('install . (? store-path? path)) - (let-values (((name version) - (package-name->name+version - (store-path-package-name - path)))) - `(,name ,version #f ,path ()))) - (_ #f)) - opts) - (map (lambda (tuple drv) - (match tuple - ((name version sub-drv _ (deps ...)) - (let ((output-path - (derivation->output-path - drv sub-drv))) - `(,name ,version ,sub-drv ,output-path - ,(canonicalize-deps deps)))))) - install drv))) - (remove (filter-map (match-lambda - (('remove . package) - package) - (_ #f)) - opts)) - (remove* (filter-map (cut assoc <> installed) remove)) - (packages (append install* - (fold (lambda (package result) - (match package - ((name _ out _ ...) - (filter (negate - (cut same-package? <> - name out)) - result)))) - (fold alist-delete installed remove) - install*)))) + (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?)) + (begin + (roll-back profile) + (process-actions (alist-delete 'roll-back? opts)))) + ((and (assoc-ref opts 'delete-generations) + (not dry-run?)) + (filter-map + (match-lambda + (('delete-generations . pattern) + (cond ((not (file-exists? profile)) ; XXX: race condition + (leave (_ "profile '~a' does not exist~%") + profile)) + ((string-null? pattern) + (let ((numbers (generation-numbers profile))) + (if (equal? numbers '(0)) + (exit 0) + (for-each display-and-delete + (delete current-generation-number + numbers))))) + ;; Do not delete the zeroth generation. + ((equal? 0 (string->number pattern)) + (exit 0)) + + ;; If PATTERN is a duration, match generations that are + ;; older than the specified duration. + ((matching-generations pattern profile + #:duration-relation >) + => + (lambda (numbers) + (if (null-list? numbers) + (exit 1) + (for-each delete-generation numbers)))) + (else + (leave (_ "invalid syntax: ~a~%") + pattern))) + + (process-actions + (alist-delete 'delete-generations opts))) + (_ #f)) + opts)) + (else + (let* ((installed (manifest-packages (profile-manifest profile))) + (upgrade-regexps (filter-map (match-lambda + (('upgrade . regexp) + (make-regexp (or regexp ""))) + (_ #f)) + opts)) + (upgrade (if (null? upgrade-regexps) + '() + (let ((newest (find-newest-available-packages))) + (filter-map + (match-lambda + ((name version output path _) + (and (any (cut regexp-exec <> name) + upgrade-regexps) + (upgradeable? name version path) + (find-package name + (or output "out")))) + (_ #f)) + installed)))) + (install (append + upgrade + (filter-map (match-lambda + (('install . (? package? p)) + (package->tuple p)) + (('install . (? store-path?)) + #f) + (('install . package) + (find-package package)) + (_ #f)) + opts))) + (drv (filter-map (match-lambda + ((name version sub-drv + (? package? package) + (deps ...)) + (check-package-freshness package) + (package-derivation (%store) package)) + (_ #f)) + install)) + (install* + (append + (filter-map (match-lambda + (('install . (? package? p)) + #f) + (('install . (? store-path? path)) + (let-values (((name version) + (package-name->name+version + (store-path-package-name + path)))) + `(,name ,version #f ,path ()))) + (_ #f)) + opts) + (map (lambda (tuple drv) + (match tuple + ((name version sub-drv _ (deps ...)) + (let ((output-path + (derivation->output-path + drv sub-drv))) + `(,name ,version ,sub-drv ,output-path + ,(canonicalize-deps deps)))))) + install drv))) + (remove (filter-map (match-lambda + (('remove . package) + package) + (_ #f)) + opts)) + (remove* (filter-map (cut assoc <> installed) remove)) + (packages + (append install* + (fold (lambda (package result) + (match package + ((name _ out _ ...) + (filter (negate + (cut same-package? <> + name out)) + result)))) + (fold alist-delete installed remove) + install*)))) (when (equal? profile %current-profile) (ensure-default-profile)) @@ -946,7 +1029,7 @@ more information.~%")) count) count) (display-search-paths packages - profile)))))))))) + profile))))))))))) (define (process-query opts) ;; Process any query specified by OPTS. Return #t when a query was @@ -983,7 +1066,7 @@ more information.~%")) ((string-null? pattern) (let ((numbers (generation-numbers profile))) (if (equal? numbers '(0)) - (exit 1) + (exit 0) (for-each list-generation numbers)))) ((matching-generations pattern profile) => |