28
29
from inventory import InventoryEntry, Inventory
29
30
from osutils import isdir, quotefn, isfile, uuid, sha_file, username, chomp, \
30
31
format_date, compact_date, pumpfile, user_email, rand_bytes, splitpath, \
31
joinpath, sha_string, file_kind, local_time_offset, appendpath
32
joinpath, sha_string, file_kind, local_time_offset
32
33
from store import ImmutableStore
33
34
from revision import Revision
34
from errors import bailout, BzrError
35
from errors import bailout
35
36
from textui import show_status
36
37
from diff import diff_trees
87
63
:todo: mkdir() method.
89
def __init__(self, base, init=False, find_root=True):
65
def __init__(self, base, init=False):
90
66
"""Create new branch object at a particular location.
92
68
:param base: Base directory for the branch.
94
70
:param init: If True, create new control files in a previously
95
71
unversioned directory. If False, the branch must already
98
:param find_root: If true and init is false, find the root of the
99
existing branch containing base.
101
74
In the test suite, creation of new trees is tested using the
102
75
`ScratchBranch` class.
77
self.base = os.path.realpath(base)
105
self.base = os.path.realpath(base)
106
79
self._make_control()
108
self.base = find_branch_root(base)
110
self.base = os.path.realpath(base)
111
81
if not isdir(self.controlfilename('.')):
112
82
bailout("not a bzr branch: %s" % quotefn(base),
113
83
['use "bzr init" to initialize a new working tree',
114
84
'current bzr can only operate from top-of-tree'])
117
87
self.text_store = ImmutableStore(self.controlfilename('text-store'))
118
88
self.revision_store = ImmutableStore(self.controlfilename('revision-store'))
279
229
bailout("cannot add top-level %r" % f)
281
fullpath = os.path.normpath(self.abspath(f))
284
kind = file_kind(fullpath)
286
# maybe something better?
287
bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
289
if kind != 'file' and kind != 'directory':
290
bailout('cannot add: not a regular file or directory: %s' % quotefn(f))
292
file_id = gen_file_id(f)
293
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))
296
253
show_status('A', kind, quotefn(f))
298
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))
300
257
self._write_inventory(inv)
303
def print_file(self, file, revno):
304
"""Print `file` to stdout."""
305
tree = self.revision_tree(self.lookup_revision(revno))
306
# use inventory as it was in that revision
307
file_id = tree.inventory.path2id(file)
309
bailout("%r is not present in revision %d" % (file, revno))
310
tree.print_file(file_id)
313
261
def remove(self, files, verbose=False):
314
262
"""Mark nominated files for removal from the inventory.
715
def rename_one(self, from_rel, to_rel):
716
tree = self.working_tree()
718
if not tree.has_filename(from_rel):
719
bailout("can't rename: old working file %r does not exist" % from_rel)
720
if tree.has_filename(to_rel):
721
bailout("can't rename: new working file %r already exists" % to_rel)
723
file_id = inv.path2id(from_rel)
725
bailout("can't rename: old name %r is not versioned" % from_rel)
727
if inv.path2id(to_rel):
728
bailout("can't rename: new name %r is already versioned" % to_rel)
730
to_dir, to_tail = os.path.split(to_rel)
731
to_dir_id = inv.path2id(to_dir)
732
if to_dir_id == None and to_dir != '':
733
bailout("can't determine destination directory id for %r" % to_dir)
735
mutter("rename_one:")
736
mutter(" file_id {%s}" % file_id)
737
mutter(" from_rel %r" % from_rel)
738
mutter(" to_rel %r" % to_rel)
739
mutter(" to_dir %r" % to_dir)
740
mutter(" to_dir_id {%s}" % to_dir_id)
742
inv.rename(file_id, to_dir_id, to_tail)
744
print "%s => %s" % (from_rel, to_rel)
746
from_abs = self.abspath(from_rel)
747
to_abs = self.abspath(to_rel)
749
os.rename(from_abs, to_abs)
751
bailout("failed to rename %r to %r: %s"
752
% (from_abs, to_abs, e[1]),
753
["rename rolled back"])
755
self._write_inventory(inv)
759
def move(self, from_paths, to_name):
762
to_name must exist as a versioned directory.
764
If to_name exists and is a directory, the files are moved into
765
it, keeping their old names. If it is a directory,
767
Note that to_name is only the last component of the new name;
768
this doesn't change the directory.
770
## TODO: Option to move IDs only
771
assert not isinstance(from_paths, basestring)
772
tree = self.working_tree()
774
to_abs = self.abspath(to_name)
775
if not isdir(to_abs):
776
bailout("destination %r is not a directory" % to_abs)
777
if not tree.has_filename(to_name):
778
bailout("destination %r not in working directory" % to_abs)
779
to_dir_id = inv.path2id(to_name)
780
if to_dir_id == None and to_name != '':
781
bailout("destination %r is not a versioned directory" % to_name)
782
to_dir_ie = inv[to_dir_id]
783
if to_dir_ie.kind not in ('directory', 'root_directory'):
784
bailout("destination %r is not a directory" % to_abs)
786
to_idpath = Set(inv.get_idpath(to_dir_id))
789
if not tree.has_filename(f):
790
bailout("%r does not exist in working tree" % f)
791
f_id = inv.path2id(f)
793
bailout("%r is not versioned" % f)
794
name_tail = splitpath(f)[-1]
795
dest_path = appendpath(to_name, name_tail)
796
if tree.has_filename(dest_path):
797
bailout("destination %r already exists" % dest_path)
798
if f_id in to_idpath:
799
bailout("can't move %r to a subdirectory of itself" % f)
801
# OK, so there's a race here, it's possible that someone will
802
# create a file in this interval and then the rename might be
803
# left half-done. But we should have caught most problems.
806
name_tail = splitpath(f)[-1]
807
dest_path = appendpath(to_name, name_tail)
808
print "%s => %s" % (f, dest_path)
809
inv.rename(inv.path2id(f), to_dir_id, name_tail)
811
os.rename(self.abspath(f), self.abspath(dest_path))
813
bailout("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
814
["rename rolled back"])
816
self._write_inventory(inv)
820
def show_status(self, show_all=False):
659
def show_status(branch, show_all=False):
821
660
"""Display single-line status for non-ignored working files.
823
662
The list is show sorted in order by file name.
893
734
If any files are listed, they are created in the working copy.
895
736
Branch.__init__(self, tempfile.mkdtemp(), init=True)
897
os.mkdir(self.abspath(d))
900
738
file(os.path.join(self.base, f), 'w').write('content of %s' % f)
903
741
def __del__(self):
904
742
"""Destroy the test branch, removing the scratch directory."""
906
shutil.rmtree(self.base)
908
# Work around for shutil.rmtree failing on Windows when
909
# readonly files are encountered
910
for root, dirs, files in os.walk(self.base, topdown=False):
912
os.chmod(os.path.join(root, name), 0700)
913
shutil.rmtree(self.base)
743
shutil.rmtree(self.base)