summaryrefslogtreecommitdiffstats
path: root/packaging/windows/fetch-msys2-installer.py
blob: e30e7205c8d843a38ff4c80daaebb8ebd145effd (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
#!/usr/bin/env python

'''Fetch the MSYS2 installer.'''

from __future__ import annotations

import hashlib
import json
import shutil
import sys

from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Final
from urllib.request import Request, urlopen

REPO: Final = 'msys2/msys2-installer'


def get_latest_release() -> tuple[str, str]:
    '''Get the latest release for the repo.'''
    REQUEST: Final = Request(
        url=f'https://api.github.com/repos/{REPO}/releases',
        headers={
            'Accept': 'application/vnd.github+json',
            'X-GitHub-API-Version': '2022-11-28',
        },
        method='GET',
    )

    print('>>> Fetching release list')

    with urlopen(REQUEST, timeout=15) as response:
        if response.status != 200:
            print(f'!!! Failed to fetch release list, status={response.status}')
            sys.exit(1)

        data = json.load(response)

    data = list(filter(lambda x: x['name'] != 'Nightly Installer Build', data))

    name = data[0]['name']
    version = data[0]['tag_name'].replace('-', '')

    return name, version


def fetch_release_asset(tmpdir: Path, name: str, file: str) -> Path:
    '''Fetch a specific release asset.'''
    REQUEST: Final = Request(
        url=f'https://github.com/{REPO}/releases/download/{name}/{file}',
        method='GET',
    )
    TARGET: Final = tmpdir / file

    print(f'>>> Downloading {file}')

    with urlopen(REQUEST, timeout=15) as response:
        if response.status != 200:
            print(f'!!! Failed to fetch {file}, status={response.status}')
            sys.exit(1)

        TARGET.write_bytes(response.read())

    return TARGET


def main() -> None:
    '''Core program logic.'''
    if len(sys.argv) != 2:
        print(f'{__file__} must be run with exactly one argument.')

    target = Path(sys.argv[1])
    tmp_target = target.with_name(f'.{target.name}.tmp')

    name, version = get_latest_release()

    with TemporaryDirectory() as tmpdir:
        tmppath = Path(tmpdir)

        installer = fetch_release_asset(tmppath, name, f'msys2-base-x86_64-{version}.tar.zst')
        checksums = fetch_release_asset(tmppath, name, f'msys2-base-x86_64-{version}.tar.zst.sha256')

        print('>>> Verifying SHA256 checksum')
        expected_checksum = checksums.read_text().partition(' ')[0].casefold()
        actual_checksum = hashlib.sha256(installer.read_bytes()).hexdigest().casefold()

        if expected_checksum != actual_checksum:
            print('!!! Checksum mismatch')
            print(f'!!! Expected: {expected_checksum}')
            print(f'!!! Actual:   {actual_checksum}')
            sys.exit(1)

        print(f'>>> Copying to {target}')

        shutil.copy(installer, tmp_target)
        tmp_target.replace(target)


if __name__ == '__main__':
    main()