p4ftpsync-manual.html #2

  • //
  • guest/
  • richard_gruet/
  • p4ftpsync/
  • p4ftpsync-manual.html
  • View
  • Commits
  • Open Download .zip Download (32 KB)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="description" content="Manual for p4ftpsync, a Python script to synchronize a remote site with a P4 depot via FTP." />
<meta name="keywords" content="Perforce,P4,FTP,sync,synchronization,remote,site,web,python" />
<meta name="author" content="Richard Gruet" />
<title>p4ftpsync Manual</title>

<style type="text/css">
    h1,h2,h3,h4,h5 {
        font-family:Arial, Helvetica, sans-serif;
        margin-left: 5px;
    }
    
    h1 {
        margin: 25px 10% 40px 10%;
        margin-bottom: 40px;
        border: gray dotted 2px;
        background-color:#FFCC99;
    }
    
    h2 {
        border-bottom: black solid 1px;
    }
    
    h4 {
        margin-bottom: 5px;
    }
    div {
        margin-bottom: 10px;
        margin-left: 15px;
        font-family: Georgia, "Times New Roman", Times, serif;
        /* font-family: Geneva, Arial, Helvetica, sans-serif; */
        font-size:12px;
        }

    div.optionCategory {
        margin-top: 20px;
        margin-right: 5%;
        font-weight: bold;
        font-style: italic;
        border-bottom: gray solid 1px;
    }
    
    div.option {
        font-weight: bold;
        margin-left: 40px;
        margin-bottom: 2px;
    }
    
    div.optionDesc {
        margin-left: 80px;
    }

    pre {
        border: black solid 1px;
        border-width: 1px 0 1px 0;
        margin: 7px 5% 7px 3%;
        padding: 5px 5px 5px 5px;
        background-color: #EFEFEF /* #FFCC99;*/
    }
</style>
</head>

<body>
<div style="font-size:smaller">
  <a href="javascript:location='mailto:\u0070\u0034\u0066\u0074\u0070\u0073\u0079\u006e\u0063\u0040\u0072\u0067\u0072\u0075\u0065\u0074\u002e\u006e\u0065\u0074';void 0">Richard Gruet</a> - Created September 15, 2005 - Last revised 
  <!-- #BeginDate format:Am1 -->September 20, 2005<!-- #EndDate --></div>
<h1 align="center">p4ftpsync <span style="font-size:smaller">- Synchronizes a remote site with a P4 depot via FTP</span></h1>

<h2>Table Of Contents</h2>
<div class="toc">
  <ul>
    <li><a href="#overview">Overview</a></li>
    <li><ul>
      <li><a href="#Whatsthat">What's that ?</a></li>
      <li><a href="#WhatsFor">What's for ?</a></li>
    </ul></li>
    <li><a href="#requirements">Requirements</a></li>
    <li><a href="#installation">Installation</a></li>
    <li><a href="#startup">Start-up</a></li>
    <li><a href="#commandReference">Command Reference</a></li>
      <li><ul>
        <li><a href="#reverseSync">Reverse Synchronization</a></li>
        <li><a href="#validOptions">Valid Options</a></li>
        <li><a href="#defaultValues">Default Values</a></li>
        <li><a href="#cache">Cache</a></li>
        <li><a href="#generatedScript">Generated FTP script</a></li>
        <li><a href="#log">Log</a></li>
      </ul></li>
    <li><a href="#limitations">Limitation, Bugs, Todo</a></li>
    <li><a href="#license">License</a></li>
  </ul>
</div>

<!-- OVERVIEW -->
<a name="overview" id="overview"></a><h2>Overview</h2>

<a name="Whatsthat" id="Whatsthat"></a>
<h3>What's that ?</h3>
<div><code>p4ftpsync.py</code> is a Python script which synchronizes a remote site with a P4 repository via Ftp, and vice versa. It is specially useful when you have not enough control over the remote host to be able to install a Perforce client there, which would make synchronization easy (at least the P4 to remote site sync).</div>

<a name="WhatsFor" id="WhatsFor"></a><h3>What for ?</h3>
<div>I am a member of a team which designs web sites. We want to keep the pages and code for our sites under P4 control,
     and <strong>synchronize</strong> the remote live sites from time to time to reflect the changes. Occasionally we
     have also to modify the pages <strong>directly</strong> on the live sites (in emergency situations!), and some
     of our clients can even edit the pages directly using Macromedia <a href="http://www.macromedia.com/software/contribute/"
     title="Macromedia Contribute">Contribute</a>: In these cases we want to have the P4 repository <strong>synced back</strong>.</div>

<div>If you have enough control over the web host where your live site resides, i.e. if you can install a P4 client, the first sync
    (P4 to the live site) is easily accomplished via a <code>P4 sync</code> command, but not the second since P4 doesn't detect
     automatically changes in workspaces, you still have to manually open the files for add or delete.
     And if you have not enough privileges to be able to install a P4 client, which is the case of a lot of small to medium
     sites using cheap Web Hosting, you just can't use the P4 client install/P4 sync strategy [this strategy and others are developped
     in an interesting article on the P4 web site: <a href="http://www.perforce.com/perforce/wcm.html"> Web Content management in
     Perforce</a>].</div>

<div>I searched for alternate solutions but could not find any - I could have missed something though, please let me know! -
     So I eventually wrote a program to perform the P4 to remote site synchronization, which I extended later to perform
     the reverse sync as well.</div>

<div> The problem is to emulate a P4 remote client accessible only via FTP. The basic idea is to use a dedicated local
      client/workspace that reflects (mirrors) the state of the remote site. If we P4 sync this workspace to a certain
      revision, we get the exact list of changes that occurred, which we can then propagate (<em>push</em>) to the remote
      site using FTP operations. Conversely, with the restriction that the remote site be synced to the head revision,
      we can detect changes made directly to the site by comparing the remote site and the local workspace (synced to
      the head revision beforehand).</div>

<div>Basically that's what <code>p4ftpsync</code> does. It's plain <a href="http://python.org/"
    title="Python language official site" target="_blank">Python</a>, one single loooooong file (>3000 lines!),
     uses no external library (not even the Perforce Python API) and requires only the basic P4 client install + the
     Python language (not required with the (almost) standalone executable version). It works with Perforce
     server version 2005.1 but should work with older versions as well (it doesn't use any fancy features but relies
     on P4 output parsing so it could be sensitive to change in format). The code uses some tricks to optimize speed
     (file caching, multi-threaded FTP operations) and so far it seems to be rather reliable, at least for common simple
     operations (eg sync to head revision).</div>

<!-- REQUIREMENTS -->
<a name="requirements" id="requirements"></a><h2>Requirements</h2>
<ul>
  <li>Python 2.2+ (not required if the Windows standalone executable version is used). </li>
  <li>Basic (text mode) Perforce client installed locally. No Python API required.</li>
  <li>Your remote site accessible via FTP. The more possible simultaneous connections the faster transfers will be. </li>
</ul>

<!-- INSTALLATION -->
<a name="installation" id="installation"></a><h2>Installation</h2>
<div>You have the choice between 2 distributions : </div>
<ul>
  <li>A Python script <a href="p4ftpsync.py" title="Python script">p4ftpsync.py</a>
     (you will need <a href="http://www.python.org/download/">Python</a> 2.2+ to execute it).</li>
  <li>A Win32 standalone executable <a href="p4ftpsync.exe" title="Standalone executable">p4ftpsync.exe</a>.
      Actually you may also need to download <a href="MSVCR71.dll" title="MicroSoft C Runtime library">MSVCR71.dll</a>
      if not already present on your system (this is because Python 2.4 is compiled with MicroSoft VC7, which creates
      executables that depend on that dll). Put it in the same directory as the .exe.</li>
</ul>

