def run(self, args): db = Db(self.get_pc_dir()) top = db.top_patch() if not top: self.exit_error("No patches applied.") print(top)
def __init__(self, cwd, quilt_pc, quilt_patches): super(Delete, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) self.pop = Pop(cwd, quilt_pc)
def run(self, args): series = Series(self.get_patches_dir()) if not series.exists(): self.exit_error("No series file found.") db = Db(self.get_pc_dir()) top = None if args.patch: patch_name = args.patch top = Patch(patch_name) else: if db.exists(): top = db.top_patch() if not top: top = series.first_patch() if not top: self.exit_error("No patch in series.") else: print(top) else: patch = series.patch_after(top) if not patch: self.exit_error("No patch available after %s." % top) else: print(patch)
def test_unreverted(self): """ Test when the patch modifies unreverted files """ with tmp_series() as [dir, series]: old_dir = os.getcwd() try: os.chdir(dir) db = Db(dir) db.add_patch(Patch("patch")) db.save() originals = os.path.join(db.dirname, "patch") os.mkdir(originals) make_file(b"unreverted original\n", originals, "unreverted") make_file(b"reverted original\n", originals, "reverted") make_file(b"unreverted patched\n", dir, "unreverted") make_file(b"reverted patched\n", dir, "reverted") Refresh(dir, db.dirname, series.dirname).refresh() make_file(b"unreverted change\n", dir, "unreverted") make_file(b"reverted change\n", dir, "reverted") cmd = quilt.revert.Revert(dir, db.dirname, series.dirname) cmd.revert_file("reverted") with open(os.path.join(dir, "reverted"), "rb") as file: self.assertEqual(file.read(), b"reverted patched\n") with open(os.path.join(dir, "unreverted"), "rb") as file: self.assertEqual(file.read(), b"unreverted change\n") finally: os.chdir(old_dir)
def run(self, args): db = Db(self.get_pc_dir()) top = db.top_patch() series = Series(self.get_patches_dir()) if top is None: patches = series.patches() else: patches = series.patches_after(top) for patch in patches: print(patch)
def run(self, options, args): db = Db(self.get_pc_dir()) top = db.top_patch() series = Series(self.get_patches_dir()) if top is None: patches = series.patches() else: patches = series.patches_after(top) for patch in patches: print patch
class New(Command): patch_created = Signal() """ Creates a new patch in the queue """ def __init__(self, cwd, quilt_pc, quilt_patches): super(New, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def create(self, patchname): """ Adds a new patch with patchname to the queue The new patch will be added as the topmost applied patch. """ patch = Patch(patchname) if self.series.is_patch(patch): raise PatchAlreadyExists(self.series, patchname) patch_dir = self.quilt_patches patch_dir.create() patchfile = patch_dir + File(patchname) patchfile.touch() pc_dir = self.quilt_pc + patchname if pc_dir.exists(): # be sure that the directory is clear pc_dir.delete() # create empty .pc/<patchname> directory as quilt does too pc_dir.create() top = self.db.top_patch() # add new patch after the current topmost applied patch self.series.add_patches([patch], top) # "apply" patch self.db.add_patch(patch) # create patches/series files self.series.save() # create .pc/.version and .pc/applied-patches files self.db.save() self.patch_created(patch)
def run(self, args): series = Series(self.get_patches_dir()) db = Db(self.get_pc_dir()) top = None if args.patch: top = Patch(args.patch) else: if db.exists(): top = db.top_patch() if not top: self.exit_error("No patches applied.") else: patch = series.patch_before(top) if not patch: self.exit_error("No patch available before %s." % top) else: print(patch)
def run(self, options, args): series = Series(self.get_patches_dir()) db = Db(self.get_pc_dir()) top = None if len(args) > 0: top = Patch(args[0]) else: if db.exists(): top = db.top_patch() if not top: top = series.first_patch() if not top: self.exit_error("No patch in series.") else: print top else: patch = series.patch_before(top) if not patch: self.exit_error("No patch available after %s." % patch) else: print patch
class Import(Command): """ Command class to import patches into the patch queue """ def __init__(self, cwd, quilt_pc, quilt_patches): super(Import, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def _import_patches(self, patches, reverse=False, strip=None): top = self.db.top_patch() patchlist = [] for patch in patches: patchlist.append(Patch(patch, reverse=reverse, strip=strip)) self.series.add_patches(patchlist, top) self.series.save() def import_patch(self, patch_name, new_name=None): """ Import patch into the patch queue The patch is inserted after the current top applied patch """ if new_name: dir_name = os.path.dirname(new_name) name = os.path.basename(new_name) dest_dir = self.quilt_patches + Directory(dir_name) dest_dir.create() else: name = os.path.basename(patch_name) dest_dir = self.quilt_patches patch_file = File(patch_name) dest_file = dest_dir + File(name) patch_file.copy(dest_file) self._import_patches([name]) def import_patches(self, patches): """ Import several patches into the patch queue """ dest_dir = self.quilt_patches patch_names = [] for patch in patches: patch_name = os.path.basename(patch) patch_file = File(patch) dest_file = dest_dir + File(patch_name) patch_file.copy(dest_file) patch_names.append(patch_name) self._import_patches(patch_names)
def test_unrefreshed(self): with TmpDirectory() as dir: db = Db(dir.get_name()) db.add_patch(Patch("unrefreshed.patch")) db.save() make_file(b"", db.dirname, "unrefreshed.patch~refresh") cmd = Pop(dir.get_name(), db.dirname) with six.assertRaisesRegex(self, QuiltError, r"needs to be refreshed"): cmd.unapply_top_patch()
def run(self, args): series = Series(self.get_patches_dir()) if args.v: applied = Db(self.get_pc_dir()).patches() for patch in applied[:-1]: print("+ " + patch.get_name()) if applied: print("= " + applied[-1].get_name()) patches = series.patches_after(applied[-1]) else: patches = series.patches() for patch in patches: print(" " + patch.get_name()) else: for patch in series.patches(): print(patch.get_name())
def test_series_v(self): with tmp_series() as [dir, series]: applied = Db(dir) applied.add_patch(Patch("applied.patch")) applied.add_patch(Patch("topmost.patch")) applied.save() series.add_patches(applied.applied_patches()) series.add_patch(Patch("unapplied.patch")) series.save() output = run_cli(SeriesCommand, dict(v=True), series.dirname, applied.dirname) self.assertMultiLineEqual(output, "+ applied.patch\n" "= topmost.patch\n" " unapplied.patch\n")
def test_refresh(self): with TmpDirectory() as dir: old_dir = os.getcwd() try: os.chdir(dir.get_name()) db = Db(".pc") db.create() backup = os.path.join(".pc", "patch") os.mkdir(backup) make_file(b"", backup, "file") db.add_patch(Patch("patch")) db.save() make_file(b"", "patch") make_file(b"added\n", "file") cmd = quilt.refresh.Refresh(".", ".pc", ".") cmd.refresh() with open("patch", "r") as patch: self.assertTrue(patch.read(30)) finally: os.chdir(old_dir)
def test_next_after(self): """ Delete the successor to the topmost patch """ with tmp_series() as [dir, series]: series.add_patch(Patch("topmost")) series.add_patch(Patch("unapplied")) series.save() db = Db(dir) db.add_patch(Patch("topmost")) db.save() cmd = Delete(dir, db.dirname, series.dirname) cmd.delete_next() series.read() [patch] = series.patches() self.assertEqual(patch, Patch("topmost"))
class New(Command): patch_created = Signal() """ Creates a new patch in the queue """ def __init__(self, cwd, quilt_pc, quilt_patches): super(New, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def create(self, patchname): """ Adds a new patch with patchname to the queue The new patch will be added after the top patch """ patch = Patch(patchname) if self.series.is_patch(patch): raise PatchAlreadyExists(self.series, patchname) patch_dir = self.quilt_patches patch_dir.create() patchfile = patch_dir + File(patchname) patchfile.touch() pc_dir = self.quilt_pc + patchname if pc_dir.exists(): # be sure that the directory is clear pc_dir.delete() else: pc_dir.create() top = self.db.top_patch() self.series.add_patches([patch], top) self.series.save() self.patch_created(patch)
def test_fail_after_success(self): """ Test where the first patch applies but a later patch fails """ with tmp_series() as [dir, series]: make_file( b"--- /dev/null\n" b"+++ dir/new-file\n" b"@@ -0,0 +1,1 @@\n" b"+new file\n", series.dirname, "good.patch") series.add_patch(Patch("good.patch")) self._make_conflict(dir, series) series.save() cmd = Push(dir, quilt_pc=dir, quilt_patches=series.dirname) with six.assertRaisesRegex(self, QuiltError, r"conflict\.patch does not apply"), \ self._suppress_output(): cmd.apply_all() [applied] = Db(dir).patches() self.assertEqual(applied.get_name(), "good.patch") with open(os.path.join(dir, "new-file"), "rb") as file: self.assertEqual(file.read(), b"new file\n") with open(os.path.join(dir, "file"), "rb") as file: self.assertEqual(file.read(), b"conflict\n")
class Delete(Command): """Command class to delete patches """ deleting_patch = Signal() deleted_patch = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Delete, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) self.pop = Pop(cwd, quilt_pc) def _delete_patch(self, patch, remove=False, backup=False): if self.series.is_empty(): raise NoPatchesInSeries(self.series) if not self.series.is_patch(patch): raise UnknownPatch(self.series, patch) applied = self.db.top_patch() == patch self.deleting_patch(patch, applied) if applied: self.pop._unapply_patch(patch) self.db = self.pop.db self.db.save() self.series.remove_patch(patch) self.series.save() patch_file = self.quilt_patches + File(patch.get_name()) if remove: if backup: patch_file.copy(File(patch_file.get_name() + "~")) patch_file.delete_if_exists() self.deleted_patch(patch) def delete_next(self, remove=False, backup=False): """ Delete next unapplied patch If remove is True the patch file will also be removed. If remove and backup are True a copy of the deleted patch file will be made. """ patch = self.db.top_patch() if patch: after = self.series.patch_after(patch) else: after = self.series.first_patch() if not after: raise QuiltError("No next patch") self._delete_patch(after, remove=remove, backup=backup) def delete_patch(self, patch_name=None, remove=False, backup=False): """ Delete specified patch from the series If remove is True the patch file will also be removed. If remove and backup are True a copy of the deleted patch file will be made. """ if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise NoAppliedPatch(self.db) self._delete_patch(patch, remove=remove, backup=backup)
def __init__(self, cwd, quilt_pc, quilt_patches): super(Refresh, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches)
class Refresh(Command): """ Command class to refresh (add or remove chunks) a patch """ edit_patch = Signal() refreshed = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Refresh, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def refresh(self, patch_name=None, edit=False): """ Refresh patch with patch_name or applied top patch if patch_name is None """ if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise QuiltError("No patch applied. Nothing to refresh.") pc_dir = self.quilt_pc + patch.get_name() patch_file = self.quilt_patches + File(patch.get_name()) files = pc_dir.content()[1] with TmpFile(prefix="pquilt-") as tmpfile: f = tmpfile.open() if patch_file.exists(): header = patch.get_header(self.quilt_patches) tmpfile.write(header) for file_name in files: if file_name == ".timestamp": continue orig_file = pc_dir + File(file_name) new_file = File(file_name) left_label, right_label, index = self._get_labels(file_name, orig_file, new_file) self._write_index(tmpfile, index) diff = Diff(orig_file, new_file) diff.run(self.cwd, fd=f, left_label=left_label, right_label=right_label) if tmpfile.is_empty(): raise QuiltError("Nothing to refresh.") if edit: self.edit_patch(tmpfile) tpatch = Patch(tmpfile.get_name()) tpatch.run(pc_dir.get_name(), dry_run=True, quiet=True) if patch_file.exists(): diff = Diff(patch_file, tmpfile) if diff.equal(self.cwd): raise QuiltError("Nothing to refresh.") tmpfile.copy(patch_file) timestamp = pc_dir + File(".timestamp") timestamp.touch() refresh = self.quilt_pc + File(patch.get_name() + "~refresh") refresh.delete_if_exists() self.refreshed(patch) def _get_labels(self, file_name, old_file, new_file): dir = os.path.basename(self.cwd) old_hdr = dir + ".orig/" + file_name new_hdr = dir + "/" + file_name index = new_hdr if not old_file.exists() or old_file.is_empty(): old_hdr = "/dev/null" if not new_file.exists() or new_file.is_empty(): old_hdr = new_hdr new_hdr = "/dev/null" return (old_hdr, new_hdr, index) def _write_index(self, f, index): f.write("Index: ") f.write(index) f.write("\n") f.write(INDEX_LINE) f.write("\n")
class Add(Command): """Command class to add files to the current patch """ file_added = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Add, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def _file_in_patch(self, filename, patch, ignore): """ Checks if a backup file of the filename in the current patch exists """ file = self.quilt_pc + File(os.path.join(patch.get_name(), filename)) if file.exists(): if ignore: return True else: raise QuiltError("File %s is already in patch %s" % (filename, patch.get_name())) return False def _file_in_next_patches(self, filename, patch): """ Checks if a backup file of the filename in the applied patches after patch exists """ if not self.db.is_patch(patch): # no patches applied return patches = self.db.patches_after(patch) for patch in patches: file = self.quilt_pc + File(os.path.join(patch.get_name(), filename)) if file.exists(): raise QuiltError("File %s is already modified by patch %s" % (filename, patch.get_name())) def _backup_file(self, file, patch): """ Creates a backup of file """ dest_dir = self.quilt_pc + patch.get_name() file_dir = file.get_directory() if file_dir: #TODO get relative path dest_dir = dest_dir + file_dir backup = Backup() backup.backup_file(file, dest_dir, copy_empty=True) def add_file(self, filename, patch_name=None, ignore=False): """ Add file to the patch with patch_name. If patch_name is None or empty the topmost patch will be used. Adding an already added patch will raise an QuiltError if ignore is False. """ file = File(filename) if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise NoAppliedPatch(self.db) exists = self._file_in_patch(filename, patch, ignore) if exists: return self._file_in_next_patches(filename, patch) if file.is_link(): raise QuiltError("Cannot add symbolic link %s" % filename) self._backup_file(file, patch) if file.exists(): # be sure user can write original file os.chmod(filename, file.get_mode() | stat.S_IWUSR | stat.S_IRUSR) self.file_added(file, patch) def add_files(self, filenames, patch_name=None, ignore=False): for filename in filenames: self.add_file(filename, patch_name, ignore)
class Refresh(Command): """ Command class to refresh (add or remove chunks) a patch """ edit_patch = Signal() refreshed = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Refresh, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def refresh(self, patch_name=None, edit=False): """ Refresh patch with patch_name or applied top patch if patch_name is None """ if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise QuiltError("No patch applied. Nothing to refresh.") pc_dir = self.quilt_pc + patch.get_name() patch_file = self.quilt_patches + File(patch.get_name()) files = pc_dir.content()[1] with TmpFile(prefix="pquilt-") as tmpfile: f = tmpfile.open() if patch_file.exists(): header = patch.get_header(self.quilt_patches) tmpfile.write(header) for file_name in files: if file_name == ".timestamp": continue orig_file = pc_dir + File(file_name) new_file = File(file_name) left_label, right_label, index = self._get_labels( file_name, orig_file, new_file) self._write_index(tmpfile, index) diff = Diff(orig_file, new_file) diff.run(self.cwd, fd=f, left_label=left_label, right_label=right_label) if tmpfile.is_empty(): raise QuiltError("Nothing to refresh.") if edit: self.edit_patch(tmpfile) tpatch = Patch(tmpfile.get_name()) tpatch.run(pc_dir.get_name(), dry_run=True, quiet=True) if patch_file.exists(): diff = Diff(patch_file, tmpfile) if diff.equal(self.cwd): raise QuiltError("Nothing to refresh.") tmpfile.copy(patch_file) timestamp = pc_dir + File(".timestamp") timestamp.touch() refresh = self.quilt_pc + File(patch.get_name() + "~refresh") refresh.delete_if_exists() self.refreshed(patch) def _get_labels(self, file_name, old_file, new_file): dir = os.path.basename(self.cwd) old_hdr = dir + ".orig/" + file_name new_hdr = dir + "/" + file_name index = new_hdr if not old_file.exists() or old_file.is_empty(): old_hdr = "/dev/null" if not new_file.exists() or new_file.is_empty(): old_hdr = new_hdr new_hdr = "/dev/null" return (old_hdr, new_hdr, index) def _write_index(self, f, index): f.write(b"Index: ") f.write(_encode_str(index)) f.write(b"\n") f.write(INDEX_LINE) f.write(b"\n")
class Revert(Command): """Command class to remove files from the current patch """ file_reverted = Signal() file_unchanged = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Revert, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def _file_in_patch(self, filename, patch): """ Checks if a backup file of the filename in the current patch exists and raises a QuiltError if not. """ pc_dir = self.quilt_pc + patch.get_name() file = pc_dir + File(filename) if not file.exists(): raise QuiltError("File %s is not in patch %s" % (filename, patch.get_name())) def _file_in_next_patches(self, filename, patch): """ Checks if a backup file of the filename in the applied patches after patch exists """ if not self.db.is_patch(patch): # no patches applied return patches = self.db.patches_after(patch) for patch in patches: file = self.quilt_pc + File( os.path.join(patch.get_name(), filename)) if file.exists(): raise QuiltError("File %s is modified by patch %s" % (filename, patch.get_name())) def _apply_patch_temporary(self, tmpdir, file, patch): backup = Backup() backup_file = backup.backup_file(file, tmpdir) patch_file = self.quilt_patches + File(patch.get_name()) if patch_file.exists() and not patch_file.is_empty(): try: patch.run( self.cwd, self.quilt_patches.get_absdir(), work_dir=tmpdir, no_backup_if_mismatch=True, remove_empty_files=True, force=True, quiet=True, suppress_output=True, ) except SubprocessError: pass # Expected to fail if there are other files in patch return backup_file def revert_file(self, filename, patch_name=None): """ Revert not added changes of filename. If patch_name is None or empty the topmost patch will be used. """ file = File(filename) if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise QuiltError("No patch available. Nothing to revert.") self._file_in_patch(filename, patch) self._file_in_next_patches(filename, patch) pc_dir = self.quilt_pc + patch.get_name() pc_file = pc_dir + file if not file.exists() and pc_file.is_empty(): # new and empty file will be reverted pc_file.delete() self.file_reverted(file, patch) return with TmpDirectory(prefix="pquilt-") as tmpdir: # apply current patch in temporary directory to revert changes of # file that aren't committed in the patch tmp_file = self._apply_patch_temporary(tmpdir, pc_file, patch) if tmp_file and tmp_file.exists() and not tmp_file.is_empty(): diff = Diff(file, tmp_file) if diff.equal(self.cwd): self.file_unchanged(file, patch) return dir = file.get_directory() if not dir: dir = Directory(os.getcwd()) else: dir.create() tmp_file.copy(dir) self.file_reverted(file, patch) else: self.file_unchanged(file, patch) def revert_files(self, filenames, patch_name=None): for filename in filenames: self.revert_file(filename, patch_name)
class Push(Command): applying = Signal() applying_patch = Signal() applied = Signal() applied_patch = Signal() applied_empty_patch = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Push, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def _apply_patch(self, patch, force=False, quiet=False): patch_name = patch.get_name() pc_dir = self.quilt_pc + patch_name patch_file = self.quilt_patches + File(patch_name) refresh = File(pc_dir.get_name() + "~refresh") forced = False self.applying_patch(patch) if patch_file.exists(): try: patch.run(self.cwd, patch_dir=self.quilt_patches, backup=True, prefix=pc_dir.get_name(), quiet=quiet) except SubprocessError as e: if not force: patch = RollbackPatch(self.cwd, pc_dir) patch.rollback() patch.delete_backup() raise QuiltError("Patch %s does not apply" % patch_name) else: refresh.touch() forced = True self.db.add_patch(patch) if pc_dir.exists(): timestamp = pc_dir + File(".timestamp") timestamp.touch() else: pc_dir.create() if not patch_file.exists(): self.applied_empty_patch(patch, False) elif pc_dir.is_empty(): self.applied_empty_patch(patch, True) elif forced: raise QuiltError("Applied patch %s (forced; needs refresh)" % patch.get_name()) else: self.applied_patch(patch) def _check(self): if not self.series.exists() or not self.series.patches(): raise NoPatchesInSeries(self.series) top = self.db.top_patch() if top is not None: refresh = top.get_name() + "~refresh" refresh = os.path.join(self.quilt_pc.get_name(), refresh) if os.path.exists(refresh): raise QuiltError("Patch %s needs to be refreshed" % \ top.get_name()) def apply_patch(self, patch_name, force=False, quiet=False): """ Apply all patches up to patch_name """ self._check() patch = Patch(patch_name) patches = self.series.patches_until(patch)[:] applied = self.db.applied_patches() for patch in applied: if patch in patches: patches.remove(patch) if not patches: raise AllPatchesApplied(self.series, self.db.top_patch()) self.applying(patch) try: for cur_patch in patches: self._apply_patch(cur_patch, force, quiet) finally: self.db.save() self.applied(self.db.top_patch()) def apply_next_patch(self, force=False, quiet=False): """ Apply next patch in series file """ self._check() top = self.db.top_patch() if not top: patch = self.series.first_patch() else: patch = self.series.patch_after(top) if not patch: raise AllPatchesApplied(self.series, top) self.applying(patch) self._apply_patch(patch, force, quiet) self.db.save() self.applied(self.db.top_patch()) def apply_all(self, force=False, quiet=False): """ Apply all patches in series file """ self._check() top = self.db.top_patch() if top: patches = self.series.patches_after(top) else: patches = self.series.patches() if not patches: raise AllPatchesApplied(self.series, top) try: for patch in patches: self.applying(patch) self._apply_patch(patch, force, quiet) finally: self.db.save() self.applied(self.db.top_patch())
def __init__(self, cwd, quilt_pc): super(Pop, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.db = Db(quilt_pc)
class Pop(Command): unapplying = Signal() unapplied = Signal() unapplied_patch = Signal() empty_patch = Signal() def __init__(self, cwd, quilt_pc): super(Pop, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.db = Db(quilt_pc) def _check(self, force=False): if not self.db.exists() or not self.db.patches(): raise NoAppliedPatch(self.db) if not force: patch = self.db.top_patch() pc_dir = self.quilt_pc + patch.get_name() refresh = File(pc_dir.get_name() + "~refresh") if refresh.exists(): raise QuiltError("Patch %s needs to be refreshed first." % patch.get_name()) def _unapply_patch(self, patch): self.unapplying(patch) patch_name = patch.get_name() pc_dir = self.quilt_pc + patch_name timestamp = pc_dir + File(".timestamp") timestamp.delete_if_exists() if pc_dir.is_empty(): pc_dir.delete() self.empty_patch(patch) else: unpatch = RollbackPatch(self.cwd, pc_dir) unpatch.rollback() unpatch.delete_backup() self.db.remove_patch(patch) refresh = File(pc_dir.get_name() + "~refresh") refresh.delete_if_exists() self.unapplied_patch(patch) def unapply_patch(self, patch_name, force=False): """ Unapply patches up to patch_name. patch_name will end up as top patch """ self._check(force) patches = self.db.patches_after(Patch(patch_name)) for patch in reversed(patches): self._unapply_patch(patch) self.db.save() self.unapplied(self.db.top_patch()) def unapply_top_patch(self, force=False): """ Unapply top patch """ self._check(force) patch = self.db.top_patch() self._unapply_patch(patch) self.db.save() self.unapplied(self.db.top_patch()) def unapply_all(self, force=False): """ Unapply all patches """ self._check(force) for patch in reversed(self.db.applied_patches()): self._unapply_patch(patch) self.db.save() self.unapplied(self.db.top_patch())
class Revert(Command): """Command class to remove files from the current patch """ file_reverted = Signal() file_unchanged = Signal() def __init__(self, cwd, quilt_pc, quilt_patches): super(Revert, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches) def _file_in_patch(self, filename, patch): """ Checks if a backup file of the filename in the current patch exists and raises a QuiltError if not. """ pc_dir = self.quilt_pc + patch.get_name() file = pc_dir + File(filename) if not file.exists(): raise QuiltError("File %s is not in patch %s" % (filename, patch.get_name())) def _file_in_next_patches(self, filename, patch): """ Checks if a backup file of the filename in the applied patches after patch exists """ if not self.db.is_patch(patch): # no patches applied return patches = self.db.patches_after(patch) for patch in patches: file = self.quilt_pc + File(os.path.join(patch.get_name(), filename)) if file.exists(): raise QuiltError("File %s is modified by patch %s" % (filename, patch.get_name())) def _apply_patch_temporary(self, tmpdir, file, patch): backup = Backup() backup_file = backup.backup_file(file, tmpdir) patch_file = self.quilt_patches + File(patch.get_name()) if patch_file.exists() and not patch_file.is_empty(): try: patch.run(self.cwd, self.quilt_patches.get_absdir(), work_dir=tmpdir, no_backup_if_mismatch=True, remove_empty_files=True, force=True, quiet=True, suppress_output=True, ) except SubprocessError: pass # Expected to fail if there are other files in patch return backup_file def revert_file(self, filename, patch_name=None): """ Revert not added changes of filename. If patch_name is None or empty the topmost patch will be used. """ file = File(filename) if patch_name: patch = Patch(patch_name) else: patch = self.db.top_patch() if not patch: raise QuiltError("No patch available. Nothing to revert.") self._file_in_patch(filename, patch) self._file_in_next_patches(filename, patch) pc_dir = self.quilt_pc + patch.get_name() pc_file = pc_dir + file if not file.exists() and pc_file.is_empty(): # new and empty file will be reverted pc_file.delete() self.file_reverted(file, patch) return with TmpDirectory(prefix="pquilt-") as tmpdir: # apply current patch in temporary directory to revert changes of # file that aren't committed in the patch tmp_file = self._apply_patch_temporary(tmpdir, pc_file, patch) if tmp_file and tmp_file.exists() and not tmp_file.is_empty(): diff = Diff(file, tmp_file) if diff.equal(self.cwd): self.file_unchanged(file, patch) return dir = file.get_directory() if not dir: dir = Directory(os.getcwd()) else: dir.create() tmp_file.copy(dir) self.file_reverted(file, patch) else: self.file_unchanged(file, patch) def revert_files(self, filenames, patch_name=None): for filename in filenames: self.revert_file(filename, patch_name)
def __init__(self, cwd, quilt_pc, quilt_patches): super(Revert, self).__init__(cwd) self.quilt_pc = Directory(quilt_pc) self.quilt_patches = Directory(quilt_patches) self.db = Db(quilt_pc) self.series = Series(quilt_patches)