.c	Monday  Jan 24,1983  17:45  FQ+3D.13H.34M.26S.  -*- Bolio -*-

.chapter "The Patch Facility"

.cindex patch facility
The patch facility provides a means by which a program (whatever that
might mean) may be incrementally updated;  it essentially a
bookkeeping operation, and is primarily designed for providing the
updates necessary for a dumped-out system.  In the context of the
patch facility, such a program unit is called a term_i{patchable
system};  use of the term term{system} in this context means the
same thing, but may not in other contexts.  (lan{Nil} has no more
sophisticated system-building tools currently, although it certainly
has whatever primitives might be needed.)

The design of the lan{nil} patch facility is originally derived from
the lan{lisp machine lisp} patch facility ref{LMman}.  That was
first implemented from scratch in lan{maclisp}, and some time later
the lan{maclisp} version was copied and modified to be more
appropriate for lan{nil}.  This is noted because there are various
design flaws and misfeatures of the facility, which are inherited and
are due in part to the application of the techniques used to a
different programming environment.  A future release should have a
redesigned facility which will correct these things.

Patchable systems have both 2major* and 2minor* version
numbers.  The major version number corresponds to a complete new
system generation, like when a lan{nil} maintainer (one of the
authors) loads up a new lan{nil}, having incorporated any fixes into
the source files and recompiled any files which needed it.  The minor
version number is incremented whenever an update is made.  The updates
are maintained on disk;  each one corresponds to a particular file
(a term_i{patch file}) which implements the fix (usually, some function
and variable definitions the same as in a newer version of some source
file).  A term_i{patch directory} is maintained for each major
version number;  it enumerates (and describes) the patches for each
minor version number.  Finally, each patchable system has a
term_i{patch system definition file}, which primarily provides all
kinds of default attributes about the system, which include the
current version number and the location of the 2other* files in
the filesystem (thus the only place a pathname need ordinarily be
specified to the patch facility is when pointing at the patch system
definition file to define the patch system originally).

A typical cycle of usage for the authors might thus look like this.
We have a freshly-made lan{nil}, say version 175 (the Release 0
version).  As bugs are found, they are accumulated into patch files.
One person might accumulate several fixes over the course of a day
into a single patch file.  This might then be the update which makes
Lisp 175.0 become Lisp 175.1.  Exportation of the patch directory and
the patch files for Lisp 175 to other sites will then allow them to be
loaded by other dumped-out NILs of Lisp version 175.  Eventually, one
of us will decide that the changes are too far-reaching or too
numerous, and decide to go on to another system version.  This
normally involves ensuring that all updated sources are recompiled,
loading up a new lan{nil}, and telling the patch system we want a
new major version number.  Note that the last is independent,
conceptually, from loading up a new lan{nil}:  it is an operation
which says that what we have on disk is a new version.  A conceptual
bug in the distributed lan{nil} is the ease with which one may load
up a lan{nil} and increment the version number.  Unless one is
actually modifying the files which get loaded, one's site should remain
at lan{nil} version 175.  If it does not, then a bug report
referring to the lan{nil} version is meaningless to us.

At the end of section (defining-patch-systems-css-number),
(lsb-patch-system-example), is a description of a more common usage
of the patch system, where it is used for a system which is 2not*
dumped out.

.section "User Functions"

.defun load-patches &rest poorly-designed-keywords
Loads patches for the specified (or all) systems.  This takes keyword
arguments in a non-standard fashion, although that is expected to be
changed incompatibly in the future.  All of them except for
3:systems* take 2no arguments*.  They are:
.table 3 250 250
.item :systems 2list-of-systems*
Load patches for the specified list of patch systems, rather than all
those currently defined.
.item :verbose
Be verbose.  (Verbosity is forced when there is interaction, of
course.)  This is the default.
.item :silent
Don't be verbose.
.item :noselective
Don't be interactive, just load the patches.  The default is to query
the user on each patch.
.item :selective
Query for loading of each patch.  This is the default.  Note that one
may answer 3P* instead of 3Y* or 3N* to the query:  this
means 3proceed*, which will cause all succeeding patches to be
loaded non-interactively.  3load-patches* is (supposed to be)
clever to force verbose typeout when it is going to ask, and inhibit
it again if 3:silent* was specified and the loading was proceeded.
.end_table
The standard lan{nil} default init file does a
.lisp
(load-patches :noselective)
.end_lisp
to load patches without querying, but verbosely (so that you see what
might be taking it a while during startup).
.end_defun

The following two functions, if given no arguments, print information
about all defined systems;  otherwise, about the systems given as
arguments.

.defun print-system-modifications &rest systems
This prints information about the systems as they exist in core.  For
each system, it lists its (current) status, and lists the minor
version numbers that have been loaded, and their descriptions.
.end_defun

.defun print-system-history &rest systems
This reads the patch directory for the named systems off of disk, and
displays the information;  all patches and their descriptions are
listed (whether or not they have been loaded), status changes (the
system status may change with a particular minor version number) are
noted, and the "in-core" status with respect to all of this is shown.

