/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.27.16 by Martin von Gagern
Added distutils setup script and plugin meta data.
1
#!/usr/bin/env python
0.27.2 by Martin von Gagern
First programmatic generation of completions.
2
5147.5.4 by Martin von Gagern
Assign copyright to Canonical Ltd.
3
# Copyright (C) 2009, 2010 Canonical Ltd
0.27.14 by Martin von Gagern
Added GPL 2 license document and copyright notice.
4
#
5147.5.5 by Martin von Gagern
Adjust copyright notice comments for bash_completion.
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
0.27.14 by Martin von Gagern
Added GPL 2 license document and copyright notice.
14
#
15
# You should have received a copy of the GNU General Public License
5147.5.5 by Martin von Gagern
Adjust copyright notice comments for bash_completion.
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.27.14 by Martin von Gagern
Added GPL 2 license document and copyright notice.
18
0.28.2 by Martin von Gagern
merge from trunk
19
from bzrlib import (
20
    commands,
21
    config,
22
    help_topics,
23
    option,
24
    plugin,
25
)
0.27.36 by Martin von Gagern
List versions of bzr and plugins.
26
import bzrlib
0.27.18 by Martin von Gagern
Add global options in all cases
27
import re
0.27.2 by Martin von Gagern
First programmatic generation of completions.
28
0.32.8 by Martin von Gagern
Refactor to increase modularity.
29
30
class BashCodeGen(object):
31
    """Generate a bash script for given completion data."""
32
33
    def __init__(self, data, function_name='_bzr', debug=False):
34
        self.data = data
35
        self.function_name = function_name
36
        self.debug = debug
37
38
    def script(self):
39
        return ("""\
0.30.3 by Martin von Gagern
Lazy initialization
40
# Programmable completion for the Bazaar-NG bzr command under bash.
41
# Known to work with bash 2.05a as well as bash 4.1.2, and probably
42
# all versions in between as well.
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
43
44
# Based originally on the svn bash completition script.
45
# Customized by Sven Wilhelm/Icecrash.com
0.27.2 by Martin von Gagern
First programmatic generation of completions.
46
# Adjusted for automatic generation by Martin von Gagern
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
47
5147.5.12 by Martin von Gagern
Use version of bzrlib. Drop meta.py.
48
# Generated using the bash_completion plugin.
0.27.17 by Martin von Gagern
Mention version and homepage in generated shell code comment.
49
# See https://launchpad.net/bzr-bash-completion for details.
50
0.27.36 by Martin von Gagern
List versions of bzr and plugins.
51
# Commands and options of bzr %(bzr_version)s
52
0.27.20 by Martin von Gagern
More flexible handling of fixed word lists.
53
shopt -s progcomp
0.32.8 by Martin von Gagern
Refactor to increase modularity.
54
%(function)s
55
complete -F %(function_name)s -o default bzr
56
"""     % {
57
            "function_name": self.function_name,
58
            "function": self.function(),
59
            "bzr_version": self.bzr_version(),
60
        })
61
62
    def function(self):
