/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
329 by Martin Pool
- refactor command functions into command classes
1
# Copyright (C) 2004, 2005 by Canonical Ltd
1 by mbp at sourcefrog
import from baz patch-364
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
18
338 by Martin Pool
- cleanup of some imports
19
import sys, os, time, os.path
1 by mbp at sourcefrog
import from baz patch-364
20
from sets import Set
21
22
import bzrlib
23
from bzrlib.trace import mutter, note, log_error
329 by Martin Pool
- refactor command functions into command classes
24
from bzrlib.errors import bailout, BzrError, BzrCheckError, BzrCommandError
1 by mbp at sourcefrog
import from baz patch-364
25
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
26
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
27
from bzrlib.revision import Revision
28
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
29
     format_date
30
31
350 by Martin Pool
- refactor command aliases into command classes
32
def _squish_command_name(cmd):
33
    return 'cmd_' + cmd.replace('-', '_')
34
35
36
def _unsquish_command_name(cmd):
37
    assert cmd.startswith("cmd_")
38
    return cmd[4:].replace('_','-')
39
351 by Martin Pool
- Split out help functions into bzrlib.help
40
def get_all_cmds():
350 by Martin Pool
- refactor command aliases into command classes
41
    """Return canonical name and class for all registered commands."""
42
    for k, v in globals().iteritems():
43
        if k.startswith("cmd_"):
44
            yield _unsquish_command_name(k), v
45
351 by Martin Pool
- Split out help functions into bzrlib.help
46
def get_cmd_class(cmd):
350 by Martin Pool
- refactor command aliases into command classes
47
    """Return the canonical name and command class for a command.
48
    """
49
    cmd = str(cmd)                      # not unicode
50
51
    # first look up this command under the specified name
272 by Martin Pool
- Add command aliases
52
    try:
350 by Martin Pool
- refactor command aliases into command classes
53
        return cmd, globals()[_squish_command_name(cmd)]
272 by Martin Pool
- Add command aliases
54
    except KeyError:
350 by Martin Pool
- refactor command aliases into command classes
55
        pass
56
57
    # look for any command which claims this as an alias
351 by Martin Pool
- Split out help functions into bzrlib.help
58
    for cmdname, cmdclass in get_all_cmds():
350 by Martin Pool
- refactor command aliases into command classes
59
        if cmd in cmdclass.aliases:
60
            return cmdname, cmdclass
422 by Martin Pool
- External-command patch from mpe
61
62
    cmdclass = ExternalCommand.find_command(cmd)
63
    if cmdclass:
64
        return cmd, cmdclass
65
66
    raise BzrCommandError("unknown command %r" % cmd)
272 by Martin Pool
- Add command aliases
67
329 by Martin Pool
- refactor command functions into command classes
68
69
class Command:
70
    """Base class for commands.
71
72
    The docstring for an actual command should give a single-line
73
    summary, then a complete description of the command.  A grammar
74
    description will be inserted.
75
76
    takes_args
77
        List of argument forms, marked with whether they are optional,
78
        repeated, etc.
79
80
    takes_options
81
        List of options that may be given for this command.
82
83
    hidden
84
        If true, this command isn't advertised.
85
    """
86
    aliases = []
87
    
88
    takes_args = []
89
    takes_options = []
90
91
    hidden = False
92
    
93
    def __init__(self, options, arguments):
94
        """Construct and run the command.
95
96
        Sets self.status to the return value of run()."""
97
        assert isinstance(options, dict)
98
        assert isinstance(arguments, dict)
99
        cmdargs = options.copy()
100
        cmdargs.update(arguments)
101
        assert self.__doc__ != Command.__doc__, \
102
               ("No help message set for %r" % self)
103
        self.status = self.run(**cmdargs)
104
105
    
106
    def run(self):
107
        """Override this in sub-classes.
108
109
        This is invoked with the options and arguments bound to
110
        keyword parameters.
111
337 by Martin Pool
- Clarify return codes from command objects
112
        Return 0 or None if the command was successful, or a shell
113
        error code if not.
329 by Martin Pool
- refactor command functions into command classes
114
        """
337 by Martin Pool
- Clarify return codes from command objects
115
        return 0
329 by Martin Pool
- refactor command functions into command classes
116
117
422 by Martin Pool
- External-command patch from mpe
118
class ExternalCommand(Command):
119
    """Class to wrap external commands.
120
121
    We cheat a little here, when get_cmd_class() calls us we actually give it back
122
    an object we construct that has the appropriate path, help, options etc for the
123
    specified command.
124
125
    When run_bzr() tries to instantiate that 'class' it gets caught by the __call__
126
    method, which we override to call the Command.__init__ method. That then calls
127
    our run method which is pretty straight forward.
128
129
    The only wrinkle is that we have to map bzr's dictionary of options and arguments
130
    back into command line options and arguments for the script.
131
    """
132
133
    def find_command(cls, cmd):
134
        bzrpath = os.environ.get('BZRPATH', '')
135
136
        for dir in bzrpath.split(':'):
137
            path = os.path.join(dir, cmd)
138
            if os.path.isfile(path):
139
                return ExternalCommand(path)
140
141
        return None
142
143
    find_command = classmethod(find_command)
144
145
    def __init__(self, path):
146
        self.path = path
147
148
        pipe = os.popen('%s --bzr-usage' % path, 'r')
149
        self.takes_options = pipe.readline().split()
150
        self.takes_args = pipe.readline().split()
151
        pipe.close()
152
153
        pipe = os.popen('%s --bzr-help' % path, 'r')
154
        self.__doc__ = pipe.read()
155
        pipe.close()
156
157
    def __call__(self, options, arguments):
