cmd/sole_subdir_lift.py

68 lines
2.1 KiB
Python
Raw Normal View History

2020-07-01 03:30:11 +00:00
import argparse
import collections
2020-07-01 03:30:11 +00:00
import os
import shutil
import sys
from voussoirkit import passwordy
from voussoirkit import pathclass
from voussoirkit import spinal
from voussoirkit import vlogging
2020-07-01 03:30:11 +00:00
log = vlogging.getLogger(__name__, 'sole_subdir_lift')
2020-07-01 03:30:11 +00:00
def sole_lift_argparse(args):
starting = pathclass.Path(args.starting)
queue = collections.deque()
queue.extend(spinal.walk(starting, yield_files=False, yield_directories=True))
while len(queue) > 0:
directory = queue.popleft()
2020-07-01 03:30:11 +00:00
if not directory.exists:
log.debug('%s no longer exists.', directory)
continue
2020-07-01 03:30:11 +00:00
if directory not in starting:
log.debug('%s is outside of starting.', directory)
continue
2020-07-01 03:30:11 +00:00
children = directory.listdir()
child_count = len(children)
if child_count != 1:
log.debug('%s has %d children.', directory, child_count)
continue
2020-07-01 03:30:11 +00:00
child = children[0]
2020-07-01 03:30:11 +00:00
if not child.is_dir:
log.debug('%s contains a file, not a dir.', directory)
continue
log.info('Lifting contents of %s.', child.absolute_path)
# child is renamed to random hex so that the grandchildren we are about
# to lift don't have name conflicts with the child dir itself.
# Consider .\abc\abc where the grandchild can't be moved.
temp_dir = directory.with_child(passwordy.urandom_hex(32))
os.rename(child.absolute_path, temp_dir.absolute_path)
for grandchild in temp_dir.listdir():
shutil.move(grandchild.absolute_path, directory.absolute_path)
if temp_dir.listdir():
raise Exception()
os.rmdir(temp_dir.absolute_path)
queue.append(directory.parent)
2020-07-01 03:30:11 +00:00
@vlogging.main_decorator
2020-07-01 03:30:11 +00:00
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('starting', nargs='?', default='.')
2020-07-01 03:30:11 +00:00
parser.set_defaults(func=sole_lift_argparse)
args = parser.parse_args(argv)
return args.func(args)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))