| // FIXME: this obviously won't work with remote databases - upstream␊ |
| // needs to implement mtn db info in automate at first␊ |
| $repo = sprintf(Pluf::f('mtn_repositories'), $this->project->shortname);␊ |
| if (!file_exists($repo))␊ |
| {␊ |
| if (!file_exists($repo)) {␊ |
| return 0;␊ |
| }␊ |
| ␊ |
|
| {␊ |
| try␊ |
| {␊ |
| $out = $this->stdio->exec(array("interface_version"));␊ |
| $out = $this->stdio->exec(array('interface_version'));␊ |
| return floatval($out) >= self::$MIN_INTERFACE_VERSION;␊ |
| }␊ |
| catch (IDF_Scm_Exception $e) {}␊ |
|
| }␊ |
| // FIXME: we could / should introduce handling of suspended␊ |
| // (i.e. dead) branches here by hiding them from the user's eye...␊ |
| $out = $this->stdio->exec(array("branches"));␊ |
| $out = $this->stdio->exec(array('branches'));␊ |
| ␊ |
| // note: we could expand each branch with one of its head revisions␊ |
| // here, but these would soon become bogus anyway and we cannot␊ |
| // map multiple head revisions here either, so we just use the␊ |
| // selector as placeholder␊ |
| $res = array();␊ |
| foreach (preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY) as $b)␊ |
| {␊ |
| foreach (preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY) as $b) {␊ |
| $res["h:$b"] = $b;␊ |
| }␊ |
| ␊ |
|
| $branch = "*";␊ |
| }␊ |
| ␊ |
| if (count($this->_resolveSelector("h:$branch")) == 0)␊ |
| {␊ |
| if (count($this->_resolveSelector("h:$branch")) == 0) {␊ |
| throw new IDF_Scm_Exception(␊ |
| "Branch $branch is empty"␊ |
| );␊ |
|
| */␊ |
| private function _resolveSelector($selector)␊ |
| {␊ |
| $out = $this->stdio->exec(array("select", $selector));␊ |
| $out = $this->stdio->exec(array('select', $selector));␊ |
| return preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY);␊ |
| }␊ |
| ␊ |
|
| $pos = 0;␊ |
| $stanzas = array();␊ |
| ␊ |
| while ($pos < strlen($in))␊ |
| {␊ |
| while ($pos < strlen($in)) {␊ |
| $stanza = array();␊ |
| while ($pos < strlen($in))␊ |
| {␊ |
| while ($pos < strlen($in)) {␊ |
| if ($in[$pos] == "\n") break;␊ |
| ␊ |
| $stanzaLine = array("key" => "", "values" => array(), "hash" => null);␊ |
| while ($pos < strlen($in))␊ |
| {␊ |
| $stanzaLine = array('key' => '', 'values' => array(), 'hash' => null);␊ |
| while ($pos < strlen($in)) {␊ |
| $ch = $in[$pos];␊ |
| if ($ch == '"' || $ch == '[') break;␊ |
| ++$pos;␊ |
|
| $stanzaLine['key'] .= $ch;␊ |
| }␊ |
| ␊ |
| if ($in[$pos] == '[')␊ |
| {␊ |
| if ($in[$pos] == '[') {␊ |
| ++$pos; // opening square bracket␊ |
| $stanzaLine['hash'] = substr($in, $pos, 40);␊ |
| $pos += 40;␊ |
|
| else␊ |
| {␊ |
| $valCount = 0;␊ |
| while ($in[$pos] == '"')␊ |
| {␊ |
| while ($in[$pos] == '"') {␊ |
| ++$pos; // opening quote␊ |
| $stanzaLine['values'][$valCount] = "";␊ |
| while ($pos < strlen($in))␊ |
| {␊ |
| $stanzaLine['values'][$valCount] = '';␊ |
| while ($pos < strlen($in)) {␊ |
| $ch = $in[$pos]; $pr = $in[$pos-1];␊ |
| if ($ch == '"' && $pr != '\\') break;␊ |
| ++$pos;␊ |
|
| }␊ |
| ++$pos; // closing quote␊ |
| ␊ |
| if ($in[$pos] == ' ')␊ |
| {␊ |
| if ($in[$pos] == ' ') {␊ |
| ++$pos; // space␊ |
| ++$valCount;␊ |
| }␊ |
| }␊ |
| ␊ |
| for ($i = 0; $i <= $valCount; $i++)␊ |
| {␊ |
| for ($i = 0; $i <= $valCount; $i++) {␊ |
| $stanzaLine['values'][$i] = str_replace(␊ |
| array("\\\\", "\\\""),␊ |
| array("\\", "\""),␊ |
|
| {␊ |
| static $certCache = array();␊ |
| ␊ |
| if (!array_key_exists($rev, $certCache))␊ |
| {␊ |
| $out = $this->stdio->exec(array("certs", $rev));␊ |
| if (!array_key_exists($rev, $certCache)) {␊ |
| $out = $this->stdio->exec(array('certs', $rev));␊ |
| ␊ |
| $stanzas = self::_parseBasicIO($out);␊ |
| $certs = array();␊ |
| foreach ($stanzas as $stanza)␊ |
| {␊ |
| foreach ($stanzas as $stanza) {␊ |
| $certname = null;␊ |
| foreach ($stanza as $stanzaline)␊ |
| {␊ |
| foreach ($stanza as $stanzaline) {␊ |
| // luckily, name always comes before value␊ |
| if ($stanzaline['key'] == "name")␊ |
| {␊ |
| if ($stanzaline['key'] == 'name') {␊ |
| $certname = $stanzaline['values'][0];␊ |
| continue;␊ |
| }␊ |
| ␊ |
| if ($stanzaline['key'] == "value")␊ |
| {␊ |
| if (!array_key_exists($certname, $certs))␊ |
| {␊ |
| if ($stanzaline['key'] == 'value') {␊ |
| if (!array_key_exists($certname, $certs)) {␊ |
| $certs[$certname] = array();␊ |
| }␊ |
| ␊ |
|
| private function _getUniqueCertValuesFor($revs, $certName, $prefix)␊ |
| {␊ |
| $certValues = array();␊ |
| foreach ($revs as $rev)␊ |
| {␊ |
| foreach ($revs as $rev) {␊ |
| $certs = $this->_getCerts($rev);␊ |
| if (!array_key_exists($certName, $certs))␊ |
| continue;␊ |
| foreach ($certs[$certName] as $certValue)␊ |
| {␊ |
| foreach ($certs[$certName] as $certValue) {␊ |
| $certValues[] = "$prefix$certValue";␊ |
| }␊ |
| }␊ |
|
| private function _getLastChangeFor($file, $startrev)␊ |
| {␊ |
| $out = $this->stdio->exec(array(␊ |
| "get_content_changed", $startrev, $file␊ |
| 'get_content_changed', $startrev, $file␊ |
| ));␊ |
| ␊ |
| $stanzas = self::_parseBasicIO($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")␊ |
| {␊ |
| foreach ($stanzas as $stanza) {␊ |
| foreach ($stanza as $stanzaline) {␊ |
| if ($stanzaline['key'] == 'content_mark') {␊ |
| return $stanzaline['hash'];␊ |
| }␊ |
| }␊ |
|
| {␊ |
| $revs = $this->_resolveSelector($commit);␊ |
| if (count($revs) == 0) return array();␊ |
| return $this->_getUniqueCertValuesFor($revs, "branch", "h:");␊ |
| return $this->_getUniqueCertValuesFor($revs, 'branch', 'h:');␊ |
| }␊ |
| ␊ |
| /**␊ |
|
| */␊ |
| public function getTags()␊ |
| {␊ |
| if (isset($this->cache['tags']))␊ |
| {␊ |
| if (isset($this->cache['tags'])) {␊ |
| return $this->cache['tags'];␊ |
| }␊ |
| ␊ |
| $out = $this->stdio->exec(array("tags"));␊ |
| $out = $this->stdio->exec(array('tags'));␊ |
| ␊ |
| $tags = array();␊ |
| $stanzas = self::_parseBasicIO($out);␊ |
| foreach ($stanzas as $stanza)␊ |
| {␊ |
| foreach ($stanzas as $stanza) {␊ |
| $tagname = null;␊ |
| foreach ($stanza as $stanzaline)␊ |
| {␊ |
| foreach ($stanza as $stanzaline) {␊ |
| // revision comes directly after the tag stanza␊ |
| if ($stanzaline['key'] == "tag")␊ |
| {␊ |
| if ($stanzaline['key'] == 'tag') {␊ |
| $tagname = $stanzaline['values'][0];␊ |
| continue;␊ |
| }␊ |
| if ($stanzaline['key'] == "revision")␊ |
| {␊ |
| if ($stanzaline['key'] == 'revision') {␊ |
| // FIXME: warn if multiple revisions have␊ |
| // equally named tags␊ |
| if (!array_key_exists("t:$tagname", $tags))␊ |
| {␊ |
| if (!array_key_exists("t:$tagname", $tags)) {␊ |
| $tags["t:$tagname"] = $tagname;␊ |
| }␊ |
| break;␊ |
|
| {␊ |
| $revs = $this->_resolveSelector($commit);␊ |
| if (count($revs) == 0) return array();␊ |
| return $this->_getUniqueCertValuesFor($revs, "tag", "t:");␊ |
| return $this->_getUniqueCertValuesFor($revs, 'tag', 't:');␊ |
| }␊ |
| ␊ |
| /**␊ |
|
| public function getTree($commit, $folder='/', $branch=null)␊ |
| {␊ |
| $revs = $this->_resolveSelector($commit);␊ |
| if (count($revs) == 0)␊ |
| {␊ |
| if (count($revs) == 0) {␊ |
| return array();␊ |
| }␊ |
| ␊ |
| $out = $this->stdio->exec(array(␊ |
| "get_manifest_of", $revs[0]␊ |
| 'get_manifest_of', $revs[0]␊ |
| ));␊ |
| ␊ |
| $files = array();␊ |
| $stanzas = self::_parseBasicIO($out);␊ |
| $folder = $folder == '/' || empty($folder) ? '' : $folder.'/';␊ |
| ␊ |
| foreach ($stanzas as $stanza)␊ |
| {␊ |
| if ($stanza[0]['key'] == "format_version")␊ |
| foreach ($stanzas as $stanza) {␊ |
| if ($stanza[0]['key'] == 'format_version')␊ |
| continue;␊ |
| ␊ |
| $path = $stanza[0]['values'][0];␊ |
|
| $file['fullpath'] = $path;␊ |
| $file['efullpath'] = self::smartEncode($path);␊ |
| ␊ |
| if ($stanza[0]['key'] == "dir")␊ |
| {␊ |
| $file['type'] = "tree";␊ |
| if ($stanza[0]['key'] == 'dir') {␊ |
| $file['type'] = 'tree';␊ |
| $file['size'] = 0;␊ |
| }␊ |
| else␊ |
| {␊ |
| $file['type'] = "blob";␊ |
| $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)␊ |
| {␊ |
| if ($rev !== null) {␊ |
| $file['rev'] = $rev;␊ |
| $certs = $this->_getCerts($rev);␊ |
| ␊ |
|
| $scm = IDF_Scm::get($project);␊ |
| $branch = $scm->getMainBranch();␊ |
| ␊ |
| if (!empty($commit))␊ |
| {␊ |
| if (!empty($commit)) {␊ |
| $revs = $scm->_resolveSelector($commit);␊ |
| if (count($revs) > 0)␊ |
| {␊ |
| if (count($revs) > 0) {␊ |
| $certs = $scm->_getCerts($revs[0]);␊ |
| // for the very seldom case that a revision␊ |
| // has no branch certificate␊ |
| if (count($certs['branch']) == 0)␊ |
| {␊ |
| $branch = "*";␊ |
| if (count($certs['branch']) == 0) {␊ |
| $branch = '*';␊ |
| }␊ |
| else␊ |
| {␊ |
|
| }␊ |
| ␊ |
| $remote_url = Pluf::f('mtn_remote_url', '');␊ |
| if (empty($remote_url))␊ |
| {␊ |
| if (empty($remote_url)) {␊ |
| return '';␊ |
| }␊ |
| ␊ |
| return sprintf($remote_url, $project->shortname)."?".$branch;␊ |
| return sprintf($remote_url, $project->shortname).'?'.$branch;␊ |
| }␊ |
| ␊ |
| /**␊ |
|
| */␊ |
| public static function factory($project)␊ |
| {␊ |
| if (!array_key_exists($project->shortname, self::$instances))␊ |
| {␊ |
| if (!array_key_exists($project->shortname, self::$instances)) {␊ |
| self::$instances[$project->shortname] =␊ |
| new IDF_Scm_Monotone($project);␊ |
| }␊ |
|
| return false;␊ |
| ␊ |
| $out = $this->stdio->exec(array(␊ |
| "get_manifest_of", $revs[0]␊ |
| 'get_manifest_of', $revs[0]␊ |
| ));␊ |
| ␊ |
| $files = array();␊ |
| $stanzas = self::_parseBasicIO($out);␊ |
| ␊ |
| foreach ($stanzas as $stanza)␊ |
| {␊ |
| if ($stanza[0]['key'] == "format_version")␊ |
| foreach ($stanzas as $stanza) {␊ |
| if ($stanza[0]['key'] == 'format_version')␊ |
| continue;␊ |
| ␊ |
| $path = $stanza[0]['values'][0];␊ |
|
| $file = array();␊ |
| $file['fullpath'] = $path;␊ |
| ␊ |
| if ($stanza[0]['key'] == "dir")␊ |
| {␊ |
| if ($stanza[0]['key'] == "dir") {␊ |
| $file['type'] = "tree";␊ |
| $file['hash'] = null;␊ |
| $file['size'] = 0;␊ |
| }␊ |
| else␊ |
| {␊ |
| $file['type'] = "blob";␊ |
| $file['type'] = 'blob';␊ |
| $file['hash'] = $stanza[1]['hash'];␊ |
| $file['size'] = strlen($this->getFile((object)$file));␊ |
| }␊ |
|
| $file['file'] = $pathinfo['basename'];␊ |
| ␊ |
| $rev = $this->_getLastChangeFor($file['fullpath'], $revs[0]);␊ |
| if ($rev !== null)␊ |
| {␊ |
| if ($rev !== null) {␊ |
| $file['rev'] = $rev;␊ |
| $certs = $this->_getCerts($rev);␊ |
| ␊ |
|
| public function getFile($def, $cmd_only=false)␊ |
| {␊ |
| // this won't work with remote databases␊ |
| if ($cmd_only)␊ |
| {␊ |
| if ($cmd_only) {␊ |
| throw new Pluf_Exception_NotImplemented();␊ |
| }␊ |
| ␊ |
| return $this->stdio->exec(array("get_file", $def->hash));␊ |
| return $this->stdio->exec(array('get_file', $def->hash));␊ |
| }␊ |
| ␊ |
| /**␊ |
|
| */␊ |
| private function _getDiff($target, $source = null)␊ |
| {␊ |
| if (empty($source))␊ |
| {␊ |
| if (empty($source)) {␊ |
| $source = "p:$target";␊ |
| }␊ |
| ␊ |
|
| $targets = $this->_resolveSelector($target);␊ |
| $sources = $this->_resolveSelector($source);␊ |
| ␊ |
| if (count($targets) == 0 || count($sources) == 0)␊ |
| {␊ |
| return "";␊ |
| if (count($targets) == 0 || count($sources) == 0) {␊ |
| return '';␊ |
| }␊ |
| ␊ |
| // if target contains a root revision, we cannot produce a diff␊ |
| if (empty($sources[0]))␊ |
| {␊ |
| return "";␊ |
| if (empty($sources[0])) {␊ |
| return '';␊ |
| }␊ |
| ␊ |
| return $this->stdio->exec(␊ |
| array("content_diff"),␊ |
| array("r" => array($sources[0], $targets[0]))␊ |
| array('content_diff'),␊ |
| array('r' => array($sources[0], $targets[0]))␊ |
| );␊ |
| }␊ |
| ␊ |
|
| $certs = $this->_getCerts($revs[0]);␊ |
| ␊ |
| // FIXME: this assumes that author, date and changelog are always given␊ |
| $res['author'] = implode(", ", $certs['author']);␊ |
| $res['author'] = implode(', ', $certs['author']);␊ |
| ␊ |
| $dates = array();␊ |
| foreach ($certs['date'] as $date)␊ |
|
| */␊ |
| public function isCommitLarge($commit=null)␊ |
| {␊ |
| if (empty($commit))␊ |
| {␊ |
| $commit = "h:"+$this->getMainBranch();␊ |
| if (empty($commit)) {␊ |
| $commit = 'h:'.$this->getMainBranch();␊ |
| }␊ |
| ␊ |
| $revs = $this->_resolveSelector($commit);␊ |
|
| return false;␊ |
| ␊ |
| $out = $this->stdio->exec(array(␊ |
| "get_revision", $revs[0]␊ |
| 'get_revision', $revs[0]␊ |
| ));␊ |
| ␊ |
| $newAndPatchedFiles = 0;␊ |
| $stanzas = self::_parseBasicIO($out);␊ |
| ␊ |
| foreach ($stanzas as $stanza)␊ |
| {␊ |
| if ($stanza[0]['key'] == "patch" || $stanza[0]['key'] == "add_file")␊ |
| foreach ($stanzas as $stanza) {␊ |
| if ($stanza[0]['key'] == 'patch' || $stanza[0]['key'] == 'add_file')␊ |
| $newAndPatchedFiles++;␊ |
| }␊ |
| ␊ |
|
| $initialBranches = array();␊ |
| $logs = array();␊ |
| ␊ |
| while (!empty($horizont) && $n > 0)␊ |
| {␊ |
| if (count($horizont) > 1)␊ |
| {␊ |
| $out = $this->stdio->exec(array("toposort") + $horizont);␊ |
| while (!empty($horizont) && $n > 0) {␊ |
| if (count($horizont) > 1) {␊ |
| $out = $this->stdio->exec(array('toposort') + $horizont);␊ |
| $horizont = preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY);␊ |
| }␊ |
| ␊ |
|
| $certs = $this->_getCerts($rev);␊ |
| ␊ |
| // read in the initial branches we should follow␊ |
| if (count($initialBranches) == 0)␊ |
| {␊ |
| if (count($initialBranches) == 0) {␊ |
| $initialBranches = $certs['branch'];␊ |
| }␊ |
| ␊ |
| // only add it to our log if it is on one of the initial branches␊ |
| if (count(array_intersect($initialBranches, $certs['branch'])) > 0)␊ |
| {␊ |
| if (count(array_intersect($initialBranches, $certs['branch'])) > 0) {␊ |
| --$n;␊ |
| ␊ |
| $log = array();␊ |
|
| $logs[] = (object)$log;␊ |
| }␊ |
| ␊ |
| $out = $this->stdio->exec(array("parents", $rev));␊ |
| $out = $this->stdio->exec(array('parents', $rev));␊ |
| $horizont += preg_split("/\n/", $out, -1, PREG_SPLIT_NO_EMPTY);␊ |
| }␊ |
| ␊ |