~bzr-pqm/bzr/bzr.dev

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