Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement --rmdirs option #225

Merged
merged 1 commit into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions phockup.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,17 @@ def parse_args(args=sys.argv[1:]):
and `--skip-unknown`.
""",
)

parser.add_argument(
'--rmdirs',
action='store_true',
default=False,
help="""\
DELETE empty directories after processing. Only valid in
conjunction with `--move`.
""",
)

parser.add_argument(
'--output_prefix',
type=str,
Expand Down Expand Up @@ -376,6 +387,7 @@ def main(options):
no_date_dir=options.no_date_dir,
skip_unknown=options.skip_unknown,
movedel=options.movedel,
rmdirs=options.rmdirs,
output_prefix=options.output_prefix,
output_suffix=options.output_suffix,
from_date=options.from_date,
Expand Down
22 changes: 22 additions & 0 deletions src/phockup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def __init__(self, input_dir, output_dir, **args):
self.date_field = args.get('date_field', False)
self.skip_unknown = args.get("skip_unknown", False)
self.movedel = args.get("movedel", False),
self.rmdirs = args.get("rmdirs", False),
self.dry_run = args.get('dry_run', False)
self.progress = args.get('progress', False)
self.max_depth = args.get('max_depth', -1)
Expand Down Expand Up @@ -89,6 +90,9 @@ def __init__(self, input_dir, output_dir, **args):
self.pbar = None
self.walk_directory()

if self.move and self.rmdirs:
self.rm_subdirs()

run_time = time.time() - start_time
if self.files_processed and run_time:
self.print_action_report(run_time)
Expand Down Expand Up @@ -156,6 +160,24 @@ def walk_directory(self):
if root.count(os.sep) >= self.stop_depth:
del dirnames[:]

def rm_subdirs(self):
def _get_depth(sub_path):
return sub_path.count(os.sep) - self.input_dir.count(os.sep)

for root, dirs, files in os.walk(self.input_dir, topdown=False):
# Traverse the tree bottom-up
if _get_depth(root) > self.stop_depth:
continue
for name in dirs:
dir_path = os.path.join(root, name)
if _get_depth(dir_path) > self.stop_depth:
continue
try:
os.rmdir(dir_path) # Try to remove the dir
logger.info(f"Deleted empty directory: {dir_path}")
except OSError as e:
logger.info(f"{e.strerror} - {dir_path} not deleted.")

def get_file_count(self):
file_count = 0
for root, dirnames, files in os.walk(self.input_dir):
Expand Down
35 changes: 35 additions & 0 deletions tests/test_phockup.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,41 @@ def test_process_movedel(mocker, caplog):
shutil.rmtree('output', ignore_errors=True)


def test_process_rmdirs(mocker, caplog):
shutil.rmtree('output', ignore_errors=True)
shutil.rmtree('input/sub_folder/sub0', ignore_errors=True)
mocker.patch.object(Exif, 'data')
Exif.data.return_value = {
"MIMEType": "image/jpeg"
}
os.mkdir('input/sub_folder/sub0')
os.mkdir('input/sub_folder/sub0/sub1')
os.mkdir('input/sub_folder/sub0/sub2')
os.mkdir('input/sub_folder/sub0/sub2/sub3')
open("input/sub_folder/sub0/tmp_20170101_010101.jpg", "w").close()
open("input/sub_folder/sub0/sub1/tmp_20170101_010102.jpg", "w").close()
open("input/sub_folder/sub0/sub2/tmp_20170101_010103.jpg", "w").close()
open("input/sub_folder/sub0/sub2/sub3/tmp_20170101_010104.jpg", "w").close()
with caplog.at_level(logging.INFO):
Phockup('input/sub_folder/sub0', 'output', move=True, rmdirs=True, max_depth=1)
assert 'Deleted empty directory: input/sub_folder/sub0/sub1' in caplog.text
assert 'input/sub_folder/sub0/sub2/sub3 not deleted' in caplog.text
assert os.path.isfile("output/2017/01/01/20170101-010101.jpg")
assert os.path.isfile("output/2017/01/01/20170101-010102.jpg")
assert os.path.isfile("output/2017/01/01/20170101-010103.jpg")
assert not os.path.isfile("output/2017/01/01/20170101-010104.jpg")
assert not os.path.isdir("input/sub_folder/sub0/sub1")
assert os.path.isdir("input/sub_folder/sub0/sub2")
assert os.path.isdir("input/sub_folder/sub0/sub2/sub3")
with caplog.at_level(logging.INFO):
Phockup('input/sub_folder/sub0', 'output', move=True, rmdirs=True)
assert 'Deleted empty directory: input/sub_folder/sub0/sub2' in caplog.text
assert not os.path.isdir("input/sub_folder/sub0/sub2")
assert os.path.isfile("output/2017/01/01/20170101-010104.jpg")
shutil.rmtree('input/sub_folder/sub0', ignore_errors=True)
shutil.rmtree('output', ignore_errors=True)


def test_process_link(mocker):
shutil.rmtree('output', ignore_errors=True)
mocker.patch.object(Phockup, 'check_directories')
Expand Down