From f003b6a2794b2071f0c2d3cfa783f28670645fa4 Mon Sep 17 00:00:00 2001 From: Hugo Thunnissen Date: Sat, 5 Aug 2023 00:52:07 +0200 Subject: [PATCH] Make project indexation asynchronous using `phpinspect-pipeline' --- phpinspect-autoload.el | 291 +++++++++++++++++++++++++---------------- phpinspect-cache.el | 6 +- phpinspect-fs.el | 5 +- phpinspect-pipeline.el | 115 ++++++++-------- phpinspect.el | 14 +- test/test-autoload.el | 132 +++++++++---------- 6 files changed, 313 insertions(+), 250 deletions(-) diff --git a/phpinspect-autoload.el b/phpinspect-autoload.el index 8245be3..cb7cca9 100644 --- a/phpinspect-autoload.el +++ b/phpinspect-autoload.el @@ -27,12 +27,19 @@ (require 'phpinspect-project) (require 'phpinspect-fs) (require 'phpinspect-util) +(require 'phpinspect-pipeline) (cl-defstruct (phpinspect-psr0 (:constructor phpinspect-make-psr0-generated)) (prefix nil :type string :documentation "The namespace prefix for which the directories contain code.") + (autoloader nil + :type phpinspect-autoloader) + (own nil + :type boolean) + (fs nil + :type phpinspect-fs) (directories nil :type list :documentation @@ -43,17 +50,17 @@ (prefix nil :type string :documentation "The namespace prefix for which the directories contain code.") + (autoloader nil + :type phpinspect-autoloader) + (own nil + :type boolean) + (fs nil + :type phpinspect-fs) (directories nil :type list :documentation "The directories that this autoloader finds code in.")) -(cl-defstruct (phpinspect-classmap - (:constructor phpinspect-make-classmap-generated)) - (directories nil - :type list - :documentation - "The directories that this autoloader finds code in.")) (cl-defstruct (phpinspect-autoloader (:constructor phpinspect-make-autoloader)) @@ -75,34 +82,29 @@ qualified names congruent with a bareword type name. Keyed by bareword typenames.")) -(defun phpinspect-make-autoload-definition-closure (project-root fs typehash) - "Create a closure that can be used to `maphash' the autoload -section of a composer-json." - (lambda (type prefixes) - (let ((strategy)) - (cond - ((string= "psr-0" type) - (maphash - (lambda (prefix directory-paths) - (when (stringp directory-paths) (setq directory-paths (list directory-paths))) - (setq strategy (phpinspect-make-psr0-generated :prefix prefix)) - (dolist (path directory-paths) - (push (concat project-root "/" path) - (phpinspect-psr0-directories strategy)))) - prefixes)) - ((string= "psr-4" type) - (maphash - (lambda (prefix directory-paths) - (when (stringp directory-paths) (setq directory-paths (list directory-paths))) - (setq strategy (phpinspect-make-psr4-generated :prefix prefix)) - (dolist (path directory-paths) - (push (concat project-root "/" path) - (phpinspect-psr4-directories strategy)))) - prefixes)) - (t (phpinspect--log "Unsupported autoload strategy \"%s\" encountered" type))) - - (when strategy - (phpinspect-al-strategy-fill-typehash strategy fs typehash))))) +;; (define-inline phpinspect-directory-lister (dirs &optional fs) +;; (inline-letevals (dirs fs) +;; (inline-quote +;; (let* ((directory (pop ,dirs)) +;; (files +;; (phpinspect-fs-directory-files ,fs directory)) +;; listing) +;; (dolist (file files) +;; (if (phpinspect-fs-file-directory-p ,fs file) +;; (push file ,dirs) +;; (push file listing))) + +;; listing)))) + +;; (phpinspect-define-pipeline-step phpinspect-directory-lister phpinspect-directory-lister) + +(cl-defstruct (phpinspect-cj-iter-ctx (:constructor phpinspect-make-cj-iter-ctx)) + (autoloader nil + :type phpinspect-autoloader) + (compiled-dirs nil + :type boolean) + (dirs nil + :type list)) (cl-defmethod phpinspect--read-json-file (fs file) (with-temp-buffer @@ -110,100 +112,161 @@ section of a composer-json." (goto-char 0) (phpinspect-json-preset (json-read)))) -(cl-defmethod phpinspect-autoloader-refresh ((autoloader phpinspect-autoloader)) - "Refresh autoload definitions by reading composer.json files - from the project and vendor folders." - (let* ((project-root (phpinspect-project-root (phpinspect-autoloader-project autoloader))) - (fs (phpinspect-project-fs (phpinspect-autoloader-project autoloader))) - (vendor-dir (concat project-root "/vendor")) - (composer-json-path (concat project-root "/composer.json")) - (composer-json) - (project-autoload ) - (type-name-fqn-bags (make-hash-table :test 'eq :size 3000 :rehash-size 3000)) - (own-types (make-hash-table :test 'eq :size 10000 :rehash-size 10000)) - (types (make-hash-table :test 'eq :size 10000 :rehash-size 10000))) - - (when (phpinspect-fs-file-exists-p fs composer-json-path) - (setq composer-json (phpinspect--read-json-file fs composer-json-path)) - - (if (hash-table-p composer-json) - (setq project-autoload (gethash "autoload" composer-json)) - (phpinspect--log "Error: Parsing %s did not return a hashmap." - composer-json-path))) +(define-inline phpinspect-filename-to-typename (dir filename &optional prefix) + (inline-quote + (phpinspect-intern-name + (replace-regexp-in-string + "[\\\\]+" + "\\\\" + (concat "\\" + (or ,prefix "") + (replace-regexp-in-string + "/" "\\\\" + (string-remove-suffix + ".php" + (string-remove-prefix ,dir ,filename)))))))) - - (when project-autoload - (maphash (phpinspect-make-autoload-definition-closure project-root fs own-types) - project-autoload) - - (maphash (phpinspect-make-autoload-definition-closure project-root fs types) - project-autoload)) +(defun phpinspect-find-composer-json-files (fs project-root) + (let ((cj-path (concat project-root "/composer.json")) + (vendor-dir (concat project-root "/vendor")) + files) + (when (phpinspect-fs-file-exists-p fs cj-path) + (push `(local . ,cj-path) files)) (when (phpinspect-fs-file-directory-p fs vendor-dir) (dolist (author-dir (phpinspect-fs-directory-files fs vendor-dir)) (when (phpinspect-fs-file-directory-p fs author-dir) (dolist (dependency-dir (phpinspect-fs-directory-files fs author-dir)) + (setq cj-path (concat dependency-dir "/composer.json")) (when (and (phpinspect-fs-file-directory-p fs dependency-dir) - (phpinspect-fs-file-exists-p fs (concat dependency-dir "/composer.json"))) - (let* ((dependency-json (phpinspect--read-json-file - fs - (concat dependency-dir "/composer.json"))) - (dependency-autoload (gethash "autoload" dependency-json))) - (when dependency-autoload - (maphash (phpinspect-make-autoload-definition-closure - dependency-dir fs types) - dependency-autoload)))))))) - - (maphash (lambda (type-fqn _) - (let* ((type-name (phpinspect-intern-name - (car (last (split-string (symbol-name type-fqn) "\\\\"))))) - (bag (gethash type-name type-name-fqn-bags))) - (push type-fqn bag) - (puthash type-name bag type-name-fqn-bags))) - types) - - (setf (phpinspect-autoloader-own-types autoloader) own-types) - (setf (phpinspect-autoloader-types autoloader) types) - (setf (phpinspect-autoloader-type-name-fqn-bags autoloader) - type-name-fqn-bags))) + (phpinspect-fs-file-exists-p fs cj-path)) + (push `(vendor . ,cj-path) files)))))) + files)) + +(cl-defmethod phpinspect-al-strategy-execute ((strat phpinspect-psr4)) + (let* ((fs (phpinspect-psr4-fs strat)) + (al (phpinspect-psr4-autoloader strat)) + (own (phpinspect-psr4-own strat)) + (own-typehash (phpinspect-autoloader-own-types al)) + (typehash (phpinspect-autoloader-types al)) + (prefix (phpinspect-psr4-prefix strat)) + type-fqn) + (dolist (dir (phpinspect-psr4-directories strat)) + (dolist (file (phpinspect-fs-directory-files-recursively fs dir "\\.php$")) + (setq type-fqn (phpinspect-filename-to-typename dir file prefix)) + (phpinspect-autoloader-put-type-bag al type-fqn) + (puthash type-fqn file typehash) + (when own + (puthash type-fqn file own-typehash)))))) + +(cl-defmethod phpinspect-al-strategy-execute ((strat phpinspect-psr0)) + (let* ((fs (phpinspect-psr0-fs strat)) + (al (phpinspect-psr0-autoloader strat)) + (own (phpinspect-psr0-own strat)) + (own-typehash (phpinspect-autoloader-own-types al)) + (typehash (phpinspect-autoloader-types al)) + type-fqn) + (dolist (dir (phpinspect-psr0-directories strat)) + (dolist (file (phpinspect-fs-directory-files-recursively fs dir "\\.php$")) + (setq type-fqn (phpinspect-filename-to-typename dir file)) + (phpinspect-autoloader-put-type-bag al type-fqn) + (puthash type-fqn file typehash) + (when own + (puthash type-fqn file own-typehash)))))) + +(cl-defmethod phpinspect-autoloader-put-type-bag ((al phpinspect-autoloader) (type-fqn symbol)) + (let* ((type-name (phpinspect-intern-name + (car (last (split-string (symbol-name type-fqn) "\\\\"))))) + (bag (gethash type-name (phpinspect-autoloader-type-name-fqn-bags al)))) + (if bag + (push type-fqn bag) + (push type-fqn bag) + (puthash type-name bag (phpinspect-autoloader-type-name-fqn-bags al))))) + + +(phpinspect-define-pipeline-step phpinspect-al-strategy-execute phpinspect-al-strategy-execute) + +(cl-defmethod phpinspect-iterate-composer-jsons + ((al phpinspect-autoloader) file) + (let* ((fs (phpinspect-project-fs (phpinspect-autoloader-project al))) + (project-root (file-name-directory (cdr file))) + (json (phpinspect--read-json-file fs (cdr file))) + (autoload (gethash "autoload" json)) + batch) + (when (hash-table-p autoload) + (maphash + (lambda (type prefixes) + (let ((strategy)) + (pcase type + ("psr-0" + (maphash + (lambda (prefix directory-paths) + (when (stringp directory-paths) + (setq directory-paths (list directory-paths))) + (setq strategy (phpinspect-make-psr0-generated + :autoloader al + :fs fs + :prefix prefix + :own (eq 'local (car file)))) + (dolist (path directory-paths) + (push (file-name-concat project-root path) + (phpinspect-psr0-directories strategy)))) + prefixes)) + ("psr-4" + (maphash + (lambda (prefix directory-paths) + (when (stringp directory-paths) + (setq directory-paths (list directory-paths))) + (setq strategy (phpinspect-make-psr4-generated + :fs fs + :autoloader al + :prefix prefix + :own (eq 'local (car file)))) + (dolist (path directory-paths) + (push (file-name-concat project-root path) + (phpinspect-psr4-directories strategy)))) + prefixes)) + (_ (phpinspect--log "Unsupported autoload strategy \"%s\" encountered" type))) + + (push strategy batch))) + autoload) + (phpinspect-pipeline-emit-all batch)))) + +(phpinspect-define-pipeline-step phpinspect-iterate-composer-jsons + phpinspect-iterate-composer-jsons) (cl-defmethod phpinspect-autoloader-resolve ((autoloader phpinspect-autoloader) typename-symbol) (or (gethash typename-symbol (phpinspect-autoloader-own-types autoloader)) (gethash typename-symbol (phpinspect-autoloader-types autoloader)))) +(cl-defmethod phpinspect-autoloader-refresh ((autoloader phpinspect-autoloader) &optional async-callback) + "Refresh autoload definitions by reading composer.json files + from the project and vendor folders." + (let* ((project-root (phpinspect-project-root (phpinspect-autoloader-project autoloader))) + (fs (phpinspect-project-fs (phpinspect-autoloader-project autoloader))) + result error) + (setf (phpinspect-autoloader-type-name-fqn-bags autoloader) + (make-hash-table :test 'eq :size 3000 :rehash-size 3000)) + (setf (phpinspect-autoloader-own-types autoloader) + (make-hash-table :test 'eq :size 10000 :rehash-size 10000)) + (setf (phpinspect-autoloader-types autoloader) + (make-hash-table :test 'eq :size 10000 :rehash-size 10000)) + + (phpinspect-pipeline (phpinspect-find-composer-json-files fs project-root) + :async (or async-callback + (lambda (_result error) + (if error + (message "Error during autoloader refresh: %s" error) + (message (concat "Refreshed project autoloader. Found %d types within project," + " %d types total.") + (hash-table-count (phpinspect-autoloader-own-types autoloader)) + (hash-table-count (phpinspect-autoloader-types autoloader)))))) + :into (phpinspect-iterate-composer-jsons :with-context autoloader) + :into phpinspect-al-strategy-execute))) + +(cl-defmethod phpinspect-autoloader-refresh -(cl-defgeneric phpinspect-al-strategy-fill-typehash (strategy fs typehash) - "Make STRATEGY return a map with type names as keys and the - paths to the files they are defined in as values.") - -(defsubst phpinspect-filename-to-typename (dir filename &optional prefix) - (phpinspect-intern-name - (replace-regexp-in-string - "[\\\\]+" - "\\\\" - (concat "\\" - (or prefix "") - (replace-regexp-in-string - "/" "\\\\" - (string-remove-suffix - ".php" - (string-remove-prefix dir filename))))))) - -(cl-defmethod phpinspect-al-strategy-fill-typehash ((strategy phpinspect-psr0) - fs - typehash) - (dolist (dir (phpinspect-psr0-directories strategy)) - (dolist (file (phpinspect-fs-directory-files-recursively fs dir "\\.php$")) - (puthash (phpinspect-filename-to-typename dir file) file typehash)))) - -(cl-defmethod phpinspect-al-strategy-fill-typehash ((strategy phpinspect-psr4) - fs - typehash) - (let ((prefix (phpinspect-psr4-prefix strategy))) - (dolist (dir (phpinspect-psr4-directories strategy)) - (dolist (file (phpinspect-fs-directory-files-recursively fs dir "\\.php$")) - (puthash (phpinspect-filename-to-typename dir file prefix) file typehash))))) (provide 'phpinspect-autoload) ;;; phpinspect-autoload.el ends here diff --git a/phpinspect-cache.el b/phpinspect-cache.el index b5b0182..54a5507 100644 --- a/phpinspect-cache.el +++ b/phpinspect-cache.el @@ -55,9 +55,9 @@ then returned." :root project-root :worker (phpinspect-make-dynamic-worker)) (phpinspect--cache-projects cache))) - (let ((autoload (phpinspect-make-autoloader :project project))) - (setf (phpinspect-project-autoload project) autoload) - (phpinspect-autoloader-refresh autoload))) + (let ((autoloader (phpinspect-make-autoloader :project project))) + (setf (phpinspect-project-autoload project) autoloader) + (phpinspect-autoloader-refresh autoloader))) project)) (provide 'phpinspect-cache) diff --git a/phpinspect-fs.el b/phpinspect-fs.el index 0a9aece..ab293ef 100644 --- a/phpinspect-fs.el +++ b/phpinspect-fs.el @@ -41,9 +41,8 @@ (defalias 'phpinspect-virtual-file-modification-time #'cadr) (defalias 'phpinspect-virtual-file-contents #'car) -(cl-defmethod phpinspect-virtual-fs-set-file ((fs phpinspect-virtual-fs) - path - contents) +(defun phpinspect-virtual-fs-set-file (fs path contents) + (declare (indent defun)) (puthash path (phpinspect-make-virtual-file contents) (phpinspect-virtual-fs-files fs))) diff --git a/phpinspect-pipeline.el b/phpinspect-pipeline.el index 456243c..77cd704 100644 --- a/phpinspect-pipeline.el +++ b/phpinspect-pipeline.el @@ -70,7 +70,7 @@ thread-live (thread-live-p (car thread))) (when thread-live - (if ended + (if end (setq errors (nconc errors (list (format "Thread %s ended pipeline, but is still running" (thread-name (car thread)))))) (setq errors (nconc errors (list (format "Thread %s is still running when pipeline is closing" @@ -91,13 +91,19 @@ (signal 'phpinspect-pipeline-error errors)))) -(defmacro phpinspect-pipeline-emit (data) - `(throw 'phpinspect-pipeline-emit ,data)) +(define-inline phpinspect-pipeline-emit (data) + (inline-letevals (data) + (inline-quote + (throw 'phpinspect-pipeline-emit ,data)))) -(defmacro phpinspect-pipeline-emit-all (collection) - `(throw 'phpinspect-pipeline-emit - (phpinspect-make-pipeline-emission - :collection ,collection))) +(define-inline phpinspect-pipeline-emit-all (collection) + (inline-letevals (collection) + (inline-quote + (throw 'phpinspect-pipeline-emit + (if ,collection + (phpinspect-make-pipeline-emission + :collection ,collection) + ,collection))))) (defmacro phpinspect-pipeline-end (&optional value) (if value @@ -197,8 +203,8 @@ (end-queue-sym (gensym "end-queue")) (ctx-sym (gensym "ctx")) (recv-sym (gensym)) - (errors (gensym)) (result-sym (gensym)) + (seed-sym (gensym)) (collecting-sym (gensym))) `(progn (when (eq main-thread (current-thread)) @@ -209,13 +215,15 @@ (,queue-sym (phpinspect-make-queue)) (,end-queue-sym (phpinspect-make-queue)) (,collecting-sym t) - ,recv-sym ,result-sym) + ,recv-sym ,result-sym ,seed-sym) ,(phpinspect--chain-pipeline-steps steps queue-sym end-queue-sym ctx-sym) - (phpinspect-pipeline--enqueue - ,queue-sym - (phpinspect-make-pipeline-emission :collection ,seed-form) 'no-notify) + (setq ,seed-sym ,seed-form) + (when ,seed-sym + (phpinspect-pipeline--enqueue + ,queue-sym + (phpinspect-make-pipeline-emission :collection ,seed-form) 'no-notify)) (phpinspect-pipeline--enqueue ,queue-sym (phpinspect-make-pipeline-end :thread (current-thread))) @@ -249,7 +257,7 @@ (lambda () (condition-case err (let ((,result ,(append '(phpinspect--pipeline) (list seed-form) macro-params))) - (funcall ,async ,result nil)) + (funcall ,async (or ,result 'phpinspect-pipeline-nil-result) nil)) (t (funcall ,async nil err)))) "phpinspect-pipeline-async") ,(append '(phpinspect--pipeline) (list seed-form) macro-params))))) @@ -257,11 +265,11 @@ (define-inline phpinspect-pipeline-receive (queue) (inline-letevals (queue) - `(or (phpinspect-queue-dequeue ,queue) - (let ((mx (make-mutex))) - (with-mutex mx - (condition-wait (make-condition-variable mx "phpinspect-pipeline-receive"))) - (phpinspect-queue-dequeue ,queue))))) + (inline-quote + (let ((val)) + (while (not (setq val (phpinspect-queue-dequeue ,queue))) + (thread-yield)) + val)))) (defun phpinspect-pipeline-step-name (name &optional suffix) (intern (concat (symbol-name name) (if suffix (concat "-" suffix) "")))) @@ -275,17 +283,16 @@ (define-inline phpinspect-pipeline--enqueue (queue emission &optional no-notify) (inline-letevals (queue emission no-notify) (inline-quote - (if (and (phpinspect-pipeline-emission-p ,emission) - (phpinspect-pipeline-emission-collection ,emission)) - (progn - (while (cdr (phpinspect-pipeline-emission-collection ,emission)) + (when ,emission + (if (phpinspect-pipeline-emission-p ,emission) + (when (phpinspect-pipeline-emission-collection ,emission) + (while (cdr (phpinspect-pipeline-emission-collection ,emission)) + (phpinspect-queue-enqueue + ,queue (pop (phpinspect-pipeline-emission-collection ,emission)) + ,no-notify)) (phpinspect-queue-enqueue - ,queue (pop (phpinspect-pipeline-emission-collection ,emission)) - ,no-notify)) - (phpinspect-queue-enqueue - ,queue (pop (phpinspect-pipeline-emission-collection ,emission)) ,no-notify)) - (phpinspect-queue-enqueue ,queue ,emission ,no-notify))))) - + ,queue (pop (phpinspect-pipeline-emission-collection ,emission)) ,no-notify)) + (phpinspect-queue-enqueue ,queue ,emission ,no-notify)))))) (defmacro phpinspect-define-pipeline-step (name function-name) (unless (symbolp name) @@ -320,7 +327,6 @@ (out-queue (gensym "queue")) (context-sym (gensym "context")) (continue-running (gensym "continue-running")) - (original-thread (gensym "original-thread")) (pctx-sym (gensym "pipeline-ctx")) (incoming-end (gensym "incoming-end")) (end (gensym "end"))) @@ -330,8 +336,7 @@ (setq statement (nconc statement (list context-sym)))) (inline-quote - (let ((,original-thread (current-thread)) - (,inc-queue ,queue) + (let ((,inc-queue ,queue) (,out-queue ,consumer-queue) (,context-sym ,context) (,pctx-sym ,pipeline-ctx)) @@ -345,33 +350,29 @@ (condition-case err (progn (phpinspect-pipeline-pause) - (catch 'phpinspect-pipeline-break - (while ,continue-running - (setq ,incoming (phpinspect-pipeline-receive ,inc-queue)) - (if (phpinspect-pipeline-end-p ,incoming) + (setq ,incoming (phpinspect-pipeline-receive ,inc-queue)) + + (if (phpinspect-pipeline-end-p ,incoming) + (progn + (setq ,incoming-end ,incoming) + (when (phpinspect-pipeline-end-value ,incoming) (progn - (setq ,incoming-end ,incoming) - (when (phpinspect-pipeline-end-value ,incoming) - (progn - (setq ,incoming (phpinspect-pipeline-end-value ,incoming) - ,outgoing ,statement) - (phpinspect-pipeline--enqueue ,out-queue ,outgoing 'no-notify))) - - (setq ,end (phpinspect-make-pipeline-end :thread (current-thread))) - (phpinspect-pipeline-ctx-register-end ,pctx-sym ,end) - (setq ,continue-running nil) - (phpinspect-pipeline--enqueue ,out-queue ,end)) - - ;; Else - (setq ,outgoing ,statement) - (when (phpinspect-pipeline-end-p ,outgoing) - (setq ,end (phpinspect-make-pipeline-end :thread (current-thread))) - (phpinspect-pipeline-ctx-register-end ,pctx-sym ,end) - (setq ,continue-running nil)) - (phpinspect-pipeline--enqueue ,out-queue ,outgoing)) - - (when ,end - (throw 'phpinspect-pipeline-break nil))))) + (setq ,incoming (phpinspect-pipeline-end-value ,incoming) + ,outgoing ,statement) + (phpinspect-pipeline--enqueue ,out-queue ,outgoing 'no-notify))) + + (setq ,end (phpinspect-make-pipeline-end :thread (current-thread))) + (phpinspect-pipeline-ctx-register-end ,pctx-sym ,end) + (setq ,continue-running nil) + (phpinspect-pipeline--enqueue ,out-queue ,end)) + + ;; Else + (setq ,outgoing ,statement) + (when (phpinspect-pipeline-end-p ,outgoing) + (setq ,end (phpinspect-make-pipeline-end :thread (current-thread))) + (phpinspect-pipeline-ctx-register-end ,pctx-sym ,end) + (setq ,continue-running nil)) + (phpinspect-pipeline--enqueue ,out-queue ,outgoing))) (phpinspect-pipeline-incoming) (t (phpinspect--log "Pipeline thread errored: %s" err) (setq ,end (phpinspect-make-pipeline-end :thread (current-thread) :error err)) diff --git a/phpinspect.el b/phpinspect.el index 8a13cd6..fa7c124 100644 --- a/phpinspect.el +++ b/phpinspect.el @@ -352,11 +352,15 @@ before the search is executed." (phpinspect--get-or-create-global-cache) (phpinspect-current-project-root))) (autoloader (phpinspect-project-autoload project))) - (phpinspect-autoloader-refresh autoloader) - (message (concat "Refreshed project autoloader. Found %d types within project," - " %d types total.") - (hash-table-count (phpinspect-autoloader-own-types autoloader)) - (hash-table-count (phpinspect-autoloader-types autoloader))))) + ;; Update display so that it is clear to the user that emacs is + ;; responsive. Otherwise the autoloader refresh thread hogging the cpu will + ;; make it look like emacs is not responsive, especially when M-x uses some + ;; kind of completion framework, in which case the completion popup will + ;; appear frozen while the thread is executing. + (redisplay) + + (phpinspect-autoloader-refresh autoloader))) + (provide 'phpinspect) ;;; phpinspect.el ends here diff --git a/test/test-autoload.el b/test/test-autoload.el index 43417c3..7d9348b 100644 --- a/test/test-autoload.el +++ b/test/test-autoload.el @@ -28,91 +28,73 @@ (require 'phpinspect-fs) (require 'phpinspect-autoload) -(ert-deftest phpinspect-psr0-fill-typehash () +(ert-deftest phpinspect-find-composer-json-files () (let* ((fs (phpinspect-make-virtual-fs)) - (typehash (make-hash-table :size 10 :test 'eq)) - (autoload - (phpinspect-make-psr0-generated :prefix "App\\"))) - - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/App/Services/SuperService.php" "") - - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/Kernel.php" "") - - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/App/Controller/Banana.php" "") - - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/lib/Mailer_Lib.php" "") + (autoloader (phpinspect-make-autoloader + :project (phpinspect--make-project :root "/root" :fs fs)))) + (phpinspect-virtual-fs-set-file fs + "/root/composer.json" + "{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}") - (setf (phpinspect-psr0-directories autoload) (list "/home/user/projects/app/src/" - "/home/user/projects/app/lib/")) + (phpinspect-virtual-fs-set-file fs + "/root/vendor/runescape/client/composer.json" + "{\"autoload\": { \"psr-0\": {\"Runescape\\\\Banana\\\\\": [\"src/\", \"lib\"]}}}") - (phpinspect-al-strategy-fill-typehash autoload fs typehash) - (should-not (hash-table-empty-p typehash)) + (phpinspect-virtual-fs-set-file fs + "/root/vendor/apples/pears/composer.json" + "{\"autoload\": { \"psr-0\": {\"Runescape\\\\Banana\\\\\": [\"src/\", \"lib\"]}}}") - (should (string= "/home/user/projects/app/src/App/Services/SuperService.php" - (gethash (phpinspect-intern-name "\\App\\Services\\SuperService") - typehash))) - (should (string= "/home/user/projects/app/src/Kernel.php" - (gethash (phpinspect-intern-name "\\Kernel") - typehash))) - (should (string= "/home/user/projects/app/src/App/Controller/Banana.php" - (gethash (phpinspect-intern-name "\\App\\Controller\\Banana") - typehash))) + (let ((sorter (lambda (file1 file2) (string-lessp (cdr file1) (cdr file2))))) - (should (string= "/home/user/projects/app/lib/Mailer_Lib.php" - (gethash (phpinspect-intern-name "\\Mailer_Lib") - typehash))))) + (should (equal (sort '((vendor . "/root/vendor/apples/pears/composer.json") + (vendor . "/root/vendor/runescape/client/composer.json") + (local . "/root/composer.json")) + sorter) + (sort (phpinspect-find-composer-json-files fs "/root") + sorter)))))) -(ert-deftest phpinspect-psr4-fill-typehash () +(ert-deftest phpinspect-autoload-composer-json-iterator () (let* ((fs (phpinspect-make-virtual-fs)) - (typehash (make-hash-table :size 10 :test 'eq)) - (autoload - (phpinspect-make-psr4-generated :prefix "App\\"))) - - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/Services/SuperService.php" "") + (autoloader (phpinspect-make-autoloader + :project (phpinspect--make-project :root "/root" :fs fs))) + result error) - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/Kernel.php" "") + (phpinspect-virtual-fs-set-file fs + "/root/composer.json" + "{ \"autoload\": { \"psr-4\": {\"WoW\\\\Dwarves\\\\\": \"src/\"}}}") - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/src/Controller/Banana.php" "") + (phpinspect-virtual-fs-set-file fs + "/root/vendor/runescape/client/composer.json" + "{\"autoload\": { \"psr-0\": {\"Runescape\\\\Banana\\\\\": [\"src/\", \"lib\"]}}}") - (phpinspect-virtual-fs-set-file - fs "/home/user/projects/app/lib/Mailer_Lib.php" "") - (setf (phpinspect-psr4-directories autoload) (list "/home/user/projects/app/src/" - "/home/user/projects/app/lib/")) + (phpinspect-virtual-fs-set-file fs + "/root/vendor/apples/pears/composer.json" + "{\"autoload\": { \"psr-0\": {\"Runescape\\\\Banana\\\\\": [\"src/\", \"lib\"]}, + \"psr-4\": {\"Another\\\\Namespace\\\\\": [\"separate/\"]}}}") - (phpinspect-al-strategy-fill-typehash autoload fs typehash) + (phpinspect-pipeline (phpinspect-find-composer-json-files fs "/root") + :async (lambda (res err) + (setq result res + error err)) + :into (phpinspect-iterate-composer-jsons :with-context autoloader)) - (should-not (hash-table-empty-p typehash)) + (while (not (or result error)) + (thread-yield)) - (should (string= "/home/user/projects/app/src/Services/SuperService.php" - (gethash (phpinspect-intern-name "\\App\\Services\\SuperService") - typehash))) - (should (string= "/home/user/projects/app/src/Kernel.php" - (gethash (phpinspect-intern-name "\\App\\Kernel") - typehash))) - (should (string= "/home/user/projects/app/src/Controller/Banana.php" - (gethash (phpinspect-intern-name "\\App\\Controller\\Banana") - typehash))) + (should-not error) - (should (string= "/home/user/projects/app/lib/Mailer_Lib.php" - (gethash (phpinspect-intern-name "\\App\\Mailer_Lib") - typehash))))) + (should (= 4 (length result))) + (should (= 2 (length (seq-filter #'phpinspect-psr0-p result)))) + (should (= 2 (length (seq-filter #'phpinspect-psr4-p result)))))) -(ert-deftest phpinspect-autoloader-refresh () +(ert-deftest phpinspect-al-strategy-execute () (let* ((fs (phpinspect-make-virtual-fs)) - (project (phpinspect--make-project - :fs fs - :root "/project/root")) (autoloader (phpinspect-make-autoloader - :project project))) + :project (phpinspect--make-project :root "/project/root" :fs fs))) + result error) + (phpinspect-virtual-fs-set-file fs "/project/root/composer.json" @@ -144,7 +126,17 @@ (phpinspect-virtual-fs-set-file fs "/project/root/vendor/not-runescape/wow/src/TestClass.php" "") - (phpinspect-autoloader-refresh autoloader) + (phpinspect-pipeline (phpinspect-find-composer-json-files fs "/project/root") + :async (lambda (res err) + (setq result res + error err)) + :into (phpinspect-iterate-composer-jsons :with-context autoloader) + :into phpinspect-al-strategy-execute) + + (while (not (or result error)) + (thread-yield)) + + (should-not error) (should-not (hash-table-empty-p (phpinspect-autoloader-own-types autoloader))) (should-not (hash-table-empty-p (phpinspect-autoloader-types autoloader))) @@ -152,4 +144,8 @@ (should (string= "/project/root/vendor/runescape/client/src/Runescape/Banana/App.php" (phpinspect-autoloader-resolve autoloader - (phpinspect-intern-name "\\Runescape\\Banana\\App")))))) + (phpinspect-intern-name "\\Runescape\\Banana\\App")))) + (should (string= "/project/root/vendor/not-runescape/wow/src/TestClass.php" + (phpinspect-autoloader-resolve + autoloader + (phpinspect-intern-name "\\WoW\\Dwarves\\TestClass"))))))