MTrack/SCM/WorkingCopy.php
[web.mtrack] / MTrack / SCM.php
index 1cb934b..817a1af 100644 (file)
 
 require_once 'MTrack/Repo.php';
 
-abstract class MTrackSCM {
-  static $repos = array();
+abstract class MTrackSCM
+{
 
-  public $repopath = '';
-  
-  static function factory(&$repopath) {
-    /* [ / owner type rest ] */
-    $bits = explode('/', $repopath, 4);
-  //  print_r($bits);
-    if (count($bits) < 3) {
-      throw new Exception("Invalid repo $repopath");
-    }
-    array_shift($bits);
-    list($owner, $type) = $bits;
-    $repo = "$owner/$type";
-
-    $r = MTrackRepo::loadByName($repo);
-    if (!$r) {
-      throw new Exception("invalid repo $repo");
-    }
-    $repopath = isset($bits[2]) ? $bits[2] : '';
-    $r->repopath = $repopath;
-    return $r;
-  }
-
-  /** Returns an array keyed by possible branch names.
-   * The data associated with the branches is implementation
-   * defined.
-   * If the SCM does not have a concept of first-class branch
-   * objects, this function returns null */
-  abstract public function getBranches();
-
-  /** Returns an array keyed by possible tag names.
-   * The data associated with the tags is implementation
-   * defined.
-   * If the SCM does not have a concept of first-class tag
-   * objects, this function returns null */
-  abstract public function getTags();
-
-  /** Enumerates the files/dirs that are present in the specified
-   * location of the repository that match the specified revision,
-   * branch or tag information.  If no revision, branch or tag is
-   * specified, then the appropriate default is assumed.
-   *
-   * The second and third parameters are optional; the second
-   * parameter is one of 'rev', 'branch', or 'tag', and if specifed
-   * the third parameter must be the corresponding revision, branch
-   * or tag identifier.
-   *
-   * The return value is an array of MTrackSCMFile objects present
-   * at that location/revision of the repository.
-   */
-  abstract public function readdir($path, $object = null, $ident = null);
-
-  /** Queries information on a specific file in the repository.
-   *
-   * Parameters are as for readdir() above.
-   *
-   * This function returns a single MTrackSCMFile for the location
-   * in question.
-   */
-  abstract public function file($path, $object = null, $ident = null);
-
-  /** Queries history for a particular location in the repo.
-   *
-   * Parameters are as for readdir() above, except that path can be
-   * left unspecified to query the history for the entire repo.
-   *
-   * The limit parameter limits the number of entries returned; it it is
-   * a number, it specifies the number of events, otherwise it is assumed
-   * to be a date in the past; only events since that date will be returned.
-   *
-   * Returns an array of MTrackSCMEvent objects.
-   */
-  abstract public function history($path, $limit = null, $object = null,
-    $ident = null);
-
-  /** Obtain the diff text representing a change to a file.
-   *
-   * You may optionally provide one or two revisions as context.
-   *
-   * If no revisions are passed in, then the change associated
-   * with the location will be assumed.
-   *
-   * If one revision is passed, then the change associated with
-   * that event will be assumed.
-   *
-   * If two revisions are passed, then the difference between
-   * the two events will be assumed.
-   */
-  abstract public function diff($path, $from = null, $to = null);
-
-  /** Determine the next and previous revisions for a given
-   * changeset.
-   *
-   * Returns an array: the 0th element is an array of prior revisions,
-   * and the 1st element is an array of successor revisions.
-   *
-   * There will usually be one prior and one successor revision for a
-   * given change, but some SCMs will return multiples in the case of
-   * merges.
-   */
-  abstract public function getRelatedChanges($revision);
-
-  /** Returns a working copy object for the repo
-   *
-   * The intended purpose is to support wiki page modifications, and
-   * as such, is not meant to be an especially efficient means to do so.
-   */
-  abstract public function getWorkingCopy();
-
-  /** Returns meta information about the SCM type; this is used in the
-   * UI and tooling to let the user know their options.
-   *
-   * Returns an array with the following keys:
-   * 'name' => 'Mercurial', // human displayable name
-   * 'tools' => array('hg'), // list of tools to find during setup
-   */
-  abstract public function getSCMMetaData();
-
-  /** Returns the default 'root' location in the repository.
-   * For SCMs that have a concept of branches, this is the empty string.
-   * For SCMs like SVN, this is the trunk dir */
-  public function getDefaultRoot() {
-    return '';
-  }
-
-  
-    
-  
-  /* takes an MTrackSCM as a parameter because in some bootstrapping
-   * cases, we're actually MTrackRepo and not the end-class.
-   * MTrackRepo calls the end-class method and passes itself in for
-   * context */
-  public function reconcileRepoSettings(MTrackSCM $r) {
-    throw new Exception(
-      "Creating/updating a repo of type $this->scmtype is not implemented");
-  }
+  // statics...
+    static $repos = array();
 
-  static function makeBreadcrumbs($pi) {
-    if (!strlen($pi)) {
-      $pi = '/';
-    }
-    if ($pi == '/') {
-      $crumbs = array('');
-    } else {
-      $crumbs = explode('/', $pi);
-    }
-    return $crumbs;
-  }
 
-  static function makeDisplayName($data) {
-    $parent = '';
-    $name = '';
-    if (is_object($data)) {
-      $parent = $data->parent;
-      $name = $data->shortname;
-    } else if (is_array($data)) {
-      $parent = $data['parent'];
-      $name = $data['shortname'];
-    }
-    if ($parent) {
-      list($type, $owner) = explode(':', $parent);
-      return "$owner/$name";
+    static function makeBreadcrumbs($pi) {
+        if (!strlen($pi)) {
+          $pi = '/';
+        }
+        if ($pi == '/') {
+          $crumbs = array('');
+        } else {
+          $crumbs = explode('/', $pi);
+        }
+        return $crumbs;
     }
-    return "default/$name";
-  }
-
-  public function getBrowseRootName() {
-    return self::makeDisplayName($this);
-  }
 
-  public function resolveRevision($rev, $object, $ident) {
-    if ($rev !== null) {
-      return $rev;
-    }
-    if ($object === null) {
-      return null;
-    }
-    switch ($object) {
-      case 'rev':
-        $rev = $ident;
-        break;
-      case 'branch':
-        $branches = $this->getBranches();
-         $rev = isset($branches[$ident]) ? $branches[$ident] : null;
-        break;
-      case 'tag':
-        $tags = $this->getTags();
-        $rev = isset($tags[$ident]) ? $tags[$ident] : null;
-        break;
-    }
-    if ($rev === null) {
-      throw new Exception(
-        "don't know which revision to use ($rev,$object,$ident)");
+    static function makeDisplayName($data) {
+        $parent = '';
+        $name = '';
+        if (is_object($data)) {
+          $parent = $data->parent;
+          $name = $data->shortname;
+        } else if (is_array($data)) {
+          $parent = $data['parent'];
+          $name = $data['shortname'];
+        }
+        if ($parent) {
+          list($type, $owner) = explode(':', $parent);
+          return "$owner/$name";
+        }
+        return "default/$name";
     }
-    return $rev;
-  }
 
     /**
      * was run tool...
@@ -209,12 +46,16 @@ abstract class MTrackSCM {
     {
         global $FORKS; //??? why?
         
-        static $tools; // we cache the lookups... - we could use the config for this... (as per original..)
-                        // but that would only be needed or realy heavily loaded sites.
+        static $tools; // we cache the lookups...
+                //- we could use the config for this... (as per original..)
+                // but that would only be needed or realy heavily loaded sites.
+                
         
         require_once 'System.php';
         $tool = isset($tools[$toolname]) ? $tools[$toolname] :  System::which($toolname);
         $tools[$toolname] = $tool;
+        
+        
         if (empty($tool)) {
             throw new Exception("Could not find '$toolname'");
         }
@@ -224,12 +65,12 @@ abstract class MTrackSCM {
         
         foreach ($args as $arg) {
             if (!is_array($arg)) {
-                $cmd .= ' ' . escapeshellarg($arg);
+                $cmd .= ' ' . MTrackSCM::escapeshellarg($arg);
                 continue;
             }
             
             foreach ($arg as $a) {
-                $cmd .= ' ' . escapeshellarg($a);
+                $cmd .= ' ' . MTrackSCM::escapeshellarg($a);
             }
         }
         
@@ -237,7 +78,7 @@ abstract class MTrackSCM {
             $FORKS[$cmd] = 0;
         }
         $FORKS[$cmd]++;
-        
+        //echo  $cmd;
         // debugging....
         if (false) {
             if (php_sapi_name() == 'cli') {
@@ -261,5 +102,196 @@ abstract class MTrackSCM {
               $proc = proc_open($cmd, $pipedef, $pipes);
               return array($proc, $pipes);
         }
-    }  
+    }
+    
+    static function escapeshellarg($a) {
+        if (preg_match('/\-[a-z0-9]+$/i', $a)) {
+            return $a; // raw -a
+        }
+        if (preg_match('/\-\-[a-z0-9]+=/i', $a)) {
+            $lr = explode('=', $a,2);
+            return $lr[0].'=' . escapeshellarg($lr[1]); // raw -a
+        }
+        return escapeshellarg($a);
+        
+        
+    }
+    
+    public $repopath = '';
+    /*
+    static function factory(&$repopath) {
+        // [ / owner type rest ] 
+        $bits = explode('/', $repopath, 4);
+        //  print_r($bits);
+        if (count($bits) < 3) {
+          throw new Exception("Invalid repo $repopath");
+        }
+        array_shift($bits);
+        list($owner, $type) = $bits;
+        $repo = "$owner/$type";
+        
+        $r = MTrack_Repo::loadByName($repo);
+        if (!$r) {
+          throw new Exception("invalid repo $repo");
+        }
+        $repopath = isset($bits[2]) ? $bits[2] : '';
+        $r->repopath = $repopath;
+        return $r;
+    }
+    */
+    
+    /** Returns an array keyed by possible branch names.
+    * The data associated with the branches is implementation
+    * defined.
+    * If the SCM does not have a concept of first-class branch
+    * objects, this function returns null */
+    abstract public function getBranches();
+    
+    /** Returns an array keyed by possible tag names.
+    * The data associated with the tags is implementation
+    * defined.
+    * If the SCM does not have a concept of first-class tag
+    * objects, this function returns null */
+    abstract public function getTags();
+    
+    /** Enumerates the files/dirs that are present in the specified
+    * location of the repository that match the specified revision,
+    * branch or tag information.  If no revision, branch or tag is
+    * specified, then the appropriate default is assumed.
+    *
+    * The second and third parameters are optional; the second
+    * parameter is one of 'rev', 'branch', or 'tag', and if specifed
+    * the third parameter must be the corresponding revision, branch
+    * or tag identifier.
+    *
+    * The return value is an array of MTrackSCMFile objects present
+    * at that location/revision of the repository.
+    */
+    abstract public function readdir($path, $object = null, $ident = null);
+    
+    /** Queries information on a specific file in the repository.
+    *
+    * Parameters are as for readdir() above.
+    *
+    * This function returns a single MTrackSCMFile for the location
+    * in question.
+    */
+    abstract public function file($path, $object = null, $ident = null);
+    
+    /** Queries history for a particular location in the repo.
+    *
+    * Parameters are as for readdir() above, except that path can be
+    * left unspecified to query the history for the entire repo.
+    *
+    * The limit parameter limits the number of entries returned; it it is
+    * a number, it specifies the number of events, otherwise it is assumed
+    * to be a date in the past; only events since that date will be returned.
+    *
+    * Returns an array of MTrackSCMEvent objects.
+    */
+    abstract public function history($path, $limit = null, $object = null,
+    $ident = null);
+    
+    /** Obtain the diff text representing a change to a file.
+    *
+    * You may optionally provide one or two revisions as context.
+    *
+    * If no revisions are passed in, then the change associated
+    * with the location will be assumed.
+    *
+    * If one revision is passed, then the change associated with
+    * that event will be assumed.
+    *
+    * If two revisions are passed, then the difference between
+    * the two events will be assumed.
+    */
+    abstract public function diff($path, $from = null, $to = null);
+    
+    /** Determine the next and previous revisions for a given
+    * changeset.
+    *
+    * Returns an array: the 0th element is an array of prior revisions,
+    * and the 1st element is an array of successor revisions.
+    *
+    * There will usually be one prior and one successor revision for a
+    * given change, but some SCMs will return multiples in the case of
+    * merges.
+    */
+    abstract public function getRelatedChanges($revision);
+    
+    /** Returns a working copy object for the repo
+    *
+    * The intended purpose is to support wiki page modifications, and
+    * as such, is not meant to be an especially efficient means to do so.
+    */
+    abstract public function getWorkingCopy();
+    
+    /** Returns meta information about the SCM type; this is used in the
+    * UI and tooling to let the user know their options.
+    *
+    * Returns an array with the following keys:
+    * 'name' => 'Mercurial', // human displayable name
+    * 'tools' => array('hg'), // list of tools to find during setup
+    */
+    abstract public function getSCMMetaData();
+    
+    /** Returns the default 'root' location in the repository.
+    * For SCMs that have a concept of branches, this is the empty string.
+    * For SCMs like SVN, this is the trunk dir */
+    public function getDefaultRoot() {
+    return '';
+    }
+
+  
+    
+  
+  /* takes an MTrackSCM as a parameter because in some bootstrapping
+   * cases, we're actually MTrack_Repo and not the end-class.
+   * MTrack_Repo calls the end-class method and passes itself in for
+   * context */
+  public function reconcileRepoSettings(MTrackSCM $r) {
+    throw new Exception(
+      "Creating/updating a repo of type $this->scmtype is not implemented");
+  }
+
+
+
+
+  public function getBrowseRootName() {
+    return self::makeDisplayName($this);
+  }
+
+    public function resolveRevision($rev, $object, $ident)
+    {
+        if ($rev !== null) {
+          return $rev;
+        }
+        
+        if ($object === null) {
+          return null;
+        }
+        
+        switch ($object) {
+            case 'rev':
+                $rev = $ident;
+                break;
+            
+            case 'branch':
+                $branches = $this->getBranches();
+                $rev = isset($branches[$ident]) ? $branches[$ident] : null;
+                break;
+            
+            case 'tag':
+              $tags = $this->getTags();
+              $rev = isset($tags[$ident]) ? $tags[$ident] : null;
+              break;
+        }
+        if ($rev === null) {
+          throw new Exception(
+            "don't know which revision to use ($rev,$object,$ident)");
+        }
+      return $rev;
+    }
+
+     
 }