Skip to content

Commit

Permalink
implement --rmdirs option (ivandokov#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
rob-miller authored and unapproachable committed Sep 23, 2024
1 parent 84009e5 commit 1a45221
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
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

0 comments on commit 1a45221

Please sign in to comment.