Remove ASDF-INSTALL from ABCL-CONTRIB

The Quicklisp library manager has superseded all plausible use of
ADSF-INSTALL at this historical moment.
parent 332d2e14
......@@ -19,12 +19,12 @@
dc:identifier <urn:abcl.org/1.4.0#dev> ;
doap:language "Common Lisp" ;
dc:created "01-JAN-2004" ;
dc:modified "29-SEP-2016" ;
dc:modified "01-OCT-2016" ;
dc:version "abcl-1.4.0" ;
dc:release "dev" ;
abcl:git <https://github.com/easye/abcl/> ; # Does this overwrite? TODO Check RDF specs.
abcl:git <https://gitlab.common-lisp.net/mevenson/abcl/> ;
abcl:svn <http://abcl.org/trac/changeset/14875> .
abcl:svn <http://abcl.org/trac/changeset/14885> .
<>
rdfs:seeAlso <file:README> ;
......@@ -137,7 +137,6 @@ doap:Project rdfs:seeAlso
a rdf:Alt;
rdf:_1 abcl:abcl ;
rdf:_2 abcl:abcl-contrib ;
rdf:_3 abcl:asdf-install ; # remove with abcl-1.4.0
rdf:_4 abcl:jss ;
rdf:_5 abcl:jfli ;
rdf:_6 abcl:abcl-asdf ;
......@@ -146,22 +145,17 @@ doap:Project rdfs:seeAlso
rdf:_9 abcl:quicklisp-abcl ;
] .
abcl:asdf dc:version "3.1.7.26" .
abcl:jna dc:version "4.2.2" .
abcl:asdf dc:version "3.1.7.27" .
abcl:abcl-contrib
rdfs:seeAlso <file:contrib/README.markdown> .
abcl:asdf-install
rdfs:seeAlso <file:contrib/asdf-install/README> .
abcl:abcl-asdf
rdfs:seeAlso <file:contrib/asdf-asdf/README.markdown> .
abcl:asdf-jar
rdfs:seeAlso <file:contrib/asdf-jar/README.markdown> .
abcl:jfli
rdfs:seeAlso <file:contrib/jfli/README> .
abcl:jss
rdfs:seeAlso <file:contrib/jss/README.markdown> .
......
......@@ -4,6 +4,10 @@ ABCL-CONTRIB
The contributions to Armed Bear constitute Common Lisp only code that
is potentially useful for system construction and distribution.
quicklisp-abcl
Loads and installs the Quicklisp library manager from the network
if not locally present.
abcl-asdf
......@@ -38,13 +42,6 @@ jfli
[jfli]: http://sourceforge.net/projects/jfli/
quicklisp-abcl
Stub for loading Quicklisp from main repository if not locally
present. Must currently be invoked with the force option:
CL-USER> (asdf:load-system :quicklisp-abcl :force t)
mvn
A collection of various useful JVM artifacts downloaded and cached by
the Aether Maven connector. Requires the maven-3.0.3 executable "mvn"
......@@ -54,29 +51,16 @@ mvn
mvn currently includes only the single artifact:
jna
Cache, from the network if necessary, the jna-3.4.0.jar in
the current JVM process, allowing the bootstrapping of
dynamically linking to shared executables on the host platform.
Deprecated
----------
asdf-install
Install ASDF system definitions from the network.
Deprecated, use Quicklisp from the REPL via
CL-USER> (load "http://beta.quicklisp.org/quicklisp.lisp")
instead.
Cache, from the network if necessary, the jna-4.2.2.jar binary
artifact in the current JVM process, allowing the
bootstrapping of dynamically linking to shared executables on
the host platform.
# Colophon
Mark <evenson.not.org@gmail.com>
Created: 2011-09-11
Revised: 2012-12-06
Revised: 2016-10-01
<> abcl:documents <release#abcl-contrib.jar> .
......
The original ASDF-INSTALL code (the files Makefile, README,
asdf-install.asd, defpackage.lisp, and installer.lisp) was written by
Daniel Barlow <dan@telent.net> and is distributed with SBCL and
therefore in the public domain. The SBCL Common Lisp implementation
can be obtained from Sourceforge: <http://sbcl.sf.net/>.
The initial port of ASDF-INSTALL to other Lisps was done by Dr. Edmund
Weitz <edi@agharta.de> and included the file port.lisp and some
changes to the files mentioned above. More code was provided by Marco
Baringer <mb@bese.it> (OpenMCL port), James Anderson
<james.anderson@setf.de> (MCL port, including the file digitool.lisp),
Kiyoshi Mizumaru <maru@krc.sony.co.jp>, Robert P. Goldman
<rpgoldman@sift.info>, and Raymond Toy <toy@rtp.ericsson.se>
(bugfixes). Marco Antoniotti <marcoxa@cs.nyu.edu> added support for
MK:DEFSYSTEM which includes the files load-asdf-install.lisp,
loader.lisp, and finally split-sequence.lisp which has its own
copyright notice. ASDF-Install is currently maintained by Gary King
<gwking@metabang.com> and is hosted on Common-Lisp.net.
The complete code distributed with this archive (asdf-install.tar.gz)
is copyrighted by the above-mentioned authors and governed by the
following license.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHORS 'AS IS' AND ANY EXPRESSED OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
SYSTEM=asdf-install
EXTRA_INSTALL_TARGETS=asdf-install-install
include ../asdf-module.mk
asdf-install-install: asdf-install
if test -f $(BUILD_ROOT)$(INSTALL_ROOT)/bin/sbcl-asdf-install ; then \
mv $(BUILD_ROOT)$(INSTALL_ROOT)/bin/sbcl-asdf-install $(BUILD_ROOT)$(INSTALL_ROOT)/bin/sbcl-asdf-install.old ; \
fi
# KLUDGE: mv rather than cp because keeping asdf-install in that
# directory interferes with REQUIRE, and this is done before the tar
# in ../asdf-module.mk. Better solutions welcome.
mv asdf-install $(BUILD_ROOT)$(INSTALL_ROOT)/bin/sbcl-asdf-install
Downloads and installs an ASDF or a MK:DEFSYSTEM system or anything
else that looks convincingly like one. It updates the
ASDF:*CENTRAL-REGISTRY* symlinks for all the toplevel .asd files it
contains, and it also MK:ADD-REGISTRY-LOCATION for the appropriate
directories for MK:DEFSYSTEM.
Please read this file before use: in particular: this is an automatic
tool that downloads and compiles stuff it finds on the 'net. Please
look at the SECURITY section and be sure you understand the
implications
= USAGE
This can be used either from within a CL implementation:
cl-prompt> (load "/path/to/load-asdf-install.lisp")
cl-prompt> (asdf-install:install 'xlunit) ; for example
With SBCL you can also use the standalone command `sbcl-asdf-install'
from the shell:
$ sbcl-asdf-install xlunit
Each argument may be -
- The name of a cliki page. asdf-install visits that page and finds
the download location from the `:(package)' tag - usually rendered
as "Download ASDF package from ..."
- A URL, which is downloaded directly
- A local tar.gz file, which is installed
= SECURITY CONCERNS: READ THIS CAREFULLY
When you invoke asdf-install, you are asking your CL implementation to
download, compile, and install software from some random site on the
web. Given that it's indirected through a page on CLiki, any
malicious third party doesn't even need to hack the distribution
server to replace the package with something else: he can just edit
the link.
For this reason, we encourage package providers to crypto-sign their
packages (see details at the URL in the PACKAGE CREATION section) and
users to check the signatures. asdf-install has three levels of
automatic signature checking: "on", "off" and "unknown sites", which
can be set using the configuration variables described in
CUSTOMIZATION below. The default is "unknown sites", which will
expect a GPG signature on all downloads except those from
presumed-good sites. The current default presumed-good sites are
CCLAN nodes, and two web sites run by SBCL maintainers: again, see
below for customization details
= CUSTOMIZATION
If the file $HOME/.asdf-install exists, it is loaded. This can be
used to override the default values of exported special variables.
Presently these are
*PROXY*
defaults to $http_proxy environment variable
*CCLAN-MIRROR*
preferred/nearest CCLAN node. See the list at
http://ww.telent.net/cclan-choose-mirror
*ASDF-INSTALL-DIRS*
Set from ASDF_INSTALL_DIR environment variable. If you are running
SBCL, then *ASDF-INSTALL-DIRS* may be set form the environment variable
SBCL_HOME, which should already be correct for whatever SBCL is
running, if it's been installed correctly. This is done for
backward compatibility with SBCL installations.
*SBCL-HOME*
This is actually a symbol macro for *ASDF-INSTALL-DIRS*
*VERIFY-GPG-SIGNATURES*
Verify GPG signatures for the downloaded packages?
NIL - no, T - yes, :UNKNOWN-LOCATIONS - only for URLs which aren't in CCLAN
and don't begin with one of the prefixes in *SAFE-URL-PREFIXES*
*LOCATIONS*
Possible places in the filesystem to install packages into. See default
value for format
*SAFE-URL-PREFIXES*
List of locations for which GPG signature checking /won't/ be done when
*verify-gpg-signatures* is :unknown-locations
= PACKAGE CREATION
If you want to create your own packages that can be installed using this
loader, see the "Making your package downloadable..." section at
<http://www.cliki.net/asdf-install>
= HACKERS NOTE
Listen very carefully: I will say this only as often as it appears to
be necessary to say it. asdf-install is not a good example of how to
write a URL parser, HTTP client, or anything else, really.
Well-written extensible and robust URL parsers, HTTP clients, FTP
clients, etc would definitely be nice things to have, but it would be
nicer to have them in CCLAN where anyone can use them - after having
downloaded them with asdf-install - than in SBCL contrib where they're
restricted to SBCL users and can only be updated once a month via SBCL
developers. This is a bootstrap tool, and as such, will tend to
resist changes that make it longer or dependent on more other
packages, unless they also add to its usefulness for bootstrapping.
= TODO
a) gpg signature checking would be better if it actually checked against
a list of "trusted to write Lisp" keys, instead of just "trusted to be
who they say they are"
e) nice to have: resume half-done downloads instead of starting from scratch
every time. but right now we're dealing in fairly small packages, this is not
an immediate concern
12 Sept 2006 gwking@metabang.com
* added :where parameter to install
* now uses more tempoary files
* changed selection of locations - 0 is always abort, can use symbols / strings
;;; -*- Lisp -*-
;;; Portatble ASDF-Install is based on Dan Barlow's ASDF-Install
;; (see the file COPYRIGHT for details). It is currently maintained
;; by Gary King <gwking@metabang.com>.
(defpackage #:asdf-install-system
(:use #:cl #:asdf))
(in-package #:asdf-install-system)
(defsystem asdf-install
#+:sbcl :depends-on
#+:sbcl (sb-bsd-sockets)
:version "0.6.10.3"
:description "<> asdf:defsystem <urn:abcl.org/release/1.3.0/contrib/asdf-install#0.6.10.3>"
:author "Dan Barlow <dan@telent.net>, Edi Weitz <edi@agharta.de> and many others. See the file COPYRIGHT for more details."
:maintainer "Gary Warren King <gwking@metabang.com> // ABCL <evenson@not.org> ."
:components ((:file "defpackage")
(:file "split-sequence" :depends-on ("defpackage"))
(:file "port" :depends-on ("defpackage" "split-sequence"))
#+:digitool
(:file "digitool" :depends-on ("port"))
(:file "conditions" :depends-on ("defpackage" "variables"))
(:file "variables" :depends-on ("port"))
(:file "installer"
:depends-on ("port" "split-sequence"
#+:digitool "digitool"
"conditions" "variables"))
(:file "deprecated" :depends-on ("installer")))
:in-order-to ((test-op (load-op test-asdf-install)))
:perform (test-op :after (op c)
(funcall
(intern (symbol-name '#:run-tests) :lift)
:config :generic)))
(defmethod perform :after ((o load-op) (c (eql (find-system :asdf-install))))
(let ((show-version (find-symbol
(symbol-name '#:show-version-information)
'#:asdf-install)))
(when (and show-version (fboundp show-version))
(funcall show-version)))
(provide 'asdf-install))
(defmethod operation-done-p
((o test-op) (c (eql (find-system :asdf-install))))
nil)
#+(or)
(defmethod perform ((o test-op) (c (eql (find-system :asdf-install))))
t)
(in-package #:asdf-install)
(define-condition download-error (error)
((url :initarg :url :reader download-url)
(response :initarg :response :reader download-response))
(:report (lambda (c s)
(format s "Server responded ~A for GET ~A"
(download-response c) (download-url c)))))
(define-condition signature-error (error)
((cause :initarg :cause :reader signature-error-cause))
(:report (lambda (c s)
(format s "Cannot verify package signature: ~A"
(signature-error-cause c)))))
(define-condition gpg-error (error)
((message :initarg :message :reader gpg-error-message))
(:report (lambda (c s)
(format s "GPG failed with error status:~%~S"
(gpg-error-message c)))))
(define-condition gpg-shell-error (gpg-error)
()
(:report (lambda (c s)
(declare (ignore c))
(format s "Call to GPG failed. Perhaps GPG is not installed or not ~
in the path."))))
(define-condition no-signature (gpg-error) ())
(define-condition key-not-found (gpg-error)
((key-id :initarg :key-id :reader key-id))
(:report (lambda (c s)
(let* ((*print-circle* nil)
(key-id (key-id c))
(key-id (if (and (consp key-id)
(> (length key-id) 1))
(car key-id) key-id)))
(format s "~&No key found for key id 0x~A.~%" key-id)
(format s "~&Try some command like ~% gpg --recv-keys 0x~A"
(format nil "~a" key-id))))))
(define-condition key-not-trusted (gpg-error)
((key-id :initarg :key-id :reader key-id)
(key-user-name :initarg :key-user-name :reader key-user-name))
(:report (lambda (c s)
(format s "GPG warns that the key id 0x~A (~A) is not fully trusted"
(key-id c) (key-user-name c)))))
(define-condition author-not-trusted (gpg-error)
((key-id :initarg :key-id :reader key-id)
(key-user-name :initarg :key-user-name :reader key-user-name))
(:report (lambda (c s)
(format s "~A (key id ~A) is not on your package supplier list"
(key-user-name c) (key-id c)))))
(define-condition installation-abort (condition)
()
(:report (lambda (c s)
(declare (ignore c))
(installer-msg s "Installation aborted."))))
(defun report-valid-preferred-locations (stream &optional attempted-location)
(when attempted-location
(installer-msg stream "~s is not a valid value for *preferred-location*"
attempted-location))
(installer-msg stream "*preferred-location* may either be nil, a number between 1 and ~d \(the length of *locations*\) or the name of one of the *locations* \(~{~s~^, ~}\). If using a name, then it can be a symbol tested with #'eq or a string tested with #'string-equal."
(length *locations*)
(mapcar #'third *locations*)))
(define-condition invalid-preferred-location-error (error)
((preferred-location :initarg :preferred-location))
(:report (lambda (c s)
(report-valid-preferred-locations
s (slot-value c 'preferred-location)))))
(define-condition invalid-preferred-location-number-error
(invalid-preferred-location-error) ())
(define-condition invalid-preferred-location-name-error
(invalid-preferred-location-error) ())
;;;; dead letter
#+Old
(defun load-system-definition (sysfile)
(declare (type pathname sysfile))
#+asdf
(when (or (string-equal "asd" (pathname-type sysfile))
(string-equal "asdf" (pathname-type sysfile)))
(installer-msg t "Loading system ~S via ASDF." (pathname-name sysfile))
;; just load the system definition
(load sysfile)
#+Ignore
(asdf:operate 'asdf:load-op (pathname-name sysfile)))
#+mk-defsystem
(when (string-equal "system" (pathname-type sysfile))
(installer-msg t "Loading system ~S via MK:DEFSYSTEM." (pathname-name sysfile))
(mk:load-system (pathname-name sysfile))))
#+Old
;; from download-files-for-package
(with-open-file
#-(and allegro-version>= (not (version>= 8 0)))
(o file-name :direction :output
#+(or :clisp :digitool (and :lispworks :win32))
:element-type
#+(or :clisp :digitool (and :lispworks :win32))
'(unsigned-byte 8)
#+:sbcl #+:sbcl :external-format :latin1
:if-exists :supersede)
;; for Allegro versions < 8.0, the above #+sbcl #+sbcl
;; will cause an error [2006/01/09:rpg]
#+(and allegro-version>= (not (version>= 8 0)))
(o file-name :direction :output :if-exists :supersede))
\ No newline at end of file
(cl:in-package :cl-user)
(defpackage #:asdf-install
(:use #:common-lisp)
#+asdf
(:import-from #:asdf #:*defined-systems*)
(:export
;; Customizable variables.
#:*shell-path*
#:*proxy*
#:*cclan-mirror*
#:asdf-install-dirs
#:private-asdf-install-dirs
#:*tar-extractors*
#:*shell-search-paths*
#:*verify-gpg-signatures*
#:*locations*
#:*safe-url-prefixes*
#:*preferred-location*
#:*temporary-directory*
;; External entry points.
#:add-locations
#:add-registry-location
#:uninstall
#:install
#:asdf-install-version
#+(and asdf (or :win32 :mswindows))
#:sysdef-source-dir-search
;; proxy authentication
#:*proxy-user*
#:*proxy-passwd*
;; conditions
#:download-error
#:signature-error
#:gpg-error
#:gpg-shell-error
#:key-not-found
#:key-not-trusted
#:author-not-trusted
#:installation-abort
;; restarts
#:install-anyways
)
#+(or :win32 :mswindows)
(:export
#:*cygwin-bin-directory*
#:*cygwin-bash-command*))
(defpackage #:asdf-install-customize
(:use #:common-lisp #:asdf-install))
(in-package asdf-install)
#+(and ignore sbcl) ; Deprecated.
(define-symbol-macro *sbcl-home* *asdf-install-dirs*)
#+(and ignore sbcl) ; Deprecated.
(define-symbol-macro *dot-sbcl* *private-asdf-install-dirs*)
#+(or)
;; uncalled
(defun read-until-eof (stream)
(with-output-to-string (o)
(copy-stream stream o)))
#+(or)
(defun verify-gpg-signature/string (string file-name)
(block verify
(loop
(restart-case
(let ((gpg-stream (make-stream-from-gpg-command string file-name))
tags)
(unwind-protect
(loop for l = (read-line gpg-stream nil nil)
while l
do (print l)
when (> (mismatch l "[GNUPG:]") 6)
do (destructuring-bind (_ tag &rest data)
(split-sequence-if (lambda (x)
(find x '(#\Space #\Tab)))
l)
(declare (ignore _))
(pushnew (cons (intern (string-upcase tag) :keyword)
data) tags)))
(ignore-errors
(close gpg-stream)))
;; test that command returned something
(unless tags
(error 'gpg-shell-error))
;; test for obvious key/sig problems
(let ((errsig (header-value :errsig tags)))
(and errsig (error 'key-not-found :key-id errsig)))
(let ((badsig (header-value :badsig tags)))
(and badsig (error 'key-not-found :key-id badsig)))
(let* ((good (header-value :goodsig tags))
(id (first good))
(name (format nil "~{~A~^ ~}" (rest good))))
;; good signature, but perhaps not trusted
(restart-case
(let ((trusted? (or (header-pair :trust_ultimate tags)
(header-pair :trust_fully tags)))
(in-list? (assoc id *trusted-uids* :test #'equal)))
(cond ((or trusted? in-list?)
;; ok
)
((not trusted?)
(error 'key-not-trusted :key-user-name name :key-id id))
((not in-list?)
(error 'author-not-trusted
:key-user-name name :key-id id))
(t
(error "Boolean logic gone bad. Run for the hills"))))
(add-key (&rest rest)
:report "Add to package supplier list"
(declare (ignore rest))
(pushnew (list id name) *trusted-uids*))))
(return-from verify t))
#+Ignore
(install-anyways (&rest rest)
:report "Don't check GPG signature for this package"
(declare (ignore rest))
(return-from verify t))
(retry-gpg-check (&rest args)
:report "Retry GPG check \(e.g., after downloading the key\)"
(declare (ignore args))
nil)))))
#+(or)
(defun verify-gpg-signature/url (url file-name)
(block verify
(loop
(restart-case
(when (verify-gpg-signatures-p url)
(let ((sig-url (concatenate 'string url ".asc")))
(destructuring-bind (response headers stream)
(url-connection sig-url)
(unwind-protect
(flet (#-:digitool
(read-signature (data stream)
(read-sequence data stream))
#+:digitool
(read-signature (data stream)
(multiple-value-bind (reader arg)
(ccl:stream-reader stream)
(let ((byte 0))
(dotimes (i (length data))
(unless (setf byte (funcall reader arg))
(error 'download-error :url sig-url
:response 200))
(setf (char data i) (code-char byte)))))))
(if (= response 200)
(let ((data (make-string (parse-integer
(header-value :content-length headers)
:junk-allowed t))))
(read-signature data stream)
(verify-gpg-signature/string data file-name))
(error 'download-error :url sig-url
:response response)))
(close stream)
(return-from verify t)))))
(install-anyways (&rest rest)
:report "Don't check GPG signature for this package"
(declare (ignore rest))
(return-from verify t))
(retry-gpg-check (&rest args)
:report "Retry GPG check \(e.g., after fixing the network connection\)"
(declare (ignore args))
nil)))))
#+(or :sbcl :cmu :scl)
(defun make-stream-from-gpg-command (string file-name)
(#+:sbcl sb-ext:process-output
#+(or :cmu :scl) ext:process-output
(#+:sbcl sb-ext:run-program
#+(or :cmu :scl) ext:run-program
"gpg"
(list
"--status-fd" "1" "--verify" "-"
(namestring file-name))
:output :stream
:error nil
#+sbcl :search #+sbcl t
:input (make-string-input-stream string)
:wait t)))
#+(and :lispworks (not :win32))
(defun make-stream-from-gpg-command (string file-name)
;; kludge - we can't separate the in and out streams
(let ((stream (sys:open-pipe (format nil "echo '~A' | gpg --status-fd 1 --verify - ~A"
string
(namestring file-name)))))
stream))
#+(and :lispworks :win32)
(defun make-stream-from-gpg-command (string file-name)
(sys:open-pipe (format nil "gpg --status-fd 1 --verify \"~A\" \"~A\""
(make-temp-sig file-name string)
(namestring file-name))))
#+(and :clisp (not (or :win32 :cygwin)))
(defun make-stream-from-gpg-command (string file-name)
(let ((stream
(ext:run-shell-command (format nil "echo '~A' | gpg --status-fd 1 --verify - ~A"
string
(namestring file-name))
:output :stream
:wait nil)))
stream))
#+(and :clisp (or :win32 :cygwin))
(defun make-stream-from-gpg-command (string file-name)
(ext:run-shell-command (format nil "gpg --status-fd 1 --verify \"~A\" \"~A\""
(make-temp-sig file-name string)
(namestring file-name))
:output :stream
:wait nil))
#+:allegro
(defun make-stream-from-gpg-command (string file-name)
(multiple-value-bind (in-stream out-stream)
(excl:run-shell-command
#-:mswindows
(concatenate 'vector
#("gpg" "gpg" "--status-fd" "1" "--verify" "-")
(make-sequence 'vector 1
:initial-element (namestring file-name)))
#+:mswindows
(format nil "gpg --status-fd 1 --verify - \"~A\"" (namestring file-name))
:input :stream
:output :stream
:separate-streams t
:wait nil)
(write-string string in-stream)
(finish-output in-stream)
(close in-stream)
out-stream))
#+:openmcl
(defun make-stream-from-gpg-command (string file-name)
(let ((proc (ccl:run-program "gpg" (list "--status-fd" "1" "--verify" "-" (namestring file-name))
:input :stream
:output :stream
:wait nil)))
(write-string string (ccl:external-process-input-stream proc))
(close (ccl:external-process-input-stream proc))
(ccl:external-process-output-stream proc)))
#+:digitool
(defun make-stream-from-gpg-command (string file-name)
(make-instance 'popen-input-stream
:command (format nil "echo '~A' | gpg --status-fd 1 --verify - '~A'"
string
(system-namestring file-name))))