build.py: handle the case of no satisfiable packages
[~helmut/crossqa.git] / build.py
1 #!/usr/bin/python3
2
3 import collections
4 import contextlib
5 import datetime
6 import lzma
7 import os.path
8 import sqlite3
9 import subprocess
10 import time
11
12 from common import decompress_stream, yield_lines, yield_chunks
13
14 def scan_log_status(filelike):
15     it = yield_chunks(filelike)
16     it = decompress_stream(it, lzma.LZMADecompressor())
17     it = yield_lines(it)
18     last_lines = collections.deque(it, 25)
19     status = [l.split(b':', 1)[1].strip()
20               for l in last_lines if l.startswith(b"Status:")]
21     if status:
22         return status[0].decode("ascii")
23     return "unknown"
24
25 def do_build(source, version, architecture):
26     now = datetime.datetime.utcnow()
27     logtarget = "%s_%s_%s_%s.log.xz" % (source, version, architecture,
28                                         now.strftime("%Y%m%d%H%M%S"))
29     cmdline = ["ssh", "gcc131", "sh", "/dev/stdin", architecture,
30                "%s_%s" % (source, version)]
31     with open(os.path.join("logs", logtarget), "w+b") as output:
32         with open("build.sh", "rb") as instructions:
33             code = subprocess.call(cmdline, stdin=instructions, stdout=output)
34         output.seek(0)
35         status = scan_log_status(output)
36         print("status %s code %d" % (status, code))
37     return (now, code == 0, logtarget, status == "given-back")
38
39 def main():
40     db = sqlite3.connect("db", detect_types=sqlite3.PARSE_DECLTYPES)
41     with contextlib.closing(db.cursor()) as cur:
42         cur.execute("SELECT source, version, depstate.architecture FROM depstate JOIN depcheck ON depstate.architecture = depcheck.architecture WHERE satisfiable = 1 AND giveback = 0 ORDER BY random() LIMIT 1;")
43         row = cur.fetchone()
44     if not row:
45         print("no package satisfiable")
46         time.sleep(60)
47         return
48     source, version, architecture = row
49     print("building %s_%s for %s" % (source, version, architecture))
50     timestamp, success, filename, giveback = do_build(source, version, architecture)
51     with contextlib.closing(db.cursor()) as cur:
52         cur.execute("INSERT INTO builds (source, version, architecture, success, starttime, filename) VALUES (?, ?, ?, ?, ?, ?);",
53                     (source, version, architecture, success, timestamp,
54                      filename))
55         if giveback:
56             cur.execute("UPDATE depcheck SET giveback = 1 WHERE architecture = ?;",
57                         (architecture,))
58     db.commit()
59
60 if __name__ == "__main__":
61     main()