/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
#! /usr/bin/python
2
3
4
# Copyright (C) 2004, 2005 by Martin Pool
5
# Copyright (C) 2005 by Canonical Ltd
6
7
8
# This program is free software; you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation; either version 2 of the License, or
11
# (at your option) any later version.
12
13
# This program is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
# GNU General Public License for more details.
17
18
# You should have received a copy of the GNU General Public License
19
# along with this program; if not, write to the Free Software
20
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
22
"""Bazaar-NG -- a free distributed version-control tool
23
24
**WARNING: THIS IS AN UNSTABLE DEVELOPMENT VERSION**
25
26
Current limitation include:
27
28
* Metadata format is not stable yet -- you may need to
29
  discard history in the future.
30
31
* No handling of subdirectories, symlinks or any non-text files.
32
33
* Insufficient error handling.
34
35
* Many commands unimplemented or partially implemented.
36
37
* Space-inefficient storage.
38
39
* No merge operators yet.
40
41
Interesting commands::
42
43
  bzr help
44
       Show summary help screen
45
  bzr version
46
       Show software version/licence/non-warranty.
47
  bzr init
48
       Start versioning the current directory
49
  bzr add FILE...
50
       Make files versioned.
51
  bzr log
52
       Show revision history.
53
  bzr diff
54
       Show changes from last revision to working copy.
55
  bzr commit -m 'MESSAGE'
56
       Store current state as new revision.
57
  bzr export REVNO DESTINATION
58
       Export the branch state at a previous version.
59
  bzr status
60
       Show summary of pending changes.
61
  bzr remove FILE...
62
       Make a file not versioned.
63
"""
64
65
# not currently working:
66
#  bzr check
67
#       Run internal consistency checks.
68
#  bzr info
69
#       Show some information about this branch.
70
71
72
73
__copyright__ = "Copyright 2005 Canonical Development Ltd."
74
__author__ = "Martin Pool <mbp@canonical.com>"
75
__docformat__ = "restructuredtext en"
76
__version__ = '0.0.0'
77
78
79
import sys, os, random, time, sha, sets, types, re, shutil, tempfile
80
import traceback, socket, fnmatch, difflib
81
from os import path
82
from sets import Set
83
from pprint import pprint
84
from stat import *
85
from glob import glob
86
87
import bzrlib
88
from bzrlib.store import ImmutableStore
89
from bzrlib.trace import mutter, note, log_error
90
from bzrlib.errors import bailout, BzrError
91
from bzrlib.osutils import quotefn, pumpfile, isdir, isfile
92
from bzrlib.tree import RevisionTree, EmptyTree, WorkingTree, Tree
93
from bzrlib.revision import Revision
94
from bzrlib import Branch, Inventory, InventoryEntry, ScratchBranch, BZRDIR, \
95
     format_date
96
97
BZR_DIFF_FORMAT = "## Bazaar-NG diff, format 0 ##\n"
98
BZR_PATCHNAME_FORMAT = 'cset:sha1:%s'
99
100
## standard representation
101
NONE_STRING = '(none)'
102
EMPTY = 'empty'
103
104
105
## TODO: Perhaps a different version of inventory commands that
106
## returns iterators...
107
108
## TODO: Perhaps an AtomicFile class that writes to a temporary file and then renames.
109
110
## TODO: Some kind of locking on branches.  Perhaps there should be a
111
## parameter to the branch object saying whether we want a read or
112
## write lock; release it from destructor.  Perhaps don't even need a
113
## read lock to look at immutable objects?
114
115
## TODO: Perhaps make UUIDs predictable in test mode to make it easier
116
## to compare output?
117
118
119
120
121
######################################################################
122
# check status
123
124
125
def cmd_status(all=False):
126
    """Display status summary.
127
128
    For each file there is a single line giving its file state and name.
129
    The name is that in the current revision unless it is deleted or
130
    missing, in which case the old name is shown.
131
132
    :todo: Don't show unchanged files unless ``--all`` is given?
133
    """
134
    Branch('.').show_status(show_all=all)
135
136
137
138
######################################################################
139
# examining history
140
def cmd_get_revision(revision_id):
141
    Branch('.').get_revision(revision_id).write_xml(sys.stdout)
