/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to patches/plugins-no-plugins.patch

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-07-20 08:56:45 UTC
  • mfrom: (4526.9.23 apply-inventory-delta)
  • Revision ID: pqm@pqm.ubuntu.com-20090720085645-54mtgybxua0yx6hw
(robertc) Add checks for inventory deltas which try to ensure that
        deltas that are not an exact fit are not applied. (Robert
        Collins, bug 397705, bug 367633)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
*** added file 'bzrlib/plugin.py'
2
 
--- /dev/null
3
 
+++ bzrlib/plugin.py
4
 
@@ -0,0 +1,92 @@
5
 
+# Copyright (C) 2004, 2005 by Canonical Ltd
6
 
+
7
 
+# This program is free software; you can redistribute it and/or modify
8
 
+# it under the terms of the GNU General Public License as published by
9
 
+# the Free Software Foundation; either version 2 of the License, or
10
 
+# (at your option) any later version.
11
 
+
12
 
+# This program is distributed in the hope that it will be useful,
13
 
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
+# GNU 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, write to the Free Software
19
 
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
+
21
 
+
22
 
+# This module implements plug-in support.
23
 
+# Any python module in $BZR_PLUGIN_PATH will be imported upon initialization
24
 
+# of bzrlib (and then forgotten about).  In the plugin's main body, it should
25
 
+# update any bzrlib registries it wants to extend; for example, to add new
26
 
+# commands, import bzrlib.commands and add your new command to the
27
 
+# plugin_cmds variable.
28
 
+
29
 
+import sys, os, imp
30
 
+try:
31
 
+    set
32
 
+except NameError:
33
 
+    from sets import Set as set
34
 
+from bzrlib.trace import log_error
35
 
+
36
 
+
37
 
+def load_plugins():
38
 
+    """Find all python files which are plugins, and load them
39
 
+
40
 
+    The environment variable BZR_PLUGIN_PATH is considered a delimited set of
41
 
+    paths to look through. Each entry is searched for *.py files (and whatever
42
 
+    other extensions are used in the platform, such as *.pyd).
43
 
+    """
44
 
+    bzrpath = os.environ.get('BZR_PLUGIN_PATH', os.path.expanduser('~/.bzr/plugins'))
45
 
+
46
 
+    # The problem with imp.get_suffixes() is that it doesn't include
47
 
+    # .pyo which is technically valid
48
 
+    # It also means that "testmodule.so" will show up as both test and testmodule
49
 
+    # though it is only valid as 'test'
50
 
+    # but you should be careful, because "testmodule.py" loads as testmodule.
51
 
+    suffixes = imp.get_suffixes()
52
 
+    suffixes.append(('.pyo', 'rb', imp.PY_COMPILED))
53
 
+    package_entries = ['__init__.py', '__init__.pyc', '__init__.pyo']
54
 
+    for d in bzrpath.split(os.pathsep):
55
 
+        # going trough them one by one allows different plugins with the same
56
 
+        # filename in different directories in the path
57
 
+        if not d:
58
 
+            continue
59
 
+        plugin_names = set()
60
 
+        if not os.path.isdir(d):
61
 
+            continue
62
 
+        for f in os.listdir(d):
63
 
+            path = os.path.join(d, f)
64
 
+            if os.path.isdir(path):
65
 
+                for entry in package_entries:
66
 
+                    # This directory should be a package, and thus added to
67
 
+                    # the list
68
 
+                    if os.path.isfile(os.path.join(path, entry)):
69
 
+                        break
70
 
+                else: # This directory is not a package
71
 
+                    continue
72
 
+            else:
73
 
+                for suffix_info in suffixes:
74
 
+                    if f.endswith(suffix_info[0]):
75
 
+                        f = f[:-len(suffix_info[0])]
76
 
+                        if suffix_info[2] == imp.C_EXTENSION and f.endswith('module'):
77
 
+                            f = f[:-len('module')]
78
 
+                        break
79
 
+                else:
80
 
+                    continue
81
 
+            plugin_names.add(f)
82
 
+
83
 
+        plugin_names = list(plugin_names)
84
 
