1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2012, 2013, 2015, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
4 ;;; This file is part of GNU Guix.
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19 (define-module (guix scripts gc)
20 #:use-module (guix ui)
21 #:use-module (guix scripts)
22 #:use-module (guix store)
23 #:use-module (guix store roots)
24 #:autoload (guix build syscalls) (free-disk-space)
25 #:autoload (guix profiles) (generation-profile
28 #:autoload (guix scripts package) (delete-generations)
29 #:use-module (ice-9 match)
30 #:use-module (ice-9 regex)
31 #:use-module (srfi srfi-1)
32 #:use-module (srfi srfi-11)
33 #:use-module (srfi srfi-26)
34 #:use-module (srfi srfi-37)
39 ;;; Command-line options.
42 (define %default-options
43 ;; Alist of default option values.
44 `((action . collect-garbage)))
47 (display (G_ "Usage: guix gc [OPTION]... PATHS...
48 Invoke the garbage collector.\n"))
50 -C, --collect-garbage[=MIN]
51 collect at least MIN bytes of garbage"))
53 -F, --free-space=FREE attempt to reach FREE available space in the store"))
55 -d, --delete-generations[=PATTERN]
56 delete profile generations matching PATTERN"))
58 -D, --delete attempt to delete PATHS"))
60 --list-roots list the user's garbage collector roots"))
62 --list-busy list store items used by running processes"))
64 --optimize optimize the store by deduplicating identical files"))
66 --list-dead list dead paths"))
68 --list-live list live paths"))
71 --references list the references of PATHS"))
73 -R, --requisites list the requisites of PATHS"))
75 --referrers list the referrers of PATHS"))
77 --derivers list the derivers of PATHS"))
80 --verify[=OPTS] verify the integrity of the store; OPTS is a
81 comma-separated combination of 'repair' and
84 --list-failures list cached build failures"))
86 --clear-failures remove PATHS from the set of cached failures"))
89 -h, --help display this help and exit"))
91 -V, --version display version information and exit"))
93 (show-bug-report-information))
95 (define argument->verify-options
96 (let ((not-comma (char-set-complement (char-set #\,)))
97 (validate (lambda (option)
98 (unless (memq option '(repair contents))
99 (leave (G_ "~a: invalid '--verify' option~%")
102 "Turn ARG into a list of symbols denoting '--verify' options."
104 (let ((lst (map string->symbol
105 (string-tokenize arg not-comma))))
106 (for-each validate lst)
110 (define (delete-old-generations store profile pattern)
111 "Remove the generations of PROFILE that match PATTERN, a duration pattern;
112 do nothing if none matches. If PATTERN is #f, delete all generations but the
114 (let* ((current (generation-number profile))
115 (numbers (if (not pattern)
116 (profile-generations profile)
117 (matching-generations pattern profile
118 #:duration-relation >))))
120 ;; Make sure we don't inadvertently remove the current generation.
121 (delete-generations store profile (delv current numbers))))
124 ;; Specification of the command-line options.
125 (list (option '(#\h "help") #f #f
129 (option '(#\V "version") #f #f
131 (show-version-and-exit "guix gc")))
133 (option '(#\C "collect-garbage") #f #t
134 (lambda (opt name arg result)
135 (let ((result (alist-cons 'action 'collect-garbage
136 (alist-delete 'action result))))
139 (let ((amount (size->number arg)))
141 (alist-cons 'min-freed amount result)
142 (leave (G_ "invalid amount of storage: ~a~%")
145 (option '(#\F "free-space") #t #f
146 (lambda (opt name arg result)
147 (alist-cons 'free-space (size->number arg) result)))
148 (option '(#\D "delete") #f #f ;used to be '-d' (lower case)
149 (lambda (opt name arg result)
150 (alist-cons 'action 'delete
151 (alist-delete 'action result))))
152 (option '(#\d "delete-generations") #f #t
153 (lambda (opt name arg result)
154 (if (and arg (store-path? arg))
156 (warning (G_ "'-d' as an alias for '--delete' \
157 is deprecated; use '-D'~%"))
160 (alist-delete 'action result)))
162 (when (and arg (not (string->duration arg)))
163 (leave (G_ "~s does not denote a duration~%")
165 (alist-cons 'delete-generations arg result)))))
166 (option '("optimize") #f #f
167 (lambda (opt name arg result)
168 (alist-cons 'action 'optimize
169 (alist-delete 'action result))))
170 (option '("verify") #f #t
171 (lambda (opt name arg result)
172 (let ((options (argument->verify-options arg)))
173 (alist-cons 'action 'verify
174 (alist-cons 'verify-options options
175 (alist-delete 'action
177 (option '("list-roots") #f #f
178 (lambda (opt name arg result)
179 (alist-cons 'action 'list-roots
180 (alist-delete 'action result))))
181 (option '("list-busy") #f #f
182 (lambda (opt name arg result)
183 (alist-cons 'action 'list-busy
184 (alist-delete 'action result))))
185 (option '("list-dead") #f #f
186 (lambda (opt name arg result)
187 (alist-cons 'action 'list-dead
188 (alist-delete 'action result))))
189 (option '("list-live") #f #f
190 (lambda (opt name arg result)
191 (alist-cons 'action 'list-live
192 (alist-delete 'action result))))
193 (option '("references") #f #f
194 (lambda (opt name arg result)
195 (alist-cons 'action 'list-references
196 (alist-delete 'action result))))
197 (option '(#\R "requisites") #f #f
198 (lambda (opt name arg result)
199 (alist-cons 'action 'list-requisites
200 (alist-delete 'action result))))
201 (option '("referrers") #f #f
202 (lambda (opt name arg result)
203 (alist-cons 'action 'list-referrers
204 (alist-delete 'action result))))
205 (option '("derivers") #f #f
206 (lambda (opt name arg result)
207 (alist-cons 'action 'list-derivers
208 (alist-delete 'action result))))
209 (option '("list-failures") #f #f
210 (lambda (opt name arg result)
211 (alist-cons 'action 'list-failures
212 (alist-delete 'action result))))
213 (option '("clear-failures") #f #f
214 (lambda (opt name arg result)
215 (alist-cons 'action 'clear-failures
216 (alist-delete 'action result))))))
223 (define-command (guix-gc . args)
224 (synopsis "invoke the garbage collector")
226 (define (parse-options)
227 ;; Return the alist of option values.
228 (parse-command-line args %options (list %default-options)
229 #:build-options? #f))
231 (define (symlink-target file)
232 (let ((s (false-if-exception (lstat file))))
233 (if (and s (eq? 'symlink (stat:type s)))
234 (symlink-target (readlink file))
237 (define (store-directory file)
238 ;; Return the store directory that holds FILE if it's in the store,
239 ;; otherwise return FILE.
240 (or (and=> (string-match (string-append "^" (regexp-quote (%store-prefix))
243 (compose (cut string-append (%store-prefix) "/" <>)
244 (cut match:substring <> 1)))
247 (define (ensure-free-space store space)
248 ;; Attempt to have at least SPACE bytes available in STORE.
249 (let ((free (free-disk-space (%store-prefix))))
251 (info (G_ "already ~h MiBs available on ~a, nothing to do~%")
252 (/ free 1024. 1024.) (%store-prefix))
253 (let ((to-free (- space free)))
254 (info (G_ "freeing ~h MiBs~%") (/ to-free 1024. 1024.))
255 (collect-garbage store to-free)))))
257 (define (delete-generations store pattern)
258 ;; Delete the generations matching PATTERN of all the user's profiles.
259 (let ((profiles (delete-duplicates
260 (filter-map (lambda (root)
261 (and (or (zero? (getuid))
263 (generation-profile root)))
265 (for-each (lambda (profile)
266 (delete-old-generations store profile pattern))
270 ;; List all the user-owned GC roots.
271 (let ((roots (filter (if (zero? (getuid)) (const #t) user-owned?)
273 (for-each (lambda (root)
279 ;; List store items used by running processes.
280 (for-each (lambda (item)
281 (display item) (newline))
285 (let* ((opts (parse-options))
286 (store (open-connection))
287 (paths (filter-map (match-lambda
288 (('argument . arg) arg)
291 (define (assert-no-extra-arguments)
292 (unless (null? paths)
293 (leave (G_ "extraneous arguments: ~{~a ~}~%") paths)))
295 (define (list-relatives relatives)
296 (for-each (compose (lambda (path)
297 (for-each (cut simple-format #t "~a~%" <>)
298 (relatives store path)))
303 (case (assoc-ref opts 'action)
305 (assert-no-extra-arguments)
306 (let ((min-freed (assoc-ref opts 'min-freed))
307 (free-space (assoc-ref opts 'free-space)))
308 (match (assq 'delete-generations opts)
311 (delete-generations store pattern)))
314 (ensure-free-space store free-space))
316 (let-values (((paths freed) (collect-garbage store min-freed)))
317 (info (G_ "freed ~h MiBs~%") (/ freed 1024. 1024.))))
319 (let-values (((paths freed) (collect-garbage store)))
320 (info (G_ "freed ~h MiBs~%") (/ freed 1024. 1024.)))))))
322 (assert-no-extra-arguments)
325 (assert-no-extra-arguments)
328 (delete-paths store (map direct-store-path paths)))
330 (list-relatives references))
332 (list-relatives (lambda (store item)
333 (requisites store (list item)))))
335 (list-relatives referrers))
337 (list-relatives valid-derivers))
339 (assert-no-extra-arguments)
340 (optimize-store store))
342 (assert-no-extra-arguments)
343 (let ((options (assoc-ref opts 'verify-options)))
346 #:check-contents? (memq 'contents options)
347 #:repair? (memq 'repair options)))))
349 (for-each (cut simple-format #t "~a~%" <>)
350 (query-failed-paths store)))
352 (clear-failed-paths store (map direct-store-path paths)))
354 (for-each (cut simple-format #t "~a~%" <>)
357 (for-each (cut simple-format #t "~a~%" <>)
358 (live-paths store)))))))