158
        Command.__init__(self, options, arguments)
159
        return self
160
161
    def run(self, **kargs):
162
        opts = []
163
        args = []
164
165
        keys = kargs.keys()
166
        keys.sort()
167
        for name in keys:
168
            value = kargs[name]
169
            if OPTIONS.has_key(name):
170
                # it's an option
171
                opts.append('--%s' % name)
172
                if value is not None and value is not True:
173
                    opts.append(str(value))
174
            else:
175
                # it's an arg, or arg list
176
                if type(value) is not list:
177
                    value = [value]
178
                for v in value:
179
                    if v is not None:
180
                        args.append(str(v))
181
182
        self.status = os.spawnv(os.P_WAIT, self.path, [self.path] + opts + args)
183
        return self.status
184
329 by Martin Pool
- refactor command functions into command classes
185
186
class cmd_status(Command):
1 by mbp at sourcefrog
import from baz patch-364
187
    """Display status summary.
188
189
    For each file there is a single line giving its file state and name.
190
    The name is that in the current revision unless it is deleted or
191
    missing, in which case the old name is shown.
192
    """
404 by Martin Pool
- bzr status now optionally takes filenames to check
193
    takes_args = ['file*']
329 by Martin Pool
- refactor command functions into command classes
194
    takes_options = ['all']
350 by Martin Pool
- refactor command aliases into command classes
195
    aliases = ['st', 'stat']
329 by Martin Pool
- refactor command functions into command classes
196
    
404 by Martin Pool
- bzr status now optionally takes filenames to check
197
    def run(self, all=False, file_list=None):
406 by Martin Pool
- bzr status only needs a read-lock
198
        b = Branch('.', lock_mode='r')
199
        b.show_status(show_all=all, file_list=file_list)
329 by Martin Pool
- refactor command functions into command classes
200
201
202
class cmd_cat_revision(Command):
203
    """Write out metadata for a revision."""
204
205
    hidden = True
206
    takes_args = ['revision_id']
207
    
208
    def run(self, revision_id):
209
        Branch('.').get_revision(revision_id).write_xml(sys.stdout)
210
211
212
class cmd_revno(Command):
213
    """Show current revision number.
214
215
    This is equal to the number of revisions on this branch."""
216
    def run(self):
217
        print Branch('.').revno()
218
219
    
220
class cmd_add(Command):
70 by mbp at sourcefrog
Prepare for smart recursive add.
221
    """Add specified files or directories.
222
223
    In non-recursive mode, all the named items are added, regardless
224
    of whether they were previously ignored.  A warning is given if
225
    any of the named files are already versioned.
226
227
    In recursive mode (the default), files are treated the same way
228
    but the behaviour for directories is different.  Directories that
229
    are already versioned do not give a warning.  All directories,
230
    whether already versioned or not, are searched for files or
231
    subdirectories that are neither versioned or ignored, and these
232
    are added.  This search proceeds recursively into versioned
233
    directories.
234
235
    Therefore simply saying 'bzr add .' will version all files that
236
    are currently unknown.
279 by Martin Pool
todo
237
238
    TODO: Perhaps adding a file whose directly is not versioned should
239
    recursively add that parent, rather than giving an error?
70 by mbp at sourcefrog
Prepare for smart recursive add.
240
    """
329 by Martin Pool
- refactor command functions into command classes
241
    takes_args = ['file+']
242
    takes_options = ['verbose']
243
    
244
    def run(self, file_list, verbose=False):
245
        bzrlib.add.smart_add(file_list, verbose)
246
247
386 by Martin Pool
- Typo (reported by uws)
248
class cmd_relpath(Command):
329 by Martin Pool
- refactor command functions into command classes
249
    """Show path of a file relative to root"""
392 by Martin Pool
- fix relpath and add tests
250
    takes_args = ['filename']
329 by Martin Pool
- refactor command functions into command classes
251
    
392 by Martin Pool
- fix relpath and add tests
252
    def run(self, filename):
253
        print Branch(filename).relpath(filename)
329 by Martin Pool
- refactor command functions into command classes
254
255
256
257
class cmd_inventory(Command):
258
    """Show inventory of the current working copy or a revision."""
259
    takes_options = ['revision']
260
    
261
    def run(self, revision=None):
262
        b = Branch('.')
263
        if revision == None:
264
            inv = b.read_working_inventory()
265
        else:
266
            inv = b.get_revision_inventory(b.lookup_revision(revision))
267
268
        for path, entry in inv.iter_entries():
269
            print '%-50s %s' % (entry.file_id, path)
270
271
272
class cmd_move(Command):
273
    """Move files to a different directory.
274
275
    examples:
276
        bzr move *.txt doc
277
278
    The destination must be a versioned directory in the same branch.
279
    """
280
    takes_args = ['source$', 'dest']
281
    def run(self, source_list, dest):
282
        b = Branch('.')
283
284
        b.move([b.relpath(s) for s in source_list], b.relpath(dest))
285
286
287
class cmd_rename(Command):
168 by mbp at sourcefrog
new "rename" command
288
    """Change the name of an entry.
289
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
290
    examples:
291
      bzr rename frob.c frobber.c
292
      bzr rename src/frob.c lib/frob.c
293
294
    It is an error if the destination name exists.
295
296
    See also the 'move' command, which moves files into a different
297
    directory without changing their name.
298
299
    TODO: Some way to rename multiple files without invoking bzr for each
300
    one?"""
329 by Martin Pool
- refactor command functions into command classes
301
    takes_args = ['from_name', 'to_name']
168 by mbp at sourcefrog
new "rename" command
302
    
329 by Martin Pool
- refactor command functions into command classes
303
    def run(self, from_name, to_name):
304
        b = Branch('.')
305
        b.rename_one(b.relpath(from_name), b.relpath(to_name))
306
307
308
309
class cmd_renames(Command):
164 by mbp at sourcefrog
new 'renames' command
310
    """Show list of renamed files.
311
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
312
    TODO: Option to show renames between two historical versions.
313
314
    TODO: Only show renames under dir, rather than in the whole branch.
315
    """
329 by Martin Pool
- refactor command functions into command classes
316
    takes_args = ['dir?']
317
318
    def run(self, dir='.'):
319
        b = Branch(dir)
320
        old_inv = b.basis_tree().inventory
321
        new_inv = b.read_working_inventory()
322
323
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
324
        renames.sort()
325
        for old_name, new_name in renames:
326
            print "%s => %s" % (old_name, new_name)        
327
328
329
class cmd_info(Command):
330
    """Show statistical information for this branch"""
331
    def run(self):
332
        import info
333
        info.show_info(Branch('.'))        
334
335
336
class cmd_remove(Command):
337
    """Make a file unversioned.
338
339
    This makes bzr stop tracking changes to a versioned file.  It does
340
    not delete the working copy.
341
    """
342
    takes_args = ['file+']
343
    takes_options = ['verbose']
344
    
345
    def run(self, file_list, verbose=False):
346
        b = Branch(file_list[0])
347
        b.remove([b.relpath(f) for f in file_list], verbose=verbose)
348
349
350
class cmd_file_id(Command):
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
351
    """Print file_id of a particular file or directory.
352
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
353
    The file_id is assigned when the file is first added and remains the
354
    same through all revisions where the file exists, even when it is
355
    moved or renamed.
356
    """
329 by Martin Pool
- refactor command functions into command classes
357
    hidden = True
358
    takes_args = ['filename']
359
    def run(self, filename):
360
        b = Branch(filename)
361
        i = b.inventory.path2id(b.relpath(filename))
362
        if i == None:
363
            bailout("%r is not a versioned file" % filename)
364
        else:
365
            print i
366
367
368
class cmd_file_path(Command):
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
369
    """Print path of file_ids to a file or directory.
370
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
371
    This prints one line for each directory down to the target,
372
    starting at the branch root."""
329 by Martin Pool
- refactor command functions into command classes
373
    hidden = True
374
    takes_args = ['filename']
375
    def run(self, filename):
376
        b = Branch(filename)
377
        inv = b.inventory
378
        fid = inv.path2id(b.relpath(filename))
379
        if fid == None:
380
            bailout("%r is not a versioned file" % filename)
381
        for fip in inv.get_idpath(fid):
382
            print fip
383
384
385
class cmd_revision_history(Command):
386
    """Display list of revision ids on this branch."""
387
    def run(self):
388
        for patchid in Branch('.').revision_history():
389
            print patchid
390
391
392
class cmd_directories(Command):
393
    """Display list of versioned directories in this branch."""
394
    def run(self):
395
        for name, ie in Branch('.').read_working_inventory().directories():
396
            if name == '':
397
                print '.'
398
            else:
399
                print name
400
401
402
class cmd_init(Command):
403
    """Make a directory into a versioned branch.
404
405
    Use this to create an empty branch, or before importing an
406
    existing project.
407
408
    Recipe for importing a tree of files:
409
        cd ~/project
410
        bzr init
411
        bzr add -v .
412
        bzr status
413
        bzr commit -m 'imported project'
414
    """
415
    def run(self):
416
        Branch('.', init=True)
417
418
419
class cmd_diff(Command):
420
    """Show differences in working tree.
421
    
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
422
    If files are listed, only the changes in those files are listed.
423
    Otherwise, all changes for the tree are listed.
424
425
    TODO: Given two revision arguments, show the difference between them.
426
427
    TODO: Allow diff across branches.
428
429
    TODO: Option to use external diff command; could be GNU diff, wdiff,
430
          or a graphical diff.
431
276 by Martin Pool
Doc
432
    TODO: Python difflib is not exactly the same as unidiff; should
433
          either fix it up or prefer to use an external diff.
434
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
435
    TODO: If a directory is given, diff everything under that.
436
276 by Martin Pool
Doc
437
    TODO: Selected-file diff is inefficient and doesn't show you
438
          deleted files.
278 by Martin Pool
- Better workaround for trailing newlines in diffs
439
440
    TODO: This probably handles non-Unix newlines poorly.
329 by Martin Pool
- refactor command functions into command classes
441
    """
442
    
443
    takes_args = ['file*']
444
    takes_options = ['revision']
350 by Martin Pool
- refactor command aliases into command classes
445
    aliases = ['di']
329 by Martin Pool
- refactor command functions into command classes
446
447
    def run(self, revision=None, file_list=None):
448
        from bzrlib.diff import show_diff
449
    
450
        show_diff(Branch('.'), revision, file_list)
451
452
453
class cmd_deleted(Command):
135 by mbp at sourcefrog
Simple new 'deleted' command
454
    """List files deleted in the working tree.
455
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
456
    TODO: Show files deleted since a previous revision, or between two revisions.
135 by mbp at sourcefrog
Simple new 'deleted' command
457
    """
329 by Martin Pool
- refactor command functions into command classes
458
    def run(self, show_ids=False):
459
        b = Branch('.')
460
        old = b.basis_tree()
461
        new = b.working_tree()
462
463
        ## TODO: Much more efficient way to do this: read in new
464
        ## directories with readdir, rather than stating each one.  Same
465
        ## level of effort but possibly much less IO.  (Or possibly not,
466
        ## if the directories are very large...)
