ldcheck.py

changeset 145
fde18c4d6784
parent 122
116a81996832
child 147
bec55b021ae7
--- 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)):

mercurial