Skip to content

Commit

Permalink
Fast dependency resolution in src/{analysis,model/project}/*.lisp
Browse files Browse the repository at this point in the history
* src/analysis/dependencies.lisp (dependency-key): new function;
  construct an index key for a dependency
  (make-provider-index): new function; make a provider index for fast
  lookup
  (index-provider!): new function; add a provider to the index
  (lookup-providers): new function; find providers for a requirement in
  an indexed table
* src/analysis/package.lisp (package jenkins.analysis): added exported
  symbols dependency-key, make-provider-index, index-provider! and
  find-providers
* src/model/project/variables.lisp (find-provider/version): use new
  `lookup-providers' function; adapted to unified provider
  representation
* src/model/project/classes-model.lisp (index-platform-provides): new
  function; make an index for the platform provides of a version
  (add-dependencies! version): use `index-platform-provides'
* src/model/project/classes-spec.lisp (instantiate distribution-spec):
  use new index provider machinery to build per-distribution provider
  index and use it to resolve dependencies
  • Loading branch information
scymtym committed May 21, 2019
1 parent df0b3d6 commit 69766f7
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 24 deletions.
20 changes: 20 additions & 0 deletions src/analysis/dependencies.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,23 @@
current)))))
dependencies)
(hash-table-values seen)))

;;; Indexed dependencies

(defun dependency-key (dependency)
(let+ (((nature target &optional version) dependency))
(cond
((eq nature :cmake) (list nature (string-downcase target)))
(version (list nature target))
(t dependency))))

(defun make-provider-index ()
(make-hash-table :test #'equal))

(defun index-provider! (provided provider index)
(let ((key (jenkins.analysis:dependency-key provided)))
(push (cons provided provider) (gethash key index '()))
index))

(defun lookup-providers (required index)
(gethash (dependency-key required) index))
7 changes: 6 additions & 1 deletion src/analysis/package.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,12 @@
#:dependency-matches?

#:merge-dependencies
#:effective-requires)
#:effective-requires

#:dependency-key
#:make-provider-index
#:index-provider!
#:lookup-providers)

;; Analysis protocol
(:export
Expand Down
14 changes: 11 additions & 3 deletions src/model/project/classes-model.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,13 @@
(defmethod direct-platform-dependencies ((thing version))
(map 'list #'car (%direct-platform-dependencies thing)))

(defun index-platform-provides (thing)
(with-simple-restart (continue "~@<Do not compute platform provides.~@:>")
(reduce (lambda+ (index (dependency . provider))
(jenkins.analysis:index-provider! dependency provider index))
(platform-provides thing)
:initial-value (jenkins.analysis:make-provider-index))))

(defmethod model:add-dependencies! ((thing version)
&key
(providers (missing-required-argument :providers)))
Expand All @@ -318,7 +325,7 @@
(if platform-provides?
platform-provides
(setf platform-provides? t
platform-provides (platform-provides thing)))))
platform-provides (index-platform-provides thing)))))
((&flet add-dependency (required provider)
(let ((cell (or (assoc provider (%direct-dependencies thing))
(let ((new (cons provider '())))
Expand All @@ -344,8 +351,9 @@
(add-dependency requires match))
t))
;; Search in platform-provided features.
((when-let ((provider (find-provider/version
requires (platform-provides))))
((when-let* ((platform-provides (platform-provides))
(provider (find-provider/version
requires platform-provides)))
(typecase provider
(platform-dependency
(add-platform-dependency requires provider))
Expand Down
25 changes: 13 additions & 12 deletions src/model/project/classes-spec.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -135,20 +135,21 @@
;; and transitive) with include contexts.
(versions (append (mapcan #'make-version (direct-versions spec))
(mappend #'one-distribution-include
(direct-includes spec))))
(providers (make-hash-table :test #'equal)))
(direct-includes spec)))))

;; Build a table of provided things and providers.
(map nil (lambda (version)
(map nil (lambda (provided)
(push version (gethash provided providers '())))
(provides version)))
versions)

;; After all `version' instances have been made, resolve
;; dependencies among them.
(let ((providers (hash-table-alist providers)))
(map nil (rcurry #'model:add-dependencies! :providers providers) versions))
(let ((provider-index (jenkins.analysis:make-provider-index)))
(map nil (lambda (version)
(map nil (rcurry #'jenkins.analysis:index-provider!
version provider-index)
(provides version)))
versions)

;; After all `version' instances have been made, resolve
;; dependencies among them.
(map nil (rcurry #'model:add-dependencies! :providers provider-index)
versions))

(reinitialize-instance distribution :versions versions)))

;;; `project-spec' class
Expand Down
11 changes: 3 additions & 8 deletions src/model/project/variables.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,15 @@
(version-better (third (car left)) (third (car right)))))
;; Find providers in PROVIDERS which can provide the required
;; NATURE, TARGET and VERSION of SPEC.
(candidates (jenkins.analysis:lookup-providers required providers))
(candidates (remove-if-not
(curry #'jenkins.analysis:dependency-matches? required)
providers :key #'car))
candidates :key #'car))
;; Sort CANDIDATES according to PROVIDER-BETTER (which may
;; use ORDER).
(candidates (stable-sort candidates #'provider-better)))
;; Take the best candidate or act according to IF-DOES-NOT-EXIST.
(or (when-let ((providers (cdr (first candidates))))
(cond ((eq providers :system-package)
providers)
((typep providers 'platform-dependency)
providers)
(t
(first providers))))
(or (cdr (first candidates))
(error-behavior-restart-case
(if-does-not-exist
(jenkins.analysis:unfulfilled-project-dependency-error
Expand Down

0 comments on commit 69766f7

Please sign in to comment.