summaryrefslogtreecommitdiffstats
path: root/scripts/osmo-depcheck/parse.py
blob: c6297d635f5955162179585828fe4e64233ff7c6 (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
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2018 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>

import sys
import fnmatch

# Same folder
import config


def error(line_i, message):
    """ Print a configure.ac error message with the line number.
        :param line_i: the zero based line counter """
    print("ERROR: configure.ac line " + str(line_i+1) + ": " + message)
    sys.exit(1)


def repository(library, version):
    """ Find the git repository that contains a certain library. Based on the
        information in config.py.

        :param library: the name as referenced in the PKG_CHECK_MODULES
                        statement. For example: "libosmoabis"
        :param version: for example "0.5.0"
        :returns: the repository name, e.g. "libosmo-abis" """
    for repo, libraries in config.repos.items():
        if library in libraries:
            print(" * " + library + ":" + version + " (part of " + repo + ")")
            return repo

    print(" * " + library + ":" + version)
    return library


def library_is_relevant(library):
    """ :returns: True when we would build the library in question from source,
                  False otherwise. """
    for pattern in config.relevant_library_patterns:
        if fnmatch.fnmatch(library, pattern):
            return True
    return False


def parse_condition(line):
    """ Find the PKG_CHECK_MODULES conditions in any line from a configure.ac.

        Example lines:
        PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore  >= 0.10.0)
        PKG_CHECK_MODULES(LIBSYSTEMD, libsystemd)

        :returns: * None when there's no condition in that line
                  * a string like "libosmocore  >= 0.1.0" """
    # Only look at PKG_CHECK_MODULES lines
    if "PKG_CHECK_MODULES" not in line:
        return

    # Extract the condition
    ret = line.split(",")[1].split(")")[0].strip()

    # Only look at Osmocom libraries
    library = ret.split(" ")[0]
    if library_is_relevant(library):
        return ret


def library_version(line_i, condition):
    """ Get the library and version strings from a condition.
        :param line_i: the zero based line counter
        :param condition: a condition like "libosmocore  >= 0.1.0" """
    # Split by space and remove empty list elements
    split = list(filter(None, condition.split(" ")))
    if len(split) != 3:
        error(line_i, "invalid condition format, expected something"
                      " like 'libosmocore >= 0.10.0' but got: '" +
                      condition + "'")
    library, operator, version = split

    # Right operator
    if operator == ">=":
        return (library, version)

    # Wrong operator
    error(line_i, "invalid operator, expected '>=' but got: '" +
                  operator + "'")


def configure_ac(gitdir, repo):
    """ Parse the PKG_CHECK_MODULES statements of a configure.ac file.

        :param gitdir: parent folder of all locally cloned git repositories
        :param repo: the repository to look at (e.g. "osmo-bts")
        :returns: a dictionary like the following:
                  {"libosmocore": "0.11.0",
                   "libosmo-abis": "0.5.0"} """
    # Read configure.ac
    path = gitdir + "/" + repo + "/configure.ac"
    with open(path) as handle:
        lines = handle.readlines()

    # Parse the file into ret
    ret = {}
    for i in range(0, len(lines)):
        # Parse the line
        condition = parse_condition(lines[i])
        if not condition:
            continue
        (library, version) = library_version(i, condition)

        # Add to ret (with duplicate check)
        repo_dependency = repository(library, version)
        if repo_dependency in ret and version != ret[repo_dependency]:
            error(i, "found multiple PKG_CHECK_MODULES statements for " +
                     repo_dependency + ".git, and they have different"
                     " versions!")
        ret[repo_dependency] = version
    return ret