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