<div>In both cases you must have installed at least the <a href="http://perforce.com/perforce/loadprog.html"
     title="Perforce downloads" target="_blank">Perforce client</a>, and added the P4 install directory to
     your <code>PATH</code> environment variable before you can run <code>p4ftpsync</code>.
     Check it by opening a terminal and type: </div>
<pre>p4</pre>
<div>You should get a P4 help message. If not, check your P4 install and <code>PATH</code> envt var.</div>

<div><code>p4ftpsync</code> also requires that you <strong>create a dedicated P4 <em>client</em></strong> (workspace).
    This workspace will be used to <em>mirror</em> the remote site in order to perform the synchronization.
    Use the Perforce command <code>p4 client</code> to create a client. Define the client <em>map spec</em>
    so to include the part of the depot that you want to synchronize.</div>

<!-- START-UP -->
<a name="startup" id="startup"></a><h2>Start-up </h2>
<div>We assume that you have installed everything as described above and created a dedicated P4 client
    (called here <em>syncClient</em>). The examples described use the python script <code>p4ftpsync.py</code>,
    but apply to the executable version as well.</div>

<div>To get help, type :</div>
<pre>[python] p4ftpsync[.py] -h  (or --help)
</pre>
<div>You can skip the "python" if <code>p4ftpsync.py</code> is in your <code>PATH</code> and files with extension
    <code>.py</code> are associated to the Python interpreter (which is generally the case). On windows, you can even
    omit the extension <code>.py</code>, provided you have added .py to the list of extensions in the <code>PATHEXT</code>
    environment variable.</div>

<div>Let's try a normal (P4 to remote site) synchronization. Say you have your site on ftp server <em>ftpServerAddress</em>
    accessible by user <em>userName</em>, password <em>passwd</em>, rooted at <em>/mySite/www/</em>. Say the corresponding
    location in the P4 depot is at <em>//depot/mySite/www/...</em>. You want to synchronize the remote site with the
    head revision of the depot. Type:
</div>
<pre>
p4ftpsync.py -v -t --p4Passwd <em>password</em> --p4Client <em>syncClient</em> --ftpHost <em>ftpServerAddress</em>
 --ftpUser <em>userName</em> --ftpPasswd <em>passwd</em> --ftpRoot <em>/mySite/www/</em> <em>//depot/mySite/www/...</em>
