| // +----------------------------------------------------------------------+ // // $Id$ // /** * @package VersionControl_SVN * @category VersionControl * @author Clay Loveless */ /** * Subversion Diff command manager class * * Display the differences between two paths. * * From 'svn diff --help': * * usage: 1. diff [-r N[:M]] [--old OLD-TARGET] [--new NEW-TARGET] [PATH...] * 2. diff -r N:M URL * 3. diff [-r N[:M]] URL1[@N] URL2[@M] * * 1. Display the differences between OLD-TARGET and NEW-TARGET. PATHs, if * given, are relative to OLD-TARGET and NEW-TARGET and restrict the output * to differences for those paths. OLD-TARGET and NEW-TARGET may be working * copy paths or URL[@REV]. * * OLD-TARGET defaults to the path '.' and NEW-TARGET defaults to OLD-TARGET. * N defaults to BASE or, if OLD-TARGET is an URL, to HEAD. * M defaults to the current working version or, if NEW-TARGET is an URL, * to HEAD. * * '-r N' sets the revision of OLD-TGT to N, '-r N:M' also sets the * revision of NEW-TGT to M. * * 2. Shorthand for 'svn diff -r N:M --old=URL --new=URL'. * * 3. Shorthand for 'svn diff [-r N[:M]] --old=URL1 --new=URL2' * * Use just 'svn diff' to display local modifications in a working copy * * Conversion of the above usage examples to VersionControl_SVN_Diff: * * Example 1: * * VERSIONCONTROL_SVN_FETCHMODE_RAW); * * $switches = array('r' => '5:8'); * $args = array('svn://svn.example.com/repos/TestProj/trunk/example.php', * 'svn://svn.example.com/repos/TestProj/trunk/example2.php'); * ); * * $svn = VersionControl_SVN::factory(array('diff'), $options); * if ($diffs = $svn->diff->run($args, $switches)) { * echo "
$diffs
"; * } else { * if (count($errs = $svnstack->getErrors())) { * foreach ($errs as $err) { * echo '
'.$err['message']."
\n"; * echo "Command used: " . $err['params']['cmd']; * } * } * } * ?> *
* * Example 2: * * VERSIONCONTROL_SVN_FETCHMODE_RAW); * * $switches = array('r' => '5:8'); * $args = array('svn://svn.example.com/repos/TestProj/trunk/example.php'); * * $svn = VersionControl_SVN::factory(array('diff'), $options); * if ($diffs = $svn->diff->run($args, $switches)) { * echo "
$diffs
"; * } else { * if (count($errs = $svnstack->getErrors())) { * foreach ($errs as $err) { * echo '
'.$err['message']."
\n"; * echo "Command used: " . $err['params']['cmd']; * } * } * } * ?> *
* * Example 3: * * VERSIONCONTROL_SVN_FETCHMODE_RAW); * * $switches = array('r' => '5:8'); * $args = array('svn://svn.example.com/repos/TestProj/trunk/example.php', * 'svn://svn.example.com/repos/TestProj/trunk/example2.php'); * * $svn = VersionControl_SVN::factory(array('diff'), $options); * if ($diffs = $svn->diff->run($args, $switches)) { * echo "
$diffs
"; * } else { * if (count($errs = $svnstack->getErrors())) { * foreach ($errs as $err) { * echo '
'.$err['message']."
\n"; * echo "Command used: " . $err['params']['cmd']; * } * } * } * ?> *
* * $switches is an array containing one or more command line options * defined by the following associative keys: * * * * $switches = array( * 'r [revision]' => 'ARG (some commands also take ARG1:ARG2 range) * A revision argument can be one of: * NUMBER revision number * "{" DATE "}" revision at start of the date * "HEAD" latest in repository * "BASE" base rev of item's working copy * "COMMITTED" last commit at or before BASE * "PREV" revision just before COMMITTED', * // either 'r' or 'revision' may be used * 'old' => 'OLD-TARGET', * // use OLD-TARGET as the older target * 'new' => 'NEW-TARGET', * // use NEW-TARGET as the newer target * 'x [extensions]'=> 'ARG', * // pass ARG as bundled options to GNU diff * // either 'x' or 'extensions' may be used * 'N' => true|false, * // operate on single directory only * 'non-recursive' => true|false, * // operate on single directory only * 'diff-cmd' => 'ARG', * // use ARG as diff command * 'no-diff-deleted' => true|false, * // do not print differences for deleted files * 'notice-ancestry' => true|false, * // notice ancestry when calculating differences * 'username' => 'Subversion repository login', * 'password' => 'Subversion repository password', * 'no-auth-cache' => true|false, * // Do not cache authentication tokens * 'config-dir' => 'Path to a Subversion configuration directory' * ); * * * * Note: Subversion does not offer an XML output option for this subcommand * * The non-interactive option available on the command-line * svn client may also be set (true|false), but it is set to true by default. * * The editor-cmd option available on the command-line svn client is not available * since this class does not operate as an interactive shell session. * * @package VersionControl_SVN * @version @version@ * @category SCM * @author Clay Loveless */ class VersionControl_SVN_Diff extends VersionControl_SVN { /** * Valid switches for svn diff * * @var array * @access public */ var $valid_switches = array('r', 'revision', 'old', 'new', 'x', 'extensions', 'N', 'non-recursive', 'non_recursive', 'diff-cmd', 'no-diff-deleted', 'no_diff_deleted', 'notice-ancestry', 'notice_ancestry', 'username', 'password', 'no-auth-cache', 'no_auth_cache', 'non-interactive', 'non_interactive', 'config-dir', 'config_dir' ); /** * Command-line arguments that should be passed * outside of those specified in {@link switches}. * * @var array * @access public */ var $args = array(); /** * Minimum number of args required by this subcommand. * See {@link http://svnbook.red-bean.com/svnbook/ Version Control with Subversion}, * Subversion Complete Reference for details on arguments for this subcommand. * @var int * @access public */ var $min_args = 1; /** * Switches required by this subcommand. * See {@link http://svnbook.red-bean.com/svnbook/ Version Control with Subversion}, * Subversion Complete Reference for details on arguments for this subcommand. * @var array * @access public */ var $required_switches = array(); /** * Use exec or passthru to get results from command. * @var bool * @access public */ var $passthru = false; /** * Prepare the svn subcommand switches. * * Defaults to non-interactive mode, and will auto-set the * --xml switch (if available) if $fetchmode is set to VERSIONCONTROL_SVN_FETCHMODE_XML, * VERSIONCONTROL_SVN_FETCHMODE_ASSOC or VERSIONCONTROL_SVN_FETCHMODE_OBJECT * * @param void * @return int true on success, false on failure. Check PEAR_ErrorStack * for error details, if any. */ function prepare() { $meets_requirements = $this->checkCommandRequirements(); if (!$meets_requirements) { return false; } $valid_switches = $this->valid_switches; $switches = $this->switches; $args = $this->args; $fetchmode = $this->fetchmode; $invalid_switches = array(); $_switches = ''; foreach ($switches as $switch => $val) { if (in_array($switch, $valid_switches)) { $switch = str_replace('_', '-', $switch); switch ($switch) { case 'revision': case 'username': case 'password': case 'old': case 'new': case 'extensions': case 'diff-cmd': case 'config-dir': $_switches .= "--$switch $val "; break; case 'r': case 'x': $_switches .= "-$switch $val "; break; case 'F': case 'm': $_switches .= "-$switch \"$val\" "; break; case 'no-auth-cache': case 'no-diff-deleted': case 'notice-ancestry': case 'non-interactive': case 'non-recursive': if ($val === true) { $_switches .= '--$switch '; } break; case 'N': if ($val === true) { $switches .= "-$switch "; } break; default: // that's all, folks! break; } } else { $invalid_switches[] = $switch; } } // We don't want interactive mode if (strpos($_switches, 'non-interactive') === false) { $_switches .= '--non-interactive '; } $_switches = trim($_switches); $this->_switches = $_switches; $cmd = "$this->svn_path $this->_svn_cmd $_switches"; if (!empty($args)) { $cmd .= ' '. join(' ', $args); } $this->_prepped_cmd = $cmd; $this->prepared = true; $invalid = count($invalid_switches); if ($invalid > 0) { $params['was'] = 'was'; $params['is_invalid_switch'] = 'is an invalid switch'; if ($invalid > 1) { $params['was'] = 'were'; $params['is_invalid_switch'] = 'are invalid switches'; } $params['list'] = $invalid_switches; $params['switches'] = $switches; $params['_svn_cmd'] = ucfirst($this->_svn_cmd); $this->_stack->push(VERSIONCONTROL_SVN_NOTICE_INVALID_SWITCH, 'notice', $params); } return true; } // }}} // {{{ parseOutput() /** * Handles output parsing of standard and verbose output of command. * * @param array $out Array of output captured by exec command in {@link run}. * @return mixed Returns output requested by fetchmode (if available), or raw output * if desired fetchmode is not available. * @access public */ function parseOutput($out) { $fetchmode = $this->fetchmode; switch($fetchmode) { case VERSIONCONTROL_SVN_FETCHMODE_RAW: return join("\n", $out); break; case VERSIONCONTROL_SVN_FETCHMODE_ASSOC: // Temporary, see parseOutputArray below return join("\n", $out); break; case VERSIONCONTROL_SVN_FETCHMODE_OBJECT: // Temporary, will return object-ified array from // parseOutputArray return join("\n", $out); break; case VERSIONCONTROL_SVN_FETCHMODE_XML: // Temporary, will eventually build an XML string // with XML_Util or XML_Tree return join("\n", $out); break; default: // What you get with VERSIONCONTROL_SVN_FETCHMODE_DEFAULT return join("\n", $out); break; } } /** * Helper method for parseOutput that parses output into an associative array * * @todo Finish this method! : ) */ function parseOutputArray($out) { $parsed = array(); } } // }}} ?>