Skip to content

Commit

Permalink
Pass unrecognized CLI options to svn. Enabled stop on copy.
Browse files Browse the repository at this point in the history
Renamed options to prevent naming conflicts with SVN, so that options can be
passed through directly to SVN. This allows the username to be specified on
the command line and enables the user to set any other SVN params.
Changed:
    -s (--reverse)  to  -R (--reverse)
    -r (--repo)     to  -o (--repo)
    -v (--verbose)  to  -D (--debug)

Only show history since current branch was created. This is another way to
naturally limit the size of the svn response and improve performance.
(Use --follow-copies to see full history with commits from origin branch.)

Disable limit on number of commits transferred by setting --limit=0.
Disable limit on days of data transferred by setting --days=0. (default)

Refactored:
Moved code for determining repo based on CWD from command line runner to Slog.
Moved code for loading the formatter class from command line runner to Slog.
  • Loading branch information
Mariano Peterson authored and marianopeterson committed Mar 2, 2011
1 parent 244ce91 commit ee96c5c
Show file tree
Hide file tree
Showing 3 changed files with 290 additions and 70 deletions.
23 changes: 23 additions & 0 deletions CliParser.php
Expand Up @@ -36,6 +36,13 @@ class CliParser
*/
private $opts = array();

/**
* Array of unrecognized args (no matching entry in $this->spec).
*
* @var array<string>
*/
private $unrecognized = array();

/**
* Map of specifications for allowable parameters, keyed by short name.
*
Expand Down Expand Up @@ -124,23 +131,30 @@ public function load(array $argv)
$nextArg = ($i + 1 < $argc) ? $argv[$i + 1] : null;

if (strpos($arg, '=') !== false) { // -a=foo, --author=foo
$unrecognized = $arg; // raw value that will be added to the
// unrecognized list if we can't find it
// in $this->spec
$tmp = explode('=', $arg);
$name = trim(trim($tmp[0]), '-');
$value = trim($tmp[1]);
} elseif ($nextArg && substr($nextArg, 0, 1) != '-') { // -a foo, --author foo
$unrecognized = $arg . " " . $nextArg;
$name = trim(trim($arg), '-');
$value = trim($nextArg);
$i++;
} else { // -v, --verbose
$unrecognized = $arg;
$name = trim(trim($arg), '-');
$value = null;
}
$this->debug("load(): analyzing input \"$name\"=\"$value\"");
$matched = false;

foreach ($this->spec as $spec) {
$this->debug("load(): comparing to option ({$spec['short']}, {$spec['long']})");
if ($name == $spec['short'] || $name == $spec['long']) {
$this->debug("load(): MATCHES ({$spec['short']}, {$spec['long']})");
$matched = true;
if ($spec['type'] == self::TYPE_FLAG) {
$this->opts[$spec['short']] = true;
} elseif ($spec['type'] == self::TYPE_ARRAY) {
Expand All @@ -159,6 +173,10 @@ public function load(array $argv)
break;
}
}

if (!$matched) {
$this->unrecognized[] = trim($unrecognized);
}
}
return $this;
}
Expand Down Expand Up @@ -206,4 +224,9 @@ public function debug($msg)
return;
print "[DEBUG] $msg\n";
}

public function getUnrecognizedOpts()
{
return implode(" ", $this->unrecognized);
}
}
242 changes: 221 additions & 21 deletions Slog.php
Expand Up @@ -61,6 +61,23 @@ class Slog
*/
private $limit;

/**
* Whether or not to follow commit history beyond the current branch and
* into the origin branch.
*
* @var bool
*/
private $stopOnCopy;

/**
* String of command line options to send to svn log. This is intended to
* store options that were unrecognized by Slog so that we can pass them
* along to svn log instead.
*
* @var string
*/
private $svnOpts;

/**
* Path to the SVN binary.
*
Expand All @@ -76,22 +93,132 @@ class Slog
private $formatter;

/**
* @param string $repo Path to the SVN repo.
* @param int $days Fetch commits submitted within this number of days.
* @param int $limit Max number of commits to fetch from the SVN repo.
*/
public function __construct($repo, $days, $limit)
public function __construct()
{
$this->debug = false;
$this->removeAuthors = array();
$this->mustMatchAuthors = array();
$this->mustMatchRegexes = array();
$this->repo = $repo;
$this->days = $days;
$this->limit = $limit;
$this->repo = null;
$this->days = null;
$this->limit = null;
$this->stopOnCopy = true;
$this->svnOpts = '';
$this->svn = '/usr/bin/env svn';
}

/**
* Override the path to the SVN repo.
*
* @param string $path Filepath or URL to the SVN repo.
*
* @return Slog (supports fluent interface)
*/
public function setRepo($path)
{
$this->repo = $repoUrl;
return $this;
}

/**
* Get repo for working copy at $path.
*
* @param string $path
*
* @return string|null URL for SVN repo associated with Working Copy at
* $path.
*/
public function getRepoFromWorkingCopy($path)
{
$repo = null;
$cmd = "{$this->svn} info 2>/dev/null";
$stdOut = array();
$exitCode = null;
$lastLine = exec($cmd, $stdOut, $exitCode);
foreach ($stdOut as $line) {
if (substr($line, 0, 5) == 'URL: ') {
$repo = substr($line, 5);
break;
}
}
// $repo will be null if svn couldn't get the repo URL for the
// working copy at $path
return $repo;
}

