From ccc41c86b0677ff1d6d79ec1755c34a8ac5e2cab Mon Sep 17 00:00:00 2001
From: Nicolas LASSALLE
Date: Fri, 29 Aug 2008 19:50:10 +0200
Subject: [PATCH] Added support of subversion.
---
src/IDF/Diff.php | 13 +
src/IDF/Git.php | 4 +-
src/IDF/Project.php | 28 ++
src/IDF/ScmFactory.php | 53 +++
src/IDF/Svn.php | 384 +++++++++++++++++++
src/IDF/Views/Source.php | 158 ++++++--
src/IDF/conf/views.php | 14 +-
src/IDF/templates/base.html | 2 +-
src/IDF/templates/source/base.html | 4 +-
src/IDF/templates/source/changelog.html | 10 +
src/IDF/templates/source/commit.html | 2 +
src/IDF/templates/source/{ => git}/tree.html | 0
src/IDF/templates/source/svn/tree.html | 71 ++++
www/media/idf/css/style.css | 5 +
14 files changed, 713 insertions(+), 35 deletions(-)
create mode 100644 src/IDF/ScmFactory.php
create mode 100644 src/IDF/Svn.php
rename src/IDF/templates/source/{ => git}/tree.html (100%)
create mode 100644 src/IDF/templates/source/svn/tree.html
diff --git a/src/IDF/Diff.php b/src/IDF/Diff.php
index 2f86fd0..58bab6b 100644
--- a/src/IDF/Diff.php
+++ b/src/IDF/Diff.php
@@ -56,6 +56,14 @@ class IDF_Diff
$current_chunk = 0;
continue;
}
+ if (0 === strpos($line, 'Index: ')) {
+ $current_file = self::getSvnFile($line);
+ $files[$current_file] = array();
+ $files[$current_file]['chunks'] = array();
+ $files[$current_file]['chunks_def'] = array();
+ $current_chunk = 0;
+ continue;
+ }
if (0 === strpos($line, '@@ ')) {
$files[$current_file]['chunks_def'][] = self::getChunk($line);
$files[$current_file]['chunks'][] = array();
@@ -95,6 +103,11 @@ class IDF_Diff
return trim(substr($line, 3, $n-3));
}
+ public static function getSvnFile($line)
+ {
+ return substr(trim($line), 7);
+ }
+
/**
* Return the html version of a parsed diff.
*/
diff --git a/src/IDF/Git.php b/src/IDF/Git.php
index 0fb373a..316f928 100644
--- a/src/IDF/Git.php
+++ b/src/IDF/Git.php
@@ -40,9 +40,10 @@ class IDF_Git
* Test a given object hash.
*
* @param string Object hash.
+ * @param null to be svn client compatible
* @return mixed false if not valid or 'blob', 'tree', 'commit'
*/
- public function testHash($hash)
+ public function testHash($hash, $dummy=null)
{
$cmd = sprintf('GIT_DIR=%s git cat-file -t %s',
escapeshellarg($this->repo),
@@ -297,6 +298,7 @@ class IDF_Git
}
}
$c['full_message'] = trim($c['full_message']);
+
$res[] = (object) $c;
return $res;
}
diff --git a/src/IDF/Project.php b/src/IDF/Project.php
index 26b7889..17887d9 100644
--- a/src/IDF/Project.php
+++ b/src/IDF/Project.php
@@ -335,6 +335,34 @@ class IDF_Project extends Pluf_Model
return $gitrep.'/'.$this->shortname.'.git';
}
+ /**
+ * Get the path to the git repository.
+ *
+ * @return string Path to the git repository
+ */
+ public function getSvnDaemonUrl()
+ {
+ $conf = new IDF_Conf();
+ $conf->setProject($this);
+
+ return $conf->getVal('svn_daemon_url');
+ }
+
+
+ /**
+ * Get the root name of the project scm
+ *
+ * @return string SCM root
+ */
+ public function getScmRoot()
+ {
+ $roots = array('git' => 'master', 'svn' => 'HEAD');
+ $conf = new IDF_Conf();
+ $conf->setProject($this);
+ $scm = $conf->getVal('scm', 'git');
+ return $roots[$scm];
+ }
+
/**
* Check that the object belongs to the project or rise a 404
* error.
diff --git a/src/IDF/ScmFactory.php b/src/IDF/ScmFactory.php
new file mode 100644
index 0000000..d8ae0a1
--- /dev/null
+++ b/src/IDF/ScmFactory.php
@@ -0,0 +1,53 @@
+conf->getVal('scm', 'git');
+
+ // CASE: git
+ if ($scm === 'git') {
+ return new IDF_Git($request->project->getGitRepository());
+ }
+
+ // CASE: svn
+ if ($scm === 'svn') {
+ return new IDF_Svn($request->conf->getVal('svn_repository'),
+ $request->conf->getVal('svn_username'),
+ $request->conf->getVal('svn_password'));
+ }
+ }
+}
+
diff --git a/src/IDF/Svn.php b/src/IDF/Svn.php
new file mode 100644
index 0000000..697417b
--- /dev/null
+++ b/src/IDF/Svn.php
@@ -0,0 +1,384 @@
+ 'tree',
+ 'file' => 'blob');
+
+
+ public function __construct($repo, $username='', $password='')
+ {
+ $this->repo = $repo;
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+
+ /**
+ * Test a given object hash.
+ *
+ * @param string Object hash.
+ * @return mixed false if not valid or 'blob', 'tree', 'commit'
+ */
+ public function testHash($rev, $path='')
+ {
+ // OK if HEAD on /
+ if ($rev === 'HEAD' && $path === '') {
+ return 'commit';
+ }
+
+ // Else, test the path on revision
+ $cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$path),
+ escapeshellarg($rev));
+ $xmlInfo = shell_exec($cmd);
+
+ // If exception is thrown, return false
+ try {
+ $xml = simplexml_load_string($xmlInfo);
+ }
+ catch (Exception $e) {
+ return false;
+ }
+
+ // If the entry node does exists, params are wrong
+ if (!isset($xml->entry)) {
+ return false;
+ }
+
+ // Else, enjoy it :)
+ return 'commit';
+ }
+
+
+ /**
+ * Given a commit hash returns an array of files in it.
+ *
+ * A file is a class with the following properties:
+ *
+ * 'perm', 'type', 'size', 'hash', 'file'
+ *
+ * @param string Commit ('HEAD')
+ * @param string Base folder ('')
+ * @return array
+ */
+ public function filesAtCommit($rev='HEAD', $folder='')
+ {
+ $cmd = sprintf('svn ls --xml --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$folder),
+ escapeshellarg($rev));
+ $xmlLs = shell_exec($cmd);
+ $xml = simplexml_load_string($xmlLs);
+
+ $res = array();
+ foreach ($xml->list->entry as $entry) {
+ $file = array();
+ $file['type'] = $this->assoc[(String) $entry['kind']];
+ $file['file'] = (String) $entry->name;
+ $file['fullpath'] = $folder.'/'.((String) $entry->name);
+ $file['date'] = gmdate('Y-m-d H:i:s',
+ strtotime((String) $entry->commit->date));
+ $file['rev'] = (String) $entry->commit['revision'];
+
+ // Get commit message
+ $currentReposFile = $this->repo.'/'.$folder.'/'.$file['file'];
+ $file['log'] = $this->getCommitMessage($currentReposFile, $rev);
+
+ // Get the size if the type is blob
+ if ($file['type'] == 'blob') {
+ $file['size'] = (String) $entry->size;
+ }
+
+ $file['perm'] = '';
+
+ $res[] = (Object) $file;
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Get a commit message for given file and revision.
+ *
+ * @param string File
+ * @param string Commit ('HEAD')
+ *
+ * @return String commit message
+ */
+ private function getCommitMessage($file, $rev='HEAD')
+ {
+ $cmd = sprintf('svn log --xml --limit 1 --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($file),
+ escapeshellarg($rev));
+ $xmlLog = shell_exec($cmd);
+ $xml = simplexml_load_string($xmlLog);
+ return (String) $xml->logentry->msg;
+ }
+
+
+ /**
+ * Get the file info.
+ *
+ * @param string File
+ * @param string Commit ('HEAD')
+ * @return false Information
+ */
+ public function getFileInfo($totest, $rev='HEAD')
+ {
+ $cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$totest),
+ escapeshellarg($rev));
+ $xmlInfo = shell_exec($cmd);
+ $xml = simplexml_load_string($xmlInfo);
+ $entry = $xml->entry;
+
+ $file = array();
+ $file['fullpath'] = $totest;
+ $file['hash'] = (String) $entry->repository->uuid;
+ $file['type'] = $this->assoc[(String) $entry['kind']];
+ $file['file'] = $totest;
+ $file['rev'] = (String) $entry->commit['revision'];
+ $file['author'] = (String) $entry->author;
+ $file['date'] = gmdate('Y-m-d H:i:s', strtotime((String) $entry->commit->date));
+ $file['size'] = (String) $entry->size;
+ $file['log'] = '';
+
+ return (Object) $file;
+ }
+
+
+ /**
+ * Get a blob.
+ *
+ * @param string Blob hash
+ * @return string Raw blob
+ */
+ public function getBlob($path, $rev)
+ {
+ $cmd = sprintf('svn cat --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$path),
+ escapeshellarg($rev));
+ return shell_exec($cmd);
+ }
+
+
+ /**
+ * Get the branches.
+ *
+ * @return array Branches.
+ */
+ public function getBranches()
+ {
+ $res = array('HEAD');
+ return $res;
+ }
+
+
+ /**
+ * Get commit details.
+ *
+ * @param string Commit ('HEAD').
+ * @return array Changes.
+ */
+ public function getCommit($rev='HEAD')
+ {
+ $res = array();
+ $cmd = sprintf('svn log --xml -v --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo),
+ escapeshellarg($rev));
+ $xmlRes = shell_exec($cmd);
+ $xml = simplexml_load_string($xmlRes);
+
+ $res['author'] = (String) $xml->logentry->author;
+ $res['date'] = gmdate('Y-m-d H:i:s', strtotime((String) $xml->logentry->date));
+ $res['title'] = (String) $xml->logentry->msg;
+ $res['commit'] = (String) $xml->logentry['revision'];
+ $res['changes'] = $this->getDiff($rev);
+ $res['tree'] = '';
+
+
+ return (Object) $res;
+ }
+
+ private function getDiff($rev='HEAD')
+ {
+ $res = array();
+ $cmd = sprintf('svn diff -c %s --username=%s --password=%s %s',
+ escapeshellarg($rev),
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo));
+ return shell_exec($cmd);
+ }
+
+
+ /**
+ * Get latest changes.
+ *
+ * @param string Commit ('HEAD').
+ * @param int Number of changes (10).
+ *
+ * @return array Changes.
+ */
+ public function getChangeLog($rev='HEAD', $n=10)
+ {
+ $res = array();
+ $cmd = sprintf('svn log --xml -v --limit %s --username=%s --password=%s %s@%s',
+ escapeshellarg($n),
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo),
+ escapeshellarg($rev));
+ $xmlRes = shell_exec($cmd);
+ $xml = simplexml_load_string($xmlRes);
+
+ $res = array();
+ foreach ($xml->logentry as $entry) {
+ $log = array();
+ $log['author'] = (String) $entry->author;
+ $log['date'] = gmdate('Y-m-d H:i:s', strtotime((String) $entry->date));
+ $log['title'] = (String) $entry->msg;
+ $log['commit'] = (String) $entry['revision'];
+ $log['full_message'] = '';
+
+ $res[] = (Object) $log;
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Generate the command to create a zip archive at a given commit.
+ * Unsupported feature in subversion
+ *
+ * @param string dummy
+ * @param string dummy
+ * @return Exception
+ */
+ public function getArchiveCommand($commit, $prefix='git-repo-dump/')
+ {
+ throw new Exception(('Unsupported feature.'));
+ }
+
+
+ /**
+ * Get additionnals properties on path and revision
+ *
+ * @param string File
+ * @param string Commit ('HEAD')
+ * @return array
+ */
+ public function getProperties($rev, $path='')
+ {
+ $res = array();
+ $cmd = sprintf('svn proplist --xml --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$path),
+ escapeshellarg($rev));
+ $xmlProps = shell_exec($cmd);
+ $props = simplexml_load_string($xmlProps);
+
+ // No properties, returns an empty array
+ if (!isset($props->target)) {
+ return $res;
+ }
+
+ // Get the value of each property
+ foreach ($props->target->property as $prop) {
+ $key = (String) $prop['name'];
+ $res[$key] = $this->getProperty($key, $rev, $path);
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Get a specific additionnal property on path and revision
+ *
+ * @param string Property
+ * @param string File
+ * @param string Commit ('HEAD')
+ * @return string the property value
+ */
+ private function getProperty($property, $rev, $path='')
+ {
+ $res = array();
+ $cmd = sprintf('svn propget --xml %s --username=%s --password=%s %s@%s',
+ escapeshellarg($property),
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo.'/'.$path),
+ escapeshellarg($rev));
+ $xmlProp = shell_exec($cmd);
+ $prop = simplexml_load_string($xmlProp);
+
+ return (String) $prop->target->property;
+ }
+
+
+ /**
+ * Get the number of the last commit in the repository.
+ *
+ * @param string Commit ('HEAD').
+ *
+ * @return String last number commit
+ */
+ public function getLastCommit($rev='HEAD')
+ {
+ $xmlInfo = '';
+ $cmd = sprintf('svn info --xml --username=%s --password=%s %s@%s',
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->repo),
+ escapeshellarg($rev));
+ $xmlInfo = shell_exec($cmd);
+
+ $xml = simplexml_load_string($xmlInfo);
+ return (String) $xml->entry->commit['revision'];
+ }
+}
+
diff --git a/src/IDF/Views/Source.php b/src/IDF/Views/Source.php
index 4180dca..9fe5503 100644
--- a/src/IDF/Views/Source.php
+++ b/src/IDF/Views/Source.php
@@ -34,11 +34,13 @@ class IDF_Views_Source
public $changeLog_precond = array('IDF_Precondition::accessSource');
public function changeLog($request, $match)
{
- $title = sprintf(__('%s Git Change Log'), (string) $request->project);
- $git = new IDF_Git($request->project->getGitRepository());
- $branches = $git->getBranches();
+ $title = sprintf(__('%s %s Change Log'), (string) $request->project,
+ $this->getScmType($request));
+ $scm = IDF_ScmFactory::getScm($request);
+ $branches = $scm->getBranches();
$commit = $match[2];
- $res = $git->getChangeLog($commit, 25);
+ $res = $scm->getChangeLog($commit, 25);
+ $scmConf = $request->conf->getVal('scm', 'git');
return Pluf_Shortcuts_RenderToResponse('source/changelog.html',
array(
'page_title' => $title,
@@ -46,6 +48,7 @@ class IDF_Views_Source
'changes' => $res,
'commit' => $commit,
'branches' => $branches,
+ 'scm' => $scmConf,
),
$request);
}
@@ -53,21 +56,27 @@ class IDF_Views_Source
public $treeBase_precond = array('IDF_Precondition::accessSource');
public function treeBase($request, $match)
{
- $title = sprintf(__('%s Git Source Tree'), (string) $request->project);
- $git = new IDF_Git($request->project->getGitRepository());
+ $title = sprintf(__('%s %s Source Tree'), (string) $request->project,
+ $this->getScmType($request));
+ $scm = IDF_ScmFactory::getScm($request);
$commit = $match[2];
- $branches = $git->getBranches();
- if ('commit' != $git->testHash($commit)) {
+ $branches = $scm->getBranches();
+ if ('commit' != $scm->testHash($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$branches[0]));
return new Pluf_HTTP_Response_Redirect($url);
}
- $res = $git->filesAtCommit($commit);
- $cobject = $git->getCommit($commit);
+ $res = $scm->filesAtCommit($commit);
+ $cobject = $scm->getCommit($commit);
$tree_in = in_array($commit, $branches);
- return Pluf_Shortcuts_RenderToResponse('source/tree.html',
+ $scmConf = $request->conf->getVal('scm', 'git');
+ $props = null;
+ if ($scmConf === 'svn') {
+ $props = $scm->getProperties($commit);
+ }
+ return Pluf_Shortcuts_RenderToResponse('source/'.$scmConf.'/tree.html',
array(
'page_title' => $title,
'title' => $title,
@@ -76,6 +85,7 @@ class IDF_Views_Source
'commit' => $commit,
'tree_in' => $tree_in,
'branches' => $branches,
+ 'props' => $props,
),
$request);
}
@@ -83,19 +93,20 @@ class IDF_Views_Source
public $tree_precond = array('IDF_Precondition::accessSource');
public function tree($request, $match)
{
- $title = sprintf(__('%s Git Source Tree'), (string) $request->project);
- $git = new IDF_Git($request->project->getGitRepository());
- $branches = $git->getBranches();
+ $title = sprintf(__('%s %s Source Tree'), (string) $request->project,
+ $this->getScmType($request));
+ $scm = IDF_ScmFactory::getScm($request);
+ $branches = $scm->getBranches();
$commit = $match[2];
- if ('commit' != $git->testHash($commit)) {
+ $request_file = $match[3];
+ if ('commit' != $scm->testHash($commit, $request_file)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
$branches[0]));
return new Pluf_HTTP_Response_Redirect($url);
}
- $request_file = $match[3];
- $request_file_info = $git->getFileInfo($request_file, $commit);
+ $request_file_info = $scm->getFileInfo($request_file, $commit);
if (!$request_file_info) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
@@ -105,21 +116,32 @@ class IDF_Views_Source
}
if ($request_file_info->type != 'tree') {
$info = self::getMimeType($request_file_info->file);
- $rep = new Pluf_HTTP_Response($git->getBlob($request_file_info->hash),
- $info[0]);
+ if (Pluf::f('src') == 'git') {
+ $rep = new Pluf_HTTP_Response($scm->getBlob($request_file_info->hash),
+ $info[0]);
+ }
+ else {
+ $rep = new Pluf_HTTP_Response($scm->getBlob($request_file_info->fullpath, $commit),
+ $info[0]);
+ }
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$info[1].'"';
return $rep;
}
$bc = self::makeBreadCrumb($request->project, $commit, $request_file_info->file);
$page_title = $bc.' - '.$title;
- $cobject = $git->getCommit($commit);
+ $cobject = $scm->getCommit($commit);
$tree_in = in_array($commit, $branches);
- $res = $git->filesAtCommit($commit, $request_file);
+ $res = $scm->filesAtCommit($commit, $request_file);
// try to find the previous level if it exists.
$prev = split('/', $request_file);
$l = array_pop($prev);
$previous = substr($request_file, 0, -strlen($l.' '));
- return Pluf_Shortcuts_RenderToResponse('source/tree.html',
+ $scmConf = $request->conf->getVal('scm', 'git');
+ $props = null;
+ if ($scmConf === 'svn') {
+ $props = $scm->getProperties($commit, $request_file);
+ }
+ return Pluf_Shortcuts_RenderToResponse('source/'.$scmConf.'/tree.html',
array(
'page_title' => $page_title,
'title' => $title,
@@ -131,6 +153,7 @@ class IDF_Views_Source
'prev' => $previous,
'tree_in' => $tree_in,
'branches' => $branches,
+ 'props' => $props,
),
$request);
}
@@ -155,10 +178,10 @@ class IDF_Views_Source
public $commit_precond = array('IDF_Precondition::accessSource');
public function commit($request, $match)
{
- $git = new IDF_Git($request->project->getGitRepository());
+ $scm = IDF_ScmFactory::getScm($request);
$commit = $match[2];
- $branches = $git->getBranches();
- if ('commit' != $git->testHash($commit)) {
+ $branches = $scm->getBranches();
+ if ('commit' != $scm->testHash($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
@@ -167,9 +190,10 @@ class IDF_Views_Source
}
$title = sprintf(__('%s Commit Details'), (string) $request->project);
$page_title = sprintf(__('%s Commit Details - %s'), (string) $request->project, $commit);
- $cobject = $git->getCommit($commit);
+ $cobject = $scm->getCommit($commit);
$diff = new IDF_Diff($cobject->changes);
$diff->parse();
+ $scmConf = $request->conf->getVal('scm', 'git');
return Pluf_Shortcuts_RenderToResponse('source/commit.html',
array(
'page_title' => $page_title,
@@ -178,6 +202,7 @@ class IDF_Views_Source
'cobject' => $cobject,
'commit' => $commit,
'branches' => $branches,
+ 'scm' => $scmConf,
),
$request);
}
@@ -190,9 +215,9 @@ class IDF_Views_Source
public function download($request, $match)
{
$commit = trim($match[2]);
- $git = new IDF_Git($request->project->getGitRepository());
- $branches = $git->getBranches();
- if ('commit' != $git->testHash($commit)) {
+ $scm = IDF_ScmFactory::getScm($request);
+ $branches = $scm->getBranches();
+ if ('commit' != $scm->testHash($commit)) {
// Redirect to the first branch
$url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
array($request->project->shortname,
@@ -200,13 +225,76 @@ class IDF_Views_Source
return new Pluf_HTTP_Response_Redirect($url);
}
$base = $request->project->shortname.'-'.$commit;
- $cmd = $git->getArchiveCommand($commit, $base.'/');
+ $cmd = $scm->getArchiveCommand($commit, $base.'/');
$rep = new Pluf_HTTP_Response_CommandPassThru($cmd, 'application/x-zip');
$rep->headers['Content-Transfer-Encoding'] = 'binary';
$rep->headers['Content-Disposition'] = 'attachment; filename="'.$base.'.zip"';
return $rep;
}
+ /**
+ * Display tree of a specific SVN revision
+ *
+ */
+ public function treeRev($request, $match)
+ {
+ $prj = $request->project;
+
+ // Redirect to tree base if not svn
+ if ($request->conf->getVal('scm', 'git') != 'svn') {
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
+ array($prj->shortname, $prj->getScmRoot()));
+
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+
+ // Get revision value
+ if (!isset($request->REQUEST['rev']) or trim($request->REQUEST['rev']) == '') {
+ $scmRoot = $prj->getScmRoot();
+ }
+ else {
+ $scmRoot = $request->REQUEST['rev'];
+ }
+
+ // Get source if not /
+ if (isset($request->REQUEST['sourcefile']) and trim($request->REQUEST['sourcefile']) != '') {
+ $scmRoot .= '/'.$request->REQUEST['sourcefile'];
+ }
+
+ // Redirect
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::treeBase',
+ array($prj->shortname, $scmRoot));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+
+ /**
+ * Display SVN changelog from specific revision
+ *
+ */
+ public function changelogRev($request, $match)
+ {
+ $prj = $request->project;
+
+ // Redirect to tree base if not svn
+ if ($request->conf->getVal('scm', 'git') != 'svn') {
+ $scmRoot = $prj->getScmRoot();
+ }
+ // Get revision value if svn
+ else {
+ if (!isset($request->REQUEST['rev']) or trim($request->REQUEST['rev']) == '') {
+ $scmRoot = $prj->getScmRoot();
+ }
+ else {
+ $scmRoot = $request->REQUEST['rev'];
+ }
+ }
+
+ // Redirect
+ $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::changeLog',
+ array($prj->shortname, $scmRoot));
+ return new Pluf_HTTP_Response_Redirect($url);
+ }
+
/**
* Find the mime type of a file.
*
@@ -238,6 +326,16 @@ class IDF_Views_Source
}
return array('application/octet-stream', $info['basename']);
}
+
+ /**
+ * Get the scm type for page title
+ *
+ * @return String
+ */
+ private function getScmType($request)
+ {
+ return ucfirst($scm = $request->conf->getVal('scm', 'git'));
+ }
}
function IDF_Views_Source_PrettySize($size)
diff --git a/src/IDF/conf/views.php b/src/IDF/conf/views.php
index 5bb68a2..01ecac1 100644
--- a/src/IDF/conf/views.php
+++ b/src/IDF/conf/views.php
@@ -133,7 +133,7 @@ $ctl[] = array('regex' => '#^/p/(\w+)/issues/my/(\w+)/$#',
'model' => 'IDF_Views_Issue',
'method' => 'myIssues');
-// ---------- GIT ----------------------------------------
+// ---------- SCM ----------------------------------------
$ctl[] = array('regex' => '#^/p/(\w+)/source/$#',
'base' => $base,
@@ -171,6 +171,18 @@ $ctl[] = array('regex' => '#^/p/(\w+)/source/download/(\w+)/$#',
'model' => 'IDF_Views_Source',
'method' => 'download');
+$ctl[] = array('regex' => '#^/p/(\w+)/source/treerev/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Source',
+ 'method' => 'treeRev');
+
+$ctl[] = array('regex' => '#^/p/(\w+)/source/changesrev/$#',
+ 'base' => $base,
+ 'priority' => 4,
+ 'model' => 'IDF_Views_Source',
+ 'method' => 'changelogRev');
+
// ---------- Downloads ------------------------------------
$ctl[] = array('regex' => '#^/p/(\w+)/downloads/$#',
diff --git a/src/IDF/templates/base.html b/src/IDF/templates/base.html
index 74de62c..5c49e5f 100644
--- a/src/IDF/templates/base.html
+++ b/src/IDF/templates/base.html
@@ -44,7 +44,7 @@
{trans 'Project Home'}
{if $hasIssuesAccess} {trans 'Issues'}{/if}
{if $hasDownloadsAccess} {trans 'Downloads'}{/if}
-{if $hasSourceAccess} {trans 'Source'}{/if}
+{if $hasSourceAccess} {trans 'Source'}{/if}
{if $isOwner}
{trans 'Administer'}{/if}{/if}
diff --git a/src/IDF/templates/source/base.html b/src/IDF/templates/source/base.html
index fec2832..166e767 100644
--- a/src/IDF/templates/source/base.html
+++ b/src/IDF/templates/source/base.html
@@ -2,8 +2,8 @@
{block tabsource} class="active"{/block}
{block subtabs}
{/block}
diff --git a/src/IDF/templates/source/changelog.html b/src/IDF/templates/source/changelog.html
index ce78a20..e5edb53 100644
--- a/src/IDF/templates/source/changelog.html
+++ b/src/IDF/templates/source/changelog.html
@@ -29,11 +29,21 @@
{/block}
{block context}
+{if $scm == 'git'}
{trans 'Branches:'}
{foreach $branches as $branch}
{aurl 'url', 'IDF_Views_Source::changeLog', array($project.shortname, $branch)}
{$branch}
{/foreach}
+{/if}
+{if $scm == 'svn'}
+{trans 'Revison:'} {$commit}
+
+
+{/if}
{/block}
diff --git a/src/IDF/templates/source/commit.html b/src/IDF/templates/source/commit.html
index f8398ce..4231c30 100644
--- a/src/IDF/templates/source/commit.html
+++ b/src/IDF/templates/source/commit.html
@@ -36,11 +36,13 @@
{/if}
{/block}
{block context}
+{if $scm == 'git'}
{trans 'Branches:'}
{foreach $branches as $branch}
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $branch)}
{$branch}
{/foreach}
+{/if}
{/block}
diff --git a/src/IDF/templates/source/tree.html b/src/IDF/templates/source/git/tree.html
similarity index 100%
rename from src/IDF/templates/source/tree.html
rename to src/IDF/templates/source/git/tree.html
diff --git a/src/IDF/templates/source/svn/tree.html b/src/IDF/templates/source/svn/tree.html
new file mode 100644
index 0000000..ce5fc9c
--- /dev/null
+++ b/src/IDF/templates/source/svn/tree.html
@@ -0,0 +1,71 @@
+{extends "source/base.html"}
+{block docclass}yui-t1{assign $inSourceTree=true}{/block}
+{block body}
+{trans 'Root'}/{if $breadcrumb}{$breadcrumb|safe}{/if}
+
+
+
+
+ {trans 'File'} |
+ {trans 'Age'} |
+ {trans 'Rev'} |
+ {trans 'Message'} |
+ {trans 'Size'} |
+
+ {if !$tree_in || $props}
+ {aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
+
+ {if $props}
+
+
+ {foreach $props as $prop => $val}
+ - {trans 'Property'} {$prop} {trans 'set to:'} {$val}
+ {/foreach}
+
+ |
+ {/if}
+ {if !$tree_in}
+ {blocktrans}Source at commit {$commit} created {$cobject.date|dateago}.{/blocktrans}
+ {blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}
+ |
+ {/if}
+
+ {/if}
+ {if $base}
+
+ |
+
+ .. |
+ |
+
+ {/if}
+ {foreach $files as $file}
+ {aurl 'url', 'IDF_Views_Source::tree', array($project.shortname, $commit, $file.fullpath)}
+
+ |
+
+ {$file.file} |
+ {$file.date|dateago:"wihtout"} |
+ {$file.rev} |
+ {$file.log|nl2br} |
+ {if $file.type == 'blob'}
+ {$file.size|size} |
+ {/if}
+
+
+ {/foreach}
+
+
+ svn checkout {$project.getSvnDaemonUrl()}@{$commit}
+
+
+{/block}
+{block context}
+{trans 'Revison:'} {$commit}
+
+
+{/block}
diff --git a/www/media/idf/css/style.css b/www/media/idf/css/style.css
index 3b39a4f..f83f64f 100644
--- a/www/media/idf/css/style.css
+++ b/www/media/idf/css/style.css
@@ -330,6 +330,11 @@ table.tree-list tfoot th a {
font-weight: normal;
}
+table.tree-list tfoot th ul {
+ text-align: left;
+ font-size: 85%;
+}
+
table.tree-list tr.log {
border-bottom: 1px solid #e7ebe3;
/* background-color: #eef2ea !important; */