build.py 4.28 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
72
        if additional_content is not None:
            os.chdir(workdir)
Robin Sonnabend's avatar
Robin Sonnabend committed
73
            print(os.listdir())
Robin Sonnabend's avatar
Robin Sonnabend committed
74
            for content in additional_content:
75
                os.chdir(content["target_dir"])
Robin Sonnabend's avatar
Robin Sonnabend committed
76
                print(os.listdir())
Robin Sonnabend's avatar
Robin Sonnabend committed
77
78
79
80
81
82
83
                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"]])

84
85
86
87
88
89
90
91
92
93
94
95
96

        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])

97
        command = ["apt-get", "build-dep", "-y", name]
98
99
        run_checked(command)

100
101
102
103
104
105
106
107
        command = ["debuild", "-b", "-uc", "-us"]
        run_checked(command)

        deb_packages =  [
            filename
            for filename in os.listdir(tempdir)
            if filename.endswith(".deb")
        ]
108
109
110
111
        for filename in os.listdir(tempdir):
            if not filename.endswith(".deb"):
                continue
            shutil.move(os.path.join(tempdir, filename), package_dir)
112
113


114
115
def main():
    repo_dir = os.getcwd()
116
117
118
119
120
121
122
123
124
125
    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

126
127
128
    package_dir = "packages"
    os.makedirs(package_dir, exist_ok=True)
    
129
    for package in config["packages"]:
130
        build_package(repo_dir=repo_dir, package_dir=package_dir, **package)
Robin Sonnabend's avatar
Robin Sonnabend committed
131
        os.chdir(repo_dir)
132

Robin Sonnabend's avatar
Robin Sonnabend committed
133
    print(os.listdir(package_dir))
134
135
136
137

if __name__ == "__main__":
    main()