Remove Horde_Vcs_Diff class.
Fix some issues relating to paths.
Clean up patchset generation.
Clean up caching/directory browsing.
Various phpdoc cleanup.
Make this code more correctly OO - now down to only 1 main class
(Horde_Vcs) and 4 subclasses (Horde_Vcs_File, Horde_Vcs_Directory,
Horde_Vcs_Log, and Horde_Vcs_Patchset).
/* Spawn the file object. */
try {
- $fl = $VC->getFileObject($where, array('cache' => $cache));
+ $fl = $VC->getFileObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
if ($atdir) {
try {
- $dir = $VC->queryDir($where);
$atticFlags = (bool)$acts['sa'];
- $dir->browseDir($cache, true, $atticFlags);
+ $dir = $VC->getDirObject($where, array('quicklog' => true, 'showattic' => $atticFlags));
$dir->applySort($acts['sbt'], $acts['ord']);
$dirList = &$dir->queryDirList();
$fileList = $dir->queryFileList($atticFlags);
/* Showing a file. */
$onb = Util::getFormData('onb');
try {
- $fl = $VC->getFileObject($where, array('cache' => $cache, 'branch' => $onb));
+ $fl = $VC->getFileObject($where, array('branch' => $onb));
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
$title = sprintf(_("Revisions for %s"), $where);
$extraLink = Chora::getFileViews();
-$first = end($fl->logs);
+$logs = $fl->queryLogs();
+$first = end($logs);
$diffValueLeft = $first->queryRevision();
$diffValueRight = $fl->queryRevision();
$sel = '';
-foreach ($fl->symrev as $sm => $rv) {
+foreach ($fl->querySymbolicRevisions() as $sm => $rv) {
$sel .= '<option value="' . $rv . '">' . $sm . '</option>';
}
$selAllBranches = '';
if ($VC->hasFeature('branches')) {
- foreach (array_keys($fl->branches) as $sym) {
+ foreach (array_keys($fl->queryBranches()) as $sym) {
$selAllBranches .= '<option value="' . $sym . '"' . (($sym === $onb) ? ' selected="selected"' : '' ) . '>' . $sym . '</option>';
}
}
require CHORA_TEMPLATES . '/log/header.inc';
$i = 0;
-foreach ($fl->logs as $lg) {
+reset($logs);
+while (list(,$lg) = each($logs)) {
$rev = $lg->queryRevision();
$branch_info = $lg->queryBranch();
/* Create the VC_File object and populate it. */
try {
- $file = $VC->getFileObject($where, array('cache' => $cache));
+ $file = $VC->getFileObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
/* Retrieve the actual checkout. */
try {
- $checkOut = $VC->checkout($file, $r);
+ $checkOut = $VC->checkout($file->queryPath(), $r);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
$pretty = Chora::pretty($mime_type, $checkOut);
/* Get this revision's attributes in printable form. */
- $log = $file->logs[$r];
+ $log = $file->queryLogs($r);
$title = sprintf(_("%s Revision %s (%s ago)"),
basename($fullname),
$r,
- Chora::readableTime($log->date, true));
+ Chora::readableTime($log->queryDate(), true));
$extraLink = sprintf('<a href="%s">%s</a> | <a href="%s">%s</a>',
Chora::url('annotate', $where, array('rev' => $r)), _("Annotate"),
Chora::url('co', $where, array('r' => $r, 'p' => 1)), _("Download"));
/* Spawn the repository and file objects */
try {
- $fl = $VC->getFileObject($where, array('cache' => $cache));
+ $fl = $VC->getFileObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
* the end of the file - patch requires it. */
if ($type != 'colored') {
header('Content-Type: text/plain');
- echo implode("\n", $VC->getDiff($fl, $r1, $r2, $type, $num, $ws)) . "\n";
+ echo implode("\n", $VC->diff($fl, $r1, $r2, array('num' => $num, 'type' => $type, 'ws' => $ws))) . "\n";
exit;
}
"<td><img src=\"$url2\" alt=\"" . htmlspecialchars($r2) . '" /></td></tr>';
} else {
/* Retrieve the tree of changes. */
- $lns = $VC->getDiff($fl, $r1, $r2, 'unified', $num, $ws, true);
+ $lns = $VC->diff($fl, $r1, $r2, array('human' => true, 'num' => $num, 'ws' => $ws));
if (!$lns) {
/* Is the diff empty? */
require CHORA_TEMPLATES . '/diff/hr/nochange.inc';
require_once dirname(__FILE__) . '/lib/base.php';
+// TODO - This currently doesn't work.
+Chora::fatal('History display is currently broken', '500 Internal Server Error');
+
/* Exit if it's not supported. */
if (!$VC->hasFeature('branches')) {
header('Location: ' . Chora::url('browse', $where));
/* Spawn the file object. */
try {
- $fl = $VC->getFileObject($where, array('cache' => $cache));
+ $fl = $VC->getFileObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
$brrev = $brkeys[$a];
$brcont = $branches[$brrev];
/* Check to see if current point matches a branch point. */
- if (!strcmp($rev, $VC->strip($brrev, 1))) {
+// if (!strcmp($rev, $VC->strip($brrev, 1))) {
+ if (!strcmp($rev, $brrev)) {
/* If it does, figure out how many rows we have to add. */
$numRows = sizeof($brcont);
/* Check rows in columns to the right, until one is
/* Otherwise, this cell has content; determine what it is. */
$rev = $row[$i];
- if ($VC->isValidRevision($rev) && ($VC->sizeof($rev) % 2)) {
+// if ($VC->isValidRevision($rev) && ($VC->sizeof($rev) % 2)) {
+ if ($VC->isValidRevision($rev)) {
/* This is a branch point, so put the info out. */
$bg = isset($branch_colors[$rev]) ? $branch_colors[$rev] : '#e9e9e9';
$symname = $fl->branches[$rev];
} elseif (preg_match('|^:|', $rev)) {
/* This is a continuation cell, so render it with the
* branch colour. */
- $bgbr = $VC->strip(preg_replace('|^\:|', '', $rev), 1);
+// $bgbr = $VC->strip(preg_replace('|^\:|', '', $rev), 1);
$bg = isset($branch_colors[$bgbr]) ? $branch_colors[$bgbr] : '#e9e9e9';
require CHORA_TEMPLATES . '/history/blank.inc';
} elseif ($VC->isValidRevision($rev)) {
/* This cell contains a revision, so render it. */
- $bgbr = $VC->strip($rev, 1);
+// $bgbr = $VC->strip($rev, 1);
$bg = isset($branch_colors[$bgbr]) ? $branch_colors[$bgbr] : '#e9e9e9';
$log = $fl->logs[$rev];
$author = Chora::showAuthorName($log->queryAuthor());
$sourcerootopts = $sourceroots[$acts['rt']];
$sourceroot = $acts['rt'];
+ // Cache.
+ if (empty($conf['caching'])) {
+ $cache = null;
+ } else {
+ $cache = &Horde_Cache::singleton($conf['cache']['driver'], Horde::getDriverConfig('cache', $conf['cache']['driver']));
+ }
+
$conf['paths']['temp'] = Horde::getTempDir();
try {
$GLOBALS['VC'] = Horde_Vcs::factory(String::ucfirst($sourcerootopts['type']),
- array('sourceroot' => $sourcerootopts['location'],
+ array('cache' => $cache,
+ 'sourceroot' => $sourcerootopts['location'],
'paths' => $conf['paths'],
'username' => isset($sourcerootopts['username']) ? $sourcerootopts['username'] : '',
'password' => isset($sourcerootopts['password']) ? $sourcerootopts['password'] : ''));
* @param string $message The verbose error message to be displayed.
* @param string $responseCode The HTTP error number (and optional text),
* for sending 404s or other codes if
- * appropriate..
+ * appropriate.
*/
static public function fatal($message, $responseCode = null)
{
$tags[] = '<a href="' . Chora::url('', $where, array('onb' => $bra)) . '">'. htmlspecialchars($symb) . '</a>';
}
- if ($lg->tags) {
- foreach ($lg->tags as $tag) {
- $tags[] = htmlspecialchars($tag);
- }
+ foreach ($lg->queryTags() as $tag) {
+ $tags[] = htmlspecialchars($tag);
}
return $tags;
$notification = &Notification::singleton();
$notification->attach('status');
-// Cache.
-if (empty($conf['caching'])) {
- $cache = null;
-} else {
- $cache = &Horde_Cache::singleton($conf['cache']['driver'], Horde::getDriverConfig('cache', $conf['cache']['driver']));
-}
-
// Horde base libraries.
require_once 'Horde/Text.php';
require_once 'Horde/Help.php';
}
try {
- $ps = $VC->getPatchsetObject($where, $cache);
+ $ps = $VC->getPatchsetObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
require CHORA_TEMPLATES . '/headerbar.inc';
require CHORA_TEMPLATES . '/patchsets/header.inc';
-$patchsets = $ps->_patchsets;
+$patchsets = $ps->getPatchsets();
krsort($patchsets);
foreach ($patchsets as $id => $patchset) {
$commitDate = Chora::formatDate($patchset['date']);
require_once dirname(__FILE__) . '/lib/base.php';
try {
- $fl = $VC->getFileObject($where, array('cache' => $cache));
+ $fl = $VC->getFileObject($where);
} catch (Horde_Vcs_Exception $e) {
Chora::fatal($e);
}
</tbody>
</table>
-<?php if (count($fl->logs) > 100 && !Util::getFormData('all')): ?>
+<?php if ($fl->revisionCount() > 100 && !Util::getFormData('all')): ?>
<table class="options" cellspacing="0">
<tr>
<td>
*
* @var array
*/
- protected $_users;
+ protected $_users = null;
/**
* The current driver.
protected $_driver;
/**
- * Cached objects.
+ * If caching is desired, a Horde_Cache object.
*
- * @var array
+ * @var Horde_Cache
*/
- protected $_cached = array();
+ protected $_cache;
/**
* Does driver support deleted files?
protected $_cacheVersion = 3;
/**
+ * The available diff types.
+ *
+ * @var array
+ */
+ protected $_diffTypes = array('column', 'context', 'ed', 'unified');
+
+ /**
* Attempts to return a concrete Horde_Vcs instance based on $driver.
*
* @param mixed $driver The type of concrete Horde_Vcs subclass to return.
*/
public function __construct($params = array())
{
+ $this->_cache = empty($params['cache']) ? null : $params['cache'];
$this->_sourceroot = $params['sourceroot'];
$this->_paths = $params['paths'];
* Create a range of revisions between two revision numbers.
*
* @param Horde_Vcs_File $file The desired file.
- * @param string $r1 The initial revision.
- * @param string $r2 The ending revision.
+ * @param string $r1 The initial revision.
+ * @param string $r2 The ending revision.
*
* @return array The revision range, or empty if there is no straight
* line path between the revisions.
*/
public function getRevisionRange($file, $r1, $r2)
{
- if (!isset($this->_cache['diff'])) {
- $class = 'Horde_Vcs_Diff_' . $this->_driver;
- $this->_cache['diff'] = new $class();
- }
- return $this->_cache['diff']->getRevisionRange($this, $file, $r1, $r2);
- }
-
- /**
- * Returns the location of the specified binary.
- *
- * @param string $binary An external program name.
- *
- * @return boolean|string The location of the external program or false if
- * it wasn't specified.
- */
- public function getPath($binary)
- {
- if (isset($this->_paths[$binary])) {
- return $this->_paths[$binary];
- }
-
- return false;
- }
-
- /**
- * Parse the users file, if present in the source root, and return
- * a hash containing the requisite information, keyed on the
- * username, and with the 'desc', 'name', and 'mail' values inside.
- *
- * @return boolean|array False if the file is not present, otherwise
- * $this->_users populated with the data
- */
- public function getUsers($usersfile)
- {
- /* Check that we haven't already parsed users. */
- if (isset($this->_users) && is_array($this->_users)) {
- return $this->_users;
- }
-
- if (!@is_file($usersfile) || !($fl = @fopen($usersfile, VC_WINDOWS ? 'rb' : 'r'))) {
- return false;
- }
-
- $this->_users = array();
-
- /* Discard the first line, since it'll be the header info. */
- fgets($fl, 4096);
-
- /* Parse the rest of the lines into a hash, keyed on
- * username. */
- while ($line = fgets($fl, 4096)) {
- if (preg_match('/^\s*$/', $line)) {
- continue;
- }
- if (!preg_match('/^(\w+)\s+(.+)\s+([\w\.\-\_]+@[\w\.\-\_]+)\s+(.*)$/', $line, $regs)) {
- continue;
- }
-
- $this->_users[$regs[1]]['name'] = trim($regs[2]);
- $this->_users[$regs[1]]['mail'] = trim($regs[3]);
- $this->_users[$regs[1]]['desc'] = trim($regs[4]);
- }
-
- return $this->_users;
- }
-
- public function queryDir($where)
- {
- $class = 'Horde_Vcs_Directory_' . $this->_driver;
- return new $class($this, $where);
- }
-
- public function getDiff($file, $rev1, $rev2, $type = 'unified', $num = 3,
- $ws = true, $human = false)
- {
- if (!isset($this->_cache['diff'])) {
- $class = 'Horde_Vcs_Diff_' . $this->_driver;
- $this->_cache['diff'] = new $class();
- }
- $diff = $this->_cache['diff']->get($this, $file, $rev1, $rev2, $type, $num, $ws);
- return $human ? $this->_cache['diff']->humanReadable($diff) : $diff;
- }
-
- public function availableDiffTypes()
- {
- if (!isset($this->_cache['diff'])) {
- $class = 'Horde_Vcs_Diff_' . $this->_driver;
- $this->_cache['diff'] = new $class();
- }
- return $this->_cache['diff']->availableDiffTypes();
- }
-
- /**
- * Function which returns a file pointing to the head of the requested
- * revision of an SVN file.
- *
- * @param string $fullname Fully qualified pathname of the desired file
- * to checkout
- * @param string $rev Revision number to check out
- *
- * @return resource A stream pointer to the head of the checkout.
- */
- public function checkout($fullname, $rev)
- {
- return null;
- }
-
- /**
- * $opts:
- * 'cache' - (boolean)
- * 'quicklog' - (boolean)
- * 'branch' - (string)
- */
- public function getFileObject($filename, $opts = array())
- {
- $class = 'Horde_Vcs_File_' . $this->_driver;
-
- /* The version of the cached data. Increment this whenever the
- * internal storage format changes, such that we must
- * invalidate prior cached data. */
- sort($opts);
- $cacheId = implode('|', array($class, $this->sourceroot(), $filename, serialize($opts), $this->_cacheVersion));
-
- $ctime = time() - filemtime($filename);
- if (!empty($opts['cache']) &&
- $opts['cache']->exists($cacheId, $ctime)) {
- $fileOb = unserialize($opts['cache']->get($cacheId, $ctime));
- $fileOb->setRepository($this);
- } else {
- $fileOb = new $class($this, $filename, $opts);
- $fileOb->applySort(self::SORT_AGE);
-
- if (!empty($opts['cache'])) {
- $opts['cache']->set($cacheId, serialize($fileOb));
- }
- }
-
- return $fileOb;
- }
-
- public function getPatchsetObject($filename, $cache = null)
- {
- $class = 'Horde_Vcs_Patchset_' . $this->_driver;
- $vc_patchset = new $class($this, $filename, $cache);
- return $vc_patchset->getPatchsetObject();
- }
-
- /**
- * TODO
- */
- public function annotate($fileob, $rev)
- {
return array();
}
/**
- * Given a revision string, remove a given number of portions from
- * it. For example, if we remove 2 portions of 1.2.3.4, we are
- * left with 1.2.
- *
- * @param string $val Input revision string.
- * @param integer $amount Number of portions to strip.
- *
- * @return string Stripped revision string.
- */
- public function strip($val, $amount = 1)
- {
- return $val;
- }
-
- /**
- * The size of a revision number is the number of portions it has.
- * For example, 1,2.3.4 is of size 4.
- *
- * @param string $val Revision number to determine size of
- *
- * @return integer Size of revision number
- */
- public function sizeof($val)
- {
- return 1;
- }
-
- /**
- * Given two revisions, this figures out which one is greater than the
- * the other.
- *
- * @param string $rev1 Revision string.
- * @param string $rev2 Second revision string.
- *
- * @return integer 1 if the first is greater, -1 if the second if greater,
- * and 0 if they are equal
- */
- public function cmp($rev1, $rev2)
- {
- return strcasecmp($rev1, $rev2);
- }
-
- /**
- * Return the logical revision before this one.
- *
- * @param string $rev Revision string to decrement.
- *
- * @return string|boolean Revision string, or false if none could be
- * determined.
- */
- public function prev($rev)
- {
- return false;
- }
-
- /**
- * Returns an abbreviated form of the revision, for display.
+ * Obtain the differences between two revisions of a file.
*
- * @param string $rev The revision string.
+ * @param Horde_Vcs_File $file The desired file.
+ * @param string $rev1 Original revision number to compare from.
+ * @param string $rev2 New revision number to compare against.
+ * @param array $opts The following optional options:
+ * <pre>
+ * 'human' - (boolean) DEFAULT: false
+ * 'num' - (integer) DEFAULT: 3
+ * 'type' - (string) DEFAULT: 'unified'
+ * 'ws' - (boolean) DEFAULT: true
+ * </pre>
*
- * @return string The abbreviated string.
+ * @return string|boolean False on failure, or a string containing the
+ * diff on success.
+ * @throws Horde_Vcs_Exception
*/
- public function abbrev($rev)
+ public function diff($file, $rev1, $rev2, $opts = array())
{
- return $rev;
+ $opts = array_merge(array(
+ 'num' => 3,
+ 'type' => 'unified',
+ 'ws' => true
+ ), $opts);
+
+ $this->assertValidRevision($rev1);
+ $this->assertValidRevision($rev2);
+
+ $diff = $this->_diff($file, $rev1, $rev2, $opts);
+ return empty($opts['human'])
+ ? $diff
+ : $this->_humanReadableDiff($diff);
}
-}
-
-/**
- * @package Horde_Vcs
- */
-abstract class Horde_Vcs_Diff
-{
- /**
- * The available diff types.
- *
- * @var array
- */
- protected $_diffTypes = array('column', 'context', 'ed', 'unified');
-
/**
* Obtain the differences between two revisions of a file.
*
- * @param Horde_Vcs $rep A repository object.
* @param Horde_Vcs_File $file The desired file.
* @param string $rev1 Original revision number to compare from.
* @param string $rev2 New revision number to compare against.
- * @param string $type The type of diff (e.g. 'unified').
- * @param integer $num Number of lines to be used in context and
- * unified diffs.
- * @param boolean $ws Show whitespace in the diff?
+ * @param array $opts The following optional options:
+ * <pre>
+ * 'num' - (integer) DEFAULT: 3
+ * 'type' - (string) DEFAULT: 'unified'
+ * 'ws' - (boolean) DEFAULT: true
+ * </pre>
*
* @return string|boolean False on failure, or a string containing the
* diff on success.
*/
- abstract public function get($rep, $file, $rev1, $rev2, $type = 'context',
- $num = 3, $ws = true);
+ protected function _diff($file, $rev1, $rev2, $opts)
+ {
+ return false;
+ }
/**
* Obtain a tree containing information about the changes between
*
* @return array @TODO
*/
- public function humanReadable($raw)
+ protected function _humanReadableDiff($raw)
{
$ret = array();
}
/**
- * Create a range of revisions between two revision numbers.
+ * Return the list of available diff types.
*
- * @param Horde_Vcs $rep A repository object.
- * @param Horde_Vcs_File $file The desired file.
- * @param string $r1 The initial revision.
- * @param string $r2 The ending revision.
+ * @return array The list of available diff types for use with get().
+ */
+ public function availableDiffTypes()
+ {
+ return $this->_diffTypes;
+ }
+
+ /**
+ * Returns the location of the specified binary.
*
- * @return array The revision range, or empty if there is no straight
- * line path between the revisions.
+ * @param string $binary An external program name.
+ *
+ * @return boolean|string The location of the external program or false
+ * if it wasn't specified.
+ */
+ public function getPath($binary)
+ {
+ if (isset($this->_paths[$binary])) {
+ return $this->_paths[$binary];
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse the users file, if present in the sourceroot, and return
+ * a hash containing the requisite information, keyed on the
+ * username, and with the 'desc', 'name', and 'mail' values inside.
+ *
+ * @return boolean|array False if the file is not present, otherwise
+ * $this->_users populated with the data
+ */
+ public function getUsers($usersfile)
+ {
+ /* Check that we haven't already parsed users. */
+ if (!is_null($this->_users)) {
+ return $this->_users;
+ }
+
+ if (!@is_file($usersfile) ||
+ !($fl = @fopen($usersfile, VC_WINDOWS ? 'rb' : 'r'))) {
+ return false;
+ }
+
+ $this->_users = array();
+
+ /* Discard the first line, since it'll be the header info. */
+ fgets($fl, 4096);
+
+ /* Parse the rest of the lines into a hash, keyed on
+ * username. */
+ while ($line = fgets($fl, 4096)) {
+ if (preg_match('/^\s*$/', $line) ||
+ !preg_match('/^(\w+)\s+(.+)\s+([\w\.\-\_]+@[\w\.\-\_]+)\s+(.*)$/', $line, $regs)) {
+ continue;
+ }
+
+ $this->_users[$regs[1]] = array(
+ 'name' => trim($regs[2]),
+ 'mail' => trim($regs[3]),
+ 'desc' => trim($regs[4])
+ );
+ }
+
+ return $this->_users;
+ }
+
+ /**
+ * TODO
+ *
+ * $opts:
+ * 'quicklog' - (boolean)
+ * 'showAttic' - (boolean)
+ */
+ public function getDirObject($where, $opts = array())
+ {
+ $class = 'Horde_Vcs_Directory_' . $this->_driver;
+ return new $class($this, $where, $opts);
+ }
+
+ /**
+ * Function which returns a file pointing to the head of the requested
+ * revision of a file.
+ *
+ * @param string $fullname Fully qualified pathname of the desired file
+ * to checkout.
+ * @param string $rev Revision number to check out.
+ *
+ * @return resource A stream pointer to the head of the checkout.
+ */
+ public function checkout($fullname, $rev)
+ {
+ return null;
+ }
+
+ /**
+ * TODO
+ *
+ * $opts:
+ * 'quicklog' - (boolean)
+ * 'branch' - (string)
*/
- public function getRevisionRange($rep, $file, $r1, $r2)
+ public function getFileObject($filename, $opts = array())
{
- if ($rev->cmp($r1, $r2) == 1) {
- $curr = $rev->prev($r1);
- $stop = $rev->prev($r2);
- $flip = true;
- } else {
- $curr = $r2;
- $stop = $r1;
- $flip = false;
+ $class = 'Horde_Vcs_File_' . $this->_driver;
+
+ sort($opts);
+ $cacheId = implode('|', array($class, $this->sourceroot(), $filename, serialize($opts), $this->_cacheVersion));
+
+ if (!empty($this->_cache)) {
+ // TODO: Can't use filemtime() - Git bare repos contain no files
+ $ctime = time() - filemtime($filename);
+ if ($this->_cache->exists($cacheId, $ctime)) {
+ $ob = unserialize($this->_cache->get($cacheId, $ctime));
+ $ob->setRepository($this);
+ return $ob;
+ }
+ }
+
+ $ob = new $class($this, $filename, $opts);
+ $ob->applySort(self::SORT_AGE);
+
+ if (!empty($this->_cache)) {
+ $this->_cache->set($cacheId, serialize($ob));
}
- $ret_array = array();
+ return $ob;
+ }
+
+ /**
+ *
+ */
+ public function getLogObject($fl, $rev)
+ {
+ $class = 'Horde_Vcs_Log_' . $this->_driver;
+
+ if (!is_null($rev) && !empty($this->_cache)) {
+ $cacheId = implode('|', array($class, $this->sourceroot(), $fl->queryPath(), $rev, $this->_cacheVersion));
- do {
- $ret_array[] = $curr;
- $curr = $rev->prev($curr);
- if ($curr == $stop) {
- return ($flip) ? array_reverse($ret_array) : $ret_array;
+ // Individual revisions can be cached forever
+ if ($this->_cache->exists($cacheId, 0)) {
+ $ob = unserialize($this->_cache->get($cacheId, 0));
+ $ob->setRepository($this);
+ return $ob;
}
- } while ($rev->cmp($curr, $stop) != -1);
+ }
+
+ $ob = new $class($this, $fl, $rev);
+
+ if (!is_null($rev) && !empty($this->_cache)) {
+ $this->_cache->set($cacheId, serialize($ob));
+ }
+
+ return $ob;
+ }
+
+ /**
+ * TODO
+ */
+ public function getPatchsetObject($filename)
+ {
+ $class = 'Horde_Vcs_Patchset_' . $this->_driver;
+
+ $cacheId = implode('|', array($class, $this->sourceroot(), $filename, $this->_cacheVersion));
+
+ if (!empty($this->_cache)) {
+ // TODO: Can't use filemtime() - Git bare repos contain no files
+ $ctime = time() - filemtime($filename);
+ if ($this->_cache->exists($cacheId, $ctime)) {
+ return unserialize($this->_cache->get($cacheId, $ctime));
+ }
+ }
+
+ $ob = new $class($this, $filename);
+
+ if (!empty($this->_cache)) {
+ $this->_cache->set($cacheId, serialize($ob));
+ }
+ return $ob;
+ }
+
+ /**
+ * TODO
+ */
+ public function annotate($fileob, $rev)
+ {
return array();
}
/**
- * Return the list of available diff types.
+ * Returns an abbreviated form of the revision, for display.
*
- * @return array The list of available diff types for use with get().
+ * @param string $rev The revision string.
+ *
+ * @return string The abbreviated string.
*/
- public function availableDiffTypes()
+ public function abbrev($rev)
{
- return $this->_diffTypes;
+ return $rev;
}
+
}
/**
+ * Horde_Vcs_Cvs directory class.
+ *
* @package Horde_Vcs
*/
abstract class Horde_Vcs_Directory
{
+ /**
+ * @var Horde_Vcs
+ */
protected $_rep;
+
+ /**
+ * @var string
+ */
protected $_dirName;
- protected $_files;
- protected $_atticFiles;
- protected $_mergedFiles;
- protected $_dirs;
- protected $_parent;
+
+ /**
+ * @var array
+ */
+ protected $_files = array();
+
+ /**
+ * @var array
+ */
+ protected $_atticFiles = array();
+
+ /**
+ * @var array
+ */
+ protected $_mergedFiles = array();
+
+ /**
+ * @var string
+ */
+ protected $_dirs = array();
+
+ /**
+ * @var string
+ */
protected $_moduleName;
/**
* Create a Directory object to store information about the files in a
- * single directory in the repository
+ * single directory in the repository.
*
- * @param Horde_Vcs $rp The Repository object this directory
- * is part of.
- * @param string $dn Path to the directory.
- * @param Horde_Vcs_Directory $pn The parent Directory object to this one.
+ * @param Horde_Vcs $rep The Repository object this directory is part of.
+ * @param string $dn Path to the directory.
+ * @param array $opts TODO
*/
- public function __construct($rep, $dn, $pn = '')
+ public function __construct($rep, $dn, $opts = array())
{
$this->_rep = $rep;
- $this->_parent = $pn;
$this->_moduleName = $dn;
$this->_dirName = '/' . $dn;
- $this->_dirs = $this->_files = array();
}
/**
- * Return fully qualified pathname to this directory with no
- * trailing /.
+ * Return fully qualified pathname to this directory with no trailing /.
*
- * @return Pathname of this directory
+ * @return string Pathname of this directory.
*/
public function queryDir()
{
}
/**
- * TODO
- */
- abstract public function browseDir($cache = null, $quicklog = true,
- $showattic = false);
-
- /**
* Sort the contents of the directory in a given fashion and
* order.
*
- * @param integer $how Of the form SORT_* where * can be:
+ * @param integer $how Of the form Horde_Vcs::SORT_[*] where * can be:
* NONE, NAME, AGE, REV for sorting by name, age or
* revision.
- * @param integer $dir Of the form SORT_* where * can be:
+ * @param integer $dir Of the form Horde_Vcs::SORT_[*] where * can be:
* ASCENDING, DESCENDING for the order of the sort.
*/
public function applySort($how = Horde_Vcs::SORT_NONE,
{
switch ($how) {
case Horde_Vcs::SORT_AGE:
- usort($fileList, array($this, 'fileAgeSort'));
+ usort($fileList, array($this, '_fileAgeSort'));
break;
case Horde_Vcs::SORT_NAME:
- usort($fileList, array($this, 'fileNameSort'));
+ usort($fileList, array($this, '_fileNameSort'));
break;
case Horde_Vcs::SORT_AUTHOR:
- usort($fileList, array($this, 'fileAuthorSort'));
+ usort($fileList, array($this, '_fileAuthorSort'));
break;
case Horde_Vcs::SORT_REV:
- usort($fileList, array($this, 'fileRevSort'));
+ usort($fileList, array($this, '_fileRevSort'));
break;
case Horde_Vcs::SORT_NONE:
break;
}
}
+
/**
* Sort function for ascending age.
*/
- public function fileAgeSort($a, $b)
+ public function _fileAgeSort($a, $b)
{
$aa = $a->queryLastLog();
$bb = $b->queryLastLog();
/**
* Sort function by author name.
*/
- public function fileAuthorSort($a, $b)
+ public function _fileAuthorSort($a, $b)
{
$aa = $a->queryLastLog();
$bb = $b->queryLastLog();
/**
* Sort function for ascending filename.
*/
- public function fileNameSort($a, $b)
+ public function _fileNameSort($a, $b)
{
- return strcasecmp($a->name, $b->name);
+ return strcasecmp($a->queryName(), $b->queryName());
}
/**
* Sort function for ascending revision.
*/
- public function fileRevSort($a, $b)
+ public function _fileRevSort($a, $b)
{
return $this->_rep->cmp($a->queryHead(), $b->queryHead());
}
}
/**
+ * Horde_Vcs file class.
+ *
* @package Horde_Vcs
*/
-class Horde_Vcs_File
+abstract class Horde_Vcs_File
{
- public $rep;
- public $dir;
- public $name;
- public $logs = array();
- public $revs = array();
- public $head;
- public $quicklog;
- public $symrev = array();
- public $revsym = array();
- public $branches = array();
+ /**
+ * TODO
+ */
+ protected $_dir;
+
+ /**
+ * TODO
+ */
+ protected $_name;
+
+ /**
+ * TODO
+ */
+ protected $_logs = array();
+
+ /**
+ * TODO
+ */
+ protected $_revs = array();
+
+ /**
+ * TODO
+ */
+ protected $_rep;
+
+ /**
+ * TODO
+ */
+ protected $_symrev = array();
+
+ /**
+ * TODO
+ */
+ protected $_branches = array();
+
+ /**
+ * TODO
+ */
+ protected $_quicklog;
+
+ /**
+ * TODO
+ */
+ protected $_branch;
+
+ /**
+ * TODO
+ */
+ protected $_head = null;
+
+ /**
+ * Create a repository file object, and give it information about
+ * what its parent directory and repository objects are.
+ *
+ * @param TODO $rep TODO
+ * @param string $fl Full path to this file.
+ * @param array $opts TODO
+ */
+ public function __construct($rep, $fl, $opts = array())
+ {
+ $this->_rep = $rep;
+ $this->_name = basename($fl);
+ $this->_dir = dirname($fl);
+ $this->_quicklog = !empty($opts['quicklog']);
+ if (!empty($opts['branch'])) {
+ $this->_branch = $opts['branch'];
+ }
+ }
/**
* TODO
*/
public function setRepository($rep)
{
- $this->rep = $rep;
+ $this->_rep = $rep;
}
/**
*/
function queryName()
{
- return $this->name;
+ return $this->_name;
}
/**
*/
public function queryRepositoryName()
{
- return $this->name;
+ return $this->_name;
}
/**
- * Return the last revision of the current file on the HEAD branch
+ * Return the last revision of the current file on the HEAD branch.
*
- * @return Last revision of the current file
+ * @return string Last revision of the current file.
+ * @throws Horde_Vcs_Exception
*/
public function queryRevision()
{
- if (!isset($this->revs[0])) {
+ if (!isset($this->_revs[0])) {
throw new Horde_Vcs_Exception('No revisions');
}
- return $this->revs[0];
+ return $this->_revs[0];
}
/**
*/
public function queryPreviousRevision($rev)
{
- $key = array_search($rev, $this->revs);
- return (($key !== false) && isset($this->revs[$key + 1]))
- ? $this->revs[$key + 1]
+ $key = array_search($rev, $this->_revs);
+ return (($key !== false) && isset($this->_revs[$key + 1]))
+ ? $this->_revs[$key + 1]
: false;
}
/**
* Return the HEAD (most recent) revision number for this file.
*
- * @return HEAD revision number
+ * @return string HEAD revision string.
*/
public function queryHead()
{
- return $this->queryRevision();
+ return is_null($this->_head) ? $this->queryRevision() : $this->_head;
}
/**
* Return the last Horde_Vcs_Log object in the file.
*
- * @return Horde_Vcs_Log of the last entry in the file
+ * @return Horde_Vcs_Log Log object of the last entry in the file.
+ * @throws Horde_Vcs_Exception
*/
public function queryLastLog()
{
- if (!isset($this->revs[0]) || !isset($this->logs[$this->revs[0]])) {
+ if (!isset($this->_revs[0]) || !isset($this->_logs[$this->_revs[0]])) {
throw new Horde_Vcs_Exception('No revisions');
}
- return $this->logs[$this->revs[0]];
+ return $this->_logs[$this->_revs[0]];
}
/**
break;
}
- uasort($this->logs, array($this, 'sortBy' . $func));
+ uasort($this->_logs, array($this, 'sortBy' . $func));
return true;
}
*/
public function sortByRevision($a, $b)
{
- return $this->rep->cmp($b->rev, $a->rev);
+ return $this->_rep->cmp($b->queryRevision(), $a->queryRevision());
}
public function sortByAge($a, $b)
{
- return $b->date - $a->date;
+ return $b->queryDate() - $a->queryDate();
}
public function sortByName($a, $b)
{
- return strcmp($a->author, $b->author);
+ return strcmp($a->queryAuthor(), $b->queryAuthor());
}
/**
* Return the fully qualified filename of this object.
*
- * @return Fully qualified filename of this object
+ * @return string Fully qualified filename of this object.
*/
public function queryFullPath()
{
- return $this->rep->sourceroot() . '/' . $this->queryModulePath();
+ return $this->_rep->sourceroot() . '/' . $this->queryModulePath();
}
/**
- * Return the name of this file relative to its sourceroot.
+ * Return the filename relative to its sourceroot.
*
* @return string Pathname relative to the sourceroot.
*/
public function queryModulePath()
{
- return $this->dir . '/' . $this->name;
+ return $this->_dir . '/' . $this->_name;
+ }
+
+ /**
+ * Return the "base" filename (i.e. the filename needed by the various
+ * command line utilities).
+ *
+ * @return string A filename.
+ */
+ public function queryPath()
+ {
+ return $this->queryFullPath();
+ }
+
+ /**
+ * TODO
+ */
+ public function queryBranches()
+ {
+ return $this->_branches;
+ }
+
+ /**
+ * TODO
+ */
+ public function queryLogs($rev = null)
+ {
+ return is_null($rev) ? $this->_logs : (isset($this->_logs[$rev]) ? $this->_logs[$rev] : null);
+ }
+
+ /**
+ * TODO
+ */
+ public function revisionCount()
+ {
+ return count($this->_revs);
+ }
+
+ /**
+ * TODO
+ */
+ public function querySymbolicRevisions()
+ {
+ return $this->_symrev;
}
}
*
* @package Horde_Vcs
*/
-class Horde_Vcs_Log
+abstract class Horde_Vcs_Log
{
- public $rep;
- public $file;
- public $tags;
- public $rev;
- public $date;
- public $log;
- public $author;
- public $state;
- public $lines;
- public $branches = array();
+ protected $_rep;
+ protected $_file;
+ protected $_rev;
+ protected $_author;
+ protected $_tags = array();
+ protected $_date;
+ protected $_log;
+ protected $_state;
+ protected $_lines = '';
+ protected $_branches = array();
/**
* Constructor.
*/
- public function __construct($fl)
+ public function __construct($rep, $fl, $rev)
{
- $this->file = $fl;
- $this->rep = $fl->rep;
+ $this->_rep = $rep;
+ $this->_file = $fl;
+ $this->_rev = $rev;
}
+ /**
+ * TODO
+ */
+ public function setRepository($rep)
+ {
+ $this->_rep = $rep;
+ }
+
+ /**
+ * TODO
+ */
public function queryDate()
{
- return $this->date;
+ return $this->_date;
}
+ /**
+ * TODO
+ */
public function queryRevision()
{
- return $this->rev;
+ return $this->_rev;
}
+ /**
+ * TODO
+ */
public function queryAuthor()
{
- return $this->author;
+ return $this->_author;
}
+ /**
+ * TODO
+ */
public function queryLog()
{
- return $this->log;
+ return $this->_log;
}
+ /**
+ * TODO
+ */
public function queryBranch()
{
return array();
}
+ /**
+ * TODO
+ */
public function queryChangedLines()
{
- return isset($this->lines) ? $this->lines : '';
+ return $this->_lines;
+ }
+
+ /**
+ * TODO
+ */
+ public function queryTags()
+ {
+ return $this->_tags;
}
/**
public function querySymbolicBranches()
{
$symBranches = array();
+ $branches = $this->_file->queryBranches();
- foreach ($this->branches as $branch) {
- $key = array_search($branch, $this->file->branches);
- if ($key !== false) {
+ foreach ($this->_branches as $branch) {
+ $key = array_search($branch, $branches);
+ if (($key = array_search($branch, $branches)) !== false) {
$symBranches[$key] = $branch;
}
}
*/
abstract class Horde_Vcs_Patchset
{
- protected $_rep;
- public $_patchsets = array();
- protected $_file;
- protected $_cache;
- protected $_ctime = 3600;
+ /**
+ * @var array
+ */
+ protected $_patchsets = array();
/**
- * Create a patchset object.
+ * Constructor
*
- * @param string $file The filename to get patchsets for.
+ * @param Horde_Vcs $rep A Horde_Vcs repository object.
+ * @param string $file The filename to create patchsets for.
*/
- public function __construct($rep, $file, $cache = null)
- {
- $this->_rep = $rep;
- $this->_file = $file;
- $this->_cache = $cache;
- }
+ abstract public function __construct($rep, $file);
- public function &getPatchsetObject()
+ /**
+ * TODO
+ */
+ public function getPatchsets()
{
- /* The version of the cached data. Increment this whenever the
- * internal storage format changes, such that we must
- * invalidate prior cached data. */
- if ($this->_cache) {
- $cacheVersion = 1;
- $cacheId = $this->_rep->sourceroot() . '_n' . $this->_file . '_f_v' . $cacheVersion;
- }
-
- if ($this->_cache &&
- $this->_cache->exists($cacheId, $this->_ctime)) {
- $psOb = unserialize($this->_cache->get($cacheId, $this->_ctime));
- $psOb->setRepository($this->_rep);
- } else {
- $class_name = get_class($this);
- $psOb = new $class_name($this->_rep, $this->_file, $this->_cache);
- $psOb->setRepository($this->_rep);
- if (is_a(($result = $psOb->getPatchsets()), 'PEAR_Error')) {
- return $result;
- }
-
- if ($this->_cache) {
- $this->_cache->set($cacheId, serialize($psOb));
- }
- }
-
- return $psOb;
+ return $this->_patchsets;
}
- abstract public function getPatchsets();
-
- public function setRepository($rep)
- {
- $this->_rep = $rep;
- }
}
* <pre>
* 'sourceroot': The source root for this repository
* 'paths': Hash with the locations of all necessary binaries: 'rcsdiff',
- * 'rlog', 'cvsps', 'cvsps_home' and the temp path: 'temp'
+ * 'rlog', 'cvsps', 'cvsps_home', and 'temp' (the temp path).
* </pre>
*
* Copyright 2000-2009 The Horde Project (http://www.horde.org/)
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Cvs extends Horde_Vcs_Rcs
{
/**
+ * Does driver support patchsets?
+ *
+ * @var boolean
+ */
+ protected $_patchsets = true;
+
+ /**
* Does driver support deleted files?
*
* @var boolean
}
/**
+ * Obtain the differences between two revisions of a file.
+ *
+ * @param Horde_Vcs_File $file The desired file.
+ * @param string $rev1 Original revision number to compare from.
+ * @param string $rev2 New revision number to compare against.
+ * @param array $opts The following optional options:
+ * <pre>
+ * 'num' - (integer) DEFAULT: 3
+ * 'type' - (string) DEFAULT: 'unified'
+ * 'ws' - (boolean) DEFAULT: true
+ * </pre>
+ *
+ * @return string|boolean False on failure, or a string containing the
+ * diff on success.
+ */
+ protected function _diff($file, $rev1, $rev2, $opts)
+ {
+ $fullName = $file->queryFullPath();
+ $diff = array();
+ $flags = '-kk ';
+
+ if (!$opts['ws']) {
+ $flags .= ' -bB ';
+ }
+
+ switch ($opts['type']) {
+ case 'context':
+ $flags .= '-p --context=' . (int)$opts['num'];
+ break;
+
+ case 'unified':
+ $flags .= '-p --unified=' . (int)$opts['num'];
+ break;
+
+ case 'column':
+ $flags .= '--side-by-side --width=120';
+ break;
+
+ case 'ed':
+ $flags .= '-e';
+ break;
+ }
+
+ // Windows versions of cvs always return $where with forwards slashes.
+ if (VC_WINDOWS) {
+ $fullName = str_replace(DIRECTORY_SEPARATOR, '/', $fullName);
+ }
+
+ // TODO: add options for $hr options - however these may not be
+ // compatible with some diffs.
+ $command = $this->getPath('rcsdiff') . " $flags -r" . escapeshellarg($rev1) . ' -r' . escapeshellarg($rev2) . ' ' . escapeshellarg($fullName) . ' 2>&1';
+ if (VC_WINDOWS) {
+ $command .= ' < "' . __FILE__ . '"';
+ }
+
+ exec($command, $diff, $retval);
+ return ($retval > 0) ? $diff : array();
+ }
+
+ /**
* TODO
*/
public function getFileObject($filename, $opts = array())
/**
* TODO
*/
- public function getPatchsetObject($filename, $cache = null)
- {
- return parent::getPatchsetObject($this->sourceroot() . '/' . $filename, $cache);
- }
-
- /**
- * TODO
- */
public function annotate($fileob, $rev)
{
$this->assertValidRevision($rev);
*/
public function checkout($fullname, $rev)
{
- $rep->assertValidRevision($rev);
+ $this->assertValidRevision($rev);
if (!($RCS = popen($this->getPath('co') . ' ' . escapeshellarg('-p' . $rev) . ' ' . escapeshellarg($fullname) . " 2>&1", VC_WINDOWS ? 'rb' : 'r'))) {
throw new Horde_Vcs_Exception('Couldn\'t perform checkout of the requested file');
}
/**
- * Horde_Vcs_Cvs diff class.
- *
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
- * @author Anil Madhavapeddy <anil@recoil.org>
- * @package Horde_Vcs
- */
-class Horde_Vcs_Diff_Cvs extends Horde_Vcs_Diff
-{
- /**
- * Obtain the differences between two revisions of a file.
- *
- * @param Horde_Vcs $rep A repository object.
- * @param Horde_Vcs_File $file The desired file.
- * @param string $rev1 Original revision number to compare from.
- * @param string $rev2 New revision number to compare against.
- * @param string $type The type of diff (e.g. 'unified').
- * @param integer $num Number of lines to be used in context and
- * unified diffs.
- * @param boolean $ws Show whitespace in the diff?
- *
- * @return string|boolean False on failure, or a string containing the
- * diff on success.
- */
- public function get($rep, $file, $rev1, $rev2, $type = 'context',
- $num = 3, $ws = true)
- {
- /* Check that the revision numbers are valid. */
- $rev1 = $rep->isValidRevision($rev1) ? $rev1 : '1.1';
- $rev2 = $rep->isValidRevision($rev1) ? $rev2 : '1.1';
-
- $fullName = $file->queryFullPath();
- $diff = array();
- $options = '-kk ';
- if (!$ws) {
- $opts = ' -bB ';
- $options .= $opts;
- } else {
- $opts = '';
- }
-
- switch ($type) {
- case 'context':
- $options = $opts . '-p --context=' . (int)$num;
- break;
-
- case 'unified':
- $options = $opts . '-p --unified=' . (int)$num;
- break;
-
- case 'column':
- $options = $opts . '--side-by-side --width=120';
- break;
-
- case 'ed':
- $options = $opts . '-e';
- break;
- }
-
- // Windows versions of cvs always return $where with forwards slashes.
- if (VC_WINDOWS) {
- $fullName = str_replace(DIRECTORY_SEPARATOR, '/', $fullName);
- }
-
- // TODO: add options for $hr options - however these may not be
- // compatible with some diffs.
- $command = $rep->getPath('rcsdiff') . " $options -r$rev1 -r$rev2 \"" . escapeshellcmd($fullName) . '" 2>&1';
- if (VC_WINDOWS) {
- $command .= ' < "' . __FILE__ . '"';
- }
-
- exec($command, $diff, $retval);
- return ($retval > 0) ? $diff : array();
- }
-
-}
-
-/**
* Horde_Vcs_Cvs directory class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Directory_Cvs extends Horde_Vcs_Directory
{
/**
- * Creates a CVS Directory object to store information
- * about the files in a single directory in the repository.
+ * Create a Directory object to store information about the files in a
+ * single directory in the repository
*
- * @param Horde_Vcs $rep A repository object
- * @param string $dn Path to the directory.
- * @param Horde_Vcs_Directory $pn The parent Directory object to this one.
+ * @param Horde_Vcs $rep The Repository object this directory is part of.
+ * @param string $dn Path to the directory.
+ * @param array $opts TODO
*/
- public function __construct($rep, $dn, $pn = '')
+ public function __construct($rep, $dn, $opts = array())
{
- parent::__construct($rep, $dn, $pn);
- $this->_dirName = $rep->sourceroot() . "/$dn";
- }
+ parent::__construct($rep, $dn, $opts);
+ $this->_dirName = $rep->sourceroot() . '/' . $dn;
- /**
- * Tell the object to open and browse its current directory, and
- * retrieve a list of all the objects in there. It then populates
- * the file/directory stack and makes it available for retrieval.
- *
- * @return boolean True on success.
- */
- public function browseDir($cache = null, $quicklog = true,
- $showattic = false)
- {
/* Make sure we are trying to list a directory */
if (!@is_dir($this->_dirName)) {
- throw new Horde_Vcs_Exception('Unable to find directory ' . $this->_dirName);
+ throw new Horde_Vcs_Exception('Unable to find directory: ' . $this->_dirName);
}
/* Open the directory for reading its contents */
}
} elseif (@is_file($path) && (substr($name, -2) == ',v')) {
/* Spawn a new file object to represent this file. */
- $this->_files[] = $this->_rep->getFileObject(substr($path, strlen($this->_rep->sourceroot()), -2), array('cache' => $cache, 'quicklog' => $quicklog));
+ $this->_files[] = $rep->getFileObject(substr($path, strlen($rep->sourceroot()), -2), array('quicklog' => !empty($opts['quicklog'])));
}
}
closedir($DIR);
/* If we want to merge the attic, add it in here. */
- if ($showattic) {
+ if (!empty($opts['showattic'])) {
try {
- $atticDir = new Horde_Vcs_Directory_Cvs($this->_rep, $this->_moduleName . '/Attic', $this);
+ $atticDir = new Horde_Vcs_Directory_Cvs($rep, $this->_moduleName . '/Attic', $opts, $this);
$this->_atticFiles = $atticDir->queryFileList();
$this->_mergedFiles = array_merge($this->_files, $this->_atticFiles);
} catch (Horde_Vcs_Exception $e) {}
/**
* Horde_Vcs_Cvs file class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_File_Cvs extends Horde_Vcs_File
{
- /* @TODO */
- public $filename;
- protected $_branch = '';
+ /**
+ * TODO
+ */
+ public $accum;
+
+ /**
+ * TODO
+ */
+ protected $_revsym = array();
/**
* Create a repository file object, and give it information about
*/
public function __construct($rep, $fl, $opts = array())
{
- $this->rep = $rep;
- $this->name = basename($fl);
- $this->dir = dirname($fl);
- $this->filename = $fl;
- $this->quicklog = !empty($opts['quicklog']);
- if (!empty($opts['branch'])) {
- $this->_branch = $opts['branch'];
- }
+ parent::__construct($rep, $fl, $opts);
/* Check that we are actually in the filesystem. */
$file = $this->queryFullPath();
throw new Horde_Vcs_Exception('File Not Found: ' . $file);
}
- /* Call the RCS rlog command to retrieve the file
- * information. */
- $flag = $this->quicklog ? ' -r ' : ' ';
-
- $cmd = $this->rep->getPath('rlog') . $flag . escapeshellarg($file);
- exec($cmd, $return_array, $retval);
+ $ret_array = array();
+ $cmd = $rep->getPath('rlog') . ($this->_quicklog ? ' -r' : '') . ' ' . escapeshellarg($file);
+ exec($cmd, $ret_array, $retval);
if ($retval) {
throw new Horde_Vcs_Exception('Failed to spawn rlog to retrieve file log information for ' . $file);
$accum = $revsym = $symrev = array();
$state = 'init';
- foreach ($return_array as $line) {
+ foreach ($ret_array as $line) {
switch ($state) {
case 'init':
if (!strncmp('head: ', $line, 6)) {
- $this->head = substr($line, 6);
- $this->branches['HEAD'] = $this->head;
+ $this->_head = $this->_branches['HEAD'] = substr($line, 6);
} elseif (!strncmp('branch:', $line, 7)) {
$state = 'rev';
}
case 'rev':
if (!strncmp('----------', $line, 10)) {
$state = 'info';
- $this->symrev = $symrev;
- $this->revsym = $revsym;
+ $this->_symrev = $symrev;
+ $this->_revsym = $revsym;
} elseif (preg_match("/^\s+([^:]+):\s+([\d\.]+)/", $line, $regs)) {
// Check to see if this is a branch
if (preg_match('/^(\d+(\.\d+)+)\.0\.(\d+)$/', $regs[2])) {
$branchRev = $this->toBranch($regs[2]);
- $this->branches[$regs[1]] = $branchRev;
+ $this->_branches[$regs[1]] = $branchRev;
} else {
$symrev[$regs[1]] = $regs[2];
if (empty($revsym[$regs[2]])) {
strcmp('----------------------------', $line)) {
$accum[] = $line;
} elseif (count($accum)) {
- // Spawn a new Horde_Vcs_Log object and add it to the logs
- // hash.
- $log = new Horde_Vcs_Log_Cvs($this);
- $err = $log->processLog($accum);
+ $this->accum = $accum;
+ $log = $rep->getLogObject($this, null);
$rev = $log->queryRevision();
$branch = $log->queryBranch();
if (empty($this->_branch) ||
in_array($this->_branch, $log->queryBranch()) ||
- (($this->rep->cmp($rev, $this->branches[$this->_branch]) === -1) &&
+ (($rep->cmp($rev, $this->_branches[$this->_branch]) === -1) &&
(empty($branch) ||
in_array('HEAD', $branch) ||
- (strpos($this->branches[$this->_branch], $rev) === 0)))) {
+ (strpos($this->_branches[$this->_branch], $rev) === 0)))) {
$log->setBranch($branch);
- $this->logs[$rev] = $log;
- $this->revs[] = $rev;
+ $this->_logs[$rev] = $log;
+ $this->_revs[] = $rev;
}
$accum = array();
}
*/
public function isDeleted()
{
- return (substr($this->dir, -5) == 'Attic');
+ return (substr($this->_dir, -5) == 'Attic');
}
/**
*/
public function queryName()
{
- return preg_replace('/,v$/', '', $this->name);
- }
-
- /**
- * Return the HEAD (most recent) revision number for this file.
- *
- * @return string HEAD revision number
- */
- public function queryHead()
- {
- return $this->head;
+ return preg_replace('/,v$/', '', $this->_name);
}
/**
*/
public function queryFullPath()
{
- return $this->dir . '/' . $this->name;
+ return parent::queryModulePath();
}
/**
*/
public function queryModulePath()
{
- return preg_replace('|^'. $this->rep->sourceroot() . '/?(.*),v$|', '\1', $this->queryFullPath());
+ return preg_replace('|^'. $this->_rep->sourceroot() . '/?(.*),v$|', '\1', $this->queryFullPath());
}
/**
public function toBranch($rev)
{
/* Check if we have a valid revision number */
- if (!$this->rep->isValidRevision($rev) ||
+ if (!$this->_rep->isValidRevision($rev) ||
(($end = strrpos($rev, '.')) === false)) {
return false;
}
*/
}
+ /**
+ * TODO
+ */
+ public function queryRevsym($rev)
+ {
+ return isset($this->_revsym[$rev])
+ ? $this->_revsym[$rev]
+ : array();
+ }
+
}
/**
* Horde_Vcs_cvs Log class.
*
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Log_Cvs extends Horde_Vcs_Log
{
- /* Cached branch info. */
+ /**
+ * Cached branch info.
+ *
+ * @var string
+ */
protected $_branch;
- public function processLog($raw)
+ /**
+ * Constructor.
+ */
+ public function __construct($rep, $fl, $rev)
{
+ parent::__construct($rep, $fl, $rev);
+
+ $raw = $fl->accum;
+
/* Initialise a simple state machine to parse the output of rlog */
$state = 'init';
while (!empty($raw) && $state != 'done') {
case 'init':
$line = array_shift($raw);
if (preg_match("/revision (.+)$/", $line, $parts)) {
- $this->rev = $parts[1];
+ $this->_rev = $parts[1];
$state = 'date';
}
break;
case 'date':
$line = array_shift($raw);
if (preg_match("|^date:\s+(\d+)[-/](\d+)[-/](\d+)\s+(\d+):(\d+):(\d+).*?;\s+author:\s+(.+);\s+state:\s+(\S+);(\s+lines:\s+([0-9\s+-]+))?|", $line, $parts)) {
- $this->date = gmmktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
- $this->author = $parts[7];
- $this->state = $parts[8];
- $this->lines = isset($parts[10]) ? $parts[10] : '';
+ $this->_date = gmmktime($parts[4], $parts[5], $parts[6], $parts[2], $parts[3], $parts[1]);
+ $this->_author = $parts[7];
+ $this->_state = $parts[8];
+ $this->_lines = isset($parts[10]) ? $parts[10] : '';
$state = 'branches';
}
break;
* push valid revisions into the branches array */
$brs = preg_split('/;\s*/', $br[1]);
foreach ($brs as $brpoint) {
- if ($this->rep->isValidRevision($brpoint)) {
- $this->branches[] = $brpoint;
+ if ($rep->isValidRevision($brpoint)) {
+ $this->_branches[] = $brpoint;
}
}
array_shift($raw);
}
/* Assume the rest of the lines are the log message */
- $this->log = implode("\n", $raw);
- $this->tags = isset($this->file->revsym[$this->rev]) ?
- $this->file->revsym[$this->rev] :
- array();
+ $this->_log = implode("\n", $raw);
+ $this->_tags = $fl->queryRevsym($this->_rev);
}
+ /**
+ * TODO
+ */
public function setBranch($branch)
{
$this->_branch = $branch;
}
+ /**
+ * TODO
+ */
public function queryBranch()
{
if (!empty($this->_branch)) {
return $this->_branch;
}
- $key = array_keys($this->file->branches, $this->rev);
+ $branches = $this->_file->queryBranches();
+ $key = array_keys($branches, $this->_rev);
return empty($key)
- ? array_keys($this->file->branches, $this->rep->strip($this->rev, 1))
+ ? array_keys($branches, $this->_rep->strip($this->_rev, 1))
: $key;
}
/**
* Horde_Vcs_Cvs Patchset class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Patchset_Cvs extends Horde_Vcs_Patchset
{
- protected $_dir;
- protected $_name;
-
/**
- * Create a patchset object.
+ * Constructor
*
- * @param string $file The filename to get patchsets for.
+ * @param Horde_Vcs $rep A Horde_Vcs repository object.
+ * @param string $file The filename to create a patchset for.
*/
- public function __construct($rep, $file, $cache = null)
+ public function __construct($rep, $file)
{
- $this->_name = basename($file);
- $this->_dir = dirname($file);
- $this->_ctime = time() - filemtime($file . ',v');
+ $file = $rep->sourceroot() . '/' . $file;
+ $name = basename($file);
+ $dir = dirname($file);
- parent::__construct($rep, $file, $cache);
- }
-
- /**
- * Populate the object with information about the patchsets that
- * this file is involved in.
- *
- * @return boolean True on success.
- */
- public function getPatchsets()
- {
/* Check that we are actually in the filesystem. */
- if (!is_file($this->getFullPath() . ',v')) {
+ if (!is_file($file . ',v')) {
throw new Horde_Vcs_Exception('File Not Found');
}
/* Call cvsps to retrieve all patchsets for this file. */
- $cvsps_home = $this->_rep->getPath('cvsps_home');
+ $cvsps_home = $rep->getPath('cvsps_home');
$HOME = !empty($cvsps_home) ?
'HOME=' . $cvsps_home . ' ' :
'';
- $cmd = $HOME . $this->_rep->getPath('cvsps') . ' -u --cvs-direct --root ' . escapeshellarg($this->_rep->sourceroot) . ' -f ' . escapeshellarg($this->_name) . ' ' . escapeshellarg($this->_dir);
- exec($cmd, $return_array, $retval);
+ $ret_array = array();
+ $cmd = $HOME . $rep->getPath('cvsps') . ' -u --cvs-direct --root ' . escapeshellarg($rep->sourceroot()) . ' -f ' . escapeshellarg($name) . ' ' . escapeshellarg($dir);
+ exec($cmd, $ret_array, $retval);
if ($retval) {
- throw new Horde_Vcs_Exception('Failed to spawn cvsps to retrieve patchset information');
+ throw new Horde_Vcs_Exception('Failed to spawn cvsps to retrieve patchset information.');
}
- $this->_patchsets = array();
$state = 'begin';
- foreach ($return_array as $line) {
+ foreach ($ret_array as $line) {
$line = trim($line);
if ($line == '---------------------') {
$state = 'begin';
return true;
}
- /**
- * Return the fully qualified filename of this object.
- *
- * @return string Fully qualified filename of this object
- */
- function getFullPath()
- {
- return $this->_dir . '/' . $this->_name;
- }
-
}
protected $_branches = true;
/**
+ * The available diff types.
+ *
+ * @var array
+ */
+ protected $_diffTypes = array('unified');
+
+ /**
* TODO
*/
public function isValidRevision($rev)
*/
public function getCommand()
{
- return $this->getPath('git') . ' --git-dir=' . escapeshellarg($this->_sourceroot);
+ return escapeshellcmd($this->getPath('git')) . ' --git-dir=' . escapeshellarg($this->_sourceroot);
}
/**
}
/**
- * Returns an abbreviated form of the revision, for display.
+ * Create a range of revisions between two revision numbers.
*
- * @param string $rev The revision string.
+ * @param Horde_Vcs_File $file The desired file.
+ * @param string $r1 The initial revision.
+ * @param string $r2 The ending revision.
*
- * @return string The abbreviated string.
+ * @return array The revision range, or empty if there is no straight
+ * line path between the revisions.
*/
- public function abbrev($rev)
+ public function getRevisionRange($file, $r1, $r2)
{
- return substr($rev, 0, 7) . '[...]';
+ $revs = $this->_getRevisionRange($file, $r1, $r2);
+ return empty($revs)
+ ? array_reverse($this->_getRevisionRange($file, $r2, $r1))
+ : $revs;
}
-}
-
-/**
- * Horde_Vcs_Git diff class.
- *
- * Copyright Chuck Hagenbuch <chuck@horde.org>
- *
- * @author Chuck Hagenbuch <chuck@horde.org>
- * @package Horde_Vcs
- */
-class Horde_Vcs_Diff_Git extends Horde_Vcs_Diff
-{
/**
- * The available diff types.
- *
- * @var array
+ * TODO
*/
- protected $_diffTypes = array('unified');
+ protected function _getRevisionRange($file, $r1, $r2)
+ {
+ $cmd = $this->getCommand() . ' rev-list ' . escapeshellarg($r1) . '..' . escapeshellarg($r2) . ' -- ' . escapeshellarg($file->queryModulePath());
+ $revs = array();
+
+ exec($cmd, $revs);
+ return array_map('trim', $revs);
+ }
/**
* Obtain the differences between two revisions of a file.
*
- * @param Horde_Vcs $rep A repository object.
* @param Horde_Vcs_File $file The desired file.
- * @param string $rev1 Original revision number to compare from.
- * @param string $rev2 New revision number to compare against.
- * @param string $type The type of diff (e.g. 'unified').
- * @param integer $num Number of lines to be used in context and
- * unified diffs.
- * @param boolean $ws Show whitespace in the diff?
+ * @param string $rev1 Original revision number to compare from.
+ * @param string $rev2 New revision number to compare against.
+ * @param array $opts The following optional options:
+ * <pre>
+ * 'num' - (integer) DEFAULT: 3
+ * 'type' - (string) DEFAULT: 'unified'
+ * 'ws' - (boolean) DEFAULT: true
+ * </pre>
*
* @return string|boolean False on failure, or a string containing the
* diff on success.
*/
- public function get($rep, $file, $rev1, $rev2, $type = 'context',
- $num = 3, $ws = true)
+ protected function _diff($file, $rev1, $rev2, $opts)
{
- /* Check that the revision numbers are valid */
- $rev1 = $rep->isValidRevision($rev1) ? $rev1 : 0;
- $rev2 = $rep->isValidRevision($rev1) ? $rev2 : 0;
-
$diff = array();
- $options = '';
- if (!$ws) {
- $options .= ' -b -w ';
+ $flags = '';
+
+ if (!$opts['ws']) {
+ $flags .= ' -b -w ';
}
- switch ($type) {
+ switch ($opts['type']) {
case 'unified':
- $options .= '--unified=' . (int)$num;
+ $flags .= '--unified=' . (int)$opts['num'];
break;
}
// @TODO: add options for $hr options - however these may not
// be compatible with some diffs.
- $command = $rep->getCommand() . " diff -M -C $options --no-color $rev1..$rev2 -- " . escapeshellarg($file->queryModulePath()) . ' 2>&1';
+ $command = $this->getCommand() . " diff -M -C $flags --no-color " . escapeshellarg($rev1 . '..' . $rev2) . ' -- ' . escapeshellarg($file->queryModulePath()) . ' 2>&1';
exec($command, $diff, $retval);
return $diff;
}
/**
- * Create a range of revisions between two revision numbers.
+ * Returns an abbreviated form of the revision, for display.
*
- * @param Horde_Vcs $rep A repository object.
- * @param Horde_Vcs_File $file The desired file.
- * @param string $r1 The initial revision.
- * @param string $r2 The ending revision.
+ * @param string $rev The revision string.
*
- * @return array The revision range, or empty if there is no straight
- * line path between the revisions.
+ * @return string The abbreviated string.
*/
- public function getRevisionRange($rep, $file, $r1, $r2)
+ public function abbrev($rev)
{
- $revs = $this->_getRevisionRange($rep, $file, $r1, $r2);
- if (empty($revs)) {
- $revs = array_reverse($this->_getRevisionRange($rep, $file, $r2, $r1));
- }
- return $revs;
+ return substr($rev, 0, 7) . '[...]';
}
- protected function _getRevisionRange($rep, $file, $r1, $r2)
- {
- $cmd = $rep->getCommand() . ' rev-list ' . escapeshellarg($r1) . '..' . escapeshellarg($r2) . ' -- ' . escapeshellarg($file->queryModulePath());
- $revs = array();
-
- exec($cmd, $revs);
- return array_map('trim', $revs);
- }
}
/**
* Horde_Vcs_Git directory class.
*
- * Copyright Chuck Hagenbuch <chuck@horde.org>
- *
* @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Directory_Git extends Horde_Vcs_Directory
{
/**
- * Tell the object to open and browse its current directory, and
- * retrieve a list of all the objects in there. It then populates
- * the file/directory stack and makes it available for retrieval.
+ * Create a Directory object to store information about the files in a
+ * single directory in the repository.
*
- * @return integer 1 on success.
+ * @param Horde_Vcs $rep The Repository object this directory is part of.
+ * @param string $dn Path to the directory.
+ * @param array $opts TODO
*/
- public function browseDir($cache = null, $quicklog = true,
- $showattic = false)
+ public function __construct($rep, $dn, $opts = array())
{
- // @TODO For now, we're browsing master
+ parent::__construct($rep, $dn, $opts);
+
+ // @TODO For now, we're browsing HEAD
//$head = trim(shell_exec($this->_rep->getCommand() . ' rev-parse --verify master'));
$head = 'HEAD';
// @TODO can use this to see if we have a valid cache of the tree at this revision
$dir .= '/';
}
- $cmd = $this->_rep->getCommand() . ' ls-tree --full-name ' . $head . ' ' . escapeshellarg($dir) . ' 2>&1';
+ $cmd = $rep->getCommand() . ' ls-tree --full-name ' . escapeshellarg($head) . ' ' . escapeshellarg($dir) . ' 2>&1';
$dir = popen($cmd, 'r');
if (!$dir) {
if ($type == 'tree') {
$this->_dirs[] = basename($file);
} else {
- $this->_files[] = $this->_rep->getFileObject($file, array('cache' => $cache, 'quicklog' => $quicklog));
+ $this->_files[] = $rep->getFileObject($file, array('quicklog' => !empty($opts['quicklog'])));
}
}
/**
* Horde_Vcs_Git file class.
*
- * Copyright Chuck Hagenbuch <chuck@horde.org>
- *
* @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_File_Git extends Horde_Vcs_File
{
- /* @TODO */
- protected $_branch;
- public $cache;
-
/**
* Create a repository file object, and give it information about
* what its parent directory and repository objects are.
*/
public function __construct($rep, $fl, $opts = array())
{
- $this->rep = $rep;
- $this->fullname = $fl;
- $this->name = basename($fl);
- $this->dir = dirname($fl);
- $this->cache = empty($opts['cache']) ? null : $opts['cache'];
- $this->quicklog = !empty($opts['quicklog']);
- if (!empty($opts['branch'])) {
- $this->_branch = $opts['branch'];
- }
+ parent::__construct($rep, $fl, $opts);
// Get the list of revisions that touch this path
- $this->revs = $this->_getRevList($this->_branch);
+ $this->_revs = $this->_getRevList($this->_branch);
- foreach ($this->revs as $rev) {
- $this->logs[$rev] = Horde_Vcs_Log_Git::factory($this, $rev);
- if ($this->quicklog) {
+ foreach ($this->_revs as $rev) {
+ $this->_logs[$rev] = $rep->getLogObject($this, $rev);
+ if ($this->_quicklog) {
break;
}
}
// Add branch information
- $cmd = $this->rep->getCommand() . ' show-ref --heads';
+ $cmd = $rep->getCommand() . ' show-ref --heads';
$branch_list = shell_exec($cmd);
if (empty($branch_list)) {
throw new Horde_Vcs_Exception('No branches found');
foreach (explode("\n", trim($branch_list)) as $val) {
$line = explode(' ', trim($val), 2);
- $this->branches[substr($line[1], strrpos($line[1], '/') + 1)] = $line[0];
+ $this->_branches[substr($line[1], strrpos($line[1], '/') + 1)] = $line[0];
}
}
*/
public function getHashForRevision($rev)
{
- return $this->logs[$rev]->getHashForPath($this->fullname);
+ return $this->_logs[$rev]->getHashForPath($this->queryModulePath());
}
/**
*/
public function queryModulePath()
{
- return ($this->dir == '.')
- ? $this->name
- : $this->dir . '/' . $this->name;
+ return ($this->_dir == '.')
+ ? $this->_name
+ : parent::queryModulePath();
}
/**
{
$revs = array();
- foreach (array_keys($this->branches) as $key) {
+ foreach (array_keys($this->_branches) as $key) {
$revs[$key] = $this->_getRevList($key);
}
*/
protected function _getRevList($branch)
{
- $cmd = $this->rep->getCommand() . ' rev-list ' . (empty($branch) ? '--branches' : $branch) . ' -- ' . escapeshellarg($this->fullname) . ' 2>&1';
+ $cmd = $this->_rep->getCommand() . ' rev-list ' . (empty($branch) ? '--branches' : $branch) . ' -- ' . escapeshellarg($this->queryModulePath()) . ' 2>&1';
$revisions = shell_exec($cmd);
if (substr($revisions, 5) == 'fatal') {
return explode("\n", trim($revisions));
}
+ /**
+ * Return the "base" filename (i.e. the filename needed by the various
+ * command line utilities).
+ *
+ * @return string A filename.
+ */
+ public function queryPath()
+ {
+ return $this->queryModulePath();
+ }
+
}
/**
* Horde_Vcs_Git log class.
*
- * Chuck Hagenbuch <chuck@horde.org>
- *
* @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Log_Git extends Horde_Vcs_Log
{
- public $files = array();
-
- public static function factory($file, $rev)
- {
- /* The version of the cached data. Increment this whenever the
- * internal storage format changes, such that we must
- * invalidate prior cached data. */
- $cacheVersion = 1;
- $cacheId = $file->rep->sourceroot() . '_r' . $rev . '_v' . $cacheVersion;
-
- if ($file->cache &&
- // Individual revisions can be cached forever
- // return array_keys(
- $file->cache->exists($cacheId, 0)) {
- $logOb = unserialize($file->cache->get($cacheId, 0));
- $logOb->setRepository($file->rep);
- } else {
- $logOb = new Horde_Vcs_Log_Git($file, $rev);
-
- if ($file->cache) {
- $file->cache->set($cacheId, serialize($logOb));
- }
- }
-
- return $logOb;
- }
-
/**
* Constructor.
*/
- public function __construct($fl, $rev)
+ public function __construct($rep, $fl, $rev)
{
- parent::__construct($fl);
+ parent::__construct($rep, $fl, $rev);
- $this->rev = $rev;
-
- $cmd = $this->rep->getCommand() . ' whatchanged --no-color --pretty=format:"commit %H%nAuthor:%an <%ae>%nAuthorDate:%at%nRefs:%d%n%n%s%n%b" --no-abbrev -n 1 ' . $this->rev;
+ $cmd = $rep->getCommand() . ' whatchanged --no-color --pretty=format:"commit %H%nAuthor:%an <%ae>%nAuthorDate:%at%nRefs:%d%n%n%s%n%b" --no-abbrev -n 1 ' . $rev;
$pipe = popen($cmd, 'r');
if (!is_resource($pipe)) {
throw new Horde_Vcs_Exception('Unable to run ' . $cmd . ': ' . error_get_last());
switch (trim($key)) {
case 'Author':
- $this->author = $value;
+ $this->_author = $value;
break;
case 'AuthorDate':
- $this->date = $value;
+ $this->_date = $value;
break;
case 'Refs':
foreach (explode(',', $value) as $val) {
$val = trim($val);
if (strpos($val, 'refs/tags/') === 0) {
- $this->tags[] = substr($val, 10);
+ $this->_tags[] = substr($val, 10);
}
}
- if (!empty($this->tags)) {
- sort($this->tags);
+ if (!empty($this->_tags)) {
+ sort($this->_tags);
}
}
break;
$log .= $line;
$line = fgets($pipe);
}
- $this->log = trim($log);
+ $this->_log = trim($log);
// @TODO internal line formatting
// Build list of files in this revision. The format of these lines is
// http://www.kernel.org/pub/software/scm/git/docs/git-diff-tree.html
while ($line) {
preg_match('/:(\d+) (\d+) (\w+) (\w+) (.+)\t(.+)(\t(.+))?/', $line, $matches);
- $this->files[$matches[6]] = array(
+ $this->_files[$matches[6]] = array(
'srcMode' => $matches[1],
'dstMode' => $matches[2],
'srcSha1' => $matches[3],
'dstSha1' => $matches[4],
'status' => $matches[5],
'srcPath' => $matches[6],
- 'dstPath' => isset($matches[7]) ? $matches[7] : '',
+ 'dstPath' => isset($matches[7]) ? $matches[7] : ''
);
$line = fgets($pipe);
fclose($pipe);
}
- public function setRepository($rep)
- {
- $this->rep = $rep;
- }
-
+ /**
+ * TODO
+ */
public function getHashForPath($path)
{
- // @TODO not confident yet abotu the choice of dstSha1 vs. srcSha1
- return $this->files[$path]['dstSha1'];
+ // @TODO Not confident yet abotu the choice of dstSha1 vs. srcSha1
+ return $this->_files[$path]['dstSha1'];
}
/**
public function queryBranch()
{
- $branches = $ret = array();
- $command = $this->rep->getCommand() . ' branch --contains ' . escapeshellarg($this->rev) . ' 2>&1';
+ $branches = array();
+ $command = $this->_rep->getCommand() . ' branch --contains ' . escapeshellarg($this->_rev) . ' 2>&1';
exec($command, $branches);
return array_map('trim', $branches, array_fill(0, count($branches), '* '));
}
/**
* Horde_Vcs_Git Patchset class.
*
- * Copyright Chuck Hagenbuch <chuck@horde.org>
- *
* @author Chuck Hagenbuch <chuck@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Patchset_Git extends Horde_Vcs_Patchset
{
/**
- * Populate the object with information about the patchsets that
- * this file is involved in.
+ * Constructor
+ *
+ * @param Horde_Vcs $rep A Horde_Vcs repository object.
+ * @param string $file The filename to create patchsets for.
*/
- function getPatchsets()
+ public function __construct($rep, $file)
{
- $fileOb = $this->_rep->getFileObject($this->_file);
- $this->_patchsets = array();
+ $fileOb = $rep->getFileObject($this->file);
foreach ($fileOb->logs as $rev => $log) {
$this->_patchsets[$rev] = array(
}
/**
+ * Create a range of revisions between two revision numbers.
+ *
+ * @param Horde_Vcs_File $file The desired file.
+ * @param string $r1 The initial revision.
+ * @param string $r2 The ending revision.
+ *
+ * @return array The revision range, or empty if there is no straight
+ * line path between the revisions.
+ */
+ public function getRevisionRange($file, $r1, $r2)
+ {
+ if ($this->cmp($r1, $r2) == 1) {
+ $curr = $this->prev($r1);
+ $stop = $this->prev($r2);
+ $flip = true;
+ } else {
+ $curr = $r2;
+ $stop = $r1;
+ $flip = false;
+ }
+
+ $ret_array = array();
+
+ do {
+ $ret_array[] = $curr;
+ $curr = $this->prev($curr);
+ if ($curr == $stop) {
+ return ($flip) ? array_reverse($ret_array) : $ret_array;
+ }
+ } while ($this->cmp($curr, $stop) != -1);
+
+ return array();
+ }
+
+ /**
* Checks an RCS file in with a specified change log.
*
* @param string $filepath Location of file to check in.
*/
public function ci($filepath, $message, $user = null, $newBinary = false)
{
- if ($user) {
- putenv('LOGNAME=' . $user);
- } else {
- putenv('LOGNAME=guest');
- }
+ putenv('LOGNAME=' . ($user ? $user : 'guest'));
$ci_cmd = $this->getPath('ci') . ' ' . escapeshellarg($filepath) . ' 2>&1';
$rcs_cmd = $this->getPath('rcs') . ' -i -kb ' . escapeshellarg($filepath) . ' 2>&1';
$pipe_def = array(0 => array("pipe", 'r'),
1 => array("pipe", 'w'));
- if ($newBinary) {
- $process = proc_open($rcs_cmd, $pipe_def, $pipes);
- } else {
- $process = proc_open($ci_cmd, $pipe_def, $pipes);
- }
-
+ $process = proc_open($newBinary ? $rcs_cmd : $ci_cmd, $pipe_def, $pipes);
if (is_resource($process)) {
foreach ($message_lines as $line) {
if ($line == '.\n') {
* it. For example, if we remove 2 portions of 1.2.3.4, we are
* left with 1.2.
*
- * @param string $val Input revision
- * @param integer $amount Number of portions to strip
+ * @param string $val Input revision.
+ * @param integer $amount Number of portions to strip.
*
- * @return string Stripped revision number
+ * @return string Stripped revision number.
*/
public function strip($val, $amount = 1)
{
while ($amount-- > 0 && ($pos = strrpos($val, '.')) !== false) {
$val = substr($val, 0, $pos);
}
+
return ($pos !== false) ? $val : false;
}
* The size of a revision number is the number of portions it has.
* For example, 1,2.3.4 is of size 4.
*
- * @param string $val Revision number to determine size of
+ * @param string $val Revision number to determine size of.
*
- * @return integer Size of revision number
+ * @return integer Size of revision number.
*/
public function sizeof($val)
{
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
*
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Svn extends Horde_Vcs
{
$rep->assertValidRevision($rev);
- return ($RCS = popen($this->getCommand() . ' cat -r ' . escapeshellarg($rev) . ' ' . escapeshellarg($fullname) . ' 2>&1', VC_WINDOWS ? 'rb' : 'r'))
- ? $RCS
- : throw new Horde_Vcs_Exception('Couldn\'t perform checkout of the requested file');
+ if ($RCS = popen($this->getCommand() . ' cat -r ' . escapeshellarg($rev) . ' ' . escapeshellarg($fullname) . ' 2>&1', VC_WINDOWS ? 'rb' : 'r')) {
+ return $RCS;
+ }
+
+ throw new Horde_Vcs_Exception('Couldn\'t perform checkout of the requested file');
}
/**
return $rev && is_numeric($rev);
}
-}
+ /**
+ * Create a range of revisions between two revision numbers.
+ *
+ * @param Horde_Vcs_File $file The desired file.
+ * @param string $r1 The initial revision.
+ * @param string $r2 The ending revision.
+ *
+ * @return array The revision range, or empty if there is no straight
+ * line path between the revisions.
+ */
+ public function getRevisionRange($file, $r1, $r2)
+ {
+ // TODO
+ }
-/**
- * Horde_Vcs_Svn diff class.
- *
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
- * @author Anil Madhavapeddy <anil@recoil.org>
- * @package Horde_Vcs
- */
-class Horde_Vcs_Diff_Svn extends Horde_Vcs_Diff
-{
/**
* Obtain the differences between two revisions of a file.
*
- * @param Horde_Vcs $rep A repository object.
* @param Horde_Vcs_File $file The desired file.
* @param string $rev1 Original revision number to compare from.
* @param string $rev2 New revision number to compare against.
- * @param string $type The type of diff (e.g. 'unified').
- * @param integer $num Number of lines to be used in context and
- * unified diffs.
- * @param boolean $ws Show whitespace in the diff?
+ * @param array $opts The following optional options:
+ * <pre>
+ * 'num' - (integer) DEFAULT: 3
+ * 'type' - (string) DEFAULT: 'unified'
+ * 'ws' - (boolean) DEFAULT: true
+ * </pre>
*
* @return string|boolean False on failure, or a string containing the
* diff on success.
*/
- public function get($rep, $file, $rev1, $rev2, $type = 'context',
- $num = 3, $ws = true)
+ protected function _diff($file, $rev1, $rev2, $opts)
{
- /* Check that the revision numbers are valid */
- $rev1 = $rep->isValidRevision($rev1) ? $rev1 : 0;
- $rev2 = $rep->isValidRevision($rev1) ? $rev2 : 0;
-
$fullName = $file->queryFullPath();
$diff = array();
- $options = '';
- if (!$ws) {
- $options .= ' -bB ';
+ $flags = '';
+
+ if (!$opts['ws']) {
+ $flags .= ' -bB ';
}
- switch ($type) {
+ switch ($opts['type']) {
case 'context':
- $options .= '--context=' . (int)$num;
+ $flags .= '--context=' . (int)$opts['num'];
break;
case 'unified':
- $options .= '-p --unified=' . (int)$num;
+ $flags .= '-p --unified=' . (int)$opts['num'];
break;
case 'column':
- $options .= '--side-by-side --width=120';
+ $flags .= '--side-by-side --width=120';
break;
case 'ed':
- $options .= '-e';
+ $flags .= '-e';
break;
}
// TODO: add options for $hr options - however these may not
// be compatible with some diffs.
- $command = $rep->getCommand() . " diff --diff-cmd " . $rep->getPath('diff') . " -r $rev1:$rev2 -x " . escapeshellarg($options) . ' ' . escapeshellarg($file->queryFullPath()) . ' 2>&1';
+ $command = $this->getCommand() . " diff --diff-cmd " . $this->getPath('diff') . ' -r ' . escapeshellarg($rev1 . ':' . $rev2) . ' -x ' . escapeshellarg($flags) . ' ' . escapeshellarg($file->queryFullPath()) . ' 2>&1';
exec($command, $diff, $retval);
return $diff;
/**
* Horde_Vcs_Svn directory class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Directory_Svn extends Horde_Vcs_Directory
{
/**
- * Tell the object to open and browse its current directory, and
- * retrieve a list of all the objects in there. It then populates
- * the file/directory stack and makes it available for retrieval.
+ * Create a Directory object to store information about the files in a
+ * single directory in the repository.
*
- * @return integer 1 on success.
+ * @param Horde_Vcs $rep The Repository object this directory is part of.
+ * @param string $dn Path to the directory.
+ * @param array $opts TODO
*/
- public function browseDir($cache = null, $quicklog = true,
- $showattic = false)
+ public function __construct($rep, $dn, $opts = array())
{
- $cmd = $this->_rep->getCommand() . ' ls ' . escapeshellarg($this->_rep->sourceroot() . $this->queryDir()) . ' 2>&1';
+ parent::__construct($rep, $dn, $opts);
+
+ $cmd = $rep->getCommand() . ' ls ' . escapeshellarg($rep->sourceroot() . $this->queryDir()) . ' 2>&1';
$dir = popen($cmd, 'r');
if (!$dir) {
} elseif (substr($line, -1) == '/') {
$this->_dirs[] = substr($line, 0, -1);
} else {
- $this->_files[] = $this->_rep->getFileObject($this->queryDir() . "/$line", array('cache' => $cache, 'quicklog' => $quicklog));
+ $this->_files[] = $rep->getFileObject($this->queryDir() . '/' . $line, array('quicklog' => !empty($opts['quicklog'])));
}
}
pclose($dir);
- return $errors
- ? throw new Horde_Vcs_Exception(implode("\n", $errors))
- : true;
+ if (empty($errors)) {
+ return true;
+ }
+
+ throw new Horde_Vcs_Exception(implode("\n", $errors));
}
}
/**
* Horde_Vcs_Svn file class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
-class Horde_Vcs_File_Svn extends Horde_Vcs_File {
+class Horde_Vcs_File_Svn extends Horde_Vcs_File
+{
+ /**
+ * @var resource
+ */
+ public $logpipe;
/**
* Create a repository file object, and give it information about
*/
public function __construct($rep, $fl, $opts = array())
{
- $this->rep = $rep;
- $this->name = basename($fl);
- $this->dir = dirname($fl);
- $this->filename = $fl;
- $this->quicklog = !empty($opts['quicklog']);
+ parent::__construct($rep, $fl, $opts);
/* This doesn't work; need to find another way to simply
* request the most recent revision:
*
- * $flag = $this->quicklog ? '-r HEAD ' : ''; */
- $flag = '';
- $cmd = $this->rep->getCommand() . ' log -v ' . $flag . escapeshellarg($this->queryFullPath()) . ' 2>&1';
+ * $flag = $this->_quicklog ? '-r HEAD ' : '';
+ */
+ $cmd = $rep->getCommand() . ' log -v ' . escapeshellarg($this->queryFullPath()) . ' 2>&1';
$pipe = popen($cmd, 'r');
if (!$pipe) {
throw new Horde_Vcs_Exception('Failed to execute svn log: ' . $cmd);
throw new Horde_Vcs_Exception('Error executing svn log: ' . $header);
}
+ $this->logpipe = $pipe;
+
while (!feof($pipe)) {
- $log = new Horde_Vcs_Log_Svn($this->rep, $this);
- $err = $log->processLog($pipe);
- if ($err) {
+ try {
+ $log = $rep->getLogObject($this, null);
$rev = $log->queryRevision();
- $this->logs[$rev] = $log;
- $this->revs[] = $rev;
- }
+ $this->_logs[$rev] = $log;
+ $this->_revs[] = $rev;
+ } catch (Horde_Vcs_Exception $e) {}
- if ($this->quicklog) {
+ if ($this->_quicklog) {
break;
}
}
/**
* Returns name of the current file without the repository
- * extensions (usually ,v)
+ * extensions (usually ,v).
*
- * @return Filename without repository extension
+ * @return string Filename without repository extension.
*/
- function queryName()
+ public function queryName()
{
- return preg_replace('/,v$/', '', $this->name);
+ return preg_replace('/,v$/', '', $this->_name);
}
}
/**
* Horde_Vcs_Svn log class.
*
- * Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Log_Svn extends Horde_Vcs_Log
{
- public $err;
- public $files;
+ /**
+ * TODO
+ */
+ protected $_files = array();
- public function processLog($pipe)
+ /**
+ * Constructor.
+ */
+ public function __construct($rep, $fl, $rev)
{
- $line = fgets($pipe);
+ parent::__construct($rep, $fl, $rev);
- if (feof($pipe)) {
- return false;
+ $line = fgets($fl->logpipe);
+
+ if (feof($fl->logpipe)) {
+ return;
}
if (preg_match('/^r([0-9]*) \| (.*?) \| (.*) \(.*\) \| ([0-9]*) lines?$/', $line, $matches)) {
- $this->rev = $matches[1];
- $this->author = $matches[2];
- $this->date = strtotime($matches[3]);
+ $this->_rev = $matches[1];
+ $this->_author = $matches[2];
+ $this->_date = strtotime($matches[3]);
$size = $matches[4];
} else {
- $this->err = $line;
- return false;
+ throw new Horde_Vcs_Exception('SVN Error');
}
- fgets($pipe);
+ fgets($fl->logpipe);
- $this->files = array();
- while (($line = trim(fgets($pipe))) != '') {
- $this->files[] = $line;
+ while (($line = trim(fgets($fl->logpipe))) != '') {
+ $this->_files[] = $line;
}
for ($i = 0; $i != $size; ++$i) {
- $this->log = $this->log . chop(fgets($pipe)) . "\n";
+ $this->_log = $this->_log . chop(fgets($fl->logpipe)) . "\n";
}
- $this->log = chop($this->log);
- fgets($pipe);
+ $this->_log = chop($this->_log);
+ fgets($fl->logpipe);
+ }
- return true;
+ /**
+ * TODO
+ */
+ public function queryFiles()
+ {
+ return $this->_files;
}
}
/**
* Horde_Vcs_Svn Patchset class.
*
- * Copyright Anil Madhavapeddy, <anil@recoil.org>
- *
* @author Anil Madhavapeddy <anil@recoil.org>
+ * @author Michael Slusarz <slusarz@horde.org>
* @package Horde_Vcs
*/
class Horde_Vcs_Patchset_Svn extends Horde_Vcs_Patchset
{
/**
- * Populate the object with information about the patchsets that
- * this file is involved in.
+ * Constructor
*
- * @return boolean True on success.
+ * @param Horde_Vcs $rep A Horde_Vcs repository object.
+ * @param string $file The filename to create patchsets for.
*/
- function getPatchsets()
+ public function __construct($rep, $file)
{
- $fileOb = new Horde_Vcs_File_Svn($this->_rep, $this->_file);
+ $fileOb = $rep->getFileObject($file);
- $this->_patchsets = array();
foreach ($fileOb->logs as $rev => $log) {
- $this->_patchsets[$rev] = array();
- $this->_patchsets[$rev]['date'] = $log->queryDate();
- $this->_patchsets[$rev]['author'] = $log->queryAuthor();
- $this->_patchsets[$rev]['branch'] = '';
- $this->_patchsets[$rev]['tag'] = '';
- $this->_patchsets[$rev]['log'] = $log->queryLog();
- $this->_patchsets[$rev]['members'] = array();
- foreach ($log->files as $file) {
+ $this->_patchsets[$rev] = array(
+ 'author' => $log->queryAuthor(),
+ 'branch' => '',
+ 'date' => $log->queryDate(),
+ 'log' => $log->queryLog(),
+ 'members' => array(),
+ 'tag' => ''
+ );
+
+ foreach ($log->queryFiles() as $file) {
$action = substr($file, 0, 1);
$file = preg_replace('/.*?\s(.*?)(\s|$).*/', '\\1', $file);
$to = $rev;