<!--  vim: set sw=2 sts=2 et ft=docbk:

  Part of the A-A-P recipe executive: Version Control

  Copyright (C) 2002-2003 Stichting NLnet Labs
  Permission to copy and use this file is specified in the file COPYING.
  If this file is missing you can find it here: http://www.a-a-p.org/COPYING

-->

<para>
This is about using &Aap; with a Version Control System (VCS)
</para>

<para>
The generic form of version control commands is:
<programlisting>
        :command file ...
</programlisting>
Or:
<programlisting>
        :command {attr = val} ... file ...
</programlisting>
</para>

<para>
The commands use the "commit" attribute of a file to obtain the kind of
version control system and its location.  For example:
<programlisting>
        :attr foo.c {commit = cvs://:ext:$CVSUSER_AAP@cvs.a-a-p.sf.net:/cvsroot/a-a-p}
</programlisting>
For CVS it is also possible to only specify the method.  CVS will then use the
same specification for the repository as used when checking the files out.
<programlisting>
        :attr foo.c {commit = cvs://}
</programlisting>
</para>

<para>
These commands can be used:
<informaltable frame="none">
  <tgroup cols="2">
    <colspec colwidth="100"/>
    <tbody>
    <row>
    <entry><link linkend='cmd-commit'>:commit</link></entry>
    <entry>Update each file in the repository.  Add it when needed.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-checkout'>:checkout</link></entry>
    <entry>Like fetch and additionally lock for editing when possible.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-checkin'>:checkin</link></entry>
    <entry>Like commit, but unlock file.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-unlock'>:unlock</link></entry>
    <entry>Remove lock on file, don't change file in repository or
    locally.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-add'>:add</link></entry>
    <entry>Add file to repository.  File must exist locally.  Implies a
    "commit" of the file.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-remove'>:remove</link></entry>
    <entry>Remove file from repository.  File may exist locally.  Implies a
    "commit" of the file.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-tag'>:tag</link></entry>
    <entry>Add a tag to the current version.  Uses the "tag"
    attribute.</entry>
    </row>
    </tbody>
  </tgroup>
</informaltable>
</para>

<para>
Additionally, there is the generic command:
</para>
<programlisting>
        <link linkend='cmd-verscont'>:verscont</link> action {attr = val} ... file ...
</programlisting>
<para>
This calls the Version control module as specified in the "commit" attribute
for "action" with the supplied arguments.  What happens is specific for the
VCS.
</para>


<bridgehead>Operating On All Files</bridgehead>

<para>
These commands work on all the files mentioned in the recipe and child
recipes that have the "commit" attribute:
</para>

<para>
<informaltable frame="none">
  <tgroup cols="2">
    <colspec colwidth="120"/>
    <tbody>
    <row>
    <entry><link linkend='cmd-checkoutall'>:checkoutall</link></entry>
    <entry>Checkout the files and locks them.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-commitall'>:commitall</link></entry>
    <entry> Commit the files .  Files missing in the VCS will be added.  No
    files will be removed.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-checkinall'>:checkinall</link></entry>
    <entry>Just like :commitall and also remove any locks.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-unlockall'>:unlockall</link></entry>
    <entry>Unlock the files.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-addall'>:addall</link></entry>
    <entry>Inspect directories and add items that do not exist in the VCS
                but are mentioned in the recipe(s) with a "commit" attribute.
                Uses the current directory or specified directories.
                May enter directories recursively.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-removeall'>:removeall</link></entry>
    <entry>Inspect directories and remove items that do exist in the VCS
                but are not mentioned or do not have a "commit" attribute.
                Careful: Only use this command when it is certain that all
                files that should be in the VCS are explicitly mentioned and
                do have a "commit" attribute!</entry>
    </row>
    <row>
    <entry><link linkend='cmd-reviseall'>:reviseall</link></entry>
    <entry>Just like using both <literal>:checkinall</literal> and
                <literal>:removeall</literal>.</entry>
    </row>
    <row>
    <entry><link linkend='cmd-tagall'>:tagall</link></entry>
    <entry>Add a tag to all items with a "commit" and "tag"
                attribute.</entry>
    </row>
    </tbody>
  </tgroup>
</informaltable>
</para>

<para>
Related to these commands are targets that are handled automatically when not
defined explicitly.  When defining a target for these, it would be highly
unexpected if it works differently.
</para>

<para>
<informaltable frame="none">
  <tgroup cols="2">
    <colspec colwidth="120"/>
    <tbody>
    <row>
    <entry><userinput>aap commit</userinput></entry>
    <entry> Normally uses the files you currently have to update the
                version control system.  This can be used after you are done
                making a change.  Default is using
                <link linkend="cmd-commitall">:commitall</link>.</entry>
    </row>
    <row>
    <entry><userinput>aap checkout</userinput></entry>
    <entry> Update all files from the VCS that have a "commit" attribute.
                When the VCS supports locking all files will be locked.
                Without locking this does the same as "aap fetch".</entry>
    </row>
    <row>
    <entry><userinput>aap checkin</userinput></entry>
    <entry> Do
      <link linkend="cmd-checkin">:checkin</link> for all files that have been checked out of the
                VCS.  For a VCS that doesn't do file locking this is the same
                as "aap commit".</entry>
    </row>
    <row>
    <entry><userinput>aap unlock</userinput></entry>
    <entry> Unlock all files that are locked in the VCS.  Doesn't change
                any files in the VCS or locally.</entry>
    </row>
    <row>
    <entry><userinput>aap add</userinput></entry>
    <entry> Do
      <link linkend="cmd-add">:add</link> for all files that appear in the recipe with a
                "commit" attribute that do not appear in the VCS.</entry>
    </row>
    <row>
    <entry><userinput>aap remove</userinput></entry>
    <entry> Do 
      <link linkend="cmd-removeall">:removeall</link>: remove all files that
      appear in the VCS but
                do not exist in the recipe with a "commit" attribute or do not
                exist in the local directory.  This works in the current
                directory and recursively enters all subdirectories.
                Careful: files with a search path may be accidentally
                removed!</entry>
    </row>
    <row>
    <entry><userinput>aap tag</userinput></entry>
    <entry> Do
      <link linkend="cmd-tagall">:tagall</link>: tag all files with a "commit"
      and "tag"
                attribute.  The tag name should be defined properly in the
                recipe, although "aap tag TAG=name" can be used if the recipe
                contains something like:
                        <literal>:attr {tag = $TAG} $FILES</literal></entry>
    </row>
    <row>
    <entry><userinput>aap revise</userinput></entry>
    <entry> Same as "aap checkin" followed by "aap remove": checkin all
                changed files, unlock all files and remove files that don't
                have the "commit" attribute.</entry>
    </row>
    </tbody>
  </tgroup>
</informaltable>
</para>

<para>
For the above the "-l" or "--local" command line option can be used to
restrict the operation to the directory of the recipe and not recurse into
subdirectories.
</para>

<para>
A variable can be used to set the default change log entries:
<programlisting>
    LOGENTRY=message
</programlisting>
This variable is used for new, changed and deleted files that don't have a
{logentry} attribute.
</para>

<para>
When it's desired to commit one directory at a time the following construct
can be used:
</para>
<programlisting>
        source_files = *.c
        include_files = include/*.h
        commit-src {virtual}:
            :commit $source_files
            :removeall .
        commit-include {virtual}:
            :commit $include_files
            :removeall include
</programlisting>
<para>
Note that this is not possible when the sources and include files are in one
directory,
<link linkend="cmd-removeall">:removeall</link> only works per directory.
</para>

<bridgehead>Using Subversion</bridgehead>

<para>
Subversion is a new version control system that is going to replace CVS.
It has many advantages, such as atomic commits.  But version 1.0 is not ready
yet (although the current versions appear to be very stable and usable).
</para>

<para>
Subversion support is not implemented yet.  For the time being you can
retrieve files from a Subversion repository by using a URL.  That works,
because subversion is using an Apache server.  You can obtain a copy of single
files by specifying the URL in the fetch attribute.  Obviously you can't
commit changed files this way.
</para>


<bridgehead>Using Another Version Control System</bridgehead>

<para>
To add support for a new version control system, define a Python function with
the name "method_command", where "method" is the word at the start of the
commit attribute.
The function will be called with five arguments:
<informaltable frame="none">
  <tgroup cols="2">
    <colspec colwidth="100"/>
    <tbody>
      <row>
        <entry>recdict</entry>
        <entry>a dictionary with references to all variable scopes (for expert
        users only)</entry>
      </row>
      <row>
        <entry>name</entry>
        <entry>the name of the repository defined with the "commit" attribute
          with the "scheme://" part removed.</entry>
      </row>
      <row>
        <entry>commit_dict</entry>
        <entry>the dictionary holding attributes for the specified repository;
          e.g., for "{commit = foo:// {arg = blah}}" it is (in Python syntax):
          { "name" : "foo://", "arg" : "blah" }</entry>
      </row>
      <row>
        <entry>nodelist</entry>
        <entry>a list of the nodes on which the action is to be
          performed</entry>
      </row>
      <row>
        <entry>action</entry>
        <entry>the name of the action to be executed; can be "fetch",
          "commit", etc.</entry>
      </row>
    </tbody>
   </tgroup>
</informaltable>

The function should a list of nodes that failed.  When the action worked
without errors an empty list should be returned.
</para>
<para>
  For an example look at cvs_command() in the VersContCvs.py file of the &Aap;
  sources.
</para>

<para>
  A second function that is to be defined is "method_list".  
  It should return a list of the files that are currently in a specified
  directory in the repository.  Return an empty list if there are no files.
  The function will be called with these arguments:
<informaltable frame="none">
  <tgroup cols="2">
    <colspec colwidth="100"/>
    <tbody>
      <row>
        <entry>recdict</entry>
        <entry>a dictionary with references to all variable scopes (for expert
        users only)</entry>
      </row>
      <row>
        <entry>name</entry>
        <entry>the name of the repository defined with the "commit" attribute
          with the "scheme://" part removed.</entry>
      </row>
      <row>
        <entry>commit_dict</entry>
        <entry>the dictionary holding attributes for the specified repository;
          e.g., for "{commit = foo:// {arg = blah}}" it is (in Python syntax):
          { "name" : "foo://", "arg" : "blah" }</entry>
      </row>
      <row>
        <entry>dirname</entry>
        <entry>name of the directory to be listed</entry>
      </row>
      <row>
        <entry>recursive</entry>
        <entry>boolean indicating whether recursive listing is to be
          done</entry>
      </row>
    </tbody>
   </tgroup>
</informaltable>
</para>

<para>
  For an example look at cvs_list() in the VersContCvs.py file of the &Aap;
  sources.
</para>
