/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1 by mbp at sourcefrog
import from baz patch-364
1
# Copyright (C) 2004, 2005 by Martin Pool
2
# Copyright (C) 2005 by Canonical Ltd
3
4
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19
"""Bazaar-NG -- a free distributed version-control tool
273 by Martin Pool
- New 'bzr help commands'
20
http://bazaar-ng.org/
1 by mbp at sourcefrog
import from baz patch-364
21
22
**WARNING: THIS IS AN UNSTABLE DEVELOPMENT VERSION**
23
24
* Metadata format is not stable yet -- you may need to
25
  discard history in the future.
26
27
* Many commands unimplemented or partially implemented.
28
29
* Space-inefficient storage.
30
31
* No merge operators yet.
32
273 by Martin Pool
- New 'bzr help commands'
33
Interesting commands:
1 by mbp at sourcefrog
import from baz patch-364
34
85 by mbp at sourcefrog
improved help string
35
  bzr help [COMMAND]
273 by Martin Pool
- New 'bzr help commands'
36
      Show help screen
1 by mbp at sourcefrog
import from baz patch-364
37
  bzr version
273 by Martin Pool
- New 'bzr help commands'
38
      Show software version/licence/non-warranty.
1 by mbp at sourcefrog
import from baz patch-364
39
  bzr init
273 by Martin Pool
- New 'bzr help commands'
40
      Start versioning the current directory
1 by mbp at sourcefrog
import from baz patch-364
41
  bzr add FILE...
273 by Martin Pool
- New 'bzr help commands'
42
      Make files versioned.
1 by mbp at sourcefrog
import from baz patch-364
43
  bzr log
273 by Martin Pool
- New 'bzr help commands'
44
      Show revision history.
196 by mbp at sourcefrog
selected-file diff
45
  bzr diff [FILE...]
273 by Martin Pool
- New 'bzr help commands'
46
      Show changes from last revision to working copy.
1 by mbp at sourcefrog
import from baz patch-364
47
  bzr commit -m 'MESSAGE'
273 by Martin Pool
- New 'bzr help commands'
48
      Store current state as new revision.
1 by mbp at sourcefrog
import from baz patch-364
49
  bzr export REVNO DESTINATION
273 by Martin Pool
- New 'bzr help commands'
50
      Export the branch state at a previous version.
1 by mbp at sourcefrog
import from baz patch-364
51
  bzr status
273 by Martin Pool
- New 'bzr help commands'
52
      Show summary of pending changes.
1 by mbp at sourcefrog
import from baz patch-364
53
  bzr remove FILE...
273 by Martin Pool
- New 'bzr help commands'
54
      Make a file not versioned.
76 by mbp at sourcefrog
mention "info" in top-level help
55
  bzr info
273 by Martin Pool
- New 'bzr help commands'
56
      Show statistics about this branch.
57
  bzr check
58
      Verify history is stored safely. 
59
  (for more type 'bzr help commands')
1 by mbp at sourcefrog
import from baz patch-364
60
"""
61
62
63
64
263 by Martin Pool
factor out code to log exceptions
65
import sys, os, time, types, shutil, tempfile, fnmatch, difflib, os.path
1 by mbp at sourcefrog
import from baz patch-364
66
from sets import Set
67
from pprint import pprint
68
from stat import *
69
from glob import glob
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
70
from inspect import getdoc
1 by mbp at sourcefrog
import from baz patch-364
71
72
import bzrlib
73
from bzrlib.store import ImmutableStore
74
from bzrlib.trace import mutter, note, log_error
184 by mbp at sourcefrog
pychecker fixups
75
from bzrlib.errors import bailout, BzrError, BzrCheckError
1 by mbp at sourcefrog
import from baz patch-364
76
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
77
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
78
from bzrlib.revision import Revision
79
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
80
     format_date
81
82
BZR_DIFF_FORMAT = "## Bazaar-NG diff, format 0 ##\n"
83
BZR_PATCHNAME_FORMAT = 'cset:sha1:%s'
84
85
## standard representation
86
NONE_STRING = '(none)'
87
EMPTY = 'empty'
88
89
90
## TODO: Perhaps a different version of inventory commands that
91
## returns iterators...
92
93
## TODO: Perhaps an AtomicFile class that writes to a temporary file and then renames.
94
95
## TODO: Some kind of locking on branches.  Perhaps there should be a
96
## parameter to the branch object saying whether we want a read or
97
## write lock; release it from destructor.  Perhaps don't even need a
98
## read lock to look at immutable objects?
99
100
## TODO: Perhaps make UUIDs predictable in test mode to make it easier
101
## to compare output?
102
34 by mbp at sourcefrog
doc
103
## TODO: Some kind of global code to generate the right Branch object
104
## to work on.  Almost, but not quite all, commands need one, and it
105
## can be taken either from their parameters or their working
106
## directory.
107
46 by Martin Pool
todo
108
## TODO: rename command, needed soon: check destination doesn't exist
109
## either in working copy or tree; move working copy; update
110
## inventory; write out
111
112
## TODO: move command; check destination is a directory and will not
113
## clash; move it.
114
115
## TODO: command to show renames, one per line, as to->from
116
117
1 by mbp at sourcefrog
import from baz patch-364
118
272 by Martin Pool
- Add command aliases
119
cmd_aliases = {
120
    '?':         'help',
121
    'ci':        'commit',
122
    'checkin':   'commit',
123
    'di':        'diff',
124
    'st':        'status',
125
    'stat':      'status',
126
    }
127
128
129
def get_cmd_handler(cmd):
274 by Martin Pool
- Fix 'bzr help COMMAND' for Unicode changes
130
    cmd = str(cmd)
272 by Martin Pool
- Add command aliases
131
    
132
    cmd = cmd_aliases.get(cmd, cmd)
133
    
134
    try:
135
        cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
136
    except KeyError:
137
        raise BzrError("unknown command %r" % cmd)
138
139
    return cmd, cmd_handler
140
141
1 by mbp at sourcefrog
import from baz patch-364
142
143
def cmd_status(all=False):
144
    """Display status summary.
145
146
    For each file there is a single line giving its file state and name.
147
    The name is that in the current revision unless it is deleted or
148
    missing, in which case the old name is shown.
149
    """
