cmd/sole_subdir_lift.py

74 lines
2.2 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 pipeable
from voussoirkit import spinal
from voussoirkit import vlogging
from voussoirkit import winglob
2020-07-01 03:30:11 +00:00
log = vlogging.getLogger(__name__, 'sole_subdir_lift')
2020-07-01 03:30:11 +00:00
def main(argv):
argv = vlogging.set_level_by_argv(log, argv)
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
def main(argv):
argv = vlogging.set_level_by_argv(log, argv)
2020-07-01 03:30:11 +00:00
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:]))