467
468
        for path, ie in old.inventory.iter_entries():
469
            if not new.has_id(ie.file_id):
470
                if show_ids:
471
                    print '%-50s %s' % (path, ie.file_id)
472
                else:
473
                    print path
474
475
class cmd_root(Command):
476
    """Show the tree root directory.
477
478
    The root is the nearest enclosing directory with a .bzr control
479
    directory."""
480
    takes_args = ['filename?']
481
    def run(self, filename=None):
482
        """Print the branch root."""
416 by Martin Pool
- bzr log and bzr root now accept an http URL
483
        from branch import find_branch
484
        b = find_branch(filename)
485
        print getattr(b, 'base', None) or getattr(b, 'baseurl')
329 by Martin Pool
- refactor command functions into command classes
486
487
488
class cmd_log(Command):
1 by mbp at sourcefrog
import from baz patch-364
489
    """Show log of this branch.
490
367 by Martin Pool
- New --show-ids option for bzr log
491
    TODO: Option to limit range.
492
493
    TODO: Perhaps show most-recent first with an option for last.
1 by mbp at sourcefrog
import from baz patch-364
494
    """
378 by Martin Pool
- New usage bzr log FILENAME
495
    takes_args = ['filename?']
367 by Martin Pool
- New --show-ids option for bzr log
496
    takes_options = ['timezone', 'verbose', 'show-ids']
378 by Martin Pool
- New usage bzr log FILENAME
497
    def run(self, filename=None, timezone='original', verbose=False, show_ids=False):
416 by Martin Pool
- bzr log and bzr root now accept an http URL
498
        from branch import find_branch
499
        b = find_branch((filename or '.'), lock_mode='r')
378 by Martin Pool
- New usage bzr log FILENAME
500
        if filename:
501
            filename = b.relpath(filename)
502
        bzrlib.show_log(b, filename,
371 by Martin Pool
- Fix up bzr log command
503
                        show_timezone=timezone,
504
                        verbose=verbose,
505
                        show_ids=show_ids)
329 by Martin Pool
- refactor command functions into command classes
506
507
375 by Martin Pool
- New command touching-revisions and function to trace
508
509
class cmd_touching_revisions(Command):
510
    """Return revision-ids which affected a particular file."""
511
    hidden = True
512
    takes_args = ["filename"]
513
    def run(self, filename):
514
        b = Branch(filename, lock_mode='r')
515
        inv = b.read_working_inventory()
516
        file_id = inv.path2id(b.relpath(filename))
517
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
518
            print "%6d %s" % (revno, what)
519
520
329 by Martin Pool
- refactor command functions into command classes
521
class cmd_ls(Command):
1 by mbp at sourcefrog
import from baz patch-364
522
    """List files in a tree.
523
254 by Martin Pool
- Doc cleanups from Magnus Therning
524
    TODO: Take a revision or remote path and list that tree instead.
1 by mbp at sourcefrog
import from baz patch-364
525
    """
329 by Martin Pool
- refactor command functions into command classes
526
    hidden = True
527
    def run(self, revision=None, verbose=False):
528
        b = Branch('.')
529
        if revision == None:
530
            tree = b.working_tree()
531
        else:
532
            tree = b.revision_tree(b.lookup_revision(revision))
533
534
        for fp, fc, kind, fid in tree.list_files():
535
            if verbose:
536
                if kind == 'directory':
537
                    kindch = '/'
538
                elif kind == 'file':
539
                    kindch = ''
540
                else:
541
                    kindch = '???'
542
543
                print '%-8s %s%s' % (fc, fp, kindch)
1 by mbp at sourcefrog
import from baz patch-364
544
            else:
329 by Martin Pool
- refactor command functions into command classes
545
                print fp
546
547
548
549
class cmd_unknowns(Command):
1 by mbp at sourcefrog
import from baz patch-364
550
    """List unknown files"""
329 by Martin Pool
- refactor command functions into command classes
551
    def run(self):
552
        for f in Branch('.').unknowns():
553
            print quotefn(f)
554
555
556
557
class cmd_ignore(Command):
420 by Martin Pool
Doc
558
    """Ignore a command or pattern
559
560
    To remove patterns from the ignore list, edit the .bzrignore file.
561
562
    If the pattern contains a slash, it is compared to the whole path
563
    from the branch root.  Otherwise, it is comapred to only the last
564
    component of the path.
565
566
    Ignore patterns are case-insensitive on case-insensitive systems.
567
568
    Note: wildcards must be quoted from the shell on Unix.
569
570
    examples:
571
        bzr ignore ./Makefile
572
        bzr ignore '*.class'
573
    """
329 by Martin Pool
- refactor command functions into command classes
574
    takes_args = ['name_pattern']
310 by Martin Pool
- new 'bzr ignored' command!
575
    
329 by Martin Pool
- refactor command functions into command classes
576
    def run(self, name_pattern):
409 by Martin Pool
- New AtomicFile class
577
        from bzrlib.atomicfile import AtomicFile
578
        import codecs
579
329 by Martin Pool
- refactor command functions into command classes
580
        b = Branch('.')
410 by Martin Pool
- Fix ignore command and add tests
581
        ifn = b.abspath('.bzrignore')
329 by Martin Pool
- refactor command functions into command classes
582
409 by Martin Pool
- New AtomicFile class
583
        # FIXME: probably doesn't handle non-ascii patterns
584
410 by Martin Pool
- Fix ignore command and add tests
585
        if os.path.exists(ifn):
586
            f = b.controlfile(ifn, 'rt')
409 by Martin Pool
- New AtomicFile class
587
            igns = f.read()
588
            f.close()