233 by mbp at sourcefrog
- more output from test.sh
150
    #import bzrlib.status
151
    #bzrlib.status.tree_status(Branch('.'))
1 by mbp at sourcefrog
import from baz patch-364
152
    Branch('.').show_status(show_all=all)
153
154
155
156
######################################################################
157
# examining history
158
def cmd_get_revision(revision_id):
159
    Branch('.').get_revision(revision_id).write_xml(sys.stdout)
160
161
162
def cmd_get_file_text(text_id):
163
    """Get contents of a file by hash."""
164
    sf = Branch('.').text_store[text_id]
165
    pumpfile(sf, sys.stdout)
166
167
168
169
######################################################################
170
# commands
171
    
172
173
def cmd_revno():
174
    """Show number of revisions on this branch"""
175
    print Branch('.').revno()
176
    
177
70 by mbp at sourcefrog
Prepare for smart recursive add.
178
    
1 by mbp at sourcefrog
import from baz patch-364
179
def cmd_add(file_list, verbose=False):
70 by mbp at sourcefrog
Prepare for smart recursive add.
180
    """Add specified files or directories.
181
182
    In non-recursive mode, all the named items are added, regardless
183
    of whether they were previously ignored.  A warning is given if
184
    any of the named files are already versioned.
185
186
    In recursive mode (the default), files are treated the same way
187
    but the behaviour for directories is different.  Directories that
188
    are already versioned do not give a warning.  All directories,
189
    whether already versioned or not, are searched for files or
190
    subdirectories that are neither versioned or ignored, and these
191
    are added.  This search proceeds recursively into versioned
192
    directories.
193
194
    Therefore simply saying 'bzr add .' will version all files that
195
    are currently unknown.
279 by Martin Pool
todo
196
197
    TODO: Perhaps adding a file whose directly is not versioned should
198
    recursively add that parent, rather than giving an error?
70 by mbp at sourcefrog
Prepare for smart recursive add.
199
    """
87 by mbp at sourcefrog
- clean up smart_add code, and make it commit the inventory
200
    bzrlib.add.smart_add(file_list, verbose)
1 by mbp at sourcefrog
import from baz patch-364
201
    
202
68 by mbp at sourcefrog
- new relpath command and function
203
def cmd_relpath(filename):
87 by mbp at sourcefrog
- clean up smart_add code, and make it commit the inventory
204
    """Show path of file relative to root"""
68 by mbp at sourcefrog
- new relpath command and function
205
    print Branch(filename).relpath(filename)
206
207
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
208
1 by mbp at sourcefrog
import from baz patch-364
209
def cmd_inventory(revision=None):
210
    """Show inventory of the current working copy."""
211
    ## TODO: Also optionally show a previous inventory
212
    ## TODO: Format options
213
    b = Branch('.')
214
    if revision == None:
215
        inv = b.read_working_inventory()
216
    else:
217
        inv = b.get_revision_inventory(b.lookup_revision(revision))
218
        
219
    for path, entry in inv.iter_entries():
220
        print '%-50s %s' % (entry.file_id, path)
221
222
223
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
224
# TODO: Maybe a 'mv' command that has the combined move/rename
225
# special behaviour of Unix?
226
227
def cmd_move(source_list, dest):
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
228
    b = Branch('.')
229
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
230
    b.move([b.relpath(s) for s in source_list], b.relpath(dest))
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
231
232
233
168 by mbp at sourcefrog
new "rename" command
234
def cmd_rename(from_name, to_name):
235
    """Change the name of an entry.
236
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
237
    usage: bzr rename FROM_NAME TO_NAME
238
239
    examples:
240
      bzr rename frob.c frobber.c
241
      bzr rename src/frob.c lib/frob.c
242
243
    It is an error if the destination name exists.
244
245
    See also the 'move' command, which moves files into a different
246
    directory without changing their name.
247
248
    TODO: Some way to rename multiple files without invoking bzr for each
249
    one?"""
168 by mbp at sourcefrog
new "rename" command
250
    b = Branch('.')
251
    b.rename_one(b.relpath(from_name), b.relpath(to_name))
252
    
253
254
255
164 by mbp at sourcefrog
new 'renames' command
256
def cmd_renames(dir='.'):
257
    """Show list of renamed files.
258
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
259
    usage: bzr renames [BRANCH]
260
261
    TODO: Option to show renames between two historical versions.
262
263
    TODO: Only show renames under dir, rather than in the whole branch.
264
    """
164 by mbp at sourcefrog
new 'renames' command
265
    b = Branch(dir)
266
    old_inv = b.basis_tree().inventory
267
    new_inv = b.read_working_inventory()
268
    
269
    renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
270
    renames.sort()
271
    for old_name, new_name in renames:
272
        print "%s => %s" % (old_name, new_name)        
273
274
275
1 by mbp at sourcefrog
import from baz patch-364
276
def cmd_info():
112 by mbp at sourcefrog
help for info command
277
    """info: Show statistical information for this branch
278
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
279
    usage: bzr info"""
77 by mbp at sourcefrog
- split info command out into separate file
280
    import info
281
    info.show_info(Branch('.'))        
21 by mbp at sourcefrog
- bzr info: show summary information on branch history
282
    
1 by mbp at sourcefrog
import from baz patch-364
283
284
285
def cmd_remove(file_list, verbose=False):
69 by Martin Pool
handle add, remove, file-id being given filenames that are
286
    b = Branch(file_list[0])
287
    b.remove([b.relpath(f) for f in file_list], verbose=verbose)
1 by mbp at sourcefrog
import from baz patch-364
288
289
290
291
def cmd_file_id(filename):
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
292
    """Print file_id of a particular file or directory.
293
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
294
    usage: bzr file-id FILE
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
295
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
296
    The file_id is assigned when the file is first added and remains the
297
    same through all revisions where the file exists, even when it is
298
    moved or renamed.
299
    """
69 by Martin Pool
handle add, remove, file-id being given filenames that are
300
    b = Branch(filename)
301
    i = b.inventory.path2id(b.relpath(filename))
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
302
    if i == None:
303
        bailout("%r is not a versioned file" % filename)
1 by mbp at sourcefrog
import from baz patch-364
304
    else:
