def merge_patches(old, new, opt_desc): """Return the merge of the old and new patches""" old_desc = patchfns.gen_tempfile() open(old_desc, 'w').write(putils.get_patch_descr(old)) new_desc = patchfns.gen_tempfile() open(new_desc, 'w').write(putils.get_patch_descr(new)) if opt_desc is None: if os.path.getsize(old_desc) == 0: opt_desc = 'n' elif os.path.getsize(new_desc) == 0: opt_desc = 'o' if opt_desc is None: result = shell.run_cmd('diff -u %s %s' % (old_desc, new_desc)) diff_lines = result.stdout.splitlines(True) if len(diff_lines) > 2: output.error('Patch headers differ:\n') output.error(''.join(diff_lines[2:])) output.error('Please use -d {o|a|n} to specify which patch header(s) to keep.\n') os.remove(old_desc) os.remove(new_desc) return False patchtext = open(old_desc).read() if opt_desc != 'n' else '' if opt_desc == 'a': patchtext += '---\n' if opt_desc == 'o': patchtext += putils.get_patch_diff(new) else: patchtext += fsutils.get_file_contents(new) os.remove(old_desc) os.remove(new_desc) return patchtext
def apply_patch_text(text, indir=None, patch_args=""): from pyquilt_pkg import customization patch_opts = customization.get_default_opts("patch") if indir: cmd = "patch -d %s" % indir else: cmd = "patch" cmd += " %s %s" % (patch_opts, patch_args) return shell.run_cmd(cmd, input_text=text)
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_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 process_mail(message, args): if args.opt_send: sendmail_cmd = '%s %s --f %s ' % (os.getenv('QUILT_SENDMAIL', 'sendmail'), os.getenv('QUILT_SENDMAIL_ARGS', ''), args.opt_sender) sendmail_cmd += extract_recipients(message) output.write(sendmail_cmd) del message['Bcc'] result = shell.run_cmd(sendmail_cmd, message.as_string(False)) output.write(result.stdout) output.error(result.stderr) else: from_date = time.strftime('+%a %b %e %H:%M:%S %Y') fobj = open(args.opt_mbox, 'a') fobj.write('From %s %s\n' % (args.opt_sender_address, from_date)) for field, value in message.items(): fobj.write('%s: %s\n' % (field, value)) fobj.write('\n') for line in message.get_payload().splitlines(True): fobj.write(re.sub('^From ', '>From ', line)) fobj.close()
def annotation_for(old_file, new_file, annotation): """Return diff for annotation for changes from osd_file to new_file""" if not os.path.exists(old_file) or os.path.getsize(old_file) == 0: old_file = '/dev/null' if not os.path.exists(new_file) or os.path.getsize(new_file) == 0: new_file = '/dev/null' result = shell.run_cmd('diff -e "%s" "%s"' % (old_file, new_file)) if result.eflags > 1: output.error(result.stderr) sys.exit(result.eflags) difftxt = '' start_cre = re.compile('^(\d+)(,\d+)?([acd])$') end_cre = re.compile('^\.$') lines = result.stdout.splitlines(True) index = 0 aline = '%s\n' % annotation while index < len(lines): match = start_cre.match(lines[index]) if match: difftxt += lines[index] start = int(match.group(1)) if match.group(3) == 'a': index += 1 while end_cre.match(lines[index]) is None: difftxt += aline index += 1 difftxt += lines[index] elif match.group(3) == 'c': end = int(match.group(2)[1:]) if match.group(2) is not None else start cnt = end - start + 1 index += cnt + 1 difftxt += aline * cnt assert end_cre.match(lines[index]) difftxt += lines[index] else: assert match.group(3) == 'd' index += 1 else: assert False index += 1 return difftxt
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_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