+        plugin_names.sort()
85
 
+        for name in plugin_names:
86
 
+            try:
87
 
+                plugin_info = imp.find_module(name, [d])
88
 
+                try:
89
 
+                    plugin = imp.load_module('bzrlib.plugin.' + name,
90
 
+                                             *plugin_info)
91
 
+                finally:
92
 
+                    if plugin_info[0] is not None:
93
 
+                        plugin_info[0].close()
94
 
+            except Exception, e:
95
 
+                log_error('Unable to load plugin: %r from %r\n%s' % (name, d, e))
96
 
+
97
 
 
98
 
*** modified file 'bzrlib/__init__.py'
99
 
--- bzrlib/__init__.py
100
 
+++ bzrlib/__init__.py
101
 
@@ -23,6 +23,7@@
102
 
 from diff import compare_trees
103
 
 from trace import mutter, warning, open_tracefile
104
 
 from log import show_log
105
 
+from plugin import load_plugins
106
 
 import add
107
 
 
108
 
 BZRDIR = ".bzr"
109
 
@@ -62,4 +63,4 @@
110
 
             return None
111
 
     except BzrError:
112
 
         return None
113
 
-
114
 
+
115
 
 
116
 
*** modified file 'bzrlib/commands.py'
117
 
--- bzrlib/commands.py
118
 
+++ bzrlib/commands.py
119
 
@@ -24,6 +24,24 @@
120
 
 from bzrlib.osutils import quotefn
121
 
 from bzrlib import Branch, Inventory, InventoryEntry, BZRDIR, \
122
 
      format_date
123
 
+
124
 
+
125
 
+plugin_cmds = {}
126
 
+
127
 
+
128
 
+def register_plugin_command(cmd):
129
 
+    "Utility function to help register a command"
130
 
+    global plugin_cmds
131
 
+    k = cmd.__name__
132
 
+    if k.startswith("cmd_"):
133
 
+        k_unsquished = _unsquish_command_name(k)
134
 
+    else:
135
 
+        k_unsquished = k
136
 
+    if not plugin_cmds.has_key(k_unsquished):
137
 
+        plugin_cmds[k_unsquished] = cmd
138
 
+    else:
139
 
+        log_error('Two plugins defined the same command: %r' % k)
140
 
+        log_error('Not loading the one in %r' % sys.modules[cmd.__module__])
141
 
 
142
 
 
143
 
 def _squish_command_name(cmd):
144
 
@@ -68,100 +86,34 @@
145
 
         revs = int(revstr)
146
 
     return revs
147
 
 
148
 
-def _find_plugins():
149
 
-    """Find all python files which are plugins, and load their commands
150
 
-    to add to the list of "all commands"
151
 
-
152
 
-    The environment variable BZRPATH is considered a delimited set of
153
 
-    paths to look through. Each entry is searched for *.py files.
154
 
-    If a directory is found, it is also searched, but they are
155
 
-    not searched recursively. This allows you to revctl the plugins.
156
 
-
157
 
-    Inside the plugin should be a series of cmd_* function, which inherit from
158
 
-    the bzrlib.commands.Command class.
159
 
-    """
160
 
-    bzrpath = os.environ.get('BZRPLUGINPATH', '')
161
 
-
162
 
-    plugin_cmds = {}
163
 
-    if not bzrpath:
164
 
-        return plugin_cmds
165
 
-    _platform_extensions = {
166
 
-        'win32':'.pyd',
167
 
-        'cygwin':'.dll',
168
 
-        'darwin':'.dylib',
169
 
-        'linux2':'.so'
170
 
-        }
171
 
-    if _platform_extensions.has_key(sys.platform):
172
 
-        platform_extension = _platform_extensions[sys.platform]
173
 
-    else:
174
 
-        platform_extension = None
175
 
-    for d in bzrpath.split(os.pathsep):
176
 
-        plugin_names = {} # This should really be a set rather than a dict
177
 
-        for f in os.listdir(d):
178
 
-            if f.endswith('.py'):
179
 
-                f = f[:-3]
180
 
