summarylogtreecommitdiffstats
path: root/update.py
blob: 232d688fccf81c0dc3c65667bfdcb8c1124c0a33 (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
#!/usr/bin/env python3
#                  _       _
#  _   _ _ __   __| | __ _| |_ ___   _ __  _   _
# | | | | '_ \ / _` |/ _` | __/ _ \ | '_ \| | | |
# | |_| | |_) | (_| | (_| | ||  __/_| |_) | |_| |
#  \__,_| .__/ \__,_|\__,_|\__\___(_) .__/ \__, |
#       |_|                         |_|    |___/
#

## Make sure that we catch this error fast
try:
    import requests
except ImportError:
    import sys

    sys.exit("Please install requests: pacman -S python-requests")


## Check the arguments before iterpreting the rest of the script
## and before sourcing other stuff.
import argparse
from pathlib import Path

parser = argparse.ArgumentParser(description="Update AUR package version and checksum.")
parser.add_argument("new_version", help="New version like 1.0.0")
parser.add_argument(
    "--dir",
    default=Path(__file__).parent,
    help="Directory containing PKGBUILD and .SRCINFO (default: script dir)",
)
args = parser.parse_args()

import hashlib
import re
import sys


class SourceInfoReader:
    def __init__(self, root: Path):
        with (root / ".SRCINFO").open("r") as f:
            self.content = f.read()

    def get(self, field: str) -> str:
        match = re.search(rf"(?m)^\s*{re.escape(field)}\s*=\s*(.+?)\s*$", self.content)
        if not match:
            raise KeyError(f"{field} not found")
        return match.group(1).strip()


def sha256_of_remote_resource(remote_url: str) -> str:
    request = requests.get(remote_url, timeout=30)
    request.raise_for_status()
    return hashlib.sha256(request.content).hexdigest()


def update_file(path: Path, substitutions: list[tuple[re.Pattern, str]]):
    text = path.read_text(encoding="utf-8")
    for pattern, replacement in substitutions:
        text = pattern.sub(replacement, text)
    path.write_text(text, encoding="utf-8")


def main():
    root = Path(args.dir)
    sir = SourceInfoReader(root)
    package = sir.get("pkgname")
    repository = sir.get("url")

    package_version_line = re.compile(r"(?m)^(?P<prefix>\s*pkgver\s*=\s*)[^\n]+$")
    new_version = args.new_version.strip()
    tar_name = f"{package}-{new_version}.tar.gz"
    tar_url = f"{repository}/archive/refs/tags/v{new_version}.tar.gz"

    print(f"Fetching {tar_url} ...", file=sys.stderr)
    new_sha = sha256_of_remote_resource(tar_url)
    print(f"SHA256: {new_sha}", file=sys.stderr)

    pkgbuild = root / "PKGBUILD"
    assert pkgbuild.exists()
    update_file(
        pkgbuild,
        [
            (package_version_line, rf"\g<prefix>{new_version}"),
            (
                re.compile(r"(?ms)^(?P<prefix>sha256sums\s*=\s*)\([^)]+\)"),
                r"\g<prefix>('{}')".format(new_sha),
            ),
            (re.compile(rf"(?m){re.escape(package)}-\d+\.\d+\.\d+\.tar\.gz"), tar_name),
            (re.compile(r"(?m)/v\d+\.\d+\.\d+\.tar\.gz"), f"/v{new_version}.tar.gz"),
        ],
    )

    srcinfo = root / ".SRCINFO"
    assert srcinfo.exists()
    update_file(
        srcinfo,
        [
            (package_version_line, rf"\g<prefix>{new_version}"),
            (
                re.compile(r"(?m)^(?P<prefix>\s*sha256sums\s*=\s*)[^\n]+$"),
                rf"\g<prefix>{new_sha}",
            ),
            (
                re.compile(rf"(?m)({re.escape(package)}-)\d+\.\d+\.\d+(\.tar\.gz)"),
                rf"\g<1>{new_version}\2",
            ),
            (
                re.compile(r"(?m)(/refs/tags/)v\d+\.\d+\.\d+(\.tar\.gz)"),
                rf"\1v{new_version}\2",
            ),
        ],
    )

    print("Done.", file=sys.stderr)


if __name__ == "__main__":
    main()