305
        print i
306
307
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
308
def cmd_file_id_path(filename):
309
    """Print path of file_ids to a file or directory.
310
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
311
    usage: bzr file-id-path FILE
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
312
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
313
    This prints one line for each directory down to the target,
314
    starting at the branch root."""
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
315
    b = Branch(filename)
316
    inv = b.inventory
317
    fid = inv.path2id(b.relpath(filename))
318
    if fid == None:
319
        bailout("%r is not a versioned file" % filename)
320
    for fip in inv.get_idpath(fid):
321
        print fip
322
323
1 by mbp at sourcefrog
import from baz patch-364
324
def cmd_revision_history():
325
    for patchid in Branch('.').revision_history():
326
        print patchid
327
328
156 by mbp at sourcefrog
new "directories" command
329
def cmd_directories():
330
    for name, ie in Branch('.').read_working_inventory().directories():
331
        if name == '':
332
            print '.'
333
        else:
334
            print name
335
1 by mbp at sourcefrog
import from baz patch-364
336
157 by mbp at sourcefrog
fix test case breakage
337
def cmd_missing():
338
    for name, ie in Branch('.').working_tree().missing():
339
        print name
340
341
1 by mbp at sourcefrog
import from baz patch-364
342
def cmd_init():
343
    # TODO: Check we're not already in a working directory?  At the
344
    # moment you'll get an ugly error.
345
    
346
    # TODO: What if we're in a subdirectory of a branch?  Would like
347
    # to allow that, but then the parent may need to understand that
348
    # the children have disappeared, or should they be versioned in
349
    # both?
350
351
    # TODO: Take an argument/option for branch name.
352
    Branch('.', init=True)
353
354
196 by mbp at sourcefrog
selected-file diff
355
def cmd_diff(revision=None, file_list=None):
109 by mbp at sourcefrog
more help for diff command
356
    """bzr diff: Show differences in working tree.
357
    
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
358
    usage: bzr diff [-r REV] [FILE...]
359
360
    --revision REV
361
         Show changes since REV, rather than predecessor.
362
363
    If files are listed, only the changes in those files are listed.
364
    Otherwise, all changes for the tree are listed.
365
366
    TODO: Given two revision arguments, show the difference between them.
367
368
    TODO: Allow diff across branches.
369
370
    TODO: Option to use external diff command; could be GNU diff, wdiff,
371
          or a graphical diff.
372
276 by Martin Pool
Doc
373
    TODO: Python difflib is not exactly the same as unidiff; should
374
          either fix it up or prefer to use an external diff.
375
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
376
    TODO: If a directory is given, diff everything under that.
377
276 by Martin Pool
Doc
378
    TODO: Selected-file diff is inefficient and doesn't show you
379
          deleted files.
278 by Martin Pool
- Better workaround for trailing newlines in diffs
380
381
    TODO: This probably handles non-Unix newlines poorly.
109 by mbp at sourcefrog
more help for diff command
382
"""
383
384
    ## TODO: Shouldn't be in the cmd function.
1 by mbp at sourcefrog
import from baz patch-364
385
386
    b = Branch('.')
387
388
    if revision == None:
389
        old_tree = b.basis_tree()
390
    else:
391
        old_tree = b.revision_tree(b.lookup_revision(revision))
392
        
393
    new_tree = b.working_tree()
394
395
    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
396
    old_label = ''
397
    new_label = ''
398
399
    DEVNULL = '/dev/null'
400
    # Windows users, don't panic about this filename -- it is a
401
    # special signal to GNU patch that the file should be created or
402
    # deleted respectively.
403
404
    # TODO: Generation of pseudo-diffs for added/deleted files could
405
    # be usefully made into a much faster special case.
406
407
    # TODO: Better to return them in sorted order I think.
196 by mbp at sourcefrog
selected-file diff
408
271 by Martin Pool
- Windows path fixes
409
    if file_list:
410
        file_list = [b.relpath(f) for f in file_list]
411
196 by mbp at sourcefrog
selected-file diff
412
    # FIXME: If given a file list, compare only those files rather
413
    # than comparing everything and then throwing stuff away.
1 by mbp at sourcefrog
import from baz patch-364
414
    
415
    for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
196 by mbp at sourcefrog
selected-file diff
416
271 by Martin Pool
- Windows path fixes
417
        if file_list and (new_name not in file_list):
196 by mbp at sourcefrog
selected-file diff
418
            continue
419
        
1 by mbp at sourcefrog
import from baz patch-364
420
        # Don't show this by default; maybe do it if an option is passed
421
        # idlabel = '      {%s}' % fid
422
        idlabel = ''
423
424
        # FIXME: Something about the diff format makes patch unhappy
425
        # with newly-added files.
426
162 by mbp at sourcefrog
workaround for python2.3 difflib bug
427
        def diffit(oldlines, newlines, **kw):
278 by Martin Pool
- Better workaround for trailing newlines in diffs
428
            
162 by mbp at sourcefrog
workaround for python2.3 difflib bug
429
            # FIXME: difflib is wrong if there is no trailing newline.
278 by Martin Pool
- Better workaround for trailing newlines in diffs
430
            # The syntax used by patch seems to be "\ No newline at
431
            # end of file" following the last diff line from that
432
            # file.  This is not trivial to insert into the
433
            # unified_diff output and it might be better to just fix
434
            # or replace that function.
435
436
            # In the meantime we at least make sure the patch isn't
437
            # mangled.
438
            
162 by mbp at sourcefrog
workaround for python2.3 difflib bug
439
440
            # Special workaround for Python2.3, where difflib fails if
441
            # both sequences are empty.
278 by Martin Pool
- Better workaround for trailing newlines in diffs
442
            if not oldlines and not newlines:
443
                return
444
445
            nonl = False
446
447
            if oldlines and (oldlines[-1][-1] != '\n'):
448
                oldlines[-1] += '\n'
449
                nonl = True
450
            if newlines and (newlines[-1][-1] != '\n'):
451
                newlines[-1] += '\n'
452
                nonl = True
453
454
            ud = difflib.unified_diff(oldlines, newlines, **kw)
455
            sys.stdout.writelines(ud)
456
            if nonl:
457
                print "\\ No newline at end of file"