-            elif f.endswith('.pyc') or f.endswith('.pyo'):
181
 
-                f = f[:-4]
182
 
-            elif platform_extension and f.endswith(platform_extension):
183
 
-                f = f[:-len(platform_extension)]
184
 
-                if f.endswidth('module'):
185
 
-                    f = f[:-len('module')]
186
 
-            else:
187
 
-                continue
188
 
-            if not plugin_names.has_key(f):
189
 
-                plugin_names[f] = True
190
 
-
191
 
-        plugin_names = plugin_names.keys()
192
 
-        plugin_names.sort()
193
 
-        try:
194
 
-            sys.path.insert(0, d)
195
 
-            for name in plugin_names:
196
 
-                try:
197
 
-                    old_module = None
198
 
-                    try:
199
 
-                        if sys.modules.has_key(name):
200
 
-                            old_module = sys.modules[name]
201
 
-                            del sys.modules[name]
202
 
-                        plugin = __import__(name, locals())
203
 
-                        for k in dir(plugin):
204
 
-                            if k.startswith('cmd_'):
205
 
-                                k_unsquished = _unsquish_command_name(k)
206
 
-                                if not plugin_cmds.has_key(k_unsquished):
207
 
-                                    plugin_cmds[k_unsquished] = getattr(plugin, k)
208
 
-                                else:
209
 
-                                    log_error('Two plugins defined the same command: %r' % k)
210
 
-                                    log_error('Not loading the one in %r in dir %r' % (name, d))
211
 
-                    finally:
212
 
-                        if old_module:
213
 
-                            sys.modules[name] = old_module
214
 
-                except ImportError, e:
215
 
-                    log_error('Unable to load plugin: %r from %r\n%s' % (name, d, e))
216
 
-        finally:
217
 
-            sys.path.pop(0)
218
 
-    return plugin_cmds
219
 
-
220
 
-def _get_cmd_dict(include_plugins=True):
221
 
+def _get_cmd_dict(plugins_override=True):
222
 
     d = {}
223
 
     for k, v in globals().iteritems():
224
 
         if k.startswith("cmd_"):
225
 
             d[_unsquish_command_name(k)] = v
226
 
-    if include_plugins:
227
 
-        d.update(_find_plugins())
228
 
+    # If we didn't load plugins, the plugin_cmds dict will be empty
229
 
+    if plugins_override:
230
 
+        d.update(plugin_cmds)
231
 
+    else:
232
 
+        d2 = {}
233
 
+        d2.update(plugin_cmds)
234
 
+        d2.update(d)
235
 
+        d = d2
236
 
     return d
237
 
 
238
 
-def get_all_cmds(include_plugins=True):
239
 
+def get_all_cmds(plugins_override=True):
240
 
     """Return canonical name and class for all registered commands."""
241
 
-    for k, v in _get_cmd_dict(include_plugins=include_plugins).iteritems():
242
 
+    for k, v in _get_cmd_dict(plugins_override=plugins_override).iteritems():
243
 
         yield k,v
244
 
 
245
 
 
246
 
-def get_cmd_class(cmd,include_plugins=True):
247
 
+def get_cmd_class(cmd, plugins_override=True):
248
 
     """Return the canonical name and command class for a command.
249
 
     """
250
 
     cmd = str(cmd)                      # not unicode
251
 
 
252
 
     # first look up this command under the specified name
253
 
-    cmds = _get_cmd_dict(include_plugins=include_plugins)
254
 
+    cmds = _get_cmd_dict(plugins_override=plugins_override)
255
 
     try:
256
 
         return cmd, cmds[cmd]
257
 
     except KeyError:
258
 
@@ -1461,6 +1413,75 @@
259
 
     return argdict
260
 
 
261
 
 
262
 
+def _parse_master_args(argv):
263
 