63
        return ("""\
0.27.4 by Martin von Gagern
Introduce --function-name switch. (LP #439829)
64
%(function_name)s ()
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
65
{
0.27.20 by Martin von Gagern
More flexible handling of fixed word lists.
66
	local cur cmds cmdIdx cmd cmdOpts fixedWords i globalOpts
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
67
	local curOpt optEnums
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
68
69
	COMPREPLY=()
70
	cur=${COMP_WORDS[COMP_CWORD]}
71
0.27.2 by Martin von Gagern
First programmatic generation of completions.
72
	cmds='%(cmds)s'
0.27.19 by Martin von Gagern
Take global options preceding the command into account.
73
	globalOpts='%(global_options)s'
74
75
	# do ordinary expansion if we are anywhere after a -- argument
76
	for ((i = 1; i < COMP_CWORD; ++i)); do
77
		[[ ${COMP_WORDS[i]} == "--" ]] && return 0
78
	done
79
80
	# find the command; it's the first word not starting in -
81
	cmd=
82
	for ((cmdIdx = 1; cmdIdx < ${#COMP_WORDS[@]}; ++cmdIdx)); do
83
		if [[ ${COMP_WORDS[cmdIdx]} != -* ]]; then
84
			cmd=${COMP_WORDS[cmdIdx]}
85
			break
86
		fi
87
	done
88
89
	# complete command name if we are not already past the command
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
90
	if [[ $COMP_CWORD -le cmdIdx ]]; then
0.27.18 by Martin von Gagern
Add global options in all cases
91
		COMPREPLY=( $( compgen -W "$cmds $globalOpts" -- $cur ) )
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
92
		return 0
93
	fi
94
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
95
	# find the option for which we want to complete a value
96
	curOpt=
97
	if [[ $cur != -* ]] && [[ $COMP_CWORD -gt 1 ]]; then
98
		curOpt=${COMP_WORDS[COMP_CWORD - 1]}
99
		if [[ $curOpt == = ]]; then
100
			curOpt=${COMP_WORDS[COMP_CWORD - 2]}
0.32.1 by Martin von Gagern
Complete tag names.
101
		elif [[ $cur == : ]]; then
102
			cur=
103
			curOpt="$curOpt:"
104
		elif [[ $curOpt == : ]]; then
105
			curOpt=${COMP_WORDS[COMP_CWORD - 2]}:
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
106
		fi
107
	fi
0.27.31 by Martin von Gagern
Introduce --debug switch to enable some debugging code.
108
%(debug)s
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
109
	cmdOpts=
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
110
	optEnums=
0.27.20 by Martin von Gagern
More flexible handling of fixed word lists.
111
	fixedWords=
0.27.19 by Martin von Gagern
Take global options preceding the command into account.
112
	case $cmd in
0.27.2 by Martin von Gagern
First programmatic generation of completions.
113
%(cases)s\
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
114
	*)
0.27.2 by Martin von Gagern
First programmatic generation of completions.
115
		cmdOpts='--help -h'
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
116
		;;
117
	esac
118
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
119
	if [[ -z $fixedWords ]] && [[ -z $optEnums ]] && [[ $cur != -* ]]; then
0.32.1 by Martin von Gagern
Complete tag names.
120
		case $curOpt in
121
			tag:*)
0.32.7 by Martin von Gagern
Allow different formats for tag completion.
122
				fixedWords="$(bzr tags 2>/dev/null | sed 's/  *[^ ]*$//')"
0.32.1 by Martin von Gagern
Complete tag names.
123
				;;
124
		esac
125
	elif [[ $cur == = ]] && [[ -n $optEnums ]]; then
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
126
		# complete directly after "--option=", list all enum values
0.32.3 by Martin von Gagern
Restore completion of registry options immediately after =.
127
		COMPREPLY=( $optEnums )
128
		return 0
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
129
	else
130
		fixedWords="$cmdOpts $globalOpts $optEnums $fixedWords"
0.32.1 by Martin von Gagern
Complete tag names.
131
	fi
132
133
	if [[ -n $fixedWords ]]; then
0.27.30 by Martin von Gagern
Complete values for enum_switch of RegistryOptions.
134
		COMPREPLY=( $( compgen -W "$fixedWords" -- $cur ) )
135
	fi
0.27.1 by Martin von Gagern
Original script from bzr.dev/contrib/bash/bzr
136
137
	return 0
138
}
0.32.8 by Martin von Gagern
Refactor to increase modularity.
139
"""     % {
140
            "cmds": self.command_names(),
141
            "function_name": self.function_name,
142
            "cases": self.command_cases(),
143
            "global_options": self.global_options(),
144
            "debug": self.debug_output(),
145
        })
146
147
    def command_names(self):
148
        return " ".join(self.data.all_command_aliases())
149
150
    def debug_output(self):
151
        if not self.debug:
152
            return ''
153
        else:
154
            return (r"""
0.27.31 by Martin von Gagern
Introduce --debug switch to enable some debugging code.
155
	# Debugging code enabled using the --debug command line switch.
156
	# Will dump some variables to the top portion of the terminal.
157
	echo -ne '\e[s\e[H'
158
	for (( i=0; i < ${#COMP_WORDS[@]}; ++i)); do
159
		echo "\$COMP_WORDS[$i]='${COMP_WORDS[i]}'"$'\e[K'
160
	done
161
	for i in COMP_CWORD COMP_LINE COMP_POINT COMP_TYPE COMP_KEY cur curOpt; do
162
		echo "\$${i}=\"${!i}\""$'\e[K'
163
	done
164
	echo -ne '---\e[K\e[u'
0.32.8 by Martin von Gagern
Refactor to increase modularity.
165
""")
166
167
    def bzr_version(self):
168
        bzr_version = bzrlib.version_string
169
        if not self.data.plugins:
170
            bzr_version += "."
171
        else:
