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)
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)
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)
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)
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)
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:
523
522
return (trans_id in self._new_name) or (trans_id in self._new_parent)
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)
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)"""
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:
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())
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):
999
998
if (not modified and from_versioned == to_versioned and
1000
999
from_parent==to_parent and from_name == to_name and
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):
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)
1236
def create_file(self, contents, trans_id):
1237
name = self._limbo_name(trans_id)
1238
f = open(name, 'wb')
1240
unique_add(self._new_contents, trans_id, 'file')
1241
f.writelines(contents)
1246
def create_hardlink(self, path, trans_id):
1247
"""Schedule creation of a hard link"""
1248
name = self._limbo_name(trans_id)
1252
if e.errno != errno.EPERM:
1254
raise errors.HardLinkNotSupported(path)
1256
unique_add(self._new_contents, trans_id, 'file')
1258
# Clean up the file, it never got registered so
1259
# TreeTransform.finalize() won't clean it up.
1263
def create_directory(self, trans_id):
1264
"""Schedule creation of a new directory.
1266
See also new_directory.
1268
os.mkdir(self._limbo_name(trans_id))
1269
unique_add(self._new_contents, trans_id, 'directory')
1271
def create_symlink(self, target, trans_id, transform):
1272
"""Schedule creation of a new symbolic link.
1274
target is a bytestring.
1275
See also new_symlink.
1278
os.symlink(target, self._limbo_name(trans_id))
1279
unique_add(self._new_contents, trans_id, 'symlink')
1282
path = FinalPaths(transform).get_path(trans_id)
1285
raise UnableCreateSymlink(path=path)
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
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))
1235
1299
def read_file_chunks(self, trans_id):
1236
1300
cur_file = open(self._limbo_name(trans_id), 'rb')
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:
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
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.
1420
name = self._storage._limbo_name(trans_id)
1421
f = open(name, 'wb')
1423
unique_add(self._new_contents, trans_id, 'file')
1424
f.writelines(contents)
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
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)
1450
if e.errno != errno.EPERM:
1452
raise errors.HardLinkNotSupported(path)
1454
unique_add(self._new_contents, trans_id, 'file')
1456
# Clean up the file, it never got registered so
1457
# TreeTransform.finalize() won't clean it up.
1504
self._storage.create_hardlink(path, trans_id)
1461
1506
def create_directory(self, trans_id):
1462
1507
"""Schedule creation of a new directory.
1464
1509
See also new_directory.
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)
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.
1476
os.symlink(target, self._storage._limbo_name(trans_id))
1477
unique_add(self._new_contents, trans_id, 'symlink')
1480
path = FinalPaths(self).get_path(trans_id)
1483
raise UnableCreateSymlink(path=path)
1519
self._storage.create_symlink(target, trans_id, self)
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
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))
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
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)
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)
2287
2315
kind = self._transform.final_kind(trans_id)
2288
2316
if kind != 'file':
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)
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':
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:
2329
2357
elif trans_id in self._transform._removed_contents:
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