1 | (in-package #:asdf-install) |
---|
2 | |
---|
3 | (pushnew :asdf-install *features*) |
---|
4 | |
---|
5 | (defun installer-msg (stream format-control &rest format-arguments) |
---|
6 | (apply #'format stream "~&;;; ASDF-INSTALL: ~@?~%" |
---|
7 | format-control format-arguments)) |
---|
8 | |
---|
9 | (defun verify-gpg-signatures-p (url) |
---|
10 | (labels ((prefixp (prefix string) |
---|
11 | (let ((m (mismatch prefix string))) |
---|
12 | (or (not m) (>= m (length prefix)))))) |
---|
13 | (case *verify-gpg-signatures* |
---|
14 | ((nil) nil) |
---|
15 | ((:unknown-locations) |
---|
16 | (notany |
---|
17 | (lambda (x) (prefixp x url)) |
---|
18 | *safe-url-prefixes*)) |
---|
19 | (t t)))) |
---|
20 | |
---|
21 | (defun same-central-registry-entry-p (a b) |
---|
22 | (flet ((ensure-string (x) |
---|
23 | (typecase x |
---|
24 | (string x) |
---|
25 | (pathname (namestring (translate-logical-pathname x))) |
---|
26 | (t nil)))) |
---|
27 | (and (setf a (ensure-string a)) |
---|
28 | (setf b (ensure-string b)) |
---|
29 | a b (string-equal a b)))) |
---|
30 | |
---|
31 | (defun add-registry-location (location) |
---|
32 | (let ((location-directory (pathname-sans-name+type location))) |
---|
33 | #+asdf |
---|
34 | (pushnew location-directory |
---|
35 | asdf:*central-registry* |
---|
36 | :test #'same-central-registry-entry-p) |
---|
37 | |
---|
38 | #+mk-defsystem |
---|
39 | (mk:add-registry-location location-directory))) |
---|
40 | |
---|
41 | ;;; Fixing the handling of *LOCATIONS* |
---|
42 | |
---|
43 | (defun add-locations (loc-name site system-site) |
---|
44 | (declare (type string loc-name) |
---|
45 | (type pathname site system-site)) |
---|
46 | #+asdf |
---|
47 | (progn |
---|
48 | (pushnew site asdf:*central-registry* :test #'equal) |
---|
49 | (pushnew system-site asdf:*central-registry* :test #'equal)) |
---|
50 | |
---|
51 | #+mk-defsystem |
---|
52 | (progn |
---|
53 | (mk:add-registry-location site) |
---|
54 | (mk:add-registry-location system-site)) |
---|
55 | (setf *locations* |
---|
56 | (append *locations* (list (list site system-site loc-name))))) |
---|
57 | |
---|
58 | ;;;--------------------------------------------------------------------------- |
---|
59 | ;;; URL handling. |
---|
60 | |
---|
61 | (defun url-host (url) |
---|
62 | (assert (string-equal url "http://" :end1 7)) |
---|
63 | (let* ((port-start (position #\: url :start 7)) |
---|
64 | (host-end (min (or (position #\/ url :start 7) (length url)) |
---|
65 | (or port-start (length url))))) |
---|
66 | (subseq url 7 host-end))) |
---|
67 | |
---|
68 | (defun url-port (url) |
---|
69 | (assert (string-equal url "http://" :end1 7)) |
---|
70 | (let ((port-start (position #\: url :start 7))) |
---|
71 | (if port-start |
---|
72 | (parse-integer url :start (1+ port-start) :junk-allowed t) 80))) |
---|
73 | |
---|
74 | ; This is from Juri Pakaste's <juri@iki.fi> base64.lisp |
---|
75 | (defparameter *encode-table* |
---|
76 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") |
---|
77 | |
---|
78 | (defun base64-encode (string) |
---|
79 | (let ((result (make-array |
---|
80 | (list (* 4 (truncate (/ (+ 2 (length string)) 3)))) |
---|
81 | :element-type 'base-char))) |
---|
82 | (do ((sidx 0 (+ sidx 3)) |
---|
83 | (didx 0 (+ didx 4)) |
---|
84 | (chars 2 2) |
---|
85 | (value nil nil)) |
---|
86 | ((>= sidx (length string)) t) |
---|
87 | (setf value (ash (logand #xFF (char-code (char string sidx))) 8)) |
---|
88 | (dotimes (n 2) |
---|
89 | (when (< (+ sidx n 1) (length string)) |
---|
90 | (setf value |
---|
91 | (logior value |
---|
92 | (logand #xFF (char-code (char string (+ sidx n 1)))))) |
---|
93 | (incf chars)) |
---|
94 | (when (= n 0) |
---|
95 | (setf value (ash value 8)))) |
---|
96 | (setf (elt result (+ didx 3)) |
---|
97 | (elt *encode-table* (if (> chars 3) (logand value #x3F) 64))) |
---|
98 | (setf value (ash value -6)) |
---|
99 | (setf (elt result (+ didx 2)) |
---|
100 | (elt *encode-table* (if (> chars 2) (logand value #x3F) 64))) |
---|
101 | (setf value (ash value -6)) |
---|
102 | (setf (elt result (+ didx 1)) |
---|
103 | (elt *encode-table* (logand value #x3F))) |
---|
104 | (setf value (ash value -6)) |
---|
105 | (setf (elt result didx) |
---|
106 | (elt *encode-table* (logand value #x3F)))) |
---|
107 | result)) |
---|
108 | |
---|
109 | (defun request-uri (url) |
---|
110 | (assert (string-equal url "http://" :end1 7)) |
---|
111 | (if *proxy* |
---|
112 | url |
---|
113 | (let ((path-start (position #\/ url :start 7))) |
---|
114 | (assert (and path-start) nil "url does not specify a file.") |
---|
115 | (subseq url path-start)))) |
---|
116 | |
---|
117 | (defun url-connection (url) |
---|
118 | (let ((stream (make-stream-from-url (or *proxy* url))) |
---|
119 | (host (url-host url))) |
---|
120 | (format stream "GET ~A HTTP/1.0~C~CHost: ~A~C~CCookie: CCLAN-SITE=~A~C~C" |
---|
121 | (request-uri url) #\Return #\Linefeed |
---|
122 | host #\Return #\Linefeed |
---|
123 | *cclan-mirror* #\Return #\Linefeed) |
---|
124 | (when (and *proxy-passwd* *proxy-user*) |
---|
125 | (format stream "Proxy-Authorization: Basic ~A~C~C" |
---|
126 | (base64-encode (format nil "~A:~A" *proxy-user* *proxy-passwd*)) |
---|
127 | #\Return #\Linefeed)) |
---|
128 | (format stream "~C~C" #\Return #\Linefeed) |
---|
129 | (force-output stream) |
---|
130 | (list |
---|
131 | (let* ((l (read-header-line stream)) |
---|
132 | (space (position #\Space l))) |
---|
133 | (parse-integer l :start (1+ space) :junk-allowed t)) |
---|
134 | (loop for line = (read-header-line stream) |
---|
135 | until (or (null line) |
---|
136 | (zerop (length line)) |
---|
137 | (eql (elt line 0) (code-char 13))) |
---|
138 | collect |
---|
139 | (let ((colon (position #\: line))) |
---|
140 | (cons (intern (string-upcase (subseq line 0 colon)) :keyword) |
---|
141 | (string-trim (list #\Space (code-char 13)) |
---|
142 | (subseq line (1+ colon)))))) |
---|
143 | stream))) |
---|
144 | |
---|
145 | (defun download-link-for-package (package-name-or-url) |
---|
146 | (if (= (mismatch package-name-or-url "http://") 7) |
---|
147 | package-name-or-url |
---|
148 | (format nil "http://www.cliki.net/~A?download" |
---|
149 | package-name-or-url))) |
---|
150 | |
---|
151 | (defun download-link-for-signature (url) |
---|
152 | (concatenate 'string url ".asc")) |
---|
153 | |
---|
154 | ;;; XXX unsightful hack |
---|
155 | (defvar *dont-check-signature* nil) |
---|
156 | |
---|
157 | (defun download-files-for-package (package-name-or-url) |
---|
158 | (setf *dont-check-signature* nil) |
---|
159 | (multiple-value-bind (package-url package-file) |
---|
160 | (download-url-to-temporary-file |
---|
161 | (download-link-for-package package-name-or-url)) |
---|
162 | (if (verify-gpg-signatures-p package-name-or-url) |
---|
163 | (restart-case |
---|
164 | (multiple-value-bind (signature-url signature-file) |
---|
165 | (download-url-to-temporary-file |
---|
166 | (download-link-for-signature package-url)) |
---|
167 | (declare (ignore signature-url)) |
---|
168 | (values package-file signature-file)) |
---|
169 | (skip-gpg-check () |
---|
170 | :report "Don't check GPG signature for this package" |
---|
171 | (progn |
---|
172 | (setf *dont-check-signature* t) |
---|
173 | (values package-file nil)))) |
---|
174 | (values package-file nil)))) |
---|
175 | |
---|
176 | (defun verify-gpg-signature (file-name signature-name) |
---|
177 | (block verify |
---|
178 | (when (and (null signature-name) *dont-check-signature*) |
---|
179 | (return-from verify t)) |
---|
180 | (loop |
---|
181 | (restart-case |
---|
182 | (let ((tags (gpg-results file-name signature-name))) |
---|
183 | ;; test that command returned something |
---|
184 | (unless tags |
---|
185 | (error 'gpg-shell-error)) |
---|
186 | ;; test for obvious key/sig problems |
---|
187 | (let ((errsig (header-value :errsig tags))) |
---|
188 | (and errsig (error 'key-not-found :key-id errsig))) |
---|
189 | (let ((badsig (header-value :badsig tags))) |
---|
190 | (and badsig (error 'key-not-found :key-id badsig))) |
---|
191 | (let* ((good (header-value :goodsig tags)) |
---|
192 | (id (first good)) |
---|
193 | (name (format nil "~{~A~^ ~}" (rest good)))) |
---|
194 | ;; good signature, but perhaps not trusted |
---|
195 | (restart-case |
---|
196 | (let ((trusted? (or (header-pair :trust_ultimate tags) |
---|
197 | (header-pair :trust_fully tags))) |
---|
198 | (in-list? (assoc id *trusted-uids* :test #'equal))) |
---|
199 | (cond ((or trusted? in-list?) |
---|
200 | ;; ok |
---|
201 | ) |
---|
202 | ((not trusted?) |
---|
203 | (error 'key-not-trusted |
---|
204 | :key-user-name name :key-id id)) |
---|
205 | ((not in-list?) |
---|
206 | (error 'author-not-trusted |
---|
207 | :key-user-name name :key-id id)))) |
---|
208 | (add-key (&rest rest) |
---|
209 | :report "Add to package supplier list" |
---|
210 | (declare (ignore rest)) |
---|
211 | (pushnew (list id name) *trusted-uids*)))) |
---|
212 | (return-from verify t)) |
---|
213 | (install-anyways |
---|
214 | (&rest rest) |
---|
215 | :report "Don't check GPG signature for this package" |
---|
216 | (declare (ignore rest)) |
---|
217 | (return-from verify t)) |
---|
218 | (retry-gpg-check |
---|
219 | (&rest args) |
---|
220 | :report "Retry GPG check \(e.g., after downloading the key\)" |
---|
221 | (declare (ignore args)) |
---|
222 | nil))))) |
---|
223 | |
---|
224 | (defun header-value (name headers) |
---|
225 | "Searchers headers for name _without_ case sensitivity. Headers should be an alist mapping symbols to values; name a symbol. Returns the value if name is found or nil if it is not." |
---|
226 | (cdr (header-pair name headers))) |
---|
227 | |
---|
228 | (defun header-pair (name headers) |
---|
229 | "Searchers headers for name _without_ case sensitivity. Headers should be an alist mapping symbols to values; name a symbol. Returns the \(name value\) pair if name is found or nil if it is not." |
---|
230 | (assoc name headers |
---|
231 | :test (lambda (a b) |
---|
232 | (string-equal (symbol-name a) (symbol-name b))))) |
---|
233 | |
---|
234 | (defun validate-preferred-location () |
---|
235 | (typecase *preferred-location* |
---|
236 | (null t) |
---|
237 | ((integer 0) |
---|
238 | (assert (<= 1 *preferred-location* (length *locations*)) |
---|
239 | (*preferred-location*) |
---|
240 | 'invalid-preferred-location-number-error |
---|
241 | :preferred-location *preferred-location*)) |
---|
242 | ((or symbol string) |
---|
243 | (assert (find *preferred-location* *locations* |
---|
244 | :test (if (typep *preferred-location* 'symbol) |
---|
245 | #'eq #'string-equal) :key #'third) |
---|
246 | (*preferred-location*) |
---|
247 | 'invalid-preferred-location-name-error |
---|
248 | :preferred-location *preferred-location*)) |
---|
249 | (t |
---|
250 | (assert nil |
---|
251 | (*preferred-location*) |
---|
252 | 'invalid-preferred-location-error |
---|
253 | :preferred-location *preferred-location*))) |
---|
254 | *preferred-location*) |
---|
255 | |
---|
256 | (defun select-location () |
---|
257 | (loop with n-locations = (length *locations*) |
---|
258 | for response = (progn |
---|
259 | (format t "Install where?~%") |
---|
260 | (loop for (source system name) in *locations* |
---|
261 | for i from 1 |
---|
262 | do (format t "~A) ~A: ~% System in ~A~% Files in ~A ~%" |
---|
263 | i name system source)) |
---|
264 | (format t "0) Abort installation.~% --> ") |
---|
265 | (force-output) |
---|
266 | (read)) |
---|
267 | when (and (numberp response) |
---|
268 | (<= 1 response n-locations)) |
---|
269 | return response |
---|
270 | when (and (numberp response) |
---|
271 | (zerop response)) |
---|
272 | do (abort (make-condition 'installation-abort)))) |
---|
273 | |
---|
274 | (defun install-location () |
---|
275 | (validate-preferred-location) |
---|
276 | (let ((location-selection (or *preferred-location* |
---|
277 | (select-location)))) |
---|
278 | (etypecase location-selection |
---|
279 | (integer |
---|
280 | (elt *locations* (1- location-selection))) |
---|
281 | ((or symbol string) |
---|
282 | (find location-selection *locations* :key #'third |
---|
283 | :test (if (typep location-selection 'string) |
---|
284 | #'string-equal #'eq)))))) |
---|
285 | |
---|
286 | |
---|
287 | ;;; install-package -- |
---|
288 | |
---|
289 | (defun find-shell-command (command) |
---|
290 | (loop for directory in *shell-search-paths* do |
---|
291 | (let ((target (make-pathname :name command :type nil |
---|
292 | :directory directory))) |
---|
293 | (when (probe-file target) |
---|
294 | (return-from find-shell-command (namestring target))))) |
---|
295 | (values nil)) |
---|
296 | |
---|
297 | (defun tar-command () |
---|
298 | #-(or :win32 :mswindows) |
---|
299 | (find-shell-command *gnu-tar-program*) |
---|
300 | #+(or :win32 :mswindows) |
---|
301 | *cygwin-bash-program*) |
---|
302 | |
---|
303 | (defun tar-arguments (source packagename) |
---|
304 | #-(or :win32 :mswindows :scl) |
---|
305 | (list "-C" (namestring (truename source)) |
---|
306 | "-xzvf" (namestring (truename packagename))) |
---|
307 | #+(or :win32 :mswindows) |
---|
308 | (list "-l" |
---|
309 | "-c" |
---|
310 | (format nil "\"tar -C \\\"`cygpath '~A'`\\\" -xzvf \\\"`cygpath '~A'`\\\"\"" |
---|
311 | (namestring (truename source)) |
---|
312 | (namestring (truename packagename)))) |
---|
313 | #+scl |
---|
314 | (list "-C" (ext:unix-namestring (truename source)) |
---|
315 | "-xzvf" (ext:unix-namestring (truename packagename)))) |
---|
316 | |
---|
317 | (defun extract-using-tar (to-dir tarball) |
---|
318 | (let ((tar-command (tar-command))) |
---|
319 | (if (and tar-command (probe-file tar-command)) |
---|
320 | (return-output-from-program tar-command |
---|
321 | (tar-arguments to-dir tarball)) |
---|
322 | (warn "Cannot find tar command ~S." tar-command)))) |
---|
323 | |
---|
324 | (defun extract (to-dir tarball) |
---|
325 | (or (some #'(lambda (extractor) (funcall extractor to-dir tarball)) |
---|
326 | *tar-extractors*) |
---|
327 | (error "Unable to extract tarball ~A." tarball))) |
---|
328 | |
---|
329 | (defun install-package (source system packagename) |
---|
330 | "Returns a list of system names (ASDF or MK:DEFSYSTEM) for installed systems." |
---|
331 | (ensure-directories-exist source) |
---|
332 | (ensure-directories-exist system) |
---|
333 | (let* ((tar (extract source packagename)) |
---|
334 | ;; Some tar programs (OSX) list entries with preceeding "x " |
---|
335 | ;; as in "x entry/file.asd" |
---|
336 | (pos-begin (if (string= (subseq tar 0 2) "x ") |
---|
337 | 2 |
---|
338 | 0)) |
---|
339 | (pos-slash (or (position #\/ tar) |
---|
340 | (position #\Return tar) |
---|
341 | (position #\Linefeed tar))) |
---|
342 | (*default-pathname-defaults* |
---|
343 | (merge-pathnames |
---|
344 | (make-pathname :directory |
---|
345 | `(:relative ,(subseq tar pos-begin pos-slash))) |
---|
346 | source))) |
---|
347 | (loop for sysfile in (append |
---|
348 | (directory |
---|
349 | (make-pathname :defaults *default-pathname-defaults* |
---|
350 | :name :wild |
---|
351 | :type "asd")) |
---|
352 | (directory |
---|
353 | (make-pathname :defaults *default-pathname-defaults* |
---|
354 | :name :wild |
---|
355 | :type "system"))) |
---|
356 | do (maybe-symlink-sysfile system sysfile) |
---|
357 | do (installer-msg t "Found system definition: ~A" sysfile) |
---|
358 | do (maybe-update-central-registry sysfile) |
---|
359 | collect sysfile))) |
---|
360 | |
---|
361 | (defun maybe-update-central-registry (sysfile) |
---|
362 | ;; make sure that the systems we install are accessible in case |
---|
363 | ;; asdf-install:*locations* and asdf:*central-registry* are out |
---|
364 | ;; of sync |
---|
365 | (add-registry-location sysfile)) |
---|
366 | |
---|
367 | (defun temp-file-name (p) |
---|
368 | (declare (ignore p)) |
---|
369 | (let ((pathname nil)) |
---|
370 | (loop for i = 0 then (1+ i) do |
---|
371 | (setf pathname |
---|
372 | (merge-pathnames |
---|
373 | (make-pathname |
---|
374 | :name (format nil "asdf-install-~d" i) |
---|
375 | :type "asdf-install-tmp") |
---|
376 | *temporary-directory*)) |
---|
377 | (unless (probe-file pathname) |
---|
378 | (return-from temp-file-name pathname))))) |
---|
379 | |
---|
380 | |
---|
381 | ;;; install |
---|
382 | ;;; This is the external entry point. |
---|
383 | |
---|
384 | (defun install (packages &key (propagate nil) (where *preferred-location*)) |
---|
385 | (let* ((*preferred-location* where) |
---|
386 | (*temporary-files* nil) |
---|
387 | (trusted-uid-file |
---|
388 | (merge-pathnames "trusted-uids.lisp" *private-asdf-install-dirs*)) |
---|
389 | (*trusted-uids* |
---|
390 | (when (probe-file trusted-uid-file) |
---|
391 | (with-open-file (f trusted-uid-file) (read f)))) |
---|
392 | (old-uids (copy-list *trusted-uids*)) |
---|
393 | #+asdf |
---|
394 | (*defined-systems* (if propagate |
---|
395 | (make-hash-table :test 'equal) |
---|
396 | *defined-systems*)) |
---|
397 | (packages (if (atom packages) (list packages) packages)) |
---|
398 | (*propagate-installation* propagate) |
---|
399 | (*systems-installed-this-time* nil)) |
---|
400 | (unwind-protect |
---|
401 | (destructuring-bind (source system name) (install-location) |
---|
402 | (declare (ignore name)) |
---|
403 | (labels |
---|
404 | ((one-iter (packages) |
---|
405 | (let ((packages-to-install nil)) |
---|
406 | (loop for p in (mapcar #'string packages) do |
---|
407 | (cond ((local-archive-p p) |
---|
408 | (setf packages-to-install |
---|
409 | (append packages-to-install |
---|
410 | (install-package source system p)))) |
---|
411 | (t |
---|
412 | (multiple-value-bind (package signature) |
---|
413 | (download-files-for-package p) |
---|
414 | (when (verify-gpg-signatures-p p) |
---|
415 | (verify-gpg-signature package signature)) |
---|
416 | (installer-msg t "Installing ~A in ~A, ~A" |
---|
417 | p source system) |
---|
418 | (install-package source system package)) |
---|
419 | (setf packages-to-install |
---|
420 | (append packages-to-install |
---|
421 | (list p)))))) |
---|
422 | (dolist (package packages-to-install) |
---|
423 | (setf package |
---|
424 | (etypecase package |
---|
425 | (symbol package) |
---|
426 | (string (intern package :asdf-install)) |
---|
427 | (pathname (intern |
---|
428 | (namestring (pathname-name package)) |
---|
429 | :asdf-install)))) |
---|
430 | (handler-bind |
---|
431 | ( |
---|
432 | #+asdf |
---|
433 | (asdf:missing-dependency |
---|
434 | (lambda (c) |
---|
435 | (installer-msg |
---|
436 | t |
---|
437 | "Downloading package ~A, required by ~A~%" |
---|
438 | (asdf::missing-requires c) |
---|
439 | (asdf:component-name |
---|
440 | (asdf::missing-required-by c))) |
---|
441 | (one-iter |
---|
442 | (list (asdf::coerce-name |
---|
443 | (asdf::missing-requires c)))) |
---|
444 | (invoke-restart 'retry))) |
---|
445 | #+mk-defsystem |
---|
446 | (make:missing-component |
---|
447 | (lambda (c) |
---|
448 | (installer-msg |
---|
449 | t |
---|
450 | "Downloading package ~A, required by ~A~%" |
---|
451 | (make:missing-component-name c) |
---|
452 | package) |
---|
453 | (one-iter (list (make:missing-component-name c))) |
---|
454 | (invoke-restart 'retry)))) |
---|
455 | (loop (multiple-value-bind (ret restart-p) |
---|
456 | (with-simple-restart |
---|
457 | (retry "Retry installation") |
---|
458 | (push package *systems-installed-this-time*) |
---|
459 | (load-package package)) |
---|
460 | (declare (ignore ret)) |
---|
461 | (unless restart-p (return))))))))) |
---|
462 | (one-iter packages))) |
---|
463 | ;;; cleanup |
---|
464 | (unless (equal old-uids *trusted-uids*) |
---|
465 | (let ((create-file-p nil)) |
---|
466 | (unless (probe-file trusted-uid-file) |
---|
467 | (installer-msg t "Trusted UID file ~A does not exist" |
---|
468 | (namestring trusted-uid-file)) |
---|
469 | (setf create-file-p |
---|
470 | (y-or-n-p "Do you want to create the file?"))) |
---|
471 | (when (or create-file-p (probe-file trusted-uid-file)) |
---|
472 | (ensure-directories-exist trusted-uid-file) |
---|
473 | (with-open-file (out trusted-uid-file |
---|
474 | :direction :output |
---|
475 | :if-exists :supersede) |
---|
476 | (with-standard-io-syntax |
---|
477 | (prin1 *trusted-uids* out)))))) |
---|
478 | (dolist (l *temporary-files* t) |
---|
479 | (when (probe-file l) (delete-file l)))) |
---|
480 | (nreverse *systems-installed-this-time*))) |
---|
481 | |
---|
482 | (defun local-archive-p (package) |
---|
483 | #+(or :sbcl :allegro) (probe-file package) |
---|
484 | #-(or :sbcl :allegro) (and (/= (mismatch package "http://") 7) |
---|
485 | (probe-file package))) |
---|
486 | |
---|
487 | (defun load-package (package) |
---|
488 | #+asdf |
---|
489 | (progn |
---|
490 | (installer-msg t "Loading system ~S via ASDF." package) |
---|
491 | (asdf:operate 'asdf:load-op package)) |
---|
492 | #+mk-defsystem |
---|
493 | (progn |
---|
494 | (installer-msg t "Loading system ~S via MK:DEFSYSTEM." package) |
---|
495 | (mk:load-system package))) |
---|
496 | |
---|
497 | ;;; uninstall -- |
---|
498 | |
---|
499 | (defun uninstall (system &optional (prompt t)) |
---|
500 | #+asdf |
---|
501 | (let* ((asd (asdf:system-definition-pathname system)) |
---|
502 | (system (asdf:find-system system)) |
---|
503 | (dir (pathname-sans-name+type |
---|
504 | (asdf::resolve-symlinks asd)))) |
---|
505 | (when (or (not prompt) |
---|
506 | (y-or-n-p |
---|
507 | "Delete system ~A~%asd file: ~A~%sources: ~A~%Are you sure?" |
---|
508 | system asd dir)) |
---|
509 | #-(or :win32 :mswindows) |
---|
510 | (delete-file asd) |
---|
511 | (let ((dir (#-scl namestring #+scl ext:unix-namestring (truename dir)))) |
---|
512 | (when dir |
---|
513 | (asdf:run-shell-command "rm -r '~A'" dir))))) |
---|
514 | |
---|
515 | #+mk-defsystem |
---|
516 | (multiple-value-bind (sysfile sysfile-exists-p) |
---|
517 | (mk:system-definition-pathname system) |
---|
518 | (when sysfile-exists-p |
---|
519 | (let ((system (ignore-errors (mk:find-system system :error)))) |
---|
520 | (when system |
---|
521 | (when (or (not prompt) |
---|
522 | (y-or-n-p |
---|
523 | "Delete system ~A.~%system file: ~A~%Are you sure?" |
---|
524 | system |
---|
525 | sysfile)) |
---|
526 | (mk:clean-system system) |
---|
527 | (delete-file sysfile) |
---|
528 | (dolist (f (mk:files-in-system system)) |
---|
529 | (delete-file f))) |
---|
530 | )) |
---|
531 | ))) |
---|
532 | |
---|
533 | |
---|
534 | ;;; some day we will also do UPGRADE, but we need to sort out version |
---|
535 | ;;; numbering a bit better first |
---|
536 | |
---|
537 | #+(and :asdf (or :win32 :mswindows)) |
---|
538 | (defun sysdef-source-dir-search (system) |
---|
539 | (let ((name (asdf::coerce-name system))) |
---|
540 | (dolist (location *locations*) |
---|
541 | (let* ((dir (first location)) |
---|
542 | (files (directory (merge-pathnames |
---|
543 | (make-pathname :name name |
---|
544 | :type "asd" |
---|
545 | :version :newest |
---|
546 | :directory '(:relative :wild) |
---|
547 | :host nil |
---|
548 | :device nil) |
---|
549 | dir)))) |
---|
550 | (dolist (file files) |
---|
551 | (when (probe-file file) |
---|
552 | (return-from sysdef-source-dir-search file))))))) |
---|
553 | |
---|
554 | (defmethod asdf:find-component :around |
---|
555 | ((module (eql nil)) name) |
---|
556 | (when (or (not *propagate-installation*) |
---|
557 | (member name *systems-installed-this-time* |
---|
558 | :test (lambda (a b) |
---|
559 | (flet ((ensure-string (x) |
---|
560 | (etypecase x |
---|
561 | (symbol (symbol-name x)) |
---|
562 | (string x)))) |
---|
563 | (string-equal (ensure-string a) (ensure-string b)))))) |
---|
564 | (call-next-method))) |
---|
565 | |
---|
566 | (defun show-version-information () |
---|
567 | (let ((version (asdf-install-version))) |
---|
568 | (if version |
---|
569 | (format *standard-output* "~&;;; ASDF-Install version ~A" |
---|
570 | version) |
---|
571 | (format *standard-output* "~&;;; ASDF-Install version unknown; unable to find ASDF system definition.")) |
---|
572 | (values))) |
---|
573 | |
---|
574 | (defun asdf-install-version () |
---|
575 | "Returns the ASDf-Install version information as a string or nil if it cannot be determined." |
---|
576 | (let ((system (asdf:find-system 'asdf-install))) |
---|
577 | (when system (asdf:component-version system)))) |
---|
578 | |
---|
579 | ;; load customizations if any |
---|
580 | (eval-when (:load-toplevel :execute) |
---|
581 | (let* ((*package* (find-package :asdf-install-customize)) |
---|
582 | (file (probe-file (merge-pathnames |
---|
583 | (make-pathname :name ".asdf-install") |
---|
584 | (truename (user-homedir-pathname)))))) |
---|
585 | (when file (load file)))) |
---|
586 | |
---|
587 | ;;; end of file -- install.lisp -- |
---|