Add --cleanup files to report, #395
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.41.2"
|
__version__ = "0.41.3"
|
||||||
|
|||||||
@@ -1509,10 +1509,14 @@ def export(
|
|||||||
+ [str(pathlib.Path(export_db_path).resolve())]
|
+ [str(pathlib.Path(export_db_path).resolve())]
|
||||||
)
|
)
|
||||||
click.echo(f"Cleaning up {dest}")
|
click.echo(f"Cleaning up {dest}")
|
||||||
(cleaned_files, cleaned_dirs) = cleanup_files(dest, all_files, fileutil)
|
cleaned_files, cleaned_dirs = cleanup_files(dest, all_files, fileutil)
|
||||||
file_str = "files" if cleaned_files != 1 else "file"
|
file_str = "files" if len(cleaned_files) != 1 else "file"
|
||||||
dir_str = "directories" if cleaned_dirs != 1 else "directory"
|
dir_str = "directories" if len(cleaned_dirs) != 1 else "directory"
|
||||||
click.echo(f"Deleted: {cleaned_files} {file_str}, {cleaned_dirs} {dir_str}")
|
click.echo(
|
||||||
|
f"Deleted: {len(cleaned_files)} {file_str}, {len(cleaned_dirs)} {dir_str}"
|
||||||
|
)
|
||||||
|
results.deleted_files = cleaned_files
|
||||||
|
results.deleted_directories = cleaned_dirs
|
||||||
|
|
||||||
if report:
|
if report:
|
||||||
verbose_(f"Writing export report to {report}")
|
verbose_(f"Writing export report to {report}")
|
||||||
@@ -2896,8 +2900,12 @@ def write_export_report(report_file, results):
|
|||||||
"exiftool_error": "",
|
"exiftool_error": "",
|
||||||
"extended_attributes_written": 0,
|
"extended_attributes_written": 0,
|
||||||
"extended_attributes_skipped": 0,
|
"extended_attributes_skipped": 0,
|
||||||
|
"cleanup_deleted_file": 0,
|
||||||
|
"cleanup_deleted_directory": 0,
|
||||||
}
|
}
|
||||||
for result in results.all_files()
|
for result in results.all_files()
|
||||||
|
+ results.deleted_files
|
||||||
|
+ results.deleted_directories
|
||||||
}
|
}
|
||||||
|
|
||||||
for result in results.exported:
|
for result in results.exported:
|
||||||
@@ -2963,6 +2971,12 @@ def write_export_report(report_file, results):
|
|||||||
for result in results.xattr_skipped:
|
for result in results.xattr_skipped:
|
||||||
all_results[result]["extended_attributes_skipped"] = 1
|
all_results[result]["extended_attributes_skipped"] = 1
|
||||||
|
|
||||||
|
for result in results.deleted_files:
|
||||||
|
all_results[result]["cleanup_deleted_file"] = 1
|
||||||
|
|
||||||
|
for result in results.deleted_directories:
|
||||||
|
all_results[result]["cleanup_deleted_directory"] = 1
|
||||||
|
|
||||||
report_columns = [
|
report_columns = [
|
||||||
"filename",
|
"filename",
|
||||||
"exported",
|
"exported",
|
||||||
@@ -2981,6 +2995,8 @@ def write_export_report(report_file, results):
|
|||||||
"exiftool_error",
|
"exiftool_error",
|
||||||
"extended_attributes_written",
|
"extended_attributes_written",
|
||||||
"extended_attributes_skipped",
|
"extended_attributes_skipped",
|
||||||
|
"cleanup_deleted_file",
|
||||||
|
"cleanup_deleted_directory",
|
||||||
]
|
]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -3007,27 +3023,27 @@ def cleanup_files(dest_path, files_to_keep, fileutil):
|
|||||||
fileutile: FileUtil object
|
fileutile: FileUtil object
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple of (number of files deleted, number of directories deleted)
|
tuple of (list of files deleted, list of directories deleted)
|
||||||
"""
|
"""
|
||||||
keepers = {str(filename).lower(): 1 for filename in files_to_keep}
|
keepers = {str(filename).lower(): 1 for filename in files_to_keep}
|
||||||
|
|
||||||
deleted_files = 0
|
deleted_files = []
|
||||||
for p in pathlib.Path(dest_path).rglob("*"):
|
for p in pathlib.Path(dest_path).rglob("*"):
|
||||||
path = str(p).lower()
|
path = str(p).lower()
|
||||||
if p.is_file() and path not in keepers:
|
if p.is_file() and path not in keepers:
|
||||||
verbose_(f"Deleting {p}")
|
verbose_(f"Deleting {p}")
|
||||||
fileutil.unlink(p)
|
fileutil.unlink(p)
|
||||||
deleted_files += 1
|
deleted_files.append(str(p))
|
||||||
|
|
||||||
# delete empty directories
|
# delete empty directories
|
||||||
deleted_dirs = 0
|
deleted_dirs = []
|
||||||
for p in pathlib.Path(dest_path).rglob("*"):
|
for p in pathlib.Path(dest_path).rglob("*"):
|
||||||
path = str(p).lower()
|
path = str(p).lower()
|
||||||
# if directory and directory is empty
|
# if directory and directory is empty
|
||||||
if p.is_dir() and not next(p.iterdir(), False):
|
if p.is_dir() and not next(p.iterdir(), False):
|
||||||
verbose_(f"Deleting empty directory {p}")
|
verbose_(f"Deleting empty directory {p}")
|
||||||
fileutil.rmdir(p)
|
fileutil.rmdir(p)
|
||||||
deleted_dirs += 1
|
deleted_dirs.append(str(p))
|
||||||
|
|
||||||
return (deleted_files, deleted_dirs)
|
return (deleted_files, deleted_dirs)
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class ExportResults:
|
|||||||
exiftool_error=None,
|
exiftool_error=None,
|
||||||
xattr_written=None,
|
xattr_written=None,
|
||||||
xattr_skipped=None,
|
xattr_skipped=None,
|
||||||
|
deleted_files=None,
|
||||||
|
deleted_directories=None,
|
||||||
):
|
):
|
||||||
self.exported = exported or []
|
self.exported = exported or []
|
||||||
self.new = new or []
|
self.new = new or []
|
||||||
@@ -107,6 +109,8 @@ class ExportResults:
|
|||||||
self.exiftool_error = exiftool_error or []
|
self.exiftool_error = exiftool_error or []
|
||||||
self.xattr_written = xattr_written or []
|
self.xattr_written = xattr_written or []
|
||||||
self.xattr_skipped = xattr_skipped or []
|
self.xattr_skipped = xattr_skipped or []
|
||||||
|
self.deleted_files = deleted_files or []
|
||||||
|
self.deleted_directories = deleted_directories or []
|
||||||
|
|
||||||
def all_files(self):
|
def all_files(self):
|
||||||
""" return all filenames contained in results """
|
""" return all filenames contained in results """
|
||||||
@@ -151,6 +155,8 @@ class ExportResults:
|
|||||||
self.error += other.error
|
self.error += other.error
|
||||||
self.exiftool_warning += other.exiftool_warning
|
self.exiftool_warning += other.exiftool_warning
|
||||||
self.exiftool_error += other.exiftool_error
|
self.exiftool_error += other.exiftool_error
|
||||||
|
self.deleted_files += other.deleted_files
|
||||||
|
self.deleted_directories += other.deleted_directories
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -173,6 +179,8 @@ class ExportResults:
|
|||||||
+ f",error={self.error}"
|
+ f",error={self.error}"
|
||||||
+ f",exiftool_warning={self.exiftool_warning}"
|
+ f",exiftool_warning={self.exiftool_warning}"
|
||||||
+ f",exiftool_error={self.exiftool_error}"
|
+ f",exiftool_error={self.exiftool_error}"
|
||||||
|
+ f",deleted_files={self.deleted_files}"
|
||||||
|
+ f",deleted_directories={self.deleted_directories}"
|
||||||
+ ")"
|
+ ")"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -29,7 +29,7 @@ def test_export_default_name(photosdb):
|
|||||||
# test basic export
|
# test basic export
|
||||||
# get an unedited image and export it using default filename
|
# get an unedited image and export it using default filename
|
||||||
import os
|
import os
|
||||||
import os.path
|
import pathlib
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import osxphotos
|
import osxphotos
|
||||||
@@ -38,11 +38,12 @@ def test_export_default_name(photosdb):
|
|||||||
dest = tempdir.name
|
dest = tempdir.name
|
||||||
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
|
photos = photosdb.photos(uuid=[UUID_DICT["no_adjustments"]])
|
||||||
|
|
||||||
filename = photos[0].filename
|
filename = photos[0].original_filename
|
||||||
expected_dest = os.path.join(dest, filename)
|
expected_dest = pathlib.Path(dest) / filename
|
||||||
|
expected_dest = expected_dest.parent / f"{expected_dest.stem}.jpeg"
|
||||||
got_dest = photos[0].export(dest, use_photos_export=True)[0]
|
got_dest = photos[0].export(dest, use_photos_export=True)[0]
|
||||||
|
|
||||||
assert got_dest == expected_dest
|
assert got_dest == str(expected_dest)
|
||||||
assert os.path.isfile(got_dest)
|
assert os.path.isfile(got_dest)
|
||||||
|
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@ def test_export_edited(photosdb):
|
|||||||
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
photos = photosdb.photos(uuid=[UUID_DICT["has_adjustments"]])
|
||||||
|
|
||||||
suffix = pathlib.Path(photos[0].path_edited).suffix
|
suffix = pathlib.Path(photos[0].path_edited).suffix
|
||||||
filename = f"{pathlib.Path(photos[0].filename).stem}_edited{suffix}"
|
filename = f"{pathlib.Path(photos[0].original_filename).stem}_edited{suffix}"
|
||||||
expected_dest = os.path.join(dest, filename)
|
expected_dest = os.path.join(dest, filename)
|
||||||
got_dest = photos[0].export(dest, use_photos_export=True, edited=True)[0]
|
got_dest = photos[0].export(dest, use_photos_export=True, edited=True)[0]
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ UUID_DICT = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAMES_DICT = {
|
NAMES_DICT = {
|
||||||
"raw": "D05A5FE3-15FB-49A1-A15D-AB3DA6F8B068.jpeg",
|
"raw": "DSC03584.jpeg",
|
||||||
"heic": "7783E8E6-9CAC-40F3-BE22-81FB7051C266.jpeg",
|
"heic": "IMG_3092.jpeg"
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID_LIVE_HEIC = "612CE30B-3D8F-417A-9B14-EC42CBA10ACC"
|
UUID_LIVE_HEIC = "612CE30B-3D8F-417A-9B14-EC42CBA10ACC"
|
||||||
NAMES_LIVE_HEIC = [
|
NAMES_LIVE_HEIC = [
|
||||||
"612CE30B-3D8F-417A-9B14-EC42CBA10ACC.jpeg",
|
"IMG_3259.jpeg",
|
||||||
"612CE30B-3D8F-417A-9B14-EC42CBA10ACC.mov",
|
"IMG_3259.mov"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ EXPORT_RESULT_ATTRIBUTES = [
|
|||||||
"error",
|
"error",
|
||||||
"exiftool_warning",
|
"exiftool_warning",
|
||||||
"exiftool_error",
|
"exiftool_error",
|
||||||
|
"deleted_files",
|
||||||
|
"deleted_directories",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -43,6 +45,8 @@ def test_exportresults_init():
|
|||||||
assert results.error == []
|
assert results.error == []
|
||||||
assert results.exiftool_warning == []
|
assert results.exiftool_warning == []
|
||||||
assert results.exiftool_error == []
|
assert results.exiftool_error == []
|
||||||
|
assert results.deleted_files == []
|
||||||
|
assert results.deleted_directories == []
|
||||||
|
|
||||||
|
|
||||||
def test_exportresults_iadd():
|
def test_exportresults_iadd():
|
||||||
@@ -64,6 +68,12 @@ def test_exportresults_iadd():
|
|||||||
results1.exiftool_error = [("exiftool_error1", "foo")]
|
results1.exiftool_error = [("exiftool_error1", "foo")]
|
||||||
results2.exiftool_error = [("exiftool_error2", "bar")]
|
results2.exiftool_error = [("exiftool_error2", "bar")]
|
||||||
|
|
||||||
|
results1.deleted_files = [("foo1")]
|
||||||
|
results2.deleted_files = [("foo2")]
|
||||||
|
|
||||||
|
results1.deleted_directories = [("bar1")]
|
||||||
|
results2.deleted_directories = [("bar2")]
|
||||||
|
|
||||||
results1 += results2
|
results1 += results2
|
||||||
|
|
||||||
assert results1.exiftool_warning == [
|
assert results1.exiftool_warning == [
|
||||||
@@ -75,6 +85,9 @@ def test_exportresults_iadd():
|
|||||||
("exiftool_error2", "bar"),
|
("exiftool_error2", "bar"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
assert results1.deleted_files == ["foo1", "foo2"]
|
||||||
|
assert results1.deleted_directories == ["bar1", "bar2"]
|
||||||
|
|
||||||
|
|
||||||
def test_all_files():
|
def test_all_files():
|
||||||
""" test ExportResults.all_files() """
|
""" test ExportResults.all_files() """
|
||||||
@@ -84,10 +97,12 @@ def test_all_files():
|
|||||||
results.exiftool_warning = [("exiftool_warning1", "foo")]
|
results.exiftool_warning = [("exiftool_warning1", "foo")]
|
||||||
results.exiftool_error = [("exiftool_error1", "foo")]
|
results.exiftool_error = [("exiftool_error1", "foo")]
|
||||||
results.error = [("error1", "foo")]
|
results.error = [("error1", "foo")]
|
||||||
|
results.deleted_files = ["deleted_files1"]
|
||||||
|
results.deleted_directories = ["deleted_directories1"]
|
||||||
|
|
||||||
assert sorted(results.all_files()) == sorted(
|
assert sorted(
|
||||||
[f"{x}1" for x in EXPORT_RESULT_ATTRIBUTES]
|
results.all_files() + results.deleted_files + results.deleted_directories
|
||||||
)
|
) == sorted([f"{x}1" for x in EXPORT_RESULT_ATTRIBUTES])
|
||||||
|
|
||||||
|
|
||||||
def test_str():
|
def test_str():
|
||||||
@@ -95,6 +110,6 @@ def test_str():
|
|||||||
results = ExportResults()
|
results = ExportResults()
|
||||||
assert (
|
assert (
|
||||||
str(results)
|
str(results)
|
||||||
== "ExportResults(exported=[],new=[],updated=[],skipped=[],exif_updated=[],touched=[],converted_to_jpeg=[],sidecar_json_written=[],sidecar_json_skipped=[],sidecar_exiftool_written=[],sidecar_exiftool_skipped=[],sidecar_xmp_written=[],sidecar_xmp_skipped=[],missing=[],error=[],exiftool_warning=[],exiftool_error=[])"
|
== "ExportResults(exported=[],new=[],updated=[],skipped=[],exif_updated=[],touched=[],converted_to_jpeg=[],sidecar_json_written=[],sidecar_json_skipped=[],sidecar_exiftool_written=[],sidecar_exiftool_skipped=[],sidecar_xmp_written=[],sidecar_xmp_skipped=[],missing=[],error=[],exiftool_warning=[],exiftool_error=[],deleted_files=[],deleted_directories=[])"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user