Ethan Dalool
4a9051e617
With pathclass.glob_many, we can clean up and feel more confident about many programs that use pipeable to take glob patterns. Added return 0 to all programs that didn't have it, so we have consistent and explicit command line return values. Other linting and whitespace.
69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
import argparse
|
|
import collections
|
|
import os
|
|
import shutil
|
|
import sys
|
|
|
|
from voussoirkit import passwordy
|
|
from voussoirkit import pathclass
|
|
from voussoirkit import spinal
|
|
from voussoirkit import vlogging
|
|
|
|
log = vlogging.getLogger(__name__, 'sole_subdir_lift')
|
|
|
|
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()
|
|
|
|
if not directory.exists:
|
|
log.debug('%s no longer exists.', directory)
|
|
continue
|
|
|
|
if directory not in starting:
|
|
log.debug('%s is outside of starting.', directory)
|
|
continue
|
|
|
|
children = directory.listdir()
|
|
child_count = len(children)
|
|
if child_count != 1:
|
|
log.debug('%s has %d children.', directory, child_count)
|
|
continue
|
|
|
|
child = children[0]
|
|
|
|
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)
|
|
|
|
return 0
|
|
|
|
@vlogging.main_decorator
|
|
def main(argv):
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
|
|
parser.add_argument('starting', nargs='?', default='.')
|
|
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:]))
|