Project

General

Profile

Download (3.66 KB) Statistics
| Branch: | Tag: | Revision:

hydrilla-builder / src / hydrilla / util / _util.py @ ad4331a4

1
# SPDX-License-Identifier: AGPL-3.0-or-later
2

    
3
# Building Hydrilla packages.
4
#
5
# This file is part of Hydrilla
6
#
7
# Copyright (C) 2021, 2022 Wojtek Kosior
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU Affero General Public License as
11
# published by the Free Software Foundation, either version 3 of the
12
# License, or (at your option) any later version.
13
#
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
# GNU Affero General Public License for more details.
18
#
19
# You should have received a copy of the GNU Affero General Public License
20
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
21
#
22
#
23
# I, Wojtek Kosior, thereby promise not to sue for violation of this
24
# file's license. Although I request that you do not make use this code
25
# in a proprietary program, I am not going to enforce this in court.
26

    
27
import re
28
import json
29

    
30
from pathlib import Path
31
from typing import Optional
32

    
33
here = Path(__file__).resolve().parent
34

    
35
_strip_comment_re = re.compile(r'''
36
^ # match from the beginning of each line
37
( # catch the part before '//' comment
38
  (?: # this group matches either a string or a single out-of-string character
39
    [^"/] |
40
    "
41
    (?: # this group matches any in-a-string character
42
      [^"\\] |          # match any normal character
43
      \\[^u] |          # match any escaped character like '\f' or '\n'
44
      \\u[a-fA-F0-9]{4} # match an escape
45
    )*
46
    "
47
  )*
48
)
49
# expect either end-of-line or a comment:
50
# * unterminated strings will cause matching to fail
51
# * bad comment (with '/' instead of '//') will be indicated by second group
52
#   having length 1 instead of 2 or 0
53
(//?|$)
54
''', re.VERBOSE)
55

    
56
def strip_json_comments(text: str) -> str:
57
    """
58
    Accept JSON text with optional C++-style ('//') comments and return the text
59
    with comments removed. Consecutive slashes inside strings are handled
60
    properly. A spurious single slash ('/') shall generate an error. Errors in
61
    JSON itself shall be ignored.
62
    """
63
    processed = 0
64
    stripped_text = []
65
    for line in text.split('\n'):
66
        match = _strip_comment_re.match(line)
67

    
68
        if match is None: # unterminated string
69
            # ignore this error, let json module report it
70
            stripped = line
71
        elif len(match[2]) == 1:
72
            raise json.JSONDecodeError('bad comment', text,
73
                                       processed + len(match[1]))
74
        else:
75
            stripped = match[1]
76

    
77
        stripped_text.append(stripped)
78
        processed += len(line) + 1
79

    
80
    return '\n'.join(stripped_text)
81

    
82
def normalize_version(ver: list[int]) -> list[int]:
83
    """Strip right-most zeroes from 'ver'. The original list is not modified."""
84
    new_len = 0
85
    for i, num in enumerate(ver):
86
        if num != 0:
87
            new_len = i + 1
88

    
89
    return ver[:new_len]
90

    
91
def parse_version(ver_str: str) -> list[int]:
92
    """
93
    Convert 'ver_str' into an array representation, e.g. for ver_str="4.6.13.0"
94
    return [4, 6, 13, 0].
95
    """
96
    return [int(num) for num in ver_str.split('.')]
97

    
98
def version_string(ver: list[int], rev: Optional[int]=None) -> str:
99
    """
100
    Produce version's string representation (optionally with revision), like:
101
        1.2.3-5
102
    No version normalization is performed.
103
    """
104
    return '.'.join([str(n) for n in ver]) + ('' if rev is None else f'-{rev}')
105

    
106
def load_schema(schema_filename: str) -> dict:
107
    """Find schema JSON file in '../schemas' and json.load() it."""
108
    with open(here.parent / 'schemas' / schema_filename, 'rt') as file_handle:
109
        return json.load(file_handle)
(2-2/2)