def run_fork(args): patchfns.chdir_to_base_dir() top_patch = patchfns.find_top_patch() if not top_patch: return cmd_result.ERROR new_patch = args.arg_new_name if args.arg_new_name else patchfns.next_filename(top_patch) new_patch_file = patchfns.patch_file_name(new_patch) new_patch_dir = os.path.join(patchfns.QUILT_PC, new_patch) if patchfns.patch_in_series(new_patch) or os.path.isdir(new_patch_dir) or os.path.exists(new_patch_file): output.error('Patch %s exists already, please choose a new name\n' % patchfns.print_patch(new_patch)) return cmd_result.ERROR | cmd_result.SUGGEST_RENAME is_ok = patchfns.rename_in_db(top_patch, new_patch) is_ok = is_ok if not is_ok else patchfns.rename_in_series(top_patch, new_patch) if is_ok: top_patch_dir = os.path.join(patchfns.QUILT_PC, top_patch) try: os.rename(top_patch_dir, new_patch_dir) except OSError: is_ok = False if is_ok: top_patch_file = patchfns.patch_file_name(top_patch) if os.path.exists(top_patch_file): try: shutil.copy2(top_patch_file, new_patch_file) except Exception: is_ok = False if not is_ok: output.write('Fork of patch %s to patch %s failed\n' % (patchfns.print_patch(top_patch), patchfns.print_patch(new_patch))) else: output.error('Fork of patch %s created as %s\n' % (patchfns.print_patch(top_patch), patchfns.print_patch(new_patch))) return cmd_result.OK if is_ok else cmd_result.ERROR
def run_pop(args): number = stop_at_patch = None patchfns.chdir_to_base_dir() if args.patchnamornum: if args.patchnamornum.isdigit(): number = int(args.patchnamornum) else: stop_at_patch = patchfns.find_applied_patch(args.patchnamornum) if not stop_at_patch: return cmd_result.ERROR elif not args.opt_all: number = 1 silent = args.opt_quiet if patchfns.top_patch_needs_refresh() and not args.opt_force: output.error('The topmost patch %s needs to be refreshed first.\n' % patchfns.print_top_patch()) return cmd_result.ERROR | cmd_result.SUGGEST_FORCE_OR_REFRESH patches = list_patches(number=number, stop_at_patch=stop_at_patch) if not patches: output.error('No patch removed\n') return cmd_result.ERROR is_ok = True for patch in patches: result = remove_patch(patch, force=args.opt_force, check=args.opt_remove, silent=silent) if result is not True: return cmd_result.ERROR if result is False else result if not args.opt_quiet: output.write('\n') if not patchfns.top_patch(): output.write('No patches applied\n') else: output.write('Now at patch %s\n' % patchfns.print_top_patch()) return cmd_result.OK if is_ok is True else cmd_result.ERROR
def run_next(args): patchfns.chdir_to_base_dir() nextpatch = patchfns.find_unapplied_patch(args.arg_patch) if not nextpatch: return cmd_result.ERROR output.write('%s\n' % patchfns.print_patch(nextpatch)) return cmd_result.OK
def run_add(args): patchfns.chdir_to_base_dir() patch = patchfns.find_applied_patch(args.opt_patch) if not patch: return 1 patch_dir = os.path.join(patchfns.QUILT_PC, patch) status = 0 for filename in args.filelist: filename = patchfns.filename_rel_base(filename) if not patchfns.in_valid_dir(filename): status = 1 continue if patchfns.file_in_patch(patch, filename): output.error('File %s is already in patch %s\n' % (filename, patchfns.print_patch(patch))) status = 2 if status != 1 else 1 next_patch = patchfns.next_patch_for_file(patch, filename) if next_patch is not None: output.error('File %s modified by patch %s\n' % (filename, patchfns.print_patch(next_patch))) status = 1 continue if os.path.islink(filename): output.error('Cannot add symbolic link %s\n' % filename) status = 1 continue if not backup.backup(patch_dir, [filename]): output.error('Failed to back up file %s\n' % filename) status = 1 continue if os.path.exists(filename): # The original tree may be read-only. os.chmod(filename, os.stat(filename).st_mode|stat.S_IWUSR) output.write('File %s added to patch %s\n' % (filename, patchfns.print_patch(patch))) return status
def run_rename(args): patchfns.chdir_to_base_dir() patch = patchfns.find_patch_in_series(args.opt_patch) if not patch: return cmd_result.ERROR new_patch = patchfns.patch_name_base(args.new_name) new_patch_exists = patchfns.patch_in_series(new_patch) new_patch_exists = True if new_patch_exists else os.path.isdir(os.path.join(patchfns.QUILT_PC, new_patch)) new_patch_exists = True if new_patch_exists else os.path.exists(patchfns.patch_file_name(new_patch)) if new_patch_exists: output.error('Patch %s exists already, please choose a different name\n' % patchfns.print_patch(new_patch)) return cmd_result.ERROR is_ok = True if patchfns.is_applied(patch): is_ok = patchfns.rename_in_db(patch, new_patch) if is_ok: is_ok = move_file(os.path.join(patchfns.QUILT_PC, patch), os.path.join(patchfns.QUILT_PC, new_patch)) if is_ok: is_ok = patchfns.rename_in_series(patch, new_patch) if is_ok and os.path.exists(patchfns.patch_file_name(patch)): is_ok = move_file(patchfns.patch_file_name(patch), patchfns.patch_file_name(new_patch)) if is_ok: output.write('Patch %s renamed to %s\n' % (patchfns.print_patch(patch), patchfns.print_patch(new_patch))) return cmd_result.OK else: output.error('Renaming of patch %s to %s failed\n' % (patchfns.print_patch(patch), patchfns.print_patch(new_patch))) return cmd_result.ERROR
def run_remove(args): patchfns.chdir_to_base_dir() patch = patchfns.find_applied_patch(args.opt_patch) if not patch: return cmd_result.ERROR prpatch = patchfns.print_patch(patch) patchfn = patchfns.patch_file_name(patch) patchrefrfile = os.path.join(patchfns.QUILT_PC, patch + '~refresh') patchrefrdir = os.path.dirname(patchrefrfile) budir = patchfns.backup_dir_name(patch) is_ok = True for filename in args.file_list: if patchfns.SUBDIR: filename = os.path.join(patchfns.SUBDIR, filename) if not patchfns.file_in_patch(filename, patch): output.error('File %s is not in patch %s\n' % (filename, prpatch)) is_ok = False continue next_patch = patchfns.next_patch_for_file(patch, filename) if next_patch: output.error('File %s modified by patch %s\n' % (filename, patchfns.print_patch(next_patch))) is_ok = False continue # Restore file from backup if not backup.restore(budir, filelist=[filename], touch=True): output.error('Failed to remove file %s from patch %s\n' % (filename, prpatch)) is_ok = False continue if os.path.exists(patchrefrdir) and os.path.exists(patchfn): fsutils.touch(patchrefrfile) output.write('File %s removed from patch %s\n' % (filename, prpatch)) return cmd_result.OK if is_ok else cmd_result.ERROR
def run_top(args): patchfns.chdir_to_base_dir() top = patchfns.find_top_patch() if not top: return cmd_result.ERROR output.write('%s\n' % patchfns.print_patch(top)) return cmd_result.OK
def run_revert(args): patchfns.chdir_to_base_dir() patch = patchfns.find_applied_patch(args.opt_patch) if not patch: return cmd_result.ERROR prpatch = patchfns.print_patch(patch) if patchfns.SUBDIR: args.files = [os.path.join(patchfns.SUBDIR, item) for item in args.files] is_ok = True for filename in args.files: if not patchfns.file_in_patch(filename, patch): is_ok = False output.error('File %s is not in patch %s\n' % (filename, prpatch)) continue next_patch = patchfns.next_patch_for_file(patch, filename) if next_patch: is_ok = False output.error('' % (filename, patchfns.print_patch(next_patch))) continue if not is_ok: return cmd_result.ERROR workdir = patchfns.gen_tempfile(os.getcwd(), asdir=True) atexit.register(clean_up, workdir) if not patchfns.apply_patch_temporarily(workdir, patch, args.files): return cmd_result.ERROR for filename in args.files: revert_ok = True wdfilename = os.path.join(workdir, filename) if os.path.exists(wdfilename) and os.path.getsize(wdfilename) > 0: if os.path.exists(filename) and diff.same_contents(filename, wdfilename): output.write('File %s is unchanged\n' % filename) continue try: fdir = os.path.dirname(filename) if fdir and not os.path.exists(fdir): os.makedirs(fdir) shutil.copy2(wdfilename, filename) except OSError as edata: revert_ok = False else: if not os.path.exists(filename): output.write('File %s is unchanged\n' % filename) continue try: os.remove(filename) fdir = os.path.dirname(filename) if os.path.exists(fdir) and len(os.listdir(fdir)) == 0: os.removedirs(fdir) except OSError as edata: revert_ok = False if revert_ok: output.write('Changes to %s in patch %s reverted\n' % (filename, prpatch)) else: output.error('Failed to revert changes to %s in patch %s\n' % (filename, prpatch)) is_ok = False return cmd_result.OK if is_ok else cmd_result.ERROR
def run_previous(args): patchfns.chdir_to_base_dir() patch = patchfns.find_patch_in_series(args.arg_patch) if not patch: return cmd_result.ERROR befores = patchfns.applied_before(patch) if not befores: return cmd_result.ERROR output.write('%s\n' % patchfns.print_patch(befores[-1])) return cmd_result.OK
def run_applied(args): patchfns.chdir_to_base_dir() patch = patchfns.find_applied_patch(args.patch) if not patch: return cmd_result.ERROR output.start_pager() for patch in patchfns.applied_before(patch) + [patch]: output.write('%s\n' % patchfns.print_patch(patch)) output.wait_for_pager() return cmd_result.OK
def run_header(args): def read_input(): text = sys.stdin.read() if args.opt_strip_trailing_whitespace: return _trim_trailing_ws(text) return text def get_text(pfile): text = putils.get_patch_hdr(pfile, omit_diffstat=args.opt_strip_diffstat) if args.opt_strip_trailing_whitespace: return _trim_trailing_ws(text) return text def set_text(pfile, text): if args.opt_backup: try: shutil.copy2(pfile, pfile + '~') except Exception as edata: output.perror(edata) if args.opt_strip_trailing_whitespace: text = _trim_trailing_ws(text) putils.set_patch_hdr(pfile, text, omit_diffstat=args.opt_strip_diffstat) patchfns.chdir_to_base_dir() if not args.opt_backup: args.opt_backup = customization.get_config('QUILT_BACKUP') patch = patchfns.find_patch_in_series(args.arg_patch) if not patch: return cmd_result.ERROR patch_file = patchfns.patch_file_name(patch) if args.opt_replace: set_text(patch_file, read_input()) output.write('Replaced header of patch %s\n' % patchfns.print_patch(patch)) elif args.opt_append: set_text(patch_file, get_text(patch_file) + read_input()) output.write('Appended text to header of patch %s\n' % patchfns.print_patch(patch)) elif args.opt_edit: savelang = os.getenv('LANG', None) os.environ['LANG'] = patchfns.ORIGINAL_LANG tempfile = patchfns.gen_tempfile() result = shell.run_cmd('%s %s' % (os.getenv('EDITOR'), tempfile)) if savelang: os.environ['LANG'] = savelang output.error(result.stderr) output.write(result.stdout) text = open(tempfile).read() os.remove(tempfile) if result.eflags != 0: return cmd_result.ERROR set_text(patch_file, text) output.write('Replaced header of patch %s\n' % patchfns.print_patch(patch)) else: if not os.path.exists(patch_file): return cmd_result.OK output.start_pager() output.write(get_text(patch_file)) output.wait_for_pager() return cmd_result.OK
def run_fold(args): patchfns.chdir_to_base_dir() if not args.opt_strip_level: args.opt_strip_level = '1' opt_patch_args = '' if not args.opt_quiet else ' -s' if not args.opt_force or args.opt_quiet: opt_patch_args += ' -f' if args.opt_reverse: opt_patch_args += ' -R' top = patchfns.find_top_patch() if not top: return cmd_result.ERROR failed = suggest_force = False try: workdir = patchfns.gen_tempfile(template=os.getcwd(), asdir=True) if patchfns.SUBDIR: subdir = patchfns.SUBDIR prefix = os.path.join(workdir, patchfns.SUBDIR) + os.sep else: subdir = '.' prefix = workdir + os.sep patch_args = '-p%s --backup --prefix="%s" -E %s' % (args.opt_strip_level, prefix, opt_patch_args) patch_text = sys.stdin.read() result = putils.apply_patch_text(patch_text, indir=subdir, patch_args=patch_args) output.write(result.stdout) output.error(result.stderr) if result.eflags != 0 and not args.opt_force: suggest_force = True failed = True if not failed: for filename in fsutils.files_in_dir(workdir): backup_file = patchfns.backup_file_name(top, filename) if not os.path.exists(backup_file): try: backup_file_dir = os.path.dirname(backup_file) if backup_file_dir and not os.path.exists(backup_file_dir): os.makedirs(backup_file_dir) os.link(os.path.join(workdir, filename), backup_file) except OSError as edata: failed = True break except KeyboardInterrupt: failed = True if failed: for filename in fsutils.files_in_dir(workdir): try: shutil.move(os.path.join(workdir, filename), filename) except OSError: output.error('File %s may be corrupted\n' % filename) if os.path.exists(workdir): shutil.rmtree(workdir) return cmd_result.OK if not failed else cmd_result.ERROR_SUGGEST_FORCE if suggest_force else cmd_result.ERROR
def run_import(args): patchfns.chdir_to_base_dir() if args.opt_patch and len(args.patchfiles) > 1: output.error('Option `-P\' can only be used when importing a single patch\n') return cmd_result.ERROR patch_args = ('-p%s' % args.opt_strip) if args.opt_strip else '' if args.opt_reverse: patch_args = '-R' if not patch_args else patch_args + ' -R' before = patchfns.patch_after(patchfns.top_patch()) for patch_file in args.patchfiles: patch = args.opt_patch if args.opt_patch else os.path.basename(patch_file) patch_file_name = patchfns.find_patch_file(patch_file) if not patch_file_name: return cmd_result.ERROR merged = False if patchfns.is_applied(patch): output.error('Patch %s is applied\n' % patchfns.print_patch(patch)) return cmd_result.ERROR dest = patchfns.patch_file_name(patch) if patchfns.patch_in_series(patch): if patch_file_name == dest: output.error('Patch %s already exists in series.\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if not args.opt_force: output.error('Patch %s exists. Replace with -f.\n' % patchfns.print_patch(patch)) return cmd_result.ERROR_SUGGEST_FORCE if args.opt_desc != 'n': merged_patch = merge_patches(dest, patch_file_name, args.opt_desc) if merged_patch is False: return cmd_result.ERROR merged = True output.error('Replacing patch %s with new version\n' % patchfns.print_patch(patch)) elif os.path.exists(dest): output.write('Importing patch %s\n' % patchfns.print_patch(patch)) else: output.write('Importing patch %s (stored as %s)\n' % (patch_file, patchfns.print_patch(patch))) dest_dir = os.path.dirname(dest) if not os.path.exists(dest_dir): os.makedirs(dest_dir) try: if merged: fsutils.set_file_contents(dest, merged_patch) else: # just in case dest == patch_file do it this way text = fsutils.get_file_contents(patch_file_name) fsutils.set_file_contents(dest, text) except IOError as edata: output.error('Failed to import patch %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if not patchfns.patch_in_series(patch) and not patchfns.insert_in_series(patch, patch_args, before): output.error('Failed to insert patch %s into file series\n' % patchfns.print_patch(patch)) return cmd_result.OK
def run_new(args): patchfns.chdir_to_base_dir() patch = patchfns.patch_name_base(args.patchname) if patchfns.patch_in_series(patch): output.error('Patch "%s" exists already\n' % patchfns.print_patch(patch)) return cmd_result.ERROR | cmd_result.SUGGEST_RENAME patchfns.create_db() if not patchfns.insert_in_series(patch) or not patchfns.add_to_db(patch): output.error('Failed to create patch %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR else: output.write('Patch %s is now on top\n' % patchfns.print_patch(patch)) return cmd_result.OK
def run_snapshot(args): patchfns.chdir_to_base_dir() snap_subdir = '.snap' snap_subdir_path = os.path.join(patchfns.QUILT_PC, snap_subdir) if os.path.exists(snap_subdir_path): shutil.rmtree(snap_subdir_path) if args.opt_remove: return cmd_result.OK os.makedirs(snap_subdir_path) files = [] for patch in patchfns.applied_patches(): files += patchfns.files_in_patch(patch) # Use set functionality to remove duplicates result = backup.backup(snap_subdir_path, set(files)) return cmd_result.OK if result else cmd_result.ERROR
def run_edit(args): patchfns.chdir_to_base_dir() if patchfns.pyquilt_command('add %s' % ' '.join(args.filelist)) not in [0, 2]: return cmd_result.ERROR efilelist = args.filelist if not patchfns.SUBDIR else [os.path.join(patchfns.SUBDIR, fnm) for fnm in args.filelist] os.environ['LANG'] = patchfns.ORIGINAL_LANG result = shell.run_cmd('%s %s' % (os.getenv('EDITOR'), ' '.join(efilelist))) output.error(result.stderr) output.write(result.stdout) status = cmd_result.OK if result.eflags == 0 else cmd_result.ERROR for filename in args.filelist: efname = filename if not patchfns.SUBDIR else os.path.join(patchfns.SUBDIR, filename) if not os.path.exists(efname): patchfns.pyquilt_command('revert %s' % filename) status = cmd_result.ERROR return status
def run_files(args): patchfns.chdir_to_base_dir() first_patch = None if args.opt_combine: args.opt_all = True if args.opt_combine != '-': first_patch = patchfns.find_patch_in_series(args.opt_combine) if not first_patch: return cmd_result.ERROR last_patch = patchfns.find_applied_patch(args.patch) if not last_patch: return cmd_result.ERROR if args.opt_all: if not first_patch: first_patch = patchfns.applied_patches()[0] patches = patchfns.patches_before(last_patch) + [last_patch] if first_patch not in patches: output.error('Patch %s not applied before patch %s\n' % (patchfns.print_patch(first_patch), patchfns.print_patch(last_patch))) return cmd_result.ERROR patches = patches[patches.index(first_patch):] else: patches = [last_patch] use_status = args.opt_verbose and not args.opt_labels # Note: If opt_labels is set, then use_status is not set. output.start_pager() for patch in patches: if args.opt_all and args.opt_verbose and not args.opt_labels: output.write('%s\n' % patch) for filename in sorted(patchfns.files_in_patch(patch)): if args.opt_labels: if args.opt_verbose: output.write('[%s] ' % patch) else: output.write('%s ' % patch) if not use_status: output.write('%s\n' % filename) else: status = ' ' buname = patchfns.backup_file_name(patch, filename) if os.path.exists(buname) and os.path.getsize(buname) > 0: if not os.path.exists(filename) or os.path.getsize(filename) == 0: status = '-' elif os.path.exists(filename) or os.path.getsize(filename) > 0: status = '+' output.write('%s %s\n' % (status, filename)) output.wait_for_pager() return cmd_result.OK
def run_unapplied(args): patchfns.chdir_to_base_dir() if args.arg_patch: start = patchfns.find_patch_in_series(args.arg_patch) if not start: return cmd_result.ERROR patch = patchfns.patch_after(start) else: patch = patchfns.find_unapplied_patch() if not patch: return cmd_result.OK output.start_pager() patches = [patch] + patchfns.patches_after(patch) for patch in patches: output.write('%s\n' % patchfns.print_patch(patch)) output.wait_for_pager() return cmd_result.OK
def run_delete(args): patchfns.chdir_to_base_dir() if args.patch: patch = patchfns.find_patch(args.patch) if not patch: return cmd_result.ERROR else: patch = patchfns.top_patch() if args.opt_next: patch =patchfns.patch_after(patch) if not patch: output.error('No next patch\n') return cmd_result.ERROR if not patch: patchfns.find_top_patch() return cmd_result.ERROR if patchfns.is_applied(patch): if patch != patchfns.top_patch(): output.error('Patch %s is currently applied\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if patchfns.pyquilt_command('pop -qf') != cmd_result.OK: return cmd_result.ERROR if patchfns.remove_from_series(patch): output.write('Removed patch %s\n' % patchfns.print_patch(patch)) else: output.error('Failed to remove patch %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR patch_file = patchfns.patch_file_name(patch) if args.opt_remove and os.path.exists(patch_file): if args.opt_backup: try: os.rename(patch_file, patch_file + '~') except IOError: output.error('Failed to backup patch file %s\n' % patch_file) return cmd_result.ERROR else: try: os.remove(patch_file) except IOError: output.error('Failed to remove patch file %s\n' % patch_file) return cmd_result.ERROR return cmd_result.OK
def run_annotate(args): patchfns.chdir_to_base_dir() args.opt_patch = patchfns.find_applied_patch(args.opt_patch) opt_file = os.path.join(patchfns.SUBDIR, args.filename) if not args.opt_patch: return cmd_result.ERROR patches = [] files = [] next_patch = None for patch in patchfns.applied_patches(): old_file = patchfns.backup_file_name(patch, opt_file) if os.path.isfile(old_file): patches.append(patch) files.append(old_file) if patch == args.opt_patch: next_patch = patchfns.next_patch_for_file(patch, opt_file) break if not next_patch: files.append(opt_file) else: files.append(patchfns.backup_file_name(next_patch, opt_file)) if len(patches) == 0: for line in open(files[-1]).readlines(): output.write('\t%s\n' % line) return cmd_result.OK difftxt = '' for index in range(len(patches)): difftxt += annotation_for(files[index], files[index + 1], index + 1) template = patchfns.gen_tempfile() open(template, 'w').write('\n' * len(open(files[0]).readlines())) shell.run_cmd('patch %s' % template, difftxt) annotations = [line.rstrip() for line in open(template).readlines()] os.remove(template) output.start_pager() if os.path.exists(files[-1]): for annotation, line in zip(annotations, open(files[-1]).readlines()): output.write('%s\t%s' % (annotation, line)) output.write('\n') for index, patch in zip(range(len(patches)), patches): output.write('%s\t%s\n' % (index + 1, patchfns.print_patch(patch))) output.wait_for_pager() return cmd_result.OK
def run_patches(args): patchfns.chdir_to_base_dir() if args.opt_verbose: applied = '+ ' current = '= ' unapplied = ' ' else: applied = current = unapplied = '' do_colorize = args.opt_color == 'always' or (args.opt_color in ['auto', 'tty'] and sys.stderr.isatty()) if do_colorize: colour.set_up() file_paths = [os.path.join(patchfns.SUBDIR, file_path) if patchfns.SUBDIR else file_path for file_path in args.filelist] top = patchfns.top_patch() output.start_pager() if top: scan_applied('series_app', applied, file_paths, patchfns.patches_before(top)) scan_applied('series_top', current, file_paths, (top,)) scan_unapplied('series_una', unapplied, file_paths, patchfns.patches_after(top)) output.wait_for_pager() return cmd_result.OK
def run_grep(args): patchfns.chdir_to_base_dir() problem_args = [] # i.e. those wit optional arguments for arg in ['--color', '--colour']: while arg in args.remainder_of_args: problem_args.append(arg) args.remainder_of_args.remove(arg) grep_opts, grep_args = getopt.getopt(args.remainder_of_args, grep_options, grep_long_options) opt_list = make_opt_list(grep_opts) + problem_args if expect_pattern(grep_opts): files = grep_args[1:] opt_list += grep_args[0:1] else: files = grep_args if not files: files = get_files() if len(files) == 1 and '-h' not in opt_list and '--no-filename' not in opt_list: opt_list.append('-H') result = shell.run_cmd(['grep'] + opt_list + files) output.write(result.stdout) output.error(result.stderr) return result.eflags
def run_series(args): patchfns.chdir_to_base_dir() output.start_pager() do_colorize = args.opt_color == 'always' or (args.opt_color == 'auto' and sys.stderr.isatty()) if do_colorize: colour.set_up() if do_colorize or args.opt_verbose: top = patchfns.top_patch() for patch in patchfns.patches_before(top): string = '+ %s\n' % patchfns.print_patch(patch) output.write(colour.wrap(string, 'series_app') if do_colorize else string) if top: string = '= %s\n' % patchfns.print_patch(top) output.write(colour.wrap(string, 'series_top') if do_colorize else string) for patch in patchfns.patches_after(top): string = ' %s\n' % patchfns.print_patch(patch) output.write(colour.wrap(string, 'series_una') if do_colorize else string) else: for patch in patchfns.cat_series(): output.write('%s\n' % patchfns.print_patch(patch)) output.wait_for_pager() return cmd_result.OK
def run_mail(args): patchfns.chdir_to_base_dir() if not shell.which('formail'): output.write("You have to install 'formail' to use 'quilt mail'") return cmd_result.ERROR if not args.opt_signature or args.opt_signature == '-': args.opt_signature = None else: try: args.opt_signature = open(args.opt_signature).read() except IOError as edata: output.perror(edata) if args.first_patch: args.first_patch = patchfns.find_first_patch() if args.first_patch == '-' else patchfns.find_patch(args.first_patch) if not args.first_patch: return cmd_result.ERROR if not args.last_patch: args.last_patch = args.first_patch else: args.last_patch = patchfns.find_last_patch() if args.last_patch == '-' else patchfns.find_patch(args.last_patch) if not args.last_patch: return cmd_result.ERROR if not args.opt_sender: hostname = socket.gethostname() args.opt_sender = '%s@%s' % (get_login_name(), hostname) if not re.match('^\S+@\S+\.\S+$', args.opt_sender): output.error('Could not determine the envelope sender address. Please use --sender.\n') return cmd_result.ERROR _dummy, args.opt_sender_address = email.utils.parseaddr(args.opt_sender) if not args.opt_charset: lc_all = os.getenv('LC_ALL', patchfns.ORIGINAL_LANG) if lc_all and lc_all.endswith('UTF-8'): args.opt_charset = 'UTF-8' else: args.opt_charset = 'ISO-8859-15' patches = patchfns.cat_series() if args.first_patch: first_index = patches.index(args.first_patch) last_index = patches.index(args.last_patch) if last_index < first_index: output.error('Patch %s not applied before patch %s\n' % (patchfns.print_patch(args.first_patch), patchfns.print_patch(args.first_patch))) return cmd_result.ERROR patches = patches[first_index:last_index + 1] total = len(patches) tmpdir = patchfns.gen_tempfile(asdir=True) atexit.register(lambda: not os.path.exists(tmpdir) or shutil.rmtree(tmpdir, ignore_errors=True)) subject_map = {} patch_msgs = [] for patch in patches: contents = fsutils.get_file_contents(patchfns.patch_file_name(patch)) mailmsg = message_from_patch(contents, args.opt_charset) if mailmsg is False: subject = None else: patch_msgs.append(mailmsg) subject = mailmsg['Replace-Subject'] if mailmsg is False or not subject: output.error('Unable to extract a subject header from %s\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if subject in subject_map: subject_map[subject].append(patch) else: subject_map[subject] = [patch] if len(subject_map) != len(patches): duplicates = [] for key in sorted(subject_map): plist = subject_map[key] if len(plist) > 1: duplicates += plist output.error('Patches %s have duplicate subject headers.\n' % ', '.join([patchfns.print_patch(dup) for dup in duplicates])) return cmd_result.ERROR if args.opt_reply_to: if not os.path.exists(args.opt_reply_to): output.error('File %s does not exist\n' % args.opt_reply_to) return cmd_result.ERROR args.opt_reply_to = email.message_from_string(open(args.opt_reply_to).read()) if not args.opt_subject: repto_subject = args.opt_reply_to['Subject'] args.opt_subject = 'Re: %s' % re.sub('^([ \t]*[rR][eE]:[ \t]*)', '', repto_subject) intro = 'Message-Id: <%s>\n' % msgid(args) intro += 'User-Agent: pyquilt\n' last_ts = time.localtime() intro += time.strftime('Date: %a, %d %b %Y %H:%M:%S %z\n', last_ts) intro += 'From: %s\n' % (args.opt_from if args.opt_from else args.opt_sender) intro += 'To: %s\n' % (', '.join(args.opt_to) if args.opt_to else '') intro += 'Cc: %s\n' % (', '.join(args.opt_cc) if args.opt_cc else '') intro += 'Bcc: %s\n' % (', '.join(args.opt_bcc) if args.opt_bcc else '') if args.opt_reply_to: intro += in_reply_to_header(args.opt_reply_to) intro += references_header(args.opt_reply_to) intro += 'Subject-Prefix: [%s @num@/@total@]\n' % args.opt_prefix intro += 'Subject: %s\n\n' % (args.opt_subject if args.opt_subject else '') intro += ('%s\n\n' % args.opt_message) if args.opt_message else '' intro += ('-- \n%s\n' % args.opt_signature) if args.opt_signature else '' intro_message = email.message_from_string(intro) intro_message.set_charset(args.opt_charset) if not args.opt_message: introfile = patchfns.gen_tempfile() open(introfile, 'w').write(intro_message.as_string()) result = shell.run_cmd('%s %s' % (os.getenv('EDITOR'), introfile)) output.write(result.stdout) output.error(result.stderr) intro_message = email.message_from_string(open(introfile).read(), charset=args.opt_charset) os.remove(introfile) if result.eflags != 0: return cmd_result.ERROR subject = join_lines(intro_message['Subject']) if not subject: if not args.opt_message: savefile = patchfns.gen_tempfile() open(savefile, 'w').write(intro_message.as_string()) output.error('Introduction has no subject header (saved as %s)\n' % savefile) else: output.error('Introduction has no subject header\n') return cmd_result.ERROR if args.opt_mbox: fsutils.touch(args.opt_mbox) subject_prefix = email.utils.quote(join_lines(intro_message['Subject-Prefix'])) subject_prefix += ' ' if subject_prefix else '' subject_prefix = re.sub('@total@', str(total), subject_prefix) del intro_message['Subject-Prefix'] pnum_fmt = '{0:0%s}' % len(str(total)) pfx = re.sub('@num@', pnum_fmt.format(0), subject_prefix) intro_message.replace_header('Subject', pfx + intro_message['Subject']) remove_empty_headers(intro_message) for key in ['To', 'Cc', 'Bcc']: # Consolidate up the various recipient fields values = intro_message.get_all(key) if values: del intro_message[key] intro_message[key] = ', '.join(values) process_mail(intro_message, args) pnum = 0 for msg in patch_msgs: msg.add_header('Content-Disposition', 'inline', filename=patches[pnum]) for key in intro_message.keys(): if key.lower() not in ['message-id', 'references', 'in-reply-to', 'subject']: for value in intro_message.get_all(key): msg[key] = value msg['References'] = get_reference_to(intro_message) msg.set_charset(args.opt_charset) for aclass in ['To', 'Cc', 'Bcc']: rclass = 'Recipient-' + aclass if msg.has_key(rclass): msg[aclass] = ',\n '.join(msg.get_all(rclass)) del msg[rclass] pnum += 1 ppfx = re.sub('@num@', pnum_fmt.format(pnum), subject_prefix) msg['Message-Id'] = msgid(args) msg['Subject'] = '%s%s' % (ppfx, msg['Replace-Subject']) if ppfx else msg['Replace-Subject'] del msg['Replace-Subject'] remove_empty_headers(msg) process_mail(msg, args) return cmd_result.OK
def run_diff(args): patchfns.chdir_to_base_dir() snap_subdir = os.path.join(patchfns.QUILT_PC, '.snap') if args.opt_snapshot else None if args.opt_combine: first_patch = '-' if args.opt_combine == '-' else patchfns.find_applied_patch(args.opt_combine) if not first_patch: return cmd_result.ERROR else: first_patch = None if len([opt for opt in [args.opt_combine, args.opt_snapshot, args.opt_relative] if opt]) > 1: output.error('Options `--combine\', `--snapshot\', and `-z\' cannot be combined.\n') return cmd_result.ERROR last_patch = patchfns.find_applied_patch(args.last_patch) if not last_patch: return cmd_result.ERROR if args.opt_strip_level is None: args.opt_strip_level = patchfns.patch_strip_level(last_patch) if args.opt_strip_level not in ['0', '1', 'ab']: output.error('Cannot diff patches with -p%s, please specify -p0, -p1, or -pab instead\n' % args.opt_strip_level) return cmd_result.ERROR files = [] if args.opt_snapshot and len(args.opt_files) == 0: for path, _dirs, bases in os.walk(snap_subdir): rpath = '' if path == snap_subdir else os.path.relpath(path, snap_subdir) files += [os.path.join(rpath, base) for base in bases] files.sort() args.opt_combine = True first_patch = patchfns.applied_patches()[0] if args.opt_combine: patches = patchfns.patches_before(last_patch) + [last_patch] if first_patch != '-': try: patches = patches[patches.index(first_patch):] except ValueError: output.error('Patch %s not applied before patch %s\n' % (patchfns.print_patch(first_patch), patchfns.print_patch(last_patch))) return cmd_result.ERROR else: patches = [last_patch] if len(args.opt_files) > 0: # use a set as it should be more efficient ofiles = set() for ofile in args.opt_files: if ofile.startswith('.' + os.sep): ofile = ofile[2:] if patchfns.SUBDIR: ofile = os.path.join(patchfns.SUBDIR, ofile) ofiles.add(ofile) for patch in patches: for fname in patchfns.files_in_patch_ordered(patch): if fname in ofiles and fname not in files: files.append(fname) else: for patch in patches: for fname in patchfns.files_in_patch_ordered(patch): if fname not in files: files.append(fname) if args.opt_sort: files.sort() if args.opt_relative: workdir = patchfns.gen_tempfile(os.path.join(os.getcwd(), 'quilt'), asdir=True) atexit.register(clean_up, workdir) if not patchfns.apply_patch_temporarily(workdir, last_patch, files): return cmd_result.ERROR is_ok = True files_were_shadowed = False if args.opt_color: colour.set_up() output.start_pager() for filename in files: snapshot_path = os.path.join(snap_subdir, filename) if snap_subdir else None if snapshot_path and os.path.exists(snapshot_path): old_file = snapshot_path elif args.opt_relative: old_file = os.path.join(workdir, filename) else: patch = patchfns.first_modified_by(filename, patches) if not patch: if not args.opt_snapshot: output.error('File %s is not being modified\n' % filename) continue old_file = patchfns.backup_file_name(patch, filename) next_patch = patchfns.next_patch_for_file(last_patch, filename) if not next_patch: new_file = filename else: new_file = patchfns.backup_file_name(next_patch, filename) files_were_shadowed = True if not do_diff(filename, old_file, new_file, args): output.error('Diff failed, aborting\n') return cmd_result.ERROR if files_were_shadowed: output.error('Warning: more recent patches modify files in patch %s\n' % patchfns.print_patch(last_patch)) output.wait_for_pager() return cmd_result.OK
def run_refresh(args): workdir = None def clean_up(status): if workdir and os.path.isdir(workdir): shutil.rmtree(workdir) return status patchfns.chdir_to_base_dir() patch = patchfns.find_applied_patch(args.patchname) if not patch: return cmd_result.ERROR if not args.opt_sort: files = patchfns.files_in_patch_ordered(patch) else: files = patchfns.files_in_patch(patch) if args.opt_new_name: if args.patchname: output.error('Can only refresh the topmost patch with -z currently\n') return cmd_result.ERROR old_patch = patch old_patch_args = patchfns.patch_args(old_patch) if args.opt_new_name is True: patch = patchfns.next_filename(patch) else: patch = args.opt_new_name if os.path.exists(patchfns.patch_file_name(patch)): output.error('Patch %s exists already\n' % patchfns.print_patch(patch)) return cmd_result.ERROR if args.opt_strip_level is None: args.opt_strip_level = patchfns.patch_strip_level(patch) if args.opt_strip_level in ['0', '1']: num_strip_level = args.opt_strip_level elif args.opt_strip_level == 'ab': num_strip_level = '1' else: output.error('Cannot refresh patches with -p%s, please specify -p0 or -p1 instead\n' % args.opt_strip_level) return cmd_result.ERROR if args.opt_new_name: workdir = patchfns.gen_tempfile(asdir=True, template=os.path.join(os.getcwd(), 'quilt')) if not patchfns.apply_patch_temporarily(workdir, old_patch): return clean_up(cmd_result.ERROR) patch_content = '' files_were_shadowed = False for filn in files: if args.opt_new_name: old_file = os.path.join(workdir, filn) new_file = filn else: old_file = patchfns.backup_file_name(patch, filn) next_patch = patchfns.next_patch_for_file(patch, filn) if not next_patch: new_file = filn else: new_file = patchfns.backup_file_name(next_patch, filn) files_were_shadowed = True result = diff.diff_file(filn, old_file, new_file, args) if result.eflags > 1: output.error('\n'.join(result.stderr, 'Diff failed, aborting\n')) return clean_up(cmd_result.ERROR) elif result.eflags == 0 or not result.stdout: continue else: patch_content += result.stdout patch_file = patchfns.patch_file_name(patch) prev_patch_file = patch_file if os.path.isfile(patch_file) else '/dev/null' result_content = patchfns.patch_header(prev_patch_file) if not patch_content: output.error('Nothing in patch %s\n' % patchfns.print_patch(patch)) else: if files_were_shadowed: if not args.opt_force: output.error('More recent patches modify files in patch %s. Enforce refresh with -f.\n' % patchfns.print_patch(patch)) return clean_up(cmd_result.ERROR_SUGGEST_FORCE) if args.opt_strip_trailing_whitespace: output.error('Cannot use --strip-trailing-whitespace on a patch that has shadowed files.\n') if args.opt_strip_trailing_whitespace and not files_were_shadowed: result = putils.remove_trailing_ws(patch_content, num_strip_level) if result.eflags == cmd_result.OK: patch_content = result.stdout if result.stderr: output.error(result.stderr) else: result = putils.remove_trailing_ws(patch_content, num_strip_level, dry_run=True) if result.stderr: output.error(result.stderr) if args.opt_diffstat: diffstat_text = diffstat.get_diffstat(patch_content, num_strip_level) result_content += diffstat_text result_content += patch_content patch_file_dir = os.path.dirname(patch_file) if not os.path.exists(patch_file_dir): os.makedirs(patch_file_dir) is_ok = True QUILT_PC = customization.get_config('QUILT_PC') if fsutils.file_contents_equal(patch_file, result_content): output.write('Patch %s is unchanged\n' % patchfns.print_patch(patch)) else: if args.opt_backup and os.path.isfile(patch_file): try: os.rename(patch_file, patch_file + '~') except OSError: output.error('Failed to create backup %s\n' % patch_file + '~') is_ok = False if is_ok: is_ok = fsutils.set_file_contents(patch_file, result_content) if is_ok and args.opt_new_name: insert_ok = patchfns.insert_in_series(patch, old_patch_args) if not insert_ok: output.error('Failed to insert patch %s into file series\n' % patchfns.print_patch(patch)) return clean_up(cmd_result.ERROR) try: patch_dir = os.path.join(QUILT_PC, patch) if os.path.exists(patch_dir): shutil.rmtree(patch_dir) os.rename(workdir, patch_dir) open(patchfns.DB, 'a').write(patch + '\n') except: output.error('Failed to create patch %s\n' % patchfns.print_patch(patch)) return clean_up(cmd_result.ERROR) output.write('Fork of patch %s created as %s\n' % (patchfns.print_patch(old_patch), patchfns.print_patch(patch))) elif is_ok and patch_content: output.write('Refreshed patch %s\n' % patchfns.print_patch(patch)) fsutils.touch(os.path.join(QUILT_PC, patch, '.timestamp')) if is_ok: tagf = os.path.join(QUILT_PC, patch + '~refresh') if os.path.exists(tagf): os.remove(tagf) is_ok = patchfns.change_db_strip_level('-p%s' % num_strip_level, patch) return clean_up(cmd_result.OK if is_ok and patch_content else cmd_result.ERROR)
def run_push(args): def add_patch(patch): def apply_patch(patch_file, patch_args): if not os.path.exists(patch_file) or os.path.getsize(patch_file) == 0: return cmd_result.Result(0, '', '') return putils.apply_patch(patch_file, patch_args=patch_args) tmp = None patch_file = patchfns.patch_file_name(patch) output.write('Applying patch %s\n' % patchfns.print_patch(patch)) try: pp_args = push_patch_args(patch, reverse=False) prefix = os.path.join(patchfns.QUILT_PC, patch) if not args.opt_leave_rejects: tmp = patchfns.gen_tempfile() trf = '-r %s' % tmp else: trf = '' patch_args = '%s --backup --prefix="%s/" %s -E %s' % (pp_args, prefix, trf, more_patch_args) result = apply_patch(patch_file, patch_args=patch_args) if not args.opt_quiet or result.eflags != 0: if do_colorize: output.error(colorize(cleanup_patch_output(result.stderr, args))) output.write(colorize(cleanup_patch_output(result.stdout, args))) else: output.error(cleanup_patch_output(result.stderr, args)) output.write(cleanup_patch_output(result.stdout, args)) except KeyboardInterrupt: rollback_patch(patch) output.error('Interrupted by user; patch %s was not applied.\n' % patchfns.print_patch(patch)) return False finally: if tmp: os.remove(tmp) if result.eflags == 0 or (result.eflags == 1 and args.opt_force): patchfns.add_to_db(patch) refresh_file = os.path.join(patchfns.QUILT_PC, patch + '~refresh') if result.eflags == 0: if os.path.exists(refresh_file): os.remove(refresh_file) else: fsutils.touch(refresh_file) patch_dir = os.path.join(patchfns.QUILT_PC, patch) if os.path.exists(patch_dir): fsutils.touch(os.path.join(patch_dir, '.timestamp')) else: os.mkdir(patch_dir) if not os.path.exists(patch_file): output.write('Patch %s does not exist; applied empty patch\n' % patchfns.print_patch(patch)) elif not putils.get_patch_diff(patch_file): output.write('Patch %s appears to be empty; applied\n' % patchfns.print_patch(patch)) elif result.eflags != 0: output.write('Applied patch %s (forced; needs refresh)\n' % patchfns.print_patch(patch)) return False else: rollback_patch(patch) tmp = patchfns.gen_tempfile() trf = '-r %s' % tmp pp_args = push_patch_args(patch, reverse=True) patch_args = '%s --backup --prefix="%s/" %s -E %s' % (pp_args, prefix, trf, more_patch_args) result = apply_patch(patch_file, patch_args=patch_args) if result.eflags == 0: output.write('Patch %s can be reverse-applied\n' % patchfns.print_patch(patch)) else: output.write('Patch %s does not apply (enforce with -f)\n' % patchfns.print_patch(patch)) rollback_patch(patch) os.remove(tmp) return False return True number = stop_at_patch = None patchfns.chdir_to_base_dir() if args.patchnamornum: if args.patchnamornum.isdigit(): number = int(args.patchnamornum) else: stop_at_patch = args.patchnamornum elif not args.opt_all: number = 1 stop_at_patch = patchfns.find_unapplied_patch(stop_at_patch) if not stop_at_patch: return cmd_result.ERROR silent_unless_verbose = '-s' if not args.opt_verbose else None if args.opt_force: args.opt_leave_rejects = True more_patch_args = ' -s' if args.opt_quiet else '' more_patch_args += ' -f' if not args.opt_force or args.opt_quiet else '' if args.opt_merge is 'default': more_patch_args += ' --merge' elif args.opt_merge: more_patch_args += ' --merge=%s' % args.opt_merge more_patch_args += ' -F%d' % args.opt_fuzz if args.opt_fuzz else '' if patchfns.top_patch_needs_refresh(): output.write('The topmost patch %s needs to be refreshed first.\n' % patchfns.print_top_patch()) return cmd_result.ERROR | cmd_result.SUGGEST_REFRESH patches = list_patches(number=number, stop_at_patch=stop_at_patch, push_all=args.opt_all) patchfns.create_db() do_colorize = args.opt_color == 'always' or (args.opt_color == 'auto' and sys.stderr.isatty()) if do_colorize: colour.set_up() is_ok = True for patch in patches: is_ok = add_patch(patch) if not is_ok: break if not args.opt_quiet: output.write('\n') if is_ok: output.write('Now at patch %s\n' % patchfns.print_top_patch()) return cmd_result.OK if is_ok else cmd_result.ERROR
def run_setup(args): spec_file = series_file = None patchfns.chdir_to_base_dir() tmpfile = patchfns.gen_tempfile() def add_exit_handler(): try: os.remove(tmpfile) except OSError: pass script = [] if args.series_file.endswith('.spec'): spec_file = args.series_file print 'not yet implemented' else: series_file = args.series_file tar_dir = patch_dir = '.' for line in open(series_file).readlines(): if line.startswith('# Sourcedir: '): tar_dir = line[len('# Sourcedir: '):].rstrip() elif line.startswith('# Source: '): script.append(('tar', tar_dir, line[len('# Source: '):].rstrip())) elif line.startswith('# Patchdir: '): patch_dir = line[len('# Patchdir: '):].rstrip() elif line.startswith('#') or len(line.strip()) == 0: pass else: script.append(('patch', patch_dir, line.rstrip())) if check_for_existing_directories(args, script): return cmd_result.ERROR for action in script: if action[0] == 'tar': tarball = os.path.join(args.sourcedir, action[2]) if args.sourcedir else action[2] if not os.path.exists(tarball): output.error('File %s not found\n' % tarball) return cmd_result.ERROR output.write('Unpacking archive %s\n' % tarball) target_dir = os.path.join(args.prefix, action[1]) if args.prefix else action[1] try: os.makedirs(target_dir) except OSError as edata: if edata.errno != errno.EEXIST: output.error('%s: %s\n' % (target_dir, edata.strerror)) return cmd_result.ERROR if tarfile.is_tarfile(tarball): tarobj = tarfile.open(tarball, 'r') tarobj.extractall(target_dir) tarobj.close() else: output.error('%s: is not a supported tar format\n' % tarball) return cmd_result.ERROR if check_for_existing_files(args, script): output.error("Trying alternative patches and series names...\n") patchfns.QUILT_PATCHES = "quilt_patches" patchfns.QUILT_SERIES = "quilt_series" if check_for_existing_files(args, script): return cmd_result.ERROR tar_dir = tar_file = None for action in script: if action[0] == 'tar': tar_dir = None if action[1] == '.' else action[1] tar_file = action[2] elif action[0] == 'patch': patches_dir = os.path.join(action[1], patchfns.QUILT_PATCHES) if args.prefix: patches_dir = os.path.join(args.prefix, patches_dir) if not os.path.exists(patches_dir): create_symlink(args.sourcedir, patches_dir) patchfns.create_db(os.path.dirname(patches_dir)) this_series_file = os.path.join(action[1], patchfns.QUILT_SERIES) if args.prefix: this_series_file = os.path.join(args.prefix, this_series_file) if series_file: if not os.path.exists(this_series_file): create_symlink(series_file, this_series_file) else: if not os.path.exists(this_series_file): fobj = open(this_series_file, 'w') fobj.write('# Patch series file for quilt," created by pyquilt\n') if tar_dir is not None: fobj.write('# Sourcedir: %s\n' % tar_dir) if tar_file is not None: fobj.write('# Source: %s\n' % tar_file) fobj.write('# Patchdir: %s\n' % action[1]) fobj.write('# \n' % action[1]) else: fobj = open(this_series_file, 'a') fobj.write('%s\n' % action[2]) fobj.close() return cmd_result.OK