def test_apply_returns_false_on_failure(self): self.tmpcopy([ 'data/failing/non-empty-patch-for-empty-file.diff', 'data/failing/upload.py' ]) pto = patch_ng.fromfile('non-empty-patch-for-empty-file.diff') self.assertFalse(pto.apply())
def test_fuzzy_patch_before(self): treeroot = join(self.tmpdir, 'rootparent') shutil.copytree(join(TESTS, '10fuzzybefore'), treeroot) pto = patch_ng.fromfile( join(TESTS, '10fuzzybefore/10fuzzybefore.patch')) self.assertTrue(pto.apply(root=treeroot, fuzz=True)) self.assertFalse(pto.apply(root=treeroot, fuzz=False))
def patch(conanfile, base_path=None, patch_file=None, patch_string=None, strip=0, fuzz=False, **kwargs): """ Applies a diff from file (patch_file) or string (patch_string) in base_path directory or current dir if None :param base_path: Base path where the patch should be applied. :param patch_file: Patch file that should be applied. :param patch_string: Patch string that should be applied. :param strip: Number of folders to be stripped from the path. :param output: Stream object. :param fuzz: Should accept fuzzy patches. :param kwargs: Extra parameters that can be added and will contribute to output information """ patch_type = kwargs.get('patch_type') patch_description = kwargs.get('patch_description') if patch_type or patch_description: patch_type_str = ' ({})'.format(patch_type) if patch_type else '' patch_description_str = ': {}'.format(patch_description) if patch_description else '' conanfile.output.info('Apply patch{}{}'.format(patch_type_str, patch_description_str)) patchlog = logging.getLogger("patch_ng") patchlog.handlers = [] patchlog.addHandler(PatchLogHandler(conanfile, patch_file)) if patch_file: patchset = patch_ng.fromfile(patch_file) else: patchset = patch_ng.fromstring(patch_string.encode()) if not patchset: raise ConanException("Failed to parse patch: %s" % (patch_file if patch_file else "string")) if not patchset.apply(root=base_path, strip=strip, fuzz=fuzz): raise ConanException("Failed to apply patch: %s" % patch_file)
def _patch_map_tools_core(patches, root): for title, patch_file in patches.items(): patch_set = patch.fromfile(patch_file) if not patch_set.apply(root=root): die( f'Patch "{patch_file.name}" failed (try cleaning the ' 'giants/Quake-Tools submodule)')
def test_apply_strip(self): treeroot = join(self.tmpdir, 'rootparent') shutil.copytree(join(TESTS, '06nested'), treeroot) pto = patch_ng.fromfile(join(TESTS, '06nested/06nested.patch')) for p in pto: p.source = b'nasty/prefix/' + p.source p.target = b'nasty/prefix/' + p.target self.assertTrue(pto.apply(strip=2, root=treeroot))
def test_autofixed_parent_path(self): # [ ] exception vs return codes for error recovery # [x] separate return code when patch lib compensated the error # (implemented as warning count) pto = patch_ng.fromfile(join(TESTS, "data/autofix/parent-path.diff")) self.assertEqual(pto.errors, 0) self.assertEqual(pto.warnings, 4) self.assertEqual(pto.items[0].source, b"patch_ng.py")
def apply_patch(self) -> None: """Apply the specified patch to the destination.""" patch_set = fromfile(self.__project.patch) if not patch_set: raise RuntimeError(f'Invalid patch file: "{self.__project.patch}"') if patch_set.apply(0, root=self.local_path, fuzz=True): self._log_project(f'Applied path "{self.__project.patch}"') else: raise RuntimeError(f'Applying path "{self.__project.patch}" failed')
def test_diffstat(self): output = """\ updatedlg.cpp | 20 ++++++++++++++++++-- updatedlg.h | 1 + manifest.xml | 15 ++++++++------- conf.cpp | 23 +++++++++++++++++------ conf.h | 7 ++++--- 5 files changed, 48 insertions(+), 18 deletions(-), +1203 bytes""" pto = patch_ng.fromfile(join(TESTS, "01uni_multi/01uni_multi.patch")) self.assertEqual(pto.diffstat(), output, "Output doesn't match")
def test_unlink_backup_windows(self): """ Apply patch to a read-only file and don't change its filemode """ treeroot = join(self.tmpdir, 'rootparent') shutil.copytree(join(TESTS, '11permission'), treeroot) pto = patch_ng.fromfile( join(TESTS, '11permission', '11permission.patch')) some_file = join(treeroot, 'some_file') chmod(some_file, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) self.assertTrue(pto.apply(root=treeroot)) self.assertTrue( os.stat(some_file).st_mode, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
def test_revert(self): def get_file_content(filename): with open(filename, 'rb') as f: return f.read() self.tmpcopy(['03trail_fname.patch', '03trail_fname.from']) pto = patch_ng.fromfile('03trail_fname.patch') self.assertTrue(pto.apply()) self.assertNotEqual( get_file_content(self.tmpdir + '/03trail_fname.from'), get_file_content(TESTS + '/03trail_fname.from')) self.assertTrue(pto.revert()) self.assertEqual(get_file_content(self.tmpdir + '/03trail_fname.from'), get_file_content(TESTS + '/03trail_fname.from'))
def patch(base_path=None, patch_file=None, patch_string=None, strip=0, output=None, fuzz=False): """ Applies a diff from file (patch_file) or string (patch_string) in base_path directory or current dir if None :param base_path: Base path where the patch should be applied. :param patch_file: Patch file that should be applied. :param patch_string: Patch string that should be applied. :param strip: Number of folders to be stripped from the path. :param output: Stream object. :param fuzz: Should accept fuzzy patches. """ class PatchLogHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self, logging.DEBUG) self.output = output or ConanOutput( sys.stdout, sys.stderr, color=True) self.patchname = patch_file if patch_file else "patch_ng" def emit(self, record): logstr = self.format(record) if record.levelno == logging.WARN: self.output.warn("%s: %s" % (self.patchname, logstr)) else: self.output.info("%s: %s" % (self.patchname, logstr)) patchlog = logging.getLogger("patch_ng") if patchlog: patchlog.handlers = [] patchlog.addHandler(PatchLogHandler()) if not patch_file and not patch_string: return if patch_file: patchset = fromfile(patch_file) else: patchset = fromstring(patch_string.encode()) if not patchset: raise ConanException("Failed to parse patch: %s" % (patch_file if patch_file else "string")) if not patchset.apply(root=base_path, strip=strip, fuzz=fuzz): raise ConanException("Failed to apply patch: %s" % patch_file)
def patch(base_path=None, patch_file=None, patch_string=None, strip=0, output=None): """Applies a diff from file (patch_file) or string (patch_string) in base_path directory or current dir if None""" class PatchLogHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self, logging.DEBUG) self.output = output or ConanOutput( sys.stdout, sys.stderr, color=True) self.patchname = patch_file if patch_file else "patch_ng" def emit(self, record): logstr = self.format(record) if record.levelno == logging.WARN: self.output.warn("%s: %s" % (self.patchname, logstr)) else: self.output.info("%s: %s" % (self.patchname, logstr)) patchlog = logging.getLogger("patch_ng") if patchlog: patchlog.handlers = [] patchlog.addHandler(PatchLogHandler()) if not patch_file and not patch_string: return if patch_file: patchset = fromfile(patch_file) else: patchset = fromstring(patch_string.encode()) if not patchset: raise ConanException("Failed to parse patch: %s" % (patch_file if patch_file else "string")) if not patchset.apply(root=base_path, strip=strip): raise ConanException("Failed to apply patch: %s" % patch_file)
def main(): parser = argparse.ArgumentParser() parser.add_argument("input", help="input file") parser.add_argument("-o", dest="output", help="output file") ns = parser.parse_args() patchset: patch_ng.PatchSet = patch_ng.fromfile(ns.input) if not patchset: return 1 for item in patchset.items: if item.source != "configure": pass item.hunks = [ hunk for hunk in item.hunks if not hunk_contains_only_line_diff(hunk) ] ostream = None if ns.output: ostream = open(ns.output, "wb") patchset.dump(stream=ostream) if ns.output: ostream.close() return 0
def test_can_patch_fails_on_target_file(self): pto3 = patch_ng.fromfile("03trail_fname.patch") self.assertEqual(None, pto3.can_patch(b"03trail_fname.to")) self.assertEqual(None, pto3.can_patch(b"not_in_source.also"))
def test(self): pto = patch_ng.fromfile(join(TESTDATA, filename)) self.assertEqual(pto.type, patchtype)
def test_create_file(self): treeroot = join(self.tmpdir, 'rootparent') os.makedirs(treeroot) pto = patch_ng.fromfile(join(TESTS, '08create/08create.patch')) pto.apply(strip=0, root=treeroot) self.assertTrue(os.path.exists(os.path.join(treeroot, 'created')))
def test_delete_file(self): treeroot = join(self.tmpdir, 'rootparent') shutil.copytree(join(TESTS, '09delete'), treeroot) pto = patch_ng.fromfile(join(TESTS, '09delete/09delete.patch')) pto.apply(strip=0, root=treeroot) self.assertFalse(os.path.exists(os.path.join(treeroot, 'deleted')))
def test_apply_root(self): treeroot = join(self.tmpdir, 'rootparent') shutil.copytree(join(TESTS, '06nested'), treeroot) pto = patch_ng.fromfile(join(TESTS, '06nested/06nested.patch')) self.assertTrue(pto.apply(root=treeroot))
def test_multiline_false_on_other_file(self): pto = patch_ng.fromfile("01uni_multi/01uni_multi.patch") os.chdir(join(TESTS, "01uni_multi")) self.assertFalse(pto.can_patch(b"updatedlg.cpp"))
def test_no_header_for_plain_diff_with_single_file(self): pto = patch_ng.fromfile(join(TESTS, "03trail_fname.patch")) self.assertEqual(pto.items[0].header, [])
def test_header_for_second_file_in_svn_diff(self): pto = patch_ng.fromfile(join(TESTS, "01uni_multi/01uni_multi.patch")) self.assertEqual(pto.items[1].header[0], b'Index: updatedlg.h\r\n') self.assertTrue(pto.items[1].header[1].startswith(b'====='))
def test_can_patch_single_source(self): pto2 = patch_ng.fromfile("02uni_newline.patch") self.assertTrue(pto2.can_patch(b"02uni_newline.from"))
def test_hunk_desc(self): pto = patch_ng.fromfile(testfile('git-changed-file.diff')) self.assertEqual(pto.items[0].hunks[0].desc, b'class JSONPluginMgr(object):')
def test_autofixed_absolute_path(self): pto = patch_ng.fromfile(join(TESTS, "data/autofix/absolute-path.diff")) self.assertEqual(pto.errors, 0) self.assertEqual(pto.warnings, 9) self.assertEqual(pto.items[0].source, b"winnt/tests/run_tests.py")
def test_can_patch_checks_source_filename_even_if_target_can_be_patched( self): pto2 = patch_ng.fromfile("04can_patch.patch") self.assertFalse(pto2.can_patch("04can_patch_ng.to"))
def test_autofixed_stripped_trailing_whitespace(self): pto = patch_ng.fromfile( join(TESTS, "data/autofix/stripped-trailing-whitespace.diff")) self.assertEqual(pto.errors, 0) self.assertEqual(pto.warnings, 4)
def test_single_false_on_other_file(self): pto3 = patch_ng.fromfile("03trail_fname.patch") self.assertFalse(pto3.can_patch("03trail_fname.from"))
def test_apply_returns_true_on_success(self): self.tmpcopy(['03trail_fname.patch', '03trail_fname.from']) pto = patch_ng.fromfile('03trail_fname.patch') self.assertTrue(pto.apply())
def test_svn_detected(self): pto = patch_ng.fromfile(join(TESTS, "01uni_multi/01uni_multi.patch")) self.assertEqual(pto.type, patch_ng.SVN)
def test_fromfile(self): pst = patch_ng.fromfile(join(TESTS, "01uni_multi/01uni_multi.patch")) self.assertNotEqual(pst, False) self.assertEqual(len(pst), 5) ps2 = patch_ng.fromfile(testfile("failing/not-a-patch.log")) self.assertFalse(ps2)