[gitg] Factor out patching and implement unstage_patch



commit e327c0fa625a673973ffbe05d8ab79a84285a3fd
Author: Jesse van den Kieboom <jessevdk gmail com>
Date:   Thu Jan 2 13:28:36 2014 +0100

    Factor out patching and implement unstage_patch

 libgitg/gitg-stage.vala |  160 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 111 insertions(+), 49 deletions(-)
---
diff --git a/libgitg/gitg-stage.vala b/libgitg/gitg-stage.vala
index 6ae2f22..9cca512 100644
--- a/libgitg/gitg-stage.vala
+++ b/libgitg/gitg-stage.vala
@@ -572,6 +572,75 @@ public class Stage : Object
                yield stage(d_repository.get_workdir().resolve_relative_path(path));
        }
 
+       private void copy_stream(OutputStream dest, InputStream src, ref size_t pos, size_t index, size_t 
length) throws Error
+       {
+               if (length == 0)
+               {
+                       return;
+               }
+
+               var buf = new uint8[length];
+
+               if (pos != index)
+               {
+                       ((Seekable)src).seek(index, SeekType.SET);
+                       pos = index;
+               }
+
+               src.read_all(buf, null);
+               dest.write_all(buf, null);
+
+               pos += length;
+       }
+
+       private void apply_patch(Ggit.Index index, InputStream old_stream, InputStream new_stream, PatchSet 
patch) throws Error
+       {
+               var patched_stream = d_repository.create_blob();
+
+               size_t old_ptr = 0;
+               size_t new_ptr = 0;
+
+               // Copy old_content to patched_stream while applying patches as
+               // specified in patch.patches from new_stream
+               foreach (var p in patch.patches)
+               {
+                       // Copy from old_ptr until p.old_offset
+                       copy_stream(patched_stream,
+                                   old_stream,
+                                   ref old_ptr,
+                                   old_ptr,
+                                   p.old_offset - old_ptr);
+
+                       if (p.type == PatchSet.Type.REMOVE)
+                       {
+                               // Removing, just advance old stream
+                               ((Seekable)old_stream).seek(p.length, SeekType.CUR);
+                               old_ptr += p.length;
+                       }
+                       else
+                       {
+                               // Inserting, copy from new_stream
+                               copy_stream(patched_stream,
+                                           new_stream,
+                                           ref new_ptr,
+                                           p.new_offset,
+                                           p.length);
+                       }
+               }
+
+               // Copy remaining part of old
+               patched_stream.splice(old_stream, OutputStreamSpliceFlags.NONE);
+               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();
+       }
+
        /**
         * Stage a patch to the index.
         *
@@ -599,58 +668,12 @@ public class Stage : Object
                        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);
+                       var old_stream = new MemoryInputStream.from_bytes(new Bytes(old_content));
 
-                                       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);
-                       }
+                       apply_patch(index, old_stream, new_stream, patch);
 
                        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();
+                       old_stream.close();
                });
        }
 
@@ -700,6 +723,45 @@ public class Stage : Object
                yield unstage(d_repository.get_workdir().resolve_relative_path(path));
        }
 
+       /**
+        * Unstage a patch from the index.
+        *
+        * @param patch the patch to unstage.
+        *
+        * Unstage a provided patch from the index. The patch should contain changes
+        * of the file in the index to the file in HEAD.
+        */
+       public async void unstage_patch(PatchSet patch) throws Error
+       {
+               var file = d_repository.get_workdir().resolve_relative_path(patch.filename);
+               var tree = yield get_head_tree();
+
+               yield thread_index((index) => {
+                       var entries = index.get_entries();
+                       var entry = entries.get_by_path(file, 0);
+
+                       if (entry == null)
+                       {
+                               throw new StageError.INDEX_ENTRY_NOT_FOUND(patch.filename);
+                       }
+
+                       var head_entry = tree.get_by_path(patch.filename);
+                       var head_blob = d_repository.lookup<Ggit.Blob>(head_entry.get_id());
+                       var index_blob = d_repository.lookup<Ggit.Blob>(entry.get_id());
+
+                       unowned uchar[] head_content = head_blob.get_raw_content();
+                       unowned uchar[] index_content = index_blob.get_raw_content();
+
+                       var head_stream = new MemoryInputStream.from_bytes(new Bytes(head_content));
+                       var index_stream = new MemoryInputStream.from_bytes(new Bytes(index_content));
+
+                       apply_patch(index, head_stream, index_stream, patch);
+
+                       head_stream.close();
+                       index_stream.close();
+               });
+       }
+
        public async Ggit.Diff? diff_index(StageStatusFile f) throws Error
        {
                var opts = new Ggit.DiffOptions(Ggit.DiffOption.INCLUDE_UNTRACKED |


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