~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2005-03-14 07:07:24 UTC
  • Revision ID: mbp@sourcefrog.net-20050314070724-ba6c85db7d96c508
- add setup.py and install instructions
- rename main script to just bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
#! /usr/bin/env python
 
2
# -*- coding: UTF-8 -*-
2
3
 
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
40
41
 
41
42
 
42
43
 
43
 
def find_branch_root(f=None):
44
 
    """Find the branch root enclosing f, or pwd.
45
 
 
46
 
    It is not necessary that f exists.
47
 
 
48
 
    Basically we keep looking up until we find the control directory or
49
 
    run into the root."""
50
 
    if f is None:
51
 
        f = os.getcwd()
52
 
    elif hasattr(os.path, 'realpath'):
53
 
        f = os.path.realpath(f)
54
 
    else:
55
 
        f = os.path.abspath(f)
56
 
 
57
 
    orig_f = f
58
 
 
59
 
    last_f = f
60
 
    while True:
61
 
        if os.path.exists(os.path.join(f, bzrlib.BZRDIR)):
62
 
            return f
63
 
        head, tail = os.path.split(f)
64
 
        if head == f:
65
 
            # reached the root, whatever that may be
66
 
            bailout('%r is not in a branch' % orig_f)
67
 
        f = head
68
 
    
69
44
 
70
45
 
71
46
######################################################################
87
62
 
88
63
    :todo: mkdir() method.
89
64
    """
90
 
    def __init__(self, base, init=False, find_root=True):
 
65
    def __init__(self, base, init=False):
91
66
        """Create new branch object at a particular location.
92
67
 
93
68
        :param base: Base directory for the branch.
94
 
        
 
69
 
95
70
        :param init: If True, create new control files in a previously
96
71
             unversioned directory.  If False, the branch must already
97
72
             be versioned.
98
73
 
99
 
        :param find_root: If true and init is false, find the root of the
100
 
             existing branch containing base.
101
 
 
102
74
        In the test suite, creation of new trees is tested using the
103
75
        `ScratchBranch` class.
104
76
        """
 
77
        self.base = os.path.realpath(base)
105
78
        if init:
106
 
            self.base = os.path.realpath(base)
107
79
            self._make_control()
108
 
        elif find_root:
109
 
            self.base = find_branch_root(base)
110
80
        else:
111
 
            self.base = os.path.realpath(base)
112
81
            if not isdir(self.controlfilename('.')):
113
82
                bailout("not a bzr branch: %s" % quotefn(base),
114
83
                        ['use "bzr init" to initialize a new working tree',
115
84
                         'current bzr can only operate from top-of-tree'])
116
 
        self._check_format()
 
85
            self._check_format()
117
86
 
118
87
        self.text_store = ImmutableStore(self.controlfilename('text-store'))
119
88
        self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
127
96
    __repr__ = __str__
128
97
 
129
98
 
130
 
    def abspath(self, name):
131
 
        """Return absolute filename for something in the branch"""
 
99
    def _rel(self, name):
 
100
        """Return filename relative to branch top"""
132
101
        return os.path.join(self.base, name)
133
 
 
134
 
 
135
 
    def relpath(self, path):
136
 
        """Return path relative to this branch of something inside it.
137
 
 
138
 
        Raises an error if path is not in this branch."""
139
 
        rp = os.path.realpath(path)
140
 
        # FIXME: windows
141
 
        if not rp.startswith(self.base):
142
 
            bailout("path %r is not within branch %r" % (rp, self.base))
143
 
        rp = rp[len(self.base):]
144
 
        rp = rp.lstrip(os.sep)
145
 
        return rp
146
 
 
 
102
        
147
103
 
148
104
    def controlfilename(self, file_or_path):
149
105
        """Return location relative to branch."""
204
160
        will be committed to the next revision.
205
161
        """
206
162
        ## TODO: factor out to atomicfile?  is rename safe on windows?
207
 
        ## TODO: Maybe some kind of clean/dirty marker on inventory?
208
163
        tmpfname = self.controlfilename('inventory.tmp')
209
164
        tmpf = file(tmpfname, 'w')
210
165
        inv.write_xml(tmpf)
273
228
            if len(fp) == 0:
274
229
                bailout("cannot add top-level %r" % f)
275
230
                
276
 
            fullpath = os.path.normpath(self.abspath(f))
277
 
 
278
 
            try:
279
 
                kind = file_kind(fullpath)
280
 
            except OSError:
281
 
                # maybe something better?
282
 
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
283
 
            
284
 
            if kind != 'file' and kind != 'directory':
285
 
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
286
 
 
287
 
            file_id = gen_file_id(f)
288
 
            inv.add_path(f, kind=kind, file_id=file_id)
289
 
 
 
231
            fullpath = os.path.normpath(self._rel(f))
 