458
            sys.stdout.write('\n')
1 by mbp at sourcefrog
import from baz patch-364
459
        
460
        if file_state in ['.', '?', 'I']:
461
            continue
462
        elif file_state == 'A':
463
            print '*** added %s %r' % (kind, new_name)
464
            if kind == 'file':
465
                diffit([],
466
                       new_tree.get_file(fid).readlines(),
467
                       fromfile=DEVNULL,
468
                       tofile=new_label + new_name + idlabel)
469
        elif file_state == 'D':
470
            assert isinstance(old_name, types.StringTypes)
471
            print '*** deleted %s %r' % (kind, old_name)
472
            if kind == 'file':
473
                diffit(old_tree.get_file(fid).readlines(), [],
474
                       fromfile=old_label + old_name + idlabel,
475
                       tofile=DEVNULL)
476
        elif file_state in ['M', 'R']:
477
            if file_state == 'M':
478
                assert kind == 'file'
479
                assert old_name == new_name
480
                print '*** modified %s %r' % (kind, new_name)
481
            elif file_state == 'R':
482
                print '*** renamed %s %r => %r' % (kind, old_name, new_name)
483
484
            if kind == 'file':
485
                diffit(old_tree.get_file(fid).readlines(),
486
                       new_tree.get_file(fid).readlines(),
487
                       fromfile=old_label + old_name + idlabel,
488
                       tofile=new_label + new_name)
489
        else:
490
            bailout("can't represent state %s {%s}" % (file_state, fid))
491
492
493
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
494
def cmd_deleted(show_ids=False):
135 by mbp at sourcefrog
Simple new 'deleted' command
495
    """List files deleted in the working tree.
496
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
497
    TODO: Show files deleted since a previous revision, or between two revisions.
135 by mbp at sourcefrog
Simple new 'deleted' command
498
    """
499
    b = Branch('.')
500
    old = b.basis_tree()
501
    new = b.working_tree()
502
147 by mbp at sourcefrog
todo
503
    ## TODO: Much more efficient way to do this: read in new
504
    ## directories with readdir, rather than stating each one.  Same
505
    ## level of effort but possibly much less IO.  (Or possibly not,
506
    ## if the directories are very large...)
507
135 by mbp at sourcefrog
Simple new 'deleted' command
508
    for path, ie in old.inventory.iter_entries():
509
        if not new.has_id(ie.file_id):
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
510
            if show_ids:
511
                print '%-50s %s' % (path, ie.file_id)
512
            else:
513
                print path
148 by mbp at sourcefrog
performance notes and measurements
514
515
516
517
def cmd_parse_inventory():
518
    import cElementTree
519
    
520
    cElementTree.ElementTree().parse(file('.bzr/inventory'))
521
522
523
524
def cmd_load_inventory():
184 by mbp at sourcefrog
pychecker fixups
525
    """Load inventory for timing purposes"""
526
    Branch('.').basis_tree().inventory
149 by mbp at sourcefrog
experiment with new nested inventory file format
527
528
191 by mbp at sourcefrog
more XML performance tests
529
def cmd_dump_inventory():
530
    Branch('.').read_working_inventory().write_xml(sys.stdout)
531
149 by mbp at sourcefrog
experiment with new nested inventory file format
532
533
def cmd_dump_new_inventory():
534
    import bzrlib.newinventory
535
    inv = Branch('.').basis_tree().inventory
536
    bzrlib.newinventory.write_inventory(inv, sys.stdout)
151 by mbp at sourcefrog
experimental nested-inventory load support
537
538
539
def cmd_load_new_inventory():
540
    import bzrlib.newinventory
541
    bzrlib.newinventory.read_new_inventory(sys.stdin)
149 by mbp at sourcefrog
experiment with new nested inventory file format
542
                
543
    
544
def cmd_dump_slacker_inventory():
545
    import bzrlib.newinventory
546
    inv = Branch('.').basis_tree().inventory
547
    bzrlib.newinventory.write_slacker_inventory(inv, sys.stdout)
236 by mbp at sourcefrog
- Experiments in inventory performance
548
549
550
551
def cmd_dump_text_inventory():
552
    import bzrlib.textinv
553
    inv = Branch('.').basis_tree().inventory
554
    bzrlib.textinv.write_text_inventory(inv, sys.stdout)
555
556
557
def cmd_load_text_inventory():
558
    import bzrlib.textinv
559
    inv = bzrlib.textinv.read_text_inventory(sys.stdin)
560
    print 'loaded %d entries' % len(inv)
561
    
149 by mbp at sourcefrog
experiment with new nested inventory file format
562
    
135 by mbp at sourcefrog
Simple new 'deleted' command
563
65 by mbp at sourcefrog
rename 'find-branch-root' command to just 'root'
564
def cmd_root(filename=None):
565
    """Print the branch root."""
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
566
    print bzrlib.branch.find_branch_root(filename)
567
    
568
244 by mbp at sourcefrog
- New 'bzr log --verbose' from Sebastian Cote
569
def cmd_log(timezone='original', verbose=False):
1 by mbp at sourcefrog
import from baz patch-364
570
    """Show log of this branch.
571
254 by Martin Pool
- Doc cleanups from Magnus Therning
572
    TODO: Options for utc; to show ids; to limit range; etc.
1 by mbp at sourcefrog
import from baz patch-364
573
    """
244 by mbp at sourcefrog
- New 'bzr log --verbose' from Sebastian Cote
574
    Branch('.').write_log(show_timezone=timezone, verbose=verbose)
1 by mbp at sourcefrog
import from baz patch-364
575
576
577
def cmd_ls(revision=None, verbose=False):
578
    """List files in a tree.
579
254 by Martin Pool
- Doc cleanups from Magnus Therning
580
    TODO: Take a revision or remote path and list that tree instead.
1 by mbp at sourcefrog
import from baz patch-364
581
    """
582
    b = Branch('.')
583
    if revision == None:
584
        tree = b.working_tree()
585
    else:
586
        tree = b.revision_tree(b.lookup_revision(revision))
587
        
588
    for fp, fc, kind, fid in tree.list_files():
589
        if verbose:
590
            if kind == 'directory':
591
                kindch = '/'
592
            elif kind == 'file':
