Fix #5611 - Fix ticket filters on create branch
[gitlive] / GitRepo.vala
index 6374b4f..91feb4c 100644 (file)
@@ -18,12 +18,19 @@ public class GitRepo : Object
     public string gitdir;
     public string git_working_dir;
     public bool debug = false;
+    public bool has_local_changes = false;
+    public string git_status;    
+    public string git_diff;        
+    public string ahead_or_behind = "";
     
     public Gee.HashMap<string,bool> ignore_files;
     public GitBranch currentBranch;
-
+    public Gee.HashMap<string,GitBranch> branches; // accessed in GitBranch..
        public RooTicket? activeTicket;
-
+    public  Gee.HashMap<string,GitRepo> cache;
+    
+    
+    
        public static GitRepo singleton()
     {
         if (_GitRepo == null) {
@@ -32,7 +39,7 @@ public class GitRepo : Object
         }
         return _GitRepo;
     }
-
     /**
     * index of.. matching gitpath..
     */
@@ -49,7 +56,7 @@ public class GitRepo : Object
     
     }
     
-    public  Gee.HashMap<string,GitRepo> cache;
+
     
     
     
@@ -124,9 +131,7 @@ public class GitRepo : Object
         }
     
         return list_cache;
-        
          
-          
        }
        
        public static GitRepo get(string path) 
@@ -159,7 +164,7 @@ public class GitRepo : Object
         if (!FileUtils.test(this.gitdir , FileTest.IS_DIR)) {
             this.gitdir = path; // naked...
         }
-        this.cmds = new  Array<GitMonitorQueue> ();
+        this.cmds = new  Gee.ArrayList<GitMonitorQueue> ();
         
                var cache = GitRepo.singleton().cache;
         //Repo.superclass.constructor.call(this,cfg);
@@ -167,6 +172,8 @@ public class GitRepo : Object
                        cache.set( path, this);
        }
        this.loadBranches();
+       this.loadActiveTicket();
+       this.loadStatus();
     } 
     
     public bool is_wip_branch()
@@ -175,37 +182,104 @@ public class GitRepo : Object
                
     }
     
+    public bool is_managed()
+    {
+       // is it a roojs origin?
+       var r = this.git({ "remote" , "get-url" , "--push" , "origin"});
+       var uri = new Soup.URI(r);
+       if (uri.get_host() != "git.roojs.com") { // we can only push to this url. -- unless we have forced it to be managed.
+               return FileUtils.test(this.gitdir + "/.gitlive-managed" , FileTest.EXISTS);
+       }
+       // otherwise see if unmanaged is set to disable it..
+       return !FileUtils.test(this.gitdir + "/.gitlive-unmanaged" , FileTest.EXISTS);  
+
+    }
+    
+    
     public bool is_autocommit ()
     {
        return !FileUtils.test(this.gitdir + "/.gitlive-disable-autocommit" , FileTest.EXISTS);
     }
+    public void set_autocommit(bool val)
+    {
+
+               var cur = this.is_autocommit();
+               GLib.debug("SET auto commit : %s <= %s", val ? "ON" : "OFF",  cur  ? "ON" : "OFF");
+               if (cur == val) {
+                       return; // no change..
+               }
+               if (!val) {
+                       FileUtils.set_contents(this.gitdir + "/.gitlive-disable-autocommit" , "x");
+               } else {
+                       // it exists...
+                       FileUtils.remove(this.gitdir + "/.gitlive-disable-autocommit" ); 
+               }
+    
+    }
+    
+    public bool is_auto_branch ()
+    {
+       return FileUtils.test(this.gitdir + "/.gitlive-enable-auto-branch" , FileTest.EXISTS);
+    }
+    
+    public void set_auto_branch(bool val)
+    {
+
+               var cur = this.is_auto_branch();
+               GLib.debug("SET auto branch : %s <= %s", val ? "ON" : "OFF",  cur  ? "ON" : "OFF");
+               
+               if (cur == val) {
+                       return; // no change..
+               }
+               if (val) {
+                       FileUtils.set_contents(this.gitdir + "/.gitlive-enable-auto-branch" , "x");
+               } else {
+                       // it exists...
+                       FileUtils.remove(this.gitdir + "/.gitlive-enable-auto-branch" ); 
+               }
+    
+    }
     public bool is_autopush ()
     {
        return !FileUtils.test(this.gitdir + "/.gitlive-disable-autopush" , FileTest.EXISTS);
     }
