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
|
#!/usr/bin/python3
# SPDX-License-Identifier: GPL-2.0+
import argparse
import collections
import contextlib
import datetime
import lzma
import os.path
import sqlite3
import subprocess
import time
from common import decompress_stream, yield_lines, yield_chunks
def scan_log_status(filelike):
it = yield_chunks(filelike)
it = decompress_stream(it, lzma.LZMADecompressor())
it = yield_lines(it)
last_lines = collections.deque(it, 25)
status = [l.split(b':', 1)[1].strip()
for l in last_lines if l.startswith(b"Status:")]
if status:
return status[0].decode("ascii")
return "unknown"
def do_build(source, version, architecture, server):
now = datetime.datetime.utcnow().replace(microsecond=0)
logtarget = "%s_%s_%s_%s.log.xz" % (source, version, architecture,
now.strftime("%Y%m%d%H%M%S"))
cmdline = ["ssh", server, "sh", "/dev/stdin", architecture,
"%s_%s" % (source, version)]
with open(os.path.join("logs", logtarget), "w+b") as output:
with open("build.sh", "rb") as instructions:
code = subprocess.call(cmdline, stdin=instructions, stdout=output)
output.seek(0)
status = scan_log_status(output)
print("status %s code %d" % (status, code))
return (now, code == 0, logtarget, status == "given-back")
def main():
argp = argparse.ArgumentParser()
argp.add_argument("server", help="machine to build on")
args = argp.parse_args()
db = sqlite3.connect("db", detect_types=sqlite3.PARSE_DECLTYPES)
with contextlib.closing(db.cursor()) as cur:
cur.execute("""
SELECT d.source, d.version, d.architecture, r.rowid
FROM depstate AS d
JOIN buildrequests AS r
ON d.architecture = ifnull(r.architecture, d.architecture)
AND d.source = r.source
JOIN depcheck
ON d.architecture = depcheck.architecture
WHERE d.satisfiable = 1 AND depcheck.giveback = 0
ORDER BY r.priority DESC, random() LIMIT 1;""")
row = cur.fetchone()
if not row:
cur.execute("""
SELECT source, version, depstate.architecture, NULL
FROM depstate JOIN depcheck
ON depstate.architecture = depcheck.architecture
WHERE satisfiable = 1 AND giveback = 0
ORDER BY random() LIMIT 1;""")
row = cur.fetchone()
if not row:
print("no package satisfiable")
time.sleep(60)
return
source, version, architecture, requestid = row
print("building %s_%s for %s%s" %
(source, version, architecture,
"" if requestid is None else " (request %d)" % requestid))
timestamp, success, filename, giveback = \
do_build(source, version, architecture, args.server)
with contextlib.closing(db.cursor()) as cur:
cur.execute("INSERT INTO builds (source, version, architecture, success, starttime, filename) VALUES (?, ?, ?, ?, ?, ?);",
(source, version, architecture, success, timestamp,
filename))
if requestid is not None:
cur.execute("DELETE FROM buildrequests WHERE rowid = ?;",
(requestid,))
if giveback:
cur.execute("UPDATE depcheck SET giveback = 1 WHERE architecture = ?;",
(architecture,))
db.commit()
if __name__ == "__main__":
main()
|