Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some more cleanup #38

Merged
merged 7 commits into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@

# Remove an unused function and unused function parameters (recordfunc)
545dce2e5d0168ccf9e33ab42f6a26b63a45332f

# Reformat sources
624188a98126c5059ae8a71b2f44cb082669e11b
203 changes: 112 additions & 91 deletions git_crecord/chunk_selector.py

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions git_crecord/crecord_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,15 @@ def dorecord(ui, repo, *pats, **opts):
supports "a/" and "b/".
"""

git_args = ["git", "-c", "core.quotePath=false", "-c", "diff.mnemonicPrefix=false", "diff", "--binary"]
git_args = [
"git",
"-c",
"core.quotePath=false",
"-c",
"diff.mnemonicPrefix=false",
"diff",
"--binary",
]
git_base = []

if opts['cached']:
Expand All @@ -58,7 +66,9 @@ def dorecord(ui, repo, *pats, **opts):
if not opts['index'] and repo.head():
git_base.append("HEAD")

p = subprocess.Popen(git_args + git_base, stdout=subprocess.PIPE, close_fds=closefds)
p = subprocess.Popen(
git_args + git_base, stdout=subprocess.PIPE, close_fds=closefds
)
fp = cast(IO[bytes], p.stdout)

# 0. parse patch
Expand All @@ -80,9 +90,7 @@ def dorecord(ui, repo, *pats, **opts):
changes = [modified, added, removed]

# 1. filter patch, so we have intending-to apply subset of it
chunks = filterpatch(opts,
chunks,
chunkselector, ui)
chunks = filterpatch(opts, chunks, chunkselector, ui)
p.wait()
del fp

Expand Down Expand Up @@ -151,8 +159,14 @@ def dorecord(ui, repo, *pats, **opts):

# 3a. apply filtered patch to clean repo (clean)
if backups or any((f in contenders for f in removed)):
system(['git', 'checkout', '-f'] + git_base + ['--'] + [f for f in newfiles if f not in added],
onerr=Abort, errprefix=_("checkout failed"))
system(
["git", "checkout", "-f"]
+ git_base
+ ["--"]
+ [f for f in newfiles if f not in added],
onerr=Abort,
errprefix=_("checkout failed"),
)
# remove newly added files from 'clean' repo (so patch can apply)
for f in newly_added_backups:
pathname = repo.path / f
Expand All @@ -166,7 +180,7 @@ def dorecord(ui, repo, *pats, **opts):
p = subprocess.Popen(
["git", "apply", "--whitespace=nowarn"],
stdin=subprocess.PIPE,
close_fds=closefds
close_fds=closefds,
)
p.stdin.write(fp.getvalue())
p.stdin.close()
Expand Down
111 changes: 75 additions & 36 deletions git_crecord/crpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class PatchNode:
"""

folded: bool
applied: bool
# a patch this node belongs to
patch: 'PatchRoot'

Expand Down Expand Up @@ -246,11 +247,9 @@ def previtem(self) -> Optional['PatchNode']:
prevsibling = self.prevsibling()
if prevsibling is not None:
prevsiblinglastchild = prevsibling.lastchild()
if ((prevsiblinglastchild is not None) and
not prevsibling.folded):
if (prevsiblinglastchild is not None) and not prevsibling.folded:
prevsiblinglclc = prevsiblinglastchild.lastchild()
if ((prevsiblinglclc is not None) and
not prevsiblinglastchild.folded):
if (prevsiblinglclc is not None) and not prevsiblinglastchild.folded:
return prevsiblinglclc
else:
return prevsiblinglastchild
Expand All @@ -275,6 +274,7 @@ def __bytes__(self) -> bytes:

class Header(PatchNode):
"""Patch header"""

diff_re = re.compile(b'diff --git (?P<fromfile>(?P<aq>")?a/.*(?(aq)"|)) (?P<tofile>(?P<bq>")?b/.*(?(bq)"|))$')
allhunks_re = re.compile(b'(?:GIT binary patch|new file|deleted file) ')
pretty_re = re.compile(b'(?:new file|deleted file) ')
Expand Down Expand Up @@ -427,7 +427,13 @@ def allchildren(self) -> Sequence['Hunk']:
class HunkLine(PatchNode):
"""Represents a changed line in a hunk"""

