67
67
raise NotImplementedError('find_branch() is not supported anymore, '
68
68
'please use one of the new branch constructors')
71
def needs_read_lock(unbound):
72
"""Decorate unbound to take out and release a read lock."""
73
def decorated(self, *args, **kwargs):
76
return unbound(self, *args, **kwargs)
82
def needs_write_lock(unbound):
83
"""Decorate unbound to take out and release a write lock."""
84
def decorated(self, *args, **kwargs):
87
return unbound(self, *args, **kwargs)
70
92
######################################################################
507
529
entry.parent_id = inv.root.file_id
508
530
self._write_inventory(inv)
510
533
def read_working_inventory(self):
511
534
"""Read the working inventory."""
514
# ElementTree does its own conversion from UTF-8, so open in
516
f = self.controlfile('inventory', 'rb')
517
return bzrlib.xml5.serializer_v5.read_inventory(f)
535
# ElementTree does its own conversion from UTF-8, so open in
537
f = self.controlfile('inventory', 'rb')
538
return bzrlib.xml5.serializer_v5.read_inventory(f)
522
541
def _write_inventory(self, inv):
523
542
"""Update the working inventory.
526
545
will be committed to the next revision.
528
547
from cStringIO import StringIO
532
bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
534
# Transport handles atomicity
535
self.put_controlfile('inventory', sio)
549
bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
551
# Transport handles atomicity
552
self.put_controlfile('inventory', sio)
539
554
mutter('wrote working inventory')
541
556
inventory = property(read_working_inventory, _write_inventory, None,
542
557
"""Inventory for the working copy.""")
544
560
def add(self, files, ids=None):
545
561
"""Make files versioned.
577
593
assert(len(ids) == len(files))
581
inv = self.read_working_inventory()
582
for f,file_id in zip(files, ids):
583
if is_control_file(f):
584
raise BzrError("cannot add control file %s" % quotefn(f))
589
raise BzrError("cannot add top-level %r" % f)
591
fullpath = os.path.normpath(self.abspath(f))
594
kind = file_kind(fullpath)
596
# maybe something better?
597
raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
599
if not InventoryEntry.versionable_kind(kind):
600
raise BzrError('cannot add: not a versionable file ('
601
'i.e. regular file, symlink or directory): %s' % quotefn(f))
604
file_id = gen_file_id(f)
605
inv.add_path(f, kind=kind, file_id=file_id)
607
mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
609
self._write_inventory(inv)
595
inv = self.read_working_inventory()
596
for f,file_id in zip(files, ids):
597
if is_control_file(f):
598
raise BzrError("cannot add control file %s" % quotefn(f))
603
raise BzrError("cannot add top-level %r" % f)
605
fullpath = os.path.normpath(self.abspath(f))
608
kind = file_kind(fullpath)
610
# maybe something better?
611
raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
613
if not InventoryEntry.versionable_kind(kind):
614
raise BzrError('cannot add: not a versionable file ('
615
'i.e. regular file, symlink or directory): %s' % quotefn(f))
618
file_id = gen_file_id(f)
619
inv.add_path(f, kind=kind, file_id=file_id)
621
mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
623
self._write_inventory(inv)
614
626
def print_file(self, file, revno):
615
627
"""Print `file` to stdout."""
618
tree = self.revision_tree(self.get_rev_id(revno))
619
# use inventory as it was in that revision
620
file_id = tree.inventory.path2id(file)
622
raise BzrError("%r is not present in revision %s" % (file, revno))
623
tree.print_file(file_id)
628
tree = self.revision_tree(self.get_rev_id(revno))
629
# use inventory as it was in that revision
630
file_id = tree.inventory.path2id(file)
632
raise BzrError("%r is not present in revision %s" % (file, revno))
633
tree.print_file(file_id)
628
636
def remove(self, files, verbose=False):
629
637
"""Mark nominated files for removal from the inventory.
644
652
if isinstance(files, basestring):
650
tree = self.working_tree()
653
# do this before any modifications
657
raise BzrError("cannot remove unversioned file %s" % quotefn(f))
658
mutter("remove inventory entry %s {%s}" % (quotefn(f), fid))
660
# having remove it, it must be either ignored or unknown
661
if tree.is_ignored(f):
665
show_status(new_status, inv[fid].kind, quotefn(f))
668
self._write_inventory(inv)
655
tree = self.working_tree()
658
# do this before any modifications
662
raise BzrError("cannot remove unversioned file %s" % quotefn(f))
663
mutter("remove inventory entry %s {%s}" % (quotefn(f), fid))
665
# having remove it, it must be either ignored or unknown
666
if tree.is_ignored(f):
670
show_status(new_status, inv[fid].kind, quotefn(f))
673
self._write_inventory(inv)
672
675
# FIXME: this doesn't need to be a branch method
673
676
def set_inventory(self, new_inventory_list):
707
710
return self.working_tree().unknowns()
710
713
def append_revision(self, *revision_ids):
711
714
for revision_id in revision_ids:
712
715
mutter("add {%s} to revision-history" % revision_id)
715
rev_history = self.revision_history()
716
rev_history.extend(revision_ids)
717
self.put_controlfile('revision-history', '\n'.join(rev_history))
716
rev_history = self.revision_history()
717
rev_history.extend(revision_ids)
718
self.put_controlfile('revision-history', '\n'.join(rev_history))
721
720
def has_revision(self, revision_id):
722
721
"""True if this branch has a copy of the revision.
726
725
return (revision_id is None
727
726
or self.revision_store.has_id(revision_id))
729
729
def get_revision_xml_file(self, revision_id):
730
730
"""Return XML file object for revision object."""
731
731
if not revision_id or not isinstance(revision_id, basestring):
732
732
raise InvalidRevisionId(revision_id)
737
return self.revision_store.get(revision_id)
738
except (IndexError, KeyError):
739
raise bzrlib.errors.NoSuchRevision(self, revision_id)
734
return self.revision_store.get(revision_id)
735
except (IndexError, KeyError):
736
raise bzrlib.errors.NoSuchRevision(self, revision_id)
744
739
get_revision_xml = get_revision_xml_file
838
833
return self.get_inventory(revision_id)
840
836
def revision_history(self):
841
837
"""Return sequence of revision hashes on to this branch."""
844
transaction = self.get_transaction()
845
history = transaction.map.find_revision_history()
846
if history is not None:
847
mutter("cache hit for revision-history in %s", self)
849
history = [l.rstrip('\r\n') for l in
850
self.controlfile('revision-history', 'r').readlines()]
851
transaction.map.add_revision_history(history)
852
# this call is disabled because revision_history is
853
# not really an object yet, and the transaction is for objects.
854
# transaction.register_clean(history, precious=True)
838
transaction = self.get_transaction()
839
history = transaction.map.find_revision_history()
840
if history is not None:
841
mutter("cache hit for revision-history in %s", self)
855
842
return list(history)
843
history = [l.rstrip('\r\n') for l in
844
self.controlfile('revision-history', 'r').readlines()]
845
transaction.map.add_revision_history(history)
846
# this call is disabled because revision_history is
847
# not really an object yet, and the transaction is for objects.
848
# transaction.register_clean(history, precious=True)
860
852
"""Return current revision number for this branch.
1010
1000
return self.revision_tree(self.last_revision())
1013
1003
def rename_one(self, from_rel, to_rel):
1014
1004
"""Rename one file.
1016
1006
This can change the directory or the filename or both.
1008
tree = self.working_tree()
1009
inv = tree.inventory
1010
if not tree.has_filename(from_rel):
1011
raise BzrError("can't rename: old working file %r does not exist" % from_rel)
1012
if tree.has_filename(to_rel):
1013
raise BzrError("can't rename: new working file %r already exists" % to_rel)
1015
file_id = inv.path2id(from_rel)
1017
raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1019
if inv.path2id(to_rel):
1020
raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1022
to_dir, to_tail = os.path.split(to_rel)
1023
to_dir_id = inv.path2id(to_dir)
1024
if to_dir_id == None and to_dir != '':
1025
raise BzrError("can't determine destination directory id for %r" % to_dir)
1027
mutter("rename_one:")
1028
mutter(" file_id {%s}" % file_id)
1029
mutter(" from_rel %r" % from_rel)
1030
mutter(" to_rel %r" % to_rel)
1031
mutter(" to_dir %r" % to_dir)
1032
mutter(" to_dir_id {%s}" % to_dir_id)
1034
inv.rename(file_id, to_dir_id, to_tail)
1036
from_abs = self.abspath(from_rel)
1037
to_abs = self.abspath(to_rel)
1020
tree = self.working_tree()
1021
inv = tree.inventory
1022
if not tree.has_filename(from_rel):
1023
raise BzrError("can't rename: old working file %r does not exist" % from_rel)
1024
if tree.has_filename(to_rel):
1025
raise BzrError("can't rename: new working file %r already exists" % to_rel)
1027
file_id = inv.path2id(from_rel)
1029
raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1031
if inv.path2id(to_rel):
1032
raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1034
to_dir, to_tail = os.path.split(to_rel)
1035
to_dir_id = inv.path2id(to_dir)
1036
if to_dir_id == None and to_dir != '':
1037
raise BzrError("can't determine destination directory id for %r" % to_dir)
1039
mutter("rename_one:")
1040
mutter(" file_id {%s}" % file_id)
1041
mutter(" from_rel %r" % from_rel)
1042
mutter(" to_rel %r" % to_rel)
1043
mutter(" to_dir %r" % to_dir)
1044
mutter(" to_dir_id {%s}" % to_dir_id)
1046
inv.rename(file_id, to_dir_id, to_tail)
1048
from_abs = self.abspath(from_rel)
1049
to_abs = self.abspath(to_rel)
1051
rename(from_abs, to_abs)
1053
raise BzrError("failed to rename %r to %r: %s"
1054
% (from_abs, to_abs, e[1]),
1055
["rename rolled back"])
1057
self._write_inventory(inv)
1039
rename(from_abs, to_abs)
1041
raise BzrError("failed to rename %r to %r: %s"
1042
% (from_abs, to_abs, e[1]),
1043
["rename rolled back"])
1045
self._write_inventory(inv)
1062
1048
def move(self, from_paths, to_name):
1063
1049
"""Rename files.
1074
1060
entry that is moved.
1079
## TODO: Option to move IDs only
1080
assert not isinstance(from_paths, basestring)
1081
tree = self.working_tree()
1082
inv = tree.inventory
1083
to_abs = self.abspath(to_name)
1084
if not isdir(to_abs):
1085
raise BzrError("destination %r is not a directory" % to_abs)
1086
if not tree.has_filename(to_name):
1087
raise BzrError("destination %r not in working directory" % to_abs)
1088
to_dir_id = inv.path2id(to_name)
1089
if to_dir_id == None and to_name != '':
1090
raise BzrError("destination %r is not a versioned directory" % to_name)
1091
to_dir_ie = inv[to_dir_id]
1092
if to_dir_ie.kind not in ('directory', 'root_directory'):
1093
raise BzrError("destination %r is not a directory" % to_abs)
1095
to_idpath = inv.get_idpath(to_dir_id)
1097
for f in from_paths:
1098
if not tree.has_filename(f):
1099
raise BzrError("%r does not exist in working tree" % f)
1100
f_id = inv.path2id(f)
1102
raise BzrError("%r is not versioned" % f)
1103
name_tail = splitpath(f)[-1]
1104
dest_path = appendpath(to_name, name_tail)
1105
if tree.has_filename(dest_path):
1106
raise BzrError("destination %r already exists" % dest_path)
1107
if f_id in to_idpath:
1108
raise BzrError("can't move %r to a subdirectory of itself" % f)
1110
# OK, so there's a race here, it's possible that someone will
1111
# create a file in this interval and then the rename might be
1112
# left half-done. But we should have caught most problems.
1114
for f in from_paths:
1115
name_tail = splitpath(f)[-1]
1116
dest_path = appendpath(to_name, name_tail)
1117
result.append((f, dest_path))
1118
inv.rename(inv.path2id(f), to_dir_id, name_tail)
1120
rename(self.abspath(f), self.abspath(dest_path))
1122
raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
1123
["rename rolled back"])
1125
self._write_inventory(inv)
1063
## TODO: Option to move IDs only
1064
assert not isinstance(from_paths, basestring)
1065
tree = self.working_tree()
1066
inv = tree.inventory
1067
to_abs = self.abspath(to_name)
1068
if not isdir(to_abs):
1069
raise BzrError("destination %r is not a directory" % to_abs)
1070
if not tree.has_filename(to_name):
1071
raise BzrError("destination %r not in working directory" % to_abs)
1072
to_dir_id = inv.path2id(to_name)
1073
if to_dir_id == None and to_name != '':
1074
raise BzrError("destination %r is not a versioned directory" % to_name)
1075
to_dir_ie = inv[to_dir_id]
1076
if to_dir_ie.kind not in ('directory', 'root_directory'):
1077
raise BzrError("destination %r is not a directory" % to_abs)
1079
to_idpath = inv.get_idpath(to_dir_id)
1081
for f in from_paths:
1082
if not tree.has_filename(f):
1083
raise BzrError("%r does not exist in working tree" % f)
1084
f_id = inv.path2id(f)
1086
raise BzrError("%r is not versioned" % f)
1087
name_tail = splitpath(f)[-1]
1088
dest_path = appendpath(to_name, name_tail)
1089
if tree.has_filename(dest_path):
1090
raise BzrError("destination %r already exists" % dest_path)
1091
if f_id in to_idpath:
1092
raise BzrError("can't move %r to a subdirectory of itself" % f)
1094
# OK, so there's a race here, it's possible that someone will
1095
# create a file in this interval and then the rename might be
1096
# left half-done. But we should have caught most problems.
1098
for f in from_paths:
1099
name_tail = splitpath(f)[-1]
1100
dest_path = appendpath(to_name, name_tail)
1101
result.append((f, dest_path))
1102
inv.rename(inv.path2id(f), to_dir_id, name_tail)
1104
rename(self.abspath(f), self.abspath(dest_path))
1106
raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
1107
["rename rolled back"])
1109
self._write_inventory(inv)