232
 
 
233
            if isfile(fullpath):
 
234
                kind = 'file'
 
235
            elif isdir(fullpath):
 
236
                kind = 'directory'
 
237
            else:
 
238
                bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
 
239
 
 
240
            if len(fp) > 1:
 
241
                parent_name = joinpath(fp[:-1])
 
242
                mutter("lookup parent %r" % parent_name)
 
243
                parent_id = inv.path2id(parent_name)
 
244
                if parent_id == None:
 
245
                    bailout("cannot add: parent %r is not versioned"
 
246
                            % joinpath(fp[:-1]))
 
247
            else:
 
248
                parent_id = None
 
249
 
 
250
            file_id = _gen_file_id(fp[-1])
 
251
            inv.add(InventoryEntry(file_id, fp[-1], kind=kind, parent_id=parent_id))
290
252
            if verbose:
291
253
                show_status('A', kind, quotefn(f))
292
254
                
293
 
            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
294
 
            
 
255
            mutter("add file %s file_id:{%s} kind=%r parent_id={%s}"
 
256
                   % (f, file_id, kind, parent_id))
295
257
        self._write_inventory(inv)
296
258
 
297
259
 
426
388
 
427
389
            entry = entry.copy()
428
390
 
429
 
            p = self.abspath(path)
 
391
            p = self._rel(path)
430
392
            file_id = entry.file_id
431
393
            mutter('commit prep file %s, id %r ' % (p, file_id))
432
394
 
472
434
                           entry.text_id)
473
435
                    
474
436
                else:
475
 
                    entry.text_id = gen_file_id(entry.name)
 
437
                    entry.text_id = _gen_file_id(entry.name)
476
438
                    self.text_store.add(content, entry.text_id)
477
439
                    mutter('    stored with text_id {%s}' % entry.text_id)
478
440
                    if verbose:
480
442
                            state = 'A'
481
443
                        elif (old_ie.name == entry.name
482
444
                              and old_ie.parent_id == entry.parent_id):
 
445
                            state = 'R'
 
446
                        else:
483
447
                            state = 'M'
484
 
                        else:
485
 
                            state = 'R'
486
448
 
487
449
                        show_status(state, entry.kind, quotefn(path))
488
450
 
542
504
        mutter("committing patch r%d" % (self.revno() + 1))
543
505
 
544
506
        mutter("append to revision-history")
545
 
        f = self.controlfile('revision-history', 'at')
546
 
        f.write(rev_id + '\n')
547
 
        f.close()
 
507
        self.controlfile('revision-history', 'at').write(rev_id + '\n')
548
508
 
549
 
        if verbose:
550
 
            note("commited r%d" % self.revno())
 
509
        mutter("done!")
551
510
 
552
511
 
553
512
    def get_revision(self, revision_id):
710
669
        A       foo
711
670
        >>> b.commit("add foo")
712
671
        >>> b.show_status()
713
 
        >>> os.unlink(b.abspath('foo'))
 
672
        >>> os.unlink(b._rel('foo'))
714
673
        >>> b.show_status()
715
674
        D       foo
716
675
        
767
726
    >>> isdir(bd)
768
727
    False
769
728
    """
770
 
    def __init__(self, files=[], dirs=[]):
 
729
    def __init__(self, files = []):
771
730
        """Make a test branch.
772
731
 
773
732
        This creates a temporary directory and runs init-tree in it.
775
734
        If any files are listed, they are created in the working copy.
776
735
        """
777
736
        Branch.__init__(self, tempfile.mkdtemp(), init=True)
778
 
        for d in dirs:
779
 
            os.mkdir(self.abspath(d))
780
 
            
781
737
        for f in files:
782
738
            file(os.path.join(self.base, f), 'w').write('content of %s' % f)
783
739
 
800
756
        ## mutter('check %r for control file' % ((head, tail), ))
801
757
        if tail == bzrlib.BZRDIR:
802
758
            return True
803
 
        if filename == head:
804
 
            break
805
759
        filename = head
806
760
    return False
807
761
 
814
768
    return s
815
769
 
816
770
 
817
 
def gen_file_id(name):
 
771
def _gen_file_id(name):
818
772
    """Return new file id.
819
773
 
820
774
    This should probably generate proper UUIDs, but for the moment we
821
775
    cope with just randomness because running uuidgen every time is
822
776
    slow."""
823
 
    idx = name.rfind('/')
824
 
    if idx != -1:
825
 
        name = name[idx+1 : ]
826
 
 
827
 
    name = name.lstrip('.')
828
 
 
 
777
    assert '/' not in name
 
778
    while name[0] == '.':
 
779
        name = name[1:]
829
780
    s = hexlify(rand_bytes(8))
830
781
    return '-'.join((name, compact_date(time.time()), s))
831
782