Note that although the patch directory is read from disk, the patch
system must be defined in-core in order for this to know where to look
for the patch directory.
.end_defun


.section "Patch System Information"

.defun si:system-version-info &optional briefp
Returns a string describing the versions and statuses of the patch
systems defined.  If 2briefp* is specified and not (false), then
the status information will be abbreviated, some ("insignificant")
systems will not be shown, and the name of the primary system ("Lisp")
will be omitted (it always comes first).
.end_defun

.defun si:get-system-version &optional system
Returns multiple values describing the current version of the
specified patch system:
.table 3 250 250 0 0 0
.item *
the major version number,
.item *
the minor version number,
.item *
and the system status keyword.
.end_table
By some special strange dispensation, if 2system* is not defined
as a patch system, (false) is returned as each of the values.
.end_defun

.defun si:get-system-version-list system
This is a vestigial remnant of Maclisp implementation.  Equivalent to
.lisp
(multiple-value-list (si:get-system-version 2system*))
.end_lisp
(In lan{maclisp}, the multiple-value support code does not normally
reside in core, and code which runs interpreted and needs to examine
system version information (for instance when loading up a system)
might not want to force it to be loaded.)
.end_defun


.defun si:print-herald &optional stream look-out-of-core?
This is what prints the startup message.  If 2look-out-of-core?*
is not (false), then 3si:print-herald* reads the patch
directories off of disk so that it can show what the current versions
and statuses are (what you would get if you do 3load-patches*).
With a non-null 2look-out-of-core?*, 2si:print-herald*
effectively does a 3(si:update-system-statuses (false))* (q.v.).
.end_defun

.defun si:update-system-statuses? system-list
Looks on disk and corrects (if necessary) the in-core status
information for each of the systems in 2system-list*, or all
defined patch systems if that is (false).  The reason for this is
that it is possible for the status of a system to change on disk (a
particular patch might be deemed to be broken, or the system might be
deemed to be no longer experimental, for instance).  This is done
implicitly by 3load-patches*, and by 3si:print-herald* with a
non-null second argument.
.end_defun


.section "Adding Patches"

For the following set of functions, a default
system/minor-version-number pair is maintained, from which
2system-name* and 2minor-version-number* are defaulted.  The
system name originally defaults to 3lisp*, which is the name of
the lan{nil} patchable system.  (This should be changed.)
3si:add-patch* creates a new minor version number, allocates it in
the patch directory, and sets this in-core default patch version to
that.  Then one can (for instance) do 3(si:compile-load-patch)* to
test that patch.  If the function does not know which minor version
number to deal with, then it will cycle through all of them, from the
"most likely" one first, asking.  One way to force this behavior is to
specify a system but not a minor version number to one of these
functions.

.defun si:add-patch &optional system-name description &rest options
This allocates a new minor version number for the patchable system
2system-name*, with a description of 2description* and
environment options of 2options* (see the
3:environment-options* keyword to the
3si:initialize-patch-system* function, on
(environment-options-page)).  It then calls 3si:re-edit-patch*,
below.
.end_defun

.defun si:re-edit-patch &optional system-name minor-version-number
Creates a patch file for the appropriate file (if necessary), and
calls the built-in editor on it.
.end_defun

.defun si:compile-patch &optional system-name minor-version-number
Compiles the specified patch.  This routine returns several values;
the first of which is the pathname of the compiled file, so that it
may be loaded.
.end_defun

.defun si:compile-load-patch &optional system-name minor-version-number
Compiles and loads the specified patch.
.end_defun

.defun si:finish-patch &optional system-name minor-version-number
"Completes" the specified patch;  that is, marks it as finished.  If a
patch is not "finished", then 3load-patches* will not load it (nor
any succeeding patches).
.end_defun

.defun si:abort-patch &optional system-name minor-version-number
Flushes (aborts) the specified patch.  Any patch files are not
deleted, however;  you should consider doing that manually.  If the
minor version number was the highest in use, it will be reused, in
which case a later 3si:add-patch* will use the existing text file
to start.  Otherwise, there will be a missing minor version number,
which is ok.
.end_defun

.defun si:set-patch-environment system minor-version-number &rest options
In case you forgot with 3add-patches*, this sets the option
environment to 2options*.  Note it does not update the file
attribute list in the source file of the patch!  You must do that
manually.
.end_defun

.defun si:set-system-status system status &optional major-version minor-version
Note that this takes weirder than normal arguments.  This sets the
status of the specified version of 2system* to be 2status*.
It is willing to modify the status list of major versions differing
from that defined in the current environment.  (Not to say that that
would not be equally useful for some of the other functions...)

The typical use of this is to set either the current or the
30* minor version number of the current major version of some
system to either 3:released* or 3:broken*, with the current
status being 3:experimental* (the default when a new major version
number is made).  Or, to change the status of an antiquated system
from 3:released* to 3:obsolete*.
.end_defun


.section "Defining Patch Systems"
.setq defining-patch-systems-css-number css-number

