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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
module incus
import core.str
import sys.process as p
import sys.fd as fd
import core.result_generic as rg
import core.convert as convert
export
fn validate_name(name: string): bool
fn project_ensure(project: string, verbose: bool): rg.Result[bool, string]
fn container_exists(project: string, name: string, verbose: bool): rg.Result[bool, string]
fn launch(project: string, name: string, image: string, profiles: [string]): rg.Result[bool, string]
fn device_add_disk(project: string, name: string, dev: string, src: string, dst: string): rg.Result[bool, string]
fn set_env_var(project: string, name: string, key: string, val: string): rg.Result[bool, string]
fn restart(project: string, name: string): rg.Result[bool, string]
end export
// Spawn a program with both stdout and stderr redirected to /dev/null in the
// child. Used for existence-check probes where the upstream command's error
// output would confuse the user (e.g., `incus project show foo` writing
// "Error: Project not found" to stderr when foo doesn't exist — we already
// know that, the missing-ness is the signal we wanted).
//
// Implementation: fork → in child, open /dev/null and dup2 it over fd 1/2,
// then exec the program. Returns the child PID; caller waits as usual.
fn process_run_silent(program: string, args: [string]): int
let pid: int = p.process_fork()
if pid < 0
return -1
end if
if pid == 0
let dev_null: int = fd.fd_open("/dev/null", fd.O_WRONLY(), 0)
if dev_null >= 0
let _o: int = fd.fd_dup2(dev_null, fd.STDOUT())
let _e: int = fd.fd_dup2(dev_null, fd.STDERR())
let _c: int = fd.fd_close(dev_null)
end if
let _x: int = p.process_run_exec(program, args)
p.exit_now(127)
end if
return pid
end process_run_silent
fn is_lower_alnum_or_hyphen(c: char): bool
if c >= 'a' and c <= 'z'
return true
end if
if c >= '0' and c <= '9'
return true
end if
if c == '-'
return true
end if
return false
end is_lower_alnum_or_hyphen
fn validate_name(name: string): bool
let n: int = str.length(name)
if n == 0
return false
end if
if n > 63
return false
end if
if name[0] == '-'
return false
end if
mut i: int = 0
while i < n
if not is_lower_alnum_or_hyphen(name[i])
return false
end if
i = i + 1
end while
return true
end validate_name
// Run `incus <args>`. Returns Ok(true) on exit 0, Err with a brief diagnostic
// on non-zero. Stderr inherits the parent terminal.
fn run_incus(args: [string]): rg.Result[bool, string]
let pid: int = p.process_run("incus", args)
if pid < 0
return @Result[bool, string].Err("failed to spawn 'incus' (is it installed?)")
end if
let exit: int = p.process_wait(pid)
if exit == 0
return @Result[bool, string].Ok(true)
end if
return @Result[bool, string].Err("incus exited with code " + convert.to_string(exit))
end run_incus
fn project_ensure(project: string, verbose: bool): rg.Result[bool, string]
// `incus project show <name>` exits 0 if it exists, non-0 otherwise.
// Quiet mode silences the YAML dump on success and the "Error:
// Project not found" stderr on failure; verbose mode passes through.
mut pid: int = -1
if verbose
pid = p.process_run("incus", ["project", "show", project])
else
pid = process_run_silent("incus", ["project", "show", project])
end if
let exit: int = p.process_wait(pid)
if exit == 0
return @Result[bool, string].Ok(true)
end if
// Create with all features disabled so the project is a pure container
// namespace and shares images/profiles/networks/storage with the default
// project. Without this, profiles like 'claude-share' that live in the
// default project would be invisible to containers in this project.
return run_incus([
"project", "create", project,
"-c", "features.images=false",
"-c", "features.profiles=false",
"-c", "features.networks=false",
"-c", "features.storage.volumes=false",
"-c", "features.storage.buckets=false"
])
end project_ensure
fn container_exists(project: string, name: string, verbose: bool): rg.Result[bool, string]
// `incus info --project <p> <name>` exits 0 if it exists.
// Quiet silences both info dump and error output; verbose passes through.
mut pid: int = -1
if verbose
pid = p.process_run("incus", ["info", "--project", project, name])
else
pid = process_run_silent("incus", ["info", "--project", project, name])
end if
let exit: int = p.process_wait(pid)
if exit == 0
return @Result[bool, string].Ok(true)
end if
return @Result[bool, string].Ok(false)
end container_exists
fn launch(project: string, name: string, image: string, profiles: [string]): rg.Result[bool, string]
let pn: int = profiles.length()
// argv shape: ["launch", "--project", project, ("--profile" P)*, image, name]
mut args: [string] = new [string](3 + 2 * pn + 2)
args[0] = "launch"
args[1] = "--project"
args[2] = project
mut i: int = 0
while i < pn
args[3 + i * 2] = "--profile"
args[3 + i * 2 + 1] = profiles[i]
i = i + 1
end while
args[3 + 2 * pn] = image
args[3 + 2 * pn + 1] = name
return run_incus(args)
end launch
fn device_add_disk(project: string, name: string, dev: string, src: string, dst: string): rg.Result[bool, string]
return run_incus([
"config", "device", "add",
"--project", project,
name,
dev,
"disk",
"source=" + src,
"path=" + dst
])
end device_add_disk
fn set_env_var(project: string, name: string, key: string, val: string): rg.Result[bool, string]
return run_incus([
"config", "set",
"--project", project,
name,
"environment." + key + "=" + val
])
end set_env_var
fn restart(project: string, name: string): rg.Result[bool, string]
return run_incus(["restart", "--project", project, name])
end restart
end module
|