~abentley/bzr/memory-storage

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Aaron Bentley
  • Date: 2011-07-28 03:09:31 UTC
  • Revision ID: aaron@aaronbentley.com-20110728030931-wfaqavhg79tkh5vx
Moved most content manipulation to DiskStorage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
101
101
        self._new_name = {}
102
102
        # mapping of trans_id -> new parent trans_id
103
103
        self._new_parent = {}
104
 
        # mapping of trans_id with new contents -> new file_kind
105
 
        self._new_contents = {}
106
104
        # mapping of trans_id => (sha1 of content, stat_value)
107
105
        self._observed_sha1s = {}
108
106
        # Set of trans_ids whose contents will be removed
264
262
            self.adjust_path(self.final_name(child), self._new_root, child)
265
263
 
266
264
        # Ensure old_new_root has no directory.
267
 
        if old_new_root in self._new_contents:
 
265
        if old_new_root in self._storage._new_contents:
268
266
            self.cancel_creation(old_new_root)
269
267
        else:
270
268
            self.delete_contents(old_new_root)
381
379
        if filesystem_only:
382
380
            stale_ids = self._storage._needs_rename.difference(self._new_name)
383
381
            stale_ids.difference_update(self._new_parent)
384
 
            stale_ids.difference_update(self._new_contents)
 
382
            stale_ids.difference_update(self._storage._new_contents)
385
383
            stale_ids.difference_update(self._new_id)
386
384
            needs_rename = self._storage._needs_rename.difference(stale_ids)
387
385
            id_sets = (needs_rename, self._new_executability)
388
386
        else:
389
 
            id_sets = (self._new_name, self._new_parent, self._new_contents,
 
387
            id_sets = (self._new_name, self._new_parent,
 
388
                       self._storage._new_contents,
390
389
                       self._new_id, self._new_executability)
391
390
        for id_set in id_sets:
392
391
            new_ids.update(id_set)
416
415
        # removing implies a kind change
417
416
        changed_kind = set(self._removed_contents)
418
417
        # so does adding
419
 
        changed_kind.intersection_update(self._new_contents)
 
418
        changed_kind.intersection_update(self._storage._new_contents)
420
419
        # Ignore entries that are already known to have changed.
421
420
        changed_kind.difference_update(changed_ids)
422
421
        #  to keep only the truly changed ones
439
438
            conceivable that a path would be created without the corresponding
440
439
            contents insertion command)
441
440
        """
442
 
        if trans_id in self._new_contents:
443
 
            return self._new_contents[trans_id]
 
441
        if trans_id in self._storage._new_contents:
 
442
            return self._storage._new_contents[trans_id]
444
443
        elif trans_id in self._removed_contents:
445
444
            return None
446
445
        else:
523
522
        return (trans_id in self._new_name) or (trans_id in self._new_parent)
524
523
 
525
524
    def new_contents(self, trans_id):
526
 
        return (trans_id in self._new_contents)
 
525
        return (trans_id in self._storage._new_contents)
527
526
 
528
527
    def find_conflicts(self):
529
528
        """Find any violations of inventory or filesystem invariants"""
687
686
    def _overwrite_conflicts(self):
688
687
        """Check for overwrites (not permitted on Win32)"""
689
688
        conflicts = []
690
 
        for trans_id in self._new_contents:
 
689
        for trans_id in self._storage._new_contents:
691
690
            if self.tree_kind(trans_id) is None:
692
691
                continue
693
692
            if trans_id not in self._removed_contents:
877
876
        trans_ids = set(self._removed_id)
878
877
        trans_ids.update(self._new_id.keys())
879
878
        trans_ids.update(self._removed_contents)
880
 
        trans_ids.update(self._new_contents.keys())
 
879
        trans_ids.update(self._storage._new_contents.keys())
881
880
        trans_ids.update(self._new_executability.keys())
882
881
        trans_ids.update(self._new_name.keys())
883
882
        trans_ids.update(self._new_parent.keys())
994
993
                modified = True
995
994
            elif to_kind in ('file', 'symlink') and (
996
995
                to_trans_id != from_trans_id or
997
 
                to_trans_id in self._new_contents):
 
996
                to_trans_id in self._storage._new_contents):
998
997
                modified = True
999
998
            if (not modified and from_versioned == to_versioned and
1000
999
                from_parent==to_parent and from_name == to_name and
1041
1040
        """