593
                kindch = ''
594
            else:
595
                kindch = '???'
596
                
597
            print '%-8s %s%s' % (fc, fp, kindch)
598
        else:
599
            print fp
600
    
601
    
602
603
def cmd_unknowns():
604
    """List unknown files"""
605
    for f in Branch('.').unknowns():
606
        print quotefn(f)
607
608
133 by mbp at sourcefrog
- new 'ignored' command
609
184 by mbp at sourcefrog
pychecker fixups
610
def cmd_ignored():
133 by mbp at sourcefrog
- new 'ignored' command
611
    """List ignored files and the patterns that matched them.
612
      """
613
    tree = Branch('.').working_tree()
184 by mbp at sourcefrog
pychecker fixups
614
    for path, file_class, kind, file_id in tree.list_files():
133 by mbp at sourcefrog
- new 'ignored' command
615
        if file_class != 'I':
616
            continue
617
        ## XXX: Slightly inefficient since this was already calculated
618
        pat = tree.is_ignored(path)
619
        print '%-50s %s' % (path, pat)
620
621
1 by mbp at sourcefrog
import from baz patch-364
622
def cmd_lookup_revision(revno):
623
    try:
624
        revno = int(revno)
625
    except ValueError:
626
        bailout("usage: lookup-revision REVNO",
627
                ["REVNO is a non-negative revision number for this branch"])
628
629
    print Branch('.').lookup_revision(revno) or NONE_STRING
630
631
632
633
def cmd_export(revno, dest):
634
    """Export past revision to destination directory."""
635
    b = Branch('.')
636
    rh = b.lookup_revision(int(revno))
637
    t = b.revision_tree(rh)
638
    t.export(dest)
639
176 by mbp at sourcefrog
New cat command contributed by janmar.
640
def cmd_cat(revision, filename):
641
    """Print file to stdout."""
642
    b = Branch('.')
643
    b.print_file(b.relpath(filename), int(revision))
1 by mbp at sourcefrog
import from baz patch-364
644
645
646
######################################################################
647
# internal/test commands
648
649
650
def cmd_uuid():
651
    """Print a newly-generated UUID."""
63 by mbp at sourcefrog
fix up uuid command
652
    print bzrlib.osutils.uuid()
1 by mbp at sourcefrog
import from baz patch-364
653
654
655
8 by mbp at sourcefrog
store committer's timezone in revision and show
656
def cmd_local_time_offset():
657
    print bzrlib.osutils.local_time_offset()
658
659
660
57 by mbp at sourcefrog
error if --message is not given for commit
661
def cmd_commit(message=None, verbose=False):
97 by mbp at sourcefrog
- more commit help
662
    """Commit changes to a new revision.
663
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
664
    --message MESSAGE
665
        Description of changes in this revision; free form text.
666
        It is recommended that the first line be a single-sentence
667
        summary.
668
    --verbose
669
        Show status of changed files,
670
671
    TODO: Commit only selected files.
672
673
    TODO: Run hooks on tree to-be-committed, and after commit.
674
675
    TODO: Strict commit that fails if there are unknown or deleted files.
676
    """
97 by mbp at sourcefrog
- more commit help
677
57 by mbp at sourcefrog
error if --message is not given for commit
678
    if not message:
679
        bailout("please specify a commit message")
1 by mbp at sourcefrog
import from baz patch-364
680
    Branch('.').commit(message, verbose=verbose)
681
682
113 by mbp at sourcefrog
More help for check command
683
def cmd_check(dir='.'):
684
    """check: Consistency check of branch history.
685
232 by mbp at sourcefrog
Allow docstrings for help to be in PEP0257 format.
686
    usage: bzr check [-v] [BRANCH]
687
688
    options:
689
      --verbose, -v         Show progress of checking.
690
691
    This command checks various invariants about the branch storage to
692
    detect data corruption or bzr bugs.
693
    """
113 by mbp at sourcefrog
More help for check command
694
    import bzrlib.check
695
    bzrlib.check.check(Branch(dir, find_root=False))
1 by mbp at sourcefrog
import from baz patch-364
696
697
698
def cmd_is(pred, *rest):
699
    """Test whether PREDICATE is true."""
700
    try:
701
        cmd_handler = globals()['assert_' + pred.replace('-', '_')]
702
    except KeyError:
703
        bailout("unknown predicate: %s" % quotefn(pred))
704
        
705
    try:
706
        cmd_handler(*rest)
707
    except BzrCheckError:
708
        # by default we don't print the message so that this can
709
        # be used from shell scripts without producing noise
710
        sys.exit(1)
711
712
255 by Martin Pool
- New whoami command
713
def cmd_whoami():
714
    """Show bzr user id.
715
273 by Martin Pool
- New 'bzr help commands'
716
    usage: bzr whoami
717
255 by Martin Pool
- New whoami command
718
    TODO: Command to show only the email-address part as parsed out.
719
    """
1 by mbp at sourcefrog
import from baz patch-364
720
    print bzrlib.osutils.username()
721
722
723
def cmd_gen_revision_id():
724
    print bzrlib.branch._gen_revision_id(time.time())
725
726
184 by mbp at sourcefrog
pychecker fixups
727
def cmd_selftest():
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
728
    """Run internal test suite"""
1 by mbp at sourcefrog
import from baz patch-364
729
    ## -v, if present, is seen by doctest; the argument is just here
730
    ## so our parser doesn't complain
731
732
    ## TODO: --verbose option
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
733
734
    failures, tests = 0, 0
1 by mbp at sourcefrog
import from baz patch-364
735
    
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
736
    import doctest, bzrlib.store, bzrlib.tests
1 by mbp at sourcefrog
import from baz patch-364
737
    bzrlib.trace.verbose = False
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
738
739
    for m in bzrlib.store, bzrlib.inventory, bzrlib.branch, bzrlib.osutils, \
70 by mbp at sourcefrog
Prepare for smart recursive add.
740
        bzrlib.tree, bzrlib.tests, bzrlib.commands, bzrlib.add:
55 by mbp at sourcefrog
bzr selftest shows some counts of tests
741
        mf, mt = doctest.testmod(m)
742
        failures += mf
743
        tests += mt
744
        print '%-40s %3d tests' % (m.__name__, mt),
