chiark / gitweb /
Generate command lists automatically
authorKarl Hasselström <kha@treskal.com>
Sun, 21 Sep 2008 12:19:07 +0000 (14:19 +0200)
committerKarl Hasselström <kha@treskal.com>
Sun, 21 Sep 2008 12:19:07 +0000 (14:19 +0200)
Instead of hard-coding the list of stg subcommands everywhere,
generate them automatically. That way, they never get outdated (like
the list in stg.txt).

In order to not make StGit slower, we cache the list of commands; run
"make build" to update that cache (other make targets, such as "all"
and "test", imply "build"). If the cache doesn't exist, the code falls
back to importing all the command modules, which adds quite a bit of
overhead to each stg command (about 100 ms on my laptop).

Signed-off-by: Karl Hasselström <kha@treskal.com>
46 files changed:
Documentation/Makefile
Documentation/asciidoc.conf
Documentation/stg.txt
Makefile
stg-build
stgit/commands/.gitignore [new file with mode: 0644]
stgit/commands/__init__.py
stgit/commands/branch.py
stgit/commands/clean.py
stgit/commands/clone.py
stgit/commands/coalesce.py
stgit/commands/commit.py
stgit/commands/delete.py
stgit/commands/diff.py
stgit/commands/edit.py
stgit/commands/export.py
stgit/commands/files.py
stgit/commands/float.py
stgit/commands/fold.py
stgit/commands/goto.py
stgit/commands/hide.py
stgit/commands/id.py
stgit/commands/imprt.py
stgit/commands/init.py
stgit/commands/log.py
stgit/commands/mail.py
stgit/commands/new.py
stgit/commands/patches.py
stgit/commands/pick.py
stgit/commands/pop.py
stgit/commands/pull.py
stgit/commands/push.py
stgit/commands/rebase.py
stgit/commands/refresh.py
stgit/commands/rename.py
stgit/commands/repair.py
stgit/commands/resolved.py
stgit/commands/series.py
stgit/commands/show.py
stgit/commands/sink.py
stgit/commands/status.py
stgit/commands/sync.py
stgit/commands/top.py
stgit/commands/uncommit.py
stgit/commands/unhide.py
stgit/main.py

index 1c14fe38de7e29872c995f8dd3aabdd4db6e85cc..85e9600ce3a2dcfb046a1a8055ab4cc949764a2c 100644 (file)
@@ -60,11 +60,16 @@ doc.dep : $(wildcard *.txt) build-docdep.perl
 -include doc.dep
 
 clean:
-       rm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT)
+       rm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT) stg-cmd-list.txt
 
-$(COMMANDS_TXT): $(shell find .. -name '*.py')
+ALL_PY = $(shell find ../stgit -name '*.py')
+
+$(COMMANDS_TXT): $(ALL_PY)
        ../stg-build --asciidoc $(basename $(subst stg-,,$@)) > $@
 
