build.py 4.54 KB
Newer Older
1
2
#!/usr/bin/env python3

3
4
5
import locale
locale.setlocale(locale.LC_ALL, "en_US.UTF-8")

6
7
import os
import subprocess as sp
8
import re
9
import shutil
10
11
12
13
14
15
16
17
18
import tempfile
import yaml


def load_config():
    with open("packages.yml", "r") as config_file:
        return yaml.load(config_file)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PKG_NAME_PATTERN = r"[a-zA-Z0-9.+-]+"
EPOCH_PATTERN = r"[0-9]+:"
UPSTREAM_VERSION_PATTERN = r"[a-zA-Z0-9.+-:]+"
DEBIAN_VERSION_PATTERN = r"[a-zA-Z0-9.+~]+"
EXTRACT_PATTERN = (r"extracting (?P<name>{pkg_name}) in (?P<dir>{pkg_name}-{version})"
    .format(pkg_name=PKG_NAME_PATTERN, version=UPSTREAM_VERSION_PATTERN))


def run_checked(command, **kwargs):
    try:
        return sp.run(
            command, check=True,
            stdout=sp.PIPE, stderr=sp.PIPE, universal_newlines=True,
            **kwargs)
    except sp.CalledProcessError as error:
Robin Sonnabend's avatar
Robin Sonnabend committed
34
        print(error.stdout)
35
36
        print(error.stderr)
        raise
Robin Sonnabend's avatar
Robin Sonnabend committed
37
38
39
40
41
42
43


def apply_patches(abs_patch_dir):
    for patch in sorted(os.listdir(abs_patch_dir)):
        patch_file = os.path.join(abs_patch_dir, patch)
        run_checked(["quilt", "import", patch_file])

44

45
def build_package(repo_dir, package_dir, name,
Robin Sonnabend's avatar
Robin Sonnabend committed
46
        patch_dir=None, version=None, changelog=None, additional_content=None):
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    with tempfile.TemporaryDirectory(dir=os.path.abspath(".")) as tempdir:
        os.chdir(tempdir)
        result = run_checked(["apt-get", "source", name])
        source_dir_candidates = [
            line for line in result.stdout.splitlines() if "extracting" in line]
        if len(source_dir_candidates) != 1:
            raise ValueError("Got inconclusive candidate directories: {}".format(
                source_dir_candidates))
        source_dir_match = re.search(EXTRACT_PATTERN, source_dir_candidates[0])
        if source_dir_match is None:
            raise ValueError("Cannot get extraction directory from {}".format(
                source_dir_candidates[0]))
        pkg_dir = source_dir_match.group("dir")
        pkg_name = source_dir_match.group("name")
        if pkg_name != name:
            raise ValueError(
                "Extracted package {} is not expected package {}".format(
                    pkg_name, name))

Robin Sonnabend's avatar
Robin Sonnabend committed
66
67
68
        workdir = os.path.join(tempdir, pkg_dir)
        os.chdir(workdir)

Robin Sonnabend's avatar
Robin Sonnabend committed
69
70
        print(os.listdir())

Robin Sonnabend's avatar
Robin Sonnabend committed
71
        if additional_content is not None:
Robin Sonnabend's avatar
Robin Sonnabend committed
72
            print("applying additional content")
Robin Sonnabend's avatar
Robin Sonnabend committed
73
            os.chdir(workdir)
Robin Sonnabend's avatar
Robin Sonnabend committed
74
            print(os.listdir())
Robin Sonnabend's avatar
Robin Sonnabend committed
75
            for content in additional_content:
Robin Sonnabend's avatar
Robin Sonnabend committed
76
                print("applying {}".format(content))
77
                os.chdir(content["target_dir"])
Robin Sonnabend's avatar
Robin Sonnabend committed
78
                print(os.listdir())
Robin Sonnabend's avatar
Robin Sonnabend committed
79
80
81
82
83
84
                if "patch_dir" in content:
                    abs_patch_dir = os.path.join(
                        repo_dir, content["patch_dir"])
                    apply_patches(abs_patch_dir)
                elif "git_url" in content:
                    run_checked(["git", "clone", content["git_url"]])
Robin Sonnabend's avatar
Robin Sonnabend committed
85
86
87
88
                else:
                    print(
                        "Unknown kind of additional content: {}".format(
                            content))
Robin Sonnabend's avatar
Robin Sonnabend committed
89

90
91
92
93
94
95
96
97
98
99
100
101
102

        command = ["debchange", "--preserve"]
        if version is None:
            command.append("--nmu")
        else:
            command.extend(["--newversion", version])
        def _get_log_entries():
            if changelog:
                yield changelog
            yield "Non-maintainer upload"
        for entry in _get_log_entries():
            run_checked(command + [entry])

103
        command = ["apt-get", "build-dep", "-y", name]
104
105
        run_checked(command)

106
107
108
109
110
111
112
113
        command = ["debuild", "-b", "-uc", "-us"]
        run_checked(command)

        deb_packages =  [
            filename
            for filename in os.listdir(tempdir)
            if filename.endswith(".deb")
        ]
114
115
116
117
        for filename in os.listdir(tempdir):
            if not filename.endswith(".deb"):
                continue
            shutil.move(os.path.join(tempdir, filename), package_dir)
118
119


120
121
def main():
    repo_dir = os.getcwd()
122
123
124
125
126
127
128
129
130
131
    config = load_config()
    maintainer = config.get("maintainer", None)
    if maintainer is not None:
        name = maintainer.get("name", None)
        mail = maintainer.get("mail", None)
        if name:
            os.environ["DEBFULLNAME"] = name
        if mail:
            os.environ["DEBEMAIL"] = mail

132
133
134
    package_dir = "packages"
    os.makedirs(package_dir, exist_ok=True)
    
135
    for package in config["packages"]:
136
        build_package(repo_dir=repo_dir, package_dir=package_dir, **package)
Robin Sonnabend's avatar
Robin Sonnabend committed
137
        os.chdir(repo_dir)
138

Robin Sonnabend's avatar
Robin Sonnabend committed
139
    print(os.listdir(package_dir))
140
141
142
143

if __name__ == "__main__":
    main()