source: branches/0.22.x/abcl/contrib/asdf-install/port.lisp

Last change on this file was 12487, checked in by Mark Evenson, 15 years ago

Port of ASDF-INSTALL under 'contrib/asdf-install'.

'abcl.contrib' will package ASDF-INSTALL in dist/abcl-contrib.jar.

We only have one contrib 'asdf-install'. It is not expected to work
well under Windows at the moment.

To use ASDF-INSTALL, use the following in your ~/.abclrc:

(require 'asdf)
(pushnew "jar:file:${dist.dir}/abcl-contrib.jar!/asdf-install/" asdf:*central-registry*)

Then issuing

CL-USER> (require 'asdf-install)

will load ASDF-INSTALL.

A file ~/.asdf-install can contain customizations to help ASDF-INSTALL
find the programs 'tar' and 'gpg'. 'tar' is searched for in
asdf-install:*shell-search-paths*. The location of 'gpg' can be
customized by setting *gpg-command* to a string containing the file.
This behavior should be rationalized in the future.

ASDF-INSTALL tested under OSX.

File size: 17.5 KB
Line 
1(in-package #:asdf-install)
2
3(defvar *temporary-files*)
4
5(defparameter *shell-path* "/bin/sh"
6  "The path to a Bourne compatible command shell in physical pathname notation.")
7
8(eval-when (:load-toplevel :compile-toplevel :execute)
9  #+:allegro
10  (require :osi)
11  #+:allegro
12  (require :socket)
13  #+:digitool
14  (require :opentransport)
15  #+:ecl
16  (require :sockets)
17  #+:lispworks
18  (require "comm")
19  )
20
21(defun get-env-var (name)
22  #+:allegro (sys:getenv name)
23  #+:clisp (ext:getenv name)
24  #+:cmu (cdr (assoc (intern (substitute #\_ #\- name)
25                             :keyword)
26                     ext:*environment-list*))
27  #+:ecl (ext:getenv name)
28  #+:lispworks (lw:environment-variable name)
29  #+(or :mcl :openmcl) (ccl::getenv name)
30  #+:sbcl (sb-ext:posix-getenv name)
31  #+:scl (cdr (assoc name ext:*environment-list* :test #'string=))
32  #+abcl (ext:getenv name)
33  )
34
35#-:digitool
36(defun system-namestring (pathname)
37  (namestring (truename pathname)))
38
39#+:digitool
40(defvar *start-up-volume*
41  (second (pathname-directory (truename "ccl:"))))
42
43#+:digitool
44(defun system-namestring (pathname)
45  ;; this tries to adjust the root directory to eliminate the spurious
46  ;; volume name for the boot file system; it also avoids use of
47  ;; TRUENAME as some applications are for not yet existent files
48  (let ((truename (probe-file pathname)))
49    (unless truename
50      (setf truename
51            (translate-logical-pathname
52             (merge-pathnames pathname *default-pathname-defaults*))))
53    (let ((directory (pathname-directory truename)))
54      (flet ((string-or-nil (value) (when (stringp value) value))
55             (absolute-p (directory) (eq (first directory) :absolute))
56             (root-volume-p (directory)
57               (equal *start-up-volume* (second directory))))
58        (format nil "~:[~;/~]~{~a/~}~@[~a~]~@[.~a~]"
59                (absolute-p directory)
60                (if (root-volume-p directory) (cddr directory) (cdr directory))
61                (string-or-nil (pathname-name truename))
62                (string-or-nil (pathname-type truename)))))))
63
64#+:digitool
65(progn
66  (defun |read-linefeed-eol-comment|
67         (stream char &optional (eol '(#\return #\linefeed)))
68    (loop (setf char (read-char stream nil nil))
69          (unless char (return))
70          (when (find char eol) (return)))
71    (values))
72 
73  (set-syntax-from-char #\linefeed #\space)
74  (set-macro-character #\; #'|read-linefeed-eol-comment| nil *readtable*))
75
76;; for non-SBCL we just steal this from SB-EXECUTABLE
77#-(or :digitool)
78(defvar *stream-buffer-size* 8192)
79#-(or :digitool)
80(defun copy-stream (from to)
81  "Copy into TO from FROM until end of the input stream, in blocks of
82*stream-buffer-size*.  The streams should have the same element type."
83  (unless (subtypep (stream-element-type to) (stream-element-type from))
84    (error "Incompatible streams ~A and ~A." from to))
85  (let ((buf (make-array *stream-buffer-size*
86       :element-type (stream-element-type from))))
87    (loop
88      (let ((pos #-(or :clisp :cmu) (read-sequence buf from)
89                 #+:clisp (ext:read-byte-sequence buf from :no-hang nil)
90                 #+:cmu (sys:read-n-bytes from buf 0 *stream-buffer-size* nil)))
91        (when (zerop pos) (return))
92        (write-sequence buf to :end pos)))))
93
94#+:digitool
95(defun copy-stream (from to)
96  "Perform copy and map EOL mode."
97  (multiple-value-bind (reader reader-arg) (ccl::stream-reader from)
98    (multiple-value-bind (writer writer-arg) (ccl::stream-writer to)
99      (let ((datum nil))
100        (loop (unless (setf datum (funcall reader reader-arg))
101                (return))
102              (funcall writer writer-arg datum))))))
103
104(defun make-stream-from-url (url)
105  #+(or :sbcl :ecl)
106  (let ((s (make-instance 'sb-bsd-sockets:inet-socket
107             :type :stream
108             :protocol :tcp)))
109    (sb-bsd-sockets:socket-connect
110     s (car (sb-bsd-sockets:host-ent-addresses
111             (sb-bsd-sockets:get-host-by-name (url-host url))))
112     (url-port url))
113    (sb-bsd-sockets:socket-make-stream 
114     s
115     :input t 
116     :output t
117     :buffering :full
118     :external-format :iso-8859-1))
119  #+:cmu
120  (sys:make-fd-stream (ext:connect-to-inet-socket (url-host url) (url-port url))
121                      :input t :output t :buffering :full)
122  #+:scl
123  (sys:make-fd-stream (ext:connect-to-inet-socket (url-host url) (url-port url))
124                      :input t :output t :buffering :full
125          :external-format :iso-8859-1)
126  #+:lispworks
127  (comm:open-tcp-stream (url-host url) (url-port url)
128                        #+(and :lispworks :win32) :element-type
129                        #+(and :lispworks :win32) '(unsigned-byte 8))
130  #+:allegro
131  (socket:make-socket :remote-host (url-host url)
132                      :remote-port (url-port url))
133  #+:clisp
134  (socket:socket-connect (url-port url) (url-host url)
135                         :external-format
136                         (ext:make-encoding :charset 'charset:iso-8859-1 :line-terminator :unix))
137  #+:openmcl
138  (ccl:make-socket :remote-host (url-host url)
139                   :remote-port (url-port url))
140  #+:digitool
141  (ccl::open-tcp-stream (url-host url) (url-port url)
142                        :element-type 'unsigned-byte)
143
144  #+:abcl
145  (let ((socket 
146         (ext:make-socket (url-host url) (url-port url))))
147    (ext:get-socket-stream socket)))
148
149
150#+:sbcl
151(defun return-output-from-program (program args)
152  (with-output-to-string (out-stream)
153    (let ((proc (sb-ext:run-program
154                 program
155                 args
156                 :output out-stream
157                 :search t
158                 :wait t)))
159      (when (or (null proc)
160                (and (member (sb-ext:process-status proc) '(:exited :signaled))
161                     (not (zerop (sb-ext:process-exit-code proc)))))
162        (return-from return-output-from-program nil)))))
163
164#+(or :cmu :scl)
165(defun return-output-from-program (program args)
166  (with-output-to-string (out-stream)
167    (let ((proc (ext:run-program
168                 program
169                 args
170                 :output out-stream
171                 :wait t)))
172      (when (or (null proc)
173                (and (member (ext:process-status proc) '(:exited :signaled))
174                     (not (zerop (ext:process-exit-code proc)))))
175        (return-from return-output-from-program nil)))))
176
177#+:lispworks
178(defun return-output-from-program (program args)
179  (with-output-to-string (out-stream)
180    (unless (zerop (sys:call-system-showing-output
181                    (format nil #-:win32 "~A~{ '~A'~}"
182                            #+:win32 "~A~{ ~A~}"
183                            program args)
184                    :prefix ""
185                    :show-cmd nil
186                    :output-stream out-stream))
187      (return-from return-output-from-program nil))))
188
189#+(and :clisp (not :win32))
190(defun return-output-from-program (program args)
191  (with-output-to-string (out-stream)
192    (let ((stream
193           (ext:run-program program
194                            :arguments args
195                            :output :stream
196                            :wait nil)))
197      (loop for line = (read-line stream nil)
198            while line
199            do (write-line line out-stream)))))
200
201#+(and :clisp :win32)
202(defun return-output-from-program (program args)
203  (with-output-to-string (out-stream)
204    (let ((stream
205           (ext:run-shell-command
206            (format nil "~A~{ ~A~}" program args
207                    :output :stream
208                    :wait nil))))
209      (loop for line = (ignore-errors (read-line stream nil))
210            while line
211            do (write-line line out-stream)))))
212
213#+:allegro
214(defun return-output-from-program (program args)
215  (with-output-to-string (out-stream)
216    (let ((stream
217           (excl:run-shell-command
218            #-:mswindows
219            (concatenate 'vector
220                         (list program)
221                         (cons program args))
222            #+:mswindows
223            (format nil "~A~{ ~A~}" program args)
224            :output :stream
225            :wait nil)))
226      (loop for line = (read-line stream nil)
227            while line
228            do (write-line line out-stream)))))
229
230#+:ecl
231(defun return-output-from-program (program args)
232  (with-output-to-string (out-stream)
233    (let ((stream (ext:run-program program args :output :stream)))
234      (when stream
235  (loop for line = (ignore-errors (read-line stream nil))
236        while line
237        do (write-line line out-stream))))))
238
239#+:openmcl
240(defun return-output-from-program (program args)
241  (with-output-to-string (out-stream)
242    (let ((proc (ccl:run-program program args
243                                 :input nil
244                                 :output :stream
245                                 :wait nil)))
246      (loop for line = (read-line
247      (ccl:external-process-output-stream proc) nil nil nil)
248            while line
249            do (write-line line out-stream)))))
250
251#+:digitool
252(defun return-output-from-program (program args)
253  (ccl::call-system (format nil "~A~{ '~A'~} 2>&1" program args)))
254
255#+:abcl
256(defun return-output-from-program (program args) 
257  (let ((command (format nil "~A ~{ '~A' ~}" program args)))
258    (with-output-to-string (out-stream)
259      (ext:run-shell-command command :output out-stream))))
260   
261
262(defun unlink-file (pathname)
263  ;; 20070208 gwking@metabang.com - removed lisp-specific os-level calls
264  ;; in favor of a simple delete
265  (delete-file pathname))
266
267(defun symlink-files (old new)
268  (let* ((old (#-scl namestring #+scl ext:unix-namestring old))
269   (new (#-scl namestring #+scl ext:unix-namestring new #+scl nil))
270   ;; 20070811 - thanks to Juan Jose Garcia-Ripoll for pointing
271   ;; that ~a would wreck havoc if the working directory had a space
272   ;; in the pathname
273   (command (format nil "ln -s ~s ~s" old new)))
274    (format t "~S~%" command)
275    (shell-command command)))
276
277(defun maybe-symlink-sysfile (system sysfile)
278  (declare (ignorable system sysfile))
279  #-(or :win32 :mswindows)
280  (let ((target (merge-pathnames
281                 (make-pathname :name (pathname-name sysfile)
282                                :type (pathname-type sysfile))
283                 system)))
284    (when (probe-file target)
285      (unlink-file target))
286    (symlink-files sysfile target)))
287
288;;; ---------------------------------------------------------------------------
289;;; read-header-line
290;;; ---------------------------------------------------------------------------
291
292#-:digitool
293(defun read-header-line (stream)
294  (read-line stream))
295
296#+:digitool
297(defun read-header-line (stream &aux (line (make-array 16
298                                                       :element-type 'character
299                                                       :adjustable t
300                                                       :fill-pointer 0))
301                                (byte nil))
302  (print (multiple-value-bind (reader arg)
303                              (ccl::stream-reader stream)
304           (loop (setf byte (funcall reader arg))
305                 (case byte
306                   ((nil)
307                    (return))
308                   ((#.(char-code #\Return)
309                     #.(char-code #\Linefeed))
310                    (case (setf byte (funcall reader arg))
311                      ((nil #.(char-code #\Return) #.(char-code #\Linefeed)))
312                      (t (ccl:stream-untyi stream byte)))
313                    (return))
314                   (t
315                    (vector-push-extend (code-char byte) line))))
316           (when (or byte (plusp (length line)))
317             line))))
318
319(defun open-file-arguments ()
320  (append 
321   #+sbcl
322   '(:external-format :latin1)
323   #+:scl
324   '(:external-format :iso-8859-1)
325   #+(or :clisp :digitool (and :lispworks :win32))
326   '(:element-type (unsigned-byte 8))))
327
328(defun download-url-to-file (url file-name)
329  "Resolves url and then downloads it to file-name; returns the url actually used."
330  (multiple-value-bind (response headers stream)
331      (loop
332       (destructuring-bind (response headers stream)
333     (url-connection url)
334   (unless (member response '(301 302))
335     (return (values response headers stream)))
336   (close stream)
337   (setf url (header-value :location headers))))
338    (when (>= response 400)
339      (error 'download-error :url url :response response))
340    (let ((length (parse-integer (or (header-value :content-length headers) "")
341         :junk-allowed t)))
342      (installer-msg t "Downloading ~A bytes from ~A to ~A ..."
343         (or length "some unknown number of")
344         url
345         file-name)
346      (force-output)
347      #+:clisp (setf (stream-element-type stream)
348         '(unsigned-byte 8))
349      (let ((ok? nil) (o nil))
350  (unwind-protect
351       (progn
352         (setf o (apply #'open file-name 
353            :direction :output :if-exists :supersede
354            (open-file-arguments)))
355         #+(or :cmu :digitool)
356         (copy-stream stream o)
357         #-(or :cmu :digitool)
358         (if length
359       (let ((buf (make-array length
360            :element-type
361            (stream-element-type stream))))
362         #-:clisp (read-sequence buf stream)
363         #+:clisp (ext:read-byte-sequence buf stream :no-hang nil)
364         (write-sequence buf o))
365       (copy-stream stream o))
366         (setf ok? t))
367    (when o (close o :abort (null ok?))))))
368    (close stream))
369  (values url))
370
371(defun download-url-to-temporary-file (url)
372  "Attempts to download url to a new, temporary file. Returns the resolved url and the file name \(as multiple values\)."
373  (let ((tmp (temp-file-name url)))
374    (pushnew tmp *temporary-files*)
375    (values (download-url-to-file url tmp) tmp)))
376
377(defun gpg-results (package signature)
378  (let ((tags nil))
379    (with-input-from-string
380  (gpg-stream 
381   (shell-command (format nil "~s --status-fd 1 --verify ~s ~s"
382                                *gpg-command*
383        (namestring signature) (namestring package))))
384      (loop for l = (read-line gpg-stream nil nil)
385   while l
386   do (print l)
387   when (> (mismatch l "[GNUPG:]") 6)
388   do (destructuring-bind (_ tag &rest data)
389    (split-sequence-if (lambda (x)
390             (find x '(#\Space #\Tab)))
391           l)
392        (declare (ignore _))
393        (pushnew (cons (intern (string-upcase tag) :keyword)
394           data) tags)))
395      tags)))
396
397#+allegro
398(defun shell-command (command)
399  (multiple-value-bind (output error status)
400                 (excl.osi:command-output command :whole t)
401    (values output error status)))
402
403#+clisp
404(defun shell-command (command)
405  ;; BUG: CLisp doesn't allow output to user-specified stream
406  (values
407   nil
408   nil
409   (ext:run-shell-command  command :output :terminal :wait t)))
410
411#+(or :cmu :scl)
412(defun shell-command (command)
413  (let* ((process (ext:run-program
414                   *shell-path*
415                   (list "-c" command)
416                   :input nil :output :stream :error :stream))
417         (output (file-to-string-as-lines (ext::process-output process)))
418         (error (file-to-string-as-lines (ext::process-error process))))
419    (close (ext::process-output process))
420    (close (ext::process-error process))
421    (values
422     output
423     error
424     (ext::process-exit-code process))))
425
426#+ecl
427(defun shell-command (command)
428  ;; If we use run-program, we do not get exit codes
429  (values nil nil (ext:system command)))
430
431#+lispworks
432(defun shell-command (command)
433  ;; BUG: Lispworks combines output and error streams
434  (let ((output (make-string-output-stream)))
435    (unwind-protect
436      (let ((status
437             (system:call-system-showing-output
438              command
439              :prefix ""
440              :show-cmd nil
441              :output-stream output)))
442        (values (get-output-stream-string output) nil status))
443      (close output))))
444
445#+openmcl
446(defun shell-command (command)
447  (let* ((process (create-shell-process command t))
448         (output (file-to-string-as-lines 
449                  (ccl::external-process-output-stream process)))
450         (error (file-to-string-as-lines
451                 (ccl::external-process-error-stream process))))
452    (close (ccl::external-process-output-stream process))
453    (close (ccl::external-process-error-stream process))
454    (values output
455            error
456            (process-exit-code process))))
457
458#+openmcl
459(defun create-shell-process (command wait)
460  (ccl:run-program
461   *shell-path*
462   (list "-c" command)
463   :input nil :output :stream :error :stream
464   :wait wait))
465
466#+openmcl
467(defun process-exit-code (process)
468  (nth-value 1 (ccl:external-process-status process)))
469
470#+digitool
471(defun shell-command (command)
472  ;; BUG: I have no idea what this returns
473  (ccl::call-system command))
474
475#+sbcl
476(defun shell-command (command)
477  (let* ((process (sb-ext:run-program
478                   *shell-path*
479                   (list "-c" command)
480                   :input nil :output :stream :error :stream))
481         (output (file-to-string-as-lines (sb-impl::process-output process)))
482         (error (file-to-string-as-lines (sb-impl::process-error process))))
483    (close (sb-impl::process-output process))
484    (close (sb-impl::process-error process))
485    (values
486     output
487     error
488     (sb-impl::process-exit-code process))))
489
490#+:abcl
491(defun shell-command (command)
492  (let* ((output (make-string-output-stream))
493         (status 
494          (ext:run-shell-command command :output output)))
495    (values (get-output-stream-string output) nil (format nil "~A" status))))
496
497(defgeneric file-to-string-as-lines (pathname)
498  (:documentation ""))
499
500(defmethod file-to-string-as-lines ((pathname pathname))
501  (with-open-file (stream pathname :direction :input)
502    (file-to-string-as-lines stream)))
503
504(defmethod file-to-string-as-lines ((stream stream))
505  (with-output-to-string (s)
506    (loop for line = (read-line stream nil :eof nil) 
507   until (eq line :eof) do
508   (princ line s)
509   (terpri s))))
510
511;; copied from ASDF
512(defun pathname-sans-name+type (pathname)
513  "Returns a new pathname with same HOST, DEVICE, DIRECTORY as PATHNAME,
514and NIL NAME and TYPE components"
515  (make-pathname :name nil :type nil :defaults pathname))
516
Note: See TracBrowser for help on using the repository browser.