142
143
144
def cmd_get_inventory(inventory_id):
145
    """Return inventory in XML by hash"""
146
    Branch('.').get_inventory(inventory_hash).write_xml(sys.stdout)
147
148
149
def cmd_get_revision_inventory(revision_id):
150
    """Output inventory for a revision."""
151
    b = Branch('.')
152
    b.get_revision_inventory(revision_id).write_xml(sys.stdout)
153
154
155
def cmd_get_file_text(text_id):
156
    """Get contents of a file by hash."""
157
    sf = Branch('.').text_store[text_id]
158
    pumpfile(sf, sys.stdout)
159
160
161
162
######################################################################
163
# commands
164
    
165
166
def cmd_revno():
167
    """Show number of revisions on this branch"""
168
    print Branch('.').revno()
169
    
170
171
def cmd_add(file_list, verbose=False):
172
    """Add specified files.
173
    
174
    Fails if the files are already added.
175
    """
176
    Branch('.').add(file_list, verbose=verbose)
177
178
179
def cmd_inventory(revision=None):
180
    """Show inventory of the current working copy."""
181
    ## TODO: Also optionally show a previous inventory
182
    ## TODO: Format options
183
    b = Branch('.')
184
    if revision == None:
185
        inv = b.read_working_inventory()
186
    else:
187
        inv = b.get_revision_inventory(b.lookup_revision(revision))
188
        
189
    for path, entry in inv.iter_entries():
190
        print '%-50s %s' % (entry.file_id, path)
191
192
193
194
def cmd_info():
195
    b = Branch('.')
196
    print 'branch format:', b.controlfile('branch-format', 'r').readline().rstrip('\n')
197
    print 'revision number:', b.revno()
18 by mbp at sourcefrog
show count of versioned/unknown/ignored files
198
199
    count_versioned = count_unknown = count_ignored = 0
200
    count_version_dirs = 0
201
    for fpath, fclass, fkind, fid in b.working_tree().list_files():
202
        if fclass == 'V':
203
            count_versioned += 1
204
            if fkind == 'directory':
205
                count_version_dirs += 1
206
        elif fclass == 'I':
207
            count_ignored += 1
208
        elif fclass == '?':
209
            count_unknown += 1
210
        else:
211
            bailout('unknown file class %r for %r' % (fclass, fpath))
212
   
213
    print 'number of versioned entries: %d' % count_versioned
214
    print 'number of versioned subdirectories: %d' % count_version_dirs
215
    print 'number of unknown files: %d' % count_unknown
216
    print 'number of ignored files: %d' % count_ignored
217
218
            
1 by mbp at sourcefrog
import from baz patch-364
219
220
221
def cmd_remove(file_list, verbose=False):
222
    Branch('.').remove(file_list, verbose=verbose)
223
224
225
226
def cmd_file_id(filename):
227
    i = Branch('.').read_working_inventory().path2id(filename)
228
    if i is None:
229
        bailout("%s is not a versioned file" % filename)
230
    else:
231
        print i
232
233
234
def cmd_find_filename(fileid):
235
    n = find_filename(fileid)
236
    if n is None:
237
        bailout("%s is not a live file id" % fileid)
238
    else:
239
        print n
240
241
242
def cmd_revision_history():
243
    for patchid in Branch('.').revision_history():
244
        print patchid
245
246
247
248
def cmd_init():
249
    # TODO: Check we're not already in a working directory?  At the
250
    # moment you'll get an ugly error.
251
    
252
    # TODO: What if we're in a subdirectory of a branch?  Would like
253
    # to allow that, but then the parent may need to understand that
254
    # the children have disappeared, or should they be versioned in
255
    # both?
256
257
    # TODO: Take an argument/option for branch name.
258
    Branch('.', init=True)
259
260
261
def cmd_diff(revision=None):
262
    """Show diff from basis to working copy.
263
264
    :todo: Take one or two revision arguments, look up those trees,
265
           and diff them.
266
267
    :todo: Allow diff across branches.
268
269
    :todo: Mangle filenames in diff to be more relevant.
270
271
    :todo: Shouldn't be in the cmd function.
272
    """
273
274
    b = Branch('.')
275
276
    if revision == None:
277
        old_tree = b.basis_tree()
278
    else:
