<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter SYSTEM "../../dtd/dblite.dtd">
<chapter id="tsvn-subwcrev">
	<title>The SubWCRev Program</title>
	<simplesect>
		<indexterm>
			<primary>version extraction</primary>
		</indexterm>
		<indexterm>
			<primary>SubWCRev</primary>
		</indexterm>
		<indexterm>
			<primary>COM</primary>
		</indexterm>
		<indexterm>
			<primary>version number in files</primary>
		</indexterm>
		<para>
			SubWCRev is Windows console program which can be used to read
			the status of a Git working copy and optionally perform
			keyword substitution in a template file.
			This is often used as part of the build process as a means of
			incorporating working copy information into the object you
			are building. Typically it might be used to include the
			revision number in an <quote>About</quote> box.
		</para>
	</simplesect>
	<!-- ================================================================= -->
	<!-- ======================== SECTION 1 ============================== -->
	<!-- ================================================================= -->
	<sect1 id="tsvn-subwcrev-cli">
		<title>The SubWCRev Command Line</title>
		<para>
			SubWCRev reads the Git status of all files in a working
			copy, excluding externals by default. It records the highest commit
			revision number found, and the commit timestamp of that revision,
			It also records whether there are local modifications in the working
			copy, or mixed update revisions. The revision number, update
			revision range and modification status are displayed on stdout.
		</para>
		<para>
			SubWCRev.exe is called from the command line or a script, and
			is controlled using the command line parameters.