.defun si:new-patch-system system-name pathname &optional (do-what :increment-and-define)
.end_defun

.defun si:initialize-patch-system system-name pathname &key :initial-version :patch-directory :patch-file :compilation-function :editing-function :insignificant :default-directory :default-device :nodefault :environment-options
.table 3 250 250
.item :nodefault
If not (false), then 3si:initialize-patch-system* will read in
an existing version of the patch system definition file from
2pathnam* (appropriately defaulted) to provide defaults for those
options not specified.  Otherwise, hopefully appropriate default
defaults are used.
.item :initial-version
May be used to specify the version to be used.  This will be written
into the patch system definition file as the 2current* version,
which means that calling 3si:new-patch-system* with the (typicall)
3:increment-and-define* keyword will increment it first.
.item :patch-directory
A format string which should take one argument, which is the major
system version, to construct the patch directory pathname for that
major system version.
.item :patch-file 
A format string which should take two arguments, the major and minor
system versions (in that order), to construct the patch file pathname
for the patchs of those versions.  Alternately, it may be a list of
two such format strings:  the first will be used as the source file
pathname, the second for the vasl file.  (This may be used to split
the stuff across directories or even structures, for instance if the
sources are kept in a different place because of lack of disk space,
or are simply not kept somewhere on some particular machine.)
.item :compilation-function
The function called by 3compile-patch* etc.  By default,
3compile-file* ((compile-file-fun)) is used.  This should be a
symbol, not a closure or compiled-function object.  The function will
be given a first argument of the input pathname, and other keyworded
arguments of 3:output-file* and 3:set-default-pathname* (which
will be (false) so as to not modify pathname defaults).  That is,
.lisp
(lsbcl 2input-pathname* 
   :output-file 2output-pathname*
   :set-default-pathname nil)
.end_lisp
.item :editing-function
The editing function which should be used to edit a patch file.  It is
called with a single argument, the patch file pathname.  The default
function simply returns the list of "now" "edit" and the pathname,
which is then returned by 3si:add-patch* or
3si:re-edit-patch*.
.item :insignificant
If not (false), then 3si:system-version-info* will not show this
system when in brief mode.
.item :default-directory
.item1 :default-device
These are used to construct the default pathnames used for the
3:patch-directory* and 3:patch-file* options, when they are
not supplied.  They are 2not* used in defaulting (although they
probably should be).  The default-defaults for these are taken from
2pathname*, and if absent from that, the directory name defaults
to 2system-name*.  These options are significantly less useful in
lan{nil} than they were in the lan{maclisp} version of this
code...
.item :environment-options
.setq environment-options-page page
This and some of the code involved is partially but not totally
archaic; it predates lan{nil} file attribute lists, and was put in
to compensate for their absence.  The code in Release 0 still performs
redundant bindings of the involved attributes.  However, the data in
this option list is used to also initialize the textual file property
list when 3si:add-patch* initializes the patch file.  Because of
the kludginess of this, only a few options are supported, although it
is extensible if need be (see the code).  The options currently
handled are 
.table 3 250 250
.item :package
The package name (default is 3"SYSTEM-INTERNALS"*, which is
probably a poor choice)
.item :input-radix
The input radix (default is decimal).
.end_table
.end_table
.end_defun

.setq lsb-patch-system-example page
lan{lsb}, which has been distributed with lan{nil}, is a patchable
system also.  However, the normal lan{nil} environment does not have
lan{lsb} loaded by default.  There is a file which can be loaded
which will load up all of the parts of lan{lsb}.  (It is
7NIL$DISK:[LSB]LOAD.LSP*, if you have lan{lsb} online.)
Essentially, it
sets up the 3lsb* package and loads up all of the component files
of lan{lsb} and performs whatever initializations are needed, and
then does
.lisp
(si:new-patch-system 
  "LSB" "NIL$DISK:[LSB.PATCH]SYSDEF"
  :define)
(load-patches :noselective)
.end_lisp
The file 7NIL$DISK:[LSB.PATCH]SYSDEF.PSD* was created with the
2si:initialize-patch-system* function.  Once that has been
created, this reference to it in the lan{lsb} loadup file is the
only pathname reference necessary;  all others are contained in that
file.

With the lan{lsb} patchable system, the files which are loaded by
the loadup file are not normally modified except via patches.
However, at strategic points, like when many files are being changed
at once, or incompatible changes are being made, or the patches become
numerous, then all of the files are changed (for instance, recompiled)
at once, and the maintainer manually increments the version number of
the lan{lsb} patchable system by doing
.lisp
(si:new-patch-system 'lsb "nil$disk:[lsb.patch]sysdef"
		     :increment)
.end_lisp
which increments the on-disk version number.  Then, when someone loads
the loadup file, they get the new files, the new major version number,
and (until new patches get made) no patches loaded.

Maintaining the system in this way also results in a shorter
turnaround time for testing out small fixes, and getting them
"installed";  larger source files do not need to be recompiled.

