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_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_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_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_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_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_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_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_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