diff --git a/src/IDF/Git.php b/src/IDF/Git.php deleted file mode 100644 index 316f928..0000000 --- a/src/IDF/Git.php +++ /dev/null @@ -1,321 +0,0 @@ -%nTree: %T%nDate: %ai%n%n%s%n%n%b'; - - public function __construct($repo) - { - $this->repo = $repo; - } - - - /** - * 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, $dummy=null) - { - $cmd = sprintf('GIT_DIR=%s git cat-file -t %s', - escapeshellarg($this->repo), - escapeshellarg($hash)); - $ret = 0; $out = array(); - exec($cmd, &$out, &$ret); - if ($ret != 0) return false; - return trim($out[0]); - } - - /** - * 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($commit='HEAD', $folder='') - { - // now we grab the info about this commit including its tree. - $co = $this->getCommit($commit); - if ($folder) { - // As we are limiting to a given folder, we need to find - // the tree corresponding to this folder. - $found = false; - foreach ($this->getTreeInfo($co->tree) as $file) { - if ($file->type == 'tree' and $file->file == $folder) { - $found = true; - $tree = $file->hash; - break; - } - } - if (!$found) { - throw new Exception(sprintf(__('Folder %1$s not found in commit %2$s.'), $folder, $commit)); - } - } else { - $tree = $co->tree; - } - $res = array(); - // get the raw log corresponding to this commit to find the - // origin of each file. - $rawlog = array(); - $cmd = sprintf('GIT_DIR=%s git log --raw --abbrev=40 --pretty=oneline %s', - escapeshellarg($this->repo), escapeshellarg($commit)); - exec($cmd, &$rawlog); - // We reverse the log to be able to use a fixed efficient - // regex without back tracking. - $rawlog = implode("\n", array_reverse($rawlog)); - foreach ($this->getTreeInfo($tree, false) as $file) { - // Now we grab the files in the current tree with as much - // information as possible. - $matches = array(); - if ($file->type == 'blob' and preg_match('/^\:\d{6} \d{6} [0-9a-f]{40} '.$file->hash.' .*^([0-9a-f]{40})/msU', - $rawlog, &$matches)) { - $fc = $this->getCommit($matches[1]); - $file->date = $fc->date; - $file->log = $fc->title; - } else if ($file->type == 'blob') { - $file->date = $co->date; - $file->log = $co->title; - } - $file->fullpath = ($folder) ? $folder.'/'.$file->file : $file->file; - $res[] = $file; - } - return $res; - } - - /** - * Get the tree info. - * - * @param string Tree hash - * @param bool Do we recurse in subtrees (true) - * @return array Array of file information. - */ - public function getTreeInfo($tree, $recurse=true) - { - if ('tree' != $this->testHash($tree)) { - throw new Exception(sprintf(__('Not a valid tree: %s.'), $tree)); - } - $cmd_tmpl = 'GIT_DIR=%s git-ls-tree%s -t -l %s'; - $cmd = sprintf($cmd_tmpl, - escapeshellarg($this->repo), - ($recurse) ? ' -r' : '', - escapeshellarg($tree)); - $out = array(); - $res = array(); - exec($cmd, &$out); - foreach ($out as $line) { - list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY); - $res[] = (object) array('perm' => $perm, 'type' => $type, - 'size' => $size, 'hash' => $hash, - 'file' => $file); - } - return $res; - } - - - /** - * Get the file info. - * - * @param string File - * @param string Commit ('HEAD') - * @return false Information - */ - public function getFileInfo($totest, $commit='HEAD') - { - $cmd_tmpl = 'GIT_DIR=%s git-ls-tree -r -t -l %s'; - $cmd = sprintf($cmd_tmpl, - escapeshellarg($this->repo), - escapeshellarg($commit)); - $out = array(); - exec($cmd, &$out); - foreach ($out as $line) { - list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY); - if ($totest == $file) { - return (object) array('perm' => $perm, 'type' => $type, - 'size' => $size, 'hash' => $hash, - 'file' => $file); - } - } - return false; - } - - /** - * Get a blob. - * - * @param string Blob hash - * @return string Raw blob - */ - public function getBlob($hash) - { - return shell_exec(sprintf('GIT_DIR=%s git-cat-file blob %s', - escapeshellarg($this->repo), - escapeshellarg($hash))); - } - - /** - * Get the branches. - * - * @return array Branches. - */ - public function getBranches() - { - $out = array(); - exec(sprintf('GIT_DIR=%s git branch', - escapeshellarg($this->repo)), &$out); - $res = array(); - foreach ($out as $b) { - $res[] = substr($b, 2); - } - return $res; - } - - /** - * Get commit details. - * - * @param string Commit ('HEAD'). - * @return array Changes. - */ - public function getCommit($commit='HEAD') - { - $cmd = sprintf('GIT_DIR=%s git show --date=iso --pretty=format:%s %s', - escapeshellarg($this->repo), - "'".$this->mediumtree_fmt."'", - escapeshellarg($commit)); - $out = array(); - exec($cmd, &$out); - $log = array(); - $change = array(); - $inchange = false; - foreach ($out as $line) { - if (!$inchange and 0 === strpos($line, 'diff --git a')) { - $inchange = true; - } - if ($inchange) { - $change[] = $line; - } else { - $log[] = $line; - } - } - $out = self::parseLog($log, 4); - $out[0]->changes = implode("\n", $change); - return $out[0]; - } - - - /** - * Get latest changes. - * - * @param string Commit ('HEAD'). - * @param int Number of changes (10). - * @return array Changes. - */ - public function getChangeLog($commit='HEAD', $n=10) - { - if ($n === null) $n = ''; - else $n = ' -'.$n; - $cmd = sprintf('GIT_DIR=%s git log%s --date=iso --pretty=format:\'%s\' %s', - escapeshellarg($this->repo), $n, $this->mediumtree_fmt, - escapeshellarg($commit)); - $out = array(); - exec($cmd, &$out); - return self::parseLog($out, 4); - } - - /** - * Parse the log lines of a --pretty=medium log output. - * - * @param array Lines. - * @param int Number of lines in the headers (3) - * @return array Change log. - */ - public static function parseLog($lines, $hdrs=3) - { - $res = array(); - $c = array(); - $i = 0; - $hdrs += 2; - foreach ($lines as $line) { - $i++; - if (0 === strpos($line, 'commit')) { - if (count($c) > 0) { - $c['full_message'] = trim($c['full_message']); - $res[] = (object) $c; - } - $c = array(); - $c['commit'] = trim(substr($line, 7)); - $c['full_message'] = ''; - $i=1; - continue; - } - if ($i == $hdrs) { - $c['title'] = trim($line); - continue; - } - $match = array(); - if (preg_match('/(\S+)\s*:\s*(.*)/', $line, $match)) { - $match[1] = strtolower($match[1]); - $c[$match[1]] = trim($match[2]); - if ($match[1] == 'date') { - $c['date'] = gmdate('Y-m-d H:i:s', strtotime($match[2])); - } - continue; - } - if ($i > ($hdrs+1)) { - $c['full_message'] .= trim($line)."\n"; - continue; - } - } - $c['full_message'] = trim($c['full_message']); - - $res[] = (object) $c; - return $res; - } - - /** - * Generate the command to create a zip archive at a given commit. - * - * @param string Commit - * @param string Prefix ('git-repo-dump') - * @return string Command - */ - public function getArchiveCommand($commit, $prefix='git-repo-dump/') - { - return sprintf('GIT_DIR=%s git archive --format=zip --prefix=%s %s', - escapeshellarg($this->repo), - escapeshellarg($prefix), - escapeshellarg($commit)); - } - -} \ No newline at end of file diff --git a/src/IDF/Scm.php b/src/IDF/Scm.php new file mode 100644 index 0000000..5889579 --- /dev/null +++ b/src/IDF/Scm.php @@ -0,0 +1,49 @@ +conf->getVal('scm', 'git')) { + case 'svn': + return new IDF_Scm_Svn($request->conf->getVal('svn_repository'), + $request->conf->getVal('svn_username'), + $request->conf->getVal('svn_password')); + case 'git': + default: + return new IDF_Scm_Git($request->project->getGitRepository()); + } + } +} + diff --git a/src/IDF/Scm/Git.php b/src/IDF/Scm/Git.php new file mode 100644 index 0000000..09fb0f9 --- /dev/null +++ b/src/IDF/Scm/Git.php @@ -0,0 +1,321 @@ +%nTree: %T%nDate: %ai%n%n%s%n%n%b'; + + public function __construct($repo) + { + $this->repo = $repo; + } + + + /** + * 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, $dummy=null) + { + $cmd = sprintf('GIT_DIR=%s git cat-file -t %s', + escapeshellarg($this->repo), + escapeshellarg($hash)); + $ret = 0; $out = array(); + exec($cmd, &$out, &$ret); + if ($ret != 0) return false; + return trim($out[0]); + } + + /** + * 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($commit='HEAD', $folder='') + { + // now we grab the info about this commit including its tree. + $co = $this->getCommit($commit); + if ($folder) { + // As we are limiting to a given folder, we need to find + // the tree corresponding to this folder. + $found = false; + foreach ($this->getTreeInfo($co->tree) as $file) { + if ($file->type == 'tree' and $file->file == $folder) { + $found = true; + $tree = $file->hash; + break; + } + } + if (!$found) { + throw new Exception(sprintf(__('Folder %1$s not found in commit %2$s.'), $folder, $commit)); + } + } else { + $tree = $co->tree; + } + $res = array(); + // get the raw log corresponding to this commit to find the + // origin of each file. + $rawlog = array(); + $cmd = sprintf('GIT_DIR=%s git log --raw --abbrev=40 --pretty=oneline %s', + escapeshellarg($this->repo), escapeshellarg($commit)); + exec($cmd, &$rawlog); + // We reverse the log to be able to use a fixed efficient + // regex without back tracking. + $rawlog = implode("\n", array_reverse($rawlog)); + foreach ($this->getTreeInfo($tree, false) as $file) { + // Now we grab the files in the current tree with as much + // information as possible. + $matches = array(); + if ($file->type == 'blob' and preg_match('/^\:\d{6} \d{6} [0-9a-f]{40} '.$file->hash.' .*^([0-9a-f]{40})/msU', + $rawlog, &$matches)) { + $fc = $this->getCommit($matches[1]); + $file->date = $fc->date; + $file->log = $fc->title; + } else if ($file->type == 'blob') { + $file->date = $co->date; + $file->log = $co->title; + } + $file->fullpath = ($folder) ? $folder.'/'.$file->file : $file->file; + $res[] = $file; + } + return $res; + } + + /** + * Get the tree info. + * + * @param string Tree hash + * @param bool Do we recurse in subtrees (true) + * @return array Array of file information. + */ + public function getTreeInfo($tree, $recurse=true) + { + if ('tree' != $this->testHash($tree)) { + throw new Exception(sprintf(__('Not a valid tree: %s.'), $tree)); + } + $cmd_tmpl = 'GIT_DIR=%s git-ls-tree%s -t -l %s'; + $cmd = sprintf($cmd_tmpl, + escapeshellarg($this->repo), + ($recurse) ? ' -r' : '', + escapeshellarg($tree)); + $out = array(); + $res = array(); + exec($cmd, &$out); + foreach ($out as $line) { + list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY); + $res[] = (object) array('perm' => $perm, 'type' => $type, + 'size' => $size, 'hash' => $hash, + 'file' => $file); + } + return $res; + } + + + /** + * Get the file info. + * + * @param string File + * @param string Commit ('HEAD') + * @return false Information + */ + public function getFileInfo($totest, $commit='HEAD') + { + $cmd_tmpl = 'GIT_DIR=%s git-ls-tree -r -t -l %s'; + $cmd = sprintf($cmd_tmpl, + escapeshellarg($this->repo), + escapeshellarg($commit)); + $out = array(); + exec($cmd, &$out); + foreach ($out as $line) { + list($perm, $type, $hash, $size, $file) = preg_split('/ |\t/', $line, 5, PREG_SPLIT_NO_EMPTY); + if ($totest == $file) { + return (object) array('perm' => $perm, 'type' => $type, + 'size' => $size, 'hash' => $hash, + 'file' => $file); + } + } + return false; + } + + /** + * Get a blob. + * + * @param string Blob hash + * @return string Raw blob + */ + public function getBlob($hash) + { + return shell_exec(sprintf('GIT_DIR=%s git-cat-file blob %s', + escapeshellarg($this->repo), + escapeshellarg($hash))); + } + + /** + * Get the branches. + * + * @return array Branches. + */ + public function getBranches() + { + $out = array(); + exec(sprintf('GIT_DIR=%s git branch', + escapeshellarg($this->repo)), &$out); + $res = array(); + foreach ($out as $b) { + $res[] = substr($b, 2); + } + return $res; + } + + /** + * Get commit details. + * + * @param string Commit ('HEAD'). + * @return array Changes. + */ + public function getCommit($commit='HEAD') + { + $cmd = sprintf('GIT_DIR=%s git show --date=iso --pretty=format:%s %s', + escapeshellarg($this->repo), + "'".$this->mediumtree_fmt."'", + escapeshellarg($commit)); + $out = array(); + exec($cmd, &$out); + $log = array(); + $change = array(); + $inchange = false; + foreach ($out as $line) { + if (!$inchange and 0 === strpos($line, 'diff --git a')) { + $inchange = true; + } + if ($inchange) { + $change[] = $line; + } else { + $log[] = $line; + } + } + $out = self::parseLog($log, 4); + $out[0]->changes = implode("\n", $change); + return $out[0]; + } + + + /** + * Get latest changes. + * + * @param string Commit ('HEAD'). + * @param int Number of changes (10). + * @return array Changes. + */ + public function getChangeLog($commit='HEAD', $n=10) + { + if ($n === null) $n = ''; + else $n = ' -'.$n; + $cmd = sprintf('GIT_DIR=%s git log%s --date=iso --pretty=format:\'%s\' %s', + escapeshellarg($this->repo), $n, $this->mediumtree_fmt, + escapeshellarg($commit)); + $out = array(); + exec($cmd, &$out); + return self::parseLog($out, 4); + } + + /** + * Parse the log lines of a --pretty=medium log output. + * + * @param array Lines. + * @param int Number of lines in the headers (3) + * @return array Change log. + */ + public static function parseLog($lines, $hdrs=3) + { + $res = array(); + $c = array(); + $i = 0; + $hdrs += 2; + foreach ($lines as $line) { + $i++; + if (0 === strpos($line, 'commit')) { + if (count($c) > 0) { + $c['full_message'] = trim($c['full_message']); + $res[] = (object) $c; + } + $c = array(); + $c['commit'] = trim(substr($line, 7)); + $c['full_message'] = ''; + $i=1; + continue; + } + if ($i == $hdrs) { + $c['title'] = trim($line); + continue; + } + $match = array(); + if (preg_match('/(\S+)\s*:\s*(.*)/', $line, $match)) { + $match[1] = strtolower($match[1]); + $c[$match[1]] = trim($match[2]); + if ($match[1] == 'date') { + $c['date'] = gmdate('Y-m-d H:i:s', strtotime($match[2])); + } + continue; + } + if ($i > ($hdrs+1)) { + $c['full_message'] .= trim($line)."\n"; + continue; + } + } + $c['full_message'] = trim($c['full_message']); + + $res[] = (object) $c; + return $res; + } + + /** + * Generate the command to create a zip archive at a given commit. + * + * @param string Commit + * @param string Prefix ('git-repo-dump') + * @return string Command + */ + public function getArchiveCommand($commit, $prefix='git-repo-dump/') + { + return sprintf('GIT_DIR=%s git archive --format=zip --prefix=%s %s', + escapeshellarg($this->repo), + escapeshellarg($prefix), + escapeshellarg($commit)); + } + +} \ No newline at end of file diff --git a/src/IDF/Scm/Svn.php b/src/IDF/Scm/Svn.php new file mode 100644 index 0000000..e094d88 --- /dev/null +++ b/src/IDF/Scm/Svn.php @@ -0,0 +1,382 @@ + '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/ScmFactory.php b/src/IDF/ScmFactory.php deleted file mode 100644 index d2d8a7f..0000000 --- a/src/IDF/ScmFactory.php +++ /dev/null @@ -1,49 +0,0 @@ -conf->getVal('scm', 'git')) { - case 'svn': - return new IDF_Svn($request->conf->getVal('svn_repository'), - $request->conf->getVal('svn_username'), - $request->conf->getVal('svn_password')); - case 'git': - default: - return new IDF_Git($request->project->getGitRepository()); - } - } -} - diff --git a/src/IDF/Svn.php b/src/IDF/Svn.php deleted file mode 100644 index fc3f4c0..0000000 --- a/src/IDF/Svn.php +++ /dev/null @@ -1,382 +0,0 @@ - '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/Template/IssueComment.php b/src/IDF/Template/IssueComment.php index 9023801..1b7d957 100644 --- a/src/IDF/Template/IssueComment.php +++ b/src/IDF/Template/IssueComment.php @@ -30,13 +30,13 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag { private $project = null; private $request = null; - private $git = null; + private $scm = null; function start($text, $request) { $this->project = $request->project; $this->request = $request; - $this->git = new IDF_Git($this->project->getGitRepository()); + $this->scm = IDF_Scm::get($request); $text = wordwrap($text, 69, "\n", true); $text = Pluf_esc($text); $text = ereg_replace('[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]', @@ -47,7 +47,7 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag array($this, 'callbackIssues'), $text); } if ($request->rights['hasSourceAccess']) { - $text = preg_replace_callback('#(commit\s+)([0-9a-f]{5,40})#im', + $text = preg_replace_callback('#(commit\s+)([0-9a-f]{1,40})#im', array($this, 'callbackCommit'), $text); } echo $text; @@ -90,10 +90,10 @@ class IDF_Template_IssueComment extends Pluf_Template_Tag function callbackCommit($m) { - if ($this->git->testHash($m[2]) != 'commit') { + if ($this->scm->testHash($m[2]) != 'commit') { return $m[0]; } - $co = $this->git->getCommit($m[2]); + $co = $this->scm->getCommit($m[2]); return ''.$m[1].$m[2].''; } diff --git a/src/IDF/Views/Source.php b/src/IDF/Views/Source.php index ff79309..ae07c1e 100644 --- a/src/IDF/Views/Source.php +++ b/src/IDF/Views/Source.php @@ -36,7 +36,7 @@ class IDF_Views_Source { $title = sprintf(__('%s %s Change Log'), (string) $request->project, $this->getScmType($request)); - $scm = IDF_ScmFactory::getScm($request); + $scm = IDF_Scm::get($request); $branches = $scm->getBranches(); $commit = $match[2]; $res = $scm->getChangeLog($commit, 25); @@ -58,7 +58,7 @@ class IDF_Views_Source { $title = sprintf(__('%s %s Source Tree'), (string) $request->project, $this->getScmType($request)); - $scm = IDF_ScmFactory::getScm($request); + $scm = IDF_Scm::get($request); $commit = $match[2]; $branches = $scm->getBranches(); if ('commit' != $scm->testHash($commit)) { @@ -96,7 +96,7 @@ class IDF_Views_Source { $title = sprintf(__('%s %s Source Tree'), (string) $request->project, $this->getScmType($request)); - $scm = IDF_ScmFactory::getScm($request); + $scm = IDF_Scm::get($request); $branches = $scm->getBranches(); $commit = $match[2]; $request_file = $match[3]; @@ -179,7 +179,7 @@ class IDF_Views_Source public $commit_precond = array('IDF_Precondition::accessSource'); public function commit($request, $match) { - $scm = IDF_ScmFactory::getScm($request); + $scm = IDF_Scm::get($request); $commit = $match[2]; $branches = $scm->getBranches(); if ('commit' != $scm->testHash($commit)) { @@ -216,7 +216,7 @@ class IDF_Views_Source public function download($request, $match) { $commit = trim($match[2]); - $scm = IDF_ScmFactory::getScm($request); + $scm = IDF_Scm::get($request); $branches = $scm->getBranches(); if ('commit' != $scm->testHash($commit)) { // Redirect to the first branch