~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2005-03-15 05:19:54 UTC
  • Revision ID: mbp@sourcefrog.net-20050315051954-e4bdd6dfd26f8ecf
witty comment

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:
707
669
        A       foo
708
670
        >>> b.commit("add foo")
709
671
        >>> b.show_status()
710
 
        >>> os.unlink(b.abspath('foo'))
 
672
        >>> os.unlink(b._rel('foo'))
711
673
        >>> b.show_status()
712
674
        D       foo
713
675
        
794
756
        ## mutter('check %r for control file' % ((head, tail), ))
795
757
        if tail == bzrlib.BZRDIR:
796
758
            return True
797
 
        if filename == head:
798
 
            break
799
759
        filename = head
800
760
    return False
801
761
 
808
768
    return s
809
769
 
810
770
 
811
 
def gen_file_id(name):
 
771
def _gen_file_id(name):
812
772
    """Return new file id.
813
773
 
814
774
    This should probably generate proper UUIDs, but for the moment we
815
775
    cope with just randomness because running uuidgen every time is
816
776
    slow."""
817
 
    idx = name.rfind('/')
818
 
    if idx != -1:
819
 
        name = name[idx+1 : ]
820
 
 
821
 
    name = name.lstrip('.')
822
 
 
 
777
    assert '/' not in name
 
778
    while name[0] == '.':
 
779
        name = name[1:]
823
780
    s = hexlify(rand_bytes(8))
824
781
    return '-'.join((name, compact_date(time.time()), s))
825
782