
_Setup PLT_ or _setup-plt_: Collection Setup and Unpacking
==========================================================

The Setup PLT executable (bin/setup-plt for Unix) performs two
services:

 * Compiling and setting up all collections: When Setup PLT is run
   without any arguments, it finds all of the current collections (see
   the MzScheme manual for information on collections) and compiles
   module libraries in each collection with an "info.ss" library. The
   "info.ss" can indicate specifically how the collection's modules
   are compiled (see below). In this mode, Setup PLT also compiles any
   module that is referenced by a compiled module.

   The --clean (or -c) flag to Setup PLT causes it to delete existing
   .zo and extension files, thus ensuring a clean build from the
   source files. The exact set of deleted files can be controlled by
   "info.ss" libraries; see below for more info.

   The -l flag takes one or more collection names and restricts Setup
   PLT's action to those collections.

   The --mode <mode> flag causes Setup PLT to use a .zo compiler other
   than the default, and to put the resulting .zo files in a
   subdirectory (of the usual place) names <mode>. The compiler is
   obtained by using <mode> as a collection name, finding a
   _zo-compile.ss_ module in that collection, and extracting its
   `zo-compile' export. The `zo-compile' export should be a function
   like MzScheme's `compile'.

   In addition to compilation, a collection's "info.ss" library can
   specify executables to be installed in the "plt" directory
   ("plt/bin" under Unix) or other installation actions.

 * Unpacking _.plt_ files: A .plt file is a platform-independent
   distribution archive for MzScheme- and MrEd-based software.  When
   one or more file names are provided as the command line arguments
   to Setup PLT, the files contained in the .plt archive are unpacked
   (according to specifications embedded in the .plt file) and only
   collections specified by the plt file are compiled and setup.

 Compiling and Setting Up Collections
 ------------------------------------

Setup PLT attempts to compile and set up any collection that:

 * has an _info.ss_ library (see the mzc manual for a description of
   info.ss);
 
 * has the 'name' field in "info.ss";

 * is either a top-level collection or a sub-collection of a compilable
   collection.

Collections meeting this criteria are compiled using the
`compile-collection-zos' procedure described in the "compiler"
collection (which means that even if a collection has no "info.ss"
file, its modules will get compiled if they are used by other compiled
modules). If the -e or --extension flag is specified, then the
collections are also compiled using the `compile-collection-extension'
procedure from "compiler" (which does not compile a module merely
because it is used by another).

Additional "info.ss" fields trigger additional setup actions:

>  mzscheme-launcher-names - a list of executable names to be
   installed in "plt" (or "plt/bin") to run MzScheme programs
   implemented by the collection. A parallel list of library names
   must be provided by `mzscheme-launcher-libraries' or
   `mzscheme-launcher-flags' (see below). For each name, a launching
   executable is set up using the launcher collection's
   `make-mzscheme-launcher'. The arguments are "-mve-" and

      (format "~s" `(require (lib <file> <colls> ...)))

   where lib is the file named by `mzscheme-launcher-libraries'
   and <colls> ... are the collections (and subcollections)
   of the info.ss file. In addition,

    (build-aux-from-path
     (build-path (collection-path <colls> ...) <suffixless-file>))

   is provided for the optional "aux" argument (for icons, etc.),
   where <suffixless-file> is <file> without its suffix (see
   launcher/doc.txt).

   If `mzscheme-launcher-flags' is provided, it is used as a list of
   command-line argument lists to pass to mzscheme instead of the
   above default, allowing arbitrary command-line arguments.  If
   `mzscheme-launcher-flags' is specified together with
   `mzscheme-launcher-libraries', then the flags will override the
   libraries, but the libraries can still be used to specify a name
   for `build-aux-from-path' (to find related information like icon
   files etc).

   If compile-subcollections mentions a subcollection with
   this field, the executable is also set up for that subcollection.

   If the executable already exists, no action is taken.

>  mzscheme-launcher-libraries - a list of library names in
   parallel to `mzscheme-launcher-names' (see above).

>  mzscheme-launcher-flags - a list of command-line flag lists, in
   parallel to `mzscheme-launcher-names' (see above).

>  mred-launcher-names - a list of executable names to be installed in
   plt (or plt/bin) to run MrEd programs implemented by the
   collection.  This is treated in parallel to
   `mred-launcher-libraries' and `mred-launcher-flags' similarly to
   `mzscheme-launcher-names' above.

>  mred-launcher-libraries - a list of library names in
   parallel to `mred-launcher-names' (see above).