<screen>
SubWCRev WorkingCopyPath [SrcVersionFile DstVersionFile] [-nmdfe]
</screen>
		</para>
		<para>
			<literal>WorkingCopyPath</literal> is the path to the working
			copy being checked. You can only use SubWCRev on working copies,
			not directly on the repository. The path may be absolute or
			relative to the current working directory.
		</para>
		<para>
			If you want SubWCRev to perform keyword substitution, so that
			fields like repository revision and URL are saved to a text
			file, you need to supply a template file
			<literal>SrcVersionFile</literal>
			and an output file
			<literal>DstVersionFile</literal>
			which contains the substituted version of the template.
		</para>
		<para>
			There are a number of optional switches which affect the way
			SubWCRev works. If you use more than one, they must be specified
			as a single group, eg.
			<literal>-nm</literal>, not
			<literal>-n -m</literal>.
			<table id="tsvn-subwcrev-switch-table">
				<title>List of available command line switches</title>
				<tgroup cols="2">
					<colspec colnum="1" colwidth="2*"/>
					<colspec colnum="2" colwidth="10*"/>
					<thead>
						<row>
							<entry>Switch</entry>
							<entry>Description</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry condition="pot">-n</entry>
							<entry>
								If this switch is given, SubWCRev will exit with
								<literal>ERRORLEVEL 7</literal> if the working copy
								contains local modifications. This may be used to
								prevent building with uncommitted changes present.
							</entry>
						</row>
						<row>
							<entry condition="pot">-m</entry>
							<entry>
								If this switch is given, SubWCRev will exit with
								<literal>ERRORLEVEL 8</literal> if the working copy
								contains mixed revisions. This may be used to prevent
								building with a partially updated working copy.
							</entry>
						</row>
						<row>
							<entry condition="pot">-d</entry>
							<entry>
								If this switch is given, SubWCRev will exit with
								<literal>ERRORLEVEL 9</literal> if the destination file
								already exists.
							</entry>
						</row>
						<row>
							<entry condition="pot">-f</entry>
							<entry>
								If this switch is given, SubWCRev will include
								the last-changed revision of folders. The default
								behaviour is to use only files when getting the
								revision numbers.
							</entry>
						</row>
						<row>
							<entry condition="pot">-e</entry>
							<entry>
								If this switch is given, SubWCRev will examine
								directories which are included with
								<literal>svn:externals</literal>,
								but only if they are from the same repository.
								The default behaviour is to ignore externals.
							</entry>
						</row>
						<row>
							<entry condition="pot">-x</entry>
							<entry>
								If this switch is given, SubWCRev will 
								output the revision numbers in HEX.
							</entry>
						</row>
						<row>
							<entry condition="pot">-X</entry>
							<entry>
								If this switch is given, SubWCRev will 
								output the revision numbers in HEX, with
								'0X' prepended.
							</entry>
						</row>
					</tbody>
				</tgroup>
			</table>
		</para>
	</sect1>
	<!-- ================================================================= -->
	<!-- ======================== SECTION 2 ============================== -->
	<!-- ================================================================= -->
	<sect1 id="tsvn-subwcrev-keywords">
		<title>Keyword Substitution</title>
		<para>
			If a source and destination files are supplied, SubWCRev copies
			source to destination, performing keyword substitution as follows:
			<table id="tsvn-subwcrev-switch-table2">
				<title>List of available command line switches</title>
				<tgroup cols="2">
					<colspec colnum="1" colwidth="3*"/>
					<colspec colnum="2" colwidth="7*"/>
					<thead>
						<row>
							<entry>Keyword</entry>
							<entry>Description</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry condition="pot">$WCREV$</entry>
							<entry>
								Replaced with the highest commit revision
								in the working copy.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCDATE$</entry>
							<entry>
								Replaced with the commit date/time of the
								highest commit revision. By default,
								international format is used:
								<literal>yyyy-mm-dd hh:mm:ss</literal>.
								Alternatively, you can specify a custom format which
								will be used with <literal>strftime()</literal>,
								for example:
								<literal>$WCDATE=%a %b %d %I:%M:%S %p$</literal>.
								For a list of available formatting characters, look at the
								<ulink url="http://www.cppreference.com/stddate/strftime.html">
									<citetitle>online reference</citetitle>
								</ulink>.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCNOW$</entry>
							<entry>
								Replaced with the current system date/time.
								This can be used to indicate the build time.
								Time formatting can be used as described for
								<literal>$WCDATE$</literal>.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCRANGE$</entry>
							<entry>
								Replaced with the update revision range in
								the working copy. If the working copy is in a
								consistent state, this will be a single revision.
								If the working copy contains mixed revisions,
								either due to being out of date, or due to a
								deliberate update-to-revision, then the range
								will be shown in the form 100:200
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCMIXED$</entry>
							<entry>
								<literal>$WCMIXED?TText:FText$</literal> is
								replaced with <literal>TText</literal> if there are mixed update
								revisions, or <literal>FText</literal> if not.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCMODS$</entry>
							<entry>
								<literal>$WCMODS?TText:FText$</literal> is
								replaced with <literal>TText</literal> if there are local
								modifications, or <literal>FText</literal> if not.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCURL$</entry>
							<entry>
								Replaced with the repository URL of the working
								copy path passed to SubWCRev.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCINSVN$</entry>
							<entry>
								<literal>$WCINSVN?TText:FText$</literal> is
								replaced with <literal>TText</literal> if the entry is versioned,
								or <literal>FText</literal> if not.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCNEEDSLOCK$</entry>
							<entry>
								<literal>$WCNEEDSLOCK?TText:FText$</literal> is
								replaced with <literal>TText</literal> if the entry has 
								the <literal>svn:needs-lock</literal> property set, 
								or <literal>FText</literal> if not.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCISLOCKED$</entry>
							<entry>
								<literal>$WCISLOCKED?TText:FText$</literal> is
								replaced with <literal>TText</literal> if the entry is locked,
								or <literal>FText</literal> if not.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCLOCKDATE$</entry>
							<entry>
								Replaced with the lock date.
								Time formatting can be used as described for
								<literal>$WCDATE$</literal>.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCLOCKOWNER$</entry>
							<entry>
								Replaced with the name of the lock owner.
							</entry>
						</row>
						<row>
							<entry condition="pot">$WCLOCKCOMMENT$</entry>
							<entry>
								Replaced with the comment of the lock.
							</entry>
						</row>
					</tbody>
				</tgroup>
			</table>
		</para>
	</sect1>
	<!-- ================================================================= -->
	<!-- ======================== SECTION 3 ============================== -->
	<!-- ================================================================= -->
	<sect1 id="tsvn-subwcrev-example">
		<title>Keyword Example</title>
		<para>
			The example below shows how keywords in a template file are
			substituted in the output file.
		</para>
<programlisting>
// Test file for SubWCRev: testfile.tmpl

char *Revision = "$WCREV$";
char *Modified = "$WCMODS?Modified:Not modified$";
char *Date     = "$WCDATE$";
char *Range    = "$WCRANGE$";
char *Mixed    = "$WCMIXED?Mixed revision WC:Not mixed$";
char *URL      = "$WCURL$";

#if $WCMODS?1:0$
#error Source is modified
#endif

