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