From fcee87cf868f18a3d684c3ba71232574f92c7b11 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 12 Jul 2005 23:02:06 +0100 Subject: [PATCH] Separate the commands in stgit/commands/* files The main.py file is getting bigger and bigger and it will soon become unmaintenable. This patch creates separate files for each command. Signed-off-by: Catalin Marinas --- stgit/commands/__init__.py | 16 + stgit/commands/add.py | 39 +++ stgit/commands/applied.py | 40 +++ stgit/commands/common.py | 114 +++++++ stgit/commands/delete.py | 46 +++ stgit/commands/diff.py | 67 ++++ stgit/commands/export.py | 155 +++++++++ stgit/commands/files.py | 51 +++ stgit/commands/init.py | 39 +++ stgit/commands/new.py | 59 ++++ stgit/commands/pop.py | 79 +++++ stgit/commands/push.py | 118 +++++++ stgit/commands/refresh.py | 94 +++++ stgit/commands/resolved.py | 63 ++++ stgit/commands/rm.py | 41 +++ stgit/commands/series.py | 57 ++++ stgit/commands/status.py | 51 +++ stgit/commands/top.py | 43 +++ stgit/commands/unapplied.py | 40 +++ stgit/main.py | 816 +++----------------------------------------- 20 files changed, 1251 insertions(+), 777 deletions(-) create mode 100644 stgit/commands/__init__.py create mode 100644 stgit/commands/add.py create mode 100644 stgit/commands/applied.py create mode 100644 stgit/commands/common.py create mode 100644 stgit/commands/delete.py create mode 100644 stgit/commands/diff.py create mode 100644 stgit/commands/export.py create mode 100644 stgit/commands/files.py create mode 100644 stgit/commands/init.py create mode 100644 stgit/commands/new.py create mode 100644 stgit/commands/pop.py create mode 100644 stgit/commands/push.py create mode 100644 stgit/commands/refresh.py create mode 100644 stgit/commands/resolved.py create mode 100644 stgit/commands/rm.py create mode 100644 stgit/commands/series.py create mode 100644 stgit/commands/status.py create mode 100644 stgit/commands/top.py create mode 100644 stgit/commands/unapplied.py diff --git a/stgit/commands/__init__.py b/stgit/commands/__init__.py new file mode 100644 index 0000000..4b03e3a --- /dev/null +++ b/stgit/commands/__init__.py @@ -0,0 +1,16 @@ +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" diff --git a/stgit/commands/add.py b/stgit/commands/add.py new file mode 100644 index 0000000..7bad07c --- /dev/null +++ b/stgit/commands/add.py @@ -0,0 +1,39 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'add files or directories to the repository' +usage = """%prog """ + +options = [] + + +def func(parser, options, args): + """Add files or directories to the repository + """ + if len(args) < 1: + parser.error('incorrect number of arguments') + + git.add(args) diff --git a/stgit/commands/applied.py b/stgit/commands/applied.py new file mode 100644 index 0000000..94b26c6 --- /dev/null +++ b/stgit/commands/applied.py @@ -0,0 +1,40 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'print the applied patches' +usage = '%prog' + +options = [] + + +def func(parser, options, args): + """Show the applied patches + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + for p in crt_series.get_applied(): + print p diff --git a/stgit/commands/common.py b/stgit/commands/common.py new file mode 100644 index 0000000..6193eb0 --- /dev/null +++ b/stgit/commands/common.py @@ -0,0 +1,114 @@ +"""Function/variables commmon to all the commands +""" + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.utils import * +from stgit import stack, git + + +# Command exception class +class CmdException(Exception): + pass + + +# Global variables +crt_series = stack.Series() + + +# Utility functions +def git_id(string): + """Return the GIT id + """ + if not string: + return None + + string_list = string.split('/') + + if len(string_list) == 1: + patch_name = None + git_id = string_list[0] + + if git_id == 'HEAD': + return git.get_head() + if git_id == 'base': + return read_string(crt_series.get_base_file()) + + for path in [os.path.join(git.base_dir, 'refs', 'heads'), + os.path.join(git.base_dir, 'refs', 'tags')]: + id_file = os.path.join(path, git_id) + if os.path.isfile(id_file): + return read_string(id_file) + elif len(string_list) == 2: + patch_name = string_list[0] + if patch_name == '': + patch_name = crt_series.get_current() + git_id = string_list[1] + + if not patch_name: + raise CmdException, 'No patches applied' + elif not (patch_name in crt_series.get_applied() + + crt_series.get_unapplied()): + raise CmdException, 'Unknown patch "%s"' % patch_name + + if git_id == 'bottom': + return crt_series.get_patch(patch_name).get_bottom() + if git_id == 'top': + return crt_series.get_patch(patch_name).get_top() + + raise CmdException, 'Unknown id: %s' % string + +def check_local_changes(): + if git.local_changes(): + raise CmdException, \ + 'local changes in the tree. Use "refresh" to commit them' + +def check_head_top_equal(): + if not crt_series.head_top_equal(): + raise CmdException, \ + 'HEAD and top are not the same. You probably committed\n' \ + ' changes to the tree ouside of StGIT. If you know what you\n' \ + ' are doing, use the "refresh -f" command' + +def check_conflicts(): + if os.path.exists(os.path.join(git.base_dir, 'conflicts')): + raise CmdException, 'Unsolved conflicts. Please resolve them first' + +def print_crt_patch(): + patch = crt_series.get_current() + if patch: + print 'Now at patch "%s"' % patch + else: + print 'No patches applied' + +def resolved(filename): + git.update_cache([filename]) + for ext in ['.local', '.older', '.remote']: + fn = filename + ext + if os.path.isfile(fn): + os.remove(fn) + +def resolved_all(): + conflicts = git.get_conflicts() + if conflicts: + for filename in conflicts: + resolved(filename) + os.remove(os.path.join(git.base_dir, 'conflicts')) diff --git a/stgit/commands/delete.py b/stgit/commands/delete.py new file mode 100644 index 0000000..a003082 --- /dev/null +++ b/stgit/commands/delete.py @@ -0,0 +1,46 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'remove the topmost or any unapplied patch' +usage = '%prog ' + +options = [] + + +def func(parser, options, args): + """Deletes a patch + """ + if len(args) != 1: + parser.error('incorrect number of arguments') + + if args[0] == crt_series.get_current(): + check_local_changes() + check_conflicts() + check_head_top_equal() + + crt_series.delete_patch(args[0]) + print 'Patch "%s" successfully deleted' % args[0] + print_crt_patch() diff --git a/stgit/commands/diff.py b/stgit/commands/diff.py new file mode 100644 index 0000000..6036a18 --- /dev/null +++ b/stgit/commands/diff.py @@ -0,0 +1,67 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'show the tree diff' +usage = """%prog [options] [] + +The revision format is '([patch]/[bottom | top]) | '""" + +options = [make_option('-r', metavar = 'rev1[:[rev2]]', dest = 'revs', + help = 'show the diff between revisions'), + make_option('-s', '--stat', + help = 'show the stat instead of the diff', + action = 'store_true')] + + +def func(parser, options, args): + """Show the tree diff + """ + if options.revs: + rev_list = options.revs.split(':') + rev_list_len = len(rev_list) + if rev_list_len == 1: + if rev_list[0][-1] == '/': + # the whole patch + rev1 = rev_list[0] + 'bottom' + rev2 = rev_list[0] + 'top' + else: + rev1 = rev_list[0] + rev2 = None + elif rev_list_len == 2: + rev1 = rev_list[0] + rev2 = rev_list[1] + if rev2 == '': + rev2 = 'HEAD' + else: + parser.error('incorrect parameters to -r') + else: + rev1 = 'HEAD' + rev2 = None + + if options.stat: + print git.diffstat(args, git_id(rev1), git_id(rev2)) + else: + git.diff(args, git_id(rev1), git_id(rev2)) diff --git a/stgit/commands/export.py b/stgit/commands/export.py new file mode 100644 index 0000000..3021dbe --- /dev/null +++ b/stgit/commands/export.py @@ -0,0 +1,155 @@ +"""Export command +""" + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'exports a series of patches to (or patches)' +usage = """%prog [options] []""" + +options = [make_option('-n', '--numbered', + help = 'number the patch names', + action = 'store_true'), + make_option('-d', '--diff', + help = 'append .diff to the patch names', + action = 'store_true'), + make_option('-t', '--template', metavar = 'FILE', + help = 'Use FILE as a template'), + make_option('-r', '--range', + metavar = '[PATCH1][:[PATCH2]]', + help = 'export patches between PATCH1 and PATCH2')] + + +def func(parser, options, args): + if len(args) == 0: + dirname = 'patches' + elif len(args) == 1: + dirname = args[0] + else: + parser.error('incorrect number of arguments') + + if git.local_changes(): + print 'Warning: local changes in the tree. ' \ + 'You might want to commit them first' + + if not os.path.isdir(dirname): + os.makedirs(dirname) + series = file(os.path.join(dirname, 'series'), 'w+') + + applied = crt_series.get_applied() + + if options.range: + boundaries = options.range.split(':') + if len(boundaries) == 1: + start = boundaries[0] + stop = boundaries[0] + if len(boundaries) == 2: + if boundaries[0] == '': + start = applied[0] + else: + start = boundaries[0] + if boundaries[1] == '': + stop = applied[-1] + else: + stop = boundaries[1] + else: + raise MainException, 'incorrect parameters to "--range"' + + if start in applied: + start_idx = applied.index(start) + else: + raise MainException, 'Patch "%s" not applied' % start + if stop in applied: + stop_idx = applied.index(stop) + 1 + else: + raise MainException, 'Patch "%s" not applied' % stop + + if start_idx >= stop_idx: + raise MainException, 'Incorrect patch range order' + else: + start_idx = 0 + stop_idx = -1 + + patches = applied[start_idx:stop_idx] + + num = len(patches) + zpadding = len(str(num)) + if zpadding < 2: + zpadding = 2 + + patch_no = 1; + for p in patches: + pname = p + if options.diff: + pname = '%s.diff' % pname + if options.numbered: + pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname) + pfile = os.path.join(dirname, pname) + print >> series, pname + + # get the template + if options.template: + patch_tmpl = options.template + else: + patch_tmpl = os.path.join(git.base_dir, 'patchexport.tmpl') + if os.path.isfile(patch_tmpl): + tmpl = file(patch_tmpl).read() + else: + tmpl = '' + + # get the patch description + patch = crt_series.get_patch(p) + + tmpl_dict = {'description': patch.get_description().rstrip(), + 'diffstat': git.diffstat(rev1 = git_id('%s/bottom' % p), + rev2 = git_id('%s/top' % p)), + 'authname': patch.get_authname(), + 'authemail': patch.get_authemail(), + 'authdate': patch.get_authdate(), + 'commname': patch.get_commname(), + 'commemail': patch.get_commemail()} + for key in tmpl_dict: + if not tmpl_dict[key]: + tmpl_dict[key] = '' + + try: + descr = tmpl % tmpl_dict + except KeyError, err: + raise MainException, 'Unknown patch template variable: %s' \ + % err + except TypeError: + raise MainException, 'Only "%(name)s" variables are ' \ + 'supported in the patch template' + f = open(pfile, 'w+') + f.write(descr) + f.close() + + # write the diff + git.diff(rev1 = git_id('%s/bottom' % p), + rev2 = git_id('%s/top' % p), + output = pfile, append = True) + patch_no += 1 + + series.close() diff --git a/stgit/commands/files.py b/stgit/commands/files.py new file mode 100644 index 0000000..35be5db --- /dev/null +++ b/stgit/commands/files.py @@ -0,0 +1,51 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'show the files modified by a patch (or the current patch)' +usage = '%prog [options] []' + +options = [make_option('-s', '--stat', + help = 'show the diff stat', + action = 'store_true')] + + +def func(parser, options, args): + """Show the files modified by a patch (or the current patch) + """ + if len(args) == 0: + patch = '' + elif len(args) == 1: + patch = args[0] + else: + parser.error('incorrect number of arguments') + + rev1 = git_id('%s/bottom' % patch) + rev2 = git_id('%s/top' % patch) + + if options.stat: + print git.diffstat(rev1 = rev1, rev2 = rev2) + else: + print git.files(rev1, rev2) diff --git a/stgit/commands/init.py b/stgit/commands/init.py new file mode 100644 index 0000000..77ee1a2 --- /dev/null +++ b/stgit/commands/init.py @@ -0,0 +1,39 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'initialise the tree for use with StGIT' +usage = '%prog' + +options = [] + + +def func(parser, options, args): + """Performs the repository initialisation + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + crt_series.init() diff --git a/stgit/commands/new.py b/stgit/commands/new.py new file mode 100644 index 0000000..1779d9c --- /dev/null +++ b/stgit/commands/new.py @@ -0,0 +1,59 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'create a new patch and make it the topmost one' +usage = '%prog [options] ' + +options = [make_option('-m', '--message', + help = 'use MESSAGE as the patch description'), + make_option('--authname', + help = 'use AUTHNAME as the author name'), + make_option('--authemail', + help = 'use AUTHEMAIL as the author e-mail'), + make_option('--authdate', + help = 'use AUTHDATE as the author date'), + make_option('--commname', + help = 'use COMMNAME as the committer name'), + make_option('--commemail', + help = 'use COMMEMAIL as the committer e-mail')] + + +def func(parser, options, args): + """Creates a new patch + """ + if len(args) != 1: + parser.error('incorrect number of arguments') + + check_local_changes() + check_conflicts() + check_head_top_equal() + + crt_series.new_patch(args[0], message = options.message, + author_name = options.authname, + author_email = options.authemail, + author_date = options.authdate, + committer_name = options.commname, + committer_email = options.commemail) diff --git a/stgit/commands/pop.py b/stgit/commands/pop.py new file mode 100644 index 0000000..fb85eb8 --- /dev/null +++ b/stgit/commands/pop.py @@ -0,0 +1,79 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'pop the top of the series' +usage = '%prog [options]' + +options = [make_option('-a', '--all', + help = 'pop all the applied patches', + action = 'store_true'), + make_option('-n', '--number', type = 'int', + help = 'pop the specified number of patches'), + make_option('-t', '--to', metavar = 'PATCH', + help = 'pop all patches up to PATCH')] + + +def func(parser, options, args): + """Pop the topmost patch from the stack + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + check_local_changes() + check_conflicts() + check_head_top_equal() + + applied = crt_series.get_applied() + if not applied: + raise CmdException, 'No patches applied' + applied.reverse() + + if options.to: + if options.to not in applied: + raise CmdException, 'Patch "%s" not applied' % options.to + patches = applied[:applied.index(options.to)] + elif options.number: + patches = applied[:options.number] + elif options.all: + patches = applied + else: + patches = [applied[0]] + + if patches == []: + raise CmdException, 'No patches to pop' + + # pop everything to the given patch + p = patches[-1] + if len(patches) == 1: + print 'Popping patch "%s"...' % p, + else: + print 'Popping "%s" - "%s" patches...' % (patches[0], p), + sys.stdout.flush() + + crt_series.pop_patch(p) + + print 'done' + print_crt_patch() diff --git a/stgit/commands/push.py b/stgit/commands/push.py new file mode 100644 index 0000000..65462b3 --- /dev/null +++ b/stgit/commands/push.py @@ -0,0 +1,118 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'push a patch on top of the series' +usage = '%prog [options] []' + +options = [make_option('-a', '--all', + help = 'push all the unapplied patches', + action = 'store_true'), + make_option('-n', '--number', type = 'int', + help = 'push the specified number of patches'), + make_option('-t', '--to', metavar = 'PATCH1[:PATCH2]', + help = 'push all patches to PATCH1 or between ' + 'PATCH1 and PATCH2'), + make_option('--reverse', + help = 'push the patches in reverse order', + action = 'store_true'), + make_option('--undo', + help = 'undo the last push operation', + action = 'store_true')] + + +def func(parser, options, args): + """Pushes the given patch or all onto the series + """ + # If --undo is passed, do the work and exit + if options.undo: + patch = crt_series.get_current() + if not patch: + raise CmdException, 'No patch to undo' + + print 'Undoing the "%s" push...' % patch, + sys.stdout.flush() + resolved_all() + crt_series.undo_push() + print 'done' + print_crt_patch() + + return + + check_local_changes() + check_conflicts() + check_head_top_equal() + + unapplied = crt_series.get_unapplied() + if not unapplied: + raise CmdException, 'No more patches to push' + + if options.to: + boundaries = options.to.split(':') + if len(boundaries) == 1: + if boundaries[0] not in unapplied: + raise CmdException, 'Patch "%s" not unapplied' % boundaries[0] + patches = unapplied[:unapplied.index(boundaries[0])+1] + elif len(boundaries) == 2: + if boundaries[0] not in unapplied: + raise CmdException, 'Patch "%s" not unapplied' % boundaries[0] + if boundaries[1] not in unapplied: + raise CmdException, 'Patch "%s" not unapplied' % boundaries[1] + lb = unapplied.index(boundaries[0]) + hb = unapplied.index(boundaries[1]) + if lb > hb: + raise CmdException, 'Patch "%s" after "%s"' \ + % (boundaries[0], boundaries[1]) + patches = unapplied[lb:hb+1] + else: + raise CmdException, 'incorrect parameters to "--to"' + elif options.number: + patches = unapplied[:options.number] + elif options.all: + patches = unapplied + elif len(args) == 0: + patches = [unapplied[0]] + elif len(args) == 1: + patches = [args[0]] + else: + parser.error('incorrect number of arguments') + + if patches == []: + raise CmdException, 'No patches to push' + + if options.reverse: + patches.reverse() + + for p in patches: + print 'Pushing patch "%s"...' % p, + sys.stdout.flush() + + crt_series.push_patch(p) + + if crt_series.empty_patch(p): + print 'done (empty patch)' + else: + print 'done' + print_crt_patch() diff --git a/stgit/commands/refresh.py b/stgit/commands/refresh.py new file mode 100644 index 0000000..81e3066 --- /dev/null +++ b/stgit/commands/refresh.py @@ -0,0 +1,94 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git +from stgit.config import config + + +help = 'generate a new commit for the current patch' +usage = '%prog [options]' + +options = [make_option('-f', '--force', + help = 'force the refresh even if HEAD and '\ + 'top differ', + action = 'store_true'), + make_option('-e', '--edit', + help = 'invoke an editor for the patch '\ + 'description', + action = 'store_true'), + make_option('-m', '--message', + help = 'use MESSAGE as the patch ' \ + 'description'), + make_option('--authname', + help = 'use AUTHNAME as the author name'), + make_option('--authemail', + help = 'use AUTHEMAIL as the author e-mail'), + make_option('--authdate', + help = 'use AUTHDATE as the author date'), + make_option('--commname', + help = 'use COMMNAME as the committer name'), + make_option('--commemail', + help = 'use COMMEMAIL as the committer ' \ + 'e-mail')] + + +def func(parser, options, args): + if len(args) != 0: + parser.error('incorrect number of arguments') + + if config.has_option('stgit', 'autoresolved'): + autoresolved = config.get('stgit', 'autoresolved') + else: + autoresolved = 'no' + + if autoresolved != 'yes': + check_conflicts() + + patch = crt_series.get_current() + if not patch: + raise CmdException, 'No patches applied' + + if not options.force: + check_head_top_equal() + + if git.local_changes() \ + or not crt_series.head_top_equal() \ + or options.edit or options.message \ + or options.authname or options.authemail or options.authdate \ + or options.commname or options.commemail: + print 'Refreshing patch "%s"...' % patch, + sys.stdout.flush() + + if autoresolved == 'yes': + resolved_all() + crt_series.refresh_patch(message = options.message, + edit = options.edit, + author_name = options.authname, + author_email = options.authemail, + author_date = options.authdate, + committer_name = options.commname, + committer_email = options.commemail) + + print 'done' + else: + print 'Patch "%s" is already up to date' % patch diff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py new file mode 100644 index 0000000..c9ae6ca --- /dev/null +++ b/stgit/commands/resolved.py @@ -0,0 +1,63 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'mark a file conflict as solved' +usage = '%prog [options] [[ ]]' + +options = [make_option('-a', '--all', + help = 'mark all conflicts as solved', + action = 'store_true')] + + +def func(parser, options, args): + """Mark the conflict as resolved + """ + if options.all: + resolved_all() + return + + if len(args) == 0: + parser.error('incorrect number of arguments') + + conflicts = git.get_conflicts() + if not conflicts: + raise CmdException, 'No more conflicts' + # check for arguments validity + for filename in args: + if not filename in conflicts: + raise CmdException, 'No conflicts for "%s"' % filename + # resolved + for filename in args: + resolved(filename) + del conflicts[conflicts.index(filename)] + + # save or remove the conflicts file + if conflicts == []: + os.remove(os.path.join(git.base_dir, 'conflicts')) + else: + f = file(os.path.join(git.base_dir, 'conflicts'), 'w+') + f.writelines([line + '\n' for line in conflicts]) + f.close() diff --git a/stgit/commands/rm.py b/stgit/commands/rm.py new file mode 100644 index 0000000..9d06e9a --- /dev/null +++ b/stgit/commands/rm.py @@ -0,0 +1,41 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'remove files from the repository' +usage = '%prog [options] ' + +options = [make_option('-f', '--force', + help = 'force removing even if the file exists', + action = 'store_true')] + + +def func(parser, options, args): + """Remove files from the repository + """ + if len(args) < 1: + parser.error('incorrect number of arguments') + + git.rm(args, options.force) diff --git a/stgit/commands/series.py b/stgit/commands/series.py new file mode 100644 index 0000000..8559d25 --- /dev/null +++ b/stgit/commands/series.py @@ -0,0 +1,57 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'print the patch series' +usage = '%prog' + +options = [] + + +def func(parser, options, args): + """Show the patch series + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + applied = crt_series.get_applied() + if len(applied) > 0: + for p in applied [0:-1]: + if crt_series.empty_patch(p): + print '0', p + else: + print '+', p + p = applied[-1] + + if crt_series.empty_patch(p): + print '0>%s' % p + else: + print '> %s' % p + + for p in crt_series.get_unapplied(): + if crt_series.empty_patch(p): + print '0', p + else: + print '-', p diff --git a/stgit/commands/status.py b/stgit/commands/status.py new file mode 100644 index 0000000..65bffac --- /dev/null +++ b/stgit/commands/status.py @@ -0,0 +1,51 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'show the tree status' +usage = '%prog [options] []' + +options = [make_option('-m', '--modified', + help = 'show modified files only', + action = 'store_true'), + make_option('-n', '--new', + help = 'show new files only', + action = 'store_true'), + make_option('-d', '--deleted', + help = 'show deleted files only', + action = 'store_true'), + make_option('-c', '--conflict', + help = 'show conflict files only', + action = 'store_true'), + make_option('-u', '--unknown', + help = 'show unknown files only', + action = 'store_true')] + + +def func(parser, options, args): + """Show the tree status + """ + git.status(args, options.modified, options.new, options.deleted, + options.conflict, options.unknown) diff --git a/stgit/commands/top.py b/stgit/commands/top.py new file mode 100644 index 0000000..676c7ad --- /dev/null +++ b/stgit/commands/top.py @@ -0,0 +1,43 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'print the name of the top patch' +usage = '%prog' + +options = [] + + +def func(parser, options, args): + """Show the name of the topmost patch + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + name = crt_series.get_current() + if name: + print name + else: + raise CmdException, 'No patches applied' diff --git a/stgit/commands/unapplied.py b/stgit/commands/unapplied.py new file mode 100644 index 0000000..5d7564a --- /dev/null +++ b/stgit/commands/unapplied.py @@ -0,0 +1,40 @@ + +__copyright__ = """ +Copyright (C) 2005, Catalin Marinas + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys, os +from optparse import OptionParser, make_option + +from stgit.commands.common import * +from stgit.utils import * +from stgit import stack, git + + +help = 'print the unapplied patches' +usage = '%prog' + +options = [] + + +def func(parser, options, args): + """Show the unapplied patches + """ + if len(args) != 0: + parser.error('incorrect number of arguments') + + for p in crt_series.get_unapplied(): + print p diff --git a/stgit/main.py b/stgit/main.py index e235d10..eb5e63f 100644 --- a/stgit/main.py +++ b/stgit/main.py @@ -25,784 +25,49 @@ from stgit.utils import * from stgit import stack, git from stgit.version import version from stgit.config import config +from stgit.commands.common import * + +# The commands +import stgit.commands.add +import stgit.commands.applied +import stgit.commands.delete +import stgit.commands.diff +import stgit.commands.export +import stgit.commands.files +import stgit.commands.init +import stgit.commands.new +import stgit.commands.pop +import stgit.commands.push +import stgit.commands.refresh +import stgit.commands.resolved +import stgit.commands.rm +import stgit.commands.series +import stgit.commands.status +import stgit.commands.top +import stgit.commands.unapplied -# Main exception class -class MainException(Exception): - pass - - -# Utility functions -def __git_id(string): - """Return the GIT id - """ - if not string: - return None - - string_list = string.split('/') - - if len(string_list) == 1: - patch_name = None - git_id = string_list[0] - - if git_id == 'HEAD': - return git.get_head() - if git_id == 'base': - return read_string(crt_series.get_base_file()) - - for path in [os.path.join(git.base_dir, 'refs', 'heads'), - os.path.join(git.base_dir, 'refs', 'tags')]: - id_file = os.path.join(path, git_id) - if os.path.isfile(id_file): - return read_string(id_file) - elif len(string_list) == 2: - patch_name = string_list[0] - if patch_name == '': - patch_name = crt_series.get_current() - git_id = string_list[1] - - if not patch_name: - raise MainException, 'No patches applied' - elif not (patch_name in crt_series.get_applied() - + crt_series.get_unapplied()): - raise MainException, 'Unknown patch "%s"' % patch_name - - if git_id == 'bottom': - return crt_series.get_patch(patch_name).get_bottom() - if git_id == 'top': - return crt_series.get_patch(patch_name).get_top() - - raise MainException, 'Unknown id: %s' % string - -def __check_local_changes(): - if git.local_changes(): - raise MainException, \ - 'local changes in the tree. Use "refresh" to commit them' - -def __check_head_top_equal(): - if not crt_series.head_top_equal(): - raise MainException, \ - 'HEAD and top are not the same. You probably committed\n' \ - ' changes to the tree ouside of StGIT. If you know what you\n' \ - ' are doing, use the "refresh -f" command' - -def __check_conflicts(): - if os.path.exists(os.path.join(git.base_dir, 'conflicts')): - raise MainException, 'Unsolved conflicts. Please resolve them first' - -def __print_crt_patch(): - patch = crt_series.get_current() - if patch: - print 'Now at patch "%s"' % patch - else: - print 'No patches applied' - - -# -# Command functions -# -class Command: - """This class is used to store the command details - """ - def __init__(self, func, help, usage, option_list): - self.func = func - self.help = help - self.usage = usage - self.option_list = option_list - - -def init(parser, options, args): - """Performs the repository initialisation - """ - if len(args) != 0: - parser.error('incorrect number of arguments') - - crt_series.init() - -init_cmd = \ - Command(init, - 'initialise the tree for use with StGIT', - '%prog', - []) - - -def add(parser, options, args): - """Add files or directories to the repository - """ - if len(args) < 1: - parser.error('incorrect number of arguments') - - git.add(args) - -add_cmd = \ - Command(add, - 'add files or directories to the repository', - '%prog ', - []) - - -def rm(parser, options, args): - """Remove files from the repository - """ - if len(args) < 1: - parser.error('incorrect number of arguments') - - git.rm(args, options.force) - -rm_cmd = \ - Command(rm, - 'remove files from the repository', - '%prog [options] ', - [make_option('-f', '--force', - help = 'force removing even if the file exists', - action = 'store_true')]) - - -def status(parser, options, args): - """Show the tree status - """ - git.status(args, options.modified, options.new, options.deleted, - options.conflict, options.unknown) - -status_cmd = \ - Command(status, - 'show the tree status', - '%prog [options] []', - [make_option('-m', '--modified', - help = 'show modified files only', - action = 'store_true'), - make_option('-n', '--new', - help = 'show new files only', - action = 'store_true'), - make_option('-d', '--deleted', - help = 'show deleted files only', - action = 'store_true'), - make_option('-c', '--conflict', - help = 'show conflict files only', - action = 'store_true'), - make_option('-u', '--unknown', - help = 'show unknown files only', - action = 'store_true')]) - - -def diff(parser, options, args): - """Show the tree diff - """ - if options.revs: - rev_list = options.revs.split(':') - rev_list_len = len(rev_list) - if rev_list_len == 1: - if rev_list[0][-1] == '/': - # the whole patch - rev1 = rev_list[0] + 'bottom' - rev2 = rev_list[0] + 'top' - else: - rev1 = rev_list[0] - rev2 = None - elif rev_list_len == 2: - rev1 = rev_list[0] - rev2 = rev_list[1] - if rev2 == '': - rev2 = 'HEAD' - else: - parser.error('incorrect parameters to -r') - else: - rev1 = 'HEAD' - rev2 = None - - if options.stat: - print git.diffstat(args, __git_id(rev1), __git_id(rev2)) - else: - git.diff(args, __git_id(rev1), __git_id(rev2)) - -diff_cmd = \ - Command(diff, - 'show the tree diff', - '%prog [options] []\n\n' - 'The revision format is "([patch]/[bottom | top]) | "', - [make_option('-r', metavar = 'rev1[:[rev2]]', dest = 'revs', - help = 'show the diff between revisions'), - make_option('-s', '--stat', - help = 'show the stat instead of the diff', - action = 'store_true')]) - - -def files(parser, options, args): - """Show the files modified by a patch (or the current patch) - """ - if len(args) == 0: - patch = '' - elif len(args) == 1: - patch = args[0] - else: - parser.error('incorrect number of arguments') - - rev1 = __git_id('%s/bottom' % patch) - rev2 = __git_id('%s/top' % patch) - - if options.stat: - print git.diffstat(rev1 = rev1, rev2 = rev2) - else: - print git.files(rev1, rev2) - -files_cmd = \ - Command(files, - 'show the files modified by a patch (or the current patch)', - '%prog [options] []', - [make_option('-s', '--stat', - help = 'show the diff stat', - action = 'store_true')]) - - -def refresh(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - if config.has_option('stgit', 'autoresolved'): - autoresolved = config.get('stgit', 'autoresolved') - else: - autoresolved = 'no' - - if autoresolved != 'yes': - __check_conflicts() - - patch = crt_series.get_current() - if not patch: - raise MainException, 'No patches applied' - - if not options.force: - __check_head_top_equal() - - if git.local_changes() \ - or not crt_series.head_top_equal() \ - or options.edit or options.message \ - or options.authname or options.authemail or options.authdate \ - or options.commname or options.commemail: - print 'Refreshing patch "%s"...' % patch, - sys.stdout.flush() - - if autoresolved == 'yes': - __resolved_all() - crt_series.refresh_patch(message = options.message, - edit = options.edit, - author_name = options.authname, - author_email = options.authemail, - author_date = options.authdate, - committer_name = options.commname, - committer_email = options.commemail) - - print 'done' - else: - print 'Patch "%s" is already up to date' % patch - -refresh_cmd = \ - Command(refresh, - 'generate a new commit for the current patch', - '%prog [options]', - [make_option('-f', '--force', - help = 'force the refresh even if HEAD and '\ - 'top differ', - action = 'store_true'), - make_option('-e', '--edit', - help = 'invoke an editor for the patch '\ - 'description', - action = 'store_true'), - make_option('-m', '--message', - help = 'use MESSAGE as the patch ' \ - 'description'), - make_option('--authname', - help = 'use AUTHNAME as the author name'), - make_option('--authemail', - help = 'use AUTHEMAIL as the author e-mail'), - make_option('--authdate', - help = 'use AUTHDATE as the author date'), - make_option('--commname', - help = 'use COMMNAME as the committer name'), - make_option('--commemail', - help = 'use COMMEMAIL as the committer ' \ - 'e-mail')]) - - -def new(parser, options, args): - """Creates a new patch - """ - if len(args) != 1: - parser.error('incorrect number of arguments') - - __check_local_changes() - __check_conflicts() - __check_head_top_equal() - - crt_series.new_patch(args[0], message = options.message, - author_name = options.authname, - author_email = options.authemail, - author_date = options.authdate, - committer_name = options.commname, - committer_email = options.commemail) - -new_cmd = \ - Command(new, - 'create a new patch and make it the topmost one', - '%prog [options] ', - [make_option('-m', '--message', - help = 'use MESSAGE as the patch description'), - make_option('--authname', - help = 'use AUTHNAME as the author name'), - make_option('--authemail', - help = 'use AUTHEMAIL as the author e-mail'), - make_option('--authdate', - help = 'use AUTHDATE as the author date'), - make_option('--commname', - help = 'use COMMNAME as the committer name'), - make_option('--commemail', - help = 'use COMMEMAIL as the committer e-mail')]) - -def delete(parser, options, args): - """Deletes a patch - """ - if len(args) != 1: - parser.error('incorrect number of arguments') - - if args[0] == crt_series.get_current(): - __check_local_changes() - __check_conflicts() - __check_head_top_equal() - - crt_series.delete_patch(args[0]) - print 'Patch "%s" successfully deleted' % args[0] - __print_crt_patch() - -delete_cmd = \ - Command(delete, - 'remove the topmost or any unapplied patch', - '%prog ', - []) - - -def push(parser, options, args): - """Pushes the given patch or all onto the series - """ - # If --undo is passed, do the work and exit - if options.undo: - patch = crt_series.get_current() - if not patch: - raise MainException, 'No patch to undo' - - print 'Undoing the "%s" push...' % patch, - sys.stdout.flush() - __resolved_all() - crt_series.undo_push() - print 'done' - __print_crt_patch() - - return - - __check_local_changes() - __check_conflicts() - __check_head_top_equal() - - unapplied = crt_series.get_unapplied() - if not unapplied: - raise MainException, 'No more patches to push' - - if options.to: - boundaries = options.to.split(':') - if len(boundaries) == 1: - if boundaries[0] not in unapplied: - raise MainException, 'Patch "%s" not unapplied' % boundaries[0] - patches = unapplied[:unapplied.index(boundaries[0])+1] - elif len(boundaries) == 2: - if boundaries[0] not in unapplied: - raise MainException, 'Patch "%s" not unapplied' % boundaries[0] - if boundaries[1] not in unapplied: - raise MainException, 'Patch "%s" not unapplied' % boundaries[1] - lb = unapplied.index(boundaries[0]) - hb = unapplied.index(boundaries[1]) - if lb > hb: - raise MainException, 'Patch "%s" after "%s"' \ - % (boundaries[0], boundaries[1]) - patches = unapplied[lb:hb+1] - else: - raise MainException, 'incorrect parameters to "--to"' - elif options.number: - patches = unapplied[:options.number] - elif options.all: - patches = unapplied - elif len(args) == 0: - patches = [unapplied[0]] - elif len(args) == 1: - patches = [args[0]] - else: - parser.error('incorrect number of arguments') - - if patches == []: - raise MainException, 'No patches to push' - - if options.reverse: - patches.reverse() - - for p in patches: - print 'Pushing patch "%s"...' % p, - sys.stdout.flush() - - crt_series.push_patch(p) - - if crt_series.empty_patch(p): - print 'done (empty patch)' - else: - print 'done' - __print_crt_patch() - -push_cmd = \ - Command(push, - 'push a patch on top of the series', - '%prog [options] []', - [make_option('-a', '--all', - help = 'push all the unapplied patches', - action = 'store_true'), - make_option('-n', '--number', type = 'int', - help = 'push the specified number of patches'), - make_option('-t', '--to', metavar = 'PATCH1[:PATCH2]', - help = 'push all patches to PATCH1 or between ' - 'PATCH1 and PATCH2'), - make_option('--reverse', - help = 'push the patches in reverse order', - action = 'store_true'), - make_option('--undo', - help = 'undo the last push operation', - action = 'store_true')]) - - -def pop(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - __check_local_changes() - __check_conflicts() - __check_head_top_equal() - - applied = crt_series.get_applied() - if not applied: - raise MainException, 'No patches applied' - applied.reverse() - - if options.to: - if options.to not in applied: - raise MainException, 'Patch "%s" not applied' % options.to - patches = applied[:applied.index(options.to)] - elif options.number: - patches = applied[:options.number] - elif options.all: - patches = applied - else: - patches = [applied[0]] - - if patches == []: - raise MainException, 'No patches to pop' - - # pop everything to the given patch - p = patches[-1] - if len(patches) == 1: - print 'Popping patch "%s"...' % p, - else: - print 'Popping "%s" - "%s" patches...' % (patches[0], p), - sys.stdout.flush() - - crt_series.pop_patch(p) - - print 'done' - __print_crt_patch() - -pop_cmd = \ - Command(pop, - 'pop the top of the series', - '%prog [options]', - [make_option('-a', '--all', - help = 'pop all the applied patches', - action = 'store_true'), - make_option('-n', '--number', type = 'int', - help = 'pop the specified number of patches'), - make_option('-t', '--to', metavar = 'PATCH', - help = 'pop all patches up to PATCH')]) - - -def __resolved(filename): - git.update_cache([filename]) - for ext in ['.local', '.older', '.remote']: - fn = filename + ext - if os.path.isfile(fn): - os.remove(fn) - -def __resolved_all(): - conflicts = git.get_conflicts() - if conflicts: - for filename in conflicts: - __resolved(filename) - os.remove(os.path.join(git.base_dir, 'conflicts')) - -def resolved(parser, options, args): - if options.all: - __resolved_all() - return - - if len(args) == 0: - parser.error('incorrect number of arguments') - - conflicts = git.get_conflicts() - if not conflicts: - raise MainException, 'No more conflicts' - # check for arguments validity - for filename in args: - if not filename in conflicts: - raise MainException, 'No conflicts for "%s"' % filename - # resolved - for filename in args: - __resolved(filename) - del conflicts[conflicts.index(filename)] - - # save or remove the conflicts file - if conflicts == []: - os.remove(os.path.join(git.base_dir, 'conflicts')) - else: - f = file(os.path.join(git.base_dir, 'conflicts'), 'w+') - f.writelines([line + '\n' for line in conflicts]) - f.close() - -resolved_cmd = \ - Command(resolved, - 'mark a file conflict as solved', - '%prog [options] [[ ]]', - [make_option('-a', '--all', - help = 'mark all conflicts as solved', - action = 'store_true')]) - - -def series(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - applied = crt_series.get_applied() - if len(applied) > 0: - for p in applied [0:-1]: - if crt_series.empty_patch(p): - print '0', p - else: - print '+', p - p = applied[-1] - - if crt_series.empty_patch(p): - print '0>%s' % p - else: - print '> %s' % p - - for p in crt_series.get_unapplied(): - if crt_series.empty_patch(p): - print '0', p - else: - print '-', p - -series_cmd = \ - Command(series, - 'print the patch series', - '%prog', - []) - - -def applied(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - for p in crt_series.get_applied(): - print p - -applied_cmd = \ - Command(applied, - 'print the applied patches', - '%prog', - []) - - -def unapplied(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - for p in crt_series.get_unapplied(): - print p - -unapplied_cmd = \ - Command(unapplied, - 'print the unapplied patches', - '%prog', - []) - - -def top(parser, options, args): - if len(args) != 0: - parser.error('incorrect number of arguments') - - name = crt_series.get_current() - if name: - print name - else: - raise MainException, 'No patches applied' - -top_cmd = \ - Command(top, - 'print the name of the top patch', - '%prog', - []) - - -def export(parser, options, args): - if len(args) == 0: - dirname = 'patches' - elif len(args) == 1: - dirname = args[0] - else: - parser.error('incorrect number of arguments') - - if git.local_changes(): - print 'Warning: local changes in the tree. ' \ - 'You might want to commit them first' - - if not os.path.isdir(dirname): - os.makedirs(dirname) - series = file(os.path.join(dirname, 'series'), 'w+') - - applied = crt_series.get_applied() - - if options.range: - boundaries = options.range.split(':') - if len(boundaries) == 1: - start = boundaries[0] - stop = boundaries[0] - if len(boundaries) == 2: - if boundaries[0] == '': - start = applied[0] - else: - start = boundaries[0] - if boundaries[1] == '': - stop = applied[-1] - else: - stop = boundaries[1] - else: - raise MainException, 'incorrect parameters to "--range"' - - if start in applied: - start_idx = applied.index(start) - else: - raise MainException, 'Patch "%s" not applied' % start - if stop in applied: - stop_idx = applied.index(stop) + 1 - else: - raise MainException, 'Patch "%s" not applied' % stop - - if start_idx >= stop_idx: - raise MainException, 'Incorrect patch range order' - else: - start_idx = 0 - stop_idx = -1 - - patches = applied[start_idx:stop_idx] - - num = len(patches) - zpadding = len(str(num)) - if zpadding < 2: - zpadding = 2 - - patch_no = 1; - for p in patches: - pname = p - if options.diff: - pname = '%s.diff' % pname - if options.numbered: - pname = '%s-%s' % (str(patch_no).zfill(zpadding), pname) - pfile = os.path.join(dirname, pname) - print >> series, pname - - # get the template - if options.template: - patch_tmpl = options.template - else: - patch_tmpl = os.path.join(git.base_dir, 'patchexport.tmpl') - if os.path.isfile(patch_tmpl): - tmpl = file(patch_tmpl).read() - else: - tmpl = '' - - # get the patch description - patch = crt_series.get_patch(p) - - tmpl_dict = {'description': patch.get_description().rstrip(), - 'diffstat': git.diffstat(rev1 = __git_id('%s/bottom' % p), - rev2 = __git_id('%s/top' % p)), - 'authname': patch.get_authname(), - 'authemail': patch.get_authemail(), - 'authdate': patch.get_authdate(), - 'commname': patch.get_commname(), - 'commemail': patch.get_commemail()} - for key in tmpl_dict: - if not tmpl_dict[key]: - tmpl_dict[key] = '' - - try: - descr = tmpl % tmpl_dict - except KeyError, err: - raise MainException, 'Unknown patch template variable: %s' \ - % err - except TypeError: - raise MainException, 'Only "%(name)s" variables are ' \ - 'supported in the patch template' - f = open(pfile, 'w+') - f.write(descr) - f.close() - - # write the diff - git.diff(rev1 = __git_id('%s/bottom' % p), - rev2 = __git_id('%s/top' % p), - output = pfile, append = True) - patch_no += 1 - - series.close() - -export_cmd = \ - Command(export, - 'exports a series of patches to (or patches)', - '%prog [options] []', - [make_option('-n', '--numbered', - help = 'number the patch names', - action = 'store_true'), - make_option('-d', '--diff', - help = 'append .diff to the patch names', - action = 'store_true'), - make_option('-t', '--template', metavar = 'FILE', - help = 'Use FILE as a template'), - make_option('-r', '--range', - metavar = '[PATCH1][:[PATCH2]]', - help = 'export patches between ' \ - 'PATCH1 and PATCH2')]) - # # The commands map # commands = { - 'init': init_cmd, - 'add': add_cmd, - 'rm': rm_cmd, - 'status': status_cmd, - 'diff': diff_cmd, - 'files': files_cmd, - 'new': new_cmd, - 'delete': delete_cmd, - 'push': push_cmd, - 'pop': pop_cmd, - 'resolved': resolved_cmd, - 'series': series_cmd, - 'applied': applied_cmd, - 'unapplied':unapplied_cmd, - 'top': top_cmd, - 'refresh': refresh_cmd, - 'export': export_cmd, + 'add': stgit.commands.add, + 'applied': stgit.commands.applied, + 'delete': stgit.commands.delete, + 'diff': stgit.commands.diff, + 'export': stgit.commands.export, + 'files': stgit.commands.files, + 'init': stgit.commands.init, + 'new': stgit.commands.new, + 'pop': stgit.commands.pop, + 'push': stgit.commands.push, + 'refresh': stgit.commands.refresh, + 'resolved': stgit.commands.resolved, + 'rm': stgit.commands.rm, + 'series': stgit.commands.series, + 'status': stgit.commands.status, + 'top': stgit.commands.top, + 'unapplied':stgit.commands.unapplied, } def print_help(): @@ -822,8 +87,6 @@ def print_help(): def main(): """The main function """ - global crt_series - prog = os.path.basename(sys.argv[0]) if len(sys.argv) < 2: @@ -852,12 +115,11 @@ def main(): command = commands[cmd] parser = OptionParser(usage = command.usage, - option_list = command.option_list) + option_list = command.options) options, args = parser.parse_args() try: - crt_series = stack.Series() command.func(parser, options, args) - except (IOError, MainException, stack.StackException, git.GitException), \ + except (IOError, CmdException, stack.StackException, git.GitException), \ err: print >> sys.stderr, '%s %s: %s' % (prog, cmd, err) sys.exit(2) -- 2.11.0