~evhan/beaker

ref: 49dd5955acf9287ec5ba0503e8c30e6e81b3e746 beaker/chicken-lock.scm -rw-r--r-- 3.9 KiB
49dd5955Evan Hanson Document Nix helpers 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Generate an override file for egg dependencies.
;;;
;;; Copyright (c) 2021, Evan Hanson
;;;
;;; See LICENSE for details.
;;;

;;
;; The `chicken-lock` program generates a snapshot of all dependency versions
;; for the given eggs, or for any egg files in the current directory.
;;
;; The output is an override file that can then be used to install those same
;; versions later on via the "-override" or "-from-list" flags to `chicken-install`.
;; For example, you can record the current version of the r7rs egg and all of
;; its dependencies, and then restore them later, like this:
;;
;;     $ chicken-lock r7rs > r7rs.lock
;;     ... time passes...
;;     $ chicken-install -override r7rs.lock r7rs
;;
;; If no egg names are given on the command line, this program will look for
;; egg files in the current directory. This can be used to record the current
;; version of all dependencies for an egg in local development:
;;
;;     $ cat example.egg
;;     ((synopsis "A nice example library")
;;      (build-dependencies matchable)
;;      (dependencies r7rs)
;;      (components (extension example)))
;;     $ chicken-lock > example.egg.lock
;;     ... time passes ...
;;     $ chicken-install -override example.egg.lock
;;
;; Any extra arguments are passed through to `chicken-install` when fetching
;; eggs. So, you can use "-override" to fix some subset of an egg's dependency
;; versions when generating the snapshot, as well as other options like
;; "-verbose" to print more information about what's happening.
;;
(declare
  (module (chicken-lock))
  (import (beaker repository)
          (beaker egg info)
          (chicken condition)
          (chicken errno)
          (chicken file)
          (chicken file posix)
          (chicken format)
          (chicken gc)
          (chicken pathname)
          (chicken pretty-print)
          (chicken process)
          (chicken process-context)
          (chicken string)))

(define (usage status)
  (printf "Usage: ~a [egg ...]" (pathname-file (program-name)))
  (print)
  (exit status))

(define (create-temporary-directory*)
  (set-finalizer!
   (create-temporary-directory)
   (lambda (d)
     (condition-case (delete-directory d #t)
       (e (i/o file)
          (unless (= (errno) errno/noent)
            (signal e)))))))

(define (retrieve-eggs #!optional (eggs '()) (env '()))
  (receive (_ _ status) (process-wait
                         (process-fork
                          (lambda ()
                            (duplicate-fileno fileno/stderr fileno/stdout)
                            (process-execute
                             (chicken-install)
                             (append (list "-retrieve" "-recursive") eggs)
                             (merge-environment-variables env (get-environment-variables))))))
    (unless (zero? status) (exit status))))

(define (cached-eggs #!optional (eggs '()) (env '()))
  (let ((cache (alist-ref "CHICKEN_EGG_CACHE" env string=?)))
    (foldl (lambda (eggs dir)
             (cons (list (pathname-file dir)
                         (call-with-input-file (make-pathname dir "VERSION") read))
                   eggs))
           (list)
           (glob (make-pathname cache "*")))))

(define (generate-overrides #!optional (eggs '()))
  (let* ((cache (create-temporary-directory*))
         (repo  (create-temporary-directory*))
         (env   (list (cons "CHICKEN_EGG_CACHE" cache)
                      (cons "CHICKEN_INSTALL_REPOSITORY" repo)
                      (cons "CHICKEN_REPOSITORY_PATH" repo))))
    (retrieve-eggs eggs env)
    (for-each pretty-print (cached-eggs eggs env))))

(define (main)
  (let ((args '()))
    ((flip for-each)
     (command-line-arguments)
     (lambda (arg)
       (if (member arg '("-h" "-help" "--help"))
           (usage 0)
           (set! args (cons arg args)))))
  (generate-overrides (reverse args))))

(cond-expand
  (compiling (main))
  (else))