sync
[gitlive] / GitRepo.vala
index 29d0919..ec10a01 100644 (file)
@@ -7,10 +7,12 @@
  *
  *
  */
+static GitRepo  _GitRepo; 
 public class GitRepo : Object
 {
-    
-    public Array<GitMonitorQueue> cmds;
+     
+    public Gee.ArrayList<GitMonitorQueue> cmds;
 
     public string name;
     public string gitdir;
@@ -18,13 +20,25 @@ public class GitRepo : Object
     public bool debug = false;
     
     public Gee.HashMap<string,bool> ignore_files;
+    public GitBranch currentBranch;
 
+       public RooTicket? activeTicket;
+
+       public static GitRepo singleton()
+    {
+        if (_GitRepo == null) {
+            _GitRepo = new GitRepo.single();
+            _GitRepo.cache = new Gee.HashMap<string,GitRepo>();
+        }
+        return _GitRepo;
+    }
     /**
     * index of.. matching gitpath..
     */
     public static int indexOf( Array<GitRepo> repos, string gitpath) {
         // make a fake object to compare against..
-        var test_repo = new GitRepo(gitpath);
+        var test_repo = GitRepo.get(gitpath);
         
         for(var i =0; i < repos.length; i++) {
             if (repos.index(i).gitdir == test_repo.gitdir) {
@@ -35,15 +49,18 @@ public class GitRepo : Object
     
     }
     
+    public  Gee.HashMap<string,GitRepo> cache;
+    
+    
     
     public static   Array<GitRepo> list()
     {
-        
+
         //if (GitRepo.list_cache !=  null) {
         //    unowned  Array<GitRepo>    ret = GitRepo.list_cache;
          //   return ret;
         //}
-        
+        var cache = GitRepo.singleton().cache;
         var list_cache = new Array<GitRepo>();
         
         var dir = Environment.get_home_dir() + "/gitlive";
@@ -101,8 +118,8 @@ public class GitRepo : Object
                 continue;
             }
             
-             list_cache.append_val(new GitRepo(  sp )) ;
-             
+               var rep =  GitRepo.get(  sp );
+               list_cache.append_val(rep);             
             
         }
     
@@ -110,10 +127,20 @@ public class GitRepo : Object
         
          
           
-}
-    
-   
+       }
+       
+       public static GitRepo get(string path) 
+       {
+               var cache = GitRepo.singleton().cache;
+               if (cache.has_key(path)) {
+                       return cache.get(path);
+               }
+               return new GitRepo(path);
+       }
+       
+    private GitRepo.single() {
+               // used to create the signleton
+       }
     /**
      * constructor:
      * 
@@ -122,7 +149,7 @@ public class GitRepo : Object
      *
      */
      
