link-tool now could generate configuration

This commit is contained in:
leafee98 2025-11-16 22:22:02 +08:00
parent 4cf9ab1ea1
commit 3d3ba6c378

80
link-tool.py Normal file → Executable file
View file

@ -2,11 +2,26 @@
import argparse import argparse
import dataclasses import dataclasses
import os
import logging import logging
import os
import sys
from string import Template
from typing import List, Tuple, Union 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__) logger = logging.getLogger(__name__)
@dataclasses.dataclass(repr=True) @dataclasses.dataclass(repr=True)
@ -87,6 +102,38 @@ def make_link(links: List[Link], dry_run=False, overwrite=False):
if not dry_run: if not dry_run:
os.link(link.src, link.dst) 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(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-c', '--config', required=True, parser.add_argument('-c', '--config', required=True,
@ -98,26 +145,43 @@ def main():
parser.add_argument('-v', '--verbose', action='store_true', parser.add_argument('-v', '--verbose', action='store_true',
help='more verbose log') 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() args = parser.parse_args()
config_path = args.config logging.basicConfig(level=logging.DEBUG if args.verbose else logging.INFO)
verbose = args.verbose
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 dry_run = args.dry_run
overwrite = args.overwrite overwrite = args.overwrite
logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO) config, links = load_config(args.config)
config, links = load_config(config_path)
if not config.validate(): if not config.validate():
logger.error('invalid configuration, exiting...') logger.error('invalid configuration, exiting...')
exit(1) exit(1)
for link in links: for link in links:
logger.info('loaded link: {}'.format(link)) logger.debug('loaded link: {}'.format(link))
assert(config.cwd is not None) assert(config.cwd is not None)
config_path_dir = os.path.dirname(config_path) config_path_dir = os.path.dirname(args.config)
chdir_target = os.path.join(config_path_dir, config.cwd) chdir_target = os.path.join(config_path_dir, config.cwd)
logger.info('changing CWD: {}/{}'.format(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))) logger.info('the CWD realpath: {}'.format(os.path.realpath(chdir_target)))