>  mred-launcher-flags - a list of command-line flag lists, in
   parallel to `mred-launcher-names' (see above).

>  install-collection - a string or a path for a library module
   relative to the collection. The module must provide `installer' as
   a procedure that accepts either one or two arguments. The first
   argument is a directory path to the PLT installation directory; the
   second argument, if accepted, is a path to the collection's own
   directory. The procedure should perform collection-specific
   installation work, and it should avoid unnecessary work in the case
   that it is called multiple times for the same installation.

>  pre-install-collection - like `install-collection', except that the
   corresponding installer is called *before* the normal .zo build,
   instead of after.  The provided procedure should be named
   `pre-installer' in this case so it can be provided by the same file
   that provides an installer.

>  post-install-collection - like `install-collection'.  It is called
   right after the `install-collection' procedure is executed.  The
   only difference between these is that the `--no-install' flag can
   be used to disable the previous two installers, but not this one.
   It is therefore expected to perform operations that are always
   needed, even after an installation that contains pre-compiled
   files.  The provided procedure should be named `post-installer' in
   this case so it can be provided by the same file that provides the
   previous two.

>  clean - a list of pathnames to be deleted when the --clean or -c
   flag is passed to Setup PLT. The pathnames must be relative to the
   collection.  If any path names a directory, each of the files
   in the directory are deleted, but none of the subdirectories of the
   directory are checked. If the path names a file, the file is
   deleted. The default, if this flag is not specified, is to delete
   all files in the "compiled" subdirectory, and all of the files in
   the platform-specific subdirectory of the compiled directory for
   the current platform.

   Just as compiling .zo files will compile each module used by a
   compiled module, deleting a module's compiled image will delete the
   .zo of each module that is used by the module. More specifically,
   used modules are determined when deleting a ".dep" file, which
   would have been created to accompany a .zo file when the .zo was
   built by Setup PLT. If the .dep file indicates another module, that
   module's .zo is deleted only if it also has an accompanying .dep
   file. In that case, the .dep file is deleted, and additional used
   modules are deleted based on the used module's .dep file, etc.
   Supplying a specific list of collections to Setup PLT disables this
   dependency-based deletion of compiled files.

 Running Setup PLT from Scheme on a Single .plt file
 ---------------------------------------------------

The _plt-single-installer.ss_ module provides a function for
installing a single .plt file:

