summaryrefslogtreecommitdiff
path: root/git_crecord
diff options
context:
space:
mode:
authorAndrej Shadura <andrew@shadura.me>2022-03-20 13:40:02 +0100
committerAndrej Shadura <andrew@shadura.me>2022-03-24 16:10:23 +0100
commit6e324f50930e4fc8b13c3c9f82bafb8b7f4a36b4 (patch)
tree223865bacdb29184d3cc71929d5c349a6dd63611 /git_crecord
parent568a833c220a2761300c641d774d4e91d0e93744 (diff)
Sort the lines in hunks by their original offset, skip unapplied additions
Committing one change but not the other: @@ -1,3 +1,3 @@ RUN apt-get update [x] - && apt-get install -y supervisor python3.8 [ ] - git python3-pip ssl-cert [x] + && apt-get install -y supervisor python3.9 [ ] + git python3-pip ssl-cert time Most users would expect this diff: @@ -1,3 +1,3 @@ RUN apt-get update - && apt-get install -y supervisor python3.8 + && apt-get install -y supervisor python3.9 git python3-pip ssl-cert Currently produces: @@ -1,3 +1,3 @@ RUN apt-get update - git python3-pip ssl-cert && apt-get install -y supervisor python3.9 + git python3-pip ssl-cert time Committing all deletions but not all additions: @@ -1,3 +1,3 @@ RUN apt-get update [x] - && apt-get install -y supervisor python3.8 [x] - git python3-pip ssl-cert [x] + && apt-get install -y supervisor python3.9 [ ] + git python3-pip ssl-cert time This case is clear, too: @@ -1,3 +1,2 @@ RUN apt-get update - && apt-get install -y supervisor python3.8 + && apt-get install -y supervisor python3.9 - git python3-pip ssl-cert Committing all additions but not all deletions: @@ -1,3 +1,3 @@ RUN apt-get update [x] - && apt-get install -y supervisor python3.8 [ ] - git python3-pip ssl-cert [x] + && apt-get install -y supervisor python3.9 [x] + git python3-pip ssl-cert time What to do in this case? Could be this, but it does not make much sense: @@ -1,3 +1,2 @@ RUN apt-get update - && apt-get install -y supervisor python3.8 + && apt-get install -y supervisor python3.9 + git python3-pip ssl-cert time git python3-pip ssl-cert Or this (sorting the original lines before the new ones): @@ -1,3 +1,4 @@ RUN apt-get update - && apt-get install -y supervisor python3.8 + && apt-get install -y supervisor python3.9 git python3-pip ssl-cert + git python3-pip ssl-cert time Fixes: #29
Diffstat (limited to 'git_crecord')
-rw-r--r--git_crecord/crpatch.py59
1 files changed, 54 insertions, 5 deletions
diff --git a/git_crecord/crpatch.py b/git_crecord/crpatch.py
index dbbb42a..c5ffd36 100644
--- a/git_crecord/crpatch.py
+++ b/git_crecord/crpatch.py
@@ -432,6 +432,7 @@ class HunkLine(PatchNode):
linetext: bytes
hunk: 'Hunk'
+ offset: int
def __init__(self, linetext: bytes, hunk: 'Hunk'):
self.linetext = linetext
@@ -441,6 +442,8 @@ class HunkLine(PatchNode):
# folding lines currently is not used/needed, but this flag is needed
# in the prevItem method.
self.folded = False
+ # at this moment, the offset of the line in the hunk isn’t known yet
+ self.offset = 0
def __bytes__(self):
if self.applied:
@@ -453,8 +456,9 @@ class HunkLine(PatchNode):
return self.linetext[0:1]
def __repr__(self):
- return "<hunkline/%c %s %s>" % (
+ return "<hunkline/%c/%d %s %s>" % (
self.linetext[0],
+ self.offset,
'[x]' if self.applied else '[ ]',
self.linetext[1:10]
)
@@ -533,6 +537,7 @@ class Hunk(PatchNode):
self.proc = proc
self.changedlines = [HunkLine(line, self) for line in hunklines]
self.added, self.removed = self.countchanges()
+ self.countoffsets()
# used at end for detecting how many removed lines were un-applied
self.originalremoved = self.removed
@@ -596,6 +601,17 @@ class Hunk(PatchNode):
)
return add, rem
+ def countoffsets(self):
+ fromline = 0
+ toline = 0
+ for line in self.changedlines:
+ if line.diffop == HunkLine.INSERT:
+ fromline += 1
+ line.offset = fromline
+ if line.diffop == HunkLine.DELETE:
+ toline += 1
+ line.offset = toline
+
def getfromtoline(self):
"""Calculate the number of removed lines converted to context lines"""
removedconvertedtocontext = self.originalremoved - self.removed
@@ -635,10 +651,21 @@ class Hunk(PatchNode):
fp.write(self.getfromtoline())
fp.write(b''.join(self.before))
- # add the following to the list: (1) all applied lines, and
- # (2) all unapplied removal lines (convert these to context lines)
- for changedline in self.changedlines:
- fp.write(bytes(changedline))
+ # Include these lines:
+ # (1) all applied lines
+ # (2) all unapplied removal lines (converted context lines)
+ # Lines are sorted by their offset in the original hunk,
+ # with removals coming first.
+ for line in sorted(
+ self.changedlines,
+ key=lambda line: (
+ line.offset, line.diffop == HunkLine.INSERT
+ )
+ ):
+ if line.diffop == HunkLine.INSERT and not line.applied:
+ continue
+
+ fp.write(bytes(line))
fp.write(b''.join(self.after))
@@ -1030,12 +1057,34 @@ def filterpatch(opts, patch: PatchRoot, chunkselector, ui):
<hunk b'Dockerfile'@1>]
>>> selections = [True, False, True, False]
>>> applied = filterpatch(None, patch, partial(line_selector, selections), None)
+ >>> print(applied.headers[0].hunks[0].changedlines)
+ [<hunkline/-/1 [x] b' && apt-g'>,
+ <hunkline/-/2 [ ] b' git p'>,
+ <hunkline/+/1 [x] b' && apt-g'>,
+ <hunkline/+/2 [ ] b' git p'>]
>>> print(applied.hunks[0])
@@ -1,3 +1,3 @@
RUN apt-get update
- && apt-get install -y supervisor python3.8
+ && apt-get install -y supervisor python3.9
git python3-pip ssl-cert
+ >>> selections = [True, True, True, False]
+ >>> applied = filterpatch(None, patch, partial(line_selector, selections), None)
+ >>> print(applied.hunks[0])
+ @@ -1,3 +1,2 @@
+ RUN apt-get update
+ - && apt-get install -y supervisor python3.8
+ + && apt-get install -y supervisor python3.9
+ - git python3-pip ssl-cert
+ >>> selections = [True, False, True, True]
+ >>> applied = filterpatch(None, patch, partial(line_selector, selections), None)
+ >>> print(applied.hunks[0])
+ @@ -1,3 +1,4 @@
+ RUN apt-get update
+ - && apt-get install -y supervisor python3.8
+ + && apt-get install -y supervisor python3.9
+ git python3-pip ssl-cert
+ + git python3-pip ssl-cert time
"""
# if there are no changed files
if len(patch) == 0: