Last active
April 29, 2018 12:50
-
-
Save danijar/c845de537b799fcdd8824da60ced7afc to your computer and use it in GitHub Desktop.
Text based tool move and delete directories
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
"""Move or delete directories via your text editor. | |
Installation: | |
- Install sh.py via `pip3 install sh`. | |
- Save this file into a directory in your $PATH, for example `~/bin`. | |
""" | |
import argparse | |
import tempfile | |
import os | |
import sh | |
__author__ = 'Danijar Hafner' | |
def user_edit_text(text): | |
editor = sh.Command(os.environ.get('EDITOR', 'vim')) | |
with tempfile.NamedTemporaryFile('w+', suffix='.tmp') as file_: | |
file_.write(text) | |
file_.flush() | |
editor(file_.name, _fg=True) | |
file_.seek(0) | |
return file_.read() | |
def read_changes(dirs, edited): | |
edited = [line.strip() for line in edited.strip().split('\n')] | |
edited = [line.split(' ', 1) for line in edited if line] | |
edited = {int(index): dir_ for index, dir_ in edited} | |
keeps, moves, deletes = [], [], [] | |
for index, dir_ in enumerate(dirs): | |
if index not in edited: | |
deletes.append(dir_) | |
elif edited[index] != dir_: | |
moves.append((dir_, edited[index])) | |
else: | |
keeps.append(dir_) | |
return keeps, moves, deletes | |
def preview_changes(keeps, moves, deletes): | |
if keeps: | |
print('Unchanged:') | |
print(''.join('- {}\n'.format(x) for x in keeps)) | |
if moves: | |
print('Move:') | |
print(''.join('- {}\n {}\n'.format(*x) for x in moves)) | |
if deletes: | |
print('Delete:') | |
print(''.join('- {}\n'.format(x) for x in deletes)) | |
try: | |
if input('Looks good? [Ny]: ') == 'y': | |
return True | |
except KeyboardInterrupt: | |
print('') | |
print('No changes made.') | |
return False | |
def execute_changes(moves, deletes, args): | |
move = sh.Command(args.move_cmd.split(' ', 1)[0]) | |
params = args.move_cmd.split(' ', 1)[1] | |
commands = [] | |
for source, target in moves: | |
commands.append(move(*params.format(source, target).split(), _bg=True)) | |
delete = sh.Command(args.delete_cmd.split(' ', 1)[0]) | |
params = args.delete_cmd.split(' ', 1)[1] | |
for dir_ in deletes: | |
commands.append(delete(*params.format(dir_).split(), _bg=True)) | |
failures = 0 | |
for command in commands: | |
try: | |
command.wait() | |
except sh.ErrorReturnCode as e: | |
print(e) | |
failures += 1 | |
return failures | |
def read_directory_list(content_cmd): | |
content = sh.Command(content_cmd.split(' ', 1)[0]) | |
params = content_cmd.split(' ', 1)[1] | |
dirs = content(*params.format(args.root).split()).strip().split('\n') | |
text = ''.join('{} {}\n'.format(*x) for x in enumerate(dirs)) | |
return dirs, text | |
def main(args): | |
dirs, initial = read_directory_list(args.content_cmd) | |
current = initial | |
while True: | |
edited = user_edit_text(current) | |
if initial.strip() == edited.strip(): | |
print('No changes made.') | |
return | |
keeps, moves, deletes = read_changes(dirs, edited) | |
if not preview_changes(keeps, moves, deletes): | |
return | |
failures = execute_changes(moves, deletes, args) | |
message = '{} changes failed. Re-edit change list? [Ny]: ' | |
if failures and input(message.format(failures)) == 'y': | |
dirs, initial = read_directory_list(args.content_cmd) | |
current = edited | |
continue | |
else: | |
break | |
print('Done.') | |
if __name__ == '__main__': | |
description = 'Move or delete directories via your text editor.' | |
parser = argparse.ArgumentParser(description=description) | |
parser.add_argument('root', type=str) | |
parser.add_argument( | |
'--content-cmd', type=str, default='ls {}') | |
parser.add_argument( | |
'--move-cmd', type=str, default='mv {} {}') | |
parser.add_argument( | |
'--delete-cmd', type=str, default='rm -rf {}') | |
args = parser.parse_args() | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment