Previous: , Up: Miscellaneous additional functionality   [Contents][Index]


11.4 Some Utility Functions

The below functions are not exported by ASDF itself, but by UIOP, available since ASDF 3. Some of them have precursors in ASDF 2, but we recommend that for active developments, you should rely on the package UIOP as included in ASDF 3. UIOP provides many, many more utility functions, and we recommend you read its README.md and sources for more information.

Function: parse-unix-namestring name &key type defaults dot-dot ensure-directory &allow-other-keys

Coerce name into a pathname using standard Unix syntax.

Unix syntax is used whether or not the underlying system is Unix; on non-Unix systems it is only usable for relative pathnames. In order to manipulate relative pathnames portably, it is crucial to possess a portable pathname syntax independent of the underlying OS. This is what parse-unix-namestring provides, and why we use it in ASDF.

When given a pathname object, just return it untouched. When given nil, just return nil. When given a non-null symbol, first downcase its name and treat it as a string. When given a string, portably decompose it into a pathname as below.

#\/ separates directory components.

The last #\/-separated substring is interpreted as follows: 1- If type is :directory or ensure-directory is true, the string is made the last directory component, and its name and type are nil. if the string is empty, it’s the empty pathname with all slots nil. 2- If type is nil, the substring is a file-namestring, and its name and type are separated by split-name-type. 3- If type is a string, it is the given type, and the whole string is the name.

Directory components with an empty name the name . are removed. Any directory named .. is read as dot-dot, which must be one of :back or :up and defaults to :back.

host, device and version components are taken from defaults, which itself defaults to *nil-pathname*. *nil-pathname* is also used if defaults is nil. No host or device can be specified in the string itself, which makes it unsuitable for absolute pathnames outside Unix.

For relative pathnames, these components (and hence the defaults) won’t matter if you use merge-pathnames* but will matter if you use merge-pathnames, which is an important reason to always use merge-pathnames*.

Arbitrary keys are accepted, and the parse result is passed to ensure-pathname with those keys, removing type, defaults and dot-dot. When you’re manipulating pathnames that are supposed to make sense portably even though the OS may not be Unixish, we recommend you use :want-relative t so that parse-unix-namestring will throw an error if the pathname is absolute.

Function: merge-pathnames* specified &optional defaults

This function is a replacement for merge-pathnames that uses the host and device from the defaults rather than the specified pathname when the latter is a relative pathname. This allows ASDF and its users to create and use relative pathnames without having to know beforehand what are the host and device of the absolute pathnames they are relative to.

Function: subpathname pathname subpath &key type

This function takes a pathname and a subpath and a type. If subpath is already a pathname object (not namestring), and is an absolute pathname at that, it is returned unchanged; otherwise, subpath is turned into a relative pathname with given type as per parse-unix-namestring with :want-relative t :type type, then it is merged with the pathname-directory-pathname of pathname, as per merge-pathnames*.

We strongly encourage the use of this function for portably resolving relative pathnames in your code base.

Function: subpathname* pathname subpath &key type

This function returns nil if the base pathname is nil, otherwise acts like subpathname.

Function: run-program command &key ignore-error-status force-shell input output error-output if-input-does-not-exist if-output-exists if-error-output-exists element-type external-format &allow-other-keys

run-program takes a command argument that is either a list of a program name or path and its arguments, or a string to be executed by a shell. It spawns the command, waits for it to return, verifies that it exited cleanly (unless told not too below), and optionally captures and processes its output. It accepts many keyword arguments to configure its behaviour.

run-program returns three values: the first for the output, the second for the error-output, and the third for the return value. (Beware that before ASDF 3.0.2.11, it didn’t handle input or error-output, and returned only one value, the one for the output if any handler was specified, or else the exit code; please upgrade ASDF, or at least UIOP, to rely on the new enhanced behaviour.)

output is its most important argument; it specifies how the output is captured and processed. If it is nil, then the output is redirected to the null device, that will discard it. If it is :interactive, then it is inherited from the current process (beware: this may be different from your *standard-output*, and under SLIME will be on your *inferior-lisp* buffer). If it is t, output goes to your current *standard-output* stream. Otherwise, output should be a value that is a suitable first argument to slurp-input-stream (see below), or a list of such a value and keyword arguments. In this case, run-program will create a temporary stream for the program output; the program output, in that stream, will be processed by a call to slurp-input-stream, using output as the first argument (or if it’s a list the first element of output and the rest as keywords). The primary value resulting from that call (or nil if no call was needed) will be the first value returned by run-program. E.g., using :output :string will have it return the entire output stream as a string. And using :output '(:string :stripped t) will have it return the same string stripped of any ending newline.

error-output is similar to output, except that the resulting value is returned as the second value of run-program. t designates the *error-output*. Also :output means redirecting the error output to the output stream, in which case nil is returned.

input is similar to output, except that vomit-output-stream is used, no value is returned, and t designates the *standard-input*.

element-type and external-format are passed on to your Lisp implementation, when applicable, for creation of the output stream.

One and only one of the stream slurping or vomiting may or may not happen in parallel in parallel with the subprocess, depending on options and implementation, and with priority being given to output processing. Other streams are completely produced or consumed before or after the subprocess is spawned, using temporary files.

force-shell forces evaluation of the command through a shell, even if it was passed as a list rather than a string. If a shell is used, it is /bin/sh on Unix or CMD.EXE on Windows, except on implementations that (erroneously, IMNSHO) insist on consulting $SHELL like clisp.

ignore-error-status causes run-program to not raise an error if the spawned program exits in error. Following POSIX convention, an error is anything but a normal exit with status code zero. By default, an error of type subprocess-error is raised in this case.

run-program works on all platforms supported by ASDF, except Genera. See the source code for more documentation.

Function: slurp-input-stream processor input-stream &key

slurp-input-stream is a generic function of two arguments, a target object and an input stream, and accepting keyword arguments. Predefined methods based on the target object are as follows:

  • If the object is a function, the function is called with the stream as argument.
  • If the object is a cons, its first element is applied to its rest appended by a list of the input stream.
  • If the object is an output stream, the contents of the input stream are copied to it. If the linewise keyword argument is provided, copying happens line by line, and an optional prefix is printed before each line. Otherwise, copying happen based on a buffer of size buffer-size, using the specified element-type.
  • If the object is 'string or :string, the content is captured into a string. Accepted keywords include the element-type and a flag stripped, which when true causes any single line ending to be removed as per uiop:stripln.
  • If the object is :lines, the content is captured as a list of strings, one per line, without line ending. If the count keyword argument is provided, it is a maximum count of lines to be read.
  • If the object is :line, the content is captured as with :lines above, and then its sub-object is extracted with the at argument, which defaults to 0, extracting the first line. A number will extract the corresponding line. See the documentation for uiop:access-at.
  • If the object is :forms, the content is captured as a list of s-expressions, as read by the Lisp reader. If the count argument is provided, it is a maximum count of lines to be read. We recommend you control the syntax with such macro as uiop:with-safe-io-syntax.
  • If the object is :form, the content is captured as with :forms above, and then its sub-object is extracted with the at argument, which defaults to 0, extracting the first form. A number will extract the corresponding form. See the documentation for uiop:access-at. We recommend you control the syntax with such macro as uiop:with-safe-io-syntax.

Previous: Miscellaneous Functions, Up: Miscellaneous additional functionality   [Contents][Index]