--- a/ldcheck.py Fri Sep 18 21:57:36 2020 +0300 +++ b/ldcheck.py Fri Sep 18 23:51:45 2020 +0300 @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import argparse from sys import version_info if version_info < (3, 4): raise RuntimeError('Python 3.4 or newer required') @@ -7,7 +8,6 @@ version = (1, 0, 9999) version_string = str.join('.', map(str, version)) -from colours import load_colours from geometry import * from pathlib import Path import linetypes @@ -17,59 +17,97 @@ from os.path import realpath script_directory = Path(realpath(__file__)).parent -def load_config(filename = None): - if filename is None: - filename = script_directory / 'ldcheck.cfg' - from configobj import ConfigObj - from copy import deepcopy - config = ConfigObj(str(filename), encoding = 'UTF8') - read_config = deepcopy(config) - if 'libraries' not in config: - config['libraries'] = ['/path/to/ldraw'] - if config != read_config: - config.write() - check_library_paths(config) - load_ldconfig_ldr(config) - return config +def config_dirs(): + import appdirs + appauthor = 'Teemu Piippo' + dirs = appdirs.AppDirs(appname, appauthor) + return { + 'user': Path(dirs.user_config_dir), + 'system': Path(dirs.site_config_dir), + } -def library_paths(config): - for library_path_string in config['libraries']: - yield Path(library_path_string).expanduser() +def ldraw_dirs_from_config(): + libraries = [] + dirs = config_dirs() + for dirpath in [dirs['system'], dirs['user']]: + filename = dirpath / 'ldcheck.cfg' + from configobj import ConfigObj + config = ConfigObj(str(filename), encoding = 'UTF8') + if 'libraries' in config: + libraries = expand_paths(config['libraries']) + return libraries + +def expand_paths(paths): + return [ + Path(library).expanduser() + for library in paths + ] -def check_library_paths(config): - from sys import exit - problems = False - have_paths = False - for library_path in library_paths(config): - have_paths = True - if not library_path.exists(): - problems = True - print(str.format( - 'Library path {} does not exist', - library_path, - )) - elif not library_path.exists(): - problems = True - print(str.format( - 'Library path {} is not a directory', - library_path, - )) - if not have_paths: - print('No LDraw path specified') - problems = True - if problems: - print('Please fix ldcheck.cfg') - exit(1) - -def find_ldconfig_ldr_paths(config): - for library_path in library_paths(config): - yield from [ - library_path / path - for path in ['LDConfig.ldr', 'ldconfig.ldr'] - if (library_path / path).is_file() - ] - -import argparse +class LDrawContext: + ''' + Contains context-dependant LDraw information, like library directory + paths and the colour table. + ''' + def __init__(self, libraries = None): + self._libraries = libraries + if not self._libraries: + self._libraries = ldraw_dirs_from_config() + self.ldconfig_colour_data = self.load_ldconfig_ldr() + self.check_library_paths() + @property + def libraries(self): + return self._libraries + @property + def colours(self): + return self.ldconfig_colour_data + def ldconfig_ldr_discovery(self): + for library_path in self.libraries: + yield from [ + library_path / path + for path in ['LDConfig.ldr', 'ldconfig.ldr'] + if (library_path / path).is_file() + ] + def load_ldconfig_ldr(self): + from colours import load_colours + for ldconfig_ldr_path in self.ldconfig_ldr_discovery(): + with open(ldconfig_ldr_path) as ldconfig_ldr: + return load_colours(ldconfig_ldr) + def check_library_paths(self): + from sys import stderr + problems = False + have_paths = False + for library_path in self.libraries: + have_paths = True + if not library_path.exists(): + problems = True + print(str.format( + 'Library path {} does not exist', + library_path, + ), file = stderr) + elif not library_path.exists(): + problems = True + print(str.format( + 'Library path {} is not a directory', + library_path, + ), file = stderr) + if not have_paths: + raise RuntimeError('no LDraw library paths specified') + def is_ldconfig_colour(self, colour): + return colour.index in self.colours + def colour_name(self, colour): + if self.is_ldconfig_colour(colour): + return self.colours[self.index]['name'] + else: + return str(colour) + def colour_face(self, colour): + if self.is_ldconfig_colour(colour): + return self.colours[self.index]['value'] + elif colour.is_direct_colour: + return '#%06X' % (self.index & 0xffffff) + else: + return '#000000' + def is_valid_colour(self, colour): + return self.is_ldconfig_colour(colour) or colour.is_direct_colour class ListProblemsAction(argparse.Action): def __init__(self, option_strings, dest, nargs = None, **kwargs): @@ -87,11 +125,6 @@ )) exit(0) -def load_ldconfig_ldr(config): - for ldconfig_ldr_path in find_ldconfig_ldr_paths(config): - with ldconfig_ldr_path.open() as ldconfig_ldr: - load_colours(ldconfig_ldr) - def format_report(report, model, test_suite, *, use_colors = True): from testsuite import problem_text messages = [] @@ -142,6 +175,10 @@ action = 'store_true', help = 'use colors' ) + parser.add_argument('-d', '--ldraw-dir', + nargs = '+', + help = 'specify LDraw directory path(s)', + ) parser.add_argument('-v', '--version', action = 'version', version = str.format('{appname} {version}', @@ -150,7 +187,14 @@ ), ) args = parser.parse_args() - config = load_config() + libraries = ldraw_dirs_from_config() + if args.ldraw_dir: + libraries = expand_paths(args.ldraw_dir) + try: + context = LDrawContext(libraries) + except RuntimeError as error: + print('error:', str(error), file = stderr) + exit(1) if args.color: try: import colorama @@ -160,9 +204,7 @@ args.color = False if args.subfile: import filecache - cache = filecache.SubfileCache( - ldraw_directories = config['libraries'], - ) + cache = filecache.SubfileCache(context = context) subfile = cache.prepare_file(args.filename) if not subfile.valid: print(subfile.problem) @@ -177,7 +219,7 @@ model = parse.read_ldraw( file, name = basename(args.filename), - ldraw_directories = config['libraries']) + context = context) if args.dump: print('header: ' + type(model.header).__name__) for key in sorted(dir(model.header)):