589
        else:
590
            igns = ''
591
592
        if igns and igns[-1] != '\n':
593
            igns += '\n'
594
        igns += name_pattern + '\n'
595
410 by Martin Pool
- Fix ignore command and add tests
596
        f = AtomicFile(ifn, 'wt')
409 by Martin Pool
- New AtomicFile class
597
        f.write(igns)
598
        f.commit()
329 by Martin Pool
- refactor command functions into command classes
599
600
        inv = b.working_tree().inventory
601
        if inv.path2id('.bzrignore'):
602
            mutter('.bzrignore is already versioned')
603
        else:
604
            mutter('need to make new .bzrignore file versioned')
605
            b.add(['.bzrignore'])
606
607
608
609
class cmd_ignored(Command):
421 by Martin Pool
doc
610
    """List ignored files and the patterns that matched them.
611
612
    See also: bzr ignore"""
329 by Martin Pool
- refactor command functions into command classes
613
    def run(self):
614
        tree = Branch('.').working_tree()
615
        for path, file_class, kind, file_id in tree.list_files():
616
            if file_class != 'I':
617
                continue
618
            ## XXX: Slightly inefficient since this was already calculated
619
            pat = tree.is_ignored(path)
620
            print '%-50s %s' % (path, pat)
621
622
623
class cmd_lookup_revision(Command):
624
    """Lookup the revision-id from a revision-number
625
626
    example:
627
        bzr lookup-revision 33
421 by Martin Pool
doc
628
    """
329 by Martin Pool
- refactor command functions into command classes
629
    hidden = True
338 by Martin Pool
- cleanup of some imports
630
    takes_args = ['revno']
631
    
329 by Martin Pool
- refactor command functions into command classes
632
    def run(self, revno):
633
        try:
634
            revno = int(revno)
635
        except ValueError:
338 by Martin Pool
- cleanup of some imports
636
            raise BzrCommandError("not a valid revision-number: %r" % revno)
637
638
        print Branch('.').lookup_revision(revno)
329 by Martin Pool
- refactor command functions into command classes
639
640
641
class cmd_export(Command):
642
    """Export past revision to destination directory.
643
644
    If no revision is specified this exports the last committed revision."""
645
    takes_args = ['dest']
646
    takes_options = ['revision']
394 by Martin Pool
- Fix argument handling in export command
647
    def run(self, dest, revision=None):
329 by Martin Pool
- refactor command functions into command classes
648
        b = Branch('.')
394 by Martin Pool
- Fix argument handling in export command
649
        if revision == None:
650
            rh = b.revision_history()[-1]
329 by Martin Pool
- refactor command functions into command classes
651
        else:
394 by Martin Pool
- Fix argument handling in export command
652
            rh = b.lookup_revision(int(revision))
329 by Martin Pool
- refactor command functions into command classes
653
        t = b.revision_tree(rh)
654
        t.export(dest)
655
656
657
class cmd_cat(Command):
658
    """Write a file's text from a previous revision."""
659
660
    takes_options = ['revision']
661
    takes_args = ['filename']
662
663
    def run(self, filename, revision=None):
664
        if revision == None:
665
            raise BzrCommandError("bzr cat requires a revision number")
666
        b = Branch('.')
667
        b.print_file(b.relpath(filename), int(revision))
668
669
670
class cmd_local_time_offset(Command):
671
    """Show the offset in seconds from GMT to local time."""
672
    hidden = True    
673
    def run(self):
674
        print bzrlib.osutils.local_time_offset()
675
676
677
678
class cmd_commit(Command):
679
    """Commit changes into a new revision.
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
680
681
    TODO: Commit only selected files.
682
683
    TODO: Run hooks on tree to-be-committed, and after commit.
684
685
    TODO: Strict commit that fails if there are unknown or deleted files.
686
    """
389 by Martin Pool
- new commit --file option!
687
    takes_options = ['message', 'file', 'verbose']
350 by Martin Pool
- refactor command aliases into command classes
688
    aliases = ['ci', 'checkin']
689
389 by Martin Pool
- new commit --file option!
690
    def run(self, message=None, file=None, verbose=False):
691
        ## Warning: shadows builtin file()
692
        if not message and not file:
693
            raise BzrCommandError("please specify a commit message",
694
                                  ["use either --message or --file"])
695
        elif message and file:
696
            raise BzrCommandError("please specify either --message or --file")
697
        
698
        if file:
699
            import codecs
700
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
701
329 by Martin Pool
- refactor command functions into command classes
702
        Branch('.').commit(message, verbose=verbose)
703
704
705
class cmd_check(Command):
706
    """Validate consistency of branch history.
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
707
708
    This command checks various invariants about the branch storage to
709
    detect data corruption or bzr bugs.
710
    """
329 by Martin Pool
- refactor command functions into command classes
711
    takes_args = ['dir?']
712
    def run(self, dir='.'):
713
        import bzrlib.check
714
        bzrlib.check.check(Branch(dir, find_root=False))
715
716
717
718
class cmd_whoami(Command):
719
    """Show bzr user id."""
720
    takes_options = ['email']
286 by Martin Pool
- New bzr whoami --email option
721
    
329 by Martin Pool
- refactor command functions into command classes
722
    def run(self, email=False):
723
        if email:
724
            print bzrlib.osutils.user_email()
725
        else:
726
            print bzrlib.osutils.username()
727
728
729
class cmd_selftest(Command):
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
730
    """Run internal test suite"""
329 by Martin Pool
- refactor command functions into command classes
731
    hidden = True
732
    def run(self):
733
        failures, tests = 0, 0
734
735
        import doctest, bzrlib.store, bzrlib.tests
