def __assert_head_top_equal(self): if not self.__stack.head_top_equal(): out.error( 'HEAD and top are not the same.', 'This can happen if you modify a branch with git.', '"stg repair --help" explains more about what to do next.') self.__abort()
def execute( self, msg, iw=None, set_head=True, allow_bad_head=False, print_current_patch=True, ): """Execute the transaction. Will either succeed, or fail (with an exception) and do nothing. """ self._check_consistency() log_external_mods(self.stack) # Set branch head. if set_head: if iw: try: self._checkout(self.head.data.tree, iw, allow_bad_head) except CheckoutException: # We have to abort the transaction. # The only state we need to restore is index+worktree. self._checkout(self.stack.head.data.tree, iw, allow_bad_head=True) raise TransactionAborted() self.stack.set_head(self.head, msg) if self._error: if self._conflicts: out.error(*([self._error] + self._conflicts)) else: out.error(self._error) old_applied = self.stack.patchorder.applied if self._conflicts: msg = '%s (CONFLICT)' % (msg, ) # Write patches. for pn, commit in self.patches.items(): if pn in self.stack.patches: if commit is None: self.stack.patches.delete(pn) else: self.stack.patches.update(pn, commit, msg) else: self.stack.patches.new(pn, commit, msg) self.stack.patchorder.set_order(self._applied, self._unapplied, self._hidden) log_stack_state(self.stack, msg) if print_current_patch: _print_current_patch(old_applied, self._applied) if self._error: return utils.STGIT_CONFLICT else: return utils.STGIT_SUCCESS
def __refresh_spill(annotate): stack = directory.repository.current_stack # Fetch the topmost patch. patchname = get_patch(stack, None) cd = stack.patches[patchname].data # Set the tree of the patch to the parent. cd = cd.set_tree(cd.parent.data.tree) log_msg = 'refresh (spill)' if annotate: log_msg += '\n\n' + annotate trans = StackTransaction(stack, log_msg, allow_conflicts=True) trans.patches[patchname] = stack.repository.commit(cd) try: # Either a complete success, or a conflict during push. But in # either case, we've successfully effected the edits the user # asked us for. return trans.run() except TransactionException: # Transaction aborted -- we couldn't check out files due to # dirty index/worktree. The edits were not carried out. out.error('Unable to spill the topmost patch') return utils.STGIT_COMMAND_ERROR
def note_patch_application_failure(patch_desc, reason='Edited patch did not apply.'): """Call when edit fails. Logs to stderr and saves a patch to filesystem.""" fn = '.stgit-failed.patch' with open(fn, 'wb') as f: f.write(patch_desc) out.error(reason, 'The patch has been saved to "%s".' % fn)
def failed(reason='Edited patch did not apply.'): fn = '.stgit-failed.patch' with io.open(fn, 'wb') as f: f.write( edit.patch_desc(stack.repository, cd, options.diff, options.diff_flags, failed_diff)) out.error(reason, 'The patch has been saved to "%s".' % fn) return utils.STGIT_COMMAND_ERROR
def failed(reason='Edited patch did not apply.'): fn = '.stgit-failed.patch' with open(fn, 'w') as f: f.write(edit.patch_desc(stack.repository, cd, options.diff, options.diff_flags, failed_diff)) out.error(reason, 'The patch has been saved to "%s".' % fn) return utils.STGIT_COMMAND_ERROR
def run(self, iw=None, set_head=True, allow_bad_head=False, print_current_patch=True): """Execute the transaction. Will either succeed, or fail (with an exception) and do nothing.""" self.__check_consistency() log.log_external_mods(self.__stack) new_head = self.head # Set branch head. if set_head: if iw: try: self.__checkout(new_head.data.tree, iw, allow_bad_head) except git.CheckoutException: # We have to abort the transaction. self.abort(iw) self.__abort() self.__stack.set_head(new_head, self.__msg) if self.__error: if self.__conflicts: out.error(*([self.__error] + self.__conflicts)) else: out.error(self.__error) # Write patches. def write(msg): for pn, commit in self.__patches.items(): if self.__stack.patches.exists(pn): p = self.__stack.patches.get(pn) if commit is None: p.delete() else: p.set_commit(commit, msg) else: self.__stack.patches.new(pn, commit, msg) self.__stack.patchorder.applied = self.__applied self.__stack.patchorder.unapplied = self.__unapplied self.__stack.patchorder.hidden = self.__hidden log.log_entry(self.__stack, msg) old_applied = self.__stack.patchorder.applied if not self.__conflicts: write(self.__msg) else: write(self.__msg + ' (CONFLICT)') if print_current_patch: _print_current_patch(old_applied, self.__applied) if self.__error: return utils.STGIT_CONFLICT else: return utils.STGIT_SUCCESS
def run(self, iw=None, set_head=True, allow_bad_head=False, print_current_patch=True): """Execute the transaction. Will either succeed, or fail (with an exception) and do nothing. """ self._check_consistency() log_external_mods(self.stack) new_head = self.head # Set branch head. if set_head: if iw: try: self._checkout(new_head.data.tree, iw, allow_bad_head) except CheckoutException: # We have to abort the transaction. self.abort(iw) self._abort() self.stack.set_head(new_head, self._msg) if self._error: if self._conflicts: out.error(*([self._error] + self._conflicts)) else: out.error(self._error) old_applied = self.stack.patchorder.applied msg = self._msg + (' (CONFLICT)' if self._conflicts else '') # Write patches. for pn, commit in self.patches.items(): if pn in self.stack.patches: if commit is None: self.stack.patches.delete(pn) else: self.stack.patches.update(pn, commit, msg) else: self.stack.patches.new(pn, commit, msg) self.stack.patchorder.set_order(self._applied, self._unapplied, self._hidden) log_stack_state(self.stack, msg) if print_current_patch: _print_current_patch(old_applied, self._applied) if self._error: return utils.STGIT_CONFLICT else: return utils.STGIT_SUCCESS
def canonical_cmd(self, key): """Return the canonical name for a possibly-shortenned command name. """ candidates = [cmd for cmd in self if cmd.startswith(key)] if not candidates: out.error('Unknown command: %s' % key, 'Try "%s help" for a list of supported commands' % prog) sys.exit(utils.STGIT_GENERAL_ERROR) elif len(candidates) > 1: out.error('Ambiguous command: %s' % key, 'Candidates are: %s' % ', '.join(candidates)) sys.exit(utils.STGIT_GENERAL_ERROR) return candidates[0]
def _checkout(self, tree, iw, allow_bad_head): if not allow_bad_head: self._assert_head_top_equal() if self._current_tree == tree and not self._discard_changes: # No tree change, but we still want to make sure that # there are no unresolved conflicts. Conflicts # conceptually "belong" to the topmost patch, and just # carrying them along to another patch is confusing. if self._allow_conflicts(self) or iw is None or not iw.index.conflicts(): return out.error('Need to resolve conflicts first') self._abort() assert iw is not None if self._discard_changes: iw.checkout_hard(tree) else: iw.checkout(self._current_tree, tree) self._current_tree = tree
def canonical_cmd(self, key): """Return the canonical name for a possibly-shortened command name.""" candidates = [cmd for cmd in self if cmd.startswith(key)] if not candidates: out.error( 'Unknown command: %s' % key, 'Try "stg help" for a list of supported commands', ) raise KeyError(key) elif len(candidates) == 1: return candidates[0] elif key in candidates: return key else: out.error( 'Ambiguous command: %s' % key, 'Candidates are: %s' % ', '.join(candidates), ) raise KeyError(key)
def _checkout(self, tree, iw, allow_bad_head): assert iw is not None if not allow_bad_head and self.stack.head != self.stack.top: out.error( 'HEAD and top are not the same.', 'This can happen if you modify a branch with git.', '"stg repair --help" explains more about what to do next.', ) raise TransactionAborted() if self._current_tree == tree and not self._discard_changes: # No tree change, but we still want to make sure that # there are no unresolved conflicts. Conflicts # conceptually "belong" to the topmost patch, and just # carrying them along to another patch is confusing. if self._allow_conflicts(self) or not iw.index.conflicts(): return out.error('Need to resolve conflicts first') raise TransactionAborted() if self._discard_changes: iw.checkout_hard(tree) else: iw.checkout(self._current_tree, tree) self._current_tree = tree
def func(parser, options, args): """Pull the changes from a remote repository """ policy = config.get('branch.%s.stgit.pull-policy' % crt_series.get_name()) or \ config.get('stgit.pull-policy') if policy == 'rebase': # parent is local if len(args) == 1: parser.error( 'specifying a repository is meaningless for policy="%s"' % policy) if len(args) > 0: parser.error('incorrect number of arguments') else: # parent is remote if len(args) > 1: parser.error('incorrect number of arguments') if len(args) >= 1: repository = args[0] else: repository = crt_series.get_parent_remote() if crt_series.get_protected(): raise CmdException('This branch is protected. Pulls are not permitted') check_local_changes() check_conflicts() check_head_top_equal(crt_series) if policy not in ['pull', 'fetch-rebase', 'rebase']: raise GitConfigException('Unsupported pull-policy "%s"' % policy) applied = prepare_rebase(crt_series) # pull the remote changes if policy == 'pull': out.info('Pulling from "%s"' % repository) git.pull(repository) elif policy == 'fetch-rebase': out.info('Fetching from "%s"' % repository) git.fetch(repository) try: target = git.fetch_head() except git.GitException: out.error( 'Could not find the remote head to rebase onto - fix branch.%s.merge in .git/config' % crt_series.get_name()) out.error('Pushing any patches back...') post_rebase(crt_series, applied, False, False) raise rebase(crt_series, target) elif policy == 'rebase': rebase(crt_series, crt_series.get_parent_branch()) post_rebase(crt_series, applied, options.nopush, options.merged) # maybe tidy up if config.getbool('stgit.keepoptimized'): git.repack() print_crt_patch(crt_series)
def _main(): """The main function """ global prog sys.argv = list(map(fsdecode_utf8, sys.argv)) prog = os.path.basename(sys.argv[0]) if len(sys.argv) < 2: print('usage: %s <command>' % prog, file=sys.stderr) print(' Try "%s --help" for a list of supported commands' % prog, file=sys.stderr) sys.exit(utils.STGIT_GENERAL_ERROR) cmd = sys.argv[1] if cmd in ['-h', '--help']: if len(sys.argv) >= 3: cmd = commands.canonical_cmd(sys.argv[2]) sys.argv[2] = '--help' else: print_help() sys.exit(utils.STGIT_SUCCESS) if cmd == 'help': if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']: cmd = commands.canonical_cmd(sys.argv[2]) sys.argv[0] += ' %s' % cmd command = commands[cmd] parser = argparse.make_option_parser(command) if is_cmd_alias(command): parser.remove_option('-h') pager(parser.format_help().encode()) else: print_help() sys.exit(utils.STGIT_SUCCESS) if cmd in ['-v', '--version', 'version']: from stgit.version import get_version print('Stacked GIT %s' % get_version()) os.system('git --version') print('Python version %s' % sys.version) sys.exit(utils.STGIT_SUCCESS) if cmd in ['copyright']: print(__copyright__) sys.exit(utils.STGIT_SUCCESS) # re-build the command line arguments cmd = commands.canonical_cmd(cmd) sys.argv[0] += ' %s' % cmd del sys.argv[1] command = commands[cmd] if is_cmd_alias(command): sys.exit(command.func(sys.argv[1:])) parser = argparse.make_option_parser(command) directory = command.directory # These modules are only used from this point onwards and do not # need to be imported earlier try: from configparser import ParsingError, NoSectionError except ImportError: from ConfigParser import ParsingError, NoSectionError from stgit.exception import StgException from stgit.config import config_setup from stgit.stack import Series try: debug_level = int(environ_get('STGIT_DEBUG_LEVEL', 0)) except ValueError: out.error('Invalid STGIT_DEBUG_LEVEL environment variable') sys.exit(utils.STGIT_GENERAL_ERROR) try: (options, args) = parser.parse_args() directory.setup() config_setup() # Some commands don't (always) need an initialized series. if directory.needs_current_series: if hasattr(options, 'branch') and options.branch: command.crt_series = Series(options.branch) else: command.crt_series = Series() ret = command.func(parser, options, args) except (StgException, IOError, ParsingError, NoSectionError) as err: directory.write_log(cmd) if debug_level > 0: traceback.print_exc(file=sys.stderr) out.error(str(err), title='%s %s' % (prog, cmd)) sys.exit(utils.STGIT_COMMAND_ERROR) except SystemExit: # Triggered by the option parser when it finds bad commandline # parameters. sys.exit(utils.STGIT_COMMAND_ERROR) except KeyboardInterrupt: sys.exit(utils.STGIT_GENERAL_ERROR) except BaseException: out.error('Unhandled exception:') traceback.print_exc(file=sys.stderr) sys.exit(utils.STGIT_BUG_ERROR) directory.write_log(cmd) sys.exit(ret or utils.STGIT_SUCCESS)
def push_patch(self, name): """Pushes a patch on the stack """ unapplied = self.get_unapplied() assert(name in unapplied) patch = self.get_patch(name) head = git.get_head() bottom = patch.get_bottom() top = patch.get_top() # top != bottom always since we have a commit for each patch if head == bottom: # A fast-forward push. Just reset the backup # information. No need for logging patch.set_top(top, backup = True) git.switch(top) append_string(self.__applied_file, name) unapplied.remove(name) write_strings(self.__unapplied_file, unapplied) return False # Need to create a new commit an merge in the old patch ex = None modified = False # Try the fast applying first. If this fails, fall back to the # three-way merge if not git.apply_diff(bottom, top): # if git.apply_diff() fails, the patch requires a diff3 # merge and can be reported as modified modified = True # merge can fail but the patch needs to be pushed try: git.merge_recursive(bottom, head, top) except git.GitException: out.error('The merge failed during "push".', 'Revert the operation with "stg undo".') append_string(self.__applied_file, name) unapplied.remove(name) write_strings(self.__unapplied_file, unapplied) if not ex: # if the merge was OK and no conflicts, just refresh the patch # The GIT cache was already updated by the merge operation if modified: log = 'push(m)' else: log = 'push' self.refresh_patch(bottom = head, cache_update = False, log = log) else: # we make the patch empty, with the merged state in the # working tree. self.refresh_patch(bottom = head, cache_update = False, empty = True, log = 'push(c)') raise StackException(str(ex)) return modified
def push_patch(self, name): """Pushes a patch on the stack """ unapplied = self.get_unapplied() assert(name in unapplied) patch = self.get_patch(name) head = git.get_head() bottom = patch.get_bottom() top = patch.get_top() # top != bottom always since we have a commit for each patch if head == bottom: # A fast-forward push. Just reset the backup # information. No need for logging patch.set_top(top, backup=True) git.switch(top) append_string(self.__applied_file, name) unapplied.remove(name) write_strings(self.__unapplied_file, unapplied) return False # Need to create a new commit an merge in the old patch ex = None modified = False # Try the fast applying first. If this fails, fall back to the # three-way merge if not git.apply_diff(bottom, top): # if git.apply_diff() fails, the patch requires a diff3 # merge and can be reported as modified modified = True # merge can fail but the patch needs to be pushed try: git.merge_recursive(bottom, head, top) except git.GitException: out.error('The merge failed during "push".', 'Revert the operation with "stg undo".') append_string(self.__applied_file, name) unapplied.remove(name) write_strings(self.__unapplied_file, unapplied) if not ex: # if the merge was OK and no conflicts, just refresh the patch # The GIT cache was already updated by the merge operation if modified: log = 'push(m)' else: log = 'push' self.refresh_patch(bottom=head, cache_update=False, log=log) else: # we make the patch empty, with the merged state in the # working tree. self.refresh_patch( bottom=head, cache_update=False, empty=True, log='push(c)', ) raise StackException(str(ex)) return modified
def _main(argv): prog = argv[0] = 'stg' if len(argv) < 2: print('usage: %s <command>' % prog, file=sys.stderr) print(' Try "%s --help" for a list of supported commands' % prog, file=sys.stderr) return utils.STGIT_GENERAL_ERROR cmd = argv[1] if cmd in ['-h', '--help']: if len(argv) >= 3: try: cmd = commands.canonical_cmd(argv[2]) except KeyError: return utils.STGIT_GENERAL_ERROR argv[2] = '--help' else: print_help(prog) return utils.STGIT_SUCCESS if cmd == 'help': if len(argv) == 3 and not argv[2] in ['-h', '--help']: try: cmd = commands.canonical_cmd(argv[2]) except KeyError: return utils.STGIT_GENERAL_ERROR argv[0] += ' %s' % cmd command = commands[cmd] parser = argparse.make_option_parser(command) if is_cmd_alias(command): parser.remove_option('-h') pager(parser.format_help().encode()) else: print_help(prog) return utils.STGIT_SUCCESS if cmd in ['-v', '--version', 'version']: print('Stacked Git %s' % get_version()) os.system('git --version') os.system('%s --version' % sys.executable) return utils.STGIT_SUCCESS if cmd in ['copyright']: print(__copyright__) return utils.STGIT_SUCCESS # re-build the command line arguments try: cmd = commands.canonical_cmd(cmd) except KeyError: return utils.STGIT_GENERAL_ERROR argv[0] += ' %s' % cmd del argv[1] command = commands[cmd] if is_cmd_alias(command): return command.func(argv[1:]) parser = argparse.make_option_parser(command) # These modules are only used from this point onwards and do not # need to be imported earlier from configparser import NoSectionError, ParsingError from stgit.config import config_setup from stgit.exception import StgException from stgit.lib.git import MergeConflictException try: debug_level = int(environ_get('STGIT_DEBUG_LEVEL', 0)) except ValueError: out.error('Invalid STGIT_DEBUG_LEVEL environment variable') return utils.STGIT_GENERAL_ERROR try: (options, args) = parser.parse_args(argv[1:]) command.directory.setup() config_setup() return command.func(parser, options, args) except MergeConflictException as err: if debug_level > 1: traceback.print_exc(file=sys.stderr) for conflict in err.conflicts: out.err(conflict) return utils.STGIT_CONFLICT except (StgException, IOError, ParsingError, NoSectionError) as err: if debug_level > 0: traceback.print_exc(file=sys.stderr) out.error(str(err), title='%s %s' % (prog, cmd)) return utils.STGIT_COMMAND_ERROR except SystemExit: # Triggered by the option parser when it finds bad commandline # parameters. return utils.STGIT_COMMAND_ERROR except KeyboardInterrupt: return utils.STGIT_GENERAL_ERROR except BaseException: out.error('Unhandled exception:') traceback.print_exc(file=sys.stderr) return utils.STGIT_BUG_ERROR
def func(parser, options, args): """Pull the changes from a remote repository """ policy = config.get('branch.%s.stgit.pull-policy' % crt_series.get_name()) or \ config.get('stgit.pull-policy') if policy == 'rebase': # parent is local if len(args) == 1: parser.error('specifying a repository is meaningless for policy="%s"' % policy) if len(args) > 0: parser.error('incorrect number of arguments') else: # parent is remote if len(args) > 1: parser.error('incorrect number of arguments') if len(args) >= 1: repository = args[0] else: repository = crt_series.get_parent_remote() if crt_series.get_protected(): raise CmdException('This branch is protected. Pulls are not permitted') check_local_changes() check_conflicts() check_head_top_equal(crt_series) if policy not in ['pull', 'fetch-rebase', 'rebase']: raise GitConfigException('Unsupported pull-policy "%s"' % policy) applied = prepare_rebase(crt_series) # pull the remote changes if policy == 'pull': out.info('Pulling from "%s"' % repository) git.pull(repository) elif policy == 'fetch-rebase': out.info('Fetching from "%s"' % repository) git.fetch(repository) try: target = git.fetch_head() except git.GitException: out.error('Could not find the remote head to rebase onto - fix branch.%s.merge in .git/config' % crt_series.get_name()) out.error('Pushing any patches back...') post_rebase(crt_series, applied, False, False) raise rebase(crt_series, target) elif policy == 'rebase': rebase(crt_series, crt_series.get_parent_branch()) post_rebase(crt_series, applied, options.nopush, options.merged) # maybe tidy up if config.get('stgit.keepoptimized') == 'yes': git.repack() print_crt_patch(crt_series)
def func(parser, options, args): """Pull the changes from a remote repository""" repository = directory.repository iw = repository.default_iw stack = repository.get_stack() policy = config.get('branch.%s.stgit.pull-policy' % stack.name) or config.get('stgit.pull-policy') if policy not in ['pull', 'fetch-rebase', 'rebase']: raise GitConfigException('Unsupported pull-policy "%s"' % policy) remote_name = None if policy == 'rebase': # parent is local if len(args) == 1: parser.error( 'specifying a repository is meaningless for policy="%s"' % (policy, )) elif len(args) > 0: parser.error('incorrect number of arguments') else: # parent is remote if len(args) > 1: parser.error('incorrect number of arguments') if len(args) >= 1: remote_name = args[0] else: remote_name = stack.parent_remote if policy in ['pull', 'fetch-rebase'] and remote_name is None: parser.error( 'There is no tracking information for the current branch.\n' 'Please specify the remote repository to pull from.') if stack.protected: raise CmdException('This branch is protected. Pulls are not permitted') applied = stack.patchorder.applied retval = prepare_rebase(stack, 'pull') if retval: return retval # pull the remote changes if policy == 'pull': out.info('Pulling from "%s"' % remote_name) pull(repository, remote_name) elif policy == 'fetch-rebase': out.info('Fetching from "%s"' % remote_name) fetch(repository, remote_name) try: target = repository.rev_parse('FETCH_HEAD') except RepositoryException: out.error('Could not find the remote head to rebase onto - ' 'fix branch.%s.merge in .git/config' % stack.name) out.error('Pushing any patches back...') post_rebase(stack, applied, 'pull', check_merged=False) raise rebase(stack, iw, target) elif policy == 'rebase': value = config.get('branch.%s.stgit.parentbranch' % stack.name) if value: parent_commit = git_commit(value, repository) else: try: parent_commit = repository.rev_parse('heads/origin') except RepositoryException: raise CmdException('Cannot find a parent branch for "%s"' % stack.name) else: out.warn( 'No parent branch declared for stack "%s", defaulting to' '"heads/origin".' % stack.name, 'Consider setting "branch.%s.stgit.parentbranch" with ' '"git config".' % stack.name, ) rebase(stack, iw, parent_commit) if not options.nopush: post_rebase(stack, applied, 'pull', check_merged=options.merged) # maybe tidy up if config.getbool('stgit.keepoptimized'): repository.repack()
def __pick_commit(stack, ref_stack, iw, commit, patchname, options): """Pick a commit.""" repository = stack.repository if options.name: patchname = options.name elif patchname and options.revert: patchname = 'revert-' + patchname if patchname: patchname = find_patch_name(patchname, stack.patches.exists) else: patchname = make_patch_name(commit.data.message_str, stack.patches.exists) if options.parent: parent = git_commit(options.parent, repository, ref_stack.name) else: parent = commit.data.parent if not options.revert: bottom = parent top = commit else: bottom = commit top = parent if options.fold: out.start('Folding commit %s' % commit.sha1) diff = repository.diff_tree(bottom.data.tree, top.data.tree, pathlimits=options.file) if diff: try: # try a direct git apply first iw.apply(diff, quiet=True) except MergeException: if options.file: out.done('conflict(s)') out.error('%s does not apply cleanly' % patchname) return STGIT_CONFLICT else: try: iw.merge( bottom.data.tree, stack.head.data.tree, top.data.tree, ) except MergeConflictException as e: out.done('%s conflicts' % len(e.conflicts)) out.error('%s does not apply cleanly' % patchname, *e.conflicts) return STGIT_CONFLICT out.done() else: out.done('no changes') return STGIT_SUCCESS elif options.update: files = [ fn1 for _, _, _, _, _, fn1, fn2 in repository.diff_tree_files( stack.top.data.parent.data.tree, stack.top.data.tree) ] diff = repository.diff_tree(bottom.data.tree, top.data.tree, pathlimits=files) out.start('Updating with commit %s' % commit.sha1) try: iw.apply(diff, quiet=True) except MergeException: out.done('conflict(s)') out.error('%s does not apply cleanly' % patchname) return STGIT_CONFLICT else: out.done() return STGIT_SUCCESS else: author = commit.data.author message = commit.data.message_str if options.revert: author = Person.author() if message: lines = message.splitlines() subject = lines[0] body = '\n'.join(lines[2:]) else: subject = commit.sha1 body = '' message = 'Revert "%s"\n\nThis reverts commit %s.\n\n%s\n' % ( subject, commit.sha1, body, ) elif options.expose: fmt = config.get('stgit.pick.expose-format') message = Run('git', 'show', '--no-patch', '--pretty=' + fmt, commit.sha1).raw_output() message = message.rstrip() + '\n' out.start('Importing commit %s' % commit.sha1) new_commit = repository.commit( CommitData( tree=top.data.tree, parents=[bottom], message=message, author=author, )) trans = StackTransaction( stack, 'pick %s from %s' % (patchname, ref_stack.name)) trans.patches[patchname] = new_commit trans.unapplied.append(patchname) if not options.unapplied: try: trans.push_patch(patchname, iw, allow_interactive=True) except TransactionHalted: pass retval = trans.run(iw, print_current_patch=False) if retval == STGIT_CONFLICT: out.done('conflict(s)') elif stack.patches.get(patchname).is_empty(): out.done('empty patch') else: out.done() return retval
def _main(): """The main function """ global prog sys.argv = list(map(fsdecode_utf8, sys.argv)) prog = os.path.basename(sys.argv[0]) if len(sys.argv) < 2: print('usage: %s <command>' % prog, file=sys.stderr) print(' Try "%s --help" for a list of supported commands' % prog, file=sys.stderr) sys.exit(utils.STGIT_GENERAL_ERROR) cmd = sys.argv[1] if cmd in ['-h', '--help']: if len(sys.argv) >= 3: cmd = commands.canonical_cmd(sys.argv[2]) sys.argv[2] = '--help' else: print_help() sys.exit(utils.STGIT_SUCCESS) if cmd == 'help': if len(sys.argv) == 3 and not sys.argv[2] in ['-h', '--help']: cmd = commands.canonical_cmd(sys.argv[2]) if cmd not in commands: out.error('%s help: "%s" command unknown' % (prog, cmd)) sys.exit(utils.STGIT_GENERAL_ERROR) sys.argv[0] += ' %s' % cmd command = commands[cmd] parser = argparse.make_option_parser(command) if is_cmd_alias(command): parser.remove_option('-h') from pydoc import pager pager(parser.format_help()) else: print_help() sys.exit(utils.STGIT_SUCCESS) if cmd in ['-v', '--version', 'version']: from stgit.version import version print('Stacked GIT %s' % version) os.system('git --version') print('Python version %s' % sys.version) sys.exit(utils.STGIT_SUCCESS) if cmd in ['copyright']: print(__copyright__) sys.exit(utils.STGIT_SUCCESS) # re-build the command line arguments cmd = commands.canonical_cmd(cmd) sys.argv[0] += ' %s' % cmd del(sys.argv[1]) command = commands[cmd] if is_cmd_alias(command): sys.exit(command.func(sys.argv[1:])) parser = argparse.make_option_parser(command) directory = command.directory # These modules are only used from this point onwards and do not # need to be imported earlier try: from configparser import ParsingError, NoSectionError except ImportError: from ConfigParser import ParsingError, NoSectionError from stgit.exception import StgException from stgit.config import config_setup from stgit.stack import Series try: debug_level = int(os.environ.get('STGIT_DEBUG_LEVEL', 0)) except ValueError: out.error('Invalid STGIT_DEBUG_LEVEL environment variable') sys.exit(utils.STGIT_GENERAL_ERROR) try: (options, args) = parser.parse_args() directory.setup() config_setup() # Some commands don't (always) need an initialized series. if directory.needs_current_series: if hasattr(options, 'branch') and options.branch: command.crt_series = Series(options.branch) else: command.crt_series = Series() ret = command.func(parser, options, args) except (StgException, IOError, ParsingError, NoSectionError) as err: directory.write_log(cmd) if debug_level > 0: traceback.print_exc(file=sys.stderr) out.error(str(err), title = '%s %s' % (prog, cmd)) sys.exit(utils.STGIT_COMMAND_ERROR) except SystemExit: # Triggered by the option parser when it finds bad commandline # parameters. sys.exit(utils.STGIT_COMMAND_ERROR) except KeyboardInterrupt: sys.exit(utils.STGIT_GENERAL_ERROR) except: out.error('Unhandled exception:') traceback.print_exc(file=sys.stderr) sys.exit(utils.STGIT_BUG_ERROR) directory.write_log(cmd) sys.exit(ret or utils.STGIT_SUCCESS)