Project

General

Profile

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

hydrilla-builder / src / hydrilla / util / __init__.py @ 16eaeb86

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 as _re
28
import json as _json
29

    
30
from typing import Optional as _Optional
31

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

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

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

    
74
        stripped_text.append(stripped)
75
        processed += len(line) + 1
76

    
77
    return '\n'.join(stripped_text)
78

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

    
86
    return ver[:new_len]
87

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

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