Revision f42f5c19
Added by koszko over 1 year ago
.gitmodules | ||
---|---|---|
4 | 4 |
# |
5 | 5 |
# Available under the terms of Creative Commons Zero v1.0 Universal. |
6 | 6 |
|
7 |
[submodule "hydrilla-json-schemas"] |
|
8 |
path = src/hydrilla/schemas |
|
7 |
[submodule "hydrilla-json-schemas-1.x"]
|
|
8 |
path = src/hydrilla/schemas/1.x
|
|
9 | 9 |
url = ../hydrilla-json-schemas |
10 |
[submodule "hydrilla-json-schemas-2.x"] |
|
11 |
path = src/hydrilla/schemas/2.x |
|
12 |
url = ../hydrilla-json-schemas/ |
|
13 |
branch = koszko |
|
10 | 14 |
[submodule "hydrilla-source-package-example"] |
11 | 15 |
path = tests/source-package-example |
12 | 16 |
url = ../hydrilla-source-package-example |
MANIFEST.in | ||
---|---|---|
4 | 4 |
# |
5 | 5 |
# Available under the terms of Creative Commons Zero v1.0 Universal. |
6 | 6 |
|
7 |
include src/hydrilla/schemas/*.schema.json* |
|
7 |
include src/hydrilla/schemas/*/*.schema.json*
|
|
8 | 8 |
include src/hydrilla/builder/locales/*/LC_MESSAGES/hydrilla-messages.po |
9 | 9 |
include tests/source-package-example/* |
10 | 10 |
include tests/source-package-example/LICENSES/* |
src/hydrilla/builder/build.py | ||
---|---|---|
51 | 51 |
|
52 | 52 |
_ = util.translation(here / 'locales').gettext |
53 | 53 |
|
54 |
index_validator = util.validator_for('package_source-2.schema.json') |
|
54 |
def index_validator(major_schema_version): |
|
55 |
""" |
|
56 |
Create an index.json schema validator specific to the requested schema |
|
57 |
version series. |
|
58 |
""" |
|
59 |
exact_version = {1: '1.0.1', 2: '2'}[major_schema_version] |
|
60 |
|
|
61 |
return util.validator_for(f'package_source-{exact_version}.schema.json') |
|
55 | 62 |
|
56 | 63 |
schemas_root = 'https://hydrilla.koszko.org/schemas' |
57 | 64 |
|
... | ... | |
158 | 165 |
if not index_json_path.is_absolute(): |
159 | 166 |
index_json_path = (self.srcdir / index_json_path) |
160 | 167 |
|
161 |
with open(index_json_path, 'rt') as index_file: |
|
162 |
index_json_text = index_file.read() |
|
168 |
index_obj, major = util.load_instance_from_file(index_json_path) |
|
163 | 169 |
|
164 |
index_obj = json.loads(util.strip_json_comments(index_json_text)) |
|
170 |
if major not in (1, 2): |
|
171 |
msg = _('unknown_schema_package_source_{}')\ |
|
172 |
.format(index_json_path) |
|
173 |
raise util.UnknownSchemaError(msg) |
|
165 | 174 |
|
166 | 175 |
index_desired_path = PurePosixPath('index.json') |
167 | 176 |
self.files_by_path[index_desired_path] = \ |
168 |
FileRef(index_desired_path, index_json_text.encode())
|
|
177 |
FileRef(index_desired_path, index_json_path.read_bytes())
|
|
169 | 178 |
|
170 |
self._process_index_json(index_obj) |
|
179 |
self._process_index_json(index_obj, major)
|
|
171 | 180 |
|
172 | 181 |
def _process_file(self, filename: Union[str, PurePosixPath], |
173 | 182 |
piggybacked: Piggybacked, |
... | ... | |
308 | 317 |
props_in_ref = ('type', 'identifier', 'version', 'long_name') |
309 | 318 |
return dict([(prop, new_item_obj[prop]) for prop in props_in_ref]) |
310 | 319 |
|
311 |
def _process_index_json(self, index_obj: dict): |
|
320 |
def _process_index_json(self, index_obj: dict, |
|
321 |
major_schema_version: int) -> None: |
|
312 | 322 |
""" |
313 | 323 |
Process 'index_obj' as contents of source package's index.json and store |
314 | 324 |
in memory this source package's zipfile as well as package's individual |
315 | 325 |
files and computed definitions of the source package and items defined |
316 | 326 |
in it. |
317 | 327 |
""" |
318 |
index_validator.validate(index_obj) |
|
328 |
index_validator(major_schema_version).validate(index_obj) |
|
329 |
|
|
319 | 330 |
match = re.match(r'.*-((([1-9][0-9]*|0)\.)+)schema\.json$', |
320 | 331 |
index_obj['$schema']) |
321 | 332 |
self.source_schema_ver = \ |
src/hydrilla/builder/locales/en_US/LC_MESSAGES/hydrilla-messages.po | ||
---|---|---|
7 | 7 |
msgstr "" |
8 | 8 |
"Project-Id-Version: hydrilla.builder 0.1.dev16+g4e46d7f.d20220211\n" |
9 | 9 |
"Report-Msgid-Bugs-To: koszko@koszko.org\n" |
10 |
"POT-Creation-Date: 2022-05-11 11:10+0200\n"
|
|
10 |
"POT-Creation-Date: 2022-05-27 18:49+0200\n"
|
|
11 | 11 |
"PO-Revision-Date: 2022-02-12 00:00+0000\n" |
12 | 12 |
"Last-Translator: Wojtek Kosior <koszko@koszko.org>\n" |
13 | 13 |
"Language: en_US\n" |
... | ... | |
18 | 18 |
"Content-Transfer-Encoding: 8bit\n" |
19 | 19 |
"Generated-By: Babel 2.8.0\n" |
20 | 20 |
|
21 |
#: src/hydrilla/builder/build.py:86 src/hydrilla/builder/local_apt.py:118
|
|
22 |
#: src/hydrilla/builder/local_apt.py:407
|
|
21 |
#: src/hydrilla/builder/build.py:93 src/hydrilla/builder/local_apt.py:118
|
|
22 |
#: src/hydrilla/builder/local_apt.py:410
|
|
23 | 23 |
msgid "couldnt_execute_{}_is_it_installed" |
24 | 24 |
msgstr "Could not execute '{}'. Is the tool installed and reachable via PATH?" |
25 | 25 |
|
26 |
#: src/hydrilla/builder/build.py:90 src/hydrilla/builder/local_apt.py:122
|
|
27 |
#: src/hydrilla/builder/local_apt.py:411
|
|
26 |
#: src/hydrilla/builder/build.py:97 src/hydrilla/builder/local_apt.py:122
|
|
27 |
#: src/hydrilla/builder/local_apt.py:414
|
|
28 | 28 |
msgid "command_{}_failed" |
29 | 29 |
msgstr "The following command finished execution with a non-zero exit status: {}" |
30 | 30 |
|
31 |
#: src/hydrilla/builder/build.py:198 |
|
31 |
#: src/hydrilla/builder/build.py:171 |
|
32 |
msgid "unknown_schema_package_source_{}" |
|
33 |
msgstr "" |
|
34 |
"The provided JSON at '{}' does not use any of the known package source " |
|
35 |
"JSON schemas." |
|
36 |
|
|
37 |
#: src/hydrilla/builder/build.py:207 |
|
32 | 38 |
msgid "path_contains_double_dot_{}" |
33 | 39 |
msgstr "" |
34 | 40 |
"Attempt to load '{}' which includes a forbidden parent reference ('..') " |
35 | 41 |
"in the path." |
36 | 42 |
|
37 |
#: src/hydrilla/builder/build.py:205
|
|
43 |
#: src/hydrilla/builder/build.py:214
|
|
38 | 44 |
msgid "loading_{}_outside_package_dir" |
39 | 45 |
msgstr "Attempt to load '{}' which lies outside package source directory." |
40 | 46 |
|
41 |
#: src/hydrilla/builder/build.py:209
|
|
47 |
#: src/hydrilla/builder/build.py:218
|
|
42 | 48 |
msgid "loading_reserved_index_json" |
43 | 49 |
msgstr "Attempt to load 'index.json' which is a reserved filename." |
44 | 50 |
|
45 |
#: src/hydrilla/builder/build.py:216
|
|
51 |
#: src/hydrilla/builder/build.py:225
|
|
46 | 52 |
msgid "referenced_file_{}_missing" |
47 | 53 |
msgstr "Referenced file '{}' is missing." |
48 | 54 |
|
49 |
#: src/hydrilla/builder/build.py:351
|
|
55 |
#: src/hydrilla/builder/build.py:362
|
|
50 | 56 |
msgid "report_spdx_not_in_copyright_list" |
51 | 57 |
msgstr "" |
52 | 58 |
"Told to generate 'report.spdx' but 'report.spdx' is not listed among " |
53 | 59 |
"copyright files. Refusing to proceed." |
54 | 60 |
|
55 |
#: src/hydrilla/builder/build.py:422
|
|
61 |
#: src/hydrilla/builder/build.py:433
|
|
56 | 62 |
msgid "build_package_from_srcdir_to_dstdir" |
57 | 63 |
msgstr "" |
58 | 64 |
"Build Hydrilla package from `scrdir` and write the resulting files under " |
59 | 65 |
"`dstdir`." |
60 | 66 |
|
61 |
#: src/hydrilla/builder/build.py:424
|
|
67 |
#: src/hydrilla/builder/build.py:435
|
|
62 | 68 |
msgid "source_directory_to_build_from" |
63 | 69 |
msgstr "Source directory to build from." |
64 | 70 |
|
65 |
#: src/hydrilla/builder/build.py:426
|
|
71 |
#: src/hydrilla/builder/build.py:437
|
|
66 | 72 |
msgid "path_instead_of_index_json" |
67 | 73 |
msgstr "" |
68 | 74 |
"Path to file to be processed instead of index.json (if not absolute, " |
69 | 75 |
"resolved relative to srcdir)." |
70 | 76 |
|
71 |
#: src/hydrilla/builder/build.py:428
|
|
77 |
#: src/hydrilla/builder/build.py:439
|
|
72 | 78 |
msgid "path_instead_for_piggyback_files" |
73 | 79 |
msgstr "" |
74 | 80 |
"Path to a non-standard directory with foreign packages' archive files to " |
75 | 81 |
"use." |
76 | 82 |
|
77 |
#: src/hydrilla/builder/build.py:430
|
|
83 |
#: src/hydrilla/builder/build.py:441
|
|
78 | 84 |
msgid "built_package_files_destination" |
79 | 85 |
msgstr "Destination directory to write built package files to." |
80 | 86 |
|
81 |
#: src/hydrilla/builder/build.py:432
|
|
87 |
#: src/hydrilla/builder/build.py:443
|
|
82 | 88 |
#, python-format |
83 | 89 |
msgid "%(prog)s_%(version)s_license" |
84 | 90 |
msgstr "" |
... | ... | |
89 | 95 |
"This is free software: you are free to change and redistribute it.\n" |
90 | 96 |
"There is NO WARRANTY, to the extent permitted by law." |
91 | 97 |
|
92 |
#: src/hydrilla/builder/build.py:433
|
|
98 |
#: src/hydrilla/builder/build.py:444
|
|
93 | 99 |
msgid "version_printing" |
94 | 100 |
msgstr "Print version information and exit." |
95 | 101 |
|
... | ... | |
105 | 111 |
msgid "distro_{}_unknown" |
106 | 112 |
msgstr "Attempt to use an unknown software distribution '{}'." |
107 | 113 |
|
108 |
#: src/hydrilla/builder/local_apt.py:190
|
|
114 |
#: src/hydrilla/builder/local_apt.py:191
|
|
109 | 115 |
msgid "couldnt_import_{}_is_it_installed" |
110 | 116 |
msgstr "" |
111 | 117 |
"Could not import '{}'. Is the module installed and visible to this Python" |
112 | 118 |
" instance?" |
113 | 119 |
|
114 |
#: src/hydrilla/builder/local_apt.py:198
|
|
120 |
#: src/hydrilla/builder/local_apt.py:199
|
|
115 | 121 |
msgid "gpg_couldnt_recv_key_{}" |
116 | 122 |
msgstr "Could not import PGP key '{}'." |
117 | 123 |
|
118 |
#: src/hydrilla/builder/local_apt.py:312
|
|
124 |
#: src/hydrilla/builder/local_apt.py:313
|
|
119 | 125 |
msgid "apt_install_output_not_understood" |
120 | 126 |
msgstr "The output of an 'apt-get install' command was not understood." |
121 | 127 |
|
122 |
#: src/hydrilla/builder/local_apt.py:338
|
|
128 |
#: src/hydrilla/builder/local_apt.py:339
|
|
123 | 129 |
msgid "apt_download_gave_bad_filename_{}" |
124 | 130 |
msgstr "The 'apt-get download' command produced a file with unexpected name '{}'." |
125 | 131 |
|
... | ... | |
129 | 135 |
"Attempt to load '{}' which lies outside piggybacked packages files root " |
130 | 136 |
"directory." |
131 | 137 |
|
132 |
#: src/hydrilla/util/_util.py:79
|
|
138 |
#: src/hydrilla/util/_util.py:86
|
|
133 | 139 |
msgid "bad_comment" |
134 | 140 |
msgstr "bad comment" |
135 | 141 |
|
src/hydrilla/schemas | ||
---|---|---|
1 |
Subproject commit 4b4da5a02bc311603469eea7b3dfd4f1bbb911fd |
src/hydrilla/schemas/1.x | ||
---|---|---|
1 |
Subproject commit 09634f3446866f712a022327683b1149d8f46bf0 |
src/hydrilla/schemas/2.x | ||
---|---|---|
1 |
Subproject commit 6b6ae219929dc1d47e1dff2a780784b78bd825b8 |
src/hydrilla/util/__init__.py | ||
---|---|---|
4 | 4 |
# |
5 | 5 |
# Available under the terms of Creative Commons Zero v1.0 Universal. |
6 | 6 |
|
7 |
from ._util import strip_json_comments, normalize_version, parse_version, \ |
|
8 |
version_string, validator_for, translation |
|
7 |
from ._util import normalize_version, parse_version, version_string, \ |
|
8 |
validator_for, load_instance_from_file, translation, UnknownSchemaError |
src/hydrilla/util/_util.py | ||
---|---|---|
39 | 39 |
|
40 | 40 |
here = Path(__file__).resolve().parent |
41 | 41 |
|
42 |
class UnknownSchemaError(Exception): |
|
43 |
""" |
|
44 |
Exception used to record problems with JSON documents for which not even |
|
45 |
the appropriate validation schema could be determined. |
|
46 |
""" |
|
47 |
pass |
|
48 |
|
|
42 | 49 |
_strip_comment_re = re.compile(r''' |
43 | 50 |
^ # match from the beginning of each line |
44 | 51 |
( # catch the part before '//' comment |
... | ... | |
111 | 118 |
return '.'.join([str(n) for n in ver]) + ('' if rev is None else f'-{rev}') |
112 | 119 |
|
113 | 120 |
schemas = {} |
114 |
for path in (here.parent / 'schemas').glob('*-1.0.1.schema.json'): |
|
115 |
schema = json.loads(path.read_text()) |
|
116 |
schemas[schema['$id']] = schema |
|
121 |
for series_dir in (here.parent / 'schemas').glob('*.x'): |
|
122 |
for path in series_dir.glob("*.schema.json"): |
|
123 |
schema = json.loads(path.read_text()) |
|
124 |
schemas[schema['$id']] = schema |
|
117 | 125 |
|
118 | 126 |
common_schema_filename = 'common_definitions-1.schema.json' |
119 | 127 |
common_schema_path = here.parent / "schemas" / common_schema_filename |
120 | 128 |
|
121 |
resolver = RefResolver( |
|
122 |
base_uri=f'file://{str(common_schema_path)}', |
|
123 |
referrer=f'https://hydrilla.koszko.org/{common_schema_filename}', |
|
124 |
store=schemas |
|
125 |
) |
|
129 |
def validator_for(schema: Union[str, dict]) -> Draft7Validator: |
|
130 |
""" |
|
131 |
Prepare a validator for the provided schema. |
|
126 | 132 |
|
127 |
def validator_for(schema_filename: str) -> Draft7Validator:
|
|
133 |
Other schemas under '../schemas' can be referenced.
|
|
128 | 134 |
""" |
129 |
Prepare a validator for one of the schemas in '../schemas'. |
|
135 |
if isinstance(schema, str): |
|
136 |
schema = schemas[f'https://hydrilla.koszko.org/schemas/{schema}'] |
|
137 |
|
|
138 |
resolver = RefResolver( |
|
139 |
base_uri=schema['$id'], |
|
140 |
referrer=schema, |
|
141 |
handlers={'https': lambda uri: schemas[uri]} |
|
142 |
) |
|
143 |
|
|
144 |
return Draft7Validator(schema, resolver=resolver) |
|
145 |
|
|
146 |
_major_version_re = re.compile(r''' |
|
147 |
- |
|
148 |
(?P<major>[1-9][0-9]*) |
|
149 |
(?: # this repeated group matches the remaining version numbers |
|
150 |
\. |
|
151 |
(?:[1-9][0-9]*|0) |
|
152 |
)* |
|
153 |
\.schema\.json |
|
154 |
$ |
|
155 |
''', re.VERBOSE) |
|
156 |
|
|
157 |
def load_instance_from_file(path: Path) -> tuple[dict, Optional[int]]: |
|
158 |
""" |
|
159 |
Open a file and load its contents as a JSON document (with additional |
|
160 |
'//' comments support). Then parse its "$schema" property (if present) |
|
161 |
and return a tuple of the document instance and the major number of |
|
162 |
schema version. |
|
130 | 163 |
|
131 |
This function is not thread-safe.
|
|
164 |
If no schema version number can be extracted, None is used instead.
|
|
132 | 165 |
""" |
133 |
return Draft7Validator(resolver.resolve(schema_filename)[1], |
|
134 |
resolver=resolver) |
|
166 |
instance = json.loads(strip_json_comments(path.read_text())) |
|
167 |
major = None |
|
168 |
|
|
169 |
if type(instance) is dict and type(instance.get('$schema')) is str: |
|
170 |
match = _major_version_re.search(instance.get('$schema')) |
|
171 |
major = match and int(match.group('major')) |
|
172 |
|
|
173 |
return instance, major |
|
135 | 174 |
|
136 | 175 |
def translation(localedir: Union[Path, str], lang: Optional[str]=None) \ |
137 | 176 |
-> gettext.GNUTranslations: |
tests/test_build.py | ||
---|---|---|
34 | 34 |
|
35 | 35 |
orig_srcdir = here / 'source-package-example' |
36 | 36 |
|
37 |
index_text = (orig_srcdir / 'index.json').read_text() |
|
38 |
index_obj = json.loads(hydrilla_util.strip_json_comments(index_text)) |
|
37 |
index_obj, _ = hydrilla_util.load_instance_from_file(orig_srcdir / 'index.json') |
|
39 | 38 |
|
40 | 39 |
def read_files(*file_list): |
41 | 40 |
""" |
Also available in: Unified diff
incorporate version 2 of Hydrilla JSON schemas