+    """Parse the arguments that always go with the original command.
264
 
+    These are things like bzr --no-plugins, etc.
265
 
+
266
 
+    There are now 2 types of option flags. Ones that come *before* the command,
267
 
+    and ones that come *after* the command.
268
 
+    Ones coming *before* the command are applied against all possible commands.
269
 
+    And are generally applied before plugins are loaded.
270
 
+
271
 
+    The current list are:
272
 
+        --builtin   Allow plugins to load, but don't let them override builtin commands,
273
 
+                    they will still be allowed if they do not override a builtin.
274
 
+        --no-plugins    Don't load any plugins. This lets you get back to official source
275
 
+                        behavior.
276
 
+        --profile   Enable the hotspot profile before running the command.
277
 
+                    For backwards compatibility, this is also a non-master option.
278
 
+        --version   Spit out the version of bzr that is running and exit.
279
 
+                    This is also a non-master option.
280
 
+        --help      Run help and exit, also a non-master option (I think that should stay, though)
281
 
+
282
 
+    >>> argv, opts = _parse_master_args(['bzr', '--test'])
283
 
+    Traceback (most recent call last):
284
 
+    ...
285
 
+    BzrCommandError: Invalid master option: 'test'
286
 
+    >>> argv, opts = _parse_master_args(['bzr', '--version', 'command'])
287
 
+    >>> print argv
288
 
+    ['command']
289
 
+    >>> print opts['version']
290
 
+    True
291
 
+    >>> argv, opts = _parse_master_args(['bzr', '--profile', 'command', '--more-options'])
292
 
+    >>> print argv
293
 
+    ['command', '--more-options']
294
 
+    >>> print opts['profile']
295
 
+    True
296
 
+    >>> argv, opts = _parse_master_args(['bzr', '--no-plugins', 'command'])
297
 
+    >>> print argv
298
 
+    ['command']
299
 
+    >>> print opts['no-plugins']
300
 
+    True
301
 
+    >>> print opts['profile']
302
 
+    False
303
 
+    >>> argv, opts = _parse_master_args(['bzr', 'command', '--profile'])
304
 
+    >>> print argv
305
 
+    ['command', '--profile']
306
 
+    >>> print opts['profile']
307
 
+    False
308
 
+    """
309
 
+    master_opts = {'builtin':False,
310
 
+        'no-plugins':False,
311
 
+        'version':False,
312
 
+        'profile':False,
313
 
+        'help':False
314
 
+    }
315
 
+
316
 
+    # This is the point where we could hook into argv[0] to determine
317
 
+    # what front-end is supposed to be run
318
 
+    # For now, we are just ignoring it.
319
 
+    cmd_name = argv.pop(0)
320
 
+    for arg in argv[:]:
321
 
+        if arg[:2] != '--': # at the first non-option, we return the rest
322
 
+            break
323
 
+        arg = arg[2:] # Remove '--'
324
 
+        if arg not in master_opts:
325
 
+            # We could say that this is not an error, that we should
326
 
+            # just let it be handled by the main section instead
327
 
+            raise BzrCommandError('Invalid master option: %r' % arg)
328
 
+        argv.pop(0) # We are consuming this entry
329
 
+        master_opts[arg] = True
330
 
+    return argv, master_opts
331
 
 
332
 
 def run_bzr(argv):
333
 
     """Execute a command.
334
 
@@ -1470,22 +1491,21 @@
335
 
     """
336
 
     argv = [a.decode(bzrlib.user_encoding) for a in argv]
337
 
 
338
 
-    include_plugins=True
339
 
     try:
340
 
-        args, opts = parse_args(argv[1:])
341
 
-        if 'help' in opts:
342
 
+        argv, master_opts = _parse_master_args(argv)
343
 
+        if not master_opts['no-plugins']:
344
 
+            bzrlib.load_plugins()
345
 
+        args, opts = parse_args(argv)
346
 
+        if 'help' in opts or master_opts['help']:
347
 
             import help
348
 
             if args:
349
 
                 help.help(args[0])
350
 
             else:
351
 
                 help.help()
352
 
             return 0
353
 
-        elif 'version' in opts:
354
 
+        elif 'version' in opts or master_opts['version']:
355
 
             show_version()
356
 
             return 0
357
 
-        elif args and args[0] == 'builtin':
358
 
-            include_plugins=False
359
 
-            args = args[1:]
360
 
         cmd = str(args.pop(0))
