blob: 978af7187ffe3391f193a45014d978e76a0c747e [file] [log] [blame]
#!/usr/bin/env python3
import os
import shutil
from typing import Tuple, Any
try:
import click
except ImportError:
print("You need the module \'click\'")
exit(1)
base_path = os.getcwd()
# I don't know how to set callables with different args
def apply_all(func: Any, directory: str, extension: str,
to_extension: str='', exclude: Tuple[str]=('',),
recursive: bool=True, debug: bool=False) -> None:
excluded = [x+extension for x in exclude] if exclude else []
for p, d, files in os.walk(os.path.join(base_path,directory)):
for f in files:
if "{}".format(f) in excluded:
continue
inner_path = os.path.join(p,f)
if not inner_path.endswith(extension):
continue
if to_extension:
new_path = "{}{}".format(inner_path[:-len(extension)],to_extension)
func(inner_path,new_path)
else:
func(inner_path)
if not recursive:
break
def confirm(resp: bool=False, **kargs) -> bool:
kargs['rest'] = "to this {f2}/*{e2}".format(**kargs) if kargs.get('f2') else ''
prompt = "{act} all files {rec}matching this expression {f1}/*{e1} {rest}".format(**kargs)
prompt.format(**kargs)
prompt = "{} [{}]|{}: ".format(prompt, 'Y' if resp else 'N', 'n' if resp else 'y')
while True:
ans = input(prompt).lower()
if not ans:
return resp
if ans not in ['y','n']:
print( 'Please, enter (y) or (n).')
continue
if ans == 'y':
return True
else:
return False
actions = ['cp', 'mv', 'rm']
@click.command(context_settings=dict(help_option_names=['-h', '--help']))
@click.option('--action', '-a', type=click.Choice(actions), required=True, help="What do I have to do :-)")
@click.option('--dir', '-d', 'directory', default='stubs', help="Directory to start search!")
@click.option('--ext', '-e', 'extension', default='.py', help="Extension \"from\" will be applied the action. Default .py")
@click.option('--to', '-t', 'to_extension', default='.pyi', help="Extension \"to\" will be applied the action if can. Default .pyi")
@click.option('--exclude', '-x', multiple=True, default=('__init__',), help="For every appear, will ignore this files. (can set multiples times)")
@click.option('--not-recursive', '-n', default=True, is_flag=True, help="Set if don't want to walk recursively.")
def main(action: str, directory: str, extension: str, to_extension: str,
exclude: Tuple[str], not_recursive: bool) -> None:
"""
This script helps to copy/move/remove files based on their extension.
The three actions will ask you for confirmation.
Examples (by default the script search in stubs directory):
- Change extension of all stubs from .py to .pyi:
python <script.py> -a mv
- Revert the previous action.
python <script.py> -a mv -e .pyi -t .py
- If you want to ignore "awesome.py" files.
python <script.py> -a [cp|mv|rm] -x awesome
- If you want to ignore "awesome.py" and "__init__.py" files.
python <script.py> -a [cp|mv|rm] -x awesome -x __init__
- If you want to remove all ".todo" files in "todo" directory, but not recursively:
python <script.py> -a rm -e .todo -d todo -r
"""
if action not in actions:
print("Your action have to be one of this: {}".format(', '.join(actions)))
return
rec = "[Recursively] " if not_recursive else ''
if not extension.startswith('.'):
extension = ".{}".format(extension)
if not to_extension.startswith('.'):
to_extension = ".{}".format(to_extension)
if directory.endswith('/'):
directory = directory[:-1]
if action == 'cp':
if confirm(act='Copy',rec=rec, f1=directory, e1=extension, f2=directory, e2=to_extension):
apply_all(shutil.copy, directory, extension, to_extension, exclude, not_recursive)
elif action == 'rm':
if confirm(act='Remove',rec=rec, f1=directory, e1=extension):
apply_all(os.remove, directory, extension, exclude=exclude, recursive=not_recursive)
elif action == 'mv':
if confirm(act='Move',rec=rec, f1=directory, e1=extension, f2=directory, e2=to_extension):
apply_all(shutil.move, directory, extension, to_extension, exclude, not_recursive)
if __name__ == '__main__':
main()