X-Git-Url: http://git.roojs.org/?p=gitlive;a=blobdiff_plain;f=GitRepo.vala;h=91feb4c82fb703ccf740808f525dbdefd07affd0;hp=6374b4ffd7fd3c3ea106c305463a153242278243;hb=35449c3a6ed4c08cf09abae2ab8a582acf7080c3;hpb=03a18dbe03808a85cde3936fb5b477aa17b2cb9a diff --git a/GitRepo.vala b/GitRepo.vala index 6374b4ff..91feb4c8 100644 --- a/GitRepo.vala +++ b/GitRepo.vala @@ -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 ignore_files; public GitBranch currentBranch; - + public Gee.HashMap branches; // accessed in GitBranch.. public RooTicket? activeTicket; - + public Gee.HashMap 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 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 (); + this.cmds = new Gee.ArrayList (); 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 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[] 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 files ) throws Error, SpawnError + public string remove ( Gee.ArrayList 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; + } + + + }