| <?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_Scm_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'];␊ | 
| }␊ | 
| }␊ | 
| ␊ |