172
            bzr_version += " and the following plugins:"
173
            for name, plugin in sorted(self.data.plugins.iteritems()):
174
                bzr_version += "\n# %s" % plugin
0.32.9 by Martin von Gagern
Added test cases for DataCollector and BashCodeGen.
175
        return bzr_version
0.32.8 by Martin von Gagern
Refactor to increase modularity.
176
177
    def global_options(self):
178
        return " ".join(sorted(self.data.global_options))
179
180
    def command_cases(self):
181
        cases = ""
182
        for command in self.data.commands:
183
            cases += self.command_case(command)
184
        return cases
185
186
    def command_case(self, command):
187
        case = "\t%s)\n" % "|".join(command.aliases)
188
        if command.plugin:
189
            case += "\t\t# plugin \"%s\"\n" % command.plugin
190
        options = []
191
        enums = []
192
        for option in command.options:
193
            for message in option.error_messages:
194
                case += "\t\t# %s\n" % message
195
            if option.registry_keys:
196
                for key in option.registry_keys:
197
                    options.append("%s=%s" % (option, key))
198
                enums.append("%s) optEnums='%s' ;;" %
199
                             (option, ' '.join(option.registry_keys)))
200
            else:
201
                options.append(str(option))
202
        case += "\t\tcmdOpts='%s'\n" % " ".join(options)
203
        if command.fixed_words:
204
            fixed_words = command.fixed_words
205
            if isinstance(fixed_words, list):
206
                fixed_words = "'%s'" + ' '.join(fixed_words)
207
            case += "\t\tfixedWords=%s\n" % fixed_words
208
        if enums:
209
            case += "\t\tcase $curOpt in\n\t\t\t"
210
            case += "\n\t\t\t".join(enums)
211
            case += "\n\t\tesac\n"
212
        case += "\t\t;;\n"
213
        return case
214
215
216
class CompletionData(object):
217
218
    def __init__(self):
219
        self.plugins = {}
220
        self.global_options = set()
221
        self.commands = []
222
223
    def all_command_aliases(self):
224
        for c in self.commands:
225
            for a in c.aliases:
226
                yield a
227
228
229
class CommandData(object):
230
231
    def __init__(self, name):
232
        self.name = name
233
        self.aliases = [name]
234
        self.plugin = None
235
        self.options = []
236
        self.fixed_words = None
237
238
239
class PluginData(object):
240
241
    def __init__(self, name, version=None):
242
        if version is None:
243
            version = bzrlib.plugin.plugins()[name].__version__
244
        self.name = name
245
        self.version = version
246
247
    def __str__(self):
248
        if self.version == 'unknown':
249
            return self.name
250
        return '%s %s' % (self.name, self.version)
251
252
253
class OptionData(object):
254
255
    def __init__(self, name):
256
        self.name = name
257
        self.registry_keys = None
258
        self.error_messages = []
259
260
    def __str__(self):
261
        return self.name
262
263
    def __cmp__(self, other):
264
        return cmp(self.name, other.name)
265
266
267
class DataCollector(object):
268
269
    def __init__(self, no_plugins=False, selected_plugins=None):
270
        self.data = CompletionData()
271
        self.user_aliases = {}
272
        if no_plugins:
273
            self.selected_plugins = set()
274
        elif selected_plugins is None:
275
            self.selected_plugins = None
276
        else:
277
            self.selected_plugins = set([x.replace('-', '_')
278
                                         for x in selected_plugins])
279
280
    def collect(self):
281
        self.global_options()
282
        self.aliases()
283
        self.commands()
284
        return self.data
285
286
    def global_options(self):
287
        re_switch = re.compile(r'\n(--[A-Za-z0-9-_]+)(?:, (-\S))?\s')
288
        help_text = help_topics.topic_registry.get_detail('global-options')
289
        for long, short in re_switch.findall(help_text):
290
            self.data.global_options.add(long)
291
            if short:
292
                self.data.global_options.add(short)
293
294
    def aliases(self):
295
        for alias, expansion in config.GlobalConfig().get_aliases().iteritems():
296
            for token in commands.shlex_split_unicode(expansion):
297
                if not token.startswith("-"):
298
                    self.user_aliases.setdefault(token, set()).add(alias)
299
                    break
300
301
    def commands(self):
302
        for name in sorted(commands.all_command_names()):
303
            self.command(name)
304
305
    def command(self, name):
306
        cmd = commands.get_cmd_object(name)