-    public GitRepo(string path) {
+    private GitRepo(string path) {
         // cal parent?
         this.name =   File.new_for_path(path).get_basename();
         this.ignore_files = new Gee.HashMap<string,bool>();
@@ -132,24 +159,314 @@ public class GitRepo : Object
         if (!FileUtils.test(this.gitdir , FileTest.IS_DIR)) {
             this.gitdir = path; // naked...
         }
-        this.cmds = new  Array<GitMonitorQueue> ();
-        //Repo.superclass.constructor.call(this,cfg);
+        this.cmds = new  Gee.ArrayList<GitMonitorQueue> ();
         
+               var cache = GitRepo.singleton().cache;
+        //Repo.superclass.constructor.call(this,cfg);
+               if ( !cache.has_key(path) ) {
+                       cache.set( path, this);
+       }
+       this.loadBranches();
+       this.loadActiveTicket();
     } 
+    
+    public bool is_wip_branch()
+    {
+       return this.currentBranch.name.has_prefix("wip_");
+               
+    }
+    
+    public bool is_autocommit ()
+    {
+       return !FileUtils.test(this.gitdir + "/.gitlive-disable-autocommit" , FileTest.EXISTS);
+    }
+    
+    public bool is_auto_branch ()
+    {
+       return FileUtils.test(this.gitdir + "/.gitlive-enable-auto-branch" , FileTest.EXISTS);
+    }
+    public bool is_autopush ()
+    {
+       return !FileUtils.test(this.gitdir + "/.gitlive-disable-autopush" , FileTest.EXISTS);
+    }
+    
+    Gee.HashMap<string,GitBranch> branches;
+    
+    public void loadBranches()
+    {
+       this.branches = new Gee.HashMap<string,GitBranch>();
+       
+       string[] cmd = { "branch",   "--no-color", "--verbose", "--no-abbrev" , "-a"  };
+        var res = this.git( cmd );
+        var lines = res.split("\n");
+        for (var i = 0; i < lines.length ; i++) {
+               var br = new GitBranch(this);
+               if (!br.parseBranchListItem(lines[i])) {
+                       continue;
+               }
+               GLib.debug("add branch %s", br.realName());
+                
+               branches.set(br.realName(), br);
+               if (br.active) {
+                       this.currentBranch = br;
+               }
+        }
+    
+    }
+     
+    
+    
+    
+    public string branchesToString()
+    {
+       var ret = "";
+               foreach( var br in this.branches.values) {
+                       if (br.name == "") {
+                               continue; 
+                       }
+                       ret += ret.length > 0 ? ","  : "";
+                       ret += br.name;
+               
+               }
+               return ret;
+       
+    }
+     public static void doMerges(string action, string ticket_id, string commit_message)
+    {
+       GitMonitor.gitmonitor.stop();
+       
+       var commitrevs = "";
+       var sucess = true;
+       foreach(var  repo in GitRepo.singleton().cache.values) {
+               if (repo.activeTicket != null && repo.activeTicket.id == ticket_id) {
+                       var res = repo.doMerge(action,ticket_id, commit_message);
+                       if (!res) {
+                               sucess = false;
+                               continue;
+                       }
+                       commitrevs += commitrevs.length > 0 ? " " : "";
+                       commitrevs += repo.currentBranch.lastrev;
+               }
+       }
+       if (sucess && action == "CLOSE") {
+               RooTicket.singleton().getById(ticket_id).close(commitrevs);
+       }
+       GitMonitor.gitmonitor.start();
+    }
+     
+
+    public bool doMerge(string action, string ticket_id, string commit_message)
+    {
+       // in theory we should check to see if other repo's have got the same branch and merge all them at the same time.
+       // also need to decide which branch we will merge into?
+                  var ret = "";
+                  if (action == "CLOSE" || action == "LEAVE") {
+                                  
+               try {
+                   var oldbranch = this.currentBranch.name;
+                   this.setActiveTicket(null, "master");
+                          string [] cmd = { "merge",   "--squash",  oldbranch };
+                          this.git( cmd );
+                          cmd = { "commit",   "-a" , "-m",  commit_message };
+                          this.git( cmd );
+                          this.push();
+                          this.loadBranches(); // updates lastrev..
+               
+                      var notification = new Notify.Notification(
+                               "Merged branch %s to master".printf(oldbranch),
+                               "",
+                                "dialog-information"
+                               
+                       );
+
+                       notification.set_timeout(5);
+                       notification.show();   
+               
+               // close ticket..
+               return true; 
+               
+           } catch (Error e) {
+
+               GitMonitor.gitmonitor.pauseError(e.message);
+               return false;
+           }
+           // error~?? -- show the error dialog...
+                   return false;
+       }
+       if (action == "MASTER") {
+               // merge master into ours..
+                       try {
+                       string[] cmd = { "merge",  "master" };
+                       this.git( cmd );
+                       var notification = new Notify.Notification(
+                                       "Merged code from master to %s".printf(this.currentBranch.name),
+                                       "",
+                                        "dialog-information"
+                                       
+                               );
+                               notification.set_timeout(5);
+                               notification.show();   
+                      
+                       return true;
+                       } catch (Error e) {
+                       GitMonitor.gitmonitor.pauseError(e.message);
+                       return false;
+                   }
+           }
+       if (action == "EXIT") {
+                       try {
+                       var oldbranch  = this.currentBranch.name;
+                         this.setActiveTicket(null, "master");
+                       this.loadBranches();
+                       var notification = new Notify.Notification(
+                                       "Left branch %s".printf(oldbranch),
+                                       "",
+                                        "dialog-information"
+                                       
+                               );
+                               notification.set_timeout(5);
+                               notification.show();   
+                       
+                       return true;
+                   } catch (Error e) {
+                       GitMonitor.gitmonitor.pauseError(e.message);
+
+                       return false;                   
+                   }
+                   // error~?? -- show the error dialog...
+
+       }
+       return false;
+    }
+        
+    public void loadActiveTicket()
+    {
+       this.activeTicket = null;
+       if (!FileUtils.test(this.gitdir + "/.gitlive-active-ticket" , FileTest.EXISTS)) {
+               return;
+       }
+       string ticket_id;
+       FileUtils.get_contents(this.gitdir + "/.gitlive-active-ticket" , out ticket_id);  
+       if (ticket_id.length < 1) {
+               return;
+               }
+               this.activeTicket = RooTicket.singleton().getById(ticket_id.strip());
+       
+       
+    }
+    
+    
+    
+    public bool setActiveTicket(RooTicket? ticket, string branchname)
+    {
+       if (!this.createBranchNamed(branchname)) {
+               return false;
+               }
+               if (ticket != null) {
+               FileUtils.set_contents(this.gitdir + "/.gitlive-active-ticket" , ticket.id);
+       } else {
+               FileUtils.remove(this.gitdir + "/.gitlive-active-ticket" );
+       }
+       this.activeTicket = ticket;
+       return true;
+    }
+    
+    public bool createBranchNamed(string branchname)
+    {  
+               
+                       var stash = false;
+                    if (this.branches.has_key(branchname)) {
+                       // this is where it get's tricky...
+                               try {                   
+                                               string[] cmd = { "ls-files" ,  "-m" };                   // list the modified files..
+                                           var ret = this.git(cmd);
+                                           stash = ret.length> 1 ;
+                                           
+                                               
+                                           cmd = { "stash" };                  
+                                           if (stash) { this.git(cmd); }
+                                           
+                                           cmd = { "checkout", branchname  };
+                                           this.git(cmd);
+                                 } catch(Error e) {
+                                               GitMonitor.gitmonitor.pauseError(e.message);
+                                               return false;           
+                                 }
+                                 try {
+                                          if (branchname != "master") {
+                                              string[] cmd = { "merge", "master"  };
+                                                   this.git(cmd);
+                                                   this.push();
+                                              //cmd = { "commit",   "-a" , "-m",  "merge master changes" };
+                                      //git chethis.git( cmd );
+                                           }
+                                           
+                                  } catch(Error e) {
+                                           string[] cmd = { "checkout", "master"  };
+                                           this.git(cmd);
+                                               GitMonitor.gitmonitor.pauseError(
+                                                       "Use\n\na) git checkout %s\nb) git mergetool\nc) git commit\nd) git push\n d) stash pop \ne) start gitlive again\n".printf(
+                                                               branchname)
+                                                        + e.message
+                                               );
+                                               return false;           
+                                        
+                                       }
+                                  try {                                        
+                                          string[]  cmd = { "stash", "pop"  };
+                                           if (stash) { this.git(cmd); }
+                                       } catch(Error ee) {
+                                               GitMonitor.gitmonitor.pauseError(ee.message);
+                                               return false;           
+                                       }
+                   this.push();
+                   
+                   } else {
+                                   try {                                       
+                                          
+                                       string[] cmd = { "checkout", "-b" , branchname  };
+                                       this.git(cmd);
+                       this.push();    
+                       cmd = { "branch", "--set-upstream-to=origin/"+branchname , branchname  };
+                                       this.git(cmd);
+                       
+                                       } catch(Error ee) {
+                                               GitMonitor.gitmonitor.pauseError(ee.message);
+                                               return false;           
+                                       }
+                           
+                   }
+                      var notification = new Notify.Notification(
+                       "Changed to branch %s".printf(branchname),
+                       "",
+                        "dialog-information"
+                       
+               );
+
+               notification.set_timeout(5);
+               notification.show();   
+       
+        
+        this.loadBranches(); // update branch list...
+        //GitMonitor.gitmonitor.runQueue(); // no point - we have hidden the queue..
+        return true;
+    }
+    
+    
     /**
      * add:
      * add files to track.
      *
      * @argument {Array} files the files to add.
      */
-    public string add ( Array<GitMonitorQueue> files ) throws Error, SpawnError
+    public string add ( Gee.ArrayList<GitMonitorQueue> files ) throws Error, SpawnError
     {
         // should really find out if these are untracked files each..
         // we run multiple versions to make sure that if one failes, it does not ignore the whole lot..
         // not sure if that is how git works.. but just be certian.
         var ret = "";
-        for (var i = 0; i < files.length;i++) {
-            var f = files.index(i).vname;
+        for (var i = 0; i < files.size;i++) {
+            var f = files.get(i).vname;
             try {
                 string[] cmd = { "add",    f  };
                 this.git( cmd );
@@ -189,7 +506,7 @@ public class GitRepo : Object
      *
      * @argument {Array} files the files to add.
      */
-    public string remove  ( Array<GitMonitorQueue> files ) throws Error, SpawnError
+    public string remove  ( Gee.ArrayList<GitMonitorQueue> files ) throws Error, SpawnError
     {
         // this may fail if files do not exist..
         // should really find out if these are untracked files each..
@@ -197,8 +514,8 @@ public class GitRepo : Object
         // not sure if that is how git works.. but just be certian.
         var ret = "";
 
-        for (var i = 0; i < files.length;i++) {
-            var f = files.index(i).vname;
+        for (var i = 0; i < files.size;i++) {
+            var f = files.get(i).vname;
             try {
                 string[] cmd = { "rm",  "-f" ,  f  };
                 this.git( cmd );
@@ -226,7 +543,7 @@ public class GitRepo : Object
      * 
      */
      
-    public string commit ( string message, Array<GitMonitorQueue> files  ) throws Error, SpawnError
+    public string commit ( string message, Gee.ArrayList<GitMonitorQueue> files  ) throws Error, SpawnError
     {
         
 
@@ -250,8 +567,8 @@ public class GitRepo : Object
         */
         string[] args = { "commit", "-m" };
         args +=  (message.length > 0  ? message : "Changed" );
-        for (var i = 0; i< files.length ; i++ ) {
-            args += files.index(i).vname; // full path?
+        for (var i = 0; i< files.size ; i++ ) {
+            args += files.get(i).vname; // full path?
         }
          
         return this.git(args);
@@ -295,7 +612,7 @@ public class GitRepo : Object
     public string push () throws Error, SpawnError
     {
         // should 
-        return this.git({ "push", "origin", "HEAD" });
+        return this.git({ "push"  });
         
     }