comparison piecrust/commands/base.py @ 57:c8c522dacfea

Add `help` function, cleanup argument handling.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 26 Aug 2014 23:18:32 -0700
parents f485ba500df3
children 8703be118430
comparison
equal deleted inserted replaced
56:2d617b889b00 57:c8c522dacfea
1 import logging 1 import logging
2 import argparse
2 import functools 3 import functools
3 from piecrust.pathutil import SiteNotFoundError 4 from piecrust.pathutil import SiteNotFoundError
4 5
5 6
6 logger = logging.getLogger(__name__) 7 logger = logging.getLogger(__name__)
7 8
8 9
9 class CommandContext(object): 10 class CommandContext(object):
10 def __init__(self, app, args): 11 def __init__(self, app, parser, args):
11 self.app = app 12 self.app = app
13 self.parser = parser
12 self.args = args 14 self.args = args
13 self.result = 0
14 15
15 16
16 class ChefCommand(object): 17 class ChefCommand(object):
17 def __init__(self): 18 def __init__(self):
18 self.name = '__unknown__' 19 self.name = '__unknown__'
21 22
22 def setupParser(self, parser, app): 23 def setupParser(self, parser, app):
23 raise NotImplementedError() 24 raise NotImplementedError()
24 25
25 def run(self, ctx): 26 def run(self, ctx):
26 raise NotImplementedError() 27 raise NotImplementedError("Command '%s' doesn't implement the `run` "
28 "method." % type(self))
27 29
28 def _runFromChef(self, app, res): 30 def checkedRun(self, ctx):
29 if app.root_dir is None and self.requires_website: 31 if ctx.app.root_dir is None and self.requires_website:
30 raise SiteNotFoundError() 32 raise SiteNotFoundError()
31 ctx = CommandContext(app, res) 33 return self.run(ctx)
32 self.run(ctx)
33 return ctx.result
34 34
35 35
36 class ExtendableChefCommand(ChefCommand): 36 class ExtendableChefCommand(ChefCommand):
37 def __init__(self): 37 def __init__(self):
38 super(ExtendableChefCommand, self).__init__() 38 super(ExtendableChefCommand, self).__init__()
42 self._loadExtensions(app) 42 self._loadExtensions(app)
43 subparsers = parser.add_subparsers() 43 subparsers = parser.add_subparsers()
44 for e in self._extensions: 44 for e in self._extensions:
45 p = subparsers.add_parser(e.name, help=e.description) 45 p = subparsers.add_parser(e.name, help=e.description)
46 e.setupParser(p, app) 46 e.setupParser(p, app)
47 p.set_defaults(func=e._runFromChef) 47 p.set_defaults(func=e.checkedRun)
48 48
49 def _loadExtensions(self, app): 49 def _loadExtensions(self, app):
50 if self._extensions is not None: 50 if self._extensions is not None:
51 return 51 return
52 self._extensions = [] 52 self._extensions = []
60 super(ChefCommandExtension, self).__init__() 60 super(ChefCommandExtension, self).__init__()
61 self.command_name = '__unknown__' 61 self.command_name = '__unknown__'
62 62
63 def supports(self, app): 63 def supports(self, app):
64 return True 64 return True
65
66
67 class HelpCommand(ChefCommand):
68 def __init__(self):
69 super(HelpCommand, self).__init__()
70 self.name = 'help'
71 self.description = "Prints help about PieCrust's chef."
72 self._topic_providers = {}
73
74 @property
75 def has_topics(self):
76 return any(self._topic_providers)
77
78 def addTopic(self, name, provider):
79 self._topic_providers[name] = provider
80
81 def getTopicNames(self):
82 return self._topic_providers.keys()
83
84 def setupParser(self, parser, app):
85 parser.add_argument('topic', nargs='?',
86 help="The command name or topic on which to get help.")
87
88 def run(self, ctx):
89 topic = ctx.args.topic
90
91 if topic is None:
92 ctx.parser.print_help()
93 return 0
94
95 if topic in self._topic_providers:
96 print(self._topic_providers[topic].getHelpTopic(topic, ctx.app))
97 return 0
98
99 for c in ctx.app.plugin_loader.getCommands():
100 if c.name == topic:
101 fake = argparse.ArgumentParser(
102 prog='%s %s' % (ctx.parser.prog, c.name),
103 description=c.description)
104 c.setupParser(fake, ctx.app)
105 fake.print_help()
106 return 0
107
108 raise Exception("No such command or topic: %s" % topic)
65 109
66 110
67 class _WrappedCommand(ChefCommand): 111 class _WrappedCommand(ChefCommand):
68 def __init__(self, func, name, description): 112 def __init__(self, func, name, description):
69 super(_WrappedCommand, self).__init__() 113 super(_WrappedCommand, self).__init__()