+    public void set_autopush(bool val)
+    {
+
+               var cur = this.is_autopush();
+               GLib.debug("SET auto push : %s <= %s", val ? "ON" : "OFF",  cur  ? "ON" : "OFF");
+               if (cur == val) {
+                       return; // no change..
+               }
+               if (!val) {
+                       FileUtils.set_contents(this.gitdir + "/.gitlive-disable-autopush" , "");
+               } else {
+                       // it exists...
+                       FileUtils.remove(this.gitdir + "/.gitlive-disable-autopush" ); 
+               }
     
-    Gee.HashMap<string,GitBranch> branches;
+    }
+    
+    
+       public void loadStatus()
+       {
+               var r = this.git({ "status" , "--porcelain" });
+               this.git_status = r;
+               this.has_local_changes = r.length > 0;
+               
+               var rs = this.git({ "status" , "-sb" });
+
+               this.ahead_or_behind = rs.contains("[ahead") ? "A" : (rs.contains("[behind") ? "B" : "");
+               
+               
+               this.git_diff  = this.git({ "diff" , "HEAD", "--no-color" });
+       }    
+
     
     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;
-               }
-        }
-    
+
+       GitBranch.loadBranches(this);
     }
      
     
@@ -218,7 +292,7 @@ public class GitRepo : Object
                        if (br.name == "") {
                                continue; 
                        }
-                       ret += ret.length > 0 ? ","  : "";
+                       ret += ret.length > 0 ? "\n"  : "";
                        ret += br.name;
                
                }
@@ -247,46 +321,44 @@ public class GitRepo : Object
        }
        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",   "--m",  commit_message };
-                       this.git( cmd );
-                       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) {
+                  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"
+                               
+                       );
 
-                       GitMonitor.gitmonitor.pauseError(e.message);
-                       return false;
-                   }
-                   // error~?? -- show the error dialog...
+                       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") {
@@ -334,27 +406,166 @@ public class GitRepo : Object
        }
        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 void setActiveTicket(RooTicket ticket, string branchname)