1042
1041
        self._check_malformed()
1043
1042
        if strict:
1044
 
            unversioned = set(self._new_contents).difference(set(self._new_id))
 
1043
            unversioned = set(self._storage._new_contents).difference(set(self._new_id))
1045
1044
            for trans_id in unversioned:
1046
1045
                if self.final_file_id(trans_id) is None:
1047
1046
                    raise errors.StrictCommitFailed()
1121
1120
            }
1122
1121
        yield serializer.bytes_record(bencode.bencode(attribs),
1123
1122
                                      (('attribs',),))
1124
 
        for trans_id, kind in self._new_contents.items():
 
1123
        for trans_id, kind in self._storage._new_contents.items():
1125
1124
            if kind == 'file':
1126
1125
                lines = osutils.chunks_to_lines(
1127
1126
                    self._storage.read_file_chunks(trans_id))
1173
1172
class DiskStorage(object):
1174
1173
 
1175
1174
    def __init__(self, limbodir, deletiondir=None):
 
1175
        # mapping of trans_id with new contents -> new file_kind
 
1176
        self._new_contents = {}
1176
1177
        self._limbodir = limbodir
1177
1178
        self._deletiondir = deletiondir
1178
1179
        # List of transform ids that need to be renamed from limbo into place
1232
1233
        self._needs_rename.add(trans_id)
1233
1234
        return pathjoin(self._limbodir, trans_id)
1234
1235
 
 
1236
    def create_file(self, contents, trans_id):
 
1237
        name = self._limbo_name(trans_id)
 
1238
        f = open(name, 'wb')
 
1239
        try:
 
1240
            unique_add(self._new_contents, trans_id, 'file')
 
1241
            f.writelines(contents)
 
1242
        finally:
 
1243
            f.close()
 
1244
        return name
 
1245
 
 
1246
    def create_hardlink(self, path, trans_id):
 
1247
        """Schedule creation of a hard link"""
 
1248
        name = self._limbo_name(trans_id)
 
1249
        try:
 
1250
            os.link(path, name)
 
1251
        except OSError, e:
 
1252
            if e.errno != errno.EPERM:
 
1253
                raise
 
1254
            raise errors.HardLinkNotSupported(path)
 
1255
        try:
 
1256
            unique_add(self._new_contents, trans_id, 'file')
 
1257
        except:
 
1258
            # Clean up the file, it never got registered so
 
1259
            # TreeTransform.finalize() won't clean it up.
 
1260
            os.unlink(name)
 
1261
            raise
 
1262
 
 
1263
    def create_directory(self, trans_id):
 
1264
        """Schedule creation of a new directory.
 
1265
 
 
1266
        See also new_directory.
 
1267
        """
 
1268
        os.mkdir(self._limbo_name(trans_id))
 
1269
        unique_add(self._new_contents, trans_id, 'directory')
 
1270
 
 
1271
    def create_symlink(self, target, trans_id, transform):
 
1272
        """Schedule creation of a new symbolic link.
 
1273
 
 
1274
        target is a bytestring.
 
1275
        See also new_symlink.
 
1276
        """
 
1277
        if has_symlinks():
 
1278
            os.symlink(target, self._limbo_name(trans_id))
 
1279
            unique_add(self._new_contents, trans_id, 'symlink')
 
1280
        else:
 
1281
            try:
 
1282
                path = FinalPaths(transform).get_path(trans_id)
 
1283
            except KeyError:
 
1284
                path = None
 
1285
            raise UnableCreateSymlink(path=path)
 
1286
 
 
1287
    def cancel_creation(self, trans_id):
 
1288
        """Cancel the creation of new file contents."""
 
1289
        del self._new_contents[trans_id]
 
1290
        children = self._limbo_children.get(trans_id)
 
1291
        # if this is a limbo directory with children, move them before removing
 
1292
        # the directory
 
1293
        if children is not None:
 
1294
            self._rename_in_limbo(children)
 
1295
            del self._limbo_children[trans_id]
 
1296
            del self._limbo_children_names[trans_id]
 
1297
        delete_any(self._limbo_name(trans_id))
 
1298
 
1235
1299
    def read_file_chunks(self, trans_id):
1236
1300
        cur_file = open(self._limbo_name(trans_id), 'rb')
1237
1301
        try:
1290
1354
            old_path = self._limbo_files[trans_id]
1291
1355
            self._possibly_stale_limbo_files.add(old_path)
1292
1356
            del self._limbo_files[trans_id]
1293
 
            if trans_id not in self.transform._new_contents:
 
1357
            if trans_id not in self._new_contents:
1294
1358
                continue
1295
1359
            new_path = self._limbo_name(trans_id)
1296
1360
            os.rename(old_path, new_path)
1322
1386
        # tree), choose a limbo name inside the parent, to reduce further
1323
1387
        # renames.
1324
1388
        use_direct_path = False
1325
 
        if self.transform._new_contents.get(parent) == 'directory':
 
1389
        if self._new_contents.get(parent) == 'directory':
1326
1390
            filename = self.transform._new_name.get(trans_id)
1327
1391
            if filename is not None:
1328
1392
                if parent not in self._limbo_children:
1417
1481
        :param sha1: If the sha1 of this content is already known, pass it in.
1418
1482
            We can use it to prevent future sha1 computations.
1419
1483
        """
1420
 
        name = self._storage._limbo_name(trans_id)
1421
 
        f = open(name, 'wb')
1422
 
        try:
1423
 
            unique_add(self._new_contents, trans_id, 'file')
1424
 
            f.writelines(contents)
1425
 
        finally:
1426
 
            f.close()
 
1484
        name = self._storage.create_file(contents, trans_id)
1427
1485
        self._set_mtime(name)
1428
1486
        self._set_mode(trans_id, mode_id, S_ISREG)
1429
1487
        # It is unfortunate we have to use lstat instead of fstat, but we just
1443
1501
 
1444
1502
    def create_hardlink(self, path, trans_id):
1445
1503
        """Schedule creation of a hard link"""
1446
 
        name = self._storage._limbo_name(trans_id)
1447
 
        try:
1448
 
            os.link(path, name)
1449
 
        except OSError, e:
1450
 
            if e.errno != errno.EPERM:
1451
 
                raise
1452
 
            raise errors.HardLinkNotSupported(path)
1453
 
        try:
1454
 
            unique_add(self._new_contents, trans_id, 'file')
1455
 
        except:
1456
 
            # Clean up the file, it never got registered so
1457
 
            # TreeTransform.finalize() won't clean it up.
1458
 
            os.unlink(name)
1459
 
            raise
 
1504
        self._storage.create_hardlink(path, trans_id)
1460
1505
 
1461
1506
    def create_directory(self, trans_id):
1462
1507
        """Schedule creation of a new directory.
1463
1508
 
1464
1509
        See also new_directory.
1465
1510
        """
1466
 
        os.mkdir(self._storage._limbo_name(trans_id))
1467
 
        unique_add(self._new_contents, trans_id, 'directory')
 
1511
        self._storage.create_directory(trans_id)
1468
1512
 
1469
1513
    def create_symlink(self, target, trans_id):
1470
1514
        """Schedule creation of a new symbolic link.
1472
1516
        target is a bytestring.
1473
1517
        See also new_symlink.
