410
403
return "removed %s (but kept a copy: %s)" % (
411
404
file_to_backup, backup_name)
406
# Sort needed to first handle directory content before the directory
411
def recurse_directory_to_add_files(directory):
412
# Recurse directory and add all files
413
# so we can check if they have changed.
414
for parent_info, file_infos in self.walkdirs(directory):
415
for relpath, basename, kind, lstat, fileid, kind in file_infos:
416
# Is it versioned or ignored?
417
if self.is_versioned(relpath):
418
# Add nested content for deletion.
419
all_files.add(relpath)
421
# Files which are not versioned
422
# should be treated as unknown.
423
files_to_backup.append(relpath)
413
425
with self.lock_tree_write():
426
for filepath in files:
427
# Get file name into canonical form.
428
abspath = self.abspath(filepath)
429
filepath = self.relpath(abspath)
432
all_files.add(filepath)
433
recurse_directory_to_add_files(filepath)
435
files = list(all_files)
438
return # nothing to do
440
# Sort needed to first handle directory content before the directory
441
files.sort(reverse=True)
443
# Bail out if we are going to delete files we shouldn't
444
if not keep_files and not force:
445
for (file_id, path, content_change, versioned, parent_id, name,
446
kind, executable) in self.iter_changes(self.basis_tree(),
447
include_unchanged=True, require_versioned=False,
448
want_unversioned=True, specific_files=files):
449
if versioned[0] == False:
450
# The record is unknown or newly added
451
files_to_backup.append(path[1])
452
files_to_backup.extend(osutils.parent_directories(path[1]))
453
elif (content_change and (kind[1] is not None) and
454
osutils.is_inside_any(files, path[1])):
455
# Versioned and changed, but not deleted, and still
456
# in one of the dirs to be deleted.
457
files_to_backup.append(path[1])
458
files_to_backup.extend(osutils.parent_directories(path[1]))
466
except errors.NoSuchFile:
469
abs_path = self.abspath(f)
471
# having removed it, it must be either ignored or unknown
472
if self.is_ignored(f):
476
kind_ch = osutils.kind_marker(kind)
477
to_file.write(new_status + ' ' + f + kind_ch + '\n')
479
message = "%s does not exist" % (f, )
418
abs_path = self.abspath(f)
420
# having removed it, it must be either ignored or unknown
421
if self.is_ignored(f):
482
if f in files_to_backup and not force:
425
# XXX: Really should be a more abstract reporter interface
426
kind_ch = osutils.kind_marker(self.kind(f))
427
to_file.write(new_status + ' ' + f + kind_ch + '\n')
429
# TODO(jelmer): _unversion_path() is O(size-of-index) for directories
430
if self._unversion_path(f) == 0:
431
if (osutils.isdir(abs_path) and
432
len(os.listdir(abs_path)) == 0):
485
if kind == 'directory':
486
osutils.rmtree(abs_path)
434
488
osutils.delete_any(abs_path)
435
message = "removed %s" % (f,)
437
message = "%s is not versioned." % (f,)
489
message = "deleted %s" % (f,)
439
491
message = "removed %s" % (f,)
440
if osutils.lexists(abs_path):
441
if (osutils.isdir(abs_path) and
442
len(os.listdir(abs_path)) > 0):
444
osutils.rmtree(abs_path)
445
message = "deleted %s" % (f,)
450
osutils.delete_any(abs_path)
451
message = "deleted %s" % (f,)
492
self._unversion_path(f)
453
494
# print only one message (if any) per file.
454
495
if message is not None:
455
496
trace.note(message)
497
self._versioned_dirs = None
458
500
def _add(self, files, ids, kinds):
1372
1414
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1373
1415
require_versioned=False, include_root=False):
1374
# TODO(jelmer): Handle include_root
1375
# TODO(jelmer): Handle require_versioned
1416
if require_versioned and specific_files:
1417
for path in specific_files:
1418
if (not self.source.is_versioned(path) and
1419
not self.target.is_versioned(path)):
1420
raise errors.PathsNotVersionedError(path)
1376
1421
# TODO(jelmer): Restrict to specific_files, for performance reasons.
1377
1422
with self.lock_read():
1378
1423
return changes_between_git_tree_and_working_copy(
1379
1424
self.source.store, self.source.tree,
1380
self.target, want_unchanged=want_unchanged)
1425
self.target, want_unchanged=want_unchanged,
1426
include_root=include_root)
1382
1428
def compare(self, want_unchanged=False, specific_files=None,
1383
1429
extra_trees=None, require_versioned=False, include_root=False,
1424
1471
def untracked_changes(tree):
1425
1472
for e in tree.extras():
1426
1473
ap = tree.abspath(e)
1429
1476
np, accessible = osutils.normalized_filename(e)
1430
1477
except UnicodeDecodeError:
1431
1478
raise errors.BadFilenameEncoding(
1432
1479
e, osutils._fs_enc)
1433
yield ((None, np), (None, st.st_mode),
1434
(None, blob_from_path_and_stat(ap.encode('utf-8'), st).id))
1480
if stat.S_ISDIR(st.st_mode):
1483
obj_id = blob_from_path_and_stat(ap.encode('utf-8'), st).id
1484
yield ((None, np), (None, st.st_mode), (None, obj_id))
1437
1487
def changes_between_git_tree_and_index(store, from_tree_sha, target,