| 1 | ;;;; TODO: move to a utility package |
|---|
| 2 | (in-package :abcl/build) |
|---|
| 3 | |
|---|
| 4 | ;;; TODO remove |
|---|
| 5 | (defun localize-executable-name (name) |
|---|
| 6 | (let* ((p (if (pathnamep name) |
|---|
| 7 | name |
|---|
| 8 | (pathname name))) |
|---|
| 9 | (type (pathname-type p))) |
|---|
| 10 | (make-pathname :defaults p |
|---|
| 11 | :type |
|---|
| 12 | (if (uiop:os-windows-p) |
|---|
| 13 | (when (null type) |
|---|
| 14 | "exe") |
|---|
| 15 | type)))) |
|---|
| 16 | |
|---|
| 17 | (defun possible-executable-names (name |
|---|
| 18 | &key (suffixes '("exe" "cmd" "bat") suffixes-p)) |
|---|
| 19 | (let* ((p (if (pathnamep name) |
|---|
| 20 | name |
|---|
| 21 | (pathname name))) |
|---|
| 22 | (type (pathname-type p))) |
|---|
| 23 | (declare (ignore type)) |
|---|
| 24 | (unless (or (uiop:os-windows-p) suffixes-p) |
|---|
| 25 | (return-from possible-executable-names |
|---|
| 26 | (listify name))) |
|---|
| 27 | (loop |
|---|
| 28 | :for suffix :in suffixes |
|---|
| 29 | :with result = (list p) |
|---|
| 30 | :doing (push (make-pathname :defaults p :type suffix) |
|---|
| 31 | result) |
|---|
| 32 | :finally (return (nreverse result))))) |
|---|
| 33 | |
|---|
| 34 | (defun introspect-path-for (executable) |
|---|
| 35 | (let ((which-command (if (uiop:os-windows-p) |
|---|
| 36 | "where" |
|---|
| 37 | "which"))) |
|---|
| 38 | (when (ignore-errors |
|---|
| 39 | (uiop:run-program (list which-command which-command) :output :string)) |
|---|
| 40 | (dolist (p (possible-executable-names executable)) |
|---|
| 41 | (let ((raw-result |
|---|
| 42 | (ignore-errors (uiop:run-program |
|---|
| 43 | (list which-command |
|---|
| 44 | (namestring p)) |
|---|
| 45 | :output :string)))) |
|---|
| 46 | (when raw-result |
|---|
| 47 | (let ((result (first (split-string raw-result #\Newline)))) |
|---|
| 48 | (return-from introspect-path-for |
|---|
| 49 | (values |
|---|
| 50 | result |
|---|
| 51 | (pathname result)))))))))) |
|---|
| 52 | |
|---|
| 53 | (defun probe-for-executable (directory executable) |
|---|
| 54 | (dolist (executable (possible-executable-names executable)) |
|---|
| 55 | (let ((pathname |
|---|
| 56 | (probe-file |
|---|
| 57 | (merge-pathnames executable directory)))) |
|---|
| 58 | (when pathname |
|---|
| 59 | (return-from probe-for-executable |
|---|
| 60 | pathname))))) |
|---|
| 61 | |
|---|
| 62 | (defun split-string (string split-char) |
|---|
| 63 | (loop :for i = 0 :then (1+ j) |
|---|
| 64 | :as j = (position split-char string :test #'string-equal :start i) |
|---|
| 65 | :collect (subseq string i j) |
|---|
| 66 | :while j)) |
|---|
| 67 | |
|---|
| 68 | (defun stringify (thing) |
|---|
| 69 | (cond |
|---|
| 70 | ((pathnamep thing) |
|---|
| 71 | (namestring thing)) |
|---|
| 72 | ((stringp thing) |
|---|
| 73 | thing) |
|---|
| 74 | (t |
|---|
| 75 | (error "Don't know how stringify ~a." thing)))) |
|---|
| 76 | |
|---|
| 77 | (defun listify (thing) |
|---|
| 78 | (if (consp thing) |
|---|
| 79 | thing |
|---|
| 80 | (list thing))) |
|---|
| 81 | |
|---|
| 82 | (defun some-directory-containing (executable) |
|---|
| 83 | ;; search path |
|---|
| 84 | (let ((in-path (introspect-path-for executable))) |
|---|
| 85 | (when in-path |
|---|
| 86 | (return-from some-directory-containing |
|---|
| 87 | in-path)) |
|---|
| 88 | (dolist (d (if (uiop:os-windows-p) |
|---|
| 89 | '(#p"c:/Program Files/") ;; TODO localize me! |
|---|
| 90 | '(#p"/usr/local/bin/" #p"/opt/local/bin/" #p"/usr/bin/"))) |
|---|
| 91 | (let* ((e (localize-executable-name |
|---|
| 92 | (merge-pathnames executable d))) |
|---|
| 93 | (p (probe-file e))) |
|---|
| 94 | (when p |
|---|
| 95 | (return-from some-directory-containing p)))))) |
|---|
| 96 | |
|---|
| 97 | (defun copy-directory-recursively (from to) |
|---|
| 98 | (flet ((normalize-to-directory (p) |
|---|
| 99 | (when (or (not (pathnamep p)) |
|---|
| 100 | (not (and (null (pathname-name p)) |
|---|
| 101 | (null (pathname-type p))))) |
|---|
| 102 | (setf p (make-pathname :defaults p |
|---|
| 103 | :name nil :type nil))) |
|---|
| 104 | p)) |
|---|
| 105 | (normalize-to-directory from) |
|---|
| 106 | (normalize-to-directory to) |
|---|
| 107 | (let ((wildcard (merge-pathnames "**/*" from))) |
|---|
| 108 | (loop :for source :in (directory wildcard) |
|---|
| 109 | :for relative = (enough-namestring source from) |
|---|
| 110 | :for destination = (merge-pathnames relative to) |
|---|
| 111 | :doing |
|---|
| 112 | (progn |
|---|
| 113 | (ensure-directories-exist destination) |
|---|
| 114 | (when (or (pathname-name destination) |
|---|
| 115 | (pathname-type destination)) |
|---|
| 116 | (uiop:copy-file source destination))))))) |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | |
|---|
| 123 | |
|---|
| 124 | |
|---|