> (run-single-installer file get-dir-proc)
     file : path string
     get-dir-proc: (-> (union string #f))

   Creates a separate thread and namespace, runs the installer in that
   thread with the new namespace, and returns when the thread
   completes or dies. It also creates a custodian to manage the
   created thread, sets the exit handler for the thread to shut down
   the custodian, and explicitly shuts down the custodian when the
   created thread terminates or dies.

   The `get-dir-proc' procedure is called if the installer needs a
   target directory for installation, and a #f result means that the
   user canceled the installation. Typically, `get-dir-proc' is
   `current-directory'.

 Setup PLT as a Unit
 -------------------

The _setup-unit.ss_ library in the setup collection exports a _setup@_
signed unit that imports

  setup-option^ - described below
  compiler^ - from "sig.ss" in the "compiler" collection
  compiler:option^  - from "sig.ss" in the "compiler" collection
  launcher-maker^ - from "launcher-sig.ss" in the "launcher" collection

Invoking this unit starts the setup process. The _option-sig.ss_
library in "setup" defines the
>      setup-option^
signature, which is implemented by the _setup:option@_ unit in
_option-unit.ss_. It imports nothing and exports the following
parameters that control the setup process:

> verbose - #t => prints message from `make' to stderr [default: #f]
> make-verbose - #t => verbose `make' [default: #f]
> compiler-verbose - #t => verbose `compiler' [default: #f]
> clean - #t => delete .zo and .so/.dll files in the specified
         collections [default: #f]
> compile-mode - path => use a .zo compiler other than plain `compile',
                 and build to (build-path "compiled" (compile-mode))
                 [default: #f]
> make-zo - #t => compile .zo files [default #t]
> make-so - #t => compile .so/.dll files [default: #f]
> make-launchers - #t => make collection "info.ss"-specified launchers
                   [default: #t]
> make-info-domain - #t => update info-domain/compiled/cache.ss for each
                   collection path [default: #t]
> call-install - #t => call collection "info.ss"-specified setup code
                 [default: #t]
> force-unpack - #t => ignore version and already-installed errors
                 when unpacking a .plt archive [default: #f]
> pause-on-errors - #t => in the event of an error, prints a summary error
                 and waits for stdin input before terminating
                 [default: #f]
> specific-collections - a list of collections to set up; the empty
           list means set-up all collections if  the archives
           list is also empty [default: null]
> archives - a list of .plt archives to unpack; any collections specified
            by the archives are set-up in addition to the collections
            listed in specific-collections  [default: null]
> current-target-directory-getter - a thunk that returns the target
            directory for unpacking a relative .plt archive; when
            unpacking an archive, either this or the procedure
            in `current-target-plt-directory-getter' will be called
            [default: current-directory]
> current-target-plt-directory-getter - a procedure that takes a
            preferred path, the PLTHOME path, and a list of path choices;
            it returns a path for a "plt-relative" install; when
            unpacking an archive, either this or the procedure
            in `current-target-directory-getter' will be called
            [default: (lambda (preferred plthome choices) preferred)]

Thus, to unpack a single .plt archive "x.plt", set the `archives'
parameter to (list "x.plt") and leave `specific-collections' as null.

Beware that the current namespace might interfere with setup
actions. For example, if setup is supposed to compile a module `(lib
"foo.ss")' that imports `(lib "bar.ss")', but `(lib "bar.ss")' is
already loaded in the current namespace, then compilation will use the
loaded module rather than re-loading it. If `(lib "bar.ss")' has
changed, re-using the loaded module is unlikely to be the desired
behavior. Avoid this problem by invoking the setup process in a fresh
namespace.

Link the options and setup units so that your option-setting code is
initialized between them, e.g.:

    (compound-unit/sig
      ...
      (link ...
            [OPTIONS : setup-option^ (setup:option@)]
            [MY-CODE : () (my-init-options@ OPTIONS)]
            [SETUP : () (setup@ OPTIONS ...)])
      ...)


_Getting info.ss fields_
========================

The _getinfo.ss_ module defines the following functions:

> (get-info collection-names) -> (union #f (symbol (-> TST) -> TST))

   Accepts a list of strings naming a collection or sub-collection,
   and calls `get-info/full' with the full path corresponding to the
   named collection.

> (get-info/full path) -> (union #f (symbol (-> TST) -> TST))

   Accepts a path to a directory. It returns #f if there is no
   "info.ss" file in the directory. If the "info.ss" file has the
   wrong shape (i.e., not a module using (lib "infotab.ss" "setup")),
   or if the "info.ss" file fails to load, then an exception is
   raised.

   Otherwise, `get-info' returns an info procedure of one or two
   arguments. The first argument to the info procedure is always a
   symbolic name, and the result is the value of the name in the
   "info.ss" file, if the name is defined. The optional second
   argument to the info procedure is a thunk that is called when the
   name is not defined, and the result of the info procedure is the
   result of the thunk in that case. If the name is not defined and no
   thunk is provided, then an exception is raised.

> (find-relevant-directories list-of-sym [mode]) -> list-of-path

   Returns a list paths identifying installed directories (i.e., collections
   and installed PLaneT packages) whose "info.ss" file defines one or more
   of the given symbols. The result is based on a cache that is computed by 
   Setup PLT and stored in the "info-domain" sub-directory of each collection
   directory (as determined by the PLT_COLLECTION_PATHS environment variable, 
   etc.) and the file "cache.ss" in the user addon dir.

   The result is in a canonical order (sorted lexicographically by directory
   name), and the paths it returns are suitable for providing to
   get-info/full.

   If mode is specified, it must be either 'preferred (the default) or
   'all-available. If mode is 'all-available, find-relevant-collections
   will return all installed directories whose info files contain the
   specified symbols -- for instance, all installed PLaneT packages will
   be searched if 'all-available is specified. If mode is 'preferred,
   then only a subset of "preferred" packages will be searched, and in
   particular only the directory containing the most recent version of
   any PLaneT package will be returned.

   No matter what mode is specified, if more than one collection has the
   same name, find-relevant-directories will only search the one that 
   occurs first in the PLT_COLLECTION_PATHS environment variable.

_.plt_ Archive Internals
==========================================================

NOTE: mzc can be used to create .plt files; see the mzc manual for
details. The internals of .plt archive files should be of little
interest to most users.

 Unpacking .plt Distribution Archives
 ------------------------------------

The extension ".plt" is not required for a distribution archive; this
convention merely helps users identify the purpose of a distribution
file.

The raw format of a distribution file is described below.  This format
is uncompressed and sensitive to communication modes (text
vs. binary), so the distribution format is derived from the raw format
by first compressing the file using gzip, then encoding the gzipped
file with the MIME base64 standard (which relies only the characters
A-Z, a-z, 0-9, +, /, and =; all other characters are ignored when a
base64-encoded file is decoded).

The raw format is

 * "PLT" are the first three characters.

 * A procedure that takes a symbol and a failure thunk and returns
   information about archive for recognized symbols and calls the
   failure thunk for unrecognized symbols. The information symbols
   are:

     + 'name - a human-readable string describing the archive's
       contents. This name is used only for printing messages to the
       user during unpacking.

     + 'unpacker - a symbol indicating the expected unpacking
       environment. Currently, the only allowed value is 'mzscheme.

     + 'requires - collections required to be installed before
       unpacking the archive, which associated versions; see the
       documentation of `pack' for details.

     + 'conflicts - collections required *not* to be installed before
       unpacking the archive

     + 'plt-relative? - a boolean; if true, then the archive's content
       should be unpacked relative to the plt add-ons directory.

     + 'plt-home-relative? - a boolean; if true and if `plt-relative?'
       is true, then the archive's content should be unpacked relative
       to the plt installation directory.

   The procedure is extracted from the archive using MzScheme's `read'
   and `eval' procedures (in a fresh namespace).

 * An unsigned unit that drives the unpacking process. The unit accepts two
   imports: a path string for the plt directory and an `unmztar'
   procedure. The remainder of the unpacking process consists of invoking
   this unit. It is expected that the unit will call `unmztar' procedure to
   unpack directories and files that are defined in the input archive after
   this unit. The result of invoking the unit must be a list of collection
   paths (where each collection path is a list of strings); once the
   archive is unpacked, Setup PLT will compile and setup the specified
   collections.

   The `unmztar' procedure takes one argument: a filter
   procedure. The filter procedure is called for each directory and
   file to be unpacked. It is called with three arguments:

      + 'dir, 'file, 'file-replace - indicates whether the item to be
        unpacked is a directory, a file, or a file to be replaced;

      + a relative path string - the pathname of the directory or file
        to be unpacked, relative to the plt directory; and

      + a path string for the plt directory.

   If the filter procedure returns #f for a directory or file, the
   directory or file is not unpacked. If the filter procedure returns
   #t and the directory or file for 'dir or 'file already exists, it
   is not created. (The file for 'file-replace need not exist
   already.)

   When a directory is unpacked, intermediate directories are created
   as necessary to create the specified directory. When a file is
   unpacked, the directory must already exist.

   The unit is extracted from the archive using MzScheme's `read'
   and `eval' procedures.

Assuming that the unpacking unit calls the `unmztar' procedure, the
archive should continue with unpackables. Unpackables are extracted
until the end-of-file is found (as indicated by an `=' in the
base64-encoded input archive).

An unpackable is one of the following:

 * The symbol 'dir followed by a list. The `build-path' procedure
   will be applied to the list to obtain a relative path for the
   directory (and the relative path is combined with the plt directory
   path to get a complete path).

   The 'dir symbol and list are extracted from the archive using
   MzScheme's `read' (and the result is *not* `eval'uated).

 * The symbol 'file, a list, a number, an asterisk, and the file
   data. The list specifies the file's relative path, just as for
   directories. The number indicates the size of the file to be
   unpacked in bytes. The asterisk indicates the start of the file
   data; the next n bytes are written to the file, where n is the
   specified size of the file.

   The symbol, list, and number are all extracted from the archive
   using MzScheme's `read' (and the result is *not* `eval'uated).
   After the number is read, input characters are discarded until
   an asterisk is found. The file data must follow this asterisk
   immediately.

 * The symbol 'file-replace is treated like 'file, but if the file
   exists on disk already, the file in the archive replaces the file
   on disk.

 Making .plt archives
 --------------------

mzc supports the creation of simple .plt files (see the mzc manual for
details) but the setup collection's _pack.ss_ library provides more
general functions to help make .plt archives:

> (pack-collections dest name collections replace? extra-setup-collections [filter] [at-plt-home?])

  Creates the .plt file specified by the pathname `dest', using the
  string `name' as the name reported to Setup PLT as the archive's
  description.

  The archive contains the collections listed in `collections', which
  should be a list of collection paths; each collection path is, in
  turn, a list of relative-path strings.

  If `replace?' is #f, then attempting to unpack the archive will
  report an error when any of the collections exist already, otherwise
  unpacking the archive will overwrite an existing collection.

  The `extra-setup-collections' argument is a list of collection paths
  that are not included in the archive, but are set-up when the
  archive is unpacked.

  The optional `filter' argument is the same as for `pack' (see
  below).

  The optional `at-plt-home?' argument is the same as for `pack'
  where `plt-relative?' is true.

> (pack dest name paths collections [filter encode? file-mode unpack-unit plt-relative? requires conflicts at-plt-home?])

  Creates the .plt file specified by the pathname `dest', using the
  string `name' as the name reported to Setup PLT as the archive's
  description, and `collections' as the list of collection paths (to
  be compiled) returned by the unpacking unit. The `paths' argument
  must be a list of relative paths for directories and files; the
  contents of these files and directories will be packed into the
  archive.

  The `filter' procedure is called with the relative path of each
  candidate for packing. If it returns #f for some path, then that
  file or directory is omitted from the archive. If it returns 'file
  or 'file-replace for a file, the file is packed with that mode,
  rather than the default mode. The default `filter' is `std-filter'
  (defined below).
  
  If `encode?' is #f, then the output archive is in raw form, and
  still must be gzipped and mime-encoded (in that order). The default
  value is #t.

  The `file-mode' argument must be 'file or 'file-replace, indicating
  the default mode for a file in the archive. The default value is
  'file.

  The `unpack-unit' argument is usually #f. Otherwise, it must be an
  unsigned unit that performs the work of unpacking; see the above
  section on .plt internals for more information about the unit. If
  `unpack-unit' is #f, an appropriate unpacking unit is generated.

  If `plt-relative?', the archive's files and directories are to be
  unpacked relative to the plt add-ons directory (unless
  `plt-at-home?' is #t; see below).

  The `requires' argument should have the shape
      (list (list <coll-path> <version>) ...)
  where each <coll-path> is a non-empty list of relative-path strings,
  and each <version> is a (possibly empty) list of exact integers. The
  indicated collections must be installed at unpacking time, with
  version sequences that match as much of the version sequence
  specified in the corresponding <version>. A collection's version is
  indicated by the `version' field of it's info.ss file.

  The `conflicts' argument should have the shape
       (list <coll-path> ...)
  where each <coll-path> is a non-empty list of relative-path
  strings. The indicated collections must *not* be installed at
  unpacking time.

  If `at-plt-home?' and `plt-relative?', the archive is to be unpacked
  relative to the plt installation directory. The default is #f.

> (std-filter p) - returns #t unless `p', after stripping its
  directory path and converting to a byte string, matches one of the
  following regular expressions: "^CVS$", "^[.]svn$", "^[.]cvsignore",
  "^compiled$", "~$", "^#.*#$", "^[.]#", or "[.]plt$".

> (mztar path output filter file-mode) - called by `pack' to write one
   directory/file `path' to the output port `output' using the filter
   procedure `filter' (see `pack' for a description of `filter').  The
   `file-mode' argument specifies the default mode for packing a file,
   either 'file or 'file-replace.

 Unpacking .plt archives
 -----------------------

 The _plt-installer.ss_ library in the setup collection defines these
 procedures:

> (run-installer filename) - run the .plt installer on the .plt file
  in `filename' and show the output in a window. This is a composition
  of `with-installer-window' and `run-single-installer' with a
  `get-dir-proc' that prompts the user for a directory (turning off
  the busy cursor while the dialog is active).

> (on-installer-run thunk) - sets the on-installer-run thunk to
  `thunk'. The on-installer-run thunk is run after a .plt file is
  installed.

> (on-installer-run) - returns the on-installer-run thunk. The
  on-installer-run thunk is run after a .plt file is installed.

> (with-installer-window do-install cleanup-thunk)
    do-install : 
      ((union (instanceof dialog%) (instanceof frame%)) -> void)
    creates a frame, sets up the current error and output ports, and
    turns on the busy cursor before calling `do-install' in a separate
    thread. 

    Returns before the installation process is complete;
    cleanup-thunk is called on a queued callback to the
    eventspace active when `with-installer-window' is
    invoked.

  (run-single-installer file get-dir-proc) - the same as the sole
   export of _plt-single-installer.ss_; see above for documentation.

      
 The _plt-installer-unit.ss_ library in the setup collection returns a unit/sig
 that imports mred^ and exports setup:plt-installer^. The signature
 setup:plt-installer^ has two names: run-installer and on-installer-run, as
 above.

 The _plt-installer-sig.ss_ library defines the setup:plt-installer^
 signature, which has two names: run-installer and on-installer-run.
