X-Git-Url: http://git.roojs.org/?p=gitlive;a=blobdiff_plain;f=Git.vala;h=795eabbb1ae3dd342dad56151d92586e2a41509b;hp=af4208c25731997228f625aad8499d85ab5808f0;hb=refs%2Fheads%2Fwip_alan_T5782_messing_around_with_libgit2glib;hpb=65f75c26b72bcbd8cafd30be1f7d53742fc67bf5 diff --git a/Git.vala b/Git.vala index af4208c2..795eabbb 100644 --- a/Git.vala +++ b/Git.vala @@ -1,7 +1,6 @@ -// valac -o /tmp/ggit Git.vala --pkg libgit2-glib-1.0 --pkg libsoup-2.4 -pkg gee-0.8 -g - - +// valac -o /tmp/ggit Git.vala --pkg libgit2-glib-1.0 --pkg libsoup-2.4 --pkg gee-0.8 -g + void main() { @@ -17,11 +16,37 @@ void main() } ); - Ggit.init(); + Ggit.init(); var a = new GitLive.Repo("/home/alan/gitlive/gitlive"); - a.loadBranches(); - a.fetchAll(); + a.diffhead(); + //a.fetchAll(); + return; + /* + GLib.Timeout.add (1, () => { + GLib.debug("Meanwhile"); + return true; + }, GLib.Priority.HIGH); + + var loop = new MainLoop(); + + var a = new GitLive.Repo("/home/alan/gitlive/web.coba"); + GLib.debug("Starting"); + a.loadRemoteHeads.begin(true, (obj,res) => { + a.loadRemoteHeads.end(res); + GLib.debug("got results"); + a.loadLocalBranches(); + loop.quit(); + }); + loop.run(); + //a.mergeMasterIntoHead(); + //a.walkDiff(); + //return; + //a.is_managed(); + //a.is_autocommit(); + + + //a.fetchAll(); // /* var a = new GitLive.Repo("/home/alan/git/test1-clone"); @@ -50,7 +75,7 @@ void main() //string[] spawn_env = Environ.get (); // Process.spawn_sync ("/home/alan/git/test1-clone", spawn_args, spawn_env, SpawnFlags.SEARCH_PATH, null); - a.pushAll(); + //a.pushAll(); } @@ -58,60 +83,346 @@ namespace GitLive { public class Repo : Object { + string name = ""; public Ggit.Repository repo; Callbacks callbacks; public Repo(string path) { + this.name = GLib.Path.get_basename(path); this.repo = Ggit.Repository.open(GLib.File.new_for_path(path)); this.callbacks = new Callbacks(this); } - + Ggit.Branch head = null; Gee.ArrayList branches = null; - public void loadBranches() + Ggit.RemoteHead[] remote_heads = null; + public void loadLocalBranches(bool force = false) { + if (!force && this.branches != null) { + return; + } + this.branches = new Gee.ArrayList(); var r = this.repo.enumerate_branches(Ggit.BranchType.LOCAL); + while (r.next()) { + var br = r.get() as Ggit.Branch; + if (br == null) { + continue; + } + if (br.is_tag()) { + continue; + } + + //var head = this.repo.revparse("refs/heads/" + br.get_name() ).get_id(); + //var rhead = this.repo.revparse(br.get_upstream().get_name() ).get_id(); + try { + GLib.debug("got branch: N=%s", br.get_name() ); + GLib.debug("is_head %s", br.is_head() ? "Y" : "n"); + + GLib.debug("upstream = %s", br.get_upstream() == null ? "??" : br.get_upstream().get_name().substring(20)); + GLib.debug("oid = %s",br.get_target().to_string()); + this.branches.add(br); + if (br.is_head()) { + GLib.debug("HEAD= %s", br.get_name()); + this.head = br; + } + } catch (Error e) { + GLib.debug("Skip branch"); + } + } + + + } + + public bool is_managed() + { + GLib.debug("is_managed: %d", this.repo.get_config().get_int32("gitlive.managed")); + return this.repo.get_config().get_int32("gitlive.managed") == 1; + } + + + public bool is_autocommit () + { + GLib.debug("is_autocommit: %d", this.repo.get_config().get_int32("gitlive.autocommit")); + return this.repo.get_config().get_int32("gitlive.autocommit") == 1; + } + public void set_autocommit(bool val) + { + this.repo.get_config().set_int32("gitlive.autocommit", val ? 1 : 0); + + } + + public void walkDiff() + { + this.loadLocalBranches(); + + + var oid = this.repo.revparse(this.head.get_name() ).get_id() ; + var moid = this.repo.revparse("refs/heads/master" ).get_id() ; + var a = new Ggit.RevisionWalker(this.repo); + a.set_sort_mode(Ggit.SortMode.TOPOLOGICAL); + a.push(oid); + a.hide(moid); + var last = oid; + for (var noid = a.next(); noid != null; noid= a.next()) { + //var commit = this.repo.lookup(noid, typeof(Ggit.Commit)) as Ggit.Commit; + GLib.debug("rev: %s", + noid.to_string() + ); + last = noid; + } + var commit = this.repo.lookup(last, typeof(Ggit.Commit)) as Ggit.Commit; + var parent = commit.get_parents(); + GLib.debug("parent = %s", parent.get_id(0).to_string()); + var master_rev = parent.get_id(0); + var master_commit = this.repo.lookup_commit(master_rev);; + + var head_commit = this.repo.lookup_commit(oid); + + var master_tree = master_commit.get_tree(); + var head_tree = head_commit.get_tree(); + + var diff = new Ggit.Diff.tree_to_tree(this.repo, master_tree, head_tree, new Ggit.DiffOptions()); + + diff.print(Ggit.DiffFormatType.PATCH, ( delta, hunk, line) => { + GLib.debug("%d: %s, %s", line.get_new_lineno(), line.get_origin().to_string(), line.get_text()); + return 0; + }); + // let's try a merge.. + var mo = new Ggit.MergeOptions(); + mo.set_file_favor(Ggit.MergeFileFavor.THEIRS); + var ix = this.repo.merge_trees(master_tree, master_tree, head_tree, mo); + + if (ix.has_conflicts()) { + GLib.debug("merge has conflicts"); + return; + } + var treeoid = ix.write_tree(); + + + + var parents = new Ggit.Commit[] { master_commit }; + + + var new_tree = this.repo.lookup(treeoid,typeof (Ggit.Tree)) as Ggit.Tree; + var sig = new Ggit.Signature.now( + this.repo.get_config().get_string("user.name"), + this.repo.get_config().get_string("user.email") + ); + + + this.repo.create_commit("HEAD", sig, sig, null, "Test Merge", new_tree, parents); + + + + } + + public void diffhead() + { + var r = this.repo.enumerate_branches(Ggit.BranchType.LOCAL); + Ggit.Branch? head = null; while (r.next()) { - var br = r.get() as Ggit.Branch; - var head = this.repo.revparse("refs/heads/" + br.get_name() ).get_id(); - var rhead = this.repo.revparse(br.get_upstream().get_name() ).get_id(); - GLib.debug("got branch: name = %s upstream = %s oid = %s ", - br.get_name(), br.get_upstream().get_name(), - head.to_string()); - this.branches.add(br); - + var gbr = r.get() as Ggit.Branch; + if (gbr.is_head()) { + head = gbr; + } } + GLib.debug("checking head=%s",head == null ? "EMPTY" : head.get_name()); + var br = this.repo.lookup_branch(head.get_name(),Ggit.BranchType.LOCAL); + var commit = this.repo.lookup_commit(br.get_target()); + + + var diff = new Ggit.Diff.tree_to_workdir(this.repo, commit.get_tree(), new Ggit.DiffOptions()); + var ret = ""; + diff.print(Ggit.DiffFormatType.PATCH, (delta, hunk, line) => { + switch(line.get_origin()) { + case Ggit.DiffLineType.ADDITION: ret+="+"; break; + case Ggit.DiffLineType.DELETION: ret+="-";break; + case Ggit.DiffLineType.CONTEXT: ret+=" ";break; + case Ggit.DiffLineType.HUNK_HDR: break; + case Ggit.DiffLineType.FILE_HDR: break; + default: ret+=" ";break; + } + ret += " " + line.get_text(); + return 0; + }); + GLib.debug("%s", ret); + } + + + public void mergeMasterIntoHead() + { + // assumes head is not master... + this.loadLocalBranches(); + GLib.debug("head rev = %s", this.head.get_name()); + var head_oid = this.repo.revparse(this.head.get_name() ).get_id() ; + //var master_oid = this.repo.revparse("refs/heads/master" ).get_id() ; + var master_oid = this.repo.revparse("HEAD" ).get_id() ; + + var master_commit = this.repo.lookup_commit(master_oid);; + var head_commit = this.repo.lookup_commit(head_oid); + + + var anc_oid = this.repo.merge_base(master_commit.get_id(), head_commit.get_id()); + + var anc_commit = this.repo.lookup_commit(anc_oid); + var anc_tree = anc_commit.get_tree(); + + var mo = new Ggit.MergeOptions(); + var co = new Ggit.CheckoutOptions(); + var the_ref = this.repo.lookup_reference_dwim("refs/heads/master"); + + var ac = new Ggit.AnnotatedCommit.from_ref(this.repo, the_ref); + + var commits = new Ggit.AnnotatedCommit[] { ac }; + + this.repo.merge(commits, mo, co); + + var cfg = this.repo.get_config().snapshot(); + + var sig = new Ggit.Signature.now( + cfg.get_string("user.name"), + cfg.get_string("user.email") + ); + var new_head = this.repo.get_head(); + var oid = new_head.get_target(); + + var ix = this.repo.get_index(); + + ix.write(); + var treeoid = ix.write_tree(); + + var new_tree = this.repo.lookup(treeoid,typeof (Ggit.Tree)) as Ggit.Tree; + var parent = new_head.lookup() as Ggit.Commit; + Ggit.Commit[] parents = new Ggit.Commit[] { parent }; + this.repo.create_commit("refs/heads/" + this.head.get_name(), sig, sig, null, "Test Merge", new_tree, parents); + + } + + + + + + /* + public bool doMergeClose(string commit_message) + { + this.loadLocalBranches(true); + var oldbranch = this.head.get_name(); + // going to asume this is merge trees.. + 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 %s".printf(oldbranch, master), + "", + "dialog-information" + + ); + + notification.set_timeout(5); + notification.show(); + + + } + */ + + public bool is_auto_branch () + { + if (this.name == "gitlog") { + return false; + } + // check remote... + if (this.is_managed()) { + return true; + } + return false; + + + } + + public async void loadRemoteHeads(bool force = false) + { + SourceFunc callback = loadRemoteHeads.callback; + + ThreadFunc run = () => { + + if (!force && this.remote_heads != null) { + return true;; + } + var r = this.repo.lookup_remote("origin"); + r.connect(Ggit.Direction.FETCH, this.callbacks, null, null); + yield; + this.remote_heads = r.list(); + + foreach(var br in this.remote_heads) { + if (!br.get_name().has_prefix("refs/heads/")) { + continue; + } + + GLib.debug("Remote: name=%s oid=%s local_oid=%s is_local=%s", + br.get_name(), + br.get_oid().to_string(), + br.get_local_oid().to_string(), + br.is_local() ? "Y" : "n" + ); + } + Idle.add((owned) callback); + return true;; + }; + new Thread("loadRemoteHeads-" , run); + yield; + + } - Ggit.Branch? getBranch(string remote_name) + + + Ggit.Branch? getBranch(string remote_name, string remote_branch_name) { - GLib.debug("lookup %s", remote_name); + //GLib.debug("bn=%s",remote_branch_name); + if (remote_branch_name.has_prefix("refs/remotes/")) { + return null; + } + + var target = remote_branch_name.replace("refs/heads/", remote_name+"/") .replace("refs/remotes/", ""); + if (target == "HEAD") { + target = remote_name +"/master"; + } + foreach(var br in this.branches) { - if (br.get_upstream().get_short_name() == remote_name) { + // GLib.debug("test:%s=%s", br.get_upstream().get_shorthand() , target); + if ( br.get_upstream().get_shorthand() == target) { return br; } } - GLib.debug("missing %s", remote_name); + //GLib.debug("missing %s", remote_branch_name); return null; } - - + public void fetchAll() { + this.loadLocalBranches(); + this.loadRemoteHeads(); + // remotes probably will not work with http auth.. - var ar = this.repo.list_remotes(); - foreach(var n in ar) { + //var ar = this.repo.list_remotes(); + //foreach(var n in ar) { + var n = "origin"; + GLib.debug("got remote '%s'", n); var r = this.repo.lookup_remote(n); GLib.debug("connecting '%s'", r.get_url()); @@ -124,30 +435,58 @@ namespace GitLive { GLib.debug("Got Error Message: %s", e.message); return; } + string[] far = {}; + + foreach(var rh in this.remote_heads) { + if (rh.get_name().has_prefix("refs/remotes/")) { + continue; + } - var heads = r.list(); - foreach(var rh in heads) { - var br = this.getBranch(rh.get_name()); - - GLib.debug("got heads: name=%s rev=%s localrev=%s", + var br = this.getBranch(n, rh.get_name()); + + /*GLib.debug("got heads: name=%s rev=%s localrev=%s", rh.get_name(), rh.get_oid().to_string(), br == null ? "?": this.repo.revparse(br.get_name() ).get_id().to_string() ); + */ + //var loc_oid = this.repo.revparse(br.get_name() ).get_id(); + + var loc_oid = br.get_target(); + + size_t ahead, behind; + this.repo.get_ahead_behind( + loc_oid, + rh.get_oid(), + out ahead, + out behind + ); + + if (rh.get_oid().to_string() == this.repo.revparse(br.get_name() ).get_id().to_string()) { + continue; + } + if (ahead > 0) { + continue; + } + far += ("+refs/heads/" + br.get_name()) + ":refs/remotes/" + n + "/" + rh.get_name().replace("refs/heads/",""); + } + if (far.length < 1) { + GLib.debug("no fetch required.. it's uptodate"); + r.disconnect(); + return; } + GLib.debug("getting remote specs '%s', %d", n, far.length); - - GLib.debug("getting specs '%s'", n); - - +/* var far = r.get_fetch_specs(); - + */ foreach(var rs in far) { GLib.debug("got remote spec: %s", rs); } + var options = new Ggit.FetchOptions(); options.set_remote_callbacks(this.callbacks); //yield Async.thread(() => { @@ -157,7 +496,7 @@ namespace GitLive { r.disconnect(); //r.download( - } + } @@ -165,21 +504,19 @@ namespace GitLive { public void pushAll() { + + this.loadLocalBranches(); + this.loadRemoteHeads(); // remotes probably will not work with http auth.. - var ar = this.repo.list_remotes(); - foreach(var n in ar) { + //var ar = this.repo.list_remotes(); + var n = "origin"; + GLib.debug("got remote '%s'", n); var r = this.repo.lookup_remote(n); GLib.debug("connecting '%s'", r.get_url()); - try { - string[] h = { "a = 1" }; - r.connect(Ggit.Direction.PUSH, this.callbacks, null, null); - - } catch (Error e) { - GLib.debug("Got Error Message: %s", e.message); - return; - } + r.connect(Ggit.Direction.PUSH, this.callbacks, null, null); + //GLib.debug("getting specs '%s'", n); /* @@ -188,10 +525,49 @@ namespace GitLive { "+%s:%s".printf(head.get_shorthand(),head.get_name()) ); */ - var head = this.repo.get_head(); + + string[] far = {}; + var heads = r.list(); + foreach(var rh in heads) { + if (rh.get_name().has_prefix("refs/remotes/")) { + continue; + } + + var br = this.getBranch(n, rh.get_name()); + /* + GLib.debug("got heads: name=%s rev=%s localrev=%s", + rh.get_name(), + rh.get_oid().to_string(), + br == null ? "?": this.repo.revparse(br.get_name() ).get_id().to_string() + );*/ + var loc_oid = this.repo.revparse(br.get_name() ).get_id(); + size_t ahead, behind; + this.repo.get_ahead_behind( + loc_oid, + rh.get_oid(), + out ahead, + out behind + ); + + if (rh.get_oid().to_string() == this.repo.revparse(br.get_name() ).get_id().to_string()) { + continue; + } + if (behind > 0) { + continue; + } + far += ("+refs/heads/" + br.get_name()) + ":"+ rh.get_name(); + } + + if (far.length < 1) { + GLib.debug("no push required.. it's uptodate"); + r.disconnect(); + return; + } + + /*var head = this.repo.get_head(); string[] far = {}; far += "+%s:%s".printf(head.get_name(),head.get_name()); - + */ foreach(var rs in far) { GLib.debug("got remote spec: %s", rs); @@ -206,12 +582,11 @@ namespace GitLive { //r.download( - } + } - - + } @@ -232,7 +607,7 @@ namespace GitLive { protected override void progress(string message) { - GLib.debug("progress"); + GLib.debug("progress: %s", message); if (d_proxy != null) { d_proxy.progress(message);