+    public bool setActiveTicket(RooTicket? ticket, string branchname)
     {
-       this.createBranchNamed(branchname);
-       FileUtils.set_contents(this.gitdir + "/.gitlive-active-ticket" , ticket.id);
+       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 void createBranchNamed(string branchname)
-    {
-         if (this.branches.has_key(branchname)) {
-                string[] cmd = { "checkout", branchname  };
-                this.git(cmd);         
-       } else {
-                string[] cmd = { "checkout", "-b" , branchname  };
-                this.git(cmd);
-        }
+    public bool createBranchNamed(string branchname)
+    {  
+               
+
+                    if (this.branches.has_key(branchname)) {
+                       this.switchToExistingBranchNamed(branchname);
+                   
+                   } else {
+                                this.createNewBranchNamed(branchname); 
+                           
+                   }
+                      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(); // commit any outstanding...
+        //GitMonitor.gitmonitor.runQueue(); // no point - we have hidden the queue..
+        return true;
     }
+     bool switchToExistingBranchNamed(string branchname)
+     {
+               var stash = false;
+                                        // this is where it get's tricky...
+               string files = "";
+               try {                   
+                               string[] cmd = { "ls-files" ,  "-m" };                   // list the modified files..
+                               files = this.git(cmd);
+                               stash = files.length> 1 ;
+                               
+                               
+                               cmd = { "stash" };                      
+                               if (stash) { this.git(cmd); }
+                               
+                               this.pull();
+                               
+                               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();
+                      
+                   }
+                   
+               } 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); 
+                       var fl = files.split("\n");
+                       cmd = { "commit", "-m" , "Changed " + string.joinv("",fl) };
+                       foreach(var f in fl) {
+                               if (f.length < 1) continue;
+                               cmd += f;
+                       }
+                       this.git(cmd);                              
+               }
+            
+
+                  
+               } catch(Error ee) {
+                       GitMonitor.gitmonitor.pauseError(ee.message);
+                       return false;           
+               }
+       this.push();
+       return true;                            
+                
+     }
+    
+    
+    
+     bool createNewBranchNamed(string branchname)
+     {
+               var stash = false;
+                try {                                  
+                               string[] cmd = { "ls-files" ,  "-m" };                   // list the modified files..
+                               var files = this.git(cmd);
+                               stash = files.length> 1 ;
+                       
+                        cmd = { "checkout", "-b" , branchname  };
+                       this.git(cmd);
+
+               cmd = { "push", "-u" , "origin" ,"HEAD"  };
+                       this.git(cmd);
+                               if (stash) { 
+
+                               var fl = files.split("\n");
+                               cmd = { "commit", "-m" , "Changed " + string.joinv("",fl) };
+                               foreach(var f in fl) {
+                                       if (f.length < 1) continue;
+                                       cmd += f;
+                               }
+                               this.git(cmd);  
+                               this.push();                        
+                       }
+
+             
+               } catch(Error ee) {
+                               GitMonitor.gitmonitor.pauseError(ee.message);
+                               return false;           
+                       }
+                       return true;
+     
+     }
+    
     
     
     /**
@@ -410,7 +621,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..
@@ -418,8 +629,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 );
@@ -499,7 +710,7 @@ public class GitRepo : Object
     public void pull_async(GitAsyncCallback cb) 
     {
     
-        string[] cmd = { "pull" , "--no-edit" };
+         string[] cmd = { "pull" , "--no-edit" };
          this.git_async( cmd , cb);
          
     
@@ -516,7 +727,7 @@ public class GitRepo : Object
     public string push () throws Error, SpawnError
     {
         // should 
-        return this.git({ "push", "origin", "HEAD" });
+        return this.git({ "push"  });
         
     }
     
@@ -560,16 +771,17 @@ public class GitRepo : Object
         //if (File.exists(this.repo + '/.git/config')) {
             //env.push("GITPATH=" + this.repo );
         //}
-        
-
+          
         var cfg = new SpawnConfig(this.git_working_dir , args , env);
-        
+        //cfg.debug = true;
 
        // may throw error...
         var sp = new Spawn(cfg);
       
-
-        GLib.debug( "GOT: %s" , sp.output);
+       // diff output is a bit big..
+               if (args_in[0] != "diff") {
+               GLib.debug( "GOT: %s" , sp.output);
+        }
         // parse output for some commands ?
         return sp.output;
     }
@@ -630,4 +842,56 @@ public class GitRepo : Object
     
     }
     
+        
+    
+    public void update_async(GitAsyncCallback cb) 
+    {
+         string[] cmd = { "fetch" , "--all" };
+         this.git_async( cmd , cb);
+         
+    }
+    
+    
+    static uint update_all_total = 0;
+    static string update_all_after = "";
+     
+    public static void updateAll(string after)
+    {
+               update_all_after = after;
+               var tr =  GitRepo.singleton().cache;
+            
+        
+       update_all_total = tr.size;
+       foreach(var repo  in tr.values) {
+                       if (!repo.is_managed()) {
+                       update_all_total--;                     
+                               continue;
+                       }
+           repo.update_async(updateAllCallback); 
+        } 
+
+    }
+    public static void  updateAllCallback(GitRepo repo, int err, string res)
+    {
+       repo.loadBranches();
+       repo.loadStatus();
+       
+       update_all_total--;
+       if (update_all_total > 0 ) {
+               return;
+               }
+               switch (update_all_after) {
+                       case "show_clones":
+                               Clones.singleton().show();
+                               break;
+                       default:
+                               break;
+               }
+               return;
+    }
+    
+    
+    
 }