279
        old_tree = b.revision_tree(b.lookup_revision(revision))
280
        
281
    new_tree = b.working_tree()
282
    old_inv = old_tree.inventory
283
    new_inv = new_tree.inventory
284
285
    # TODO: Options to control putting on a prefix or suffix, perhaps as a format string
286
    old_label = ''
287
    new_label = ''
288
289
    DEVNULL = '/dev/null'
290
    # Windows users, don't panic about this filename -- it is a
291
    # special signal to GNU patch that the file should be created or
292
    # deleted respectively.
293
294
    # TODO: Generation of pseudo-diffs for added/deleted files could
295
    # be usefully made into a much faster special case.
296
297
    # TODO: Better to return them in sorted order I think.
298
    
299
    for file_state, fid, old_name, new_name, kind in bzrlib.diff_trees(old_tree, new_tree):
300
        d = None
301
302
        # Don't show this by default; maybe do it if an option is passed
303
        # idlabel = '      {%s}' % fid
304
        idlabel = ''
305
306
        # FIXME: Something about the diff format makes patch unhappy
307
        # with newly-added files.
308
309
        def diffit(*a, **kw):
310
            sys.stdout.writelines(difflib.unified_diff(*a, **kw))
311
            print
312
        
313
        if file_state in ['.', '?', 'I']:
314
            continue
315
        elif file_state == 'A':
316
            print '*** added %s %r' % (kind, new_name)
317
            if kind == 'file':
318
                diffit([],
319
                       new_tree.get_file(fid).readlines(),
320
                       fromfile=DEVNULL,
321
                       tofile=new_label + new_name + idlabel)
322
        elif file_state == 'D':
323
            assert isinstance(old_name, types.StringTypes)
324
            print '*** deleted %s %r' % (kind, old_name)
325
            if kind == 'file':
326
                diffit(old_tree.get_file(fid).readlines(), [],
327
                       fromfile=old_label + old_name + idlabel,
328
                       tofile=DEVNULL)
329
        elif file_state in ['M', 'R']:
330
            if file_state == 'M':
331
                assert kind == 'file'
332
                assert old_name == new_name
333
                print '*** modified %s %r' % (kind, new_name)
334
            elif file_state == 'R':
335
                print '*** renamed %s %r => %r' % (kind, old_name, new_name)
336
337
            if kind == 'file':
338
                diffit(old_tree.get_file(fid).readlines(),
339
                       new_tree.get_file(fid).readlines(),
340
                       fromfile=old_label + old_name + idlabel,
341
                       tofile=new_label + new_name)
342
        else:
343
            bailout("can't represent state %s {%s}" % (file_state, fid))
344
345
346
13 by mbp at sourcefrog
fix up cmd_log args
347
def cmd_log(timezone='original'):
1 by mbp at sourcefrog
import from baz patch-364
348
    """Show log of this branch.
349
350
    :todo: Options for utc; to show ids; to limit range; etc.
351
    """
12 by mbp at sourcefrog
new --timezone option for bzr log
352
    Branch('.').write_log(show_timezone=timezone)
1 by mbp at sourcefrog
import from baz patch-364
353
354
355
def cmd_ls(revision=None, verbose=False):
356
    """List files in a tree.
357
358
    :todo: Take a revision or remote path and list that tree instead.
359
    """
360
    b = Branch('.')
361
    if revision == None:
362
        tree = b.working_tree()
363
    else:
364
        tree = b.revision_tree(b.lookup_revision(revision))
365
        
366
    for fp, fc, kind, fid in tree.list_files():
367
        if verbose:
368
            if kind == 'directory':
369
                kindch = '/'
370
            elif kind == 'file':
371
                kindch = ''
372
            else:
373
                kindch = '???'
374
                
375
            print '%-8s %s%s' % (fc, fp, kindch)
376
        else:
377
            print fp
378
    
379
    
380
381
def cmd_unknowns():
382
    """List unknown files"""
383
    for f in Branch('.').unknowns():
384
        print quotefn(f)
385
386
387
def cmd_lookup_revision(revno):
388
    try:
389
        revno = int(revno)
390
    except ValueError:
391
        bailout("usage: lookup-revision REVNO",
392
                ["REVNO is a non-negative revision number for this branch"])