/**
* Get path to SVN repo.
* If repo was set with $slog->setRepo($repo), then $repo is used.
* Otherwise if the CWD is a working copy, the working copy's repo is used.
* Otherwise if the environment variable SLOG_DEFAULT_REPO exists, that is used.
* If none of the above can be resolved, an exception is thrown.
*
* @throws Exception if none of the above methods are able to resolve the repo URL.
*
* @return string|null URL for SVN repo.
*/
public function getRepo()
{
if (empty($this->repo)) {
$this->repo = $this->getRepoFromWorkingCopy(getcwd());
}
if (empty($this->repo)) {
if (isset($_SERVER['SLOG_DEFAULT_REPO'])) {
$this->repo = $_SERVER['SLOG_DEFAULT_REPO'];
}
}
if (empty($this->repo)) {
throw new Exception("Could not determine the SVN repo. Its likely "
. "that the current directory is not a working copy.");
}
return $this->repo;
}

/**
* Set the maximum number of days worth of historical data to fetch from svn log.
*
* @param int $days Maximum number of days worth of historical data to
* fetch from svn log.
*
* @return Slog (supports fluent interface)
*/
public function setDays($days)
{
$this->days = (int)$days;
return $this;
}

/**
* @return int Number of days of historical data to fetch from svn log.
*/
public function getDays()
{
return $this->days;
}

/**
* Set the max number of commits to fetch from the SVN server.
*
* @param int $limit Max number of commits to fetch from the SVN server.
*
* @return Slog (supports fluent interface)
*/
public function setLimit($limit)
{
$this->limit = (int) $limit;
return $this;
}

/**
* @return int Max number of commits to fetch from the SVN server.
*/
public function getLimit()
{
return $this->limit;
}

/**
* @param bool $status Set true to enable debugging output.
*
Expand Down Expand Up @@ -120,20 +247,46 @@ private function debug($msg)
print "[DEBUG] $msg\n";
}
}

private function load($repo, $days, $limit)

/**
* Set whether or not to follow commits past the current branch to the origin.
*
* @param bool $bool Set true to only show commits from the current branch,
* set false to show commits all the way back to origin.
*
* @return Slog (supports fluent interface)
*/
public function setStopOnCopy($bool = true)
{
$startDate = date(self::DATE_FORMAT, strtotime("-$days days"));
$cmd = sprintf(
"%s log --xml -r {%s}:HEAD -v %s 2>&1",
$this->svn,
$startDate,
$repo
);
if ($limit) {
$cmd .= " --limit $limit";
$this->stopOnCopy = (bool)$bool;
return $this;
}

/**
* Returns true if the Slog instance is configured to stop on copy.
*
* @return bool True if the Slog instance is configured to stop on copy.
*/
public function getStopOnCopy()
{
return $this->stopOnCopy;
}

private function load()
{
if ($this->getDays()) {
$startDate = date(self::DATE_FORMAT, strtotime("-{$this->getDays()} days"));
$revision = "--revision {{$startDate}}:HEAD";
} else {
$revision = '';
}
$this->debug("Executing cmd: $cmd");
$limit = $this->getLimit() ? "--limit {$this->getLimit()}" : '';
$stopOnCopy = $this->getStopOnCopy() ? "--stop-on-copy" : '';
$repo = $this->getRepo();

$cmd = "{$this->svn} log {$this->svnOpts} --xml {$revision} {$limit} {$stopOnCopy} -v {$repo} 2>&1";

$this->debug("Executing command: {$cmd}");
$xml = $this->fetchXml($cmd);
$this->data = simplexml_load_string($xml);
}
Expand Down Expand Up @@ -234,7 +387,7 @@ public function toString()
public function __toString()
{
try {
$this->load($this->repo, $this->days, $this->limit);
$this->load();
} catch (Exception $e) {
$msg = sprintf( "\nERROR(%s): %s\n\nSTACK TRACE:\n%s\n\n",
$e->getCode(),
Expand Down Expand Up @@ -284,9 +437,33 @@ private function filter($commit)
}
return true;
}


/**
* Loads and sets the formatter to be used for output, based on
* a short name and a cli object (for style preferences).
*
* @param string $name Short name of the Formatter class to load.
* @param CliParser $cli Command line options to use (for style preferences)
*
* @return Slog (supports fluent interface)
*/
public function setFormatterByName($name, CliParser $cli)
{
$format = ucfirst(strtolower($name));
$class = 'Slog_Formatter_' . $format;
$file = dirname(__FILE__) . "/Slog/Formatter/{$format}.php";
if (!is_readable($file)) {
throw new Exception("Could not load formatter: $format. Tried to load from $file.");
}
require_once($file);
$formatter = new $class($cli);
$this->setFormatter($formatter);
return $this;
}

/**
* Set the formatter to be used by the log printer.
* @see setFormatterByName()
*
* @param SvnLog_Formatter_Interface $formatter Formatting implementation
* to use for printing the
Expand All @@ -309,5 +486,28 @@ public function getFormatter()
{
return $this->formatter;
}


/**
* Set string of additional command line opts to send to svn log.
*
* @param string $opts String of additional command line opts to send to svn log.
*
* @return Slog (supports fluent interface)
*/
public function setSvnOpts($opts)
{
$this->svnOpts = $opts;
return $this;
}

/**
* Returns the string of additional command line opts to send to svn log.
*
* @return String of additional command line opts to send to svn log.
*/
public function getSvnOpts()
{
return $this->svnOpts;
}

}

0 comments on commit ee96c5c

Please sign in to comment.