all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
blob 448d83d84449b6ba394114bb3f07ced45bb55e1c 10967 bytes (raw)
name: guix/scripts/dependencies.scm 	 # note: path name is non-authoritative(*)

  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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
 
;; FIXME: copyright

(define-module (guix scripts dependencies)
  #:use-module (srfi srfi-9)
  #:use-module (srfi srfi-9 gnu)
  #:use-module (srfi srfi-11)
  #:use-module (ice-9 rdelim)
  #:use-module (guix packages)
  #:use-module (gnu packages audio)
  #:export (display-dependencies))


;; Immutable graph datastructure

;; FIXME: Taken from Guile, should be in (srfi srfi-99)
;;        adapted to make it possible to declare record type like `<abc>' and keep
;;        field accessor bracket free. record name *must* have brackets or everything
;;        is broken
;;
;; Usage:
;;
;;   (define-record-type <abc> field-one field-two)
;;   (define zzz (make-abc 1 2))
;;   (abc-field-one zzz) ;; => 1
;;
;; FIXME: maybe this is less useful than the immutable record of (srfi srfi-9 gnu)
;;        Right I will use `set-field` and `set-fields`
(define-syntax define-record-type*
  (lambda (x)
    (define (%id-name name) (string->symbol (string-drop (string-drop-right (symbol->string name) 1) 1)))
    (define (id-name ctx name)
      (datum->syntax ctx (%id-name (syntax->datum name))))
    (define (id-append ctx . syms)
      (datum->syntax ctx (apply symbol-append (map syntax->datum syms))))
    (syntax-case x ()
      ((_ rname field ...)
       (and (identifier? #'rname) (and-map identifier? #'(field ...)))
       (with-syntax ((cons (id-append #'rname #'make- (id-name #'rname #'rname)))
                     (pred (id-append #'rname (id-name #'rname #'rname) #'?))
                     ((getter ...) (map (lambda (f)
                                          (id-append f (id-name #'rname #'rname) #'- f))
                                        #'(field ...))))
         #'(define-record-type rname
             (cons field ...)
             pred
             (field getter)
             ...))))))

(define-record-type* <node> identifier label outgoings incomings properties)


;;;
;;; Store
;;;
;;; Memory bound immutable association
;;;


;; XXX: It's assumed that keys are strings.
;;
;; This replace scheme assoc, because:
;; 1) there is no immutable `assoc-set` in scheme
;; 2) `acons` (and friends) can replace `assoc-set` but memory will grow without bound
;; 3) `assoc-ref` (and friends) always return `#f` when no values is found
;; 4) `vlist` and else can not be easily written to disk
;; 5) It's fun


(define (store-set store key value)
  "Return a copy of STORE where KEY is set to VALUE"
  (let loop ((assoc store)
             (out '()))
    (if (null? assoc)
        (cons (cons key value) out)
        (if (equal? (caar assoc) key)
            (append (list (cons key value)) out (cdr assoc))
            (loop (cdr assoc) (cons (car assoc) out))))))


(define (store-ref store key)
  "Return the value of KEY in STORE, if KEY is not found return #nil"
  (let loop ((assoc store))
    (if (null? assoc)
        #nil
        (if (equal? (caar assoc) key)
            (cdar assoc)
            (loop (cdr assoc))))))

(define (store-del store key)
  "Return a copy of STORE where the KEY association doesn't exists"
  (let loop ((assoc store)
             (out '()))
    (if (null? assoc)
        store
        (if (equal? (caar assoc) key)
            (append out (cdr assoc))
            (loop (cdr assoc) (cons (car assoc) out))))))


;;;
;;; Graph
;;;

(define-record-type* <graph> label nodes edges properties)


(set-record-type-printer! <graph>
  (lambda (record port)
    (display "<graph  label: \"" port)
    (display (graph-label record) port)
    (display "\" nodes: " port)
    (display (length (graph-nodes record)) port)
    (display " edges: " port)
    (display (length (graph-edges record)) port)
    (display " properties: " port)
    (display (length (graph-properties record)) port)
    (display ">" port)))

(define (create-graph label)
  (make-graph label '() '() '()))

(define (graph-get-uid store)
  (define CHARS "AZERTYUIOPQSDFGHJKLMWXCVBN1029384756")

  (define (random-id)
    (let loop ((count 4)
               (id ""))
      (if (eq? count 0)
          id
          (loop (1- count) (format #f "~a~a" id (string-ref CHARS (random 36)))))))

  (let loop ()
    (let ((id (random-id)))
      (if (null? (store-ref store id))
          id
          (loop)))))

;; properties get/set/ref

(define (graph-property-set graph key value)
  (let* ((properties (graph-properties graph)))
    (set-field graph (graph-properties) (store-set properties key value))))

(define (graph-property-del graph key)
  (let* ((properties (graph-properties graph)))
    (set-field graph (graph-properties) (store-del properties key))))

(define (graph-property-ref graph key)
  (let* ((properties (graph-properties graph)))
    (store-ref properties key)))


;;;
;;; Node
;;;

(define-record-type* <node> identifier label outgoings incomings properties)

(define (graph-create-node graph label)
  (let* ((uid (graph-get-uid (graph-nodes graph)))
         (node (make-node uid label '() '() '()))
         (graph (set-field graph (graph-nodes) (store-set (graph-nodes graph) uid node))))
    (values graph (node-identifier node))))

(define (graph-node-ref graph uid)
  (store-ref (graph-nodes graph) uid))

(define (graph-node-label-ref graph label)
  (graph-node-ref graph (graph-property-ref graph label)))

(define (graph-node-property-set graph uid key value)
  (let* ((node (graph-node-ref graph uid))
        (properties (node-properties node))
        (node (set-field  node (node-properties) (store-set properties key value)))
        (nodes (graph-nodes graph)))
    (set-field graph (graph-nodes) (store-set nodes uid node))))

(define (graph-node-property-del graph uid key)
  (let* ((node (graph-node-ref graph uid))
        (properties (node-properties node))
        (node (set-field  node (node-properties) (store-del properties key)))
        (nodes (graph-nodes graph)))
    (set-field graph (graph-nodes) (store-set nodes uid node))))

(define (graph-node-property-ref graph uid key)
  (let* ((node (graph-node-ref graph uid))
         (properties (node-properties node)))
    (store-ref properties key)))

(define (%graph-node-edges graph uid edges-getter)
  (let loop ((edges (edges-getter (graph-edge-ref graph uid)))
             (out '()))
    (if (null? edges)
        out
        (loop (cdr edges) (cons (graph-edge-ref graph (car edges)) out)))))

(define (graph-node-outgoings graph uid)
  (%graph-node-edges graph uid node-outgoings))

(define (graph-node-incomings graph uid)
  (%graph-node-edges graph uid node-incomings))

;;;
;;; Edge
;;;

(define-record-type* <edge> identifier start label end properties)

(define (graph-create-edge graph start label end)
  (let* ((uid (graph-get-uid (graph-edges graph)))
         (edge (make-edge uid start label end '()))
         (nodes (graph-nodes graph))

         ;; add edge to `outgoings` of `start` node
         (start-node (graph-node-ref graph start))
         (outgoings (node-outgoings start-node))
         (outgoings (cons uid outgoings))
         (start-node (set-field start-node (node-outgoings) outgoings))
         (nodes (store-set nodes start start-node))

         ;; add edge to `incomings` of `end` node
         (end-node (graph-node-ref graph end))
         (incomings (node-incomings end-node))
         (incomings (cons uid incomings))
         (end-node (set-field end-node (node-incomings) incomings))
         (nodes (store-set nodes end end-node))

         ;; updates `nodes` field
         (graph (set-field graph (graph-nodes) nodes)))
    (values (set-field graph (graph-edges) (store-set (graph-edges graph) uid edge))
            (edge-identifier edge))))

(define (graph-edge-ref graph uid)
  (store-ref (graph-edges graph) uid))

(define (graph-edge-property-set graph uid key value)
  (let* ((edge (graph-edge-ref graph uid))
        (properties (edge-properties edge))
        (edge (set-field  edge (edge-properties) (store-set properties key value)))
        (edges (graph-edges graph)))
    (set-field graph (graph-edges) (store-set edges uid edge))))

(define (graph-edge-property-del graph uid key)
  (let* ((edge (graph-edge-ref graph uid))
        (properties (edge-properties edge))
        (edge (set-field  edge (edge-properties) (store-del properties key)))
        (edges (graph-edges graph)))
    (set-field graph (graph-edges) (store-set edges uid edge))))

(define (graph-edge-property-ref graph uid key)
  (let* ((edge (graph-edge-ref graph uid))
         (properties (edge-properties edge)))
    (store-ref properties key)))

(define (graph-edge-start graph uid)
  (let* ((edge (graph-edge-ref graph uid)))
    (graph-node-ref graph (edge-start edge))))

(define (graph-edge-end graph uid)
  (let* ((edge (graph-edge-ref graph uid)))
    (graph-node-ref graph (edge-end edge))))


;; Build dependency graph of a guix package

(define (maybe-create-node graph label)
  (if (graph-property-ref graph label)
      (values graph (graph-property-ref graph label))
      (let-values (((graph uid) (graph-create-node graph label)))
        (values (graph-property-set graph label uid) uid))))

(define (maybe-create-edge graph start label end)
  (if (graph-property-ref graph label)
      (values graph (graph-property-ref graph label))
      (let-values (((graph uid) (graph-create-edge graph start label end)))
        (values (graph-property-set graph label uid) uid))))

(define (package-dependency-graph package graph)
  (let loop ((packages (package-inputs package))
             (graph graph))
    (if (null? packages)
        graph
        (if (package? (cadar packages))
            (let ((dependency (package-name (cadar packages))))
              (let*-values (((graph package-uid) (maybe-create-node graph (package-name package)))
                            ((graph dependency-uid) (maybe-create-node graph dependency)))
                (let* ((label (string-append (package-name (cadar packages)) "--(depends)-->" dependency))
                       (graph (maybe-create-edge graph package-uid label dependency-uid))
                       (graph (package-dependency-graph (cadar packages) graph)))
                (loop (cdr packages) graph))))
            (loop (cdr packages) graph)))))

(define (graph-dot graph port)
  (format port
          "digraph \"dependency graph of ~a\" {\n\tratio = \"auto\";\n\tmincross = 3.0;\n\tlabel = \"~a\"\n\n"
          (graph-label graph)
          (graph-label graph))
  (let loop ((edges (graph-edges graph)))
    (if (null? edges)
        (format port "\n}\n")
        (begin
          (format port "\t\"~a\" -> \"~a\";\n"
                  (node-label (graph-node-ref graph (edge-start (cdar edges))))
                  (node-label (graph-node-ref graph (edge-end (cdar edges)))))
          (loop (cdr edges))))))


(define (display-dependencies package port)
  (let* ((graph (create-graph (string-append "dependencies of " (package-name package))))
         (graph (package-dependency-graph package graph)))
    (graph-dot graph port)
    graph))

debug log:

solving 448d83d ...
found 448d83d in https://yhetil.org/guix/3a40a61b01f71c422f8fd787fbfbeddf@hypermove.net/

applying [1/1] https://yhetil.org/guix/3a40a61b01f71c422f8fd787fbfbeddf@hypermove.net/
diff --git a/guix/scripts/dependencies.scm b/guix/scripts/dependencies.scm
new file mode 100644
index 0000000..448d83d

Checking patch guix/scripts/dependencies.scm...
Applied patch guix/scripts/dependencies.scm cleanly.

index at:
100644 448d83d84449b6ba394114bb3f07ced45bb55e1c	guix/scripts/dependencies.scm

(*) Git path names are given by the tree(s) the blob belongs to.
    Blobs themselves have no identifier aside from the hash of its contents.^

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.