3131from __future__ import print_function
3232
3333__author__ = "Conan.io <[email protected] >" 34- __version__ = "1.17.1 "
34+ __version__ = "1.17.2 "
3535__license__ = "MIT"
3636__url__ = "https://github.com/conan-io/python-patch"
3737
@@ -82,11 +82,12 @@ def tostr(b):
8282# Logging is controlled by logger named after the
8383# module name (e.g. 'patch' for patch_ng.py module)
8484
85- logger = logging .getLogger (__name__ )
85+ logger = logging .getLogger ("patch_ng" )
8686
8787debug = logger .debug
8888info = logger .info
8989warning = logger .warning
90+ error = logger .error
9091
9192class NullHandler (logging .Handler ):
9293 """ Copied from Python 2.7 to avoid getting
@@ -305,16 +306,6 @@ def __init__(self):
305306 self .desc = ''
306307 self .text = []
307308
308- # def apply(self, estream):
309- # """ write hunk data into enumerable stream
310- # return strings one by one until hunk is
311- # over
312- #
313- # enumerable stream are tuples (lineno, line)
314- # where lineno starts with 0
315- # """
316- # pass
317-
318309
319310class Patch (object ):
320311 """ Patch for a single file.
@@ -966,9 +957,12 @@ def strip_path(self, path, base_path, strip=0):
966957
967958
968959
969- def apply (self , strip = 0 , root = None ):
960+ def apply (self , strip = 0 , root = None , fuzz = False ):
970961 """ Apply parsed patch, optionally stripping leading components
971962 from file paths. `root` parameter specifies working dir.
963+ :param strip: Strip patch path
964+ :param root: Folder to apply the patch
965+ :param fuzz: Accept fuzzy patches
972966 return True on success
973967 """
974968 items = []
@@ -1018,11 +1012,11 @@ def apply(self, strip=0, root=None):
10181012 filenameo , filenamen = self .findfiles (old , new )
10191013
10201014 if not filenameo or not filenamen :
1021- warning ("source/target file does not exist:\n --- %s\n +++ %s" % (old , new ))
1015+ error ("source/target file does not exist:\n --- %s\n +++ %s" % (old , new ))
10221016 errors += 1
10231017 continue
10241018 if not isfile (filenameo ):
1025- warning ("not a file - %s" % filenameo )
1019+ error ("not a file - %s" % filenameo )
10261020 errors += 1
10271021 continue
10281022
@@ -1049,28 +1043,31 @@ def apply(self, strip=0, root=None):
10491043 # todo \ No newline at end of file
10501044
10511045 # check hunks in source file
1052- if lineno + 1 < hunk .startsrc + len (hunkfind )- 1 :
1046+ if lineno + 1 < hunk .startsrc + len (hunkfind ):
10531047 if line .rstrip (b"\r \n " ) == hunkfind [hunklineno ]:
1054- hunklineno += 1
1048+ hunklineno += 1
10551049 else :
1056- info ("file %d/%d:\t %s" % (i + 1 , total , filenamen ))
1057- info (" hunk no.%d doesn't match source file at line %d" % (hunkno + 1 , lineno + 1 ))
1058- info (" expected: %s" % hunkfind [hunklineno ])
1059- info (" actual : %s" % line .rstrip (b"\r \n " ))
1060- # not counting this as error, because file may already be patched.
1061- # check if file is already patched is done after the number of
1062- # invalid hunks if found
1063- # TODO: check hunks against source/target file in one pass
1064- # API - check(stream, srchunks, tgthunks)
1065- # return tuple (srcerrs, tgterrs)
1066-
1067- # continue to check other hunks for completeness
1068- hunkno += 1
1069- if hunkno < len (p .hunks ):
1070- hunk = p .hunks [hunkno ]
1071- continue
1050+ warning ("file %d/%d:\t %s" % (i + 1 , total , filenamen ))
1051+ warning (" hunk no.%d doesn't match source file at line %d" % (hunkno + 1 , lineno + 1 ))
1052+ warning (" expected: %s" % hunkfind [hunklineno ])
1053+ warning (" actual : %s" % line .rstrip (b"\r \n " ))
1054+ if fuzz :
1055+ hunklineno += 1
10721056 else :
1073- break
1057+ # not counting this as error, because file may already be patched.
1058+ # check if file is already patched is done after the number of
1059+ # invalid hunks if found
1060+ # TODO: check hunks against source/target file in one pass
1061+ # API - check(stream, srchunks, tgthunks)
1062+ # return tuple (srcerrs, tgterrs)
1063+
1064+ # continue to check other hunks for completeness
1065+ hunkno += 1
1066+ if hunkno < len (p .hunks ):
1067+ hunk = p .hunks [hunkno ]
1068+ continue
1069+ else :
1070+ break
10741071
10751072 # check if processed line is the last line
10761073 if len (hunkfind ) == 0 or lineno + 1 == hunk .startsrc + len (hunkfind )- 1 :
@@ -1086,7 +1083,7 @@ def apply(self, strip=0, root=None):
10861083 break
10871084 else :
10881085 if hunkno < len (p .hunks ):
1089- warning ("premature end of source file %s at hunk %d" % (filenameo , hunkno + 1 ))
1086+ error ("premature end of source file %s at hunk %d" % (filenameo , hunkno + 1 ))
10901087 errors += 1
10911088
10921089 f2fp .close ()
@@ -1095,8 +1092,11 @@ def apply(self, strip=0, root=None):
10951092 if self ._match_file_hunks (filenameo , p .hunks ):
10961093 warning ("already patched %s" % filenameo )
10971094 else :
1098- warning ("source file is different - %s" % filenameo )
1099- errors += 1
1095+ if fuzz :
1096+ warning ("source file is different - %s" % filenameo )
1097+ else :
1098+ error ("source file is different - %s" % filenameo )
1099+ errors += 1
11001100 if canpatch :
11011101 backupname = filenamen + b".orig"
11021102 if exists (backupname ):
@@ -1247,8 +1247,9 @@ def get_line():
12471247 continue
12481248 else :
12491249 if not hline .startswith (b"+" ):
1250- get_line ()
1250+ yield get_line ()
12511251 srclineno += 1
1252+ continue
12521253 line2write = hline [1 :]
12531254 # detect if line ends are consistent in source file
12541255 if sum ([bool (lineends [x ]) for x in lineends ]) == 1 :
@@ -1310,6 +1311,7 @@ def main():
13101311 help = "strip N path components from filenames" )
13111312 opt .add_option ("--revert" , action = "store_true" ,
13121313 help = "apply patch in reverse order (unpatch)" )
1314+ opt .add_option ("-f" , "--fuzz" , action = "store_true" , dest = "fuzz" , help = "Accept fuuzzy patches" )
13131315 (options , args ) = opt .parse_args ()
13141316
13151317 if not args and sys .argv [- 1 :] != ['--' ]:
@@ -1344,11 +1346,15 @@ def main():
13441346 print (patch .diffstat ())
13451347 sys .exit (0 )
13461348
1349+ if not patch :
1350+ error ("Could not parse patch" )
1351+ sys .exit (- 1 )
1352+
13471353 #pprint(patch)
13481354 if options .revert :
13491355 patch .revert (options .strip , root = options .directory ) or sys .exit (- 1 )
13501356 else :
1351- patch .apply (options .strip , root = options .directory ) or sys .exit (- 1 )
1357+ patch .apply (options .strip , root = options .directory , fuzz = options . fuzz ) or sys .exit (- 1 )
13521358
13531359 # todo: document and test line ends handling logic - patch_ng.py detects proper line-endings
13541360 # for inserted hunks and issues a warning if patched file has incosistent line ends
0 commit comments