745
        if mf:
746
            print '%3d FAILED!' % mf
747
        else:
748
            print
749
750
    print '%-40s %3d tests' % ('total', tests),
751
    if failures:
752
        print '%3d FAILED!' % failures
753
    else:
754
        print
755
756
757
758
# deprecated
759
cmd_doctest = cmd_selftest
53 by mbp at sourcefrog
'selftest' command instead of 'doctest'
760
761
1 by mbp at sourcefrog
import from baz patch-364
762
######################################################################
763
# help
764
765
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
766
def cmd_help(topic=None):
767
    if topic == None:
768
        print __doc__
273 by Martin Pool
- New 'bzr help commands'
769
    elif topic == 'commands':
770
        help_commands()
771
    else:
772
        # otherwise, maybe the name of a command?
773
        topic, cmdfn = get_cmd_handler(topic)
774
775
        doc = getdoc(cmdfn)
776
        if doc == None:
777
            bailout("sorry, no detailed help yet for %r" % topic)
778
779
        print doc
780
781
782
def help_commands():
783
    """List all commands"""
784
    accu = []
785
    for k in globals().keys():
786
        if k.startswith('cmd_'):
787
            accu.append(k[4:].replace('_','-'))
788
    accu.sort()
789
    print "bzr commands: "
790
    for x in accu:
791
        print "   " + x
792
    print "note: some of these commands are internal-use or obsolete"
793
    # TODO: Some kind of marker for internal-use commands?
794
    # TODO: Show aliases?
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
795
        
796
1 by mbp at sourcefrog
import from baz patch-364
797
798
799
def cmd_version():
84 by mbp at sourcefrog
- update version string
800
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
801
    print bzrlib.__copyright__
1 by mbp at sourcefrog
import from baz patch-364
802
    print "http://bazaar-ng.org/"
803
    print
804
    print \
805
"""bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and
806
you may use, modify and redistribute it under the terms of the GNU 
807
General Public License version 2 or later."""
808
809
810
def cmd_rocks():
811
    """Statement of optimism."""
812
    print "it sure does!"
813
814
815
816
######################################################################
817
# main routine
818
819
820
# list of all available options; the rhs can be either None for an
821
# option that takes no argument, or a constructor function that checks
822
# the type.
823
OPTIONS = {
824
    'all':                    None,
825
    'help':                   None,
826
    'message':                unicode,
137 by mbp at sourcefrog
new --profile option
827
    'profile':                None,
1 by mbp at sourcefrog
import from baz patch-364
828
    'revision':               int,
829
    'show-ids':               None,
12 by mbp at sourcefrog
new --timezone option for bzr log
830
    'timezone':               str,
1 by mbp at sourcefrog
import from baz patch-364
831
    'verbose':                None,
832
    'version':                None,
833
    }
834
835
SHORT_OPTIONS = {
836
    'm':                      'message',
837
    'r':                      'revision',
838
    'v':                      'verbose',
839
}
840
841
# List of options that apply to particular commands; commands not
842
# listed take none.
843
cmd_options = {
844
    'add':                    ['verbose'],
176 by mbp at sourcefrog
New cat command contributed by janmar.
845
    'cat':                    ['revision'],
1 by mbp at sourcefrog
import from baz patch-364
846
    'commit':                 ['message', 'verbose'],
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
847
    'deleted':                ['show-ids'],
1 by mbp at sourcefrog
import from baz patch-364
848
    'diff':                   ['revision'],
849
    'inventory':              ['revision'],
244 by mbp at sourcefrog
- New 'bzr log --verbose' from Sebastian Cote
850
    'log':                    ['timezone', 'verbose'],
1 by mbp at sourcefrog
import from baz patch-364
851
    'ls':                     ['revision', 'verbose'],
12 by mbp at sourcefrog
new --timezone option for bzr log
852
    'remove':                 ['verbose'],
1 by mbp at sourcefrog
import from baz patch-364
853
    'status':                 ['all'],
854
    }
855
856
857
cmd_args = {
858
    'add':                    ['file+'],
176 by mbp at sourcefrog
New cat command contributed by janmar.
859
    'cat':                    ['filename'],
1 by mbp at sourcefrog
import from baz patch-364
860
    'commit':                 [],
196 by mbp at sourcefrog
selected-file diff
861
    'diff':                   ['file*'],
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
862
    'export':                 ['revno', 'dest'],
1 by mbp at sourcefrog
import from baz patch-364
863
    'file-id':                ['filename'],
178 by mbp at sourcefrog
- Use a non-null file_id for the branch root directory. At the moment
864
    'file-id-path':           ['filename'],
1 by mbp at sourcefrog
import from baz patch-364
865
    'get-file-text':          ['text_id'],
866
    'get-inventory':          ['inventory_id'],
867
    'get-revision':           ['revision_id'],
868
    'get-revision-inventory': ['revision_id'],
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
869
    'help':                   ['topic?'],
870
    'init':                   [],
1 by mbp at sourcefrog
import from baz patch-364
871
    'log':                    [],
872
    'lookup-revision':        ['revno'],
174 by mbp at sourcefrog
- New 'move' command; now separated out from rename
873
    'move':                   ['source$', 'dest'],
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
874
    'relpath':                ['filename'],
1 by mbp at sourcefrog
import from baz patch-364
875
    'remove':                 ['file+'],
168 by mbp at sourcefrog
new "rename" command
876
    'rename':                 ['from_name', 'to_name'],
164 by mbp at sourcefrog
new 'renames' command
877
    'renames':                ['dir?'],
83 by mbp at sourcefrog
Can now say "bzr help COMMAND" for more detailed help
878
    'root':                   ['filename?'],
1 by mbp at sourcefrog
import from baz patch-364
879
    'status':                 [],
880
    }