307
        cmd_data = CommandData(name)
308
309
        plugin_name = cmd.plugin_name()
310
        if plugin_name is not None:
311
            if (self.selected_plugins is not None and
312
                plugin not in self.selected_plugins):
0.32.9 by Martin von Gagern
Added test cases for DataCollector and BashCodeGen.
313
                return None
0.32.8 by Martin von Gagern
Refactor to increase modularity.
314
            plugin_data = self.data.plugins.get(plugin_name)
315
            if plugin_data is None:
316
                plugin_data = PluginData(plugin_name)
317
                self.data.plugins[plugin_name] = plugin_data
318
            cmd_data.plugin = plugin_data
319
        self.data.commands.append(cmd_data)
0.27.12 by Martin von Gagern
Take user-configured aliases into account.
320
321
        # Find all aliases to the command; both cmd-defined and user-defined.
322
        # We assume a user won't override one command with a different one,
323
        # but will choose completely new names or add options to existing
324
        # ones while maintaining the actual command name unchanged.
0.32.8 by Martin von Gagern
Refactor to increase modularity.
325
        cmd_data.aliases.extend(cmd.aliases)
326
        cmd_data.aliases.extend(sorted([useralias
327
            for cmdalias in cmd_data.aliases
328
            if cmdalias in self.user_aliases
329
            for useralias in self.user_aliases[cmdalias]
330
            if useralias not in cmd_data.aliases]))
331
0.27.2 by Martin von Gagern
First programmatic generation of completions.
332
        opts = cmd.options()
0.32.8 by Martin von Gagern
Refactor to increase modularity.
333
        for optname, opt in sorted(opts.iteritems()):
334
            cmd_data.options.extend(self.option(opt))
335
336
        if 'help' == name or 'help' in cmd.aliases:
337
            cmd_data.fixed_words = ('"$cmds %s"' %
338
                " ".join(sorted(help_topics.topic_registry.keys())))
339
0.32.9 by Martin von Gagern
Added test cases for DataCollector and BashCodeGen.
340
        return cmd_data
341
0.32.8 by Martin von Gagern
Refactor to increase modularity.
342
    def option(self, opt):
343
        optswitches = {}
344
        parser = option.get_optparser({opt.name: opt})
345
        parser = self.wrap_parser(optswitches, parser)
346
        optswitches.clear()
347
        opt.add_option(parser, opt.short_name())
348
        if isinstance(opt, option.RegistryOption) and opt.enum_switch:
349
            enum_switch = '--%s' % opt.name
350
            enum_data = optswitches.get(enum_switch)
351
            if enum_data:
0.27.41 by Martin von Gagern
Recover from ImportError when loading a registry.
352
                try:
0.32.8 by Martin von Gagern
Refactor to increase modularity.
353
                    enum_data.registry_keys = opt.registry.keys()
0.27.41 by Martin von Gagern
Recover from ImportError when loading a registry.
354
                except ImportError, e:
0.32.8 by Martin von Gagern
Refactor to increase modularity.
355
                    enum_data.error_messages.append(
356
                        "ERROR getting registry keys for '--%s': %s"
357
                        % (opt.name, str(e).split('\n')[0]))
358
        return sorted(optswitches.values())
359
360
    def wrap_container(self, optswitches, parser):
361
        def tweaked_add_option(*opts, **attrs):
362
            for name in opts:
363
                optswitches[name] = OptionData(name)
364
        parser.add_option = tweaked_add_option
365
        return parser
366
367
    def wrap_parser(self, optswitches, parser):
368
        orig_add_option_group = parser.add_option_group
369
        def tweaked_add_option_group(*opts, **attrs):
370
            return self.wrap_container(optswitches,
371
                orig_add_option_group(*opts, **attrs))
372
        parser.add_option_group = tweaked_add_option_group
373
        return self.wrap_container(optswitches, parser)
374
375
376
def bash_completion_function(out, function_name="_bzr", function_only=False,
377
                             debug=False,
378
                             no_plugins=False, selected_plugins=None):
379
    dc = DataCollector(no_plugins=no_plugins, selected_plugins=selected_plugins)
380
    data = dc.collect()
381
    cg = BashCodeGen(data, function_name=function_name, debug=debug)
0.27.7 by Martin von Gagern
Introduce --function-only option
382
    if function_only:
0.32.8 by Martin von Gagern
Refactor to increase modularity.
383
        res = cg.function()
384
    else:
385
        res = cg.script()