736
        bzrlib.trace.verbose = False
737
738
        for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
739
            bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
740
            mf, mt = doctest.testmod(m)
741
            failures += mf
742
            tests += mt
743
            print '%-40s %3d tests' % (m.__name__, mt),
744
            if mf:
745
                print '%3d FAILED!' % mf
746
            else:
747
                print
748
749
        print '%-40s %3d tests' % ('total', tests),
750
        if failures:
751
            print '%3d FAILED!' % failures
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
752
        else:
753
            print
754
329 by Martin Pool
- refactor command functions into command classes
755
756
757
class cmd_version(Command):
758
    """Show version of bzr"""
759
    def run(self):
760
        show_version()
761
762
def show_version():
763
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
764
    print bzrlib.__copyright__
765
    print "http://bazaar-ng.org/"
766
    print
767
    print "bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and"
768
    print "you may use, modify and redistribute it under the terms of the GNU"
769
    print "General Public License version 2 or later."
770
771
772
class cmd_rocks(Command):
773
    """Statement of optimism."""
774
    hidden = True
775
    def run(self):
776
        print "it sure does!"
777
778
779
class cmd_assert_fail(Command):
780
    """Test reporting of assertion failures"""
781
    hidden = True
782
    def run(self):
783
        assert False, "always fails"
784
785
786
class cmd_help(Command):
787
    """Show help on a command or other topic.
788
789
    For a list of all available commands, say 'bzr help commands'."""
790
    takes_args = ['topic?']
350 by Martin Pool
- refactor command aliases into command classes
791
    aliases = ['?']
329 by Martin Pool
- refactor command functions into command classes
792
    
793
    def run(self, topic=None):
351 by Martin Pool
- Split out help functions into bzrlib.help
794
        import help
795
        help.help(topic)
796
1 by mbp at sourcefrog
import from baz patch-364
797
798
######################################################################
799
# main routine
800
801
802
# list of all available options; the rhs can be either None for an
803
# option that takes no argument, or a constructor function that checks
804
# the type.
805
OPTIONS = {
806
    'all':                    None,
807
    'help':                   None,
389 by Martin Pool
- new commit --file option!
808
    'file':                   unicode,
1 by mbp at sourcefrog
import from baz patch-364
809
    'message':                unicode,
137 by mbp at sourcefrog
new --profile option
810
    'profile':                None,
1 by mbp at sourcefrog
import from baz patch-364
811
    'revision':               int,
812
    'show-ids':               None,
12 by mbp at sourcefrog
new --timezone option for bzr log
813
    'timezone':               str,
1 by mbp at sourcefrog
import from baz patch-364
814
    'verbose':                None,
815
    'version':                None,
286 by Martin Pool
- New bzr whoami --email option
816
    'email':                  None,
1 by mbp at sourcefrog
import from baz patch-364
817
    }
818
819
SHORT_OPTIONS = {
820
    'm':                      'message',
389 by Martin Pool
- new commit --file option!
821
    'F':                      'file', 
1 by mbp at sourcefrog
import from baz patch-364
822
    'r':                      'revision',
823
    'v':                      'verbose',
824
}
825
826
827
def parse_args(argv):
828
    """Parse command line.
829
    
830
    Arguments and options are parsed at this level before being passed
831
    down to specific command handlers.  This routine knows, from a
832
    lookup table, something about the available options, what optargs
833
    they take, and which commands will accept them.
834
31 by Martin Pool
fix up parse_args doctest
835
    >>> parse_args('--help'.split())
1 by mbp at sourcefrog
import from baz patch-364
836
    ([], {'help': True})
31 by Martin Pool
fix up parse_args doctest
837
    >>> parse_args('--version'.split())
1 by mbp at sourcefrog
import from baz patch-364
838
    ([], {'version': True})
31 by Martin Pool
fix up parse_args doctest
839
    >>> parse_args('status --all'.split())
1 by mbp at sourcefrog
import from baz patch-364
840
    (['status'], {'all': True})
31 by Martin Pool
fix up parse_args doctest
841
    >>> parse_args('commit --message=biter'.split())
17 by mbp at sourcefrog
allow --option=ARG syntax
842
    (['commit'], {'message': u'biter'})
1 by mbp at sourcefrog
import from baz patch-364
843
    """
844
    args = []
845
    opts = {}
846
847
    # TODO: Maybe handle '--' to end options?
848
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
849
    while argv:
850
        a = argv.pop(0)
1 by mbp at sourcefrog
import from baz patch-364
851
        if a[0] == '-':
264 by Martin Pool
parse_args: option names must be ascii
852
            # option names must not be unicode
853
            a = str(a)
17 by mbp at sourcefrog
allow --option=ARG syntax
854
            optarg = None
1 by mbp at sourcefrog
import from baz patch-364
855
            if a[1] == '-':