</pre>
<div>
  <ul>
    <li>If you omit a mandatory option, p4ftpsync will ask you to enter it interactively. Some P4 options are
	    <em>guessed</em> from the environment, and p4ftpsync saves certain option values from one session to the
		other and uses them as defaults (more details about this later).</li>
    <li>Option <strong>-v</strong> (or --verbose) displays more detailed information messages on the screen (there
    is also an -always verbose- log, see file <code><em>sameDirAsP4ftpsync</em>/p4ftpsync.log</code>.</li>
    <li>Option <strong>-t</strong> (or --test)  performs a <em>dry run</em>: synchronization actions are listed but not
    actually executed. The 2 options can be grouped together as <code>-vt</code> since they have no parameters.</li>
  </ul>
</div>

<div>If you perform this sync for the <strong>first time</strong>, <code>p4ftpsync</code> will try to upload
    <strong>all</strong> the files in <em>//depot/mySite/www/...</em> to the remote site. Actually, the actions
	are the same as a <code>p4 sync //depot/mySite/www/...</code> would do, except that they are converted to ftp
	actions to update the remote site (viewed as a remote P4 workspace). Next runs will only transfer changes since
	the last run, as <code>P4 sync</code> would do (however option <strong>-f</strong> allows to <strong>force</strong>
    the complete refresh of the workspace and therefore will upload all the files again).
</div>
<div>As you can see, there are a <strong>lot of parameters</strong> to provide to <code>p4ftpsync</code> !
     Fortunately the program tries to <strong>help you</strong> :
  <ul>
    <li>by defaulting missing P4 parameters p4Host, p4User, p4Passwd to their current values in the environment
    (P4PORT, P4USER, P4PASSWORD - actually the program gets this info by parsing the output of a <code>p4 info</code> command).</li>
    <li> The values of several options are also <strong>saved</strong> on disk during a session and used as defaults in
         the next session (passwords are <strong>never</strong> stored).</li>
    <li> Finally, the user is prompted to dynamically enter the missing <strong>required</strong> parameters. </li>
  </ul>
  In spite of these facilities, if you have to routinely perform a sync task, it is more convenient  to define
  a small <strong>script</strong> for each site to synchronize, which will call <code>pftpsync</code> with the
  appropriate arguments. I find personally easier to define <strong>two</strong> scripts for the normal and reverse
  sync respectively (since they have different options), that I call (on Windows) <code>sync<em>MySite</em>live.bat</code>
  and <code><strong>r</strong>sync<em>MySite</em>live.bat</code>. Here is an example of such scripts :
</div>
<pre>
@echo off
REM <strong>sync<em>MySite</em>live.bat</strong>:
REM Synchronizes (depot head revision -> live site) the <em>MySite</em> live site via FTP.
REM
REM For reverse synchronization, see rsync<em>MySite</em>live.bat.
REM Uses P4 workspace ("client") <em>syncClient</em> as a mirror.
REM You can pass additional args like :
REM   -v, --verbose  to get a more detailed trace,
REM   -f, --force to force P4 to resync to the given revision
REM   ... and many more! use option -h for details.
REM 
p4ftpsync.py %* --p4Passwd <em>password</em> --p4Client <em>syncClient</em> --ftpHost <em>ftpServerAddress</em>
 --ftpUser <em>userName</em> --ftpPasswd <em>passwd</em> /mySite/www/ --exclude @<em>p4ftpSyncDir</em>\sync<em>MySite</em>live.excludes.txt
 //depot/mySite/www/...
</pre>
<div>(Replace <code>p4ftpsync.py</code> with <code>p4ftpsync.exe</code> if needed)</div>

<pre>
@echo off
REM <strong>rsync<em>MySite</em>live.bat</strong>:
REM <strong>Reverse</strong> synchronization (live site -> P4) of live site <em>MySite</em> via FTP.
REM Creates a P4 changelist for the changes and submits it.
REM
REM For normal synchronization (p4 -> live site), see sync<em>MySite</em>live.bat.
REM Uses P4 workspace ("client") <em>syncClient</em> as a mirror.
REM You can pass additional args like :
REM   -v, --verbose  to get a more detailed trace,
REM   -f, --force to disable the file desc cache and force re-reading of remote files
REM   ... and many more! use option -h for details.
REM 
p4ftpsync.py %* <strong>--reverse --submit</strong> --p4Passwd <em>password</em> --p4Client <em>syncClient</em> --ftpHost <em>ftpServerAddress</em>
 --ftpUser <em>userName</em> --ftpPasswd <em>passwd</em> /mySite/www/ <strong>--comment "GG3:rsync: Integrated changes made on the
 <em>mySite</em> live site." --mailto "[email protected],[email protected]"</strong> --exclude @<em>p4ftpSyncDir</em>\sync<em>MySite</em>live.excludes.txt
 <strong>--smtpServer smtp.myIsp.com</strong> //depot/mySite/www/...
</pre>
<div>(options specific to <strong>reverse</strong> sync are in bold).
  <ul>
    <li>option <strong>--reverse</strong> tells <code>p4ftpsync</code> to perform a <em>reverse</em> synchronisation, instead
       of the default "normal" one.</li>
    <li>option <strong>--submit</strong> tells <code>p4ftpsync</code> to automatically submit the P4 changelist created
       for the changes detected (if any). By default the changelist is not submitted to let you have a look at the
       changes and possibly revert some of them (useful during your first trials).</li>
    <li>option <strong>--comment</strong> overrides the default auto-generated changelist comment with a customized one.</li>
    <li>option <strong>--mailto</strong> tells <code>p4ftpsync</code> to send a report e-mail to each address listed.
	    The	<strong>--smtpServer</strong> option specifies the address of the SMTP server to use (the default is
	  <em>localhost:25</em>. Use options --smtpUser and --smtpPasswd if  the server requires authentication).
	  Default is to <strong>not</strong> send an email report.</li>
  </ul>
</div>

<div>Both scripts share the same <strong>list of exclusions</strong> (which makes sense). This is why the list is
     contained in a <strong>external file</strong> (<em>p4ftpSyncDir</em>\syncMySitelive.excludes.txt), rather than
     directly passed as a command line argument (this is indicated by the use of <code><strong>@</strong></code>
     in option --exclude). Files to exclude from the sync are specified as <em>patterns</em>, one per line.
     Patterns are actually Python <em>regular expressions</em>, implicitely terminated by <code>$</code>
     and preceded by <code>^.*</code>, which in practice means that patterns will be matched against the
	 <strong>end</strong> of the files to check. For examples of patterns, see option <strong>--exclude</strong>
	 in the <em><a href="#commandReference">Command Reference</a></em> section below.
</div>
<div>Once you have perfectly tuned the parameters in your 2 scripts, you may consider <strong>scheduling</strong> their
     execution, for example on a daily basis, using Control Panel/Scheduled Tasks on Windows, cron on Unix, etc...<br />
     Synchronizing and reverse synchronizing is like having two different p4 clients accessing and modifying the
     same files. If a file can be modified <strong>directly</strong> on the live site, then a situation of
     <strong>conflict</strong> (e.g. simultaneous edits of the same file) is possible, and must be <em>resolved</em>.
     By scheduling the <strong>reverse</strong> sync <strong>first</strong>, then the "normal" sync, rather
     than the contrary, one guarantees that any conflict will be detected by Perforce and scheduled for resolve.
     This is not true if the scripts are scheduled the other way (normal, then reverse): in this case any change 
     on the live site will be silently overwritten by a change (done elsewhere) already submitted in P4.
</div>
<div>The strategy above is somewhat "blind" in that it synchronizes the live site at fixed intervals without any
     consideration for actual changes made. You don't always want to propagate changes submitted in P4 to
     the live site ASAP. Maybe you want to accumulate changes somewhere and once you are ready, transfer
     them to the live site. A possible strategy to achieve this is to create a <strong>branch for the sync</strong>:
     you make the changes into the main/development branch, and when you feel ready you <em>integrate</em>
     them into the sync branch, which of course will be the one specified for the <em>whatToSync</em> parameter
     to <code>p4ftpsync</code>.
</div>

<!-- COMMAND REFERENCE -->
<a name="commandReference" id="commandReference"></a>
<h2>Command Reference</h2>
<div style="font-size:smaller">(this is basically a formatted copy of the ouput of <code>p4ftpsync --help</code>)</div>

<pre>[python] p4ftpsync[.py] [options] <em>whatToSync</em></pre>
<div> <em>whatToSync</em> specifies what to sync, and must be a valid P4 file spec such as the ones used in the
      <code>P4 sync</code> command (e.g. <code>//depot/MyProject/MyDir/...</code>,
      <code>//depot/Proj2/main.c#2</code>, <code>@label</code>, etc...). For the <em>reverse</em> sync, the revision
      range info is N.S., since the comparison is always done with the HEAD revision.</div>

<a name="reverseSync" id="reverseSync"></a><h4>Reverse sync</h4>
<div><code>p4ftpsync</code> may also be run in <em>reverse sync mode</em> (option -r). In this mode, the files
 on the remote site are compared with the latest revision files in P4 and any change on the remote site is reported
 into a new P4 <em>changelist</em> (optionally submitted at the end of the process). This mode is handy if some changes are
 done directly on the remote site and you want to easily keep your P4 repository up to date. <em>Symbolic links</em>
 are supported on the remote site but <strong>mapped to real files</strong> locally/in P4 named like the link.</div>

<a name="validOptions" id="validOptions"></a><h4>Valid options</h4>

<div class="optionCategory">Perforce options</div>

<div class="option">--p4Port <span style="font-weight:normal"><em>host</em>[:<em>port</em>]</span></div>
<div class="optionDesc">P4 host:port to use, default port 1666 [default: current config, see
     <a href="#defaultValues" target="_self">Default values</a>]</div>

<div class="option">--p4User <span style="font-weight:normal"><em>userName</em></span></div>
<div class="optionDesc">P4 user name to use [default: see <a href="#defaultValues" target="_self">Default values</a>].</div>

<div class="option">--p4Passwd <span style="font-weight:normal"><em>password</em></span></div>
<div class="optionDesc">P4 user password [default: see <a href="#defaultValues" target="_self">Default values</a>].</div>

<div class="option">--p4Client <span style="font-weight:normal"><em>client</em></span></div>
<div class="optionDesc">P4 client to use as the mirror of the remote site [default: see
     <a href="#defaultValues" target="_self">Default values</a>]. </div>

<div class="optionCategory">FTP options (for the remote site)</div>

<div class="option">--ftpHost <span style="font-weight:normal"><em>host</em>[:<em>port</em>]</span></div>
<div class="optionDesc">FTP host IP address, default port 21 [mandatory]</div>

<div class="option">--ftpUser <span style="font-weight:normal"><em>userName</em></span></div>
<div class="optionDesc">FTP user name [mandatory]</div>

<div class="option">--ftpPasswd <span style="font-weight:normal"><em>password</em></span></div>
<div class="optionDesc">FTP user password [default: will be prompted]</div>

<div class="option">--ftpRoot <span style="font-weight:normal"><em>rootRelativePath</em></span></div>
<div class="optionDesc">Path of the root folder of the site [mandatory]</div>

<div class="optionCategory">Normal sync (p4 to remote site) options</div>
<div class="option">-o, --scriptDir <span style="font-weight:normal"><em>localPath</em></span></div>
<div class="optionDesc">Directory in which to generate the Python update script in normal sync
                       [default: <code><em>thisProgDir</em>/p4FtpSyncScripts</code>]</div>
  
<div class="optionCategory">Reverse sync (remote site to P4) options</div>

<div class="option">-r, --reverse</div>
<div class="optionDesc">Reverse synchronization: Changes occurred on the remote site are detected, and
         a P4 changelist is created but not submitted, unless option -s is specified.</div>

<div class="option">-s, --submit</div>
<div class="optionDesc">Submit the P4 changelist created for the changes detected. The default is to <strong>not</strong>
         submit, so the changes can be reviewed before (manual) submit.</div>

<div class="option">-c, --comment <span style="font-weight:normal"><em>"COMMENT"</em></span></div>
<div class="optionDesc">Optional description for the changelist. A default will be generated if none is specified.</div>

<div class="option">-m, --mailto <span style="font-weight:normal"><em>addr1,addr2,...</em></span></div>
<div class="optionDesc">A list of email addresses to send a "file change report" to [default: don't send an email].
                    For now the mail server settings are globals in <code>p4ftpsync.py</code> !</div>

<div class="option">--smtpServer <span style="font-weight:normal"><em>host</em>[:<em>port</em>]</span></div>
<div class="optionDesc">SMTP server IP address to use for sending the above mail [default localhost:25]</div>

<div class="option">--smtpUser <span style="font-weight:normal"><em>userName</em></span></div>
<div class="optionDesc">SMTP user name if authentication is required [default: None]</div>

<div class="option">--smtpPasswd <span style="font-weight:normal"><em>password</em></span></div>
<div class="optionDesc">SMTP user password [default: None]</div>

<div class="option">--fromAddr <span style="font-weight:normal"><em>addr</em></span></div>
<div class="optionDesc">Email address to put in the 'From' field of the report emails [default: [email protected] -dummy!]</div>

<div class="optionCategory">Common sync. options</div>

<div class="option">-f, --force</div>
<div class="optionDesc">For <em>normal</em> sync: If specified, the target will be resynced even if supposedly up
     to date (same as P4 sync option -f).<br />
     For <em>reverse</em> sync: If specified, the file description <a href="#cache" title="File description Cache">cache</a>
     will <strong>not</strong> be used and the file download &amp; comparison will <strong>always</strong> be done.</div>
  
<div class="option">-t, --test</div>
<div class="optionDesc">Test/preview mode: For <em>normal</em> sync: do not really P4 sync the mirror client workspace,
    generate the script but do not actually FTP.<br />
    For <em>reverse</em> sync: do not create P4 changelist or copy files to client space.</div>

<div class="option">-x, --exclude <span style="font-weight:normal"><em>FILE1,FILE2,... | <strong>@</strong>FILE</em></span></div>
<div class="optionDesc">Exclude files from the list of updates to do (handy if some files must remain different locally
    from remotely, e.g. config files, system files). FILEs are specified as a comma separated list (no spaces) of
    <em>patterns</em>, or alternatively listed in a file (@FILE), one per line. <em>Patterns</em> are Python compatible
	<em>regular expressions</em>. They are implicitely completed with a <code>^.*</code> on the left and a <code>$</code>
	on the end (unless they already include them), meaning that if the <strong>end</strong> of the path of a file to sync
	matches one of the patterns, then it will be excluded from the sync. The <code>(?i)</code> flag (IGNORECASE) can be added
	to a pattern to make the match case-independent.<br /><br />
    <strong>Examples of patterns</strong><br />
    <code>.htaccess</code> (exclude the .htaccess file wherever it appears)<br />
	<code>/A/B/f.txt</code>  (exclude file f.txt located in folder /A/B/)<br />
    <code>/log/.*</code>  (exclude all files in directory log/)<br />
    <code>/~.*</code> (exclude all files whose name starts with ~)<br />
    <code>.pdf</code> (exclude all pdf files)<br />
    <code>.pdf<strong>(?i)</strong></code> (ditto, but (?i) specifies to <strong>ignore case</strong>,
	      so .PDF matches too)<br /><br />
</div>

<div class="optionCategory">Misc options</div>

<div class="option">-v, --verbose</div>
<div class="optionDesc">Verbose: More trace/error messages on stdout.</div>

<div class="option">-V, --version</div>
<div class="optionDesc">Print p4ftpsync version on stdout and exit.</div>

<div class="option">-h, --help</div>
<div class="optionDesc">Print help message on stdout and exit.</div>

<a name="defaultValues" id="defaultValues"></a><h4>Default values</h4>
<div>p4ftpsync stores (in file <code>p4ftpsync.opt</code>) the last values used for options p4Client,
     ftpHost, ftpUser and ftpRoot and uses them if no value is provided on the command line.
     Options are stored twice: as associated to the specific target sync spec, and as generic
     "last session defaults" (ftpRoot is not stored in the latter case).<br />
     When trying to reload the values for a new session, p4ftpsync first attempts to reload the
     target specific values, then the non specific ones.</div>

<a name="cache" id="cache"></a><h4>File description cache (reverse sync only)</h4>
<div> Remote file descriptions are saved on disk after a successful synchronization and used on
  subsequent syncs to determine if a file has changed (different file descs), without having to
  download the file, which can save a tremendous amount of time. There is a different cache for every
  ftp host+user (file <code><em>user</em>@<em>ftpHost</em>.fdc</code>)<br /> 
  
  On the <strong>first</strong> run of <code>p4ftpsync</code> for a given site, <strong>all</strong>
  files from the remote site will be downloaded and compared to the files in the depot, quite a lengthy
  and bandwith consuming operation ! However next iterations should use the cache and be considerably
  faster (the only relatively long operation that can't be shortened is the determination of the current
  file structure on the remote site). When the cache is missing or corrupted, the download of the entire
  site (minus the exclusions) occurs again.<br />
  
  The cache can be <strong>disabled</strong> with option -f, --force (it is then not used for the current
  iteration but will still be saved for future use).
</div>

<a name="generatedScript" id="generatedScript"></a><h4>Generated FTP Script</h4>
<div>In normal sync, a <strong>Python script</strong> is created in the directory indicated by option -o
     for the specified target (<em>whatToSync</em>). The script is named <em>what</em>_<em>date</em>.py
     (with / and spaces replaced by _). It contains the set of FTP actions required to synchronize
     the remote client (site) as requested, therefore its execution will perform the actual update,
     which can prove very useful, should the FTP session fail before completion: executing the script will
      <em>ftp</em> the changes again.
</div>

<a name="log" id="log"></a><h4>Log</h4>
<div> A file <code>p4ftpsync.log</code> is generated in <code>p4ftpsync</code>'s folder (always
    <em>verbose</em>, unlike the on-screen trace which depends on option -v). Logs are rotated to
    <code>p4ftpsync.log.<em>n</em>.zip</code> when they exceed a certain size (4MB by default).
</div>

<!-- LIMITATIONS -->
<a name="limitations" id="limitations"></a><h2>Limitations, Bugs, ToDo</h2>
<div>The most obvious limitations and todos I can think of right now are:
  <ul>
    <li>A limited support for <em>symbolic links</em>. Currently links are recognized on the remote site
        but translated into normal files in P4 during reverse sync. That is, we tolerate that links
        exist on the remote site but not locally and in P4. Since P4 supports symbolic links, it
        could potentially be changed, though. (<em>Due to the comparison strategy used during reverse
        sync, I'm not sure that the case where 2 links withing the site point to the same file is
        correctly handled: it will create as many real files in p4</em>). </li>
    <li>An uncertain support of <strong>older versions of the P4 server</strong> (&lt;2005.1). This program probably works
        with not-too-old versions of the server, but I wouldn't bet on it.</li>
    <li>Support of <strong>all ftp servers</strong> is not guaranteed either. I tried on at least
        3 different servers, but they are sometimes surprising in their use of error codes. </li>
    <li>... and probably many other ones I don't think of ...</li>
  </ul>
</div>
         
<div>Please report bugs or suggestions to <a href="javascript:location='mailto:\u0070\u0034\u0066\u0074\u0070\u0073\u0079\u006e\u0063\u0040\u0072\u0067\u0072\u0075\u0065\u0074\u002e\u006e\u0065\u0074';void 0">Richard Gruet</a>.  I'd be happy to hear from you. I'll try to fix bugs
and implement suggestions if I think they can improve p4ftpsync (and are not to complex !). Don't hold your breath, though.
I'm quite busy.
</div>

<!-- LICENSE -->
<a name="license" id="license"></a><h2>License</h2>
<div>Copyright &copy; 2004-2005 <a href="javascript:location='mailto:\u0070\u0034\u0066\u0074\u0070\u0073\u0079\u006e\u0063\u0040\u0072\u0067\u0072\u0075\u0065\u0074\u002e\u006e\u0065\u0074';void 0">Richard Gruet</a></div>
<div>Permission to use, copy, modify, and distribute this software and its
    documentation for any purpose and without fee or royalty is hereby
    granted, provided that the above copyright notice appear in all copies
    and that both that copyright notice and this permission notice appear
    in supporting documentation or portions thereof, including modifications,
    that you make.</div>

<div>THE AUTHOR RICHARD GRUET DISCLAIMS ALL WARRANTIES WITH REGARD TO
    THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
    INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
    FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
    NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !</div>

<div>In short: I publish this program in hope it can be useful to others. Use it as you wish but keep the copyright
   intact, and don't hold me responsible for any problem you run into ;)</div>

</body>
</html>
# Change User Description Committed
#2 5125 Richard Gruet minor (compatible) changes; improved manual.
#1 5122 Richard Gruet Changed cache validation method; logs now rotated when >4MB; created user manual; other minor improvements (comments, etc..).