[gitg/wip/patch-stage] Implement patchset staging



commit 1cd1276efb4a69c8c03628c934be7b8252bf98ab
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Wed Jan 1 18:33:20 2014 +0100

    Implement patchset staging

 gitg/commit/gitg-commit.vala |   34 +++++++++++++++++
 libgitg/gitg-stage.vala      |   85 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 118 insertions(+), 1 deletions(-)
---
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index 2bbc76d..3744a3f 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -733,6 +733,36 @@ namespace GitgCommit
                        }
                }
 
+               private async void stage_selection() throws Error
+               {
+                       var selection = yield d_main.diff_view.get_selection();
+                       var stage = application.repository.stage;
+
+                       foreach (var pset in selection)
+                       {
+                               yield stage.stage_patch(pset);
+                       }
+               }
+
+               private void on_stage_clicked()
+               {
+                       stage_selection.begin((obj, res) => {
+                               try
+                               {
+                                       stage_selection.end(res);
+                               }
+                               catch (Error e)
+                               {
+                                       var msg = _("Failed to stage selection");
+                                       application.show_infobar(msg, e.message, Gtk.MessageType.ERROR);
+
+                                       return;
+                               }
+
+                               reload();
+                       });
+               }
+
                private void build_ui()
                {
                        d_main = new Paned();
@@ -745,6 +775,10 @@ namespace GitgCommit
                                on_commit_clicked();
                        });
 
+                       d_main.button_stage.clicked.connect(() => {
+                               on_stage_clicked();
+                       });
+
                        d_main.diff_view.bind_property("has-selection",
                                                       d_main.button_stage,
                                                       "sensitive",
diff --git a/libgitg/gitg-stage.vala b/libgitg/gitg-stage.vala
index 91377d4..6ae2f22 100644
--- a/libgitg/gitg-stage.vala
+++ b/libgitg/gitg-stage.vala
@@ -33,7 +33,8 @@ public errordomain StageError
 {
        PRE_COMMIT_HOOK_FAILED,
        COMMIT_MSG_HOOK_FAILED,
-       NOTHING_TO_COMMIT
+       NOTHING_TO_COMMIT,
+       INDEX_ENTRY_NOT_FOUND
 }
 
 public class PatchSet
@@ -572,6 +573,88 @@ public class Stage : Object
        }
 
        /**
+        * Stage a patch to the index.
+        *
+        * @param patch the patch to stage.
+        *
+        * Stage a provided patch to the index. The patch should contain changes
+        * of the file in the current working directory to the contents of the
+        * index (i.e. as obtained from diff_workdir)
+        */
+       public async void stage_patch(PatchSet patch) throws Error
+       {
+               // new file is the current file in the working directory
+               var newf = d_repository.get_workdir().resolve_relative_path(patch.filename);
+               var new_stream = yield newf.read_async();
+
+               yield thread_index((index) => {
+                       var entries = index.get_entries();
+                       var entry = entries.get_by_path(newf, 0);
+
+                       if (entry == null)
+                       {
+                               throw new StageError.INDEX_ENTRY_NOT_FOUND(patch.filename);
+                       }
+
+                       var old_blob = d_repository.lookup<Ggit.Blob>(entry.get_id());
+                       unowned uchar[] old_content = old_blob.get_raw_content();
+
+                       var patched_stream = d_repository.create_blob();
+
+                       size_t oldptr = 0;
+                       size_t newptr = 0;
+
+                       // Copy old_content to patched_stream while applying patches as
+                       // specified in patch.patches from new_stream
+                       foreach (var p in patch.patches)
+                       {
+                               if (p.old_offset != oldptr)
+                               {
+                                       patched_stream.write(old_content[oldptr:p.old_offset]);
+                                       oldptr = p.old_offset;
+                               }
+
+                               if (p.type == PatchSet.Type.REMOVE)
+                               {
+                                       oldptr += p.length;
+                               }
+                               else
+                               {
+                                       // Copy in from new_stream
+                                       if (newptr != p.new_offset)
+                                       {
+                                               new_stream.seek(p.new_offset, SeekType.SET);
+                                       }
+
+                                       var buf = new uint8[p.length];
+
+                                       new_stream.read_all(buf, null);
+                                       patched_stream.write_all(buf, null);
+
+                                       newptr = p.new_offset + p.length;
+                               }
+                       }
+
+                       // Copy remaining part of old
+                       if (oldptr != old_content.length)
+                       {
+                               patched_stream.write_all(old_content[oldptr:old_content.length], null);
+                       }
+
+                       new_stream.close();
+                       patched_stream.close();
+
+                       var new_id = patched_stream.get_id();
+
+                       var new_entry = d_repository.create_index_entry_for_path(patch.filename,
+                                                                                new_id);
+
+                       index.add(new_entry);
+                       index.write();
+               });
+       }
+
+       /**
         * Unstage a file from the index.
         *
         * @param file the file to unstage.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]