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)
71
46
######################################################################
88
63
:todo: mkdir() method.
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.
93
68
:param base: Base directory for the branch.
95
70
:param init: If True, create new control files in a previously
96
71
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.
102
74
In the test suite, creation of new trees is tested using the
103
75
`ScratchBranch` class.
77
self.base = os.path.realpath(base)
106
self.base = os.path.realpath(base)
107
79
self._make_control()
109
self.base = find_branch_root(base)
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'])
118
87
self.text_store = ImmutableStore(self.controlfilename('text-store'))
119
88
self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
127
96
__repr__ = __str__
130
def abspath(self, name):
131
"""Return absolute filename for something in the branch"""
100
"""Return filename relative to branch top"""
132
101
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)
148
104
def controlfilename(self, file_or_path):
149
105
"""Return location relative to branch."""
204
160
will be committed to the next revision.
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)
274
229
bailout("cannot add top-level %r" % f)
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)
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))
291
253
show_status('A', kind, quotefn(f))
293
mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
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)
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)
542
504
mutter("committing patch r%d" % (self.revno() + 1))
544
506
mutter("append to revision-history")
545
f = self.controlfile('revision-history', 'at')
546
f.write(rev_id + '\n')
507
self.controlfile('revision-history', 'at').write(rev_id + '\n')
550
note("commited r%d" % self.revno())
553
512
def get_revision(self, revision_id):
770
def __init__(self, files=[], dirs=[]):
729
def __init__(self, files = []):
771
730
"""Make a test branch.
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.
777
736
Branch.__init__(self, tempfile.mkdtemp(), init=True)
779
os.mkdir(self.abspath(d))
782
738
file(os.path.join(self.base, f), 'w').write('content of %s' % f)
817
def gen_file_id(name):
771
def _gen_file_id(name):
818
772
"""Return new file id.
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
823
idx = name.rfind('/')
825
name = name[idx+1 : ]
827
name = name.lstrip('.')
777
assert '/' not in name
778
while name[0] == '.':
829
780
s = hexlify(rand_bytes(8))
830
781
return '-'.join((name, compact_date(time.time()), s))