def func(parser, options, args): """Show the tree diff """ args = git.ls_files(args) directory.cd_to_topdir() if options.revs: rev_list = options.revs.split('..') rev_list_len = len(rev_list) if rev_list_len == 1: rev1 = rev_list[0] rev2 = None elif rev_list_len == 2: rev1 = rev_list[0] rev2 = rev_list[1] else: parser.error('incorrect parameters to -r') else: rev1 = 'HEAD' rev2 = None if not options.stat: options.diff_flags.extend(color_diff_flags()) diff_str = git.diff(args, rev1 and git_id(crt_series, rev1), rev2 and git_id(crt_series, rev2), diff_flags = options.diff_flags) if options.stat: out.stdout_raw(gitlib.diffstat(diff_str) + '\n') else: if diff_str: pager(diff_str)
def func(parser, options, args): """Show the tree diff """ args = git.ls_files(args) directory.cd_to_topdir() if options.revs: rev_list = options.revs.split('..') rev_list_len = len(rev_list) if rev_list_len == 1: rev1 = rev_list[0] rev2 = None elif rev_list_len == 2: rev1 = rev_list[0] rev2 = rev_list[1] else: parser.error('incorrect parameters to -r') else: rev1 = 'HEAD' rev2 = None if not options.stat: options.diff_flags.extend(color_diff_flags()) diff_str = git.diff(args, rev1 and git_id(crt_series, rev1), rev2 and git_id(crt_series, rev2), diff_flags=options.diff_flags) if options.stat: out.stdout_raw(gitlib.diffstat(diff_str) + '\n') else: if diff_str: pager(diff_str)
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 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): """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): """Show commit log and diff """ if options.applied: patches = crt_series.get_applied() elif options.unapplied: patches = crt_series.get_unapplied() elif len(args) == 0: patches = ['HEAD'] elif '..' in ' '.join(args): # patch ranges applied = crt_series.get_applied() unapplied = crt_series.get_unapplied() patches = parse_patches(args, applied + unapplied + \ crt_series.get_hidden(), len(applied)) else: # individual patches or commit ids patches = args if not options.stat: options.diff_flags.extend(color_diff_flags()) commit_ids = [git_id(crt_series, patch) for patch in patches] commit_bytes = b'\n'.join( (Run('git', 'show', *(options.diff_flags + [commit_id])).decoding(None).raw_output()) for commit_id in commit_ids) if options.stat: commit_bytes = git.diffstat(commit_bytes).encode('utf-8') if commit_bytes: pager(commit_bytes)
def func(parser, options, args): """Show commit log and diff """ if options.applied: patches = crt_series.get_applied() elif options.unapplied: patches = crt_series.get_unapplied() elif len(args) == 0: patches = ['HEAD'] elif '..' in ' '.join(args): # patch ranges applied = crt_series.get_applied() unapplied = crt_series.get_unapplied() patches = parse_patches(args, applied + unapplied + \ crt_series.get_hidden(), len(applied)) else: # individual patches or commit ids patches = args if not options.stat: options.diff_flags.extend(color_diff_flags()) commit_ids = [git_id(crt_series, patch) for patch in patches] commit_str = '\n'.join([git.pretty_commit(commit_id, flags = options.diff_flags) for commit_id in commit_ids]) if options.stat: commit_str = gitlib.diffstat(commit_str) if commit_str: pager(commit_str)
def func(parser, options, args): """Show commit log and diff """ if options.applied: patches = crt_series.get_applied() elif options.unapplied: patches = crt_series.get_unapplied() elif len(args) == 0: patches = ['HEAD'] elif '..' in ' '.join(args): # patch ranges applied = crt_series.get_applied() unapplied = crt_series.get_unapplied() patches = parse_patches(args, applied + unapplied + \ crt_series.get_hidden(), len(applied)) else: # individual patches or commit ids patches = args if not options.stat: options.diff_flags.extend(color_diff_flags()) commit_ids = [git_id(crt_series, patch) for patch in patches] commit_str = '\n'.join([ git.pretty_commit(commit_id, flags=options.diff_flags) for commit_id in commit_ids ]) if options.stat: commit_str = gitlib.diffstat(commit_str) if commit_str: pager(commit_str)
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): """Show the files modified by a patch (or the current patch) """ 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 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): """Rebase the current stack """ if len(args) != 1: parser.error('incorrect number of arguments') if crt_series.get_protected(): raise CmdException('This branch is protected. Rebase is not permitted') check_local_changes() check_conflicts() check_head_top_equal(crt_series) # ensure an exception is raised before popping on non-existent target if git_id(crt_series, args[0]) is None: raise GitException('Unknown revision: %s' % args[0]) applied = prepare_rebase(crt_series) rebase(crt_series, args[0]) post_rebase(crt_series, applied, options.nopush, options.merged) print_crt_patch(crt_series)
def func(parser, options, args): """Rebase the current stack """ if len(args) != 1: parser.error('incorrect number of arguments') if crt_series.get_protected(): raise CmdException('This branch is protected. Rebase is not permitted') check_local_changes() check_conflicts() check_head_top_equal(crt_series) # ensure an exception is raised before popping on non-existent target if git_id(crt_series, args[0]) is None: raise GitException('Unknown revision: %s' % args[0]) applied = prepare_rebase(crt_series) rebase(crt_series, args[0]) post_rebase(crt_series, applied, options.nopush, options.merged) print_crt_patch(crt_series)
def func(parser, options, args): if options.create: if len(args) == 0 or len(args) > 2: parser.error('incorrect number of arguments') check_local_changes() check_conflicts() check_head_top_equal(crt_series) tree_id = None if len(args) >= 2: parentbranch = None try: branchpoint = git.rev_parse(args[1]) # parent branch? head_re = re.compile('refs/(heads|remotes)/') ref_re = re.compile(args[1] + '$') for ref in git.all_refs(): if head_re.match(ref) and ref_re.search(ref): # args[1] is a valid ref from the branchpoint # setting above parentbranch = args[1] break except git.GitException: # should use a more specific exception to catch only # non-git refs ? out.info('Don\'t know how to determine parent branch' ' from "%s"' % args[1]) # exception in branch = rev_parse() leaves branchpoint unbound branchpoint = None tree_id = git_id(crt_series, branchpoint or args[1]) if parentbranch: out.info('Recording "%s" as parent branch' % parentbranch) else: out.info('Don\'t know how to determine parent branch' ' from "%s"' % args[1]) else: # branch stack off current branch parentbranch = git.get_head_file() if parentbranch: parentremote = git.identify_remote(parentbranch) if parentremote: out.info('Using remote "%s" to pull parent from' % parentremote) else: out.info('Recording as a local branch') else: # no known parent branch, can't guess the remote parentremote = None stack.Series(args[0]).init(create_at=tree_id, parent_remote=parentremote, parent_branch=parentbranch) out.info('Branch "%s" created' % args[0]) log.compat_log_entry('branch --create') return elif options.clone: if len(args) == 0: clone = crt_series.get_name() + \ time.strftime('-%C%y%m%d-%H%M%S') elif len(args) == 1: clone = args[0] else: parser.error('incorrect number of arguments') check_local_changes() check_conflicts() check_head_top_equal(crt_series) out.start('Cloning current branch to "%s"' % clone) crt_series.clone(clone) out.done() log.copy_log(log.default_repo(), crt_series.get_name(), clone, 'branch --clone') return elif options.delete: if len(args) != 1: parser.error('incorrect number of arguments') __delete_branch(args[0], options.force) log.delete_log(log.default_repo(), args[0]) return elif options.cleanup: if not args: name = crt_series.get_name() elif len(args) == 1: name = args[0] else: parser.error('incorrect number of arguments') __cleanup_branch(name, options.force) log.delete_log(log.default_repo(), name) return elif options.list: if len(args) != 0: parser.error('incorrect number of arguments') branches = set(git.get_heads()) for br in set(branches): m = re.match(r'^(.*)\.stgit$', br) if m and m.group(1) in branches: branches.remove(br) if branches: out.info('Available branches:') max_len = max([len(i) for i in branches]) for i in sorted(branches): __print_branch(i, max_len) else: out.info('No branches') return elif options.protect: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) out.start('Protecting branch "%s"' % branch_name) branch.protect() out.done() return elif options.rename: if len(args) != 2: parser.error('incorrect number of arguments') if __is_current_branch(args[0]): raise CmdException('Renaming the current branch is not supported') stack.Series(args[0]).rename(args[1]) out.info('Renamed branch "%s" to "%s"' % (args[0], args[1])) log.rename_log(log.default_repo(), args[0], args[1], 'branch --rename') return elif options.unprotect: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) out.info('Unprotecting branch "%s"' % branch_name) branch.unprotect() out.done() return elif options.description is not None: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) branch.set_description(options.description) return elif len(args) == 1: if __is_current_branch(args[0]): raise CmdException('Branch "%s" is already the current branch' % args[0]) if not options.merge: check_local_changes() check_conflicts() check_head_top_equal(crt_series) out.start('Switching to branch "%s"' % args[0]) git.switch_branch(args[0]) out.done() return # default action: print the current branch if len(args) != 0: parser.error('incorrect number of arguments') print(crt_series.get_name())
def __create_patch(filename, message, author_name, author_email, author_date, diff, options): """Create a new patch on the stack """ if options.name: patch = options.name elif filename: patch = os.path.basename(filename) else: patch = '' if options.stripname: patch = __strip_patch_name(patch) if not patch: if options.ignore or options.replace: def unacceptable_name(name): return False else: unacceptable_name = crt_series.patch_exists patch = make_patch_name(message, unacceptable_name) else: # fix possible invalid characters in the patch name patch = re.sub(r'[^\w.]+', '-', patch).strip('-') if options.ignore and patch in crt_series.get_applied(): out.info('Ignoring already applied patch "%s"' % patch) return if options.replace and patch in crt_series.get_unapplied(): crt_series.delete_patch(patch, keep_log=True) # override the automatically parsed settings author = options.author(Person()) if author.name: author_name = author.name if author.email: author_email = author.email if author.date: author_date = text(author.date) sign_str = options.sign_str if not options.sign_str: sign_str = config.get('stgit.autosign') crt_series.new_patch( patch, message=message, can_edit=False, author_name=author_name, author_email=author_email, author_date=author_date, sign_str=sign_str, ) if not diff: out.warn('No diff found, creating empty patch') else: out.start('Importing patch "%s"' % patch) if options.base: base = git_id(crt_series, options.base) else: base = None try: git.apply_patch( diff=diff, base=base, reject=options.reject, strip=options.strip, ) except git.GitException: if not options.reject: crt_series.delete_patch(patch) raise crt_series.refresh_patch( edit=options.edit, show_patch=options.showdiff, author_date=author_date, backup=False, ) out.done()
def func(parser, options, args): if options.create: if len(args) == 0 or len(args) > 2: parser.error('incorrect number of arguments') check_local_changes() check_conflicts() check_head_top_equal(crt_series) tree_id = None if len(args) >= 2: parentbranch = None try: branchpoint = git.rev_parse(args[1]) # parent branch? head_re = re.compile('refs/(heads|remotes)/') ref_re = re.compile(args[1] + '$') for ref in git.all_refs(): if head_re.match(ref) and ref_re.search(ref): # args[1] is a valid ref from the branchpoint # setting above parentbranch = args[1] break except git.GitException: # should use a more specific exception to catch only # non-git refs ? out.info('Don\'t know how to determine parent branch' ' from "%s"' % args[1]) # exception in branch = rev_parse() leaves branchpoint unbound branchpoint = None tree_id = git_id(crt_series, branchpoint or args[1]) if parentbranch: out.info('Recording "%s" as parent branch' % parentbranch) else: out.info('Don\'t know how to determine parent branch' ' from "%s"' % args[1]) else: # branch stack off current branch parentbranch = git.get_head_file() if parentbranch: parentremote = git.identify_remote(parentbranch) if parentremote: out.info('Using remote "%s" to pull parent from' % parentremote) else: out.info('Recording as a local branch') else: # no known parent branch, can't guess the remote parentremote = None stack.Series(args[0]).init(create_at = tree_id, parent_remote = parentremote, parent_branch = parentbranch) out.info('Branch "%s" created' % args[0]) log.compat_log_entry('branch --create') return elif options.clone: if len(args) == 0: clone = crt_series.get_name() + \ time.strftime('-%C%y%m%d-%H%M%S') elif len(args) == 1: clone = args[0] else: parser.error('incorrect number of arguments') check_local_changes() check_conflicts() check_head_top_equal(crt_series) out.start('Cloning current branch to "%s"' % clone) crt_series.clone(clone) out.done() log.copy_log(log.default_repo(), crt_series.get_name(), clone, 'branch --clone') return elif options.delete: if len(args) != 1: parser.error('incorrect number of arguments') __delete_branch(args[0], options.force) log.delete_log(log.default_repo(), args[0]) return elif options.cleanup: if not args: name = crt_series.get_name() elif len(args) == 1: name = args[0] else: parser.error('incorrect number of arguments') __cleanup_branch(name, options.force) log.delete_log(log.default_repo(), name) return elif options.list: if len(args) != 0: parser.error('incorrect number of arguments') branches = set(git.get_heads()) for br in set(branches): m = re.match(r'^(.*)\.stgit$', br) if m and m.group(1) in branches: branches.remove(br) if branches: out.info('Available branches:') max_len = max([len(i) for i in branches]) for i in sorted(branches): __print_branch(i, max_len) else: out.info('No branches') return elif options.protect: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) out.start('Protecting branch "%s"' % branch_name) branch.protect() out.done() return elif options.rename: if len(args) != 2: parser.error('incorrect number of arguments') if __is_current_branch(args[0]): raise CmdException('Renaming the current branch is not supported') stack.Series(args[0]).rename(args[1]) out.info('Renamed branch "%s" to "%s"' % (args[0], args[1])) log.rename_log(log.default_repo(), args[0], args[1], 'branch --rename') return elif options.unprotect: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) out.info('Unprotecting branch "%s"' % branch_name) branch.unprotect() out.done() return elif options.description is not None: if len(args) == 0: branch_name = crt_series.get_name() elif len(args) == 1: branch_name = args[0] else: parser.error('incorrect number of arguments') branch = stack.Series(branch_name) if not branch.is_initialised(): raise CmdException('Branch "%s" is not controlled by StGIT' % branch_name) branch.set_description(options.description) return elif len(args) == 1: if __is_current_branch(args[0]): raise CmdException('Branch "%s" is already the current branch' % args[0]) if not options.merge: check_local_changes() check_conflicts() check_head_top_equal(crt_series) out.start('Switching to branch "%s"' % args[0]) git.switch_branch(args[0]) out.done() return # default action: print the current branch if len(args) != 0: parser.error('incorrect number of arguments') print(crt_series.get_name())
def __pick_commit(commit_id, patchname, options): """Pick a commit id. """ commit = git.Commit(commit_id) if options.name: patchname = options.name elif patchname and options.revert: patchname = 'revert-' + patchname if patchname: patchname = find_patch_name(patchname, crt_series.patch_exists) if options.parent: parent = git_id(crt_series, options.parent) else: parent = commit.get_parent() if not options.revert: bottom = parent top = commit_id else: bottom = commit_id top = parent if options.fold: out.start('Folding commit %s' % commit_id) # try a direct git apply first if not git.apply_diff(bottom, top, files=options.file): if options.file: raise CmdException('Patch folding failed') else: git.merge_recursive(bottom, git.get_head(), top) out.done() elif options.update: rev1 = git_id(crt_series, 'HEAD^') rev2 = git_id(crt_series, 'HEAD') files = git.barefiles(rev1, rev2).split('\n') out.start('Updating with commit %s' % commit_id) if not git.apply_diff(bottom, top, files=files): raise CmdException('Patch updating failed') out.done() else: message = commit.get_log() if options.revert: if message: lines = message.splitlines() subject = lines[0] body = '\n'.join(lines[2:]) else: subject = commit.get_id_hash() body = '' message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' % ( subject, commit.get_id_hash(), body) elif options.expose: if not message.endswith('\n'): message += '\n' message += '(imported from commit %s)\n' % commit.get_id_hash() (author_name, author_email, author_date) = name_email_date(commit.get_author()) if options.revert: author_name = author_email = None out.start('Importing commit %s' % commit_id) newpatch = crt_series.new_patch( patchname, message=message, can_edit=False, unapplied=True, bottom=bottom, top=top, author_name=author_name, author_email=author_email, author_date=author_date, ) # in case the patch name was automatically generated patchname = newpatch.get_name() # find a patchlog to fork from refbranchname, refpatchname = parse_rev(patchname) if refpatchname: if refbranchname: # assume the refseries is OK, since we already resolved # commit_str to a git_id refseries = Series(refbranchname) else: refseries = crt_series patch = refseries.get_patch(refpatchname) if patch.get_log(): out.info("Log was %s" % newpatch.get_log()) out.info("Setting log to %s\n" % patch.get_log()) newpatch.set_log(patch.get_log()) out.info("Log is now %s" % newpatch.get_log()) else: out.info("No log for %s\n" % patchname) if not options.unapplied: modified = crt_series.push_patch(patchname) else: modified = False if crt_series.empty_patch(patchname): out.done('empty patch') elif modified: out.done('modified') else: out.done()
def __build_message(tmpl, msg_id, options, patch, patch_nr, total_nr, ref_id): """Build the message to be sent via SMTP """ p = crt_series.get_patch(patch) if p.get_description(): descr = p.get_description().strip() else: # provide a place holder and force the edit message option on descr = '<empty message>' options.edit_patches = True descr_lines = descr.split('\n') short_descr = descr_lines[0].strip() long_descr = '\n'.join(l.rstrip() for l in descr_lines[1:]).lstrip('\n') authname = p.get_authname() authemail = p.get_authemail() commname = p.get_commname() commemail = p.get_commemail() sender = __get_sender() fromauth = '%s <%s>' % (authname, authemail) if fromauth != sender: fromauth = 'From: %s\n\n' % fromauth else: fromauth = '' if options.version: version_str = '%s' % options.version version_space = ' ' else: version_str = '' version_space = '' if options.prefix: prefix_str = options.prefix else: prefix_str = config.get('stgit.mail.prefix') if prefix_str: prefix_space = ' ' else: prefix_str = '' prefix_space = '' total_nr_str = text(total_nr) patch_nr_str = text(patch_nr).zfill(len(total_nr_str)) if not options.unrelated and total_nr > 1: number_str = '%s/%s' % (patch_nr_str, total_nr_str) number_space = ' ' else: number_str = '' number_space = '' diff = git.diff(rev1 = git_id(crt_series, '%s^' % patch), rev2 = git_id(crt_series, '%s' % patch), diff_flags = options.diff_flags) tmpl_dict = {'patch': patch, 'sender': sender, # for backward template compatibility 'maintainer': sender, 'shortdescr': short_descr, 'longdescr': long_descr, # for backward template compatibility 'endofheaders': '', 'diff': diff, 'diffstat': gitlib.diffstat(diff), # for backward template compatibility 'date': '', 'version': version_str, 'vspace': version_space, 'prefix': prefix_str, 'pspace': prefix_space, 'patchnr': patch_nr_str, 'totalnr': total_nr_str, 'number': number_str, 'nspace': number_space, 'snumber': number_str.strip(), 'fromauth': fromauth, 'authname': authname, 'authemail': authemail, 'authdate': p.get_authdate(), 'commname': commname, 'commemail': commemail} # change None to '' for key in tmpl_dict: if not tmpl_dict[key]: tmpl_dict[key] = '' try: msg_string = tmpl % tmpl_dict except KeyError as err: raise CmdException('Unknown patch template variable: %s' % err) except TypeError: raise CmdException('Only "%(name)s" variables are ' 'supported in the patch template') if options.edit_patches: msg_string = __edit_message(msg_string) # The Python email message try: msg = email.message_from_string(msg_string) except Exception as ex: raise CmdException('template parsing error: %s' % str(ex)) if options.auto: extra_cc = __get_signers_list(descr) else: extra_cc = [] if not options.git: __build_address_headers(msg, options, extra_cc) __build_extra_headers(msg, msg_id, ref_id) __encode_message(msg) return msg
def __build_cover(tmpl, msg_id, options, patches): """Build the cover message (series description) to be sent via SMTP """ sender = __get_sender() if options.version: version_str = '%s' % options.version version_space = ' ' else: version_str = '' version_space = '' if options.prefix: prefix_str = options.prefix else: prefix_str = config.get('stgit.mail.prefix') if prefix_str: prefix_space = ' ' else: prefix_str = '' prefix_space = '' total_nr_str = text(len(patches)) patch_nr_str = '0'.zfill(len(total_nr_str)) if len(patches) > 1: number_str = '%s/%s' % (patch_nr_str, total_nr_str) number_space = ' ' else: number_str = '' number_space = '' tmpl_dict = { 'sender': sender, # for backward template compatibility 'maintainer': sender, # for backward template compatibility 'endofheaders': '', # for backward template compatibility 'date': '', 'version': version_str, 'vspace': version_space, 'prefix': prefix_str, 'pspace': prefix_space, 'patchnr': patch_nr_str, 'totalnr': total_nr_str, 'number': number_str, 'nspace': number_space, 'snumber': number_str.strip(), 'shortlog': stack.shortlog(crt_series.get_patch(p) for p in reversed(patches)), 'diffstat': diffstat( git.diff( rev1=git_id(crt_series, '%s^' % patches[0]), rev2=git_id(crt_series, '%s' % patches[-1]), diff_flags=options.diff_flags, )), } try: msg_bytes = templates.specialize_template(tmpl, tmpl_dict) except KeyError as err: raise CmdException('Unknown patch template variable: %s' % err) except TypeError: raise CmdException('Only "%(name)s" variables are ' 'supported in the patch template') if options.edit_cover: msg_bytes = edit_bytes(msg_bytes, '.stgitmail.txt') # The Python email message try: msg = message_from_bytes(msg_bytes) except Exception as ex: raise CmdException('template parsing error: %s' % str(ex)) extra_cc = [] if options.auto: for patch in patches: p = crt_series.get_patch(patch) if p.get_description(): descr = p.get_description().strip() extra_cc.extend(__get_signers_list(descr)) extra_cc = list(set(extra_cc)) if not options.git: __build_address_headers(msg, options, extra_cc) __build_extra_headers(msg, msg_id, options.in_reply_to) __encode_message(msg) return msg
def __pick_commit(commit_id, patchname, options): """Pick a commit id. """ commit = git.Commit(commit_id) if options.name: patchname = options.name elif patchname and options.revert: patchname = 'revert-' + patchname if patchname: patchname = find_patch_name(patchname, crt_series.patch_exists) if options.parent: parent = git_id(crt_series, options.parent) else: parent = commit.get_parent() if not options.revert: bottom = parent top = commit_id else: bottom = commit_id top = parent if options.fold: out.start('Folding commit %s' % commit_id) # try a direct git apply first if not git.apply_diff(bottom, top, files = options.file): if options.file: raise CmdException('Patch folding failed') else: git.merge_recursive(bottom, git.get_head(), top) out.done() elif options.update: rev1 = git_id(crt_series, 'HEAD^') rev2 = git_id(crt_series, 'HEAD') files = git.barefiles(rev1, rev2).split('\n') out.start('Updating with commit %s' % commit_id) if not git.apply_diff(bottom, top, files = files): raise CmdException('Patch updating failed') out.done() else: message = commit.get_log() if options.revert: if message: lines = message.splitlines() subject = lines[0] body = '\n'.join(lines[2:]) else: subject = commit.get_id_hash() body = '' message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' \ % (subject, commit.get_id_hash(), body) elif options.expose: if not message.endswith('\n'): message += '\n' message += '(imported from commit %s)\n' % commit.get_id_hash() author_name, author_email, author_date = \ name_email_date(commit.get_author()) if options.revert: author_name = author_email = None out.start('Importing commit %s' % commit_id) newpatch = crt_series.new_patch(patchname, message = message, can_edit = False, unapplied = True, bottom = bottom, top = top, author_name = author_name, author_email = author_email, author_date = author_date) # in case the patch name was automatically generated patchname = newpatch.get_name() # find a patchlog to fork from refbranchname, refpatchname = parse_rev(patchname) if refpatchname: if refbranchname: # assume the refseries is OK, since we already resolved # commit_str to a git_id refseries = Series(refbranchname) else: refseries = crt_series patch = refseries.get_patch(refpatchname) if patch.get_log(): out.info("Log was %s" % newpatch.get_log()) out.info("Setting log to %s\n" % patch.get_log()) newpatch.set_log(patch.get_log()) out.info("Log is now %s" % newpatch.get_log()) else: out.info("No log for %s\n" % patchname) if not options.unapplied: modified = crt_series.push_patch(patchname) else: modified = False if crt_series.empty_patch(patchname): out.done('empty patch') elif modified: out.done('modified') else: out.done()
def __build_message(tmpl, msg_id, options, patch, patch_nr, total_nr, ref_id): """Build the message to be sent via SMTP """ p = crt_series.get_patch(patch) if p.get_description(): descr = p.get_description().strip() else: # provide a place holder and force the edit message option on descr = '<empty message>' options.edit_patches = True descr_lines = descr.split('\n') short_descr = descr_lines[0].strip() long_descr = '\n'.join(l.rstrip() for l in descr_lines[1:]).lstrip('\n') authname = p.get_authname() authemail = p.get_authemail() commname = p.get_commname() commemail = p.get_commemail() sender = __get_sender() fromauth = '%s <%s>' % (authname, authemail) if fromauth != sender: fromauth = 'From: %s\n\n' % fromauth else: fromauth = '' if options.version: version_str = '%s' % options.version version_space = ' ' else: version_str = '' version_space = '' if options.prefix: prefix_str = options.prefix else: prefix_str = config.get('stgit.mail.prefix') if prefix_str: prefix_space = ' ' else: prefix_str = '' prefix_space = '' total_nr_str = text(total_nr) patch_nr_str = text(patch_nr).zfill(len(total_nr_str)) if not options.unrelated and total_nr > 1: number_str = '%s/%s' % (patch_nr_str, total_nr_str) number_space = ' ' else: number_str = '' number_space = '' diff = git.diff( rev1=git_id(crt_series, '%s^' % patch), rev2=git_id(crt_series, '%s' % patch), diff_flags=options.diff_flags, ) tmpl_dict = { 'patch': patch, 'sender': sender, 'maintainer': sender, # for backward template compatibility 'shortdescr': short_descr, 'longdescr': long_descr, 'endofheaders': '', # for backward template compatibility 'diff': diff, 'diffstat': diffstat(diff), 'date': '', # for backward template compatibility 'version': version_str, 'vspace': version_space, 'prefix': prefix_str, 'pspace': prefix_space, 'patchnr': patch_nr_str, 'totalnr': total_nr_str, 'number': number_str, 'nspace': number_space, 'snumber': number_str.strip(), 'fromauth': fromauth, 'authname': authname, 'authemail': authemail, 'authdate': p.get_authdate(), 'commname': commname, 'commemail': commemail, } try: msg_bytes = templates.specialize_template(tmpl, tmpl_dict) except KeyError as err: raise CmdException('Unknown patch template variable: %s' % err) except TypeError: raise CmdException('Only "%(name)s" variables are ' 'supported in the patch template') if options.edit_patches: msg_bytes = edit_bytes(msg_bytes, '.stgitmail.txt') # The Python email message try: msg = message_from_bytes(msg_bytes) except Exception as ex: raise CmdException('template parsing error: %s' % str(ex)) if options.auto: extra_cc = __get_signers_list(descr) else: extra_cc = [] if not options.git: __build_address_headers(msg, options, extra_cc) __build_extra_headers(msg, msg_id, ref_id) __encode_message(msg) return msg
def __build_cover(tmpl, msg_id, options, patches): """Build the cover message (series description) to be sent via SMTP """ sender = __get_sender() if options.version: version_str = '%s' % options.version version_space = ' ' else: version_str = '' version_space = '' if options.prefix: prefix_str = options.prefix else: prefix_str = config.get('stgit.mail.prefix') if prefix_str: prefix_space = ' ' else: prefix_str = '' prefix_space = '' total_nr_str = text(len(patches)) patch_nr_str = '0'.zfill(len(total_nr_str)) if len(patches) > 1: number_str = '%s/%s' % (patch_nr_str, total_nr_str) number_space = ' ' else: number_str = '' number_space = '' tmpl_dict = {'sender': sender, # for backward template compatibility 'maintainer': sender, # for backward template compatibility 'endofheaders': '', # for backward template compatibility 'date': '', 'version': version_str, 'vspace': version_space, 'prefix': prefix_str, 'pspace': prefix_space, 'patchnr': patch_nr_str, 'totalnr': total_nr_str, 'number': number_str, 'nspace': number_space, 'snumber': number_str.strip(), 'shortlog': stack.shortlog(crt_series.get_patch(p) for p in reversed(patches)), 'diffstat': gitlib.diffstat(git.diff( rev1 = git_id(crt_series, '%s^' % patches[0]), rev2 = git_id(crt_series, '%s' % patches[-1]), diff_flags = options.diff_flags))} try: msg_string = tmpl % tmpl_dict except KeyError as err: raise CmdException('Unknown patch template variable: %s' % err) except TypeError: raise CmdException('Only "%(name)s" variables are ' 'supported in the patch template') if options.edit_cover: msg_string = __edit_message(msg_string) # The Python email message try: msg = email.message_from_string(msg_string) except Exception as ex: raise CmdException('template parsing error: %s' % str(ex)) extra_cc = [] if options.auto: for patch in patches: p = crt_series.get_patch(patch) if p.get_description(): descr = p.get_description().strip() extra_cc.extend(__get_signers_list(descr)) extra_cc = list(set(extra_cc)) if not options.git: __build_address_headers(msg, options, extra_cc) __build_extra_headers(msg, msg_id, options.in_reply_to) __encode_message(msg) return msg