From 3d3ba6c37869268d84565a407b02e0d8d146c569 Mon Sep 17 00:00:00 2001 From: leafee98 Date: Sun, 16 Nov 2025 22:22:02 +0800 Subject: [PATCH] link-tool now could generate configuration --- link-tool.py | 102 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 19 deletions(-) mode change 100644 => 100755 link-tool.py diff --git a/link-tool.py b/link-tool.py old mode 100644 new mode 100755 index 3347ba5..b62c0e4 --- a/link-tool.py +++ b/link-tool.py @@ -2,11 +2,26 @@ import argparse import dataclasses -import os import logging +import os +import sys + +from string import Template from typing import List, Tuple, Union + +configuration_template = Template( +''' +cwd = $cwd + +# Generated by link-tool.py +# $link_tool_cmd + +$link_rules +''') + + logger = logging.getLogger(__name__) @dataclasses.dataclass(repr=True) @@ -87,6 +102,38 @@ def make_link(links: List[Link], dry_run=False, overwrite=False): if not dry_run: os.link(link.src, link.dst) +def generate_configuration(src: str, dst: str, config_path: str): + config_path_depth = config_path.strip('/').count('/') + cwd = '.' if config_path_depth == 0 else '..' + '/..' * (config_path_depth - 1) + + logger.info('configuration: cwd: {}'.format(cwd)) + + link_rules = [] + for dirname, _, files in os.walk(src): + for file in files: + link_rules.append(Link(src=os.path.join(dirname, file), + dst=os.path.join(dst, os.path.basename(file)))) + + max_src_file_path_len = max([len(l.src) for l in link_rules]) + formater = '{:%d} -> {}' % max_src_file_path_len + link_rules_str = '' + for l in link_rules: + link_rules_str += formater.format(l.src, l.dst) + '\n' + + configuration_str = configuration_template.safe_substitute( + cwd=cwd, + link_rules=link_rules_str, + link_tool_cmd="'{}'".format("' '".join(sys.argv))) + + # create parent dir for configuration file + configuration_dir = os.path.dirname(config_path) + if not os.path.exists(configuration_dir): + os.makedirs(configuration_dir) + + # write configuration file + with open(config_path, 'w', encoding='utf-8') as f: + f.write(configuration_str) + def main(): parser = argparse.ArgumentParser() parser.add_argument('-c', '--config', required=True, @@ -98,32 +145,49 @@ def main(): parser.add_argument('-v', '--verbose', action='store_true', help='more verbose log') + parser.add_argument('-g', '--generate', action='store_true', + help='generate configuration with a predefined template, ' + 'need other arguments. When this argument is used, ' + 'the generated configuration will be place to the path of --config') + parser.add_argument('--src', default=None, + help='src directory, link rule will be generate for ' + 'every file in this (sub)directory') + parser.add_argument('--dst', default=None, + help='dst directory, link rule\'target directory') + args = parser.parse_args() - config_path = args.config - verbose = args.verbose - dry_run = args.dry_run - overwrite = args.overwrite + logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO) - logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO) + if args.generate: + if args.src is None or args.dst is None: + logger.error('invalid argument, --src or --dst is not specified') + exit(1) + if '..' in args.config: + logger.error('configuration file path must not contain any \'..\'') + else: + generate_configuration(args.src, args.dst, args.config) + else: + dry_run = args.dry_run + overwrite = args.overwrite - config, links = load_config(config_path) + config, links = load_config(args.config) - if not config.validate(): - logger.error('invalid configuration, exiting...') - exit(1) + if not config.validate(): + logger.error('invalid configuration, exiting...') + exit(1) - for link in links: - logger.info('loaded link: {}'.format(link)) + for link in links: + logger.debug('loaded link: {}'.format(link)) - assert(config.cwd is not None) - config_path_dir = os.path.dirname(config_path) - chdir_target = os.path.join(config_path_dir, config.cwd) - logger.info('changing CWD: {}/{}'.format(config_path_dir, config.cwd)) - logger.info('the CWD realpath: {}'.format(os.path.realpath(chdir_target))) - os.chdir(chdir_target) + assert(config.cwd is not None) + config_path_dir = os.path.dirname(args.config) + chdir_target = os.path.join(config_path_dir, config.cwd) + logger.info('changing CWD: {}/{}'.format(config_path_dir, config.cwd)) + logger.info('the CWD realpath: {}'.format(os.path.realpath(chdir_target))) + os.chdir(chdir_target) - make_link(links, dry_run=dry_run, overwrite=overwrite) + make_link(links, dry_run=dry_run, overwrite=overwrite) if __name__ == '__main__': main()