Browse files

Merge in code (and tests and docs) from temporary-files

  • Loading branch information...
segv committed Nov 21, 2012
1 parent b39491b commit 1f2fd07ffc273ad720f9ef6e48b3536b21355c6b
Showing with 492 additions and 25 deletions.
  1. +10 −2 cl-fad.asd
  2. +248 −21 doc/index.html
  3. 0 test.lisp → fad.test.lisp
  4. +10 −2 packages.lisp
  5. +175 −0 temporary-files.lisp
  6. +49 −0 temporary-files.test.lisp
@@ -36,5 +36,13 @@
#+:cormanlisp (:file "corman")
#+:openmcl (:file "openmcl")
(:file "fad")
- (:file "path"))
- :depends-on (#+sbcl :sb-posix))
+ (:file "path" :depends-on ("fad"))
+ (:file "temporary-files" :depends-on ("fad")))
+ :depends-on (#+sbcl :sb-posix :bordeaux-threads :alexandria))
+(asdf:defsystem #:cl-fad-test
+ :version "0.6.4"
+ :serial t
+ :components ((:file "fad.test")
+ (:file "temporary-files.test"))
+ :depends-on (:cl-fad :unit-test :cl-ppcre))
@@ -6,7 +6,7 @@
<title>CL-FAD - A portable pathname library for Common Lisp</title>
<style type="text/css">
pre { padding:5px; background-color:#e0e0e0 }
- h3, h4 { text-decoration: underline; }
+ h3, h4, h5 { text-decoration: underline; }
a { text-decoration: none; padding: 1px 2px 1px 2px; }
a:visited { text-decoration: none; padding: 1px 2px 1px 2px; }
a:hover { text-decoration: none; padding: 1px 1px 1px 1px; border: 1px solid #000000; }
@@ -54,36 +54,48 @@ <h2>CL-FAD - A portable pathname library for Common Lisp</h2>
<li><a href="#querying">Querying files, directories and pathnames</a>
- <li><a href="#directory-exists-p"><code>directory-exists-p</code></a>
- <li><a href="#directory-pathname-p"><code>directory-pathname-p</code></a>
- <li><a href="#file-exists-p"><code>file-exists-p</code></a>
- <li><a href="#pathname-absolute-p"><code>pathname-absolute-p</code></a>
- <li><a href="#pathname-equal"><code>pathname-equal</code></a>
- <li><a href="#pathname-relative-p"><code>pathname-relative-p</code></a>
- <li><a href="#pathname-root-p"><code>pathname-root-p</code></a>
+ <li><a href="#directory-exists-p"><code>directory-exists-p</code> [function]</a>
+ <li><a href="#directory-pathname-p"><code>directory-pathname-p</code> [function]</a>
+ <li><a href="#file-exists-p"><code>file-exists-p</code> [function]</a>
+ <li><a href="#pathname-absolute-p"><code>pathname-absolute-p</code> [function]</a>
+ <li><a href="#pathname-equal"><code>pathname-equal</code> [function]</a>
+ <li><a href="#pathname-relative-p"><code>pathname-relative-p</code> [function]</a>
+ <li><a href="#pathname-root-p"><code>pathname-root-p</code> [function]</a>
</ol> </li>
<li><a href="#manipulating">Manipulating pathnames</a>
- <li><a href="#canonical-pathname"><code>canonical-pathname</code></a>
- <li><a href="#merge-pathnames-as-directory"><code>merge-pathnames-as-directory</code></a>
- <li><a href="#merge-pathnames-as-file"><code>merge-pathnames-as-file</code></a>
- <li><a href="#pathname-as-directory"><code>pathname-as-directory</code></a>
- <li><a href="#pathname-as-file"><code>pathname-as-file</code></a>
- <li><a href="#pathname-directory-pathname"><code>pathname-directory-pathname</code></a>
- <li><a href="#pathname-parent-directory"><code>pathname-parent-directory</code></a>
+ <li><a href="#canonical-pathname"><code>canonical-pathname</code> [function]</a>
+ <li><a href="#merge-pathnames-as-directory"><code>merge-pathnames-as-directory</code> [function]</a>
+ <li><a href="#merge-pathnames-as-file"><code>merge-pathnames-as-file</code> [function]</a>
+ <li><a href="#pathname-as-directory"><code>pathname-as-directory</code> [function]</a>
+ <li><a href="#pathname-as-file"><code>pathname-as-file</code> [function]</a>
+ <li><a href="#pathname-directory-pathname"><code>pathname-directory-pathname</code> [function]</a>
+ <li><a href="#pathname-parent-directory"><code>pathname-parent-directory</code> [function]</a>
</ol> </li>
<li><a href="#traversing">Traversing directories</a>
- <li><a href="#list-directory"><code>list-directory</code></a>
- <li><a href="#walk-directory"><code>walk-directory</code></a>
+ <li><a href="#list-directory"><code>list-directory</code> [function]</a>
+ <li><a href="#walk-directory"><code>walk-directory</code> [function]</a>
</ol> </li>
+ <li><a href="#temporary-files">Temporary Files</a>
+ <ol>
+ <li><a href="#open-temporary"><code>open-temporary</code> [function]</a>
+ <li><a href="#with-output-to-temporary-file"><code>with-output-to-temporary-file</code> [macro]</a>
+ <li><a href="#with-open-temporary-file"><code>with-open-temporary-file</code> [macro]</a>
+ <li><a href="#star-default-template-star"><code>*default-template*</code> [variable]</a>
+ <li><a href="#cannot-create-temporary-file"><code>cannot-create-temporary-file</code> [condition]</a>
+ <li><a href="#invalid-temporary-pathname-template"><code>invalid-temporary-pathname-template</code> [condition]</a>
+ <li><a href="#missing-temp-environment-variable"><code>missing-temp-environment-variable</code> [condition]</a>
+ <li><a href="#lp-host-temporary-files"><code>temporary-files</code> [logical pathname host]</a>
+ </ol>
+ </li>
<li><a href="#modifying">Modifying the file system</a>
- <li><a href="#copy-file"><code>copy-file</code></a>
- <li><a href="#copy-stream"><code>copy-stream</code></a>
- <li><a href="#delete-directory-and-files"><code>delete-directory-and-files</code></a>
+ <li><a href="#copy-file"><code>copy-file</code> [function]</a>
+ <li><a href="#copy-stream"><code>copy-stream</code> [function]</a>
+ <li><a href="#delete-directory-and-files"><code>delete-directory-and-files</code> [function]</a>
</ol> </li>
- <li><a href="#package-path">The <code>path</code> package</a>
+ <li><a href="#package-path"><code>path</code> [package]</a>
<li><a href="#ack">Acknowledgements</a>
@@ -385,6 +397,221 @@ <h4><a class=none name="traversing">Traversing directories</a></h4>
+<h4><a class=none name="temporary-files">Temporary Files</a></h4>
+ <p>
+ Create a temporary file and return its name:
+<pre>CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-output-to-temporary-file">with-output-to-temporary-file</a></code> (foo)
+ (print "hello" foo))
+ </p>
+ <p>
+ Create a temporary file, read and write it, have it be deleted
+ automatically:
+<pre>CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-open-temporary-file">with-open-temporary-file</a></code> (foo :direction :io)
+ (print "hello" foo)
+ (file-position foo 0)
+ (read foo))
+ </p>
+ <h5><a class="none" name="default-temporary-directory">Default temporary file directory</a></h5>
+ By default, temporary files are created in a system specific
+ directory that defaults based on operating system conventions. On
+ Unix and Unix-like systems, the directory <tt>/tmp/</tt> is used
+ by default. It can be overridden by setting the <tt>TMPDIR</tt>
+ environment variable. On Windows, the value of the environment
+ variable <tt>TEMP</tt> is used. If it is not set, temporary file
+ creation will fail.
+ <h5><a class="none" name="defining-temporary-directory">Defining the temporary file directory</a></h5>
+ <p>
+ The Lisp application can set the default directory in which
+ temporary files are created by the way of the
+ <code xmlns=""><a href="#temporary-files">temporary-files</a></code> logical pathname host:
+<pre>(setf (<a xmlns="" href="">logical-pathname-translations</a> "<code xmlns=""><a href="#temporary-files">temporary-files</a></code>") '(("*.*.*" "/var/tmp/")))</pre>
+ This would set the directory for temporary files to
+ <tt>/var/tmp/</tt>. For more information about logical
+ pathnames, please refer to <a href="">Common
+ Lisp the Language, 2nd Edition</a> and the <a href="">Common Lisp
+ HyperSpec</a>.
+ </p>
+ <p>
+ Physical path names have restrictions regarding the permitted
+ character in file names. If these restrictions conflict with
+ your desired naming scheme, you can pass a physical pathname as
+ TEMPLATE parameter to the temporary file generation function.
+ </p>
+ <p>
+ Here are a few examples:
+<pre>CL-USER&gt; (<a xmlns="" href="">logical-pathname-translations</a> "temporary-files")
+(("*.*.*" #P"/var/folders/Yu/YuNMNBNPGoqs9G-1Wmj1dk+++TI/-Tmp-/"))
+CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-open-temporary-file">with-open-temporary-file</a></code> (foo)
+ (<a xmlns="" href="">pathname</a> foo))
+ This used the temporary directory established in the TMPDIR
+ environment variable, by the way of the definition of the
+ temporary-files logical host definition.
+<pre>CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-open-temporary-file">with-open-temporary-file</a></code> (foo :template "/tmp/")
+ (<a xmlns="" href="">pathname</a> foo))
+ Here, a physical pathname was used for the
+ <code xmlns=""><i>:template</i></code> keyword argument so that a
+ filename containing multiple dots could be generated.
+<pre>CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-open-temporary-file">with-open-temporary-file</a></code> (foo :template "temporary-files:blah-%.txt")
+ (<a xmlns="" href="">pathname</a> foo))
+ This used the temporary-files logical pathname host, but changed
+ the filename slightly.
+<pre>CL-USER&gt; *default-pathname-defaults*
+CL-USER&gt; (temporary-file:<code xmlns=""><a href="#with-open-temporary-file">with-open-temporary-file</a></code> (foo :template "blah-%.txt")
+ (<a xmlns="" href="">pathname</a> foo))
+ Here, a relative pathname was used in the template, which
+ caused the file to be generated in the directory established
+ by <a xmlns="" href="">*default-pathname-defaults*</a>.
+ </p>
+ <p>
+ Alternatively, the <code xmlns=""><a href="#*default-template*">*default-template*</a></code>
+ special variable can be set to define a custom default template
+ for generating names.
+ </p>
+ <h5 xmlns=""><a class="none" name="security">Security</a></h5>
+ The TEMPORARY-FILE library does not directly address security
+ issues. The application that uses it needs to take additional
+ measures if it is important that files created by one process
+ cannot be accessed by other, unrelated processes. This can be
+ done by using the system dependent security mechanisms like
+ default file permissions or access control lists.
+ <h5>Dictionary</h5>
+ <p xmlns="">[Function]<br><a class="none" name="open-temporary"><b>open-temporary</b> <i><clix:lambda-list xmlns:clix="">&amp;rest open-arguments &amp;key template generate-random-string max-tries &amp;allow-other-keys</clix:lambda-list></i>
+ =&gt;
+ <i>stream</i></a><blockquote><clix:description xmlns:clix="">
+ <p xmlns="">
+ Create a file with a randomly generated name and return the
+ opened stream. The resulting pathname is generated from
+ <code xmlns=""><i>template</i></code>, which is a string
+ representing a pathname template. A percent sign (%) in
+ that string is replaced by a randomly generated string to
+ make the filename unique. The default for
+ <code xmlns=""><i>template</i></code> places temporary files in the
+ <code xmlns=""><a href="#temporary-files">temporary-files</a></code> logical pathname host,
+ which is automatically set up in a system specific manner.
+ The file name generated from <code xmlns=""><i>template</i></code>
+ is merged with <a xmlns="" href="">*default-pathname-defaults*</a>,
+ so random pathnames relative to that directory can be
+ generated by not specifying a directory in
+ <code xmlns=""><i>template</i></code>.
+ </p>
+ <p xmlns="">
+ <code xmlns=""><i>generate-random-string</i></code> can be passed to
+ override the default function that generates the random name
+ component. It should return a random string consisting of
+ characters that are permitted in a pathname (logical or
+ physical, depending on <code xmlns=""><i>template</i></code>).
+ </p>
+ <p xmlns="">
+ The name of the temporary file can be accessed calling the
+ <a xmlns="" href="">pathname</a>
+ function on <code xmlns=""><i>stream</i></code>. For convenience,
+ the temporary file is opened on the physical pathname,
+ i.e. if the <code xmlns=""><i>template</i></code> designate a
+ logical pathname the translation to a physical pathname is
+ performed before opening the stream.
+ </p>
+ <p xmlns="">
+ In order to create a unique file name,
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> may loop internally up
+ to <code xmlns=""><i>max-tries</i></code> times before giving up and
+ signalling a
+ <code xmlns=""><a href="#cannot-create-temporary-file">cannot-create-temporary-file</a></code> condition.
+ </p>
+ <p xmlns="">
+ Any unrecognized keyword arguments are passed to the call to
+ <a xmlns="" href="">open</a>.
+ </p>
+ </clix:description></blockquote></p>
+ <p xmlns="">[Macro]<br><a class="none" name="with-output-to-temporary-file"><b>with-output-to-temporary-file</b> <i><clix:lambda-list xmlns:clix="">(stream &amp;rest args) &amp;body body</clix:lambda-list></i>
+ =&gt;
+ <i>pathname</i></a><blockquote><clix:description xmlns:clix="">
+ Create a temporary file using
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> with
+ <code xmlns=""><i>args</i></code> and run <code xmlns=""><i>body</i></code>
+ with <code xmlns=""><i>stream</i></code> bound to the temporary file
+ stream. Returns the pathname of the file that has been
+ created. See <code xmlns=""><a href="#open-temporary">open-temporary</a></code> for
+ permitted options.
+ </clix:description></blockquote></p>
+ <p xmlns="">[Macro]<br><a class="none" name="with-open-temporary-file"><b>with-open-temporary-file</b> <i><clix:lambda-list xmlns:clix="">(stream &amp;rest args &amp;key keep &amp;allow-other-keys) &amp;body body</clix:lambda-list></i>
+ =&gt;
+ <i>values</i></a><blockquote><clix:description xmlns:clix="">
+ Create a temporary file using
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> with
+ <code xmlns=""><i>args</i></code> and run <code xmlns=""><i>body</i></code>
+ with <code xmlns=""><i>stream</i></code> bound to the temporary file
+ stream. Returns the values returned by
+ <code xmlns=""><i>body</i></code>. By default, the file is deleted
+ when <code xmlns=""><i>body</i></code> is exited. If a true value is
+ passed in <code xmlns=""><i>keep</i></code>, the file is not deleted
+ when the body is exited. See
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> for more permitted
+ options.
+ </clix:description></blockquote></p>
+ <p xmlns="">
+ [Special variable]<br><a class="none" name="*default-template*"><b>*default-template*</b></a><blockquote><clix:description xmlns:clix="">
+ This variable can be set to a string representing the desired
+ default template for temporary file name generation. See
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> for a description of the
+ template string format.
+ </clix:description></blockquote></p>
+ <p xmlns="">
+ [Condition type]<br><a class="none" name="cannot-create-temporary-file"><b>cannot-create-temporary-file</b></a><blockquote><clix:description xmlns:clix="">
+ Signalled when an attempt to create unique temporary file name
+ failed after the established number of retries.
+ </clix:description></blockquote></p>
+ <p xmlns="">
+ [Condition type]<br><a class="none" name="invalid-temporary-pathname-template"><b>invalid-temporary-pathname-template</b></a><blockquote><clix:description xmlns:clix="">
+ Signalled when the <code xmlns=""><i>template</i></code> argument to
+ <code xmlns=""><a href="#open-temporary">open-temporary</a></code> does not contain a valid
+ template string. The template string must contain a percent
+ sign, which is replaced by the generated random string to
+ yield the filename.
+ </clix:description></blockquote></p>
+ <p xmlns="">
+ [Condition type]<br><a class="none" name="missing-temp-environment-variable"><b>missing-temp-environment-variable</b></a><blockquote><clix:description xmlns:clix="">
+ (Windows only) Signalled when the TEMP environment variable is
+ not set.
+ </clix:description></blockquote></p>
+ <p xmlns="">
+ [Logical Pathname Host]<br><a class="none" name="lp-host-temporary-files"><b>temporary-files</b></a><blockquote><clix:description xmlns:clix="">
+ This logical pathname host defines where temporary files are
+ stored by default. It is initialized in a suitable system
+ specific fashion: On Unix and Unix-like systems, the directory
+ specified in the TMPDIR environment variable is used. If that
+ variable is not set, /tmp is used as the default. On Windows,
+ the directory specified in the TEMP environment variable is
+ used. If it is not set, a
+ <code xmlns=""><a href="#missing-temp-environment-variable">missing-temp-environment-variable</a></code> error
+ is signalled.
+ </clix:description></blockquote></p>
<h4><a class=none name="modifying">Modifying the file system</a></h4>
File renamed without changes.
@@ -57,7 +57,15 @@
- :walk-directory))
+ :walk-directory
+ :open-temporary
+ :with-output-to-temporary-file
+ :with-open-temporary-file
+ :*default-template*
+ :invalid-temporary-pathname-template
+ :cannot-create-temporary-file
+ #+win32 #:missing-temp-environment-variable))
(defpackage :path
@@ -79,5 +87,5 @@ system intensive code easier to read (for unix people at least).")
(defpackage :cl-fad-test
- (:use :cl :cl-fad)
+ (:use :cl :cl-fad :unit-test)
(:export :test))
Oops, something went wrong.

0 comments on commit 1f2fd07

Please sign in to comment.