aboutsummaryrefslogtreecommitdiffstats
path: root/packaging-tools/release_task_reader.py
blob: 9dbaf00e124d1b11a1c4ea335d66d3f4f6410e40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#############################################################################
#
# Copyright (C) 2022 The Qt Company Ltd.
# Contact: https://www.qt.io/licensing/
#
# This file is part of the release tools of the Qt Toolkit.
#
# $QT_BEGIN_LICENSE:GPL-EXCEPT$
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
# a written agreement between you and The Qt Company. For licensing terms
# and conditions see https://www.qt.io/terms-conditions. For further
# information use the contact form at https://www.qt.io/contact-us.
#
# GNU General Public License Usage
# Alternatively, this file may be used under the terms of the GNU
# General Public License version 3 as published by the Free Software
# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
# included in the packaging of this file. Please review the following
# information to ensure the GNU General Public License requirements will
# be met: https://www.gnu.org/licenses/gpl-3.0.html.
#
# $QT_END_LICENSE$
#
#############################################################################

import os
import re
import sys
import argparse
from typing import List, Dict
from configparser import ConfigParser, ExtendedInterpolation
from logging_util import init_logger

log = init_logger(__name__, debug_mode=False)


class ReleaseTaskError(Exception):
    pass


class ReleaseTask:

    def __init__(self, name: str, settings: Dict[str, str]):
        if not len(name.split(".")) >= 3:
            raise ReleaseTaskError("The '[{0}]' has too few dot separated elements!".format(name))
        self.name = name
        self.config_file = settings["config_file"]
        self.project_name = settings.get("project_name", "")
        self.version = settings.get("version", "")
        self.prerelease_version = settings.get("prerelease_version", "")
        self.substitutions = settings.get("substitutions", "")
        self.repo_path = settings.get("repo_path", "")
        self.repo_components_to_update = settings.get("repo_components_to_update", "")
        self.installer_name = settings.get("installer_name", "")
        self.rta_key_list = settings.get("rta_key_list", "")
        tmpList = [x.strip() for x in self.substitutions.split(',')] if self.substitutions else []  # type: List[str]
        self.installer_string_replacement_list = list(filter(None, tmpList))
        self.source_online_repository_path = ""
        self.source_pkg_path = ""

    def add_to_substitutions_list(self, substitutions: List[str]) -> None:
        self.installer_string_replacement_list += substitutions

    def is_repository_task(self) -> bool:
        return self.name.split(".")[1] == "repository"

    def is_offline_installer_task(self) -> bool:
        return self.name.split(".")[1] == "offline"

    def is_online_installer_task(self) -> bool:
        return self.name.split(".")[1] == "online"

    def get_config_file(self) -> str:
        return self.config_file

    def get_substitutions(self) -> str:
        return self.substitutions

    def get_installer_string_replacement_list(self) -> List[str]:
        return self.installer_string_replacement_list

    def get_repo_components_to_update(self) -> str:
        return self.repo_components_to_update

    def get_installer_name(self) -> str:
        return self.installer_name

    def get_project_name(self) -> str:
        return self.project_name

    def get_version(self) -> str:
        return self.version

    def get_prerelease_version(self) -> str:
        return self.prerelease_version.strip()

    def get_repo_path(self) -> str:
        return self.repo_path

    def get_rta_key_list(self) -> List[str]:
        tmpList = self.rta_key_list.strip().replace(' ', '').split(",")
        return list(filter(None, tmpList))

    def get_source_online_repository_path(self) -> str:
        # this points to local repository build path
        return self.source_online_repository_path

    def get_source_pkg_path(self) -> str:
        # this points to local repository build path
        return self.source_pkg_path


def parse_substitutions_list(parser, section) -> List[str]:
    try:
        args = parser[section]['substitutions']
        return [x.strip() for x in args.split(',')]
    except KeyError:
        # it's ok, the 'substitutions' is not mandatory
        pass
    return []


def get_filter_parts(section_filters: str) -> List[str]:
    return list(filter(None, re.split("[, ;:]+", section_filters)))


def parse_data(settings, task_filters: List[str]) -> List[ReleaseTask]:
    tasks = []  # type: List[ReleaseTask]
    common_substitution_list = parse_substitutions_list(settings, 'common.substitutions')
    section_filters_list = [get_filter_parts(x) for x in task_filters]

    for section in settings.sections():
        parts = section.split(".")
        if not parts[0].startswith("task"):
            continue
        appendTask = True
        if section_filters_list:
            appendTask = False
            for section_filters in section_filters_list:
                if set(section_filters).issubset(set(parts)):
                    appendTask = True
                    break
        if appendTask:
            log.info("Parsing Task: %s", section)
            releaseTask = ReleaseTask(section, settings[section])
            releaseTask.add_to_substitutions_list(common_substitution_list)
            tasks.append(releaseTask)
        else:
            log.info("Skipping task: [%s] - not included by task filter(s): %s", section, section_filters_list)
    return tasks


def parse_config(configFile: str, task_filters: List[str]) -> List[ReleaseTask]:
    if not os.path.isfile(configFile):
        raise ReleaseTaskError("Not such file: {0}".format(configFile))
    settings = ConfigParser(interpolation=ExtendedInterpolation())
    settings.read(configFile)
    return parse_data(settings, task_filters)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(prog="Script to parse top level release config file")
    parser.add_argument("--config", dest="config", type=str, default=os.getenv("RELEASE_DESCRIPTION_FILE"),
                        help="Path to top level release config file")
    parser.add_argument("--task-filter", dest="task_filters", action='append',
                        help="Task include filters per section name in the --config file to match with " \
                        "the section name, e.g. 'offline', 'repository', ...")
    args = parser.parse_args(sys.argv[1:])

    assert os.path.isfile(args.config), "Not a valid file: {0}".format(args.config)
    parse_config(args.config, args.task_filters)