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