Author: Kevin Schoon [me@kevinschoon.com]
Hash: 901e72e311ad1a63e75c91ce26c9a6f75c628dc1
Timestamp: Fri, 03 Nov 2023 18:40:23 +0000 (6 months ago)

+131 -0 +/-3 browse
hack together a build system prototype
hack together a build system prototype

This adds an extremely simple build runner prototype with Python and the
jsonnet C++ config system. Will re-write in rust once I establish the pattern
I want to use. In the mean time I want a very simple system for running "CI"
style jobs on the "production host".
1diff --git a/Moonbuild b/Moonbuild
2new file mode 100644
3index 0000000..9a1fdf6
4--- /dev/null
5+++ b/Moonbuild
6 @@ -0,0 +1,57 @@
7+ /* vim: set ft=jsonnet:
8+ NOTE: This the the build script for a CI system that doesn't yet exist!
9+ It can however be ran via a script manually: crescent-build/hack/build-system .
10+ */
11+
12+ local test_targets = [
13+ 'crescent_api',
14+ 'crescent_config',
15+ 'crescent_database',
16+ 'crescent_git',
17+ 'crescent_rpc',
18+ 'crescent_scheduler',
19+ 'crescent_mail',
20+ 'crescent_build',
21+ 'crescent_xmpp',
22+ ];
23+
24+ {
25+ jobs: [
26+ {
27+ name: 'tests',
28+ steps: [
29+ {
30+ name: 'Test: ' + name,
31+ shell: '/bin/sh',
32+ input: 'cargo test -p %s' % name,
33+ }
34+ for name in test_targets
35+ ],
36+ dependencies: ["clippy"]
37+ },
38+ {
39+ name: 'clippy',
40+ steps: [
41+ {
42+ name: 'Clippy: ' + name,
43+ shell: '/bin/sh',
44+ input: 'cargo clippy -p %s' % name,
45+ }
46+ for name in test_targets
47+ ],
48+ },
49+ {
50+ name: 'packaging',
51+ steps: [
52+ {
53+ name: 'Arch git',
54+ shell: '/bin/sh',
55+ input: |||
56+ cd packaging/arch/crescent-git
57+ makepkg -fc --skippgpcheck
58+ |||,
59+ },
60+ ],
61+ },
62+ ],
63+ }
64 diff --git a/clippy.toml b/clippy.toml
65new file mode 100644
66index 0000000..e034672
67--- /dev/null
68+++ b/clippy.toml
69 @@ -0,0 +1 @@
70+ msrv = "1.65.0"
71 diff --git a/crescent-build/hack/build-system b/crescent-build/hack/build-system
72new file mode 100755
73index 0000000..c617e2f
74--- /dev/null
75+++ b/crescent-build/hack/build-system
76 @@ -0,0 +1,73 @@
77+ #!/usr/bin/env python
78+
79+ import logging
80+ import sys
81+ import argparse
82+ import json
83+ import subprocess
84+ from graphlib import TopologicalSorter
85+ from collections import namedtuple
86+ from os import path
87+
88+ logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.DEBUG)
89+
90+
91+ Job = namedtuple("Job", ["name", "steps", "dependencies"])
92+ Step = namedtuple("Step", ["name", "command"])
93+
94+
95+ def _load_step(json_input):
96+ name = json_input["name"]
97+ if "shell" in json_input:
98+ shell = json_input["shell"]
99+ else:
100+ shell = "/bin/sh"
101+ input = json_input["input"]
102+ command = [shell, "-c", "set -xe;\n" + input]
103+ return Step(name, command)
104+
105+
106+ def _load_job(json_input):
107+ name = json_input["name"]
108+ if "dependencies" in json_input:
109+ dependencies = json_input["dependencies"]
110+ else:
111+ dependencies = []
112+ return Job(name, [_load_step(step) for step in json_input["steps"]], dependencies)
113+
114+
115+ def _invoke_job(job):
116+ for step in job.steps:
117+ logging.info(f"running step: {step.name}")
118+ subprocess.check_call(step.command)
119+
120+
121+ def _run_build_system(script_path):
122+ if path.isdir(script_path):
123+ script_path = path.join(script_path, "Moonbuild")
124+ output = subprocess.check_output(["jsonnet", script_path])
125+ config = json.loads(output)
126+ graph = dict()
127+ jobs_by_name = dict()
128+ jobs = [_load_job(job) for job in config["jobs"]]
129+ for job in jobs:
130+ graph.update({job.name: set(job.dependencies)})
131+ jobs_by_name[job.name] = job
132+ ts = TopologicalSorter(graph)
133+ for entry in ts.static_order():
134+ job = jobs_by_name[entry]
135+ logging.info(f"running job: {job.name}")
136+ _invoke_job(job)
137+
138+
139+ def main():
140+ parser = argparse.ArgumentParser("build-system")
141+ parser.add_argument(
142+ "BUILD_DIR", help="path to a directory containg a Moonbuild script"
143+ )
144+ args = parser.parse_args()
145+ _run_build_system(args.BUILD_DIR)
146+
147+
148+ if __name__ == "__main__":
149+ main()