// End of file
</programlisting>
		<para>
			After running <literal>SubWCRev.exe path\to\workingcopy testfile.tmpl testfile.txt</literal>, 
			the output file <literal>testfile.txt</literal> would looks like this:
		</para>
<programlisting>
// Test file for SubWCRev: testfile.txt

char *Revision = "3701";
char *Modified = "Modified";
char *Date     = "2005/06/15 11:15:12";
char *Range    = "3699:3701";
char *Mixed    = "Mixed revision WC";
char *URL      = "http://project.domain.org/svn/trunk/src";

#if 1
#error Source is modified
#endif

// End of file
</programlisting>
		<tip>
			<para>
				A file like this will be included in the build so you would expect it
				to be versioned. Be sure to version the template file, not the
				generated file, otherwise each time you regenerate the version file
				you need to commit the change, which in turn means the version file
				needs to be updated.
			</para>
		</tip>
	</sect1>
	<!-- ================================================================= -->
	<!-- ======================== SECTION 4 ============================== -->
	<!-- ================================================================= -->
	<sect1 id="tsvn-subwcrev-com-interface">
		<title>COM interface</title>
		<indexterm>
			<primary>COM SubWCRev interface</primary>
		</indexterm>
		<para>
			If you need to access Git revision information from other
			programs, you can use the COM interface of SubWCRev. The object to
			create is <literal>SubWCRev.object</literal>, and the following
			methods are supported:
			<table id="tsvn-subwcrev-COM-table">
				<title>COM/automation methods supported</title>
				<tgroup cols="2">
					<colspec colnum="1" colwidth="3*"/>
					<colspec colnum="2" colwidth="7*"/>
					<thead>
						<row>
							<entry>Method</entry>
							<entry>Description</entry>
						</row>
					</thead>
					<tbody>
						<row>
							<entry condition="pot">.GetWCInfo</entry>
							<entry>
								This method traverses the working copy gathering the
								revision information. Naturally you must call this before
								you can access the information using the remaining methods.
								The first parameter is the path.
								The second parameter should be true if you want to include
								folder revisions. Equivalent to the <literal>-f</literal>
								command line switch.
								The third parameter should be true if you want to include
								svn:externals. Equivalent to the <literal>-e</literal>
								command line switch.
							</entry>
						</row>
						<row>
							<entry condition="pot">.Revision</entry>
							<entry>
								The highest commit revision in the working copy.
								Equivalent to <literal>$WCREV$</literal>
							</entry>
						</row>
						<row>
							<entry condition="pot">.Date</entry>
							<entry>
								The commit date/time of the highest commit revision.
								Equivalent to <literal>$WCDATE$</literal>
							</entry>
						</row>
						<row>
							<entry condition="pot">.Author</entry>
							<entry>
								The author of the highest commit revision, that is, the
								last person to commit changes to the working copy.
							</entry>
						</row>
						<row>
							<entry condition="pot">.MinRev</entry>
							<entry>The minimum update revision, as shown in <literal>$WCRANGE$</literal></entry>
						</row>
						<row>
							<entry condition="pot">.MaxRev</entry>
							<entry>The maximum update revision, as shown in <literal>$WCRANGE$</literal></entry>
						</row>
						<row>
							<entry condition="pot">.HasModifications</entry>
							<entry>True if there are local modifications</entry>
						</row>
						<row>
							<entry condition="pot">.Url</entry>
							<entry>
								Replaced with the repository URL of the working
								copy path used in <literal>GetWCInfo</literal>.
								Equivalent to <literal>$WCURL$</literal>
							</entry>
						</row>
						<row>
							<entry condition="pot">.IsSvnItem</entry>
							<entry>
								True if the item is versioned.
							</entry>
						</row>
						<row>
							<entry condition="pot">.NeedsLocking</entry>
							<entry>
								True if the item has the <literal>svn:needs-lock</literal>
								property set.
							</entry>
						</row>
						<row>
							<entry condition="pot">.IsLocked</entry>
							<entry>
								True if the item is locked.
							</entry>
						</row>
						<row>
							<entry condition="pot">.LockCreationDate</entry>
							<entry>
								String representing the date when the lock was
								created, or an empty string if the item is not locked.
							</entry>
						</row>
						<row>
							<entry condition="pot">.LockOwner</entry>
							<entry>
								String representing the lock owner, or an empty
								string if the item is not locked.
							</entry>
						</row>
						<row>
							<entry condition="pot">.LockComment</entry>
							<entry>
								The message entered when the lock was created.
							</entry>
						</row>
					</tbody>
				</tgroup>
			</table>
		</para>
		<para>
			The following example shows how the interface might be used.