881
882
883
def parse_args(argv):
884
    """Parse command line.
885
    
886
    Arguments and options are parsed at this level before being passed
887
    down to specific command handlers.  This routine knows, from a
888
    lookup table, something about the available options, what optargs
889
    they take, and which commands will accept them.
890
31 by Martin Pool
fix up parse_args doctest
891
    >>> parse_args('--help'.split())
1 by mbp at sourcefrog
import from baz patch-364
892
    ([], {'help': True})
31 by Martin Pool
fix up parse_args doctest
893
    >>> parse_args('--version'.split())
1 by mbp at sourcefrog
import from baz patch-364
894
    ([], {'version': True})
31 by Martin Pool
fix up parse_args doctest
895
    >>> parse_args('status --all'.split())
1 by mbp at sourcefrog
import from baz patch-364
896
    (['status'], {'all': True})
31 by Martin Pool
fix up parse_args doctest
897
    >>> parse_args('commit --message=biter'.split())
17 by mbp at sourcefrog
allow --option=ARG syntax
898
    (['commit'], {'message': u'biter'})
1 by mbp at sourcefrog
import from baz patch-364
899
    """
900
    args = []
901
    opts = {}
902
903
    # TODO: Maybe handle '--' to end options?
904
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
905
    while argv:
906
        a = argv.pop(0)
1 by mbp at sourcefrog
import from baz patch-364
907
        if a[0] == '-':
264 by Martin Pool
parse_args: option names must be ascii
908
            # option names must not be unicode
909
            a = str(a)
17 by mbp at sourcefrog
allow --option=ARG syntax
910
            optarg = None
1 by mbp at sourcefrog
import from baz patch-364
911
            if a[1] == '-':
912
                mutter("  got option %r" % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
913
                if '=' in a:
914
                    optname, optarg = a[2:].split('=', 1)
915
                else:
916
                    optname = a[2:]
1 by mbp at sourcefrog
import from baz patch-364
917
                if optname not in OPTIONS:
918
                    bailout('unknown long option %r' % a)
919
            else:
920
                shortopt = a[1:]
921
                if shortopt not in SHORT_OPTIONS:
922
                    bailout('unknown short option %r' % a)
923
                optname = SHORT_OPTIONS[shortopt]
924
            
925
            if optname in opts:
926
                # XXX: Do we ever want to support this, e.g. for -r?
927
                bailout('repeated option %r' % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
928
                
1 by mbp at sourcefrog
import from baz patch-364
929
            optargfn = OPTIONS[optname]
930
            if optargfn:
17 by mbp at sourcefrog
allow --option=ARG syntax
931
                if optarg == None:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
932
                    if not argv:
17 by mbp at sourcefrog
allow --option=ARG syntax
933
                        bailout('option %r needs an argument' % a)
934
                    else:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
935
                        optarg = argv.pop(0)
17 by mbp at sourcefrog
allow --option=ARG syntax
936
                opts[optname] = optargfn(optarg)
1 by mbp at sourcefrog
import from baz patch-364
937
            else:
17 by mbp at sourcefrog
allow --option=ARG syntax
938
                if optarg != None:
939
                    bailout('option %r takes no argument' % optname)
1 by mbp at sourcefrog
import from baz patch-364
940
                opts[optname] = True
941
        else:
942
            args.append(a)
943
944
    return args, opts
945
946
947
948
def _match_args(cmd, args):
949
    """Check non-option arguments match required pattern.
950
951
    >>> _match_args('status', ['asdasdsadasd'])
952
    Traceback (most recent call last):
953
    ...
954
    BzrError: ("extra arguments to command status: ['asdasdsadasd']", [])
955
    >>> _match_args('add', ['asdasdsadasd'])
956
    {'file_list': ['asdasdsadasd']}
957
    >>> _match_args('add', 'abc def gj'.split())
958
    {'file_list': ['abc', 'def', 'gj']}
959
    """
960
    # match argument pattern
961
    argform = cmd_args.get(cmd, [])
962
    argdict = {}
963
    # TODO: Need a way to express 'cp SRC... DEST', where it matches
964
    # all but one.
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
965
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
966
    # step through args and argform, allowing appropriate 0-many matches
1 by mbp at sourcefrog
import from baz patch-364
967
    for ap in argform:
968
        argname = ap[:-1]
969
        if ap[-1] == '?':
62 by mbp at sourcefrog
- new find_branch_root function; based on suggestion from aaron
970
            if args:
971
                argdict[argname] = args.pop(0)
196 by mbp at sourcefrog
selected-file diff
972
        elif ap[-1] == '*': # all remaining arguments
973
            if args:
974
                argdict[argname + '_list'] = args[:]
975
                args = []
976
            else:
977
                argdict[argname + '_list'] = None
1 by mbp at sourcefrog
import from baz patch-364
978
        elif ap[-1] == '+':
979
            if not args:
980
                bailout("command %r needs one or more %s"
981
                        % (cmd, argname.upper()))
982
            else:
983
                argdict[argname + '_list'] = args[:]
984
                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
985
        elif ap[-1] == '$': # all but one
986
            if len(args) < 2:
987
                bailout("command %r needs one or more %s"
988
                        % (cmd, argname.upper()))
989
            argdict[argname + '_list'] = args[:-1]
990
            args[:-1] = []                
1 by mbp at sourcefrog
import from baz patch-364
991
        else:
992
            # just a plain arg
993
            argname = ap
994
            if not args:
995
                bailout("command %r requires argument %s"
996
                        % (cmd, argname.upper()))
997
            else:
998
                argdict[argname] = args.pop(0)
999
            
1000
    if args:
1001
        bailout("extra arguments to command %s: %r"
1002
                % (cmd, args))
1003
1004
    return argdict
1005
1006
1007
1008
def run_bzr(argv):
1009
    """Execute a command.
1010
1011
    This is similar to main(), but without all the trappings for
245 by mbp at sourcefrog
- control files always in utf-8-unix format
1012
    logging and error handling.  
1 by mbp at sourcefrog
import from baz patch-364
1013
    """
245 by mbp at sourcefrog
- control files always in utf-8-unix format
1014
251 by mbp at sourcefrog
- factor out locale.getpreferredencoding()
1015
    argv = [a.decode(bzrlib.user_encoding) for a in argv]
245 by mbp at sourcefrog
- control files always in utf-8-unix format
1016
    
1 by mbp at sourcefrog
import from baz patch-364
1017
    try:
26 by mbp at sourcefrog
fix StopIteration error on python2.3(?)
1018
        args, opts = parse_args(argv[1:])
1 by mbp at sourcefrog
import from baz patch-364
1019
        if 'help' in opts:
1020
            # TODO: pass down other arguments in case they asked for
1021
            # help on a command name?
159 by mbp at sourcefrog
bzr commit --help now works
1022
            if args:
1023
                cmd_help(args[0])
1024
            else:
1025
                cmd_help()
1 by mbp at sourcefrog
import from baz patch-364
1026
            return 0
1027
        elif 'version' in opts:
1028
            cmd_version()
1029
            return 0
265 by Martin Pool
parse_args: command names must also be ascii
1030
        cmd = str(args.pop(0))
1 by mbp at sourcefrog
import from baz patch-364
1031
    except IndexError:
257 by Martin Pool
- Write less startup junk to .bzr.log
1032
        log_error('usage: bzr COMMAND')
1033
        log_error('  try "bzr help"')
1 by mbp at sourcefrog
import from baz patch-364
1034
        return 1
115 by mbp at sourcefrog
todo
1035
272 by Martin Pool
- Add command aliases
1036
    canonical_cmd, cmd_handler = get_cmd_handler(cmd)
1 by mbp at sourcefrog
import from baz patch-364
1037
137 by mbp at sourcefrog
new --profile option
1038
    # global option
1039
    if 'profile' in opts:
1040
        profile = True
1041
        del opts['profile']
1042
    else:
1043
        profile = False
1 by mbp at sourcefrog
import from baz patch-364
1044
1045
    # check options are reasonable
272 by Martin Pool
- Add command aliases
1046
    allowed = cmd_options.get(canonical_cmd, [])
1 by mbp at sourcefrog
import from baz patch-364
1047
    for oname in opts:
1048
        if oname not in allowed:
1049
            bailout("option %r is not allowed for command %r"
1050
                    % (oname, cmd))
1051
176 by mbp at sourcefrog
New cat command contributed by janmar.
1052
    # TODO: give an error if there are any mandatory options which are
1053
    # not specified?  Or maybe there shouldn't be any "mandatory
1054
    # options" (it is an oxymoron)
1055
137 by mbp at sourcefrog
new --profile option
1056
    # mix arguments and options into one dictionary
272 by Martin Pool
- Add command aliases
1057
    cmdargs = _match_args(canonical_cmd, args)
136 by mbp at sourcefrog
new --show-ids option for 'deleted' command
1058
    for k, v in opts.items():
265 by Martin Pool
parse_args: command names must also be ascii
1059
        cmdargs[k.replace('-', '_')] = v
1 by mbp at sourcefrog
import from baz patch-364
1060
137 by mbp at sourcefrog
new --profile option
1061
    if profile:
1062
        import hotshot
239 by mbp at sourcefrog
- remove profiler temporary file when done
1063
        pffileno, pfname = tempfile.mkstemp()
1064
        try:
1065
            prof = hotshot.Profile(pfname)
1066
            ret = prof.runcall(cmd_handler, **cmdargs) or 0
1067
            prof.close()
1068
1069
            import hotshot.stats
1070
            stats = hotshot.stats.load(pfname)
1071
            #stats.strip_dirs()
1072
            stats.sort_stats('time')
1073
            ## XXX: Might like to write to stderr or the trace file instead but
1074
            ## print_stats seems hardcoded to stdout
1075
            stats.print_stats(20)
1076
            
1077
            return ret
1078
1079
        finally:
1080
            os.close(pffileno)
1081
            os.remove(pfname)
137 by mbp at sourcefrog
new --profile option
1082
    else:
1083
        return cmd_handler(**cmdargs) or 0
1 by mbp at sourcefrog
import from baz patch-364
1084
1085
1086
267 by Martin Pool
- better reporting of errors
1087
def _report_exception(e, summary):
1088
    import traceback
1089
    log_error('bzr: ' + summary)
1090
    bzrlib.trace.log_exception(e)
1091
    tb = sys.exc_info()[2]
275 by Martin Pool
- Show innermost not outermost frame location when reporting
1092
    exinfo = traceback.extract_tb(tb)
267 by Martin Pool
- better reporting of errors
1093
    if exinfo:
275 by Martin Pool
- Show innermost not outermost frame location when reporting
1094
        sys.stderr.write('  at %s:%d in %s()\n' % exinfo[-1][:3])
267 by Martin Pool
- better reporting of errors
1095
    sys.stderr.write('  see ~/.bzr.log for debug information\n')
1096
1097
1098
def cmd_assert_fail():
268 by Martin Pool
- more tests for assertion failures
1099
    assert False, "always fails"
267 by Martin Pool
- better reporting of errors
1100
1101
1 by mbp at sourcefrog
import from baz patch-364
1102
def main(argv):
59 by mbp at sourcefrog
lift out tracefile creation code
1103
    bzrlib.trace.create_tracefile(argv)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1104
1 by mbp at sourcefrog
import from baz patch-364
1105
    try:
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1106
        try:
1107
            ret = run_bzr(argv)
1108
            return ret
1109
        except BzrError, e:
267 by Martin Pool
- better reporting of errors
1110
            _report_exception(e, 'error: ' + e.args[0])
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1111
            if len(e.args) > 1:
1112
                for h in e.args[1]:
267 by Martin Pool
- better reporting of errors
1113
                    # some explanation or hints
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1114
                    log_error('  ' + h)
1115
            return 1
267 by Martin Pool
- better reporting of errors
1116
        except AssertionError, e:
1117
            msg = 'assertion failed'
1118
            if str(e):
1119
                msg += ': ' + str(e)
1120
            _report_exception(e, msg)
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1121
        except Exception, e:
267 by Martin Pool
- better reporting of errors
1122
            _report_exception(e, 'exception: %s' % str(e).rstrip('\n'))
260 by Martin Pool
- remove atexit() dependency for writing out execution times
1123
            return 1
1124
    finally:
1125
        bzrlib.trace.close_trace()
1 by mbp at sourcefrog
import from baz patch-364
1126
236 by mbp at sourcefrog
- Experiments in inventory performance
1127
    ## TODO: Trap AssertionError
1128
1129
    # TODO: Maybe nicer handling of IOError especially for broken pipe.
1 by mbp at sourcefrog
import from baz patch-364
1130
1131
1132
1133
if __name__ == '__main__':
1134
    sys.exit(main(sys.argv))