php8
[web.mtrack] / MTrack / SCM.php
1 <?php
2
3 require_once 'MTrack/Repo.php';
4
5 abstract class MTrackSCM
6 {
7
8   // statics...
9     static $repos = array();
10
11
12     static function makeBreadcrumbs($pi) {
13         if (!strlen($pi)) {
14           $pi = '/';
15         }
16         if ($pi == '/') {
17           $crumbs = array('');
18         } else {
19           $crumbs = explode('/', $pi);
20         }
21         return $crumbs;
22     }
23
24     static function makeDisplayName($data) {
25         $parent = '';
26         $name = '';
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'];
33         }
34         if ($parent) {
35           list($type, $owner) = explode(':', $parent);
36           return "$owner/$name";
37         }
38         return "default/$name";
39     }
40
41     /**
42      * was run tool...
43      */
44
45     static function run($toolname, $mode, $args = null)
46     {
47         global $FORKS; //??? why?
48         
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.
52                 
53         
54         require_once 'System.php';
55         $tool = isset($tools[$toolname]) ? $tools[$toolname] :  System::which($toolname);
56         $tools[$toolname] = $tool;
57         
58         
59         if (empty($tool)) {
60             throw new Exception("Could not find '$toolname'");
61         }
62          
63         $cmd = $tool;
64         $args = is_array($args) ? $args : array();
65         
66         foreach ($args as $arg) {
67             if (!is_array($arg)) {
68                 $cmd .= ' ' . MTrackSCM::escapeshellarg($arg);
69                 continue;
70             }
71             
72             foreach ($arg as $a) {
73                 $cmd .= ' ' . MTrackSCM::escapeshellarg($a);
74             }
75         }
76         
77         if (!isset($FORKS[$cmd])) {
78             $FORKS[$cmd] = 0;
79         }
80         $FORKS[$cmd]++;
81         //echo  $cmd;
82         // debugging....
83         if (false) {
84             if (php_sapi_name() == 'cli') {
85                 echo $cmd, "\n";
86             } else {
87                 error_log($cmd);
88                 echo htmlentities($cmd) . "<br>\n";
89             }
90         }
91
92         switch ($mode) {
93             case 'read':   return popen($cmd, 'r');
94             case 'write':  return popen($cmd, 'w');
95             case 'string': return stream_get_contents(popen($cmd, 'r'));
96             case 'proc':
97               $pipedef = array(
98                 0 => array('pipe', 'r'),
99                 1 => array('pipe', 'w'),
100                 2 => array('pipe', 'w'),
101               );
102               $proc = proc_open($cmd, $pipedef, $pipes);
103               return array($proc, $pipes);
104         }
105     }
106     
107     static function escapeshellarg($a) {
108         if (preg_match('/\-[a-z0-9]+$/i', $a)) {
109             return $a; // raw -a
110         }
111         if (preg_match('/\-\-[a-z0-9]+=/i', $a)) {
112             $lr = explode('=', $a,2);
113             return $lr[0].'=' . escapeshellarg($lr[1]); // raw -a
114         }
115         return escapeshellarg($a);
116         
117         
118     }
119     
120     public $repopath = '';
121     /*
122     static function factory(&$repopath) {
123         // [ / owner type rest ] 
124         $bits = explode('/', $repopath, 4);
125         //  print_r($bits);
126         if (count($bits) < 3) {
127           throw new Exception("Invalid repo $repopath");
128         }
129         array_shift($bits);
130         list($owner, $type) = $bits;
131         $repo = "$owner/$type";
132         
133         $r = MTrack_Repo::loadByName($repo);
134         if (!$r) {
135           throw new Exception("invalid repo $repo");
136         }
137         $repopath = isset($bits[2]) ? $bits[2] : '';
138         $r->repopath = $repopath;
139         return $r;
140     }
141     */
142     
143     /** Returns an array keyed by possible branch names.
144     * The data associated with the branches is implementation
145     * defined.
146     * If the SCM does not have a concept of first-class branch
147     * objects, this function returns null */
148     abstract public function getBranches();
149     
150     /** Returns an array keyed by possible tag names.
151     * The data associated with the tags is implementation
152     * defined.
153     * If the SCM does not have a concept of first-class tag
154     * objects, this function returns null */
155     abstract public function getTags();
156     
157     /** Enumerates the files/dirs that are present in the specified
158     * location of the repository that match the specified revision,
159     * branch or tag information.  If no revision, branch or tag is
160     * specified, then the appropriate default is assumed.
161     *
162     * The second and third parameters are optional; the second
163     * parameter is one of 'rev', 'branch', or 'tag', and if specifed
164     * the third parameter must be the corresponding revision, branch
165     * or tag identifier.
166     *
167     * The return value is an array of MTrackSCMFile objects present
168     * at that location/revision of the repository.
169     */
170     abstract public function readdir($path, $object = null, $ident = null);
171     
172     /** Queries information on a specific file in the repository.
173     *
174     * Parameters are as for readdir() above.
175     *
176     * This function returns a single MTrackSCMFile for the location
177     * in question.
178     */
179     abstract public function file($path, $object = null, $ident = null);
180     
181     /** Queries history for a particular location in the repo.
182     *
183     * Parameters are as for readdir() above, except that path can be
184     * left unspecified to query the history for the entire repo.
185     *
186     * The limit parameter limits the number of entries returned; it it is
187     * a number, it specifies the number of events, otherwise it is assumed
188     * to be a date in the past; only events since that date will be returned.
189     *
190     * Returns an array of MTrackSCMEvent objects.
191     */
192     abstract public function history($path, $limit = null, $object = null,
193     $ident = null);
194     
195     /** Obtain the diff text representing a change to a file.
196     *
197     * You may optionally provide one or two revisions as context.
198     *
199     * If no revisions are passed in, then the change associated
200     * with the location will be assumed.
201     *
202     * If one revision is passed, then the change associated with
203     * that event will be assumed.
204     *
205     * If two revisions are passed, then the difference between
206     * the two events will be assumed.
207     */
208     abstract public function diff($path, $from = null, $to = null);
209     
210     /** Determine the next and previous revisions for a given
211     * changeset.
212     *
213     * Returns an array: the 0th element is an array of prior revisions,
214     * and the 1st element is an array of successor revisions.
215     *
216     * There will usually be one prior and one successor revision for a
217     * given change, but some SCMs will return multiples in the case of
218     * merges.
219     */
220     abstract public function getRelatedChanges($revision);
221     
222     /** Returns a working copy object for the repo
223     *
224     * The intended purpose is to support wiki page modifications, and
225     * as such, is not meant to be an especially efficient means to do so.
226     */
227     abstract public function getWorkingCopy();
228     
229     /** Returns meta information about the SCM type; this is used in the
230     * UI and tooling to let the user know their options.
231     *
232     * Returns an array with the following keys:
233     * 'name' => 'Mercurial', // human displayable name
234     * 'tools' => array('hg'), // list of tools to find during setup
235     */
236     abstract public function getSCMMetaData();
237     
238     /** Returns the default 'root' location in the repository.
239     * For SCMs that have a concept of branches, this is the empty string.
240     * For SCMs like SVN, this is the trunk dir */
241     public function getDefaultRoot() {
242     return '';
243     }
244
245   
246     
247   
248   /* takes an MTrackSCM as a parameter because in some bootstrapping
249    * cases, we're actually MTrack_Repo and not the end-class.
250    * MTrack_Repo calls the end-class method and passes itself in for
251    * context */
252   public function reconcileRepoSettings(MTrackSCM $r) {
253     throw new Exception(
254       "Creating/updating a repo of type $this->scmtype is not implemented");
255   }
256
257
258
259
260   public function getBrowseRootName() {
261     return self::makeDisplayName($this);
262   }
263
264     public function resolveRevision($rev, $object, $ident)
265     {
266         if ($rev !== null) {
267             return $rev;
268         }
269         
270         if ($object === null) {
271             return null;
272         }
273         
274         switch ($object) {
275             case 'rev':
276                 $rev = $ident;
277                 break;
278             
279             case 'branch':
280                 $branches = $this->getBranches();
281                 $rev = isset($branches[$ident]) ? $branches[$ident] : null;
282                 break;
283             
284             case 'tag':
285               $tags = $this->getTags();
286               $rev = isset($tags[$ident]) ? $tags[$ident] : null;
287               break;
288         }
289         if ($rev === null) {
290           throw new Exception(
291             "don't know which revision to use ($rev,$object,$ident)");
292         }
293       return $rev;
294     }
295
296      
297 }