361
 
     except IndexError:
362
 
         import help
363
 
@@ -1493,14 +1513,15 @@
364
 
         return 1
365
 
 
366
 
 
367
 
-    canonical_cmd, cmd_class = get_cmd_class(cmd,include_plugins=include_plugins)
368
 
-
369
 
-    # global option
370
 
+    plugins_override = not (master_opts['builtin'])
371
 
+    canonical_cmd, cmd_class = get_cmd_class(cmd, plugins_override=plugins_override)
372
 
+
373
 
+    profile = master_opts['profile']
374
 
+    # For backwards compatibility, I would rather stick with --profile being a
375
 
+    # master/global option
376
 
     if 'profile' in opts:
377
 
         profile = True
378
 
         del opts['profile']
379
 
-    else:
380
 
-        profile = False
381
 
 
382
 
     # check options are reasonable
383
 
     allowed = cmd_class.takes_options
384
 
 
385
 
*** modified file 'testbzr'
386
 
--- testbzr
387
 
+++ testbzr
388
 
@@ -149,6 +149,7 @@
389
 
     """Run a test involving creating a plugin to load,
390
 
     and making sure it is seen properly.
391
 
     """
392
 
+    orig_help = backtick('bzr help commands') # No plugins yet
393
 
     mkdir('plugin_test')
394
 
     f = open(os.path.join('plugin_test', 'myplug.py'), 'wb')
395
 
     f.write("""import bzrlib, bzrlib.commands
396
 
@@ -157,24 +158,36 @@
397
 
     aliases = ['mplg']
398
 
     def run(self):
399
 
         print 'Hello from my plugin'
400
 
+class cmd_myplug_with_opt(bzrlib.commands.Command):
401
 
+    '''A simple plugin that requires a special option'''
402
 
+    takes_options = ['aspecialoptionthatdoesntexist']
403
 
+    def run(self, aspecialoptionthatdoesntexist=None):
404
 
+        print 'Found: %s' % aspecialoptionthatdoesntexist
405
 
+
406
 
+bzrlib.commands.register_plugin_command(cmd_myplug)
407
 
+bzrlib.commands.register_plugin_command(cmd_myplug_with_opt)
408
 
+bzrlib.commands.OPTIONS['aspecialoptionthatdoesntexist'] = str
409
 
 """)
410
 
     f.close()
411
 
 
412
 
-    os.environ['BZRPLUGINPATH'] = os.path.abspath('plugin_test')
413
 
-    help = backtick('bzr help commands')
414
 
+    os.environ['BZR_PLUGIN_PATH'] = os.path.abspath('plugin_test')
415
 
+    help = backtick('bzr help commands') #Help with user-visible plugins
416
 
     assert help.find('myplug') != -1
417
 
     assert help.find('Just a simple test plugin.') != -1
418
 
 
419
 
 
420
 
     assert backtick('bzr myplug') == 'Hello from my plugin\n'
421
 
     assert backtick('bzr mplg') == 'Hello from my plugin\n'
422
 
+    assert backtick('bzr myplug-with-opt') == 'Found: None\n'
423
 
+    assert backtick('bzr myplug-with-opt --aspecialoptionthatdoesntexist=2') == 'Found: 2\n'
424
 
 
425
 
     f = open(os.path.join('plugin_test', 'override.py'), 'wb')
426
 
     f.write("""import bzrlib, bzrlib.commands
427
 
-class cmd_commit(bzrlib.commands.cmd_commit):
428
 
-    '''Commit changes into a new revision.'''
429
 
+class cmd_revno(bzrlib.commands.cmd_revno):
430
 
+    '''Show current revision number.'''
431
 
     def run(self, *args, **kwargs):
432
 
         print "I'm sorry dave, you can't do that"
433
 
+        return 1
434
 
 
435
 
 class cmd_help(bzrlib.commands.cmd_help):
436
 
     '''Show help on a command or other topic.'''
437
 
@@ -182,16 +195,67 @@
438
 
         print "You have been overridden"
439
 
         bzrlib.commands.cmd_help.run(self, *args, **kwargs)
440
 
 
441
 
+bzrlib.commands.register_plugin_command(cmd_revno)
442
 
+bzrlib.commands.register_plugin_command(cmd_help)
443
 
 """)
