| }␊ | 
| ␊ | 
| /**␊ | 
| * Returns the revision in which the file has been last changed,␊ | 
| * starting from the start rev␊ | 
| *␊ | 
| * @param string␊ | 
| * @param string␊ | 
| * @return string␊ | 
| */␊ | 
| private function _getLastChangeFor($file, $startrev)␊ | 
| {␊ | 
| $out = $this->stdio->exec(array(␊ | 
| 'get_content_changed', $startrev, $file␊ | 
| ));␊ | 
| ␊ | 
| $stanzas = IDF_Scm_Monotone_BasicIO::parse($out);␊ | 
| ␊ | 
| // FIXME: we only care about the first returned content mark␊ | 
| // everything else seem to be very, very rare cases␊ | 
| foreach ($stanzas as $stanza) {␊ | 
| foreach ($stanza as $stanzaline) {␊ | 
| if ($stanzaline['key'] == 'content_mark') {␊ | 
| return $stanzaline['hash'];␊ | 
| }␊ | 
| }␊ | 
| }␊ | 
| return null;␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * @see IDF_Scm::inBranches()␊ | 
| */␊ | 
| public function inBranches($commit, $path)␊ | 
|  | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Takes a single stanza coming from an extended manifest output␊ | 
| * and converts it into a file structure used by IDF␊ | 
| *␊ | 
| * @param string $forceBasedir  If given then the element's path is checked␊ | 
| *                              to be directly beneath the given directory.␊ | 
| *                              If not, null is returned and the parsing is␊ | 
| *                              aborted.␊ | 
| * @return array | null␊ | 
| */␊ | 
| private function _fillFileEntry(array $manifestEntry, $forceBasedir = null)␊ | 
| {␊ | 
| $fullpath = $manifestEntry[0]['values'][0];␊ | 
| $filename = basename($fullpath);␊ | 
| $dirname = dirname($fullpath);␊ | 
| $dirname = $dirname == '.' ? '' : $dirname;␊ | 
| ␊ | 
| if ($forceBasedir !== null && $forceBasedir != $dirname) {␊ | 
| return null;␊ | 
| }␊ | 
| ␊ | 
| $file = array();␊ | 
| $file['file'] = $filename;␊ | 
| $file['fullpath'] = $fullpath;␊ | 
| $file['efullpath'] = self::smartEncode($fullpath);␊ | 
| ␊ | 
| $wanted_mark = '';␊ | 
| if ($manifestEntry[0]['key'] == 'dir') {␊ | 
| $file['type'] = 'tree';␊ | 
| $file['size'] = 0;␊ | 
| $wanted_mark = 'path_mark';␊ | 
| }␊ | 
| else {␊ | 
| $file['type'] = 'blob';␊ | 
| $file['hash'] = $manifestEntry[1]['hash'];␊ | 
| $size = 0;␊ | 
| foreach ($manifestEntry as $line) {␊ | 
| if ($line['key'] == 'size') {␊ | 
| $size = $line['values'][0];␊ | 
| break;␊ | 
| }␊ | 
| }␊ | 
| $file['size'] = $size;␊ | 
| $wanted_mark = 'content_mark';␊ | 
| }␊ | 
| ␊ | 
| $rev_mark = null;␊ | 
| foreach ($manifestEntry as $line) {␊ | 
| if ($line['key'] == $wanted_mark) {␊ | 
| $rev_mark = $line['hash'];␊ | 
| break;␊ | 
| }␊ | 
| }␊ | 
| ␊ | 
| if ($rev_mark !== null) {␊ | 
| $file['rev'] = $rev_mark;␊ | 
| $certs = $this->_getCerts($rev_mark);␊ | 
| ␊ | 
| // FIXME: this assumes that author, date and changelog are always given␊ | 
| $file['author'] = implode(", ", $certs['author']);␊ | 
| ␊ | 
| $dates = array();␊ | 
| foreach ($certs['date'] as $date)␊ | 
| $dates[] = date('Y-m-d H:i:s', strtotime($date));␊ | 
| $file['date'] = implode(', ', $dates);␊ | 
| $combinedChangelog = implode("\n---\n", $certs['changelog']);␊ | 
| $split = preg_split("/[\n\r]/", $combinedChangelog, 2);␊ | 
| // FIXME: the complete log message is currently not used in the␊ | 
| // tree view (the same is true for the other SCM implementations)␊ | 
| // but we _should_ really use or at least return that here␊ | 
| // in case we want to do fancy stuff like described in␊ | 
| // issue 492␊ | 
| $file['log'] =  $split[0];␊ | 
| }␊ | 
| ␊ | 
| return $file;␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * @see IDF_Scm::getTree()␊ | 
| */␊ | 
| public function getTree($commit, $folder='/', $branch=null)␊ | 
|  | 
| }␊ | 
| ␊ | 
| $out = $this->stdio->exec(array(␊ | 
| 'get_manifest_of', $revs[0]␊ | 
| 'get_extended_manifest_of', $revs[0]␊ | 
| ));␊ | 
| ␊ | 
| $files = array();␊ | 
| $stanzas = IDF_Scm_Monotone_BasicIO::parse($out);␊ | 
| $folder = $folder == '/' || empty($folder) ? '' : $folder.'/';␊ | 
| $folder = $folder == '/' || empty($folder) ? '' : $folder;␊ | 
| ␊ | 
| foreach ($stanzas as $stanza) {␊ | 
| if ($stanza[0]['key'] == 'format_version')␊ | 
| continue;␊ | 
| ␊ | 
| $path = $stanza[0]['values'][0];␊ | 
| if (!preg_match('#^'.$folder.'([^/]+)$#', $path, $m))␊ | 
| $file = $this->_fillFileEntry($stanza, $folder);␊ | 
| if ($file === null)␊ | 
| continue;␊ | 
| ␊ | 
| $file = array();␊ | 
| $file['file'] = $m[1];␊ | 
| $file['fullpath'] = $path;␊ | 
| $file['efullpath'] = self::smartEncode($path);␊ | 
| ␊ | 
| if ($stanza[0]['key'] == 'dir') {␊ | 
| $file['type'] = 'tree';␊ | 
| $file['size'] = 0;␊ | 
| }␊ | 
| else␊ | 
| {␊ | 
| $file['type'] = 'blob';␊ | 
| $file['hash'] = $stanza[1]['hash'];␊ | 
| $file['size'] = strlen($this->getFile((object)$file));␊ | 
| }␊ | 
| ␊ | 
| $rev = $this->_getLastChangeFor($file['fullpath'], $revs[0]);␊ | 
| if ($rev !== null) {␊ | 
| $file['rev'] = $rev;␊ | 
| $certs = $this->_getCerts($rev);␊ | 
| ␊ | 
| // FIXME: this assumes that author, date and changelog are always given␊ | 
| $file['author'] = implode(", ", $certs['author']);␊ | 
| ␊ | 
| $dates = array();␊ | 
| foreach ($certs['date'] as $date)␊ | 
| $dates[] = date('Y-m-d H:i:s', strtotime($date));␊ | 
| $file['date'] = implode(', ', $dates);␊ | 
| $combinedChangelog = implode("\n---\n", $certs['changelog']);␊ | 
| $split = preg_split("/[\n\r]/", $combinedChangelog, 2);␊ | 
| // FIXME: the complete log message is currently not used in the␊ | 
| // tree view (the same is true for the other SCM implementations)␊ | 
| // but we _should_ really use or at least return that here␊ | 
| // in case we want to do fancy stuff like described in␊ | 
| // issue 492␊ | 
| $file['log'] =  $split[0];␊ | 
| }␊ | 
| ␊ | 
| $files[] = (object) $file;␊ | 
| }␊ | 
| return $files;␊ | 
|  | 
| return false;␊ | 
| ␊ | 
| $out = $this->stdio->exec(array(␊ | 
| 'get_manifest_of', $revs[0]␊ | 
| 'get_extended_manifest_of', $revs[0]␊ | 
| ));␊ | 
| ␊ | 
| $files = array();␊ | 
|  | 
| if ($stanza[0]['key'] == 'format_version')␊ | 
| continue;␊ | 
| ␊ | 
| $path = $stanza[0]['values'][0];␊ | 
| if (!preg_match('#^'.$file.'$#', $path, $m))␊ | 
| if ($stanza[0]['values'][0] != $file)␊ | 
| continue;␊ | 
| ␊ | 
| $file = array();␊ | 
| $file['fullpath'] = $path;␊ | 
| ␊ | 
| if ($stanza[0]['key'] == "dir") {␊ | 
| $file['type'] = "tree";␊ | 
| $file['hash'] = null;␊ | 
| $file['size'] = 0;␊ | 
| }␊ | 
| else␊ | 
| {␊ | 
| $file['type'] = 'blob';␊ | 
| $file['hash'] = $stanza[1]['hash'];␊ | 
| $file['size'] = strlen($this->getFile((object)$file));␊ | 
| }␊ | 
| ␊ | 
| $pathinfo = pathinfo($file['fullpath']);␊ | 
| $file['file'] = $pathinfo['basename'];␊ | 
| ␊ | 
| $rev = $this->_getLastChangeFor($file['fullpath'], $revs[0]);␊ | 
| if ($rev !== null) {␊ | 
| $file['rev'] = $rev;␊ | 
| $certs = $this->_getCerts($rev);␊ | 
| ␊ | 
| // FIXME: this assumes that author, date and changelog are always given␊ | 
| $file['author'] = implode(", ", $certs['author']);␊ | 
| ␊ | 
| $dates = array();␊ | 
| foreach ($certs['date'] as $date)␊ | 
| $dates[] = date('Y-m-d H:i:s', strtotime($date));␊ | 
| $file['date'] = implode(', ', $dates);␊ | 
| $file['log'] = implode("\n---\n", $certs['changelog']);␊ | 
| }␊ | 
| ␊ | 
| ␊ | 
| $file = $this->_fillFileEntry($stanza);␊ | 
| return (object) $file;␊ | 
| }␊ | 
| return false;␊ |