Added support of subversion.
This commit is contained in:
parent
763d7ca7f6
commit
ccc41c86b0
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
53
src/IDF/ScmFactory.php
Normal file
53
src/IDF/ScmFactory.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2008 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* Manage differents SCM systems
|
||||
*/
|
||||
class IDF_ScmFactory
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns an instance of the correct scm backend object.
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public static function getScm($request=null)
|
||||
{
|
||||
// Get scm type from project conf ; defaults to git
|
||||
$scm = $request->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'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
384
src/IDF/Svn.php
Normal file
384
src/IDF/Svn.php
Normal file
@ -0,0 +1,384 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2008 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* SVN utils.
|
||||
*
|
||||
*/
|
||||
class IDF_Svn
|
||||
{
|
||||
public $repo = '';
|
||||
public $username = '';
|
||||
public $password = '';
|
||||
private $assoc = array('dir' => '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'];
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
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)
|
||||
|
@ -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/$#',
|
||||
|
@ -44,7 +44,7 @@
|
||||
<a accesskey="1" href="{url 'IDF_Views_Project::home', array($project.shortname)}"{block tabhome}{/block}>{trans 'Project Home'}</a>
|
||||
{if $hasIssuesAccess} <a href="{url 'IDF_Views_Issue::index', array($project.shortname)}"{block tabissues}{/block}>{trans 'Issues'}</a>{/if}
|
||||
{if $hasDownloadsAccess} <a href="{url 'IDF_Views_Download::index', array($project.shortname)}"{block tabdownloads}{/block}>{trans 'Downloads'}</a>{/if}
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, 'master')}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $hasSourceAccess} <a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}"{block tabsource}{/block}>{trans 'Source'}</a>{/if}
|
||||
{if $isOwner}
|
||||
<a href="{url 'IDF_Views_Project::admin', array($project.shortname)}"{block tabadmin}{/block}>{trans 'Administer'}</a>{/if}{/if}
|
||||
</div>
|
||||
|
@ -2,8 +2,8 @@
|
||||
{block tabsource} class="active"{/block}
|
||||
{block subtabs}
|
||||
<div id="sub-tabs">
|
||||
<a {if $inSourceTree}class="active" {/if}href="{url 'IDF_Views_Source::treeBase', array($project.shortname, 'master')}">{trans 'Source Tree'}</a> |
|
||||
<a {if $inChangeLog}class="active" {/if}href="{url 'IDF_Views_Source::changeLog', array($project.shortname, 'master')}">{trans 'Change Log'}</a>
|
||||
<a {if $inSourceTree}class="active" {/if}href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $project.getScmRoot())}">{trans 'Source Tree'}</a> |
|
||||
<a {if $inChangeLog}class="active" {/if}href="{url 'IDF_Views_Source::changeLog', array($project.shortname, $project.getScmRoot())}">{trans 'Change Log'}</a>
|
||||
{if $inCommit}| {trans 'Commit'}{/if}
|
||||
</div>
|
||||
{/block}
|
||||
|
@ -29,11 +29,21 @@
|
||||
</table>
|
||||
{/block}
|
||||
{block context}
|
||||
{if $scm == 'git'}
|
||||
<p><strong>{trans 'Branches:'}</strong><br />
|
||||
{foreach $branches as $branch}
|
||||
{aurl 'url', 'IDF_Views_Source::changeLog', array($project.shortname, $branch)}
|
||||
<span class="label{if $commit == $branch} active{/if}"><a href="{$url}" class="label">{$branch}</a></span><br />
|
||||
{/foreach}
|
||||
</p>
|
||||
{/if}
|
||||
{if $scm == 'svn'}
|
||||
<p><strong>{trans 'Revison:'} {$commit}</strong><br />
|
||||
<form class="star" action="{url 'IDF_Views_Source::changelogRev', array($project.shortname)}" method="get">
|
||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="20" />
|
||||
<input type="submit" name="s" value="{trans 'Go to revision'}" />
|
||||
</form>
|
||||
</p>
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
|
@ -36,11 +36,13 @@
|
||||
{/if}
|
||||
{/block}
|
||||
{block context}
|
||||
{if $scm == 'git'}
|
||||
<p><strong>{trans 'Branches:'}</strong><br />
|
||||
{foreach $branches as $branch}
|
||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $branch)}
|
||||
<span class="label{if $commit == $branch} active{/if}"><a href="{$url}" class="label">{$branch}</a></span><br />
|
||||
{/foreach}
|
||||
</p>
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
|
71
src/IDF/templates/source/svn/tree.html
Normal file
71
src/IDF/templates/source/svn/tree.html
Normal file
@ -0,0 +1,71 @@
|
||||
{extends "source/base.html"}
|
||||
{block docclass}yui-t1{assign $inSourceTree=true}{/block}
|
||||
{block body}
|
||||
<h2><a href="{url 'IDF_Views_Source::treeBase', array($project.shortname, $commit)}">{trans 'Root'}</a><span class="sep">/</span>{if $breadcrumb}{$breadcrumb|safe}{/if}</h2>
|
||||
|
||||
<table summary="" class="tree-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{trans 'File'}</th>
|
||||
<th>{trans 'Age'}</th>
|
||||
<th>{trans 'Rev'}</th>
|
||||
<th>{trans 'Message'}</th>
|
||||
<th>{trans 'Size'}</th>
|
||||
</tr>
|
||||
</thead>{if !$tree_in || $props}
|
||||
{aurl 'url', 'IDF_Views_Source::commit', array($project.shortname, $commit)}
|
||||
<tfoot>
|
||||
{if $props}
|
||||
<tr><th colspan="6">
|
||||
<ul>
|
||||
{foreach $props as $prop => $val}
|
||||
<li>{trans 'Property'} <strong>{$prop}</strong> {trans 'set to:'} <em>{$val}</em></li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
</th></tr>
|
||||
{/if}
|
||||
{if !$tree_in}
|
||||
<tr><th colspan="6">{blocktrans}Source at commit <a class="mono" href="{$url}">{$commit}</a> created {$cobject.date|dateago}.{/blocktrans}<br />
|
||||
<span class="smaller">{blocktrans}By {$cobject.author|strip_tags|trim}, {$cobject.title}{/blocktrans}</span>
|
||||
</th></tr>
|
||||
{/if}
|
||||
</tfoot>
|
||||
{/if}<tbody>
|
||||
{if $base}
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>
|
||||
<a href="{url 'IDF_Views_Source::tree', array($project.shortname, $commit, $prev)}">..</a></td>
|
||||
<td colspan="3"></td>
|
||||
</tr>
|
||||
{/if}
|
||||
{foreach $files as $file}
|
||||
{aurl 'url', 'IDF_Views_Source::tree', array($project.shortname, $commit, $file.fullpath)}
|
||||
<tr>
|
||||
<td class="fileicon"><img src="{media '/idf/img/'~$file.type~'.png'}" alt="{$file.type}" /></td>
|
||||
|
||||
<td><a href="{$url}">{$file.file}</a></td>
|
||||
<td><span class="smaller">{$file.date|dateago:"wihtout"}</span></td>
|
||||
<td>{$file.rev}</td>
|
||||
<td{if $file.type != 'blob'} colspan="2"{/if}><span class="smaller">{$file.log|nl2br}</span></td>
|
||||
{if $file.type == 'blob'}
|
||||
<td>{$file.size|size}</td>
|
||||
{/if}
|
||||
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="right soft"><img style="vertical-align: text-bottom;" src="{media '/idf/img/package-grey.png'}" alt="{trans 'Archive'}" align="bottom" /></a> <kbd>svn checkout {$project.getSvnDaemonUrl()}@{$commit}</kbd></p>
|
||||
|
||||
|
||||
{/block}
|
||||
{block context}
|
||||
<p><strong>{trans 'Revison:'} {$commit}</strong><br />
|
||||
<form class="star" action="{url 'IDF_Views_Source::treeRev', array($project.shortname)}" method="get">
|
||||
<input accesskey="4" type="text" value="{$commit}" name="rev" size="20" />
|
||||
<input type="hidden" name="sourcefile" value="{$base}"/>
|
||||
<input type="submit" name="s" value="{trans 'Go to revision'}" />
|
||||
</form>
|
||||
</p>
|
||||
{/block}
|
@ -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; */
|
||||
|
Loading…
Reference in New Issue
Block a user