[gitg] Factor out patching and implement unstage_patch
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Factor out patching and implement unstage_patch
- Date: Thu, 2 Jan 2014 12:41:48 +0000 (UTC)
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]