1474
1518
        """
1475
 
        if has_symlinks():
1476
 
            os.symlink(target, self._storage._limbo_name(trans_id))
1477
 
            unique_add(self._new_contents, trans_id, 'symlink')
1478
 
        else:
1479
 
            try:
1480
 
                path = FinalPaths(self).get_path(trans_id)
1481
 
            except KeyError:
1482
 
                path = None
1483
 
            raise UnableCreateSymlink(path=path)
 
1519
        self._storage.create_symlink(target, trans_id, self)
1484
1520
 
1485
1521
    def cancel_creation(self, trans_id):
1486
1522
        """Cancel the creation of new file contents."""
1487
 
        del self._new_contents[trans_id]
 
1523
        self._storage.cancel_creation(trans_id)
1488
1524
        if trans_id in self._observed_sha1s:
1489
1525
            del self._observed_sha1s[trans_id]
1490
 
        children = self._storage._limbo_children.get(trans_id)
1491
 
        # if this is a limbo directory with children, move them before removing
1492
 
        # the directory
1493
 
        if children is not None:
1494
 
            self._storage._rename_in_limbo(children)
1495
 
            del self._storage._limbo_children[trans_id]
1496
 
            del self._storage._limbo_children_names[trans_id]
1497
 
        delete_any(self._storage._limbo_name(trans_id))
1498
1526
 
1499
1527
    def new_orphan(self, trans_id, parent_id):
1500
1528
        # FIXME: There is no tree config, so we use the branch one (it's weird
1918
1946
                    # TODO: if trans_id in self._observed_sha1s, we should
1919
1947
                    #       re-stat the final target, since ctime will be
1920
1948
                    #       updated by the change.
1921
 
                if (trans_id in self._new_contents or
 
1949
                if (trans_id in self._storage._new_contents or
1922
1950
                    self.path_changed(trans_id)):
1923
 
                    if trans_id in self._new_contents:
 
1951
                    if trans_id in self._storage._new_contents:
1924
1952
                        modified_paths.append(full_path)
1925
1953
                if trans_id in self._new_executability:
1926
1954
                    self._set_executability(path, trans_id)
1935
1963
            # stuff in new_contents actually comes from limbo.
1936
1964
            if trans_id in self._storage._limbo_files:
1937
1965
                del self._storage._limbo_files[trans_id]
1938
 
        self._new_contents.clear()
 
1966
        self._storage._new_contents.clear()
1939
1967
        return modified_paths
1940
1968
 
1941
1969
    def _apply_observed_sha1s(self):
2176
2204
    def extras(self):
2177
2205
        possible_extras = set(self._transform.trans_id_tree_path(p) for p
2178
2206
                              in self._transform._tree.extras())
2179
 
        possible_extras.update(self._transform._new_contents)
 
2207
        possible_extras.update(self._transform._storage._new_contents)
2180
2208
        possible_extras.update(self._transform._removed_id)
2181
2209
        for trans_id in possible_extras:
2182
2210
            if self._transform.final_file_id(trans_id) is None:
2268
2296
    def stored_kind(self, file_id):
2269
2297
        trans_id = self._transform.trans_id_file_id(file_id)
2270
2298
        try:
2271
 
            return self._transform._new_contents[trans_id]
 
2299
            return self._transform._storage._new_contents[trans_id]
2272
2300
        except KeyError:
2273
2301
            return self._transform._tree.stored_kind(file_id)
2274
2302
 
2287
2315
        kind = self._transform.final_kind(trans_id)
2288
2316
        if kind != 'file':
2289
2317
            return None
2290
 
        if trans_id in self._transform._new_contents:
 
2318
        if trans_id in self._transform._storage._new_contents:
2291
2319
            return self._stat_limbo_file(trans_id=trans_id).st_size
2292
2320
        if self.kind(file_id) == 'file':
2293
2321
            return self._transform._tree.get_file_size(file_id)
2296
2324
 
2297
2325
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2298
2326
        trans_id = self._transform.trans_id_file_id(file_id)
2299
 
        kind = self._transform._new_contents.get(trans_id)
 
2327
        kind = self._transform._storage._new_contents.get(trans_id)
2300
2328
        if kind is None:
2301
2329
            return self._transform._tree.get_file_sha1(file_id)
2302
2330
        if kind == 'file':
2324
2352
 
2325
2353
    def has_filename(self, path):
2326
2354
        trans_id = self._path2trans_id(path)
2327
 
        if trans_id in self._transform._new_contents:
 
2355
        if trans_id in self._transform._storage._new_contents:
2328
2356
            return True
2329
2357
        elif trans_id in self._transform._removed_contents:
2330
2358
            return False
2335
2363
        trans_id = self._path2trans_id(path)
2336
2364
        tt = self._transform
2337
2365
        tree_path = tt._tree_id_paths.get(trans_id)
2338
 
        kind = tt._new_contents.get(trans_id)
 
2366
        kind = tt._storage._new_contents.get(trans_id)
2339
2367
        if kind is None:
2340
2368
            if tree_path is None or trans_id in tt._removed_contents:
2341
2369
                return 'missing', None, None, None