3 require_once 'MTrack/Repo.php';
5 abstract class MTrackSCM
9 static $repos = array();
12 static function makeBreadcrumbs($pi) {
19 $crumbs = explode('/', $pi);
24 static function makeDisplayName($data) {
27 if (is_object($data)) {
28 $parent = $data->parent;
29 $name = $data->shortname;
30 } else if (is_array($data)) {
31 $parent = $data['parent'];
32 $name = $data['shortname'];
35 list($type, $owner) = explode(':', $parent);
36 return "$owner/$name";
38 return "default/$name";
45 static function run($toolname, $mode, $args = null)
47 global $FORKS; //??? why?
49 static $tools; // we cache the lookups...
50 //- we could use the config for this... (as per original..)
51 // but that would only be needed or realy heavily loaded sites.
54 require_once 'System.php';
55 $tool = isset($tools[$toolname]) ? $tools[$toolname] : System::which($toolname);
56 $tools[$toolname] = $tool;
60 throw new Exception("Could not find '$toolname'");
64 $args = is_array($args) ? $args : array();
66 foreach ($args as $arg) {
67 if (!is_array($arg)) {
68 $cmd .= ' ' . escapeshellarg($arg);
72 foreach ($arg as $a) {
73 $cmd .= ' ' . escapeshellarg($a);
77 if (!isset($FORKS[$cmd])) {
84 if (php_sapi_name() == 'cli') {
88 echo htmlentities($cmd) . "<br>\n";
93 case 'read': return popen($cmd, 'r');
94 case 'write': return popen($cmd, 'w');
95 case 'string': return stream_get_contents(popen($cmd, 'r'));
98 0 => array('pipe', 'r'),
99 1 => array('pipe', 'w'),
100 2 => array('pipe', 'w'),
102 $proc = proc_open($cmd, $pipedef, $pipes);
103 return array($proc, $pipes);
110 public $repopath = '';
112 static function factory(&$repopath) {
113 // [ / owner type rest ]
114 $bits = explode('/', $repopath, 4);
116 if (count($bits) < 3) {
117 throw new Exception("Invalid repo $repopath");
120 list($owner, $type) = $bits;
121 $repo = "$owner/$type";
123 $r = MTrack_Repo::loadByName($repo);
125 throw new Exception("invalid repo $repo");
127 $repopath = isset($bits[2]) ? $bits[2] : '';
128 $r->repopath = $repopath;
133 /** Returns an array keyed by possible branch names.
134 * The data associated with the branches is implementation
136 * If the SCM does not have a concept of first-class branch
137 * objects, this function returns null */
138 abstract public function getBranches();
140 /** Returns an array keyed by possible tag names.
141 * The data associated with the tags is implementation
143 * If the SCM does not have a concept of first-class tag
144 * objects, this function returns null */
145 abstract public function getTags();
147 /** Enumerates the files/dirs that are present in the specified
148 * location of the repository that match the specified revision,
149 * branch or tag information. If no revision, branch or tag is
150 * specified, then the appropriate default is assumed.
152 * The second and third parameters are optional; the second
153 * parameter is one of 'rev', 'branch', or 'tag', and if specifed
154 * the third parameter must be the corresponding revision, branch
157 * The return value is an array of MTrackSCMFile objects present
158 * at that location/revision of the repository.
160 abstract public function readdir($path, $object = null, $ident = null);
162 /** Queries information on a specific file in the repository.
164 * Parameters are as for readdir() above.
166 * This function returns a single MTrackSCMFile for the location
169 abstract public function file($path, $object = null, $ident = null);
171 /** Queries history for a particular location in the repo.
173 * Parameters are as for readdir() above, except that path can be
174 * left unspecified to query the history for the entire repo.
176 * The limit parameter limits the number of entries returned; it it is
177 * a number, it specifies the number of events, otherwise it is assumed
178 * to be a date in the past; only events since that date will be returned.
180 * Returns an array of MTrackSCMEvent objects.
182 abstract public function history($path, $limit = null, $object = null,
185 /** Obtain the diff text representing a change to a file.
187 * You may optionally provide one or two revisions as context.
189 * If no revisions are passed in, then the change associated
190 * with the location will be assumed.
192 * If one revision is passed, then the change associated with
193 * that event will be assumed.
195 * If two revisions are passed, then the difference between
196 * the two events will be assumed.
198 abstract public function diff($path, $from = null, $to = null);
200 /** Determine the next and previous revisions for a given
203 * Returns an array: the 0th element is an array of prior revisions,
204 * and the 1st element is an array of successor revisions.
206 * There will usually be one prior and one successor revision for a
207 * given change, but some SCMs will return multiples in the case of
210 abstract public function getRelatedChanges($revision);
212 /** Returns a working copy object for the repo
214 * The intended purpose is to support wiki page modifications, and
215 * as such, is not meant to be an especially efficient means to do so.
217 abstract public function getWorkingCopy();
219 /** Returns meta information about the SCM type; this is used in the
220 * UI and tooling to let the user know their options.
222 * Returns an array with the following keys:
223 * 'name' => 'Mercurial', // human displayable name
224 * 'tools' => array('hg'), // list of tools to find during setup
226 abstract public function getSCMMetaData();
228 /** Returns the default 'root' location in the repository.
229 * For SCMs that have a concept of branches, this is the empty string.
230 * For SCMs like SVN, this is the trunk dir */
231 public function getDefaultRoot() {
238 /* takes an MTrackSCM as a parameter because in some bootstrapping
239 * cases, we're actually MTrack_Repo and not the end-class.
240 * MTrack_Repo calls the end-class method and passes itself in for
242 public function reconcileRepoSettings(MTrackSCM $r) {
244 "Creating/updating a repo of type $this->scmtype is not implemented");
250 public function getBrowseRootName() {
251 return self::makeDisplayName($this);
254 public function resolveRevision($rev, $object, $ident)
260 if ($object === null) {
270 $branches = $this->getBranches();
271 $rev = isset($branches[$ident]) ? $branches[$ident] : null;
275 $tags = $this->getTags();
276 $rev = isset($tags[$ident]) ? $tags[$ident] : null;
281 "don't know which revision to use ($rev,$object,$ident)");