1
# Copyright 2005 Canonical Ltd.
3
# Copyright (C) 2005 by Hans Ulrich Niedermann
4
# Portions Copyright (C) 2005 by Canonical Ltd
3
6
# This program is free software; you can redistribute it and/or modify
4
7
# it under the terms of the GNU General Public License as published by
5
8
# the Free Software Foundation; either version 2 of the License, or
6
9
# (at your option) any later version.
8
11
# This program is distributed in the hope that it will be useful,
9
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
14
# GNU General Public License for more details.
13
16
# You should have received a copy of the GNU General Public License
14
17
# along with this program; if not, write to the Free Software
15
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""man.py - create man page from built-in bzr help and static text
20
* use usage information instead of simple "bzr foo" in COMMAND OVERVIEW
20
#<<< code taken from bzr (C) Canonical
25
version_info = sys.version_info
26
except AttributeError:
27
version_info = 1, 5 # 1.5 or older
30
REINVOKE = "__BZR_REINVOKE"
33
if version_info < NEED_VERS:
34
if not os.environ.has_key(REINVOKE):
35
# mutating os.environ doesn't work in old Pythons
36
os.putenv(REINVOKE, "1")
37
for python in 'python2.4', 'python2.3':
39
os.execvp(python, [python] + sys.argv)
42
print >>sys.stderr, "bzr-man.py: error: cannot find a suitable python interpreter"
43
print >>sys.stderr, " (need %d.%d or later)" % NEED_VERS
45
if hasattr(os, "unsetenv"):
48
import bzrlib, bzrlib.help
50
#>>> code taken from bzr (C) Canonical
31
import bzrlib.commands
34
def get_filename(options):
35
"""Provides name of manpage"""
36
return "%s.1" % (options.bzr_name)
39
def infogen(options, outfile):
40
"""Assembles a man page"""
44
{ "bzrcmd": options.bzr_name,
45
"datestamp": time.strftime("%Y-%m-%d",tt),
46
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S +0000",tt),
47
"version": bzrlib.__version__,
49
outfile.write(man_preamble % params)
50
outfile.write(man_escape(man_head % params))
51
outfile.write(man_escape(getcommand_list(params)))
52
outfile.write(man_escape(getcommand_help(params)))
53
outfile.write(man_escape(man_foot % params))
56
58
def man_escape(string):
57
"""Escapes strings for man page compatibility"""
58
59
result = string.replace("\\","\\\\")
59
60
result = result.replace("`","\\`")
60
61
result = result.replace("'","\\'")
65
def command_name_list():
66
"""Builds a list of command names from bzrlib"""
67
command_names = bzrlib.commands.builtin_command_names()
72
def getcommand_list (params):
73
"""Builds summary help for command names in manpage format"""
74
bzrcmd = params["bzrcmd"]
75
output = '.SH "COMMAND OVERVIEW"\n'
76
for cmd_name in command_name_list():
77
cmd_object = bzrlib.commands.get_cmd_object(cmd_name)
80
cmd_help = cmd_object.help()
82
firstline = cmd_help.split('\n', 1)[0]
83
usage = bzrlib.help.command_usage(cmd_object)
84
tmp = '.TP\n.B "%s"\n%s\n' % (usage, firstline)
68
def parse_line(self, line):
72
class CommandListParser(Parser):
74
"""Parser for output of "bzr help commands".
76
The parsed content can then be used to
77
- write a "COMMAND OVERVIEW" section into a man page
78
- provide a list of all commands
81
def __init__(self,params):
83
self.command_usage = []
84
self.all_commands = []
85
self.usage_exp = re.compile("([a-z0-9-]+).*")
86
self.descr_exp = re.compile(" ([A-Z].*)\s*")
92
def parse_line(self, line):
93
m = self.usage_exp.match(line)
99
self.command_usage.append((self.command,self.usage,self.descr))
100
self.all_commands.append(self.command)
101
self.usage = " ".join(line.split(" ")[1:])
102
self.command = m.groups()[0]
104
raise RuntimeError, "matching usage line in state %d" % state
107
m = self.descr_exp.match(line)
110
self.descr = m.groups()[0]
112
raise RuntimeError, "matching descr line in state %d" % state
115
raise RuntimeError, "Cannot parse this line ('%s')." % line
120
self.command_usage.append((self.command,self.usage,self.descr))
121
self.all_commands.append(self.command)
87
raise RuntimeError, "Command '%s' has no help text" % (cmd_name)
91
def getcommand_help(params):
92
"""Shows individual options for a bzr command"""
93
output='.SH "COMMAND REFERENCE"\n'
94
for cmd_name in command_name_list():
95
cmd_object = bzrlib.commands.get_cmd_object(cmd_name)
98
output = output + format_command(params, cmd_object)
102
def format_command (params, cmd):
103
"""Provides long help for each public command"""
104
subsection_header = '.SS "%s"\n' % (bzrlib.help.command_usage(cmd))
105
doc = "%s\n" % (cmd.__doc__)
106
docsplit = cmd.__doc__.split('\n')
107
doc = '\n'.join([docsplit[0]] + [line[4:] for line in docsplit[1:]])
109
options = cmd.options()
111
option_str = "\nOptions:\n"
112
for option_name, option in sorted(options.items()):
113
l = ' --' + option_name
114
if option.type is not None:
115
l += ' ' + option.argname.upper()
116
short_name = option.short_name()
118
assert len(short_name) == 1
119
l += ', -' + short_name
120
l += (30 - len(l)) * ' ' + option.help
121
# TODO: Split help over multiple lines with
122
# correct indenting and wrapping.
123
wrapped = textwrap.fill(l, initial_indent='',
124
subsequent_indent=30*' ')
125
option_str = option_str + wrapped + '\n'
126
return subsection_header + option_str + "\n" + doc + "\n"
123
raise RuntimeError, "ending parse in state %d" % state
125
def write_to_manpage(self, outfile):
126
bzrcmd = self.params["bzrcmd"]
127
outfile.write('.SH "COMMAND OVERVIEW"\n')
128
for (command,usage,descr) in self.command_usage:
129
outfile.write('.TP\n.B "%s %s"\n%s\n\n' % (bzrcmd, usage, descr))
134
def __init__(self, parser):
137
def write(self, data):
140
for line in data.split('\n'):
141
self.parser.parse_line(line)
144
def write_command_details(params, command, usage, descr, outfile):
145
x = ('.SS "%s %s"\n.B "%s"\n.PP\n.B "Usage:"\n%s %s\n\n' %
151
outfile.write(man_escape(x))
129
154
man_preamble = """\
130
Man page for %(bzrcmd)s (bazaar-ng)
155
.\\\" Man page for %(bzrcmd)s (bazaar-ng)
132
157
.\\\" Large parts of this file are autogenerated from the output of
133
158
.\\\" \"%(bzrcmd)s help commands\"
170
198
is to look for external command.
173
E-Mail address of the user. Overrides default user config.
202
E-Mail address of the user. Overrides
203
.I "~/.bzr.conf/email" and
206
.I "John Doe <john@example.com>"
176
E-Mail address of the user. Overriddes default user config.
210
E-Mail address of the user. Overridden by the content of the file
211
.I "~/.bzr.conf/email"
212
and of the environment variable
179
.I "~/.bazaar/bazaar.conf/"
180
Contains the default user config. Only one section, [DEFAULT] is allowed. A
181
typical default config file may be similiar to:
186
.B email=John Doe <jdoe@isp.com>
218
Directory where all the user\'s settings are stored.
220
.I "~/.bzr.conf/email"
221
Stores name and email address of the user. Overrides content of
223
environment variable. Example content:
224
.I "John Doe <john@example.com>"
188
.UR http://www.bazaar-vcs.org/
189
.BR http://www.bazaar-vcs.org/
227
.UR http://www.bazaar-ng.org/
228
.BR http://www.bazaar-ng.org/,
229
.UR http://www.bazaar-ng.org/doc/
230
.BR http://www.bazaar-ng.org/doc/
238
"datestamp": time.strftime("%Y-%m-%d",tt),
239
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S +0000",tt),
240
"version": bzrlib.__version__,
243
clp = CommandListParser(params)
244
bzrlib.help.help("commands", outfile=HelpReader(clp))
248
if len(sys.argv) == 2:
249
filename = sys.argv[1]
253
outfile = open(filename,"w")
255
outfile.write(man_preamble % params)
256
outfile.write(man_escape(man_head % params))
257
clp.write_to_manpage(outfile)
260
# This doesn't do more than the summary so far.
261
#outfile.write('.SH "DETAILED COMMAND DESCRIPTION"\n')
262
#for (command,usage,descr) in clp.command_usage:
263
# write_command_details(params, command, usage, descr, outfile = outfile)
265
outfile.write(man_escape(man_foot % params))
268
if __name__ == '__main__':