summaryrefslogtreecommitdiffstats
path: root/ansible_collections/hetzner/hcloud/scripts/vendor.py
blob: b55a66577b706da13d4dc7a08cea9104bc246db1 (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
#!/usr/bin/env python3

"""
Fetch and bundles the hcloud package inside the collection.

Fetch the desired version `HCLOUD_VERSION` from https://github.com/hetznercloud/hcloud-python
`HCLOUD_SOURCE_URL` using git, apply some code modifications to comply with ansible,
move the modified files at the vendor location `HCLOUD_VENDOR_PATH`.
"""

from __future__ import annotations

import logging
import re
from argparse import ArgumentParser
from pathlib import Path
from shutil import move, rmtree
from subprocess import check_call
from tempfile import TemporaryDirectory
from textwrap import dedent

logger = logging.getLogger("vendor")

HCLOUD_SOURCE_URL = "https://github.com/hetznercloud/hcloud-python"
HCLOUD_VERSION = "v1.33.2"
HCLOUD_VENDOR_PATH = "plugins/module_utils/vendor/hcloud"


def apply_code_modifications(source_path: Path):
    # The ansible galaxy-importer consider __version___.py to be an invalid filename in module_utils/
    # Move the __version__.py file to _version.py
    move(source_path / "__version__.py", source_path / "_version.py")

    for file in source_path.rglob("*.py"):
        content = file.read_text()
        content_orig = content

        # Move the __version__.py file to _version.py
        content = re.sub(
            r"from .__version__ import VERSION",
            r"from ._version import VERSION",
            content,
        )

        # Wrap requests imports
        content = re.sub(
            r"import requests",
            dedent(
                r"""
                try:
                    import requests
                except ImportError:
                    requests = None
                """
            ).strip(),
            content,
        )

        # Wrap dateutil imports
        content = re.sub(
            r"from dateutil.parser import isoparse",
            dedent(
                r"""
                try:
                    from dateutil.parser import isoparse
                except ImportError:
                    isoparse = None
                """
            ).strip(),
            content,
        )

        # Remove requests.Response typings
        content = re.sub(
            r": requests\.Response",
            r"",
            content,
        )

        if content != content_orig:
            logger.info("Applied code modifications on %s", file)

        file.write_text(content)


def main(check: bool = False) -> int:
    with TemporaryDirectory() as tmp_dir:
        tmp_dir_path = Path(tmp_dir)
        logger.info("Created temporary directory %s", tmp_dir_path)

        check_call(["git", "clone", "--depth=1", "--branch", HCLOUD_VERSION, HCLOUD_SOURCE_URL, tmp_dir_path])
        logger.info("Cloned the source files in %s", tmp_dir_path)

        apply_code_modifications(tmp_dir_path / "hcloud")
        logger.info("Applied code modifications on the source files")

        rmtree(HCLOUD_VENDOR_PATH)
        move(tmp_dir_path / "hcloud", HCLOUD_VENDOR_PATH)
        logger.info("Bundled the modified sources files in the collection")

    if check:
        check_call(["git", "diff", "--exit-code", "--", HCLOUD_VENDOR_PATH])

    return 0


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(levelname)-8s: %(message)s")

    parser = ArgumentParser()
    parser.add_argument("--check", action="store_true", default=False)
    args = parser.parse_args()

    raise SystemExit(main(check=args.check))