856
                mutter("  got option %r" % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
857
                if '=' in a:
858
                    optname, optarg = a[2:].split('=', 1)
859
                else:
860
                    optname = a[2:]
1 by mbp at sourcefrog
import from baz patch-364
861
                if optname not in OPTIONS:
862
                    bailout('unknown long option %r' % a)
863
            else:
864
                shortopt = a[1:]
865
                if shortopt not in SHORT_OPTIONS:
866
                    bailout('unknown short option %r' % a)
867
                optname = SHORT_OPTIONS[shortopt]
868
            
869
            if optname in opts:
870
                # XXX: Do we ever want to support this, e.g. for -r?
871
                bailout('repeated option %r' % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
872
                
1 by mbp at sourcefrog
import from baz patch-364
873
            optargfn = OPTIONS[optname]
874
            if optargfn:
17 by mbp at sourcefrog
allow --option=ARG syntax
875
                if optarg == None:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
876
                    if not argv:
17 by mbp at sourcefrog
allow --option=ARG syntax
877
                        bailout('option %r needs an argument' % a)
878
                    else:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
879
                        optarg = argv.pop(0)
17 by mbp at sourcefrog
allow --option=ARG syntax
880
                opts[optname] = optargfn(optarg)
1 by mbp at sourcefrog
import from baz patch-364
881
            else:
17 by mbp at sourcefrog
allow --option=ARG syntax
882
                if optarg != None:
883
                    bailout('option %r takes no argument' % optname)
1 by mbp at sourcefrog
import from baz patch-364
884
                opts[optname] = True
885
        else:
886
            args.append(a)
887
888
    return args, opts
889
890
891
892
329 by Martin Pool
- refactor command functions into command classes
893
def _match_argform(cmd, takes_args, args):
1 by mbp at sourcefrog
import from baz patch-364
894
    argdict = {}
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
895
329 by Martin Pool
- refactor command functions into command classes
896
    # step through args and takes_args, allowing appropriate 0-many matches
897
    for ap in takes_args:
1 by mbp at sourcefrog
import from baz patch-364
898
        argname = ap[:-1]
899
        if ap[-1] == '?':
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
900
            if args:
901
                argdict[argname] = args.pop(0)
196 by mbp at sourcefrog
selected-file diff
902
        elif ap[-1] == '*': # all remaining arguments
903
            if args:
904
                argdict[argname + '_list'] = args[:]
905
                args = []
906
            else:
907
                argdict[argname + '_list'] = None
1 by mbp at sourcefrog
import from baz patch-364
908
        elif ap[-1] == '+':
909
            if not args:
329 by Martin Pool
- refactor command functions into command classes
910
                raise BzrCommandError("command %r needs one or more %s"
1 by mbp at sourcefrog
import from baz patch-364
911
                        % (cmd, argname.upper()))
912
            else:
913
                argdict[argname + '_list'] = args[:]
914
                args = []
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
915
        elif ap[-1] == '$': # all but one
916
            if len(args) < 2:
329 by Martin Pool
- refactor command functions into command classes
917
                raise BzrCommandError("command %r needs one or more %s"
160 by mbp at sourcefrog
- basic support for moving files to different directories - have not done support for renaming them yet, but should be straightforward - some tests, but many cases are not handled yet i think
918
                        % (cmd, argname.upper()))
919
            argdict[argname + '_list'] = args[:-1]
920
            args[:-1] = []                
1 by mbp at sourcefrog
import from baz patch-364
921
        else:
922
            # just a plain arg
923
            argname = ap
924
            if not args:
329 by Martin Pool
- refactor command functions into command classes
925
                raise BzrCommandError("command %r requires argument %s"
1 by mbp at sourcefrog
import from baz patch-364
926
                        % (cmd, argname.upper()))
927
            else:
928
                argdict[argname] = args.pop(0)
929
            
930
    if args:
329 by Martin Pool
- refactor command functions into command classes
931
        raise BzrCommandError("extra argument to command %s: %s"
932
                              % (cmd, args[0]))
1 by mbp at sourcefrog
import from baz patch-364
933
934
    return argdict
935
936
937
938
def run_bzr(argv):
939
    """Execute a command.
940
941
    This is similar to main(), but without all the trappings for
245 by mbp at sourcefrog
- control files always in utf-8-unix format
942
    logging and error handling.  
1 by mbp at sourcefrog
import from baz patch-364
943
    """
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
944
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
245 by mbp at sourcefrog
- control files always in utf-8-unix format
945
    
1 by mbp at sourcefrog
import from baz patch-364
946
    try:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
947
        args, opts = parse_args(argv[1:])
1 by mbp at sourcefrog
import from baz patch-364
948
        if 'help' in opts:
351 by Martin Pool
- Split out help functions into bzrlib.help
949
            import help
159 by mbp at sourcefrog
bzr commit --help now works
950
            if args:
351 by Martin Pool
- Split out help functions into bzrlib.help
951
                help.help(args[0])
159 by mbp at sourcefrog
bzr commit --help now works
952
            else:
351 by Martin Pool
- Split out help functions into bzrlib.help
953
                help.help()
1 by mbp at sourcefrog
import from baz patch-364
954
            return 0
955
        elif 'version' in opts:
336 by Martin Pool
- fix up 'bzr --version'
956
            show_version()
1 by mbp at sourcefrog
import from baz patch-364
957
            return 0
265 by Martin Pool
parse_args: command names must also be ascii
958
        cmd = str(args.pop(0))
1 by mbp at sourcefrog
import from baz patch-364
959
    except IndexError:
257 by Martin Pool
- Write less startup junk to .bzr.log
960
        log_error('usage: bzr COMMAND')
961
        log_error('  try "bzr help"')
1 by mbp at sourcefrog
import from baz patch-364
962
        return 1
115 by mbp at sourcefrog
todo
963
351 by Martin Pool
- Split out help functions into bzrlib.help
964
    canonical_cmd, cmd_class = get_cmd_class(cmd)
1 by mbp at sourcefrog
import from baz patch-364
965
137 by mbp at sourcefrog
new --profile option
966
    # global option
967
    if 'profile' in opts:
968
        profile = True
969
        del opts['profile']
970
    else:
971
        profile = False
1 by mbp at sourcefrog
import from baz patch-364
972
973
    # check options are reasonable
329 by Martin Pool
- refactor command functions into command classes
974
    allowed = cmd_class.takes_options
1 by mbp at sourcefrog
import from baz patch-364
975
    for oname in opts:
976
        if oname not in allowed:
381 by Martin Pool
- Better message when a wrong argument is given
977
            raise BzrCommandError("option '--%s' is not allowed for command %r"
329 by Martin Pool
- refactor command functions into command classes
978
                                  % (oname, cmd))
176 by mbp at sourcefrog
New cat command contributed by janmar.
979
137 by mbp at sourcefrog
new --profile option
980
    # mix arguments and options into one dictionary
329 by Martin Pool
- refactor command functions into command classes
981
    cmdargs = _match_argform(cmd, cmd_class.takes_args, args)
982
    cmdopts = {}
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
983
    for k, v in opts.items():
329 by Martin Pool
- refactor command functions into command classes
984
        cmdopts[k.replace('-', '_')] = v
1 by mbp at sourcefrog
import from baz patch-364
985
137 by mbp at sourcefrog
new --profile option
986
    if profile:
338 by Martin Pool
- cleanup of some imports
987
        import hotshot, tempfile
239 by mbp at sourcefrog
- remove profiler temporary file when done
988
        pffileno, pfname = tempfile.mkstemp()
989
        try:
990
            prof = hotshot.Profile(pfname)
329 by Martin Pool
- refactor command functions into command classes
991
            ret = prof.runcall(cmd_class, cmdopts, cmdargs) or 0
239 by mbp at sourcefrog
- remove profiler temporary file when done
992
            prof.close()
993
994
            import hotshot.stats
995
            stats = hotshot.stats.load(pfname)
996
            #stats.strip_dirs()
997
            stats.sort_stats('time')
998
            ## XXX: Might like to write to stderr or the trace file instead but
999
            ## print_stats seems hardcoded to stdout
1000
            stats.print_stats(20)
1001
            
337 by Martin Pool
- Clarify return codes from command objects
1002
            return ret.status
239 by mbp at sourcefrog
- remove profiler temporary file when done
1003
1004
        finally:
1005
            os.close(pffileno)
1006
            os.remove(pfname)
137 by mbp at sourcefrog
new --profile option
1007
    else:
337 by Martin Pool
- Clarify return codes from command objects
1008
        cmdobj = cmd_class(cmdopts, cmdargs).status 
1 by mbp at sourcefrog
import from baz patch-364
1009
1010
359 by Martin Pool
- pychecker fixups
1011
def _report_exception(summary, quiet=False):
267 by Martin Pool
- better reporting of errors
1012
    import traceback
1013
    log_error('bzr: ' + summary)
359 by Martin Pool
- pychecker fixups
1014
    bzrlib.trace.log_exception()
317 by Martin Pool
- better error message for broken pipe
1015
1016
    if not quiet:
1017
        tb = sys.exc_info()[2]
1018
        exinfo = traceback.extract_tb(tb)
1019
        if exinfo:
1020
            sys.stderr.write('  at %s:%d in %s()\n' % exinfo[-1][:3])
1021
        sys.stderr.write('  see ~/.bzr.log for debug information\n')
267 by Martin Pool
- better reporting of errors
1022
1023
1024
1 by mbp at sourcefrog
import from baz patch-364
1025
def main(argv):
317 by Martin Pool
- better error message for broken pipe
1026
    import errno
1027
    
344 by Martin Pool
- It's not an error to use the library without
1028
    bzrlib.open_tracefile(argv)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1029
1 by mbp at sourcefrog
import from baz patch-364
1030
    try:
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1031
        try:
337 by Martin Pool
- Clarify return codes from command objects
1032
            try:
1033
                return run_bzr(argv)
1034
            finally:
1035
                # do this here inside the exception wrappers to catch EPIPE
1036
                sys.stdout.flush()
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1037
        except BzrError, e:
329 by Martin Pool
- refactor command functions into command classes
1038
            quiet = isinstance(e, (BzrCommandError))
359 by Martin Pool
- pychecker fixups
1039
            _report_exception('error: ' + e.args[0], quiet=quiet)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1040
            if len(e.args) > 1:
1041
                for h in e.args[1]:
267 by Martin Pool
- better reporting of errors
1042
                    # some explanation or hints
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1043
                    log_error('  ' + h)
1044
            return 1
267 by Martin Pool
- better reporting of errors
1045
        except AssertionError, e:
1046
            msg = 'assertion failed'
1047
            if str(e):
1048
                msg += ': ' + str(e)
359 by Martin Pool
- pychecker fixups
1049
            _report_exception(msg)
318 by Martin Pool
- better error message for Ctrl-c
1050
            return 2
1051
        except KeyboardInterrupt, e:
359 by Martin Pool
- pychecker fixups
1052
            _report_exception('interrupted', quiet=True)
318 by Martin Pool
- better error message for Ctrl-c
1053
            return 2
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1054
        except Exception, e:
317 by Martin Pool
- better error message for broken pipe
1055
            quiet = False
419 by Martin Pool
- RemoteBranch.__str__ and repr
1056
            if (isinstance(e, IOError) 
1057
                and hasattr(e, 'errno')
1058
                and e.errno == errno.EPIPE):
317 by Martin Pool
- better error message for broken pipe
1059
                quiet = True
1060
                msg = 'broken pipe'
1061
            else:
1062
                msg = str(e).rstrip('\n')
359 by Martin Pool
- pychecker fixups
1063
            _report_exception(msg, quiet)
318 by Martin Pool
- better error message for Ctrl-c
1064
            return 2
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1065
    finally:
1066
        bzrlib.trace.close_trace()
1 by mbp at sourcefrog
import from baz patch-364
1067
1068
1069
if __name__ == '__main__':
1070
    sys.exit(main(sys.argv))