/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

[merge] up-to-date against bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 
25
25
 
26
26
import bzrlib
27
 
from bzrlib.inventory import InventoryEntry
28
27
import bzrlib.inventory as inventory
29
28
from bzrlib.trace import mutter, note
30
 
from bzrlib.osutils import (isdir, quotefn, compact_date, rand_bytes, 
 
29
from bzrlib.osutils import (isdir, quotefn,
31
30
                            rename, splitpath, sha_file, appendpath, 
32
31
                            file_kind, abspath)
33
32
import bzrlib.errors as errors
237
236
    def set_root_id(self, file_id):
238
237
        raise NotImplementedError('set_root_id is abstract')
239
238
 
240
 
    def add(self, files, ids=None):
241
 
        """Make files versioned.
242
 
 
243
 
        Note that the command line normally calls smart_add instead,
244
 
        which can automatically recurse.
245
 
 
246
 
        This puts the files in the Added state, so that they will be
247
 
        recorded by the next commit.
248
 
 
249
 
        files
250
 
            List of paths to add, relative to the base of the tree.
251
 
 
252
 
        ids
253
 
            If set, use these instead of automatically generated ids.
254
 
            Must be the same length as the list of files, but may
255
 
            contain None for ids that are to be autogenerated.
256
 
 
257
 
        TODO: Perhaps have an option to add the ids even if the files do
258
 
              not (yet) exist.
259
 
 
260
 
        TODO: Perhaps yield the ids and paths as they're added.
261
 
        """
262
 
        raise NotImplementedError('add is abstract')
263
 
 
264
239
    def print_file(self, file, revno):
265
240
        """Print `file` to stdout."""
266
241
        raise NotImplementedError('print_file is abstract')
267
242
 
268
 
    def unknowns(self):
269
 
        """Return all unknown files.
270
 
 
271
 
        These are files in the working directory that are not versioned or
272
 
        control files or ignored.
273
 
        
274
 
        >>> from bzrlib.workingtree import WorkingTree
275
 
        >>> b = ScratchBranch(files=['foo', 'foo~'])
276
 
        >>> map(str, b.unknowns())
277
 
        ['foo']
278
 
        >>> b.add('foo')
279
 
        >>> list(b.unknowns())
280
 
        []
281
 
        >>> WorkingTree(b.base, b).remove('foo')
282
 
        >>> list(b.unknowns())
283
 
        [u'foo']
284
 
        """
285
 
        raise NotImplementedError('unknowns is abstract')
286
 
 
287
243
    def append_revision(self, *revision_ids):
288
244
        raise NotImplementedError('append_revision is abstract')
289
245
 
297
253
        or on the mainline."""
298
254
        raise NotImplementedError('has_revision is abstract')
299
255
 
300
 
    def get_revision_xml_file(self, revision_id):
301
 
        """Return XML file object for revision object."""
302
 
        raise NotImplementedError('get_revision_xml_file is abstract')
303
 
 
304
256
    def get_revision_xml(self, revision_id):
305
257
        raise NotImplementedError('get_revision_xml is abstract')
306
258
 
464
416
        raise NotImplementedError('revision_tree is abstract')
465
417
 
466
418
    def working_tree(self):
467
 
        """Return a `Tree` for the working copy."""
 
419
        """Return a `Tree` for the working copy if this is a local branch."""
468
420
        raise NotImplementedError('working_tree is abstract')
469
421
 
470
422
    def pull(self, source, overwrite=False):
872
824
                            'or remove the .bzr directory'
873
825
                            ' and "bzr init" again'])
874
826
 
 
827
    @needs_read_lock
875
828
    def get_root_id(self):
876
829
        """See Branch.get_root_id."""
877
830
        inv = self.get_inventory(self.last_revision())
878
831
        return inv.root.file_id
879
832
 
880
 
    @needs_write_lock
881
 
    def set_root_id(self, file_id):
882
 
        """See Branch.set_root_id."""
883
 
        inv = self.working_tree().read_working_inventory()
884
 
        orig_root_id = inv.root.file_id
885
 
        del inv._byid[inv.root.file_id]
886
 
        inv.root.file_id = file_id
887
 
        inv._byid[inv.root.file_id] = inv.root
888
 
        for fid in inv:
889
 
            entry = inv[fid]
890
 
            if entry.parent_id in (None, orig_root_id):
891
 
                entry.parent_id = inv.root.file_id
892
 
        self._write_inventory(inv)
893
 
 
894
 
    @needs_write_lock
895
 
    def add(self, files, ids=None):
896
 
        """See Branch.add."""
897
 
        # TODO: Re-adding a file that is removed in the working copy
898
 
        # should probably put it back with the previous ID.
899
 
        if isinstance(files, basestring):
900
 
            assert(ids is None or isinstance(ids, basestring))
901
 
            files = [files]
902
 
            if ids is not None:
903
 
                ids = [ids]
904
 
 
905
 
        if ids is None:
906
 
            ids = [None] * len(files)
907
 
        else:
908
 
            assert(len(ids) == len(files))
909
 
 
910
 
        inv = self.working_tree().read_working_inventory()
911
 
        for f,file_id in zip(files, ids):
912
 
            if is_control_file(f):
913
 
                raise BzrError("cannot add control file %s" % quotefn(f))
914
 
 
915
 
            fp = splitpath(f)
916
 
 
917
 
            if len(fp) == 0:
918
 
                raise BzrError("cannot add top-level %r" % f)
919
 
 
920
 
            fullpath = os.path.normpath(self.abspath(f))
921
 
 
922
 
            try:
923
 
                kind = file_kind(fullpath)
924
 
            except OSError:
925
 
                # maybe something better?
926
 
                raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
927
 
 
928
 
            if not InventoryEntry.versionable_kind(kind):
929
 
                raise BzrError('cannot add: not a versionable file ('
930
 
                               'i.e. regular file, symlink or directory): %s' % quotefn(f))
931
 
 
932
 
            if file_id is None:
933
 
                file_id = gen_file_id(f)
934
 
            inv.add_path(f, kind=kind, file_id=file_id)
935
 
 
936
 
            mutter("add file %s file_id:{%s} kind=%r" % (f, file_id, kind))
937
 
 
938
 
        self.working_tree()._write_inventory(inv)
939
 
 
940
833
    @needs_read_lock
941
834
    def print_file(self, file, revno):
942
835
        """See Branch.print_file."""
947
840
            raise BzrError("%r is not present in revision %s" % (file, revno))
948
841
        tree.print_file(file_id)
949
842
 
950
 
    def unknowns(self):
951
 
        """See Branch.unknowns."""
952
 
        return self.working_tree().unknowns()
953
 
 
954
843
    @needs_write_lock
955
844
    def append_revision(self, *revision_ids):
956
845
        """See Branch.append_revision."""
983
872
                or self.revision_store.has_id(revision_id))
984
873
 
985
874
    @needs_read_lock
986
 
    def get_revision_xml_file(self, revision_id):
987
 
        """See Branch.get_revision_xml_file."""
 
875
    def _get_revision_xml_file(self, revision_id):
988
876
        if not revision_id or not isinstance(revision_id, basestring):
989
877
            raise InvalidRevisionId(revision_id=revision_id, branch=self)
990
878
        try:
994
882
 
995
883
    def get_revision_xml(self, revision_id):
996
884
        """See Branch.get_revision_xml."""
997
 
        return self.get_revision_xml_file(revision_id).read()
 
885
        return self._get_revision_xml_file(revision_id).read()
998
886
 
999
887
    def get_revision(self, revision_id):
1000
888
        """See Branch.get_revision."""
1001
 
        xml_file = self.get_revision_xml_file(revision_id)
 
889
        xml_file = self._get_revision_xml_file(revision_id)
1002
890
 
1003
891
        try:
1004
892
            r = bzrlib.xml5.serializer_v5.read_revision(xml_file)
1136
1024
    def working_tree(self):
1137
1025
        """See Branch.working_tree."""
1138
1026
        from bzrlib.workingtree import WorkingTree
1139
 
        # TODO: In the future, perhaps WorkingTree should utilize Transport
1140
 
        # RobertCollins 20051003 - I don't think it should - working trees are
1141
 
        # much more complex to keep consistent than our careful .bzr subset.
1142
 
        # instead, we should say that working trees are local only, and optimise
1143
 
        # for that.
1144
1027
        if self._transport.base.find('://') != -1:
1145
1028
            raise NoWorkingTree(self.base)
1146
1029
        return WorkingTree(self.base, branch=self)
1150
1033
        """See Branch.pull."""
1151
1034
        source.lock_read()
1152
1035
        try:
 
1036
            old_count = len(self.revision_history())
1153
1037
            try:
1154
1038
                self.update_revisions(source)
1155
1039
            except DivergedBranches:
1156
1040
                if not overwrite:
1157
1041
                    raise
1158
1042
                self.set_revision_history(source.revision_history())
 
1043
            new_count = len(self.revision_history())
 
1044
            return new_count - old_count
1159
1045
        finally:
1160
1046
            source.unlock()
1161
1047
 
1162
 
    @needs_write_lock
1163
 
    def rename_one(self, from_rel, to_rel):
1164
 
        """See Branch.rename_one."""
1165
 
        tree = self.working_tree()
1166
 
        inv = tree.inventory
1167
 
        if not tree.has_filename(from_rel):
1168
 
            raise BzrError("can't rename: old working file %r does not exist" % from_rel)
1169
 
        if tree.has_filename(to_rel):
1170
 
            raise BzrError("can't rename: new working file %r already exists" % to_rel)
1171
 
 
1172
 
        file_id = inv.path2id(from_rel)
1173
 
        if file_id == None:
1174
 
            raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1175
 
 
1176
 
        if inv.path2id(to_rel):
1177
 
            raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1178
 
 
1179
 
        to_dir, to_tail = os.path.split(to_rel)
1180
 
        to_dir_id = inv.path2id(to_dir)
1181
 
        if to_dir_id == None and to_dir != '':
1182
 
            raise BzrError("can't determine destination directory id for %r" % to_dir)
1183
 
 
1184
 
        mutter("rename_one:")
1185
 
        mutter("  file_id    {%s}" % file_id)
1186
 
        mutter("  from_rel   %r" % from_rel)
1187
 
        mutter("  to_rel     %r" % to_rel)
1188
 
        mutter("  to_dir     %r" % to_dir)
1189
 
        mutter("  to_dir_id  {%s}" % to_dir_id)
1190
 
 
1191
 
        inv.rename(file_id, to_dir_id, to_tail)
1192
 
 
1193
 
        from_abs = self.abspath(from_rel)
1194
 
        to_abs = self.abspath(to_rel)
1195
 
        try:
1196
 
            rename(from_abs, to_abs)
1197
 
        except OSError, e:
1198
 
            raise BzrError("failed to rename %r to %r: %s"
1199
 
                    % (from_abs, to_abs, e[1]),
1200
 
                    ["rename rolled back"])
1201
 
 
1202
 
        self.working_tree()._write_inventory(inv)
1203
 
 
1204
 
    @needs_write_lock
1205
 
    def move(self, from_paths, to_name):
1206
 
        """See Branch.move."""
1207
 
        result = []
1208
 
        ## TODO: Option to move IDs only
1209
 
        assert not isinstance(from_paths, basestring)
1210
 
        tree = self.working_tree()
1211
 
        inv = tree.inventory
1212
 
        to_abs = self.abspath(to_name)
1213
 
        if not isdir(to_abs):
1214
 
            raise BzrError("destination %r is not a directory" % to_abs)
1215
 
        if not tree.has_filename(to_name):
1216
 
            raise BzrError("destination %r not in working directory" % to_abs)
1217
 
        to_dir_id = inv.path2id(to_name)
1218
 
        if to_dir_id == None and to_name != '':
1219
 
            raise BzrError("destination %r is not a versioned directory" % to_name)
1220
 
        to_dir_ie = inv[to_dir_id]
1221
 
        if to_dir_ie.kind not in ('directory', 'root_directory'):
1222
 
            raise BzrError("destination %r is not a directory" % to_abs)
1223
 
 
1224
 
        to_idpath = inv.get_idpath(to_dir_id)
1225
 
 
1226
 
        for f in from_paths:
1227
 
            if not tree.has_filename(f):
1228
 
                raise BzrError("%r does not exist in working tree" % f)
1229
 
            f_id = inv.path2id(f)
1230
 
            if f_id == None:
1231
 
                raise BzrError("%r is not versioned" % f)
1232
 
            name_tail = splitpath(f)[-1]
1233
 
            dest_path = appendpath(to_name, name_tail)
1234
 
            if tree.has_filename(dest_path):
1235
 
                raise BzrError("destination %r already exists" % dest_path)
1236
 
            if f_id in to_idpath:
1237
 
                raise BzrError("can't move %r to a subdirectory of itself" % f)
1238
 
 
1239
 
        # OK, so there's a race here, it's possible that someone will
1240
 
        # create a file in this interval and then the rename might be
1241
 
        # left half-done.  But we should have caught most problems.
1242
 
 
1243
 
        for f in from_paths:
1244
 
            name_tail = splitpath(f)[-1]
1245
 
            dest_path = appendpath(to_name, name_tail)
1246
 
            result.append((f, dest_path))
1247
 
            inv.rename(inv.path2id(f), to_dir_id, name_tail)
1248
 
            try:
1249
 
                rename(self.abspath(f), self.abspath(dest_path))
1250
 
            except OSError, e:
1251
 
                raise BzrError("failed to rename %r to %r: %s" % (f, dest_path, e[1]),
1252
 
                        ["rename rolled back"])
1253
 
 
1254
 
        self.working_tree()._write_inventory(inv)
1255
 
        return result
1256
 
 
1257
1048
    def get_parent(self):
1258
1049
        """See Branch.get_parent."""
1259
1050
        import errno
1457
1248
            break
1458
1249
        filename = head
1459
1250
    return False
1460
 
 
1461
 
 
1462
 
 
1463
 
def gen_file_id(name):
1464
 
    """Return new file id.
1465
 
 
1466
 
    This should probably generate proper UUIDs, but for the moment we
1467
 
    cope with just randomness because running uuidgen every time is
1468
 
    slow."""
1469
 
    import re
1470
 
    from binascii import hexlify
1471
 
    from time import time
1472
 
 
1473
 
    # get last component
1474
 
    idx = name.rfind('/')
1475
 
    if idx != -1:
1476
 
        name = name[idx+1 : ]
1477
 
    idx = name.rfind('\\')
1478
 
    if idx != -1:
1479
 
        name = name[idx+1 : ]
1480
 
 
1481
 
    # make it not a hidden file
1482
 
    name = name.lstrip('.')
1483
 
 
1484
 
    # remove any wierd characters; we don't escape them but rather
1485
 
    # just pull them out
1486
 
    name = re.sub(r'[^\w.]', '', name)
1487
 
 
1488
 
    s = hexlify(rand_bytes(8))
1489
 
    return '-'.join((name, compact_date(time()), s))
1490
 
 
1491
 
 
1492
 
def gen_root_id():
1493
 
    """Return a new tree-root file id."""
1494
 
    return gen_file_id('TREE_ROOT')
1495
 
 
1496