+stg-cmd-list.txt: $(ALL_PY)
+       ../stg-build --cmd-list > $@
+
 %.html : %.txt
        $(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf $(ASCIIDOC_EXTRA) $<
 
index 69447ab4bf3e91b29e42e55c94246c6cf53eff22..5f7a7af65dd0adb7c7be14f03ea9ca4909f4b3f8 100644 (file)
@@ -84,3 +84,20 @@ ifdef::backend-xhtml11[]
 [stglink-inlinemacro]
 <a href="stg-{target}.html">stg {target}</a>
 endif::backend-xhtml11[]
+
+## stgsublink: macro
+#
+# Usage: stgsublink:command[]
+#
+# Show StGit link as: <command> in man pages, stg <command> in
+# html.
+
+ifdef::backend-docbook[]
+[stgsublink-inlinemacro]
+{target}
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[stgsublink-inlinemacro]
+<a href="stg-{target}.html">{target}</a>
+endif::backend-xhtml11[]
index a0b2176d0c1d3e06d057228d491d92d0ad877522..b4184b213be99ed83ee022deeb24f0038a11c0ac 100644 (file)
@@ -105,141 +105,7 @@ description is available in individual command manpages.  Those
 manpages are named 'stg-<command>(1)'.
 endif::backend-docbook[]
 
-Generic commands
-~~~~~~~~~~~~~~~~
-
-User-support commands not touching the repository.
-
-stg help::
-       stgdesc:help[]
-stg version::
-       stgdesc:version[]
-stg copyright::
-       stgdesc:copyright[]
-
-Repository commands
-~~~~~~~~~~~~~~~~~~~
-
-stglink:clone[]::
-       stgdesc:clone[]
-stglink:id[]::
-       stgdesc:id[]
-
-Stack commands
-~~~~~~~~~~~~~~
-
-Stack management
-^^^^^^^^^^^^^^^^
-
-stglink:branch[]::
-       stgdesc:branch[]
-stglink:init[]::
-       stgdesc:init[]
-stglink:clean[]::
-       stgdesc:clean[]
-stglink:pull[]::
-       stgdesc:pull[]
-stglink:rebase[]::
-       stgdesc:rebase[]
-
-stglink:commit[]::
-       stgdesc:commit[]
-stglink:uncommit[]::
-       stgdesc:uncommit[]
-stglink:repair[]::
-       stgdesc:repair[]
-
-Controlling what patches are applied
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-stglink:series[]::
-       stgdesc:series[]
-stglink:push[]::
-       stgdesc:push[]
-stglink:pop[]::
-       stgdesc:pop[]
-stglink:goto[]::
-       stgdesc:goto[]
-stglink:float[]::
-       stgdesc:float[]
-stglink:sink[]::
-       stgdesc:sink[]
-stglink:applied[]::
-       stgdesc:applied[]
-stglink:unapplied[]::
-       stgdesc:unapplied[]
-stglink:top[]::
-       stgdesc:top[]
-
-stglink:hide[]::
-       stgdesc:hide[]
-stglink:unhide[]::
-       stgdesc:unhide[]
-
-Miscellaneous stack commands
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-stglink:patches[]::
-       stgdesc:patches[]
-
-
-Patch commands
-~~~~~~~~~~~~~~
-
-Patch management
-^^^^^^^^^^^^^^^^
-
-stglink:new[]::
-       stgdesc:new[]
-stglink:delete[]::
-       stgdesc:delete[]
-stglink:rename[]::
-       stgdesc:rename[]
-stglink:log[]::
-       stgdesc:log[]
-
-Controlling patch contents
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-stglink:files[]::
-       stgdesc:files[]
-stglink:show[]::
-       stgdesc:show[]
-stglink:refresh[]::
-       stgdesc:refresh[]
-stglink:fold[]::
-       stgdesc:fold[]
-stglink:pick[]::
-       stgdesc:pick[]
-stglink:sync[]::
-       stgdesc:sync[]
-
-Interaction with the rest of the world
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-stglink:export[]::
-       stgdesc:export[]
-stglink:import[]::
-       stgdesc:import[]
-stglink:mail[]::
-       stgdesc:mail[]
-
-
-Working-copy commands
-~~~~~~~~~~~~~~~~~~~~~
-
-stglink:add[]::
-       stgdesc:add[]
-stglink:rm[]::
-       stgdesc:rm[]
-stglink:cp[]::
-       stgdesc:cp[]
-stglink:status[]::
-       stgdesc:status[]
-stglink:diff[]::
-       stgdesc:diff[]
-stglink:resolved[]::
-       stgdesc:resolved[]
+include::stg-cmd-list.txt[]
 
 CONFIGURATION MECHANISM
 -----------------------
index 9322fe0954abb664cf57a5d494bd98c0b9c89990..288622a320f0b6f24be8a0a3924da5cc7cddd840 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,10 +4,17 @@ PYTHON        ?= python
 
 TEST_PATCHES ?= ..
 
-all:
+all: build
        $(PYTHON) setup.py build
 
-install:
+build: stgit/commands/cmdlist.py
+
+ALL_PY = $(shell find stgit -name '*.py')
+
+stgit/commands/cmdlist.py: $(ALL_PY)
+       $(PYTHON) stg-build --py-cmd-list > $@
+
+install: build
        $(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) --force
 
 doc:
@@ -19,10 +26,10 @@ install-doc:
 install-html:
        $(MAKE) -C Documentation install-html
 
-test:
+test: build
        cd t && $(MAKE) all
 
-test_patches:
+test_patches: build
        for patch in $$(stg series --noprefix $(TEST_PATCHES)); do \
                stg goto $$patch && $(MAKE) test || break; \
        done
@@ -35,8 +42,9 @@ clean:
        rm -f stgit/*.pyc
        rm -f stgit/commands/*.pyc
        rm -f TAGS
+       rm -f stgit/commands/cmdlist.py
 
 tags:
        ctags -e -R stgit/*
 
-.PHONY: all install doc install-doc install-html test test_patches clean
+.PHONY: all build install doc install-doc install-html test test_patches clean
index 8c39a6ffdafc7a6437415a9dee8149dae99fb754..3c9dbfa4aba3a631a0758b72007e21cd7b4e92e2 100755 (executable)
--- a/stg-build
+++ b/stg-build
@@ -2,7 +2,7 @@
 # -*- python -*-
 import optparse, sys
 import stgit.main
-from stgit import argparse
+from stgit import argparse, commands
 
 def main():
     op = optparse.OptionParser()
@@ -10,6 +10,10 @@ def main():
                   help = 'Print asciidoc documentation for a command')
     op.add_option('--commands', action = 'store_true',
                   help = 'Print list of all stg subcommands')
+    op.add_option('--cmd-list', action = 'store_true',
+                  help = 'Print asciidoc command list')
+    op.add_option('--py-cmd-list', action = 'store_true',
+                  help = 'Write Python command list')
     options, args = op.parse_args()
     if args:
         op.error('Wrong number of arguments')
@@ -17,8 +21,15 @@ def main():
         argparse.write_asciidoc(stgit.main.commands[options.asciidoc],
                                 sys.stdout)
     elif options.commands:
-        for cmd in sorted(stgit.main.commands.iterkeys()):
+        for cmd in sorted(commands.get_commands(
+                allow_cached = False).iterkeys()):
             print cmd
+    elif options.cmd_list:
+        commands.asciidoc_command_list(
+            commands.get_commands(allow_cached = False), sys.stdout)
+    elif options.py_cmd_list:
+        commands.py_commands(commands.get_commands(allow_cached = False),
+                             sys.stdout)
     else:
         op.error('No command')
 
diff --git a/stgit/commands/.gitignore b/stgit/commands/.gitignore
new file mode 100644 (file)
index 0000000..eff10ee
--- /dev/null
@@ -0,0 +1 @@
+/cmdlist.py
index 4b03e3a6440883cf8ef6092426b3d932b8b0c73a..54a93263e5c51bbfc7af41bc1c29cfee4879aafc 100644 (file)
@@ -1,5 +1,8 @@
+# -*- coding: utf-8 -*-
+
 __copyright__ = """
 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
+Copyright (C) 2008, Karl Hasselström <kha@treskal.com>
 
 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
@@ -14,3 +17,78 @@ 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 os
+from stgit import utils
+
+def get_command(mod):
+    """Import and return the given command module."""
+    return __import__(__name__ + '.' + mod, globals(), locals(), ['*'])
+
+_kinds = [('repo', 'Repository commands'),
+          ('stack', 'Stack (branch) commands'),
+          ('patch', 'Patch commands'),
+          ('wc', 'Index/worktree commands')]
+_kind_order = [kind for kind, desc in _kinds]
+_kinds = dict(_kinds)
+
+def _find_commands():
+    for p in __path__:
+        for fn in os.listdir(p):
+            if not fn.endswith('.py'):
+                continue
+            mod = utils.strip_suffix('.py', fn)
+            m = get_command(mod)
+            if not hasattr(m, 'usage'):
+                continue
+            yield mod, m
+
+def get_commands(allow_cached = True):
+    """Return a map from command name to a tuple of module name, command
+    type, and one-line command help."""
+    if allow_cached:
+        try:
+            from stgit.commands.cmdlist import command_list
+            return command_list
+        except ImportError:
+            # cmdlist.py doesn't exist, so do it the expensive way.
+            pass
+    return dict((getattr(m, 'name', mod), (mod, _kinds[m.kind], m.help))
+                for mod, m in _find_commands())
+
+def py_commands(commands, f):
+    f.write('command_list = {\n')
+    for key, val in sorted(commands.iteritems()):
+        f.write('    %r: %r,\n' % (key, val))
+    f.write('    }\n')
+
+def _command_list(commands):
+    kinds = {}
+    for cmd, (mod, kind, help) in commands.iteritems():
+        kinds.setdefault(kind, {})[cmd] = help
+    for kind in _kind_order:
+        kind = _kinds[kind]
+        yield kind, sorted(kinds[kind].iteritems())
+
+def pretty_command_list(commands, f):
+    cmd_len = max(len(cmd) for cmd in commands.iterkeys())
+    sep = ''
+    for kind, cmds in _command_list(commands):
+        f.write(sep)
+        sep = '\n'
+        f.write('%s:\n' % kind)
+        for cmd, help in cmds:
+            f.write('  %*s  %s\n' % (-cmd_len, cmd, help))
+
+def _write_underlined(s, u, f):
+    f.write(s + '\n')
+    f.write(u*len(s) + '\n')
+
+def asciidoc_command_list(commands, f):
+    for kind, cmds in _command_list(commands):
+        _write_underlined(kind, '~', f)
+        f.write('\n')
+        for cmd, help in cmds:
+            f.write('stgsublink:%s[]::\n' % cmd)
+            f.write('    %s\n' % help)
+        f.write('\n')
index 33a8afe2aa5ea6edf0b40911b8ff5509d97a3dcb..1b1b98f87954e50bbec47784f8e58ff892ea43b2 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import *
 from stgit import stack, git, basedir
 
 help = 'Branch operations: switch, list, create, rename, delete, ...'
+kind = 'stack'
 usage = ['',
          '<branch>',
          '--list',
index 5334704d40758013341f6cc7e7e8fb3249b6b7b5..27a77168eefad1e1f8d139c0e78f9499261b55d4 100644 (file)
@@ -21,6 +21,7 @@ from stgit.commands import common
 from stgit.lib import transaction
 
 help = 'Delete the empty patches in the series'
+kind = 'stack'
 usage = ['']
 description = """
 Delete the empty patches in the whole series or only those applied or
index b83169e486e24e428ce8150eec10c2bae0117d94..28500c54eea00ccf0363d90bc8cd1e691d01967c 100644 (file)
@@ -21,6 +21,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Make a local clone of a remote repository'
+kind = 'repo'
 usage = ['<repository> <dir>']
 description = """
 Clone a git repository into the local directory <dir> (using
index b390584d2e251e1f15251d1886545074de27d09f..024668a69fb7b817a847463e984e9c70ea97244c 100644 (file)
@@ -24,6 +24,7 @@ from stgit.commands import common
 from stgit.lib import git, transaction
 
 help = 'Coalesce two or more patches into one'
+kind = 'stack'
 usage = ['[options] <patches>']
 description = """
 Coalesce two or more patches, creating one big patch that contains all
index 7d467247266951f08664365a48e87e6aaa898b2b..99b7b5de18ed2370e8a77a1d766e2dcb0fd3b2c2 100644 (file)
@@ -21,6 +21,7 @@ from stgit.lib import transaction
 from stgit.out import *
 
 help = 'Permanently store the applied patches into the stack base'
+kind = 'stack'
 usage = ['',
          '<patchnames>',
          '-n NUM',
index 3ba7fc2de5331e2ea9f49bc9894b86ddc3d5e2b9..b92a039b3f23e0c407973e6e829d3bfde7f76787 100644 (file)
@@ -21,6 +21,7 @@ from stgit.commands import common
 from stgit.lib import transaction
 
 help = 'Delete patches'
+kind = 'patch'
 usage = ['[options] <patch1> [<patch2>] [<patch3>..<patch4>]']
 description = """
 Delete the patches passed as arguments.
index 47e2e7f232e9cc3d12fbd7f781c3612e98a12627..e0078f998d811e95c807970e887d8cf92bc4cf85 100644 (file)
@@ -25,6 +25,7 @@ from stgit.out import *
 from stgit import argparse, stack, git
 
 help = 'Show the tree diff'
+kind = 'wc'
 usage = ['[options] [<files or dirs>]']
 description = """
 Show the diff (default) or diffstat between the current working copy
index 0db325432abd34028417dd77bfa91fb7c824edfb..b6ef6c7c272cc3b3f2bbd31fa9845ad76f114375 100644 (file)
@@ -25,6 +25,7 @@ from stgit.lib import git as gitlib, transaction
 from stgit.out import *
 
 help = 'edit a patch description or diff'
+kind = 'patch'
 usage = ['[options] [<patch>]']
 description = """
 Edit the description and author information of the given patch (or the
index 3d74cc8c178d2fa5ad661f3161c438020efea985..8d05996e54f162f506d4a3ef29edefeb7414dcb2 100644 (file)
@@ -26,6 +26,7 @@ from stgit.out import out
 from stgit.lib import git as gitlib
 
 help = 'Export patches to a directory'
+kind = 'patch'
 usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = """
 Export a range of applied patches to a given directory (defaults to
index 08f882c21346c33b3f70c723281d32ea4bea6e35..318a4a327b16b69cdf483cd07028a90c14224cc5 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit import argparse, stack, git
 
 help = 'Show the files modified by a patch (or the current patch)'
+kind = 'patch'
 usage = ['[options] [[<branch>:]<patch>]']
 description = """
 List the files modified by the given patch (defaulting to the current
index ac8eaea4e076f60cb3ebcd84c808fbc9bd9aa755..1ca4ed38e380086016a05331467b13ae0704d8a8 100644 (file)
@@ -23,6 +23,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Push patches to the top, even if applied'
+kind = 'stack'
 usage = ['<patches>',
          '-s <series>']
 description = """
index 6ddaea96c142ed4ef9c2de98a7bd0ab5d060c73a..0f1486a031b10523766bf77d5dfdc80aece6ef28 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Integrate a GNU diff patch into the current patch'
+kind = 'patch'
 usage = ['[options] [<file>]']
 description = """
 Apply the given GNU diff file (or the standard input) onto the top of
index 33b20edf250bae56269edde8683f44070b7745c5..2bfef0f7b04114d3c3ca303bfefc11012f6ad204 100644 (file)
@@ -19,6 +19,7 @@ from stgit.commands import common
 from stgit.lib import transaction
 
 help = 'Push or pop patches to the given one'
+kind = 'stack'
 usage = ['<patch-name>']
 description = """
 Push/pop patches to/from the stack until the one given on the command
index 488ea18dc61ece892512bb16bca25c39d5f39533..bee2162a74cb01feb1e1a706b2b2b28fe4912715 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Hide a patch in the series'
+kind = 'stack'
 usage = ['[options] <patch-range>']
 description = """
 Hide a range of unapplied patches so that they are no longer shown in
index 18bab9744814685b105a98ccc7db2cb034fb75c0..857ec33051c22dbe2be79e9cb5fce7c2f7586c85 100644 (file)
@@ -20,6 +20,7 @@ from stgit.commands import common
 from stgit.lib import stack
 
 help = 'Print the git hash value of a StGit reference'
+kind = 'repo'
 usage = ['[options] [id]']
 description = """
 Print the SHA1 value of a Git id (defaulting to HEAD). In addition to
index e97b01d9b5fa46d9c85bef6f7a1ebd76f55366c8..150d9eecf511050ce0343504af4444aca3dbcb59 100644 (file)
@@ -26,6 +26,7 @@ from stgit import argparse, stack, git
 
 name = 'import'
 help = 'Import a GNU diff file as a new patch'
+kind = 'patch'
 usage = ['[options] [<file>|<url>]']
 description = """
 Create a new patch and apply the given GNU diff file (or the standard
index f7f7a218f53f9558e3424057d306c8e5bcdb70e0..67d20d1b2c8b20385427758e4d0665a7ee768d2e 100644 (file)
@@ -20,6 +20,7 @@ from stgit.commands import common
 from stgit.lib import stack
 
 help = 'Initialise the current branch for use with StGIT'
+kind = 'stack'
 usage = ['']
 description = """
 Initialise the current git branch to be used as an StGIT stack. The
index b505ed5abe1a7e337b7a5c5914260ee2160a6bba..de210ea9a0d1252d1c48a911c364ae901da505a4 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit.run import Run
 
 help = 'Display the patch changelog'
+kind = 'patch'
 usage = ['[options] [patch]']
 description = """
 List all the current and past commit ids of the given patch. The
index 83acc86f4c771965a8b02ef46afff9d220283a75..caf8f9eb971d08689b076ca0128743729ab0071f 100644 (file)
@@ -26,6 +26,7 @@ from stgit.config import config
 from stgit.run import Run
 
 help = 'Send a patch or series of patches by e-mail'
+kind = 'patch'
 usage = [' [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = r"""
 Send a patch or a range of patches by e-mail using the SMTP server
index 4ed2079258968df787de9ba076b3e704e61fefaa..f36fbd6148bb41d0d02021506cd4d9327eac5fd0 100644 (file)
@@ -22,6 +22,7 @@ from stgit.lib import git as gitlib, transaction
 from stgit.config import config
 
 help = 'Create a new, empty patch'
+kind = 'patch'
 usage = ['[options] [<name>]']
 description = """
 Create a new, empty patch on the current stack. The new patch is
index 656a4a1450ec2db1c4b8fc0a803cacc35dc3a3d1..0cbc275c6e98ed677cd57b35ff68758a90a19cae 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Show the applied patches modifying a file'
+kind = 'stack'
 usage = ['[options] [<files or dirs>]']
 description = """
 Show the applied patches modifying the given files. Without arguments,
index 72b2359af5765ed0d44fcef8a23e1706dccfd792..8a882623ad5bd47fc50ddfca2052d901dae869f3 100644 (file)
@@ -24,6 +24,7 @@ from stgit import stack, git
 from stgit.stack import Series
 
 help = 'Import a patch from a different branch or a commit object'
+kind = 'patch'
 usage = ['[options] ([<patch1>] [<patch2>] [<patch3>..<patch4>])|<commit>']
 description = """
 Import one or more patches from a different branch or a commit object
index b3c4008f76fb7d85b9089b65a3a4200d520adb7e..cf898465c57cdf6ae2cfe38edc13790a106b69e0 100644 (file)
@@ -23,6 +23,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Pop one or more patches from the stack'
+kind = 'stack'
 usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = """
 Pop the topmost patch or a range of patches from the stack. The
index 3801bf21dcf03d3de99843173ac854db96b79218..c989b5d087c979a37d0f2b1e301b11b915a3727b 100644 (file)
@@ -24,6 +24,7 @@ from stgit.config import GitConfigException
 from stgit import stack, git
 
 help = 'Pull changes from a remote repository'
+kind = 'stack'
 usage = ['[options] [<repository>]']
 description = """
 Pull the latest changes from the given remote repository (defaulting
index ee7b56e94951e2d81200c22c299a562a77ffbe5f..c6056ccafdda24c12e7abe4a4a4457ff5052e551 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Push one or more patches onto the stack'
+kind = 'stack'
 usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = """
 Push one or more patches (defaulting to the first unapplied one) onto
index ffec329b763e9234592b44d9e2772363a681f208..b09204ec2a3565ddca754d364fbbb4af02d5558c 100644 (file)
@@ -22,6 +22,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Move the stack base to another point in history'
+kind = 'stack'
 usage = ['[options] <new-base-id>']
 description = """
 Pop all patches from current stack, move the stack base to the given
index e30085bd55335832d4f14ecdd5cf6bf58b3da993..a20fcc5c4f6b020fe0bd400487dc8fbaa3054f45 100644 (file)
@@ -25,6 +25,7 @@ from stgit import stack, git
 from stgit.config import config
 
 help = 'Generate a new commit for the current patch'
+kind = 'patch'
 usage = ['[options] [<files or dirs>]']
 description = """
 Include the latest tree changes in the current patch. This command
index b978ecfa206daa800f3ba8d17f3a86c93fa8a4b8..fdb31ee55981105add3c541b58191e91405b9d75 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Rename a patch'
+kind = 'patch'
 usage = ['[options] [oldpatch] <newpatch>']
 description = """
 Rename <oldpatch> into <newpatch> in a series. If <oldpatch> is not
index a5156cd385c059ba6e67309c87fcc76c6aa14220..6218caaf443c55e19d713b5d06b0f62eb8da16e3 100644 (file)
@@ -26,6 +26,7 @@ from stgit.run import *
 from stgit import stack, git
 
 help = 'Fix StGit metadata if branch was modified with git commands'
+kind = 'stack'
 usage = ['']
 description = """
 If you modify an StGit stack (branch) with some git commands -- such
index 5643da84baf8aa3b0f0e94d3b51610e14b451ece..d8dacd6684edd98dea9984aae66849d3b6ef7551 100644 (file)
@@ -25,6 +25,7 @@ from stgit.config import config, file_extensions
 from stgit.gitmergeonefile import interactive_merge
 
 help = 'Mark a file conflict as solved'
+kind = 'wc'
 usage = ['[options] [<files...>]']
 description = """
 Mark a merge conflict as resolved. The conflicts can be seen with the
index da3106155f7f56c50b365d5ad768682c0ebcc30e..e9d148ae2b64908e37ac2132455db21c43eec9ce 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import out
 from stgit.config import config
 
 help = 'Print the patch series'
+kind = 'stack'
 usage = ['[options] [<patch-range>]']
 description = """
 Show all the patches in the series or just those in the given
index c12793fa1beecb821a5f314e24c4a5590abf2c5a..41cb31e2ef7fce370dc825199691f9ab261610a1 100644 (file)
@@ -22,6 +22,7 @@ from stgit.commands.common import *
 from stgit import argparse, git
 
 help = 'Show the commit corresponding to a patch'
+kind = 'patch'
 usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = """
 Show the commit log and the diff corresponding to the given patches.
index bf13f2b46a3b4e7f110d6d94906c4d9eab5b4e62..95a43e16a7c8681eeebfd258edbc3e1fee30a697 100644 (file)
@@ -23,6 +23,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Send patches deeper down the stack'
+kind = 'stack'
 usage = ['[-t <target patch>] [-n] [<patches>]']
 description = """
 This is the opposite operation of stglink:float[]: move the specified
index eadb507a6f3d907ee69cf77d89fb38f64d413d4b..7c68ba6380e9d542a8546e08c8b92fb77dc8c18b 100644 (file)
@@ -23,6 +23,7 @@ from stgit.utils import *
 from stgit import stack, git
 
 help = 'Show the tree status'
+kind = 'wc'
 usage = ['[options] [<files or dirs>]']
 description = """
 Show the status of the whole working copy or the given files. The
index ef944390cf4aa452fe948bbe557e2e0673867f81..767b4d27cf5d5f07d9c52f6734dcd8f7ee0b8f26 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Synchronise patches with a branch or a series'
+kind = 'patch'
 usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = """
 For each of the specified patches perform a three-way merge with the
index f4962e711b2637dd5c0e7273db4bef87ab2e21b1..523afa463255a2b777a411aa98021099f9a4b54d 100644 (file)
@@ -21,6 +21,7 @@ from stgit.commands import common
 from stgit.out import out
 
 help = 'Print the name of the top patch'
+kind = 'stack'
 usage = ['']
 description = """
 Print the name of the current (topmost) patch."""
index 19ec3c9e72cb5b41c11a1685159dc1158629d1b1..c44385da9bdb3b8c618900122140f0be49383ed8 100644 (file)
@@ -24,6 +24,7 @@ from stgit.out import *
 from stgit import utils
 
 help = 'Turn regular git commits into StGit patches'
+kind = 'stack'
 usage = ['<patch-name-1> [<patch-name-2> ...]',
          '-n NUM [<prefix>]',
          '-t <committish> [-x]']
index 6c624d0e163103ca56d23f36ca85b6fa73bb4dca..c34bc1d5d0fa013dd7c261f8c68edc946198f948 100644 (file)
@@ -23,6 +23,7 @@ from stgit.out import *
 from stgit import stack, git
 
 help = 'Unhide a hidden patch'
+kind = 'stack'
 usage = ['[options] <patch-range>']
 description = """
 Unhide a hidden range of patches so that they are shown in the plain
index 55c467c5c4cd23268ed422f484474319358e9110..48d8dbb608d06e70a4d0a4aa341d75e7173ebc8a 100644 (file)
@@ -48,107 +48,13 @@ class Commands(dict):
         return candidates[0]
         
     def __getitem__(self, key):
-        """Return the command python module name based.
-        """
-        global prog
-
         cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))
-            
-        __import__('stgit.commands.' + cmd_mod)
-        return getattr(stgit.commands, cmd_mod)
-
-commands = Commands({
-    'branch':           'branch',
-    'delete':           'delete',
-    'diff':             'diff',
-    'clean':            'clean',
-    'clone':            'clone',
-    'coalesce':         'coalesce',
-    'commit':           'commit',
-    'edit':             'edit',
-    'export':           'export',
-    'files':            'files',
-    'float':            'float',
-    'fold':             'fold',
-    'goto':             'goto',
-    'hide':             'hide',
-    'id':               'id',
-    'import':           'imprt',
-    'init':             'init',
-    'log':              'log',
-    'mail':             'mail',
-    'new':              'new',
-    'patches':          'patches',
-    'pick':             'pick',
-    'pop':              'pop',
-    'pull':             'pull',
-    'push':             'push',
-    'rebase':           'rebase',
-    'refresh':          'refresh',
-    'rename':           'rename',
-    'repair':           'repair',
-    'resolved':         'resolved',
-    'series':           'series',
-    'show':             'show',
-    'sink':             'sink',
-    'status':           'status',
-    'sync':             'sync',
-    'top':              'top',
-    'uncommit':         'uncommit',
-    'unhide':           'unhide'
-    })
+        return stgit.commands.get_command(cmd_mod)
 
-# classification: repository, stack, patch, working copy
-repocommands = (
-    'clone',
-    'id',
-    )
-stackcommands = (
-    'branch',
-    'clean',
-    'coalesce',
-    'commit',
-    'float',
-    'goto',
-    'hide',
-    'init',
-    'patches',
-    'pop',
-    'pull',
-    'push',
-    'rebase',
-    'repair',
-    'series',
-    'sink',
-    'top',
-    'uncommit',
-    'unhide',
-    )
-patchcommands = (
-    'delete',
-    'edit',
-    'export',
-    'files',
-    'fold',
-    'import',
-    'log',
-    'mail',
-    'new',
-    'pick',
-    'refresh',
-    'rename',
-    'show',
-    'sync',
-    )
-wccommands = (
-    'diff',
-    'resolved',
-    'status',
-    )
+cmd_list = stgit.commands.get_commands()
+commands = Commands((cmd, mod) for cmd, (mod, kind, help)
+                    in cmd_list.iteritems())
 
-def _print_helpstring(cmd):
-    print '  ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help
-    
 def print_help():
     print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])
     print
@@ -156,33 +62,8 @@ def print_help():
     print '  help        print the detailed command usage'
     print '  version     display version information'
     print '  copyright   display copyright information'
-    # unclassified commands if any
-    cmds = commands.keys()
-    cmds.sort()
-    for cmd in cmds:
-        if not cmd in repocommands and not cmd in stackcommands \
-               and not cmd in patchcommands and not cmd in wccommands:
-            _print_helpstring(cmd)
-    print
-
-    print 'Repository commands:'
-    for cmd in repocommands:
-        _print_helpstring(cmd)
     print
-    
-    print 'Stack commands:'
-    for cmd in stackcommands:
-        _print_helpstring(cmd)
-    print
-
-    print 'Patch commands:'
-    for cmd in patchcommands:
-        _print_helpstring(cmd)
-    print
-
-    print 'Working-copy commands:'
-    for cmd in wccommands:
-        _print_helpstring(cmd)
+    stgit.commands.pretty_command_list(cmd_list, sys.stdout)
 
 #
 # The main function (command dispatcher)