43
def find_branch_root(f=None):
44
"""Find the branch root enclosing f, or pwd.
46
It is not necessary that f exists.
48
Basically we keep looking up until we find the control directory or
52
elif hasattr(os.path, 'realpath'):
53
f = os.path.realpath(f)
55
f = os.path.abspath(f)
61
if os.path.exists(os.path.join(f, bzrlib.BZRDIR)):
63
head, tail = os.path.split(f)
65
# reached the root, whatever that may be
66
bailout('%r is not in a branch' % orig_f)
46
71
######################################################################
63
88
:todo: mkdir() method.
65
def __init__(self, base, init=False):
90
def __init__(self, base, init=False, find_root=True):
66
91
"""Create new branch object at a particular location.
68
93
:param base: Base directory for the branch.
70
95
:param init: If True, create new control files in a previously
71
96
unversioned directory. If False, the branch must already
99
:param find_root: If true and init is false, find the root of the
100
existing branch containing base.
74
102
In the test suite, creation of new trees is tested using the
75
103
`ScratchBranch` class.
77
self.base = os.path.realpath(base)
106
self.base = os.path.realpath(base)
79
107
self._make_control()
109
self.base = find_branch_root(base)
111
self.base = os.path.realpath(base)
81
112
if not isdir(self.controlfilename('.')):
82
113
bailout("not a bzr branch: %s" % quotefn(base),
83
114
['use "bzr init" to initialize a new working tree',
84
115
'current bzr can only operate from top-of-tree'])
87
118
self.text_store = ImmutableStore(self.controlfilename('text-store'))
88
119
self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
96
127
__repr__ = __str__
100
"""Return filename relative to branch top"""
130
def abspath(self, name):
131
"""Return absolute filename for something in the branch"""
101
132
return os.path.join(self.base, name)
135
def relpath(self, path):
136
"""Return path relative to this branch of something inside it.
138
Raises an error if path is not in this branch."""
139
rp = os.path.realpath(path)
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)
104
148
def controlfilename(self, file_or_path):
105
149
"""Return location relative to branch."""
160
204
will be committed to the next revision.
162
206
## TODO: factor out to atomicfile? is rename safe on windows?
207
## TODO: Maybe some kind of clean/dirty marker on inventory?
163
208
tmpfname = self.controlfilename('inventory.tmp')
164
209
tmpf = file(tmpfname, 'w')
165
210
inv.write_xml(tmpf)
229
274
bailout("cannot add top-level %r" % f)
231
fullpath = os.path.normpath(self._rel(f))
235
elif isdir(fullpath):
238
bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
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"
250
file_id = _gen_file_id(fp[-1])
251
inv.add(InventoryEntry(file_id, fp[-1], kind=kind, parent_id=parent_id))
276
fullpath = os.path.normpath(self.abspath(f))
279
kind = file_kind(fullpath)
281
# maybe something better?
282
bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
284
if kind != 'file' and kind != 'directory':
285
bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
287
file_id = gen_file_id(f)
288
inv.add_path(f, kind=kind, file_id=file_id)
253
291
show_status('A', kind, quotefn(f))
255
mutter("add file %s file_id:{%s} kind=%r parent_id={%s}"
256
% (f, file_id, kind, parent_id))
293
mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
257
295
self._write_inventory(inv)
437
entry.text_id = _gen_file_id(entry.name)
475
entry.text_id = gen_file_id(entry.name)
438
476
self.text_store.add(content, entry.text_id)
439
477
mutter(' stored with text_id {%s}' % entry.text_id)
504
542
mutter("committing patch r%d" % (self.revno() + 1))
506
544
mutter("append to revision-history")
507
self.controlfile('revision-history', 'at').write(rev_id + '\n')
545
f = self.controlfile('revision-history', 'at')
546
f.write(rev_id + '\n')
550
note("commited r%d" % self.revno())
512
553
def get_revision(self, revision_id):
729
def __init__(self, files = []):
770
def __init__(self, files=[], dirs=[]):
730
771
"""Make a test branch.
732
773
This creates a temporary directory and runs init-tree in it.
734
775
If any files are listed, they are created in the working copy.
736
777
Branch.__init__(self, tempfile.mkdtemp(), init=True)
779
os.mkdir(self.abspath(d))
738
782
file(os.path.join(self.base, f), 'w').write('content of %s' % f)
771
def _gen_file_id(name):
817
def gen_file_id(name):
772
818
"""Return new file id.
774
820
This should probably generate proper UUIDs, but for the moment we
775
821
cope with just randomness because running uuidgen every time is
777
assert '/' not in name
778
while name[0] == '.':
823
idx = name.rfind('/')
825
name = name[idx+1 : ]
827
name = name.lstrip('.')
780
829
s = hexlify(rand_bytes(8))
781
830
return '-'.join((name, compact_date(time.time()), s))