444
 
     f.close()
445
 
 
446
 
-    newhelp = backtick('bzr help commands')
447
 
+    newhelp = backtick('bzr help commands') # Help with no new commands,
448
 
     assert newhelp.startswith('You have been overridden\n')
449
 
     # We added a line, but the rest should work
450
 
     assert newhelp[25:] == help
451
 
-
452
 
-    assert backtick('bzr commit -m test') == "I'm sorry dave, you can't do that\n"
453
 
-
454
 
+    # Make sure we can get back to the original command
455
 
+    # Not overridden, and no extra commands present
456
 
+    assert backtick('bzr --builtin help commands') == help
457
 
+    assert backtick('bzr --no-plugins help commands') == orig_help
458
 
+
459
 
+    assert backtick('bzr revno', retcode=1) == "I'm sorry dave, you can't do that\n"
460
 
+
461
 
+    print_txt = '** Loading noop plugin'
462
 
+    f = open(os.path.join('plugin_test', 'loading.py'), 'wb')
463
 
+    f.write("""import bzrlib, bzrlib.commands
464
 
+class cmd_noop(bzrlib.commands.Command):
465
 
+    def run(self, *args, **kwargs):
466
 
+        pass
467
 
+
468
 
+print %r
469
 
+bzrlib.commands.register_plugin_command(cmd_noop)
470
 
+""" % print_txt)
471
 
+    f.close()
472
 
+    print_txt += '\n'
473
 
+
474
 
+    # Check that --builtin still loads the plugin, and enables it as
475
 
+    # an extra command, but not as an override
476
 
+    # and that --no-plugins doesn't load the command at all
477
 
+    assert backtick('bzr noop') == print_txt
478
 
+    assert backtick('bzr --builtin help')[:len(print_txt)] == print_txt
479
 
+    assert backtick('bzr --no-plugins help')[:len(print_txt)] != print_txt
480
 
+    runcmd('bzr revno', retcode=1)
481
 
+    runcmd('bzr --builtin revno', retcode=0)
482
 
+    runcmd('bzr --no-plugins revno', retcode=0)
483
 
+    runcmd('bzr --builtin noop', retcode=0)
484
 
+    runcmd('bzr --no-plugins noop', retcode=1)
485
 
+
486
 
+    # Check that packages can also be loaded
487
 
+    test_str = 'packages work'
488
 
+    os.mkdir(os.path.join('plugin_test', 'testpkg'))
489
 
+    f = open(os.path.join('plugin_test', 'testpkg', '__init__.py'), 'wb')
490
 
+    f.write("""import bzrlib, bzrlib.commands
491
 
+class testpkgcmd(bzrlib.commands.Command):
492
 
+    def run(self, *args, **kwargs):
493
 
+        print %r
494
 
+
495
 
+bzrlib.commands.register_plugin_command(testpkgcmd)
496
 
+""" % test_str)
497
 
+    f.close()
498
 
+    test_str += '\n'
499
 
+    assert backtick('bzr testpkgcmd') == print_txt + test_str
500
 
+    runcmd('bzr --no-plugins testpkgcmd', retcode=1)
501
 
+
502
 
+    # Make sure that setting BZR_PLUGIN_PATH to empty is the same as using --no-plugins
503
 
+    os.environ['BZR_PLUGIN_PATH'] = ''
504
 
+    assert backtick('bzr help commands') == orig_help
505
 
+
506
 
     shutil.rmtree('plugin_test')
507
 
 
508
 
 try:
509
 
@@ -221,6 +285,9 @@
510
 
 
511
 
     runcmd(['mkdir', TESTDIR])
512
 
     cd(TESTDIR)
513
 
+    # This means that any command that is naively run in this directory
514
 
+    # Won't affect the parent directory.
515
 
+    runcmd('bzr init')
516
 
     test_root = os.getcwd()
517
 
 
518
 
     progress("introductory commands")
519