{"thread":{"id":"15436","subject":"[StGit PATCH 0/3] Auto-generate man pages and command list","startedAt":"2008-09-08T21:07:52Z","lastAt":"2008-09-11T06:58:32Z","messageCount":7,"participants":["Karl Hasselström","Daniel White","Catalin Marinas"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"90133","messageId":"20080908210302.1957.44280.stgit@yoghurt","threadId":"15436","inReplyTo":null,"subject":"[StGit PATCH 0/3] Auto-generate man pages and command list","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-09-08T21:07:52Z","receivedAt":"2008-09-08T21:07:52Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"The first patch auto-generates man pages for all StGit commands. We\nstill have to write the actual text by hand (bummer!), but we get all\nthe flags for free. Now we just have to take all those man pages and\nmake them good ...\n\nThe third patch gets rid of the manual list of all commands in main.py\nand stg.txt, and instead generates it automatically. (There's still\none list in the bash completion script; it is my next target.)\n\n---\n\nKarl Hasselström (3):\n      Generate command lists automatically\n      asciidoc.conf: Steal updates from git\n      Auto-generate man pages for all StGit commands\n\n\n Documentation/.gitignore           |    4 -\n Documentation/COMMAND-TEMPLATE.txt |   42 ---------\n Documentation/Makefile             |   15 +++\n Documentation/asciidoc.conf        |  100 +++++++++++++++-----\n Documentation/stg-branch.txt       |  114 -----------------------\n Documentation/stg-clone.txt        |   32 -------\n Documentation/stg-init.txt         |   29 ------\n Documentation/stg-new.txt          |  115 ------------------------\n Documentation/stg-sink.txt         |   49 ----------\n Documentation/stg.txt              |  138 ----------------------------\n Makefile                           |   18 +++-\n stg-build                          |   37 ++++++++\n stgit/argparse.py                  |  176 ++++++++++++++++++++++++++++--------\n stgit/commands/.gitignore          |    1 \n stgit/commands/__init__.py         |   78 ++++++++++++++++\n stgit/commands/branch.py           |  123 ++++++++++++++++---------\n stgit/commands/clean.py            |   22 ++---\n stgit/commands/clone.py            |   20 +++-\n stgit/commands/coalesce.py         |   14 ++-\n stgit/commands/commit.py           |   22 +++--\n stgit/commands/delete.py           |   16 ++-\n stgit/commands/diff.py             |   27 +++---\n stgit/commands/edit.py             |   24 ++---\n stgit/commands/export.py           |   48 +++++-----\n stgit/commands/files.py            |   24 ++---\n stgit/commands/float.py            |   18 ++--\n stgit/commands/fold.py             |   23 ++---\n stgit/commands/goto.py             |   11 +-\n stgit/commands/hide.py             |   17 ++-\n stgit/commands/id.py               |   12 +-\n stgit/commands/imprt.py            |   93 +++++++++----------\n stgit/commands/init.py             |   14 ++-\n stgit/commands/log.py              |   34 +++----\n stgit/commands/mail.py             |  116 +++++++++++-------------\n stgit/commands/new.py              |   34 ++++---\n stgit/commands/patches.py          |   22 ++---\n stgit/commands/pick.py             |   50 +++++-----\n stgit/commands/pop.py              |   28 +++---\n stgit/commands/pull.py             |   23 ++---\n stgit/commands/push.py             |   38 +++-----\n stgit/commands/rebase.py           |   23 ++---\n stgit/commands/refresh.py          |   45 ++++-----\n stgit/commands/rename.py           |   20 ++--\n stgit/commands/repair.py           |   11 +-\n stgit/commands/resolved.py         |   27 +++---\n stgit/commands/series.py           |   78 +++++++---------\n stgit/commands/show.py             |   31 +++---\n stgit/commands/sink.py             |   44 ++++++---\n stgit/commands/status.py           |   53 +++++------\n stgit/commands/sync.py             |   31 +++---\n stgit/commands/top.py              |   16 ++-\n stgit/commands/uncommit.py         |   25 +++--\n stgit/commands/unhide.py           |   19 ++--\n stgit/main.py                      |  138 ++--------------------------\n 54 files changed, 1024 insertions(+), 1358 deletions(-)\n delete mode 100644 Documentation/COMMAND-TEMPLATE.txt\n delete mode 100644 Documentation/stg-branch.txt\n delete mode 100644 Documentation/stg-clone.txt\n delete mode 100644 Documentation/stg-init.txt\n delete mode 100644 Documentation/stg-new.txt\n delete mode 100644 Documentation/stg-sink.txt\n create mode 100755 stg-build\n create mode 100644 stgit/commands/.gitignore\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"90134","messageId":"20080908210805.1957.79447.stgit@yoghurt","threadId":"15436","inReplyTo":"20080908210302.1957.44280.stgit@yoghurt","subject":"[StGit PATCH 2/3] asciidoc.conf: Steal updates from git","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-09-08T21:08:05Z","receivedAt":"2008-09-08T21:08:05Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Steal updates to asciidoc.conf from git. Also, make sure that we use\nthe link:[] abd stglink:[] macros correctly everywhere.\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n Documentation/asciidoc.conf |   79 +++++++++++++++++++++++++++++++------------\n Documentation/stg.txt       |    2 +\n stgit/argparse.py           |    2 +\n stgit/commands/clone.py     |    4 +-\n 4 files changed, 61 insertions(+), 26 deletions(-)\n\n\ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 4c83756..69447ab 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -1,51 +1,86 @@\n-## gitlink: macro\n-#\n-# Usage: gitlink:command[manpage-section]\n-#\n-# Note, {0} is the manpage section, while {target} is the command.\n-#\n-# Show GIT link as: <command>(<section>); if section is defined, else just show\n-# the command.\n-\n [attributes]\n-caret=^\n+asterisk=&#42;\n+plus=&#43;\n+caret=&#94;\n startsb=&#91;\n endsb=&#93;\n tilde=&#126;\n \n ifdef::backend-docbook[]\n-[gitlink-inlinemacro]\n-{0%{target}}\n-{0#<citerefentry>}\n-{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n-{0#</citerefentry>}\n-endif::backend-docbook[]\n-\n-ifdef::backend-docbook[]\n+ifndef::docbook-xsl-172[]\n # \"unbreak\" docbook-xsl v1.68 for manpages. v1.69 works with or without this.\n+# v1.72 breaks with this because it replaces dots not in roff requests.\n [listingblock]\n <example><title>{title}</title>\n <literallayout>\n+ifdef::doctype-manpage[]\n+&#10;.ft C&#10;\n+endif::doctype-manpage[]\n |\n+ifdef::doctype-manpage[]\n+&#10;.ft&#10;\n+endif::doctype-manpage[]\n </literallayout>\n {title#}</example>\n+endif::docbook-xsl-172[]\n+endif::backend-docbook[]\n+\n+ifdef::doctype-manpage[]\n+ifdef::backend-docbook[]\n+[header]\n+template::[header-declarations]\n+<refentry>\n+<refmeta>\n+<refentrytitle>{mantitle}</refentrytitle>\n+<manvolnum>{manvolnum}</manvolnum>\n+<refmiscinfo class=\"source\">StGit</refmiscinfo>\n+<refmiscinfo class=\"version\">{stgit_version}</refmiscinfo>\n+<refmiscinfo class=\"manual\">StGit Manual</refmiscinfo>\n+</refmeta>\n+<refnamediv>\n+  <refname>{manname}</refname>\n+  <refpurpose>{manpurpose}</refpurpose>\n+</refnamediv>\n+endif::backend-docbook[]\n+endif::doctype-manpage[]\n+\n+## link: macro\n+#\n+# Usage: link:command[manpage-section]\n+#\n+# Note, {0} is the manpage section, while {target} is the command.\n+#\n+# Show link as: <command>(<section>); if section is defined, else just\n+# show the command.\n+\n+ifdef::backend-docbook[]\n+[link-inlinemacro]\n+{0%{target}}\n+{0#<citerefentry>}\n+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}\n+{0#</citerefentry>}\n endif::backend-docbook[]\n \n ifdef::backend-xhtml11[]\n-[gitlink-inlinemacro]\n+[link-inlinemacro]\n <a href=\"{target}.html\">{target}{0?({0})}</a>\n endif::backend-xhtml11[]\n \n-# stglink\n+## stglink: macro\n+#\n+# Usage: stglink:command[]\n+#\n+# Show StGit link as: stg-<command>(1) in man pages, stg <command> in\n+# html.\n \n ifdef::backend-docbook[]\n [stglink-inlinemacro]\n <citerefentry>\n-<refentrytitle>stg {target}</refentrytitle><manvolnum>1</manvolnum>\n+  <refentrytitle>stg-{target}</refentrytitle><manvolnum>1</manvolnum>\n </citerefentry>\n endif::backend-docbook[]\n \n ifdef::backend-xhtml11[]\n [stglink-inlinemacro]\n-<a href=\"stg-{target}.html\">stg {target}(1)</a>\n+<a href=\"stg-{target}.html\">stg {target}</a>\n endif::backend-xhtml11[]\ndiff --git a/Documentation/stg.txt b/Documentation/stg.txt\nindex f6cd815..a0b2176 100644\n--- a/Documentation/stg.txt\n+++ b/Documentation/stg.txt\n@@ -245,7 +245,7 @@ CONFIGURATION MECHANISM\n -----------------------\n \n Starting with 0.12, StGIT uses the same configuration mechanism as\n-GIT.  See gitlink:git[7] for more details.\n+GIT.  See link:git[7] for more details.\n \n TEMPLATES\n ---------\ndiff --git a/stgit/argparse.py b/stgit/argparse.py\nindex 4cd9527..d0134f8 100644\n--- a/stgit/argparse.py\n+++ b/stgit/argparse.py\n@@ -94,7 +94,7 @@ def write_asciidoc(cmd, f):\n             o.write_asciidoc(f)\n             f.write('\\n')\n     _write_underlined('StGit', '-', f)\n-    f.write('Part of the StGit suite - see stglink:stg[1]\\n')\n+    f.write('Part of the StGit suite - see link:stg[1]\\n')\n \n def sign_options():\n     def callback(option, opt_str, value, parser, sign_str):\ndiff --git a/stgit/commands/clone.py b/stgit/commands/clone.py\nindex d2c68bb..b83169e 100644\n--- a/stgit/commands/clone.py\n+++ b/stgit/commands/clone.py\n@@ -24,10 +24,10 @@ help = 'Make a local clone of a remote repository'\n usage = ['<repository> <dir>']\n description = \"\"\"\n Clone a git repository into the local directory <dir> (using\n-gitlink:clone[]) and initialise the local branch \"master\".\n+stglink:clone[]) and initialise the local branch \"master\".\n \n This operation is for example suitable to start working using the\n-\"tracking branch\" workflow (see gitlink:stg[1]). Other means to setup\n+\"tracking branch\" workflow (see link:stg[1]). Other means to setup\n an StGit stack are stglink:init[] and the '--create' and '--clone'\n commands of stglink:branch[].\n \n"},{"id":"90135","messageId":"20080908210811.1957.16419.stgit@yoghurt","threadId":"15436","inReplyTo":"20080908210302.1957.44280.stgit@yoghurt","subject":"[StGit PATCH 3/3] Generate command lists automatically","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-09-08T21:08:11Z","receivedAt":"2008-09-08T21:08:11Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"Instead of hard-coding the list of stg subcommands everywhere,\ngenerate them automatically. That way, they never get outdated (like\nthe list in stg.txt).\n\nIn order to not make StGit slower, we cache the list of commands; run\n\"make build\" to update that cache (other make targets, such as \"all\"\nand \"test\", imply \"build\"). If the cache doesn't exist, the code falls\nback to importing all the command modules, which adds quite a bit of\noverhead to each stg command (about 100 ms on my laptop).\n\nSigned-off-by: Karl Hasselström <kha@treskal.com>\n\n---\n\n Documentation/Makefile      |    9 ++-\n Documentation/asciidoc.conf |   17 +++++\n Documentation/stg.txt       |  136 -------------------------------------------\n Makefile                    |   18 ++++--\n stg-build                   |   15 ++++-\n stgit/commands/.gitignore   |    1 \n stgit/commands/__init__.py  |   78 +++++++++++++++++++++++++\n stgit/commands/branch.py    |    1 \n stgit/commands/clean.py     |    1 \n stgit/commands/clone.py     |    1 \n stgit/commands/coalesce.py  |    1 \n stgit/commands/commit.py    |    1 \n stgit/commands/delete.py    |    1 \n stgit/commands/diff.py      |    1 \n stgit/commands/edit.py      |    1 \n stgit/commands/export.py    |    1 \n stgit/commands/files.py     |    1 \n stgit/commands/float.py     |    1 \n stgit/commands/fold.py      |    1 \n stgit/commands/goto.py      |    1 \n stgit/commands/hide.py      |    1 \n stgit/commands/id.py        |    1 \n stgit/commands/imprt.py     |    1 \n stgit/commands/init.py      |    1 \n stgit/commands/log.py       |    1 \n stgit/commands/mail.py      |    1 \n stgit/commands/new.py       |    1 \n stgit/commands/patches.py   |    1 \n stgit/commands/pick.py      |    1 \n stgit/commands/pop.py       |    1 \n stgit/commands/pull.py      |    1 \n stgit/commands/push.py      |    1 \n stgit/commands/rebase.py    |    1 \n stgit/commands/refresh.py   |    1 \n stgit/commands/rename.py    |    1 \n stgit/commands/repair.py    |    1 \n stgit/commands/resolved.py  |    1 \n stgit/commands/series.py    |    1 \n stgit/commands/show.py      |    1 \n stgit/commands/sink.py      |    1 \n stgit/commands/status.py    |    1 \n stgit/commands/sync.py      |    1 \n stgit/commands/top.py       |    1 \n stgit/commands/uncommit.py  |    1 \n stgit/commands/unhide.py    |    1 \n stgit/main.py               |  129 ++---------------------------------------\n 46 files changed, 173 insertions(+), 268 deletions(-)\n create mode 100644 stgit/commands/.gitignore\n\n\ndiff --git a/Documentation/Makefile b/Documentation/Makefile\nindex 1c14fe3..85e9600 100644\n--- a/Documentation/Makefile\n+++ b/Documentation/Makefile\n@@ -60,11 +60,16 @@ doc.dep : $(wildcard *.txt) build-docdep.perl\n -include doc.dep\n \n clean:\n-\trm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT)\n+\trm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT) stg-cmd-list.txt\n \n-$(COMMANDS_TXT): $(shell find .. -name '*.py')\n+ALL_PY = $(shell find ../stgit -name '*.py')\n+\n+$(COMMANDS_TXT): $(ALL_PY)\n \t../stg-build --asciidoc $(basename $(subst stg-,,$@)) > $@\n \n+stg-cmd-list.txt: $(ALL_PY)\n+\t../stg-build --cmd-list > $@\n+\n %.html : %.txt\n \t$(ASCIIDOC) -b xhtml11 -d manpage -f asciidoc.conf $(ASCIIDOC_EXTRA) $<\n \ndiff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf\nindex 69447ab..5f7a7af 100644\n--- a/Documentation/asciidoc.conf\n+++ b/Documentation/asciidoc.conf\n@@ -84,3 +84,20 @@ ifdef::backend-xhtml11[]\n [stglink-inlinemacro]\n <a href=\"stg-{target}.html\">stg {target}</a>\n endif::backend-xhtml11[]\n+\n+## stgsublink: macro\n+#\n+# Usage: stgsublink:command[]\n+#\n+# Show StGit link as: <command> in man pages, stg <command> in\n+# html.\n+\n+ifdef::backend-docbook[]\n+[stgsublink-inlinemacro]\n+{target}\n+endif::backend-docbook[]\n+\n+ifdef::backend-xhtml11[]\n+[stgsublink-inlinemacro]\n+<a href=\"stg-{target}.html\">{target}</a>\n+endif::backend-xhtml11[]\ndiff --git a/Documentation/stg.txt b/Documentation/stg.txt\nindex a0b2176..b4184b2 100644\n--- a/Documentation/stg.txt\n+++ b/Documentation/stg.txt\n@@ -105,141 +105,7 @@ description is available in individual command manpages.  Those\n manpages are named 'stg-<command>(1)'.\n endif::backend-docbook[]\n \n-Generic commands\n-~~~~~~~~~~~~~~~~\n-\n-User-support commands not touching the repository.\n-\n-stg help::\n-\tstgdesc:help[]\n-stg version::\n-\tstgdesc:version[]\n-stg copyright::\n-\tstgdesc:copyright[]\n-\n-Repository commands\n-~~~~~~~~~~~~~~~~~~~\n-\n-stglink:clone[]::\n-\tstgdesc:clone[]\n-stglink:id[]::\n-\tstgdesc:id[]\n-\n-Stack commands\n-~~~~~~~~~~~~~~\n-\n-Stack management\n-^^^^^^^^^^^^^^^^\n-\n-stglink:branch[]::\n-\tstgdesc:branch[]\n-stglink:init[]::\n-\tstgdesc:init[]\n-stglink:clean[]::\n-\tstgdesc:clean[]\n-stglink:pull[]::\n-\tstgdesc:pull[]\n-stglink:rebase[]::\n-\tstgdesc:rebase[]\n-\n-stglink:commit[]::\n-\tstgdesc:commit[]\n-stglink:uncommit[]::\n-\tstgdesc:uncommit[]\n-stglink:repair[]::\n-\tstgdesc:repair[]\n-\n-Controlling what patches are applied\n-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n-\n-stglink:series[]::\n-\tstgdesc:series[]\n-stglink:push[]::\n-\tstgdesc:push[]\n-stglink:pop[]::\n-\tstgdesc:pop[]\n-stglink:goto[]::\n-\tstgdesc:goto[]\n-stglink:float[]::\n-\tstgdesc:float[]\n-stglink:sink[]::\n-\tstgdesc:sink[]\n-stglink:applied[]::\n-\tstgdesc:applied[]\n-stglink:unapplied[]::\n-\tstgdesc:unapplied[]\n-stglink:top[]::\n-\tstgdesc:top[]\n-\n-stglink:hide[]::\n-\tstgdesc:hide[]\n-stglink:unhide[]::\n-\tstgdesc:unhide[]\n-\n-Miscellaneous stack commands\n-^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n-\n-stglink:patches[]::\n-\tstgdesc:patches[]\n-\n-\n-Patch commands\n-~~~~~~~~~~~~~~\n-\n-Patch management\n-^^^^^^^^^^^^^^^^\n-\n-stglink:new[]::\n-\tstgdesc:new[]\n-stglink:delete[]::\n-\tstgdesc:delete[]\n-stglink:rename[]::\n-\tstgdesc:rename[]\n-stglink:log[]::\n-\tstgdesc:log[]\n-\n-Controlling patch contents\n-^^^^^^^^^^^^^^^^^^^^^^^^^^\n-\n-stglink:files[]::\n-\tstgdesc:files[]\n-stglink:show[]::\n-\tstgdesc:show[]\n-stglink:refresh[]::\n-\tstgdesc:refresh[]\n-stglink:fold[]::\n-\tstgdesc:fold[]\n-stglink:pick[]::\n-\tstgdesc:pick[]\n-stglink:sync[]::\n-\tstgdesc:sync[]\n-\n-Interaction with the rest of the world\n-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n-\n-stglink:export[]::\n-\tstgdesc:export[]\n-stglink:import[]::\n-\tstgdesc:import[]\n-stglink:mail[]::\n-\tstgdesc:mail[]\n-\n-\n-Working-copy commands\n-~~~~~~~~~~~~~~~~~~~~~\n-\n-stglink:add[]::\n-\tstgdesc:add[]\n-stglink:rm[]::\n-\tstgdesc:rm[]\n-stglink:cp[]::\n-\tstgdesc:cp[]\n-stglink:status[]::\n-\tstgdesc:status[]\n-stglink:diff[]::\n-\tstgdesc:diff[]\n-stglink:resolved[]::\n-\tstgdesc:resolved[]\n+include::stg-cmd-list.txt[]\n \n CONFIGURATION MECHANISM\n -----------------------\ndiff --git a/Makefile b/Makefile\nindex 9322fe0..288622a 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -4,10 +4,17 @@ PYTHON\t?= python\n \n TEST_PATCHES ?= ..\n \n-all:\n+all: build\n \t$(PYTHON) setup.py build\n \n-install:\n+build: stgit/commands/cmdlist.py\n+\n+ALL_PY = $(shell find stgit -name '*.py')\n+\n+stgit/commands/cmdlist.py: $(ALL_PY)\n+\t$(PYTHON) stg-build --py-cmd-list > $@\n+\n+install: build\n \t$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) --force\n \n doc:\n@@ -19,10 +26,10 @@ install-doc:\n install-html:\n \t$(MAKE) -C Documentation install-html\n \n-test:\n+test: build\n \tcd t && $(MAKE) all\n \n-test_patches:\n+test_patches: build\n \tfor patch in $$(stg series --noprefix $(TEST_PATCHES)); do \\\n \t\tstg goto $$patch && $(MAKE) test || break; \\\n \tdone\n@@ -35,8 +42,9 @@ clean:\n \trm -f stgit/*.pyc\n \trm -f stgit/commands/*.pyc\n \trm -f TAGS\n+\trm -f stgit/commands/cmdlist.py\n \n tags:\n \tctags -e -R stgit/*\n \n-.PHONY: all install doc install-doc install-html test test_patches clean\n+.PHONY: all build install doc install-doc install-html test test_patches clean\ndiff --git a/stg-build b/stg-build\nindex 8c39a6f..3c9dbfa 100755\n--- a/stg-build\n+++ b/stg-build\n@@ -2,7 +2,7 @@\n # -*- python -*-\n import optparse, sys\n import stgit.main\n-from stgit import argparse\n+from stgit import argparse, commands\n \n def main():\n     op = optparse.OptionParser()\n@@ -10,6 +10,10 @@ def main():\n                   help = 'Print asciidoc documentation for a command')\n     op.add_option('--commands', action = 'store_true',\n                   help = 'Print list of all stg subcommands')\n+    op.add_option('--cmd-list', action = 'store_true',\n+                  help = 'Print asciidoc command list')\n+    op.add_option('--py-cmd-list', action = 'store_true',\n+                  help = 'Write Python command list')\n     options, args = op.parse_args()\n     if args:\n         op.error('Wrong number of arguments')\n@@ -17,8 +21,15 @@ def main():\n         argparse.write_asciidoc(stgit.main.commands[options.asciidoc],\n                                 sys.stdout)\n     elif options.commands:\n-        for cmd in sorted(stgit.main.commands.iterkeys()):\n+        for cmd in sorted(commands.get_commands(\n+                allow_cached = False).iterkeys()):\n             print cmd\n+    elif options.cmd_list:\n+        commands.asciidoc_command_list(\n+            commands.get_commands(allow_cached = False), sys.stdout)\n+    elif options.py_cmd_list:\n+        commands.py_commands(commands.get_commands(allow_cached = False),\n+                             sys.stdout)\n     else:\n         op.error('No command')\n \ndiff --git a/stgit/commands/.gitignore b/stgit/commands/.gitignore\nnew file mode 100644\nindex 0000000..eff10ee\n--- /dev/null\n+++ b/stgit/commands/.gitignore\n@@ -0,0 +1 @@\n+/cmdlist.py\ndiff --git a/stgit/commands/__init__.py b/stgit/commands/__init__.py\nindex 4b03e3a..b8e1ba5 100644\n--- a/stgit/commands/__init__.py\n+++ b/stgit/commands/__init__.py\n@@ -1,5 +1,8 @@\n+# -*- coding: utf-8 -*-\n+\n __copyright__ = \"\"\"\n Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>\n+Copyright (C) 2008, Karl Hasselström <kha@treskal.com>\n \n This program is free software; you can redistribute it and/or modify\n it under the terms of the GNU General Public License version 2 as\n@@ -14,3 +17,78 @@ You should have received a copy of the GNU General Public License\n along with this program; if not, write to the Free Software\n Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n \"\"\"\n+\n+import os\n+from stgit import utils\n+\n+def get_command(mod):\n+    \"\"\"Import and return the given command module.\"\"\"\n+    return __import__(__name__ + '.' + mod, fromlist = ['*'])\n+\n+_kinds = [('repo', 'Repository commands'),\n+          ('stack', 'Stack (branch) commands'),\n+          ('patch', 'Patch commands'),\n+          ('wc', 'Index/worktree commands')]\n+_kind_order = [kind for kind, desc in _kinds]\n+_kinds = dict(_kinds)\n+\n+def _find_commands():\n+    for p in __path__:\n+        for fn in os.listdir(p):\n+            if not fn.endswith('.py'):\n+                continue\n+            mod = utils.strip_suffix('.py', fn)\n+            m = get_command(mod)\n+            if not hasattr(m, 'usage'):\n+                continue\n+            yield mod, m\n+\n+def get_commands(allow_cached = True):\n+    \"\"\"Return a map from command name to a tuple of module name, command\n+    type, and one-line command help.\"\"\"\n+    if allow_cached:\n+        try:\n+            from stgit.commands.cmdlist import command_list\n+            return command_list\n+        except ImportError:\n+            # cmdlist.py doesn't exist, so do it the expensive way.\n+            pass\n+    return dict((getattr(m, 'name', mod), (mod, _kinds[m.kind], m.help))\n+                for mod, m in _find_commands())\n+\n+def py_commands(commands, f):\n+    f.write('command_list = {\\n')\n+    for key, val in sorted(commands.iteritems()):\n+        f.write('    %r: %r,\\n' % (key, val))\n+    f.write('    }\\n')\n+\n+def _command_list(commands):\n+    kinds = {}\n+    for cmd, (mod, kind, help) in commands.iteritems():\n+        kinds.setdefault(kind, {})[cmd] = help\n+    for kind in _kind_order:\n+        kind = _kinds[kind]\n+        yield kind, sorted(kinds[kind].iteritems())\n+\n+def pretty_command_list(commands, f):\n+    cmd_len = max(len(cmd) for cmd in commands.iterkeys())\n+    sep = ''\n+    for kind, cmds in _command_list(commands):\n+        f.write(sep)\n+        sep = '\\n'\n+        f.write('%s:\\n' % kind)\n+        for cmd, help in cmds:\n+            f.write('  %*s  %s\\n' % (-cmd_len, cmd, help))\n+\n+def _write_underlined(s, u, f):\n+    f.write(s + '\\n')\n+    f.write(u*len(s) + '\\n')\n+\n+def asciidoc_command_list(commands, f):\n+    for kind, cmds in _command_list(commands):\n+        _write_underlined(kind, '~', f)\n+        f.write('\\n')\n+        for cmd, help in cmds:\n+            f.write('stgsublink:%s[]::\\n' % cmd)\n+            f.write('    %s\\n' % help)\n+        f.write('\\n')\ndiff --git a/stgit/commands/branch.py b/stgit/commands/branch.py\nindex 33a8afe..1b1b98f 100644\n--- a/stgit/commands/branch.py\n+++ b/stgit/commands/branch.py\n@@ -23,6 +23,7 @@ from stgit.out import *\n from stgit import stack, git, basedir\n \n help = 'Branch operations: switch, list, create, rename, delete, ...'\n+kind = 'stack'\n usage = ['',\n          '<branch>',\n          '--list',\ndiff --git a/stgit/commands/clean.py b/stgit/commands/clean.py\nindex 5334704..27a7716 100644\n--- a/stgit/commands/clean.py\n+++ b/stgit/commands/clean.py\n@@ -21,6 +21,7 @@ from stgit.commands import common\n from stgit.lib import transaction\n \n help = 'Delete the empty patches in the series'\n+kind = 'stack'\n usage = ['']\n description = \"\"\"\n Delete the empty patches in the whole series or only those applied or\ndiff --git a/stgit/commands/clone.py b/stgit/commands/clone.py\nindex b83169e..28500c5 100644\n--- a/stgit/commands/clone.py\n+++ b/stgit/commands/clone.py\n@@ -21,6 +21,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Make a local clone of a remote repository'\n+kind = 'repo'\n usage = ['<repository> <dir>']\n description = \"\"\"\n Clone a git repository into the local directory <dir> (using\ndiff --git a/stgit/commands/coalesce.py b/stgit/commands/coalesce.py\nindex b390584..024668a 100644\n--- a/stgit/commands/coalesce.py\n+++ b/stgit/commands/coalesce.py\n@@ -24,6 +24,7 @@ from stgit.commands import common\n from stgit.lib import git, transaction\n \n help = 'Coalesce two or more patches into one'\n+kind = 'stack'\n usage = ['[options] <patches>']\n description = \"\"\"\n Coalesce two or more patches, creating one big patch that contains all\ndiff --git a/stgit/commands/commit.py b/stgit/commands/commit.py\nindex 7d46724..99b7b5d 100644\n--- a/stgit/commands/commit.py\n+++ b/stgit/commands/commit.py\n@@ -21,6 +21,7 @@ from stgit.lib import transaction\n from stgit.out import *\n \n help = 'Permanently store the applied patches into the stack base'\n+kind = 'stack'\n usage = ['',\n          '<patchnames>',\n          '-n NUM',\ndiff --git a/stgit/commands/delete.py b/stgit/commands/delete.py\nindex 3ba7fc2..b92a039 100644\n--- a/stgit/commands/delete.py\n+++ b/stgit/commands/delete.py\n@@ -21,6 +21,7 @@ from stgit.commands import common\n from stgit.lib import transaction\n \n help = 'Delete patches'\n+kind = 'patch'\n usage = ['[options] <patch1> [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n Delete the patches passed as arguments.\ndiff --git a/stgit/commands/diff.py b/stgit/commands/diff.py\nindex 47e2e7f..e0078f9 100644\n--- a/stgit/commands/diff.py\n+++ b/stgit/commands/diff.py\n@@ -25,6 +25,7 @@ from stgit.out import *\n from stgit import argparse, stack, git\n \n help = 'Show the tree diff'\n+kind = 'wc'\n usage = ['[options] [<files or dirs>]']\n description = \"\"\"\n Show the diff (default) or diffstat between the current working copy\ndiff --git a/stgit/commands/edit.py b/stgit/commands/edit.py\nindex 0db3254..b6ef6c7 100644\n--- a/stgit/commands/edit.py\n+++ b/stgit/commands/edit.py\n@@ -25,6 +25,7 @@ from stgit.lib import git as gitlib, transaction\n from stgit.out import *\n \n help = 'edit a patch description or diff'\n+kind = 'patch'\n usage = ['[options] [<patch>]']\n description = \"\"\"\n Edit the description and author information of the given patch (or the\ndiff --git a/stgit/commands/export.py b/stgit/commands/export.py\nindex 3d74cc8..8d05996 100644\n--- a/stgit/commands/export.py\n+++ b/stgit/commands/export.py\n@@ -26,6 +26,7 @@ from stgit.out import out\n from stgit.lib import git as gitlib\n \n help = 'Export patches to a directory'\n+kind = 'patch'\n usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n Export a range of applied patches to a given directory (defaults to\ndiff --git a/stgit/commands/files.py b/stgit/commands/files.py\nindex 08f882c..318a4a3 100644\n--- a/stgit/commands/files.py\n+++ b/stgit/commands/files.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit import argparse, stack, git\n \n help = 'Show the files modified by a patch (or the current patch)'\n+kind = 'patch'\n usage = ['[options] [[<branch>:]<patch>]']\n description = \"\"\"\n List the files modified by the given patch (defaulting to the current\ndiff --git a/stgit/commands/float.py b/stgit/commands/float.py\nindex ac8eaea..1ca4ed3 100644\n--- a/stgit/commands/float.py\n+++ b/stgit/commands/float.py\n@@ -23,6 +23,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Push patches to the top, even if applied'\n+kind = 'stack'\n usage = ['<patches>',\n          '-s <series>']\n description = \"\"\"\ndiff --git a/stgit/commands/fold.py b/stgit/commands/fold.py\nindex 6ddaea9..0f1486a 100644\n--- a/stgit/commands/fold.py\n+++ b/stgit/commands/fold.py\n@@ -23,6 +23,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Integrate a GNU diff patch into the current patch'\n+kind = 'patch'\n usage = ['[options] [<file>]']\n description = \"\"\"\n Apply the given GNU diff file (or the standard input) onto the top of\ndiff --git a/stgit/commands/goto.py b/stgit/commands/goto.py\nindex 33b20ed..2bfef0f 100644\n--- a/stgit/commands/goto.py\n+++ b/stgit/commands/goto.py\n@@ -19,6 +19,7 @@ from stgit.commands import common\n from stgit.lib import transaction\n \n help = 'Push or pop patches to the given one'\n+kind = 'stack'\n usage = ['<patch-name>']\n description = \"\"\"\n Push/pop patches to/from the stack until the one given on the command\ndiff --git a/stgit/commands/hide.py b/stgit/commands/hide.py\nindex 488ea18..bee2162 100644\n--- a/stgit/commands/hide.py\n+++ b/stgit/commands/hide.py\n@@ -23,6 +23,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Hide a patch in the series'\n+kind = 'stack'\n usage = ['[options] <patch-range>']\n description = \"\"\"\n Hide a range of unapplied patches so that they are no longer shown in\ndiff --git a/stgit/commands/id.py b/stgit/commands/id.py\nindex 18bab97..857ec33 100644\n--- a/stgit/commands/id.py\n+++ b/stgit/commands/id.py\n@@ -20,6 +20,7 @@ from stgit.commands import common\n from stgit.lib import stack\n \n help = 'Print the git hash value of a StGit reference'\n+kind = 'repo'\n usage = ['[options] [id]']\n description = \"\"\"\n Print the SHA1 value of a Git id (defaulting to HEAD). In addition to\ndiff --git a/stgit/commands/imprt.py b/stgit/commands/imprt.py\nindex 1f813a2..e81475d 100644\n--- a/stgit/commands/imprt.py\n+++ b/stgit/commands/imprt.py\n@@ -26,6 +26,7 @@ from stgit import argparse, stack, git\n \n name = 'import'\n help = 'Import a GNU diff file as a new patch'\n+kind = 'patch'\n usage = ['[options] [<file>|<url>]']\n description = \"\"\"\n Create a new patch and apply the given GNU diff file (or the standard\ndiff --git a/stgit/commands/init.py b/stgit/commands/init.py\nindex f7f7a21..67d20d1 100644\n--- a/stgit/commands/init.py\n+++ b/stgit/commands/init.py\n@@ -20,6 +20,7 @@ from stgit.commands import common\n from stgit.lib import stack\n \n help = 'Initialise the current branch for use with StGIT'\n+kind = 'stack'\n usage = ['']\n description = \"\"\"\n Initialise the current git branch to be used as an StGIT stack. The\ndiff --git a/stgit/commands/log.py b/stgit/commands/log.py\nindex b505ed5..de210ea 100644\n--- a/stgit/commands/log.py\n+++ b/stgit/commands/log.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit.run import Run\n \n help = 'Display the patch changelog'\n+kind = 'patch'\n usage = ['[options] [patch]']\n description = \"\"\"\n List all the current and past commit ids of the given patch. The\ndiff --git a/stgit/commands/mail.py b/stgit/commands/mail.py\nindex 83acc86..caf8f9e 100644\n--- a/stgit/commands/mail.py\n+++ b/stgit/commands/mail.py\n@@ -26,6 +26,7 @@ from stgit.config import config\n from stgit.run import Run\n \n help = 'Send a patch or series of patches by e-mail'\n+kind = 'patch'\n usage = [' [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = r\"\"\"\n Send a patch or a range of patches by e-mail using the SMTP server\ndiff --git a/stgit/commands/new.py b/stgit/commands/new.py\nindex 5e9d4ec..c1457bd 100644\n--- a/stgit/commands/new.py\n+++ b/stgit/commands/new.py\n@@ -21,6 +21,7 @@ from stgit.commands import common\n from stgit.lib import git as gitlib, transaction\n \n help = 'Create a new, empty patch'\n+kind = 'patch'\n usage = ['[options] [<name>]']\n description = \"\"\"\n Create a new, empty patch on the current stack. The new patch is\ndiff --git a/stgit/commands/patches.py b/stgit/commands/patches.py\nindex 656a4a1..0cbc275 100644\n--- a/stgit/commands/patches.py\n+++ b/stgit/commands/patches.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Show the applied patches modifying a file'\n+kind = 'stack'\n usage = ['[options] [<files or dirs>]']\n description = \"\"\"\n Show the applied patches modifying the given files. Without arguments,\ndiff --git a/stgit/commands/pick.py b/stgit/commands/pick.py\nindex 72b2359..8a88262 100644\n--- a/stgit/commands/pick.py\n+++ b/stgit/commands/pick.py\n@@ -24,6 +24,7 @@ from stgit import stack, git\n from stgit.stack import Series\n \n help = 'Import a patch from a different branch or a commit object'\n+kind = 'patch'\n usage = ['[options] ([<patch1>] [<patch2>] [<patch3>..<patch4>])|<commit>']\n description = \"\"\"\n Import one or more patches from a different branch or a commit object\ndiff --git a/stgit/commands/pop.py b/stgit/commands/pop.py\nindex b3c4008..cf89846 100644\n--- a/stgit/commands/pop.py\n+++ b/stgit/commands/pop.py\n@@ -23,6 +23,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Pop one or more patches from the stack'\n+kind = 'stack'\n usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n Pop the topmost patch or a range of patches from the stack. The\ndiff --git a/stgit/commands/pull.py b/stgit/commands/pull.py\nindex 3801bf2..c989b5d 100644\n--- a/stgit/commands/pull.py\n+++ b/stgit/commands/pull.py\n@@ -24,6 +24,7 @@ from stgit.config import GitConfigException\n from stgit import stack, git\n \n help = 'Pull changes from a remote repository'\n+kind = 'stack'\n usage = ['[options] [<repository>]']\n description = \"\"\"\n Pull the latest changes from the given remote repository (defaulting\ndiff --git a/stgit/commands/push.py b/stgit/commands/push.py\nindex ee7b56e..c6056cc 100644\n--- a/stgit/commands/push.py\n+++ b/stgit/commands/push.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Push one or more patches onto the stack'\n+kind = 'stack'\n usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n Push one or more patches (defaulting to the first unapplied one) onto\ndiff --git a/stgit/commands/rebase.py b/stgit/commands/rebase.py\nindex ffec329..b09204e 100644\n--- a/stgit/commands/rebase.py\n+++ b/stgit/commands/rebase.py\n@@ -22,6 +22,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Move the stack base to another point in history'\n+kind = 'stack'\n usage = ['[options] <new-base-id>']\n description = \"\"\"\n Pop all patches from current stack, move the stack base to the given\ndiff --git a/stgit/commands/refresh.py b/stgit/commands/refresh.py\nindex e30085b..a20fcc5 100644\n--- a/stgit/commands/refresh.py\n+++ b/stgit/commands/refresh.py\n@@ -25,6 +25,7 @@ from stgit import stack, git\n from stgit.config import config\n \n help = 'Generate a new commit for the current patch'\n+kind = 'patch'\n usage = ['[options] [<files or dirs>]']\n description = \"\"\"\n Include the latest tree changes in the current patch. This command\ndiff --git a/stgit/commands/rename.py b/stgit/commands/rename.py\nindex b978ecf..fdb31ee 100644\n--- a/stgit/commands/rename.py\n+++ b/stgit/commands/rename.py\n@@ -23,6 +23,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Rename a patch'\n+kind = 'patch'\n usage = ['[options] [oldpatch] <newpatch>']\n description = \"\"\"\n Rename <oldpatch> into <newpatch> in a series. If <oldpatch> is not\ndiff --git a/stgit/commands/repair.py b/stgit/commands/repair.py\nindex a5156cd..6218caa 100644\n--- a/stgit/commands/repair.py\n+++ b/stgit/commands/repair.py\n@@ -26,6 +26,7 @@ from stgit.run import *\n from stgit import stack, git\n \n help = 'Fix StGit metadata if branch was modified with git commands'\n+kind = 'stack'\n usage = ['']\n description = \"\"\"\n If you modify an StGit stack (branch) with some git commands -- such\ndiff --git a/stgit/commands/resolved.py b/stgit/commands/resolved.py\nindex 5643da8..d8dacd6 100644\n--- a/stgit/commands/resolved.py\n+++ b/stgit/commands/resolved.py\n@@ -25,6 +25,7 @@ from stgit.config import config, file_extensions\n from stgit.gitmergeonefile import interactive_merge\n \n help = 'Mark a file conflict as solved'\n+kind = 'wc'\n usage = ['[options] [<files...>]']\n description = \"\"\"\n Mark a merge conflict as resolved. The conflicts can be seen with the\ndiff --git a/stgit/commands/series.py b/stgit/commands/series.py\nindex 6579a8a..492a3aa 100644\n--- a/stgit/commands/series.py\n+++ b/stgit/commands/series.py\n@@ -22,6 +22,7 @@ from stgit.commands.common import parse_patches\n from stgit.out import out\n \n help = 'Print the patch series'\n+kind = 'stack'\n usage = ['[options] [<patch-range>]']\n description = \"\"\"\n Show all the patches in the series or just those in the given\ndiff --git a/stgit/commands/show.py b/stgit/commands/show.py\nindex c12793f..41cb31e 100644\n--- a/stgit/commands/show.py\n+++ b/stgit/commands/show.py\n@@ -22,6 +22,7 @@ from stgit.commands.common import *\n from stgit import argparse, git\n \n help = 'Show the commit corresponding to a patch'\n+kind = 'patch'\n usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n Show the commit log and the diff corresponding to the given patches.\ndiff --git a/stgit/commands/sink.py b/stgit/commands/sink.py\nindex 11fae3a..2090cd4 100644\n--- a/stgit/commands/sink.py\n+++ b/stgit/commands/sink.py\n@@ -23,6 +23,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Send patches deeper down the stack'\n+kind = 'stack'\n usage = ['[-t <target patch>] [-n] [<patches>]']\n description = \"\"\"\n This is the opposite operation of stglink:float[]: move the specified\ndiff --git a/stgit/commands/status.py b/stgit/commands/status.py\nindex eadb507..7c68ba6 100644\n--- a/stgit/commands/status.py\n+++ b/stgit/commands/status.py\n@@ -23,6 +23,7 @@ from stgit.utils import *\n from stgit import stack, git\n \n help = 'Show the tree status'\n+kind = 'wc'\n usage = ['[options] [<files or dirs>]']\n description = \"\"\"\n Show the status of the whole working copy or the given files. The\ndiff --git a/stgit/commands/sync.py b/stgit/commands/sync.py\nindex ef94439..767b4d2 100644\n--- a/stgit/commands/sync.py\n+++ b/stgit/commands/sync.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Synchronise patches with a branch or a series'\n+kind = 'patch'\n usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']\n description = \"\"\"\n For each of the specified patches perform a three-way merge with the\ndiff --git a/stgit/commands/top.py b/stgit/commands/top.py\nindex f4962e7..523afa4 100644\n--- a/stgit/commands/top.py\n+++ b/stgit/commands/top.py\n@@ -21,6 +21,7 @@ from stgit.commands import common\n from stgit.out import out\n \n help = 'Print the name of the top patch'\n+kind = 'stack'\n usage = ['']\n description = \"\"\"\n Print the name of the current (topmost) patch.\"\"\"\ndiff --git a/stgit/commands/uncommit.py b/stgit/commands/uncommit.py\nindex 19ec3c9..c44385d 100644\n--- a/stgit/commands/uncommit.py\n+++ b/stgit/commands/uncommit.py\n@@ -24,6 +24,7 @@ from stgit.out import *\n from stgit import utils\n \n help = 'Turn regular git commits into StGit patches'\n+kind = 'stack'\n usage = ['<patch-name-1> [<patch-name-2> ...]',\n          '-n NUM [<prefix>]',\n          '-t <committish> [-x]']\ndiff --git a/stgit/commands/unhide.py b/stgit/commands/unhide.py\nindex 6c624d0..c34bc1d 100644\n--- a/stgit/commands/unhide.py\n+++ b/stgit/commands/unhide.py\n@@ -23,6 +23,7 @@ from stgit.out import *\n from stgit import stack, git\n \n help = 'Unhide a hidden patch'\n+kind = 'stack'\n usage = ['[options] <patch-range>']\n description = \"\"\"\n Unhide a hidden range of patches so that they are shown in the plain\ndiff --git a/stgit/main.py b/stgit/main.py\nindex 55c467c..48d8dbb 100644\n--- a/stgit/main.py\n+++ b/stgit/main.py\n@@ -48,107 +48,13 @@ class Commands(dict):\n         return candidates[0]\n         \n     def __getitem__(self, key):\n-        \"\"\"Return the command python module name based.\n-        \"\"\"\n-        global prog\n-\n         cmd_mod = self.get(key) or self.get(self.canonical_cmd(key))\n-            \n-        __import__('stgit.commands.' + cmd_mod)\n-        return getattr(stgit.commands, cmd_mod)\n-\n-commands = Commands({\n-    'branch':           'branch',\n-    'delete':           'delete',\n-    'diff':             'diff',\n-    'clean':            'clean',\n-    'clone':            'clone',\n-    'coalesce':         'coalesce',\n-    'commit':           'commit',\n-    'edit':             'edit',\n-    'export':           'export',\n-    'files':            'files',\n-    'float':            'float',\n-    'fold':             'fold',\n-    'goto':             'goto',\n-    'hide':             'hide',\n-    'id':               'id',\n-    'import':           'imprt',\n-    'init':             'init',\n-    'log':              'log',\n-    'mail':             'mail',\n-    'new':              'new',\n-    'patches':          'patches',\n-    'pick':             'pick',\n-    'pop':              'pop',\n-    'pull':             'pull',\n-    'push':             'push',\n-    'rebase':           'rebase',\n-    'refresh':          'refresh',\n-    'rename':           'rename',\n-    'repair':           'repair',\n-    'resolved':         'resolved',\n-    'series':           'series',\n-    'show':             'show',\n-    'sink':             'sink',\n-    'status':           'status',\n-    'sync':             'sync',\n-    'top':              'top',\n-    'uncommit':         'uncommit',\n-    'unhide':           'unhide'\n-    })\n+        return stgit.commands.get_command(cmd_mod)\n \n-# classification: repository, stack, patch, working copy\n-repocommands = (\n-    'clone',\n-    'id',\n-    )\n-stackcommands = (\n-    'branch',\n-    'clean',\n-    'coalesce',\n-    'commit',\n-    'float',\n-    'goto',\n-    'hide',\n-    'init',\n-    'patches',\n-    'pop',\n-    'pull',\n-    'push',\n-    'rebase',\n-    'repair',\n-    'series',\n-    'sink',\n-    'top',\n-    'uncommit',\n-    'unhide',\n-    )\n-patchcommands = (\n-    'delete',\n-    'edit',\n-    'export',\n-    'files',\n-    'fold',\n-    'import',\n-    'log',\n-    'mail',\n-    'new',\n-    'pick',\n-    'refresh',\n-    'rename',\n-    'show',\n-    'sync',\n-    )\n-wccommands = (\n-    'diff',\n-    'resolved',\n-    'status',\n-    )\n+cmd_list = stgit.commands.get_commands()\n+commands = Commands((cmd, mod) for cmd, (mod, kind, help)\n+                    in cmd_list.iteritems())\n \n-def _print_helpstring(cmd):\n-    print '  ' + cmd + ' ' * (12 - len(cmd)) + commands[cmd].help\n-    \n def print_help():\n     print 'usage: %s <command> [options]' % os.path.basename(sys.argv[0])\n     print\n@@ -156,33 +62,8 @@ def print_help():\n     print '  help        print the detailed command usage'\n     print '  version     display version information'\n     print '  copyright   display copyright information'\n-    # unclassified commands if any\n-    cmds = commands.keys()\n-    cmds.sort()\n-    for cmd in cmds:\n-        if not cmd in repocommands and not cmd in stackcommands \\\n-               and not cmd in patchcommands and not cmd in wccommands:\n-            _print_helpstring(cmd)\n-    print\n-\n-    print 'Repository commands:'\n-    for cmd in repocommands:\n-        _print_helpstring(cmd)\n     print\n-    \n-    print 'Stack commands:'\n-    for cmd in stackcommands:\n-        _print_helpstring(cmd)\n-    print\n-\n-    print 'Patch commands:'\n-    for cmd in patchcommands:\n-        _print_helpstring(cmd)\n-    print\n-\n-    print 'Working-copy commands:'\n-    for cmd in wccommands:\n-        _print_helpstring(cmd)\n+    stgit.commands.pretty_command_list(cmd_list, sys.stdout)\n \n #\n # The main function (command dispatcher)\n"},{"id":"90177","messageId":"20080909171721.2c7974a1@whitehouse.id.au","threadId":"15436","inReplyTo":"20080908210811.1957.16419.stgit@yoghurt","subject":"[StGit PATCH] Fixes for auto-generation of man pages","fromName":"Daniel White","fromEmail":"daniel@whitehouse.id.au","sentAt":"2008-09-09T07:17:21Z","receivedAt":"2008-09-09T07:17:21Z","isPatch":true,"sender":{"key":"daniel@whitehouse.id.au","avatar":"https://gravatar.com/avatar/dbe1b9de7de21d3d435a26f487adba1e4cb11ecf7b0c9beaa5a8ec792813e7e1?d=mp&s=160"},"body":"stg.txt is the only man page not generated by stg-build --commands.\nProvide this page explicitly instead of including all other\ncommands twice.\n\nstg-cmd-list.txt is only a template for inclusion in other man \npages, so rename to stop it being built along with other stg-* \nfiles.\n\nSigned-off-by: Daniel White <daniel@whitehouse.id.au>\n---\n Documentation/.gitignore |    1 +\n Documentation/Makefile   |    6 +++---\n Documentation/stg.txt    |    2 +-\n 3 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/.gitignore b/Documentation/.gitignore\nindex 32dd09d..c72f35c 100644\n--- a/Documentation/.gitignore\n+++ b/Documentation/.gitignore\n@@ -3,3 +3,4 @@\n *.[1-9]\n stg-*.txt\n doc.dep\n+command-list.txt\ndiff --git a/Documentation/Makefile b/Documentation/Makefile\nindex 85e9600..165e222 100644\n--- a/Documentation/Makefile\n+++ b/Documentation/Makefile\n@@ -1,7 +1,7 @@\n COMMANDS = $(shell ../stg-build --commands)\n COMMANDS_TXT = $(patsubst %,stg-%.txt,$(COMMANDS))\n \n-MAN1_TXT=$(wildcard stg*.txt) $(COMMANDS_TXT)\n+MAN1_TXT= stg.txt $(COMMANDS_TXT)\n \n DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT))\n \n@@ -60,14 +60,14 @@ doc.dep : $(wildcard *.txt) build-docdep.perl\n -include doc.dep\n \n clean:\n-\trm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT) stg-cmd-list.txt\n+\trm -f *.xml *.html *.pdf *.1 doc.dep $(COMMANDS_TXT) command-list.txt\n \n ALL_PY = $(shell find ../stgit -name '*.py')\n \n $(COMMANDS_TXT): $(ALL_PY)\n \t../stg-build --asciidoc $(basename $(subst stg-,,$@)) > $@\n \n-stg-cmd-list.txt: $(ALL_PY)\n+command-list.txt: $(ALL_PY)\n \t../stg-build --cmd-list > $@\n \n %.html : %.txt\ndiff --git a/Documentation/stg.txt b/Documentation/stg.txt\nindex b4184b2..d8f7d01 100644\n--- a/Documentation/stg.txt\n+++ b/Documentation/stg.txt\n@@ -105,7 +105,7 @@ description is available in individual command manpages.  Those\n manpages are named 'stg-<command>(1)'.\n endif::backend-docbook[]\n \n-include::stg-cmd-list.txt[]\n+include::command-list.txt[]\n \n CONFIGURATION MECHANISM\n -----------------------\n-- \n1.6.0.1.220.g80d1\n"},{"id":"90361","messageId":"20080910155621.GA26098@diana.vm.bytemark.co.uk","threadId":"15436","inReplyTo":"20080909171721.2c7974a1@whitehouse.id.au","subject":"Re: [StGit PATCH] Fixes for auto-generation of man pages","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-09-10T15:56:21Z","receivedAt":"2008-09-10T15:56:21Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-09-09 17:17:21 +1000, Daniel White wrote:\n\n> stg.txt is the only man page not generated by stg-build --commands.\n> Provide this page explicitly instead of including all other commands\n> twice.\n>\n> stg-cmd-list.txt is only a template for inclusion in other man\n> pages, so rename to stop it being built along with other stg-*\n> files.\n\nThanks, this makes sense.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"},{"id":"90392","messageId":"b0943d9e0809101456w3c74b86fm9d311fb2594bcf4f@mail.gmail.com","threadId":"15436","inReplyTo":"20080908210758.1957.664.stgit@yoghurt","subject":"Re: [StGit PATCH 1/3] Auto-generate man pages for all StGit commands","fromName":"Catalin Marinas","fromEmail":"catalin.marinas@gmail.com","sentAt":"2008-09-10T21:56:55Z","receivedAt":"2008-09-10T21:56:55Z","isPatch":true,"sender":{"key":"catalin.marinas@gmail.com","avatar":null},"body":"On 08/09/2008, Karl Hasselström <kha@treskal.com> wrote:\n> Auto-generate man pages based on the docs that are in each\n>  stgit/commands/<cmd>.py file. That doc format is extended in order to\n>  support both brief command help output and manpage text.\n\nReally great stuff. Thanks.\n\nI can see a slight difference in behaviour but I don't have any issue\nwith it - previously \"stg help <cmd>\" showed the full description\nwhile \"stg <cmd> --help\" only the short one.\n\nAn additional point on naming - should we use StGIT or StGit? The\noriginal name was StGIT since GIT looked like an acronym. It looks\nlike now more people name it Git hence our tool moved slowly into\nStGit but not everywhere. I personally like StGIT but the last 3\nletters should really be the same as the official git (Git, GIT).\n\n-- \nCatalin\n"},{"id":"90418","messageId":"20080911065832.GA6409@diana.vm.bytemark.co.uk","threadId":"15436","inReplyTo":"b0943d9e0809101456w3c74b86fm9d311fb2594bcf4f@mail.gmail.com","subject":"Re: [StGit PATCH 1/3] Auto-generate man pages for all StGit commands","fromName":"Karl Hasselström","fromEmail":"kha@treskal.com","sentAt":"2008-09-11T06:58:32Z","receivedAt":"2008-09-11T06:58:32Z","isPatch":true,"sender":{"key":"kha@treskal.com","avatar":"https://gravatar.com/avatar/f0120c734b5279b345075a28521e1ac66acb20c9913ffe9bf6ae97e53f7f3f13?d=mp&s=160"},"body":"On 2008-09-10 22:56:55 +0100, Catalin Marinas wrote:\n\n> On 08/09/2008, Karl Hasselström <kha@treskal.com> wrote:\n>\n> > Auto-generate man pages based on the docs that are in each\n> > stgit/commands/<cmd>.py file. That doc format is extended in order\n> > to support both brief command help output and manpage text.\n>\n> Really great stuff. Thanks.\n\nGlad you like it. Now all we have to do is feed the system with\nhigh-quality input ... :-)\n\n> I can see a slight difference in behaviour but I don't have any\n> issue with it - previously \"stg help <cmd>\" showed the full\n> description while \"stg <cmd> --help\" only the short one.\n\nYes, that's intentional. I tried to say something about it in the\ncommit message, but I guess I didn't do a very good job about it.\n\nThe interactive help now uses only the one-line command description;\nthe multiline description goes only to the man page/html. There are\ntwo reasons for this:\n\n  1. The interactive help should be short and sweet. If the user wants\n     to spend a minute or more learning about a command, she is better\n     served by the \"real\" reference docs.\n\n  2. The multiline descriptions (both for the command itself and for\n     its flags) contain, or should contain, asciidoc markup. If we\n     wanted to display this text in the interactive help we'd need to\n     at least be able to strip the markup out, something which I\n     haven't even tried to do.\n\n> An additional point on naming - should we use StGIT or StGit? The\n> original name was StGIT since GIT looked like an acronym. It looks\n> like now more people name it Git hence our tool moved slowly into\n> StGit but not everywhere. I personally like StGIT but the last 3\n> letters should really be the same as the official git (Git, GIT).\n\nAs you may or may not have noticed, I'm responsible for the vast\nmajority of \"StGit\"s. I prefer it because \"git\" isn't really an\nacronym, and I happen to like camel case ... :-)\n\nYou're right that we ought to standardize on one of the spellings,\nthough.\n\n-- \nKarl Hasselström, kha@treskal.com\n      www.treskal.com/kalle\n"}]}