diff options
Diffstat (limited to '')
| -rw-r--r-- | patternutils/commands/patterncfg.py | 2 | ||||
| -rw-r--r-- | patternutils/commands/tln.py | 122 | ||||
| -rw-r--r-- | setup.py | 1 |
3 files changed, 124 insertions, 1 deletions
diff --git a/patternutils/commands/patterncfg.py b/patternutils/commands/patterncfg.py index 75272ac..4b29dfd 100644 --- a/patternutils/commands/patterncfg.py +++ b/patternutils/commands/patterncfg.py @@ -8,7 +8,7 @@ import click from .. import config -CURRENT_SUPPORTED_PROGRAMS = ('pmatch', 'tmv', 'targs') +CURRENT_SUPPORTED_PROGRAMS = ('pmatch', 'tmv', 'targs', 'tln') @click.group(context_settings={'help_option_names': ('-h', '--help', '-?')}) diff --git a/patternutils/commands/tln.py b/patternutils/commands/tln.py new file mode 100644 index 0000000..27112ec --- /dev/null +++ b/patternutils/commands/tln.py @@ -0,0 +1,122 @@ +import json +import os +import os.path + +import click + +from .. import template +from .. import config +from .. import utils + + +def link_file(old_filename: str, new_filename: str, symbolic: bool) -> None: + dirs = os.path.dirname(new_filename) + if dirs: + os.makedirs(dirs, exist_ok=True) + + if symbolic: + os.symlink(old_filename, new_filename) + else: + os.link(old_filename, new_filename) + + +@click.command(context_settings={'help_option_names': ('-h', '--help', '-?')}) +@click.option('-i', '--interactive', is_flag=True, default=False, + help='prompt wether to remove destinations') +@click.option('-e', '--editor', is_flag=True, default=False, + help='Open an editor before renaming files to allow manual changes') +@click.option('-f', '--force', is_flag=True, default=False, + help='remove existing destination files') +@click.option('-s', '--symbolic', is_flag=True, default=False, + help='make symbolic links instead of hard links') +@click.option('-t', '--template-engine', default='python', type=click.Choice(['python', 'jinja2']), + help='select the template engine to use') +@click.option('-k', '--key', default='_abspath', + help='select the key to use as the source file') +@click.option('--stream', is_flag=True, default=False, + help='Input is a stream of JSON objects') +@click.option('-p', '--use-predefined-template', is_flag=True, default=False, + help='use predefined template') +@click.option('--read-from', default='-', type=click.File('r')) +@click.option('--abort-on-path-exist', is_flag=True, default=False, + help='exit if a renamed path already exists') +@click.option('-n', '--dry-run', is_flag=True, default=False, + help='perform a trial run with no changes made') +@click.option('-v', '--verbose', is_flag=True, default=False, + help='explain what is being done') +@click.version_option() +@click.argument('output-pattern') +def tln( + output_pattern: str, + interactive: bool, + editor: bool, + force: bool, + symbolic: bool, + template_engine: str, + use_predefined_template: bool, + read_from: click.File, + key: str, + stream: bool, + abort_on_path_exist: bool, + dry_run, bool, + verbose: bool, +) -> None: + + try: + if not stream: + data = json.load(read_from) # type: ignore + else: + data = [json.loads(line) for line in read_from] + except json.JSONDecodeError: + click.secho('JSON not valid!', fg='red', err=True) + raise SystemExit + + if use_predefined_template: + try: + output_pattern, template_engine = config.load_template(output_pattern, 'tln') + except FileNotFoundError: + click.secho('File not found!', fg='red', err=True) + raise SystemExit + except RuntimeError: + click.secho('Multiple files found!', fg='red', err=True) + raise SystemExit + + try: + render = template.get_render_function(output_pattern, engine=template_engine) + except RuntimeError: + click.secho('jinja2 not installed!', fg='red', err=True) + raise SystemExit + + new_filenames = dict((entry['_abspath'], render(**entry)) for entry in data) + + if editor: + try: + new_filenames = utils.edit(new_filenames) + except RuntimeError: + click.secho('You edit is not parseable!', fg='red', err=True) + raise SystemExit + + has_existing = False + non_existing = {} + for old, new in new_filenames.items(): + if os.path.exists(new): + click.secho('{} does exist!'.format(new), fg='red', err=True) + has_existing = True + else: + non_existing[old] = new + + if has_existing and abort_on_path_exist: + raise SystemExit + + if force: + files_to_move = new_filenames.items() + else: + files_to_move = non_existing.items() + + for old, new in files_to_move: + if verbose or interactive: + click.echo('{} -> {}'.format(old, new)) + + if not (interactive and not click.confirm('Is the match correct?')): + if not dry_run: + link_file(old, new, symbolic) @@ -15,6 +15,7 @@ ENTRY_POINTS = { 'pmatch=patternutils.commands.pmatch:pmatch', 'targs=patternutils.commands.targs:targs', 'tmv=patternutils.commands.tmv:tmv', + 'tln=patternutils.commands.tln:tln', 'patterncfg=patternutils.commands.patterncfg:patterncfg', ], } |