393
394
    print Branch('.').lookup_revision(revno) or NONE_STRING
395
396
397
398
def cmd_export(revno, dest):
399
    """Export past revision to destination directory."""
400
    b = Branch('.')
401
    rh = b.lookup_revision(int(revno))
402
    t = b.revision_tree(rh)
403
    t.export(dest)
404
405
406
407
######################################################################
408
# internal/test commands
409
410
411
def cmd_uuid():
412
    """Print a newly-generated UUID."""
413
    print uuid()
414
415
416
8 by mbp at sourcefrog
store committer's timezone in revision and show
417
def cmd_local_time_offset():
418
    print bzrlib.osutils.local_time_offset()
419
420
421
1 by mbp at sourcefrog
import from baz patch-364
422
def cmd_commit(message, verbose=False):
423
    Branch('.').commit(message, verbose=verbose)
424
425
426
def cmd_check():
427
    """Check consistency of the branch."""
428
    check()
429
430
431
def cmd_is(pred, *rest):
432
    """Test whether PREDICATE is true."""
433
    try:
434
        cmd_handler = globals()['assert_' + pred.replace('-', '_')]
435
    except KeyError:
436
        bailout("unknown predicate: %s" % quotefn(pred))
437
        
438
    try:
439
        cmd_handler(*rest)
440
    except BzrCheckError:
441
        # by default we don't print the message so that this can
442
        # be used from shell scripts without producing noise
443
        sys.exit(1)
444
445
446
def cmd_username():
447
    print bzrlib.osutils.username()
448
449
450
def cmd_user_email():
451
    print bzrlib.osutils.user_email()
452
453
454
def cmd_gen_revision_id():
455
    import time
456
    print bzrlib.branch._gen_revision_id(time.time())
457
458
459
def cmd_doctest():
460
    """Run internal doctest suite"""
461
    ## -v, if present, is seen by doctest; the argument is just here
462
    ## so our parser doesn't complain
463
464
    ## TODO: --verbose option
465
    
466
    import bzr, doctest, bzrlib.store
467
    bzrlib.trace.verbose = False
468
    doctest.testmod(bzr)
469
    doctest.testmod(bzrlib.store)
470
    doctest.testmod(bzrlib.inventory)
471
    doctest.testmod(bzrlib.branch)
472
    doctest.testmod(bzrlib.osutils)
473
    doctest.testmod(bzrlib.tree)
474
475
    # more strenuous tests;
476
    import bzrlib.tests
477
    doctest.testmod(bzrlib.tests)
478
479
480
######################################################################
481
# help
482
483
484
def cmd_help():
485
    # TODO: Specific help for particular commands
486
    print __doc__
487
488
489
def cmd_version():
490
    print "bzr (bazaar-ng) %s" % __version__
491
    print __copyright__
492
    print "http://bazaar-ng.org/"
493
    print
494
    print \
495
"""bzr comes with ABSOLUTELY NO WARRANTY.  bzr is free software, and
496
you may use, modify and redistribute it under the terms of the GNU 
497
General Public License version 2 or later."""
498
499
500
def cmd_rocks():
501
    """Statement of optimism."""
502
    print "it sure does!"
503
504
505
506
######################################################################
507
# main routine
508
509
510
# list of all available options; the rhs can be either None for an
511
# option that takes no argument, or a constructor function that checks
512
# the type.
513
OPTIONS = {
514
    'all':                    None,
515
    'help':                   None,
516
    'message':                unicode,
517
    'revision':               int,
518
    'show-ids':               None,
12 by mbp at sourcefrog
new --timezone option for bzr log
519
    'timezone':               str,
1 by mbp at sourcefrog
import from baz patch-364
520
    'verbose':                None,
521
    'version':                None,
522
    }
523
524
SHORT_OPTIONS = {
525
    'm':                      'message',
526
    'r':                      'revision',
527
    'v':                      'verbose',
528
}
529
530
# List of options that apply to particular commands; commands not
531
# listed take none.
532
cmd_options = {
533
    'add':                    ['verbose'],
534
    'commit':                 ['message', 'verbose'],
535
    'diff':                   ['revision'],
536
    'inventory':              ['revision'],
12 by mbp at sourcefrog
new --timezone option for bzr log
537
    'log':                    ['show-ids', 'timezone'],
1 by mbp at sourcefrog
import from baz patch-364
538
    'ls':                     ['revision', 'verbose'],
12 by mbp at sourcefrog
new --timezone option for bzr log
539
    'remove':                 ['verbose'],
1 by mbp at sourcefrog
import from baz patch-364
540
    'status':                 ['all'],
541
    }
542
543
544
cmd_args = {
545
    'init':                   [],
546
    'add':                    ['file+'],
547
    'commit':                 [],
548
    'diff':                   [],
549
    'file-id':                ['filename'],
550
    'get-file-text':          ['text_id'],
551
    'get-inventory':          ['inventory_id'],
552
    'get-revision':           ['revision_id'],
553
    'get-revision-inventory': ['revision_id'],
554
    'log':                    [],
555
    'lookup-revision':        ['revno'],
556
    'export':                 ['revno', 'dest'],
557
    'remove':                 ['file+'],
558
    'status':                 [],
559
    }
560
561
562
def parse_args(argv):
563
    """Parse command line.
564
    
565
    Arguments and options are parsed at this level before being passed
566
    down to specific command handlers.  This routine knows, from a
567
    lookup table, something about the available options, what optargs
568
    they take, and which commands will accept them.
569
570
    >>> parse_args('bzr --help'.split())
571
    ([], {'help': True})
572
    >>> parse_args('bzr --version'.split())
573
    ([], {'version': True})
574
    >>> parse_args('bzr status --all'.split())
575
    (['status'], {'all': True})
17 by mbp at sourcefrog
allow --option=ARG syntax
576
    >>> parse_args('bzr commit --message=biter'.split())
577
    (['commit'], {'message': u'biter'})
1 by mbp at sourcefrog
import from baz patch-364
578
    """
579
    args = []
580
    opts = {}
581
582
    # TODO: Maybe handle '--' to end options?
583
584
    it = iter(argv[1:])
585
    while it:
586
        a = it.next()
587
        if a[0] == '-':
17 by mbp at sourcefrog
allow --option=ARG syntax
588
            optarg = None
1 by mbp at sourcefrog
import from baz patch-364
589
            if a[1] == '-':
