3 require_once 'MTrack/Repo.php';
5 abstract class MTrackSCM {
6 static $repos = array();
10 static function factory(&$repopath) {
11 /* [ / owner type rest ] */
12 $bits = explode('/', $repopath, 4);
14 if (count($bits) < 3) {
15 throw new Exception("Invalid repo $repopath");
18 list($owner, $type) = $bits;
19 $repo = "$owner/$type";
21 $r = MTrackRepo::loadByName($repo);
23 throw new Exception("invalid repo $repo");
25 $repopath = isset($bits[2]) ? $bits[2] : '';
26 $r->repopath = $repopath;
30 /** Returns an array keyed by possible branch names.
31 * The data associated with the branches is implementation
33 * If the SCM does not have a concept of first-class branch
34 * objects, this function returns null */
35 abstract public function getBranches();
37 /** Returns an array keyed by possible tag names.
38 * The data associated with the tags is implementation
40 * If the SCM does not have a concept of first-class tag
41 * objects, this function returns null */
42 abstract public function getTags();
44 /** Enumerates the files/dirs that are present in the specified
45 * location of the repository that match the specified revision,
46 * branch or tag information. If no revision, branch or tag is
47 * specified, then the appropriate default is assumed.
49 * The second and third parameters are optional; the second
50 * parameter is one of 'rev', 'branch', or 'tag', and if specifed
51 * the third parameter must be the corresponding revision, branch
54 * The return value is an array of MTrackSCMFile objects present
55 * at that location/revision of the repository.
57 abstract public function readdir($path, $object = null, $ident = null);
59 /** Queries information on a specific file in the repository.
61 * Parameters are as for readdir() above.
63 * This function returns a single MTrackSCMFile for the location
66 abstract public function file($path, $object = null, $ident = null);
68 /** Queries history for a particular location in the repo.
70 * Parameters are as for readdir() above, except that path can be
71 * left unspecified to query the history for the entire repo.
73 * The limit parameter limits the number of entries returned; it it is
74 * a number, it specifies the number of events, otherwise it is assumed
75 * to be a date in the past; only events since that date will be returned.
77 * Returns an array of MTrackSCMEvent objects.
79 abstract public function history($path, $limit = null, $object = null,
82 /** Obtain the diff text representing a change to a file.
84 * You may optionally provide one or two revisions as context.
86 * If no revisions are passed in, then the change associated
87 * with the location will be assumed.
89 * If one revision is passed, then the change associated with
90 * that event will be assumed.
92 * If two revisions are passed, then the difference between
93 * the two events will be assumed.
95 abstract public function diff($path, $from = null, $to = null);
97 /** Determine the next and previous revisions for a given
100 * Returns an array: the 0th element is an array of prior revisions,
101 * and the 1st element is an array of successor revisions.
103 * There will usually be one prior and one successor revision for a
104 * given change, but some SCMs will return multiples in the case of
107 abstract public function getRelatedChanges($revision);
109 /** Returns a working copy object for the repo
111 * The intended purpose is to support wiki page modifications, and
112 * as such, is not meant to be an especially efficient means to do so.
114 abstract public function getWorkingCopy();
116 /** Returns meta information about the SCM type; this is used in the
117 * UI and tooling to let the user know their options.
119 * Returns an array with the following keys:
120 * 'name' => 'Mercurial', // human displayable name
121 * 'tools' => array('hg'), // list of tools to find during setup
123 abstract public function getSCMMetaData();
125 /** Returns the default 'root' location in the repository.
126 * For SCMs that have a concept of branches, this is the empty string.
127 * For SCMs like SVN, this is the trunk dir */
128 public function getDefaultRoot() {
135 /* takes an MTrackSCM as a parameter because in some bootstrapping
136 * cases, we're actually MTrackRepo and not the end-class.
137 * MTrackRepo calls the end-class method and passes itself in for
139 public function reconcileRepoSettings(MTrackSCM $r) {
141 "Creating/updating a repo of type $this->scmtype is not implemented");
144 static function makeBreadcrumbs($pi) {
151 $crumbs = explode('/', $pi);
156 static function makeDisplayName($data) {
159 if (is_object($data)) {
160 $parent = $data->parent;
161 $name = $data->shortname;
162 } else if (is_array($data)) {
163 $parent = $data['parent'];
164 $name = $data['shortname'];
167 list($type, $owner) = explode(':', $parent);
168 return "$owner/$name";
170 return "default/$name";
173 public function getBrowseRootName() {
174 return self::makeDisplayName($this);
177 public function resolveRevision($rev, $object, $ident) {
181 if ($object === null) {
189 $branches = $this->getBranches();
190 $rev = isset($branches[$ident]) ? $branches[$ident] : null;
193 $tags = $this->getTags();
194 $rev = isset($tags[$ident]) ? $tags[$ident] : null;
199 "don't know which revision to use ($rev,$object,$ident)");
208 static function run($toolname, $mode, $args = null)
210 global $FORKS; //??? why?
212 static $tools; // we cache the lookups... - we could use the config for this... (as per original..)
213 // but that would only be needed or realy heavily loaded sites.
215 require_once 'System.php';
216 $tool = isset($tools[$toolname]) ? $tools[$toolname] : System::which($toolname);
217 $tools[$toolname] = $tool;
219 throw new Exception("Could not find '$toolname'");
223 $args = is_array($args) ? $args : array();
225 foreach ($args as $arg) {
226 if (!is_array($arg)) {
227 $cmd .= ' ' . escapeshellarg($arg);
231 foreach ($arg as $a) {
232 $cmd .= ' ' . escapeshellarg($a);
236 if (!isset($FORKS[$cmd])) {
243 if (php_sapi_name() == 'cli') {
247 echo htmlentities($cmd) . "<br>\n";
252 case 'read': return popen($cmd, 'r');
253 case 'write': return popen($cmd, 'w');
254 case 'string': return stream_get_contents(popen($cmd, 'r'));
257 0 => array('pipe', 'r'),
258 1 => array('pipe', 'w'),
259 2 => array('pipe', 'w'),
261 $proc = proc_open($cmd, $pipedef, $pipes);
262 return array($proc, $pipes);