46
48
# This converts the various Python string types into a format that
47
49
# is appropriate for .po files, namely much closer to C style.
48
50
lines = s.split('\n')
49
51
if len(lines) == 1:
50
s = '"' + escape(s) + '"'
52
s = '"' + _escape(s) + '"'
54
56
lines[-1] = lines[-1] + '\n'
55
lines = map(escape, lines)
57
lines = map(_escape, lines)
56
58
lineterm = '\\n"\n"'
57
59
s = '""\n"' + lineterm.join(lines) + '"'
63
_FOUND_MSGID = None # set by entry function.
63
def poentry(path, lineno, s, comment=None):
65
def _poentry(outf, path, lineno, s, comment=None):
67
69
if comment is None:
70
72
comment = "# %s\n" % comment
71
print ('#: %s:%d\n' % (path, lineno) +
73
mutter("Exporting msg %r at line %d in %r", s[:20], lineno, path)
74
print >>outf, ('#: %s:%d\n' % (path, lineno) +
73
'msgid %s\n' % normalize(s) +
76
'msgid %s\n' % _normalize(s) +
76
def poentry_per_paragraph(path, lineno, msgid):
79
def _poentry_per_paragraph(outf, path, lineno, msgid):
80
# TODO: How to split long help?
77
81
paragraphs = msgid.split('\n\n')
78
82
for p in paragraphs:
79
poentry(path, lineno, p)
83
_poentry(outf, path, lineno, p)
80
84
lineno += p.count('\n') + 2
82
def offset(src, doc, name, default):
83
"""Compute offset or issue a warning on stdout."""
84
# Backslashes in doc appear doubled in src.
85
end = src.find(doc.replace('\\', '\\\\'))
87
# This can happen if the docstring contains unnecessary escape
88
# sequences such as \" in a triple-quoted string. The problem
89
# is that \" is turned into " and so doc wont appear in src.
90
sys.stderr.write("warning: unknown offset in %s, assuming %d lines\n"
94
return src.count('\n', 0, end)
98
"""Import a path like foo/bar/baz.py and return the baz module."""
99
if path.endswith('.py'):
101
if path.endswith('/__init__'):
103
path = path.replace('/', '.')
104
mod = __import__(path)
105
for comp in path.split('.')[1:]:
106
mod = getattr(mod, comp)
109
def options(path, lineno, cmdklass):
111
for name, opt in cmd.options().iteritems():
112
poentry(path, lineno, opt.help,
113
"help of '%s' option of '%s' command" % (name, cmd.name()))
116
def docstrings(path):
86
_LAST_CACHE = _LAST_CACHED_SRC = None
88
def _offsets_of_literal(src):
89
global _LAST_CACHE, _LAST_CACHED_SRC
90
if src == _LAST_CACHED_SRC:
91
return _LAST_CACHE.copy()
96
for node in ast.walk(root):
97
if not isinstance(node, ast.Str):
99
offsets[node.s] = node.lineno - node.s.count('\n')
101
_LAST_CACHED_SRC = src
102
_LAST_CACHE = offsets.copy()
105
def _standard_options(outf):
106
from bzrlib.option import Option
107
src = inspect.findsource(Option)[0]
109
path = 'bzrlib/option.py'
110
offsets = _offsets_of_literal(src)
112
for name in sorted(Option.OPTIONS.keys()):
113
opt = Option.OPTIONS[name]
114
if getattr(opt, 'hidden', False):
116
if getattr(opt, 'title', None):
117
lineno = offsets.get(opt.title, 9999)
119
note("%r is not found in bzrlib/option.py" % opt.title)
120
_poentry(outf, path, lineno, opt.title,
121
'title of %r option' % name)
122
if getattr(opt, 'help', None):
123
lineno = offsets.get(opt.help, 9999)
125
note("%r is not found in bzrlib/option.py" % opt.help)
126
_poentry(outf, path, lineno, opt.help,
127
'help of %r option' % name)
129
def _command_options(outf, path, cmd):
130
src, default_lineno = inspect.findsource(cmd.__class__)
131
offsets = _offsets_of_literal(''.join(src))
132
for opt in cmd.takes_options:
133
if isinstance(opt, str):
135
if getattr(opt, 'hidden', False):
138
if getattr(opt, 'title', None):
139
lineno = offsets.get(opt.title, default_lineno)
140
_poentry(outf, path, lineno, opt.title,
141
'title of %r option of %r command' % (name, cmd.name()))
142
if getattr(opt, 'help', None):
143
lineno = offsets.get(opt.help, default_lineno)
144
_poentry(outf, path, lineno, opt.help,
145
'help of %r option of %r command' % (name, cmd.name()))
148
def _write_command_help(outf, cmd_name, cmd):
149
path = inspect.getfile(cmd.__class__)
150
if path.endswith('.pyc'):
152
path = os.path.relpath(path)
153
src, lineno = inspect.findsource(cmd.__class__)
154
offsets = _offsets_of_literal(''.join(src))
155
lineno = offsets[cmd.__doc__]
156
doc = inspect.getdoc(cmd)
158
_poentry_per_paragraph(outf, path, lineno, doc)
159
_command_options(outf, path, cmd)
161
def _command_helps(outf):
117
162
"""Extract docstrings from path.
119
164
This respects the Bazaar cmdtable/table convention and will
120
165
only extract docstrings from functions mentioned in these tables.
122
from bzrlib.commands import Command as cmd_klass
123
mod = importpath(path)
124
for name in dir(mod):
125
if not name.startswith('cmd_'):
127
obj = getattr(mod, name)
131
doc = inspect.cleandoc(doc)
134
except AttributeError:
136
if (inspect.isclass(obj) and issubclass(obj, cmd_klass)
137
and not obj is cmd_klass):
138
lineno = inspect.findsource(obj)[1]
139
poentry_per_paragraph(path, lineno, doc)
140
options(path, lineno, obj)
167
from glob import glob
170
for cmd_name in _mod_commands.builtin_command_names():
171
command = _mod_commands.get_cmd_object(cmd_name, False)
174
note("Exporting messages from builtin command: %s", cmd_name)
175
_write_command_help(outf, cmd_name, command)
177
plugin_path = plugin.get_core_plugin_path()
178
core_plugins = glob(plugin_path + '/*/__init__.py')
179
core_plugins = [os.path.basename(os.path.dirname(p))
180
for p in core_plugins]
182
for cmd_name in _mod_commands.plugin_command_names():
183
command = _mod_commands.get_cmd_object(cmd_name, False)
186
if command.plugin_name() not in core_plugins:
187
# skip non-core plugins
188
# TODO: Support extracting from third party plugins.
190
note("Exporting messages from plugin command: %s in %s",
191
cmd_name, command.plugin_name())
192
_write_command_help(outf, cmd_name, command)
195
def _error_messages(outf):
143
196
"""Extract fmt string from bzrlib.errors."""
144
from bzrlib import errors
197
path = errors.__file__
198
if path.endswith('.pyc'):
200
offsets = _offsets_of_literal(open(path).read())
145
202
base_klass = errors.BzrError
146
203
for name in dir(errors):
147
204
klass = getattr(errors, name)