1 #!/usr/bin/env python3 |
1 #!/usr/bin/env python3 |
|
2 import argparse |
2 from sys import version_info |
3 from sys import version_info |
3 if version_info < (3, 4): |
4 if version_info < (3, 4): |
4 raise RuntimeError('Python 3.4 or newer required') |
5 raise RuntimeError('Python 3.4 or newer required') |
5 |
6 |
6 appname = 'ldcheck' |
7 appname = 'ldcheck' |
7 version = (1, 0, 9999) |
8 version = (1, 0, 9999) |
8 version_string = str.join('.', map(str, version)) |
9 version_string = str.join('.', map(str, version)) |
9 |
10 |
10 from colours import load_colours |
|
11 from geometry import * |
11 from geometry import * |
12 from pathlib import Path |
12 from pathlib import Path |
13 import linetypes |
13 import linetypes |
14 import header |
14 import header |
15 import parse |
15 import parse |
16 |
16 |
17 from os.path import realpath |
17 from os.path import realpath |
18 script_directory = Path(realpath(__file__)).parent |
18 script_directory = Path(realpath(__file__)).parent |
19 |
19 |
20 def load_config(filename = None): |
20 def config_dirs(): |
21 if filename is None: |
21 import appdirs |
22 filename = script_directory / 'ldcheck.cfg' |
22 appauthor = 'Teemu Piippo' |
23 from configobj import ConfigObj |
23 dirs = appdirs.AppDirs(appname, appauthor) |
24 from copy import deepcopy |
24 return { |
25 config = ConfigObj(str(filename), encoding = 'UTF8') |
25 'user': Path(dirs.user_config_dir), |
26 read_config = deepcopy(config) |
26 'system': Path(dirs.site_config_dir), |
27 if 'libraries' not in config: |
27 } |
28 config['libraries'] = ['/path/to/ldraw'] |
28 |
29 if config != read_config: |
29 def ldraw_dirs_from_config(): |
30 config.write() |
30 libraries = [] |
31 check_library_paths(config) |
31 dirs = config_dirs() |
32 load_ldconfig_ldr(config) |
32 for dirpath in [dirs['system'], dirs['user']]: |
33 return config |
33 filename = dirpath / 'ldcheck.cfg' |
34 |
34 from configobj import ConfigObj |
35 def library_paths(config): |
35 config = ConfigObj(str(filename), encoding = 'UTF8') |
36 for library_path_string in config['libraries']: |
36 if 'libraries' in config: |
37 yield Path(library_path_string).expanduser() |
37 libraries = expand_paths(config['libraries']) |
38 |
38 return libraries |
39 def check_library_paths(config): |
39 |
40 from sys import exit |
40 def expand_paths(paths): |
41 problems = False |
41 return [ |
42 have_paths = False |
42 Path(library).expanduser() |
43 for library_path in library_paths(config): |
43 for library in paths |
44 have_paths = True |
44 ] |
45 if not library_path.exists(): |
45 |
46 problems = True |
46 class LDrawContext: |
47 print(str.format( |
47 ''' |
48 'Library path {} does not exist', |
48 Contains context-dependant LDraw information, like library directory |
49 library_path, |
49 paths and the colour table. |
50 )) |
50 ''' |
51 elif not library_path.exists(): |
51 def __init__(self, libraries = None): |
52 problems = True |
52 self._libraries = libraries |
53 print(str.format( |
53 if not self._libraries: |
54 'Library path {} is not a directory', |
54 self._libraries = ldraw_dirs_from_config() |
55 library_path, |
55 self.ldconfig_colour_data = self.load_ldconfig_ldr() |
56 )) |
56 self.check_library_paths() |
57 if not have_paths: |
57 @property |
58 print('No LDraw path specified') |
58 def libraries(self): |
59 problems = True |
59 return self._libraries |
60 if problems: |
60 @property |
61 print('Please fix ldcheck.cfg') |
61 def colours(self): |
62 exit(1) |
62 return self.ldconfig_colour_data |
63 |
63 def ldconfig_ldr_discovery(self): |
64 def find_ldconfig_ldr_paths(config): |
64 for library_path in self.libraries: |
65 for library_path in library_paths(config): |
65 yield from [ |
66 yield from [ |
66 library_path / path |
67 library_path / path |
67 for path in ['LDConfig.ldr', 'ldconfig.ldr'] |
68 for path in ['LDConfig.ldr', 'ldconfig.ldr'] |
68 if (library_path / path).is_file() |
69 if (library_path / path).is_file() |
69 ] |
70 ] |
70 def load_ldconfig_ldr(self): |
71 |
71 from colours import load_colours |
72 import argparse |
72 for ldconfig_ldr_path in self.ldconfig_ldr_discovery(): |
|
73 with open(ldconfig_ldr_path) as ldconfig_ldr: |
|
74 return load_colours(ldconfig_ldr) |
|
75 def check_library_paths(self): |
|
76 from sys import stderr |
|
77 problems = False |
|
78 have_paths = False |
|
79 for library_path in self.libraries: |
|
80 have_paths = True |
|
81 if not library_path.exists(): |
|
82 problems = True |
|
83 print(str.format( |
|
84 'Library path {} does not exist', |
|
85 library_path, |
|
86 ), file = stderr) |
|
87 elif not library_path.exists(): |
|
88 problems = True |
|
89 print(str.format( |
|
90 'Library path {} is not a directory', |
|
91 library_path, |
|
92 ), file = stderr) |
|
93 if not have_paths: |
|
94 raise RuntimeError('no LDraw library paths specified') |
|
95 def is_ldconfig_colour(self, colour): |
|
96 return colour.index in self.colours |
|
97 def colour_name(self, colour): |
|
98 if self.is_ldconfig_colour(colour): |
|
99 return self.colours[self.index]['name'] |
|
100 else: |
|
101 return str(colour) |
|
102 def colour_face(self, colour): |
|
103 if self.is_ldconfig_colour(colour): |
|
104 return self.colours[self.index]['value'] |
|
105 elif colour.is_direct_colour: |
|
106 return '#%06X' % (self.index & 0xffffff) |
|
107 else: |
|
108 return '#000000' |
|
109 def is_valid_colour(self, colour): |
|
110 return self.is_ldconfig_colour(colour) or colour.is_direct_colour |
73 |
111 |
74 class ListProblemsAction(argparse.Action): |
112 class ListProblemsAction(argparse.Action): |
75 def __init__(self, option_strings, dest, nargs = None, **kwargs): |
113 def __init__(self, option_strings, dest, nargs = None, **kwargs): |
76 super().__init__(option_strings, dest, nargs = 0, **kwargs) |
114 super().__init__(option_strings, dest, nargs = 0, **kwargs) |
77 def __call__(self, *args, **kwargs): |
115 def __call__(self, *args, **kwargs): |
140 ) |
173 ) |
141 parser.add_argument('--color', |
174 parser.add_argument('--color', |
142 action = 'store_true', |
175 action = 'store_true', |
143 help = 'use colors' |
176 help = 'use colors' |
144 ) |
177 ) |
|
178 parser.add_argument('-d', '--ldraw-dir', |
|
179 nargs = '+', |
|
180 help = 'specify LDraw directory path(s)', |
|
181 ) |
145 parser.add_argument('-v', '--version', |
182 parser.add_argument('-v', '--version', |
146 action = 'version', |
183 action = 'version', |
147 version = str.format('{appname} {version}', |
184 version = str.format('{appname} {version}', |
148 appname = appname, |
185 appname = appname, |
149 version = version_string, |
186 version = version_string, |
150 ), |
187 ), |
151 ) |
188 ) |
152 args = parser.parse_args() |
189 args = parser.parse_args() |
153 config = load_config() |
190 libraries = ldraw_dirs_from_config() |
|
191 if args.ldraw_dir: |
|
192 libraries = expand_paths(args.ldraw_dir) |
|
193 try: |
|
194 context = LDrawContext(libraries) |
|
195 except RuntimeError as error: |
|
196 print('error:', str(error), file = stderr) |
|
197 exit(1) |
154 if args.color: |
198 if args.color: |
155 try: |
199 try: |
156 import colorama |
200 import colorama |
157 colorama.init() |
201 colorama.init() |
158 except ImportError: |
202 except ImportError: |
159 print('Use of --color requires the colorama module, disabling colours', file = stderr) |
203 print('Use of --color requires the colorama module, disabling colours', file = stderr) |
160 args.color = False |
204 args.color = False |
161 if args.subfile: |
205 if args.subfile: |
162 import filecache |
206 import filecache |
163 cache = filecache.SubfileCache( |
207 cache = filecache.SubfileCache(context = context) |
164 ldraw_directories = config['libraries'], |
|
165 ) |
|
166 subfile = cache.prepare_file(args.filename) |
208 subfile = cache.prepare_file(args.filename) |
167 if not subfile.valid: |
209 if not subfile.valid: |
168 print(subfile.problem) |
210 print(subfile.problem) |
169 else: |
211 else: |
170 print('Flat dimensions:', repr(subfile.flatness)) |
212 print('Flat dimensions:', repr(subfile.flatness)) |