590
                mutter("  got option %r" % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
591
                if '=' in a:
592
                    optname, optarg = a[2:].split('=', 1)
593
                else:
594
                    optname = a[2:]
1 by mbp at sourcefrog
import from baz patch-364
595
                if optname not in OPTIONS:
596
                    bailout('unknown long option %r' % a)
597
            else:
598
                shortopt = a[1:]
599
                if shortopt not in SHORT_OPTIONS:
600
                    bailout('unknown short option %r' % a)
601
                optname = SHORT_OPTIONS[shortopt]
602
            
603
            if optname in opts:
604
                # XXX: Do we ever want to support this, e.g. for -r?
605
                bailout('repeated option %r' % a)
17 by mbp at sourcefrog
allow --option=ARG syntax
606
                
1 by mbp at sourcefrog
import from baz patch-364
607
            optargfn = OPTIONS[optname]
608
            if optargfn:
17 by mbp at sourcefrog
allow --option=ARG syntax
609
                if optarg == None:
610
                    if not it:
611
                        bailout('option %r needs an argument' % a)
612
                    else:
613
                        optarg = it.next()
614
                opts[optname] = optargfn(optarg)
1 by mbp at sourcefrog
import from baz patch-364
615
                mutter("    option argument %r" % opts[optname])
616
            else:
17 by mbp at sourcefrog
allow --option=ARG syntax
617
                if optarg != None:
618
                    bailout('option %r takes no argument' % optname)
1 by mbp at sourcefrog
import from baz patch-364
619
                opts[optname] = True
620
        else:
621
            args.append(a)
622
623
    return args, opts
624
625
626
627
def _match_args(cmd, args):
628
    """Check non-option arguments match required pattern.
629
630
    >>> _match_args('status', ['asdasdsadasd'])
631
    Traceback (most recent call last):
632
    ...
633
    BzrError: ("extra arguments to command status: ['asdasdsadasd']", [])
634
    >>> _match_args('add', ['asdasdsadasd'])
635
    {'file_list': ['asdasdsadasd']}
636
    >>> _match_args('add', 'abc def gj'.split())
637
    {'file_list': ['abc', 'def', 'gj']}
638
    """
639
    # match argument pattern
640
    argform = cmd_args.get(cmd, [])
641
    argdict = {}
642
    # TODO: Need a way to express 'cp SRC... DEST', where it matches
643
    # all but one.
644
    for ap in argform:
645
        argname = ap[:-1]
646
        if ap[-1] == '?':
647
            assert 0
648
        elif ap[-1] == '*':
649
            assert 0
650
        elif ap[-1] == '+':
651
            if not args:
652
                bailout("command %r needs one or more %s"
653
                        % (cmd, argname.upper()))
654
            else:
655
                argdict[argname + '_list'] = args[:]
656
                args = []
657
        else:
658
            # just a plain arg
659
            argname = ap
660
            if not args:
661
                bailout("command %r requires argument %s"
662
                        % (cmd, argname.upper()))
663
            else:
664
                argdict[argname] = args.pop(0)
665
            
666
    if args:
667
        bailout("extra arguments to command %s: %r"
668
                % (cmd, args))
669
670
    return argdict
671
672
673
674
def run_bzr(argv):
675
    """Execute a command.
676
677
    This is similar to main(), but without all the trappings for
678
    logging and error handling.
679
    """
680
    try:
681
        args, opts = parse_args(argv)
682
        if 'help' in opts:
683
            # TODO: pass down other arguments in case they asked for
684
            # help on a command name?
685
            cmd_help()
686
            return 0
687
        elif 'version' in opts:
688
            cmd_version()
689
            return 0
690
        cmd = args.pop(0)
691
    except IndexError:
692
        log_error('usage: bzr COMMAND\n')
693
        log_error('  try "bzr help"\n')
694
        return 1
695
            
696
    try:
697
        cmd_handler = globals()['cmd_' + cmd.replace('-', '_')]
698
    except KeyError:
699
        bailout("unknown command " + `cmd`)
700
701
    # TODO: special --profile option to turn on the Python profiler
702
703
    # check options are reasonable
704
    allowed = cmd_options.get(cmd, [])
705
    for oname in opts:
706
        if oname not in allowed:
707
            bailout("option %r is not allowed for command %r"
708
                    % (oname, cmd))
709
710
    cmdargs = _match_args(cmd, args)
711
    cmdargs.update(opts)
712
713
    ret = cmd_handler(**cmdargs) or 0
714
715
716
717
def main(argv):
718
    ## TODO: Handle command-line options; probably know what options are valid for
719
    ## each command
720
721
    ## TODO: If the arguments are wrong, give a usage message rather
722
    ## than just a backtrace.
723
724
    try:
725
        t = bzrlib.trace._tracefile
726
        t.write('-' * 60 + '\n')
727
        t.write('bzr invoked at %s\n' % format_date(time.time()))
728
        t.write('  by %s on %s\n' % (bzrlib.osutils.username(), socket.gethostname()))
729
        t.write('  arguments: %r\n' % argv)
730
731
        starttime = os.times()[4]
732
733
        import platform
734
        t.write('  platform: %s\n' % platform.platform())
735
        t.write('  python: %s\n' % platform.python_version())
736
737
        ret = run_bzr(argv)
738
        
739
        times = os.times()
740
        mutter("finished, %.3fu/%.3fs cpu, %.3fu/%.3fs cum"
741
               % times[:4])
742
        mutter("    %.3f elapsed" % (times[4] - starttime))
743
744
        return ret
745
    except BzrError, e:
746
        log_error('bzr: error: ' + e.args[0] + '\n')
747
        if len(e.args) > 1:
748
            for h in e.args[1]:
749
                log_error('  ' + h + '\n')
750
        return 1
751
    except Exception, e:
752
        log_error('bzr: exception: %s\n' % e)
753
        log_error('    see .bzr.log for details\n')
754
        traceback.print_exc(None, bzrlib.trace._tracefile)
755
        traceback.print_exc(None, sys.stderr)
756
        return 1
757
758
    # TODO: Maybe nicer handling of IOError?
759
760
761
762
if __name__ == '__main__':
763
    sys.exit(main(sys.argv))
764
    ##import profile
765
    ##profile.run('main(sys.argv)')
766