<programlisting>
// testCOM.js - javascript file
// test script for the SubWCRev COM/Automation-object

filesystem = new ActiveXObject("Scripting.FileSystemObject");

revObject1 = new ActiveXObject("SubWCRev.object");
revObject2 = new ActiveXObject("SubWCRev.object");
revObject3 = new ActiveXObject("SubWCRev.object");
revObject4 = new ActiveXObject("SubWCRev.object");

revObject1.GetWCInfo(
    filesystem.GetAbsolutePathName("."), 1, 1);
revObject2.GetWCInfo(
    filesystem.GetAbsolutePathName(".."), 1, 1);
revObject3.GetWCInfo(
    filesystem.GetAbsolutePathName("SubWCRev.cpp"), 1, 1);
revObject4.GetWCInfo(
    filesystem.GetAbsolutePathName("..\\.."), 1, 1);

wcInfoString1 = "Revision = " + revObject1.Revision + 
				"\nMin Revision = " + revObject1.MinRev + 
				"\nMax Revision = " + revObject1.MaxRev + 
				"\nDate = " + revObject1.Date + 
				"\nURL = " + revObject1.Url + "\nAuthor = " + 
				revObject1.Author + "\nHasMods = " + 
				revObject1.HasModifications + "\nIsSvnItem = " + 
				revObject1.IsSvnItem + "\nNeedsLocking = " + 
				revObject1.NeedsLocking + "\nIsLocked = " + 
				revObject1.IsLocked + "\nLockCreationDate = " + 
				revObject1.LockCreationDate + "\nLockOwner = " + 
				revObject1.LockOwner + "\nLockComment = " + 
				revObject1.LockComment;
wcInfoString2 = "Revision = " + revObject2.Revision + 
				"\nMin Revision = " + revObject2.MinRev + 
				"\nMax Revision = " + revObject2.MaxRev + 
				"\nDate = " + revObject2.Date + 
				"\nURL = " + revObject2.Url + "\nAuthor = " + 
				revObject2.Author + "\nHasMods = " + 
				revObject2.HasModifications + "\nIsSvnItem = " + 
				revObject2.IsSvnItem + "\nNeedsLocking = " + 
				revObject2.NeedsLocking + "\nIsLocked = " + 
				revObject2.IsLocked + "\nLockCreationDate = " + 
				revObject2.LockCreationDate + "\nLockOwner = " + 
				revObject2.LockOwner + "\nLockComment = " + 
				revObject2.LockComment;
wcInfoString3 = "Revision = " + revObject3.Revision + 
				"\nMin Revision = " + revObject3.MinRev + 
				"\nMax Revision = " + revObject3.MaxRev + 
				"\nDate = " + revObject3.Date + 
				"\nURL = " + revObject3.Url + "\nAuthor = " + 
				revObject3.Author + "\nHasMods = " + 
				revObject3.HasModifications + "\nIsSvnItem = " + 
				revObject3.IsSvnItem + "\nNeedsLocking = " + 
				revObject3.NeedsLocking + "\nIsLocked = " + 
				revObject3.IsLocked + "\nLockCreationDate = " + 
				revObject3.LockCreationDate + "\nLockOwner = " + 
				revObject3.LockOwner + "\nLockComment = " + 
				revObject3.LockComment;
wcInfoString4 = "Revision = " + revObject4.Revision + 
				"\nMin Revision = " + revObject4.MinRev + 
				"\nMax Revision = " + revObject4.MaxRev + 
				"\nDate = " + revObject4.Date + 
				"\nURL = " + revObject4.Url + "\nAuthor = " + 
				revObject4.Author + "\nHasMods = " + 
				revObject4.HasModifications + "\nIsSvnItem = " + 
				revObject4.IsSvnItem + "\nNeedsLocking = " + 
				revObject4.NeedsLocking + "\nIsLocked = " + 
				revObject4.IsLocked + "\nLockCreationDate = " + 
				revObject4.LockCreationDate + "\nLockOwner = " + 
				revObject4.LockOwner + "\nLockComment = " + 
				revObject4.LockComment;

WScript.Echo(wcInfoString1);
WScript.Echo(wcInfoString2);
WScript.Echo(wcInfoString3);
WScript.Echo(wcInfoString4);

</programlisting>
		</para>
	</sect1>
</chapter>
