def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options): """Send the message using the given SMTP server """ smtpuser, smtppassword, smtpusetls = __smtp_credentials try: s = smtplib.SMTP(smtpserver) except Exception as err: raise CmdException(str(err)) s.set_debuglevel(0) try: if smtpuser and smtppassword: s.ehlo() if smtpusetls: if not hasattr(socket, 'ssl'): raise CmdException( "cannot use TLS - no SSL support in Python") s.starttls() s.ehlo() s.login(smtpuser, smtppassword) result = s.sendmail(from_addr, to_addr_list, msg) if len(result): print( "mail server refused delivery for the following recipients:", result, ) except Exception as err: raise CmdException(str(err)) s.quit()
def __import_tarfile(tarpath, options): """Import patch series from a tar archive""" import tarfile assert tarfile.is_tarfile(tarpath) tar = tarfile.open(tarpath, 'r') names = tar.getnames() # verify paths in the tarfile are safe for n in names: if n.startswith('/'): raise CmdException("Absolute path found in %s" % tarpath) if n.find("..") > -1: raise CmdException("Relative path found in %s" % tarpath) # find the series file for seriesfile in names: if seriesfile.endswith('/series') or seriesfile == 'series': break else: raise CmdException("no 'series' file found in %s" % tarpath) # unpack into a tmp dir with tempfile.TemporaryDirectory('.stg') as tmpdir: tar.extractall(tmpdir) __import_series(os.path.join(tmpdir, seriesfile), options)
def func(parser, options, args): """Integrate a GNU diff patch into the current patch""" if len(args) > 1: parser.error('incorrect number of arguments') repository = directory.repository stack = repository.get_stack() check_local_changes(repository) check_conflicts(repository.default_iw) check_head_top_equal(stack) if len(args) == 1: filename = args[0] else: filename = None applied = stack.patchorder.applied if not applied: raise CmdException('No patches applied') current = applied[-1] if filename: if os.path.exists(filename): out.start('Folding patch "%s"' % filename) with io.open(filename, 'rb') as f: diff = f.read() else: raise CmdException('No such file: %s' % filename) else: out.start('Folding patch from stdin') diff = sys.stdin.buffer.read() if options.threeway: top_patch = stack.patches.get(current) apply_patch( stack, diff, base=top_patch.commit.data.parent, strip=options.strip, reject=options.reject, ) elif options.base: apply_patch( stack, diff, base=git_commit(options.base, repository), reject=options.reject, strip=options.strip, ) else: apply_patch( stack, diff, strip=options.strip, reject=options.reject, ) out.done()
def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options): """Send the message using the given SMTP server """ smtpuser, smtppassword, smtpusetls = __smtp_credentials try: s = smtplib.SMTP(smtpserver) except Exception as err: raise CmdException(str(err)) s.set_debuglevel(0) try: if smtpuser and smtppassword: s.ehlo() if smtpusetls: try: s.starttls() except (smtplib.SMTPException, RuntimeError) as e: # RuntimeError indicates that Python lacks SSL support. # SMTPException indicates that server does not do STARTTLS. raise CmdException("cannot use TLS: %s" % e) s.ehlo() s.login(smtpuser, smtppassword) result = s.sendmail(from_addr, to_addr_list, msg) if len(result): print( "mail server refused delivery for the following recipients:", result, ) except Exception as err: raise CmdException(str(err)) s.quit()
def func(parser, options, args): """Create a new patch.""" stack = directory.repository.current_stack if stack.repository.default_index.conflicts(): raise CmdException( 'Cannot create a new patch -- resolve conflicts first') # Choose a name for the new patch -- or None, which means make one # up later when we've gotten hold of the commit message. if len(args) == 0: name = None elif len(args) == 1: name = args[0] if not stack.patches.is_name_valid(name): raise CmdException('Invalid patch name: "%s"' % name) elif name in stack.patches: raise CmdException('%s: patch already exists' % name) else: parser.error('incorrect number of arguments') if options.verbose: verbose = options.verbose else: verbose = config.getbool('stgit.new.verbose') or False cd = CommitData( tree=stack.head.data.tree, parents=[stack.head], message='', author=Person.author(), committer=Person.committer(), ) cd = update_commit_data( stack.repository, cd, message=options.message, author=options.author(cd.author), trailers=options.trailers, edit=(not options.save_template and options.message is None), verbose=verbose, ) if options.save_template: options.save_template(cd.message) return utils.STGIT_SUCCESS if not options.no_verify: cd = run_commit_msg_hook(stack.repository, cd) if name is None: name = stack.patches.make_name(cd.message_str) # Write the new patch. check_head_top_equal(stack) trans = StackTransaction(stack) trans.patches[name] = stack.repository.commit(cd) trans.applied.append(name) return trans.execute('new: %s' % name)
def func(parser, options, args): """Pushes the given patches or the first unapplied onto the stack.""" stack = directory.repository.current_stack iw = stack.repository.default_iw clean_iw = (not options.keep and iw) or None trans = transaction.StackTransaction(stack, 'push', check_clean_iw=clean_iw) if options.number == 0: # explicitly allow this without any warning/error message return if not trans.unapplied: raise CmdException('No patches to push') if options.all: patches = list(trans.unapplied) elif options.number is not None: patches = trans.unapplied[:options.number] elif not args: patches = [trans.unapplied[0]] else: try: patches = parse_patches(args, trans.unapplied) except CmdException as e: try: patches = parse_patches(args, trans.applied) except CmdException: raise e else: raise CmdException( 'Patch%s already applied: %s' % ('es' if len(patches) > 1 else '', ', '.join(patches))) assert patches if options.reverse: patches.reverse() if options.set_tree: for pn in patches: trans.push_tree(pn) else: try: if options.merged: merged = set(trans.check_merged(patches)) else: merged = set() for pn in patches: trans.push_patch(pn, iw, allow_interactive=True, already_merged=pn in merged) except transaction.TransactionHalted: pass return trans.run(iw)
def func(parser, options, args): """Generate a new commit for the current or given patch.""" if options.spill: if ( len(args) > 0 or options.index or options.edit or options.update or options.patch or options.force or options.no_verify or options.sign_str ): raise CmdException('--spill option does not take any arguments or options') return __refresh_spill(annotate=options.annotate) else: # Catch illegal argument combinations. is_path_limiting = bool(args or options.update) if options.index and is_path_limiting: raise CmdException('Only full refresh is available with the --index option') if options.index and options.force: raise CmdException( 'You cannot --force a full refresh when using --index mode' ) if options.update and options.submodules: raise CmdException( '--submodules is meaningless when only updating modified files' ) if options.index and options.submodules: raise CmdException( '--submodules is meaningless when keeping the current index' ) # If submodules was not specified on the command line, infer a default # from configuration. if options.submodules is None: options.submodules = config.getbool('stgit.refreshsubmodules') return __refresh( args, force=options.force, target_patch=options.patch, message=options.message, author=options.author, sign_str=options.sign_str, annotate=options.annotate, use_temp_index=is_path_limiting, refresh_from_index=options.index, only_update_patchfiles=options.update, include_submodules=options.submodules, no_verify=options.no_verify, invoke_editor=options.edit, )
def func(parser, options, args): """Show the patches modifying a file.""" repository = directory.repository stack = repository.get_stack(options.branch) if not stack.patchorder.applied: raise CmdException('No patches applied') iw = repository.default_iw if not args: files = iw.changed_files(stack.head.data.tree) else: files = iw.ls_files(stack.head.data.tree, args) if not files: raise CmdException('No files specified or no local changes') directory.cd_to_topdir() # Find set of revisions that modify the selected files. revs = set( repository.run( ['git', 'rev-list', '--stdin', stack.base.sha1 + '..' + stack.top.sha1] ) .raw_input('--\n' + '\n'.join(files)) .output_lines() ) diff_lines = [] for pn in stack.patchorder.applied: commit = stack.patches[pn] if commit.sha1 not in revs: continue if options.diff: diff_lines.extend( [ b'-' * 79, pn.encode('utf-8'), b'-' * 79, commit.data.message, b'---', b'', repository.diff_tree( commit.data.parent.data.tree, commit.data.tree, pathlimits=files, diff_opts=options.diff_flags + color_diff_flags(), ), ] ) else: out.stdout(pn) if options.diff: pager(b'\n'.join(diff_lines))
def __cleanup_branch(name, force=False): stack = directory.repository.get_stack(name) if stack.protected: raise CmdException('This branch is protected. Clean up is not permitted') if not force and stack.patchorder.all: raise CmdException('Cannot clean up: the series still contains patches') out.start('Cleaning up branch "%s"' % name) stack.cleanup() out.done()
def __delete_branch(doomed_name, force=False): doomed = stack.Series(doomed_name) if __is_current_branch(doomed_name): raise CmdException('Cannot delete the current branch') if doomed.get_protected(): raise CmdException('This branch is protected. Delete is not permitted') out.start('Deleting branch "%s"' % doomed_name) doomed.delete(force) out.done()
def __parse_addresses(msg): """Return a two elements tuple: (from, [to])""" from_addr_list = __addr_list(msg, 'From') if len(from_addr_list) == 0: raise CmdException('No "From" address') to_addr_list = (__addr_list(msg, 'To') + __addr_list(msg, 'Cc') + __addr_list(msg, 'Bcc')) if len(to_addr_list) == 0: raise CmdException('No "To/Cc/Bcc" addresses') return (from_addr_list[0], set(to_addr_list))
def get_patch(stack, given_patch): """Get the name of the patch we are to refresh.""" if given_patch: patch_name = given_patch if not stack.patches.exists(patch_name): raise CmdException('%s: no such patch' % patch_name) return patch_name else: if not stack.patchorder.applied: raise CmdException( 'Cannot refresh top patch because no patches are applied') return stack.patchorder.applied[-1]
def func(parser, options, args): """Import a commit object as a new patch """ if not args: parser.error('incorrect number of arguments') if options.file and not options.fold: parser.error('--file can only be specified with --fold') if not options.unapplied: check_local_changes() check_conflicts() check_head_top_equal(crt_series) if options.ref_branch: remote_series = Series(options.ref_branch) else: remote_series = crt_series applied = remote_series.get_applied() unapplied = remote_series.get_unapplied() try: patches = parse_patches(args, applied + unapplied, len(applied)) commit_id = None except CmdException: if len(args) > 1: raise # no patches found, try a commit id commit_id = git_id(remote_series, args[0]) if not commit_id and len(patches) > 1: if options.name: raise CmdException('--name can only be specified with one patch') if options.parent: raise CmdException('--parent can only be specified with one patch') if options.update and not crt_series.get_current(): raise CmdException('No patches applied') if commit_id: # Try to guess a patch name if the argument was <branch>:<patch> try: patchname = args[0].split(':')[1] except IndexError: patchname = None __pick_commit(commit_id, patchname, options) else: if options.unapplied: patches.reverse() for patch in patches: __pick_commit(git_id(remote_series, patch), patch, options) print_crt_patch(crt_series)
def func(parser, options, args): """Integrate a GNU diff patch into the current patch """ if len(args) > 1: parser.error('incorrect number of arguments') check_local_changes() check_conflicts() check_head_top_equal(crt_series) if len(args) == 1: filename = args[0] else: filename = None current = crt_series.get_current() if not current: raise CmdException('No patches applied') if filename: if os.path.exists(filename): out.start('Folding patch "%s"' % filename) else: raise CmdException('No such file: %s' % filename) else: out.start('Folding patch from stdin') if options.threeway: crt_patch = crt_series.get_patch(current) bottom = crt_patch.get_bottom() git.apply_patch( filename=filename, base=bottom, strip=options.strip, reject=options.reject, ) elif options.base: git.apply_patch( filename=filename, reject=options.reject, strip=options.strip, base=git_id(crt_series, options.base), ) else: git.apply_patch( filename=filename, strip=options.strip, reject=options.reject, ) out.done()
def func(parser, options, args): if len(args) != 1: parser.error('incorrect number of arguments') name = args[0] stack = directory.repository.current_stack iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if name not in trans.all_patches: candidates = [pn for pn in trans.all_patches if name in pn] if len(candidates) == 1: name = candidates[0] elif len(candidates) > 1: out.info('Possible patches:\n %s' % '\n '.join(candidates)) raise CmdException('Ambiguous patch name "%s"' % name) elif re.match('[0-9A-Fa-f]{4,40}$', name): sha1 = name name = stack.patches.name_from_sha1(sha1) if not name: raise CmdException('No patch associated with %s' % sha1) else: raise CmdException('Patch "%s" does not exist' % name) if name in trans.applied: to_pop = set(trans.applied[trans.applied.index(name) + 1:]) popped_extra = trans.pop_patches(lambda pn: pn in to_pop) assert not popped_extra elif name in trans.unapplied: try: to_push = trans.unapplied[:trans.unapplied.index(name) + 1] if options.merged: merged = set(trans.check_merged(to_push)) else: merged = set() for pn in to_push: trans.push_patch(pn, iw, allow_interactive=True, already_merged=pn in merged) except transaction.TransactionHalted: pass else: raise CmdException('Cannot goto a hidden patch') return trans.execute('goto', iw)
def func(parser, options, args): """Sink patches down the stack.""" stack = directory.repository.current_stack if options.to and options.to not in stack.patchorder.applied: raise CmdException('Cannot sink below %s since it is not applied' % options.to) if len(args) > 0: patches = parse_patches(args, stack.patchorder.all) else: # current patch patches = list(stack.patchorder.applied[-1:]) if not patches: raise CmdException('No patches to sink') if options.to and options.to in patches: raise CmdException('Cannot have a sinked patch as target') unapplied_rem = [p for p in stack.patchorder.unapplied if p not in patches] applied_rem = [p for p in stack.patchorder.applied if p not in patches] insert_idx = applied_rem.index(options.to) if options.to else 0 stay_applied, re_applied = applied_rem[:insert_idx], applied_rem[ insert_idx:] if options.nopush: applied = stay_applied + patches unapplied = re_applied + unapplied_rem else: applied = stay_applied + patches + re_applied unapplied = unapplied_rem iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) try: trans.reorder_patches(applied, unapplied, iw=iw, allow_interactive=True) except transaction.TransactionHalted: pass return trans.execute('sink', iw)
def func(parser, options, args): if len(args) > 1: parser.error('incorrect number of arguments') elif len(args) == 1: filename = args[0] elif options.url: raise CmdException('URL argument required') else: filename = None if not options.url and filename: filename = os.path.abspath(filename) directory.cd_to_topdir() repository = directory.repository stack = repository.current_stack check_local_changes(repository) check_conflicts(repository.default_iw) check_head_top_equal(stack) if options.url: __import_url(filename, options) elif options.series: __import_series(filename, options) elif options.mail or options.mbox: __import_mail(filename, options) else: __import_file(filename, options)
def func(parser, options, args): """Show the files modified by a patch (or the current patch) """ if options.bare and options.stat: raise CmdException('Cannot specify both --bare and --stat') if len(args) == 0: patch = 'HEAD' elif len(args) == 1: patch = args[0] else: parser.error('incorrect number of arguments') rev1 = git_id(crt_series, '%s^' % patch) rev2 = git_id(crt_series, '%s' % patch) if options.stat: output = gitlib.diffstat( git.diff(rev1=rev1, rev2=rev2, diff_flags=options.diff_flags)) elif options.bare: output = git.barefiles(rev1, rev2) else: output = git.files(rev1, rev2, diff_flags=options.diff_flags) if output: if not output.endswith('\n'): output += '\n' out.stdout_raw(output)
def __import_mbox(filename, options): """Import a series from an mbox file """ if filename: namedtemp = None else: from tempfile import NamedTemporaryFile stdin = os.fdopen(sys.__stdin__.fileno(), 'rb') namedtemp = NamedTemporaryFile('wb', suffix='.mbox', delete=False) namedtemp.write(stdin.read()) namedtemp.close() filename = namedtemp.name try: try: mbox = mailbox.mbox(filename, message_from_binary_file, create=False) except Exception as ex: raise CmdException('error parsing the mbox file: %s' % str(ex)) with closing(mbox): for msg in mbox: (message, author_name, author_email, author_date, diff) = parse_mail(msg) __create_patch(None, message, author_name, author_email, author_date, diff, options) finally: if namedtemp is not None: os.unlink(namedtemp.name)
def __import_file(filename, options, patch=None): """Import a patch from a file or standard input """ pname = None if filename: (f, pname) = __get_handle_and_name(filename) else: f = os.fdopen(sys.__stdin__.fileno(), 'rb') if patch: pname = patch elif not pname: pname = filename if options.mail: try: msg = message_from_binary_file(f) except Exception as ex: raise CmdException('error parsing the e-mail file: %s' % str(ex)) (message, author_name, author_email, author_date, diff) = parse_mail(msg) else: patch_str = f.read() (message, author_name, author_email, author_date, diff) = parse_patch(patch_str, contains_diff=True) if filename: f.close() __create_patch(pname, message, author_name, author_email, author_date, diff, options)
def __send_message(msg_type, tmpl, options, *args): """Message sending dispatcher. """ domain = options.domain or config.get('stgit.domain') if domain: if sys.version_info < (3, 2): raise CmdException("Setting domain requires Python version 3.2+") msg_id = email.utils.make_msgid('stgit', domain=domain) else: msg_id = email.utils.make_msgid('stgit') if msg_type == 'cover': assert len(args) == 1, 'too many args for msg_type == "cover"' patches = args[0] msg = __build_cover(tmpl, msg_id, options, patches) outstr = 'the cover message' elif msg_type == 'patch': patch, patch_nr, total_nr, ref_id = args msg = __build_message(tmpl, msg_id, options, patch, patch_nr, total_nr, ref_id) outstr = 'patch "%s"' % patch else: raise AssertionError('invalid msg_type: %s' % msg_type) # pragma: no cover if hasattr(msg, 'as_bytes'): msg_bytes = msg.as_bytes(options.mbox) else: msg_bytes = msg.as_string(options.mbox) # Python 3.3 only has Message.as_string(). We encode it back to bytes # and hope for the best. if isinstance(msg_bytes, text): msg_bytes = msg_bytes.encode('utf-8') if options.mbox: out.stdout_bytes(msg_bytes + b'\n') return msg_id if not options.git: from_addr, to_addrs = __parse_addresses(msg) out.start('Sending ' + outstr) smtpserver = options.smtp_server or config.get('stgit.smtpserver') if options.git: __send_message_git(msg_bytes, msg['From'], options) elif smtpserver.startswith('/'): # Use the sendmail tool __send_message_sendmail(smtpserver, msg_bytes) else: # Use the SMTP server (we have host and port information) __send_message_smtp(smtpserver, from_addr, to_addrs, msg_bytes, options) # give recipients a chance of receiving related patches in correct order if msg_type == 'cover' or (msg_type == 'patch' and patch_nr < total_nr): sleep = options.sleep or config.getint('stgit.smtpdelay') time.sleep(sleep) if not options.git: out.done() return msg_id
def func(parser, options, args): stack = directory.repository.current_stack patches = parse_patches(args, list(stack.patchorder.all)) if len(patches) < 2: raise CmdException('Need at least two patches') if options.name and not stack.patches.is_name_valid(options.name): raise CmdException('Patch name "%s" is invalid' % options.name) return _squash( stack, stack.repository.default_iw, options.name, options.message, options.save_template, patches, options.no_verify, )
def func(parser, options, args): stack = directory.repository.current_stack iw = stack.repository.default_iw if len(args) >= 1: ref, patches = args[0], args[1:] state = log.get_log_entry( stack.repository, ref, stack.repository.rev_parse(ref) ) elif options.hard: iw.checkout_hard(stack.head.data.tree) return utils.STGIT_SUCCESS else: raise CmdException('Wrong options or number of arguments') trans = transaction.StackTransaction( stack, 'reset', discard_changes=options.hard, allow_bad_head=True, ) try: if patches: log.reset_stack_partially(trans, iw, state, patches) else: log.reset_stack(trans, iw, state) except transaction.TransactionHalted: pass return trans.run(iw, allow_bad_head=not patches)
def func(parser, options, args): """Rebase the current stack """ if len(args) != 1: parser.error('incorrect number of arguments') repository = directory.repository stack = repository.get_stack() iw = repository.default_iw if stack.protected: raise CmdException('This branch is protected. Rebase is not permitted') target = git_commit(args[0], repository) applied = stack.patchorder.applied retval = prepare_rebase(stack, 'rebase') if retval: return retval rebase(stack, iw, target) if not options.nopush: return post_rebase(stack, applied, 'rebase', check_merged=options.merged)
def func(parser, options, args): """Delete one or more patches.""" stack = directory.repository.get_stack(options.branch) if options.branch: iw = None # can't use index/workdir to manipulate another branch else: iw = stack.repository.default_iw if args and options.top: parser.error('Either --top or patches must be specified') elif args: patches = set( parse_patches(args, list(stack.patchorder.all), len(stack.patchorder.applied))) elif options.top: applied = stack.patchorder.applied if applied: patches = set([applied[-1]]) else: raise CmdException('No patches applied') else: parser.error('No patches specified') if options.spill: if set(stack.patchorder.applied[-len(patches):]) != patches: parser.error('Can only spill topmost applied patches') iw = None # don't touch index+worktree return delete_patches(stack, iw, patches)
def __send_message_git(msg_bytes, from_, options): """Send the message using git send-email """ from subprocess import call from tempfile import mkstemp cmd = ["git", "send-email", "--from=%s" % from_] cmd.append("--quiet") cmd.append("--suppress-cc=self") if not options.auto: cmd.append("--suppress-cc=body") if options.in_reply_to: cmd.extend(["--in-reply-to", options.in_reply_to]) if options.no_thread: cmd.append("--no-thread") # We only support To/Cc/Bcc in git send-email for now. for x in ['to', 'cc', 'bcc']: if getattr(options, x): cmd.extend('--%s=%s' % (x, a) for a in getattr(options, x)) (fd, path) = mkstemp() try: os.write(fd, msg_bytes) os.close(fd) try: cmd.append(path) call(cmd) except Exception as err: raise CmdException(str(err)) finally: os.unlink(path)
def func(parser, options, args): """Pop the given patches or the topmost one from the stack.""" stack = directory.repository.current_stack iw = stack.repository.default_iw check_head_top_equal(stack) if not options.keep and not options.spill: check_index_and_worktree_clean(stack) trans = transaction.StackTransaction(stack) if options.number == 0: # explicitly allow this without any warning/error message return if not trans.applied: raise CmdException('No patches applied') if options.all: patches = trans.applied elif options.number is not None: # reverse it twice to also work with negative or bigger than # the length numbers patches = trans.applied[::-1][:options.number][::-1] elif not args: patches = [trans.applied[-1]] else: patches = parse_patches(args, trans.applied, ordered=True) if not patches: # FIXME: Why is this an error, and not just a noop ? raise CmdException('No patches to pop') if options.spill: if set(stack.patchorder.applied[-len(patches):]) != set(patches): parser.error('Can only spill topmost applied patches') iw = None # don't touch index+worktree try: trans.reorder_patches( applied=[p for p in trans.applied if p not in patches], unapplied=patches + trans.unapplied, iw=iw, allow_interactive=True, ) except transaction.TransactionException: pass return trans.execute('pop', iw)
def func(parser, options, args): """Create a new patch.""" stack = directory.repository.current_stack if stack.repository.default_index.conflicts(): raise CmdException( 'Cannot create a new patch -- resolve conflicts first') # Choose a name for the new patch -- or None, which means make one # up later when we've gotten hold of the commit message. if len(args) == 0: name = None elif len(args) == 1: name = args[0] if stack.patches.exists(name): raise CmdException('%s: patch already exists' % name) elif not stack.patches.is_name_valid(name): raise CmdException('Invalid patch name: "%s"' % name) else: parser.error('incorrect number of arguments') cd = CommitData( tree=stack.head.data.tree, parents=[stack.head], message='', author=Person.author(), committer=Person.committer(), ) cd = update_commit_data(cd, options) if options.save_template: options.save_template(cd.message.encode('utf-8')) return utils.STGIT_SUCCESS if not options.no_verify: cd = run_commit_msg_hook(stack.repository, cd) if name is None: name = utils.make_patch_name(cd.message, stack.patches.exists) assert stack.patches.is_name_valid(name) # Write the new patch. stack.repository.default_iw trans = StackTransaction(stack, 'new: %s' % name) trans.patches[name] = stack.repository.commit(cd) trans.applied.append(name) return trans.run()
def func(parser, options, args): """Show the patches modifying a file """ if not args: files = [path for (stat, path) in git.tree_status(verbose=True)] # git.tree_status returns absolute paths else: files = git.ls_files(args) directory.cd_to_topdir() if not files: raise CmdException('No files specified or no local changes') applied = crt_series.get_applied() if not applied: raise CmdException('No patches applied') revs = git.modifying_revs(files, crt_series.get_base(), crt_series.get_head()) revs.reverse() # build the patch/revision mapping rev_patch = dict() for name in applied: patch = crt_series.get_patch(name) rev_patch[patch.get_top()] = patch # print the patch names diff_lines = [] for rev in revs: patch = rev_patch[rev] if options.diff: diff_lines.extend([ b'-' * 79, patch.get_name().encode('utf-8'), b'-' * 79, patch.get_description().encode('utf-8'), b'---', b'', git.diff(files, patch.get_bottom(), patch.get_top()), ]) else: out.stdout(patch.get_name()) if options.diff: pager(b'\n'.join(diff_lines))
def __cleanup_branch(name, force=False): branch = stack.Series(name) if branch.get_protected(): raise CmdException( 'This branch is protected. Clean up is not permitted') out.start('Cleaning up branch "%s"' % name) branch.delete(force=force, cleanup=True) out.done()