386
    out.write(res)
387
0.27.2 by Martin von Gagern
First programmatic generation of completions.
388
5147.5.11 by Martin von Gagern
Register command lazily.
389
class cmd_bash_completion(commands.Command):
5147.5.14 by Martin von Gagern
Assign user-visible docstrings to __doc__.
390
    __doc__ = """Generate a shell function for bash command line completion.
5147.5.11 by Martin von Gagern
Register command lazily.
391
392
    This command generates a shell function which can be used by bash to
393
    automatically complete the currently typed command when the user presses
394
    the completion key (usually tab).
395
    
396
    Commonly used like this:
397
        eval "`bzr bash-completion`"
398
    """
399
400
    takes_options = [
401
        option.Option("function-name", short_name="f", type=str, argname="name",
402
               help="Name of the generated function (default: _bzr)"),
403
        option.Option("function-only", short_name="o", type=None,
404
               help="Generate only the shell function, don't enable it"),
405
        option.Option("debug", type=None, hidden=True,
406
               help="Enable shell code useful for debugging"),
407
        option.ListOption("plugin", type=str, argname="name",
408
                # param_name="selected_plugins", # doesn't work, bug #387117
409
                help="Enable completions for the selected plugin"
410
                + " (default: all plugins)"),
411
        ]
412
413
    def run(self, **kwargs):
414
        import sys
415
        from bashcomp import bash_completion_function
416
        if 'plugin' in kwargs:
417
            # work around bug #387117 which prevents us from using param_name
5147.5.18 by Martin von Gagern
Include all plugins if --plugins isn't specified (fixes regression).
418
            if len(kwargs['plugin']) > 0:
419
                kwargs['selected_plugins'] = kwargs['plugin']
5147.5.11 by Martin von Gagern
Register command lazily.
420
            del kwargs['plugin']
421
        bash_completion_function(sys.stdout, **kwargs)
422
423
0.27.2 by Martin von Gagern
First programmatic generation of completions.
424
if __name__ == '__main__':
425
426
    import sys
427
    import locale
0.27.32 by Martin von Gagern
Added OptionParser for script usage.
428
    import optparse
429
0.27.38 by Martin von Gagern
Add --plugin switch to selectively include plugins.
430
    def plugin_callback(option, opt, value, parser):
431
        values = parser.values.selected_plugins
432
        if value == '-':
433
            del values[:]
434
        else:
435
            values.append(value)
436
5147.5.12 by Martin von Gagern
Use version of bzrlib. Drop meta.py.
437
    parser = optparse.OptionParser(usage="%prog [-f NAME] [-o]")
0.27.32 by Martin von Gagern
Added OptionParser for script usage.
438
    parser.add_option("--function-name", "-f", metavar="NAME",
439
                      help="Name of the generated function (default: _bzr)")
440
    parser.add_option("--function-only", "-o", action="store_true",
441
                      help="Generate only the shell function, don't enable it")
442
    parser.add_option("--debug", action="store_true",
443
                      help=optparse.SUPPRESS_HELP)
0.27.37 by Martin von Gagern
Introduce --no-plugins option to script execution mode.
444
    parser.add_option("--no-plugins", action="store_true",
445
                      help="Don't load any bzr plugins")
0.27.38 by Martin von Gagern
Add --plugin switch to selectively include plugins.
446
    parser.add_option("--plugin", metavar="NAME", type="string",
447
                      dest="selected_plugins", default=[],
448
                      action="callback", callback=plugin_callback,
449
                      help="Enable completions for the selected plugin"
450
                      + " (default: all plugins)")
0.27.32 by Martin von Gagern
Added OptionParser for script usage.
451
    (opts, args) = parser.parse_args()
452
    if args:
453
        parser.error("script does not take positional arguments")
454
    kwargs = dict()
455
    for name, value in opts.__dict__.iteritems():
456
        if value is not None:
457
            kwargs[name] = value
0.27.2 by Martin von Gagern
First programmatic generation of completions.
458
459
    locale.setlocale(locale.LC_ALL, '')
0.27.37 by Martin von Gagern
Introduce --no-plugins option to script execution mode.
460
    if not kwargs.get('no_plugins', False):
461
        plugin.load_plugins()
0.27.2 by Martin von Gagern
First programmatic generation of completions.
462
    commands.install_bzr_command_hooks()
0.27.32 by Martin von Gagern
Added OptionParser for script usage.
463
    bash_completion_function(sys.stdout, **kwargs)