def __init__(self, linetext: bytes, hunk):
DELETE = b'-'
INSERT = b'+'

linetext: bytes
hunk: 'Hunk'

def __init__(self, linetext: bytes, hunk: 'Hunk'):
self.linetext = linetext
self.applied = True
# the parent hunk to which this line belongs
Expand All @@ -446,6 +452,13 @@ def __bytes__(self):
def diffop(self):
return self.linetext[0:1]

def __repr__(self):
return "<hunkline/%c %s %s>" % (
self.linetext[0],
'[x]' if self.applied else '[ ]',
self.linetext[1:10]
)

def __str__(self) -> str:
return self.prettystr()

Expand All @@ -462,7 +475,7 @@ def nextsibling(self):
else:
return None

def prevsibling(self):
def prevsibling(self) -> Optional['HunkLine']:
"""Return the previous line in the hunk"""
indexofthisline = self.hunk.changedlines.index(self)
if indexofthisline > 0:
Expand All @@ -471,7 +484,7 @@ def prevsibling(self):
else:
return None

def parentitem(self):
def parentitem(self) -> 'Hunk':
"""Return the parent to the current item"""
return self.hunk

Expand All @@ -488,6 +501,7 @@ def lastchild(self):

class Hunk(PatchNode):
"""ui patch hunk, wraps a hunk and keeps track of ui behavior """

maxcontext = 3
header: Header
fromline: int
Expand All @@ -498,14 +512,14 @@ class Hunk(PatchNode):
changedlines: Sequence[HunkLine]

def __init__(
self,
header: Header,
fromline: int,
toline: int,
proc: bytes,
before: Sequence[bytes],
hunklines: Sequence[bytes],
after: Sequence[bytes]
self,
header: Header,
fromline: int,
toline: int,
proc: bytes,
before: Sequence[bytes],
hunklines: Sequence[bytes],
after: Sequence[bytes],
):
def trimcontext(number, lines):
delta = len(lines) - self.maxcontext
Expand Down Expand Up @@ -574,10 +588,12 @@ def allchildren(self) -> Sequence[PatchNode]:

def countchanges(self) -> tuple[int, int]:
"""changedlines -> (n+,n-)"""
add = len([line for line in self.changedlines if line.applied
and line.diffop == b'+'])
rem = len([line for line in self.changedlines if line.applied
and line.diffop == b'-'])
add = len(
[line for line in self.changedlines if line.applied and line.diffop == HunkLine.INSERT]
)
rem = len(
[line for line in self.changedlines if line.applied and line.diffop == HunkLine.DELETE]
)
return add, rem

def getfromtoline(self):
Expand All @@ -603,9 +619,13 @@ def getfromtoline(self):
if tolen == 0 and toline > 0:
toline -= 1

fromtoline = b'@@ -%d,%d +%d,%d @@%b\n' % (
fromline, fromlen, toline, tolen,
self.proc and (b' ' + self.proc))
fromtoline = b"@@ -%d,%d +%d,%d @@%b\n" % (
fromline,
fromlen,
toline,
tolen,
self.proc and (b" " + self.proc),
)

return fromtoline

Expand Down Expand Up @@ -642,10 +662,21 @@ def reversehunks(self) -> 'Hunk':
4
5
"""
m = {b'+': b'-', b'-': b'+', b'\\': b'\\'}
hunklines = [b'%s%s' % (m[line.linetext[0:1]], line.linetext[1:])
for line in self.changedlines if line.applied]
return Hunk(self.header, self.fromline, self.toline, self.proc, self.before, hunklines, self.after)
m = {b"+": b"-", b"-": b"+", b"\\": b"\\"}
hunklines = [
b"%s%s" % (m[line.linetext[0:1]], line.linetext[1:])
for line in self.changedlines
if line.applied
]
return Hunk(
self.header,
self.fromline,
self.toline,
self.proc,
self.before,
hunklines,
self.after,
)

def files(self) -> list[Optional[bytes]]:
return self.header.files()
Expand Down Expand Up @@ -826,8 +857,15 @@ def add_new_hunk(self):
next hunk we parse.

"""
h = Hunk(self.header, self.fromline, self.toline, self.proc,
self.before, self.hunk, self.context)
h = Hunk(
self.header,
self.fromline,
self.toline,
self.proc,
self.before,
self.hunk,
self.context,
)
self.header.hunks.append(h)
self.headers.append(h)
self.fromline += len(self.before) + h.removed + len(self.context)
Expand All @@ -844,7 +882,7 @@ def addcontext(self, context):
Also, if an unprocessed set of changelines was previously
encountered, this is the condition for creating a complete
hunk object. In this case, we create and add a new hunk object to
the most recent header object, and to self.strem.
the most recent header object, and to self.strem.

"""
self.context = context
Expand Down Expand Up @@ -872,7 +910,7 @@ def newfile(self, header):
filename the header applies to. Add the header to self.headers.

"""
# if there are any lines in the unchanged-lines buffer, create a
# if there are any lines in the unchanged-lines buffer, create a
# new hunk using them, and add it to the last header.
if self.hunk:
self.add_new_hunk()
Expand All @@ -883,7 +921,7 @@ def newfile(self, header):
self.header = h

def finished(self):
# if there are any lines in the unchanged-lines buffer, create a
# if there are any lines in the unchanged-lines buffer, create a
# new hunk using them, and add it to the last header.
if self.hunk:
self.add_new_hunk()
Expand Down Expand Up @@ -952,7 +990,7 @@ def filterpatch(opts, patch: PatchRoot, chunkselector, ui):
<hunk b'dir/file.c'@1692>]
>>> def selector(opts, headers, ui):
... headers[0].hunks[0].applied = False
...
...
>>> applied = filterpatch(None, patch, selector, None)
>>> applied
[<header b'dir/file.c' b'dir/file.c'>,
Expand All @@ -978,10 +1016,11 @@ def filterpatch(opts, patch: PatchRoot, chunkselector, ui):

applied_hunks = PatchRoot([])
for header in patch.headers:
if (header.applied and
(header.special() or header.binary() or len([
h for h in header.hunks if h.applied
]) > 0)):
if header.applied and (
header.special()
or header.binary()
or len([h for h in header.hunks if h.applied]) > 0
):
applied_hunks.append(header)
fixoffset = 0
for hunk in header.hunks:
Expand Down
2 changes: 0 additions & 2 deletions git_crecord/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,3 @@ def ucolwidth(d: str) -> int:
if eaw is not None:
return sum([eaw(c) in wide and 2 or 1 for c in d])
return len(d)


29 changes: 16 additions & 13 deletions git_crecord/gitrepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self._tree)

def read(self):
util.system(['git', 'read-tree', '--reset',
self._tree], onerr=RuntimeError)
util.system(['git', 'read-tree', '--reset', self._tree], onerr=RuntimeError)


class GitIndex:
Expand Down Expand Up @@ -60,17 +59,21 @@ def backup_tree(self) -> ObjectHash:
class GitRepo:
def __init__(self, path: os.PathLike | str | None):
try:
self.path = Path(util.systemcall(
['git', 'rev-parse', '--show-toplevel'],
dir=path,
encoding="fs",
onerr=util.Abort
).rstrip('\n'))
self._controldir = Path(util.systemcall(
['git', 'rev-parse', '--git-dir'],
dir=path,
encoding="fs",
).rstrip('\n'))
self.path = Path(
util.systemcall(
['git', 'rev-parse', '--show-toplevel'],
dir=path,
encoding="fs",
onerr=util.Abort,
).rstrip('\n')
)
self._controldir = Path(
util.systemcall(
['git', 'rev-parse', '--git-dir'],
dir=path,
encoding="fs",
).rstrip('\n')
)
if not self._controldir.is_dir():
raise util.Abort
except util.Abort:
Expand Down
Loading