Proper resolution of dependencies

This commit is contained in:
Justin Ethier 2016-07-11 21:19:55 -04:00
parent 8e983a9bfa
commit 8d8c6fcd06

View file

@ -304,55 +304,46 @@
;; Given a list of alists (library-name . imports), return an ordered ;; Given a list of alists (library-name . imports), return an ordered
;; list of library names such that each lib is encounted after the ;; list of library names such that each lib is encounted after the
;; libraries it imports (it's dependencies). ;; libraries it imports (it's dependencies).
(define (lib:get-dep-list libs/deps) (define lib:get-dep-list resolve-dependencies)
; Overall strategy is:
; for each library
; compute index of result that is after any libs that lib imports
; compute index of result that is before any libs that import lib
; if there is a 'hole' then insert lib into result in that space
; otherwise, throw an error (unfortunate but will identify problems)
;
; To test, run this from hello directory:
; (pp (lib:get-all-import-deps '((scheme base) (scheme eval) (scheme base)
; (scheme read) (scheme eval) (libs lib1) (libs lib2))))
;
(let ((result '()))
(for-each
(lambda (lib/dep)
(cond
((null? result)
(set! result (cons lib/dep '())))
(else
(let ((idx-my-imports 0) ; lib must be placed after this
(idx-imports-me (length result))) ; lib must be before any libs that import it
(define (loop i)
(cond
((= i (length result))
'done)
(else
;; Does lib import this one?
(if (and
(> i idx-my-imports)
(member (car (list-ref result i)) (cdr lib/dep)))
(set! idx-my-imports i))
;; Does this one import lib? ;; Goal is to resolve a list of dependencies into the appropriate order such
(if (and ;; that no node is encountered before its dependencies.
(< i idx-imports-me) ;; We also need to raise an error if a circular dependency is found
(member (car lib/dep) (cdr (list-ref result i)))) ;;
(set! idx-imports-me i)) ;; A dependency list consists of: (name . edges)
;; Where edges are all of the dependencies of name.
;;
;; nodes is a list of many dependency lists.
;;
;; Based on code from:
;; http://www.electricmonk.nl/log/2008/08/07/dependency-resolving-algorithm/
(define (resolve-dependencies nodes)
(define (append-cell! cell value) (set-cdr! cell (cons value (cdr cell))))
(define (make-cell) (cons #f '()))
(define get-cell cdr)
(define (node->edges name) (assoc name nodes))
(loop (+ i 1))))) ;; Create a new node that depends on all the others
(loop 0) (define (master-dependency)
;(pp `(JAE DEBUG ,result ,lib/dep ,idx-imports-me ,idx-my-imports)) (cons '(#f) (map car nodes)))
(if (<= idx-my-imports idx-imports-me)
(list-insert-at! result lib/dep (define (dep-resolve node resolved seen)
(if (= idx-my-imports idx-imports-me) ; DEBUG: (write node) (newline)
idx-my-imports (append-cell! seen node)
(+ 1 idx-my-imports))) (for-each
(error "Unable to import library, possibly due to a circular dependency:" lib/dep)))) (lambda (edge)
)) (cond
libs/deps) ((not (assoc edge (get-cell resolved)))
(map car result))) (if (assoc edge (get-cell seen))
(error "Circular dependency detected" node edge))
(dep-resolve (node->edges edge) resolved seen))))
(cdr (node->edges (car node))))
(append-cell! resolved node)
resolved)
(set! nodes (cons (master-dependency) nodes))
(let* ((resolved (dep-resolve (node->edges '(#f)) (make-cell) (make-cell)))
(deps (reverse (cdr (get-cell resolved))))) ;; cdr to get rid of master list
(map car deps)))
)) ))