1use core::fmt;
2use std::{
3 collections::HashSet,
4 io::{Error, ErrorKind},
5 process::{Child, Command},
6};
7
8use libc::kill;
9
10#[derive(Default)]
11pub struct X11docker {
12 arguments: Option<HashSet<X11dockerOption>>,
13 proc_child: Option<Child>,
14}
15
16#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
17pub enum X11dockerOption {
18 Internet,
19 ImageName(String),
20 ContainerName(String),
21 Desktop,
23 Interactive,
24 Backend(String),
25 Rootless(bool),
26 Xc(String),
27 Xonly,
28 Alsa(String),
30 Clipboard(String),
31 Gpu(String),
32 Network(String),
33 Lang(String),
34 Printer(String),
35 Pulseaudio(String),
36 Webcam,
37 Home(String),
39 Share(String),
40 Auto,
42 Hostdisplay,
43 Xpra,
44 Xpra2,
45 XpraXwayland,
46 Xpra2Xwayland,
47 Nxagent,
48 Xephyr,
49 WestonXwayland,
50 Xorg,
51 Tty,
53 Xvfb,
54 Xwayland,
55 Xwin,
56 Runx,
57 Wayland,
59 Weston,
60 Kwin,
61 Hostwayland,
62 Border(String),
64 Dpi(String),
65 Fullscreen,
66 OutputCount(String),
67 Rotate(String),
68 Scale(String),
69 Size(String),
70 Wm(String),
71 Xfishtank,
72 Checkwindow(String),
74 CleanXhost,
75 Composite(String),
76 Display(String),
77 Keymap(String),
78 Vt(String),
79 Westonini(String),
80 Xhost(String),
81 Xoverip(String),
82 Xauth(String),
83 Xtest(String),
84 GroupAdd(String),
86 Hostuser(String),
87 Password(String),
88 Sudouser(String),
89 User(String),
90 CapDefault,
92 Ipc(String),
93 Limit(String),
94 Newprivileges(String),
95 Dbus(String),
97 Hostdbus,
98 Init(String),
99 Sharecgroup,
100 Env(String),
102 Name(String),
103 NoEntrypoint,
104 NoSetup,
105 Runtime(String),
106 Shell(String),
107 Snap,
108 Stdin,
109 Workdir(String),
110 Runasroot(String),
112 Runasuser(String),
113 Runfromhost(String),
114 Build(String),
116 Cachebasedir(String),
117 Homebasedir(String),
118 Fallback(String),
119 Launcher,
120 Mobyvm,
121 Preset(String),
122 Printenv(String),
124 Printid(String),
125 Printinfofile(String),
126 Printpid1(String),
127 Debug,
129 Printcheck,
130 Quiet,
131 Verbose,
132 Cleanup,
134 Install,
136 Update(String),
137 UpdateMaster(String),
138 Remove,
139 RemoveOldprefix,
140}
141
142impl X11docker {
143 pub fn arguments(mut self, args: HashSet<X11dockerOption>) -> Self {
148 self.arguments = Some(args);
149 self
150 }
151
152 pub fn append_arguments(mut self, args: HashSet<X11dockerOption>) -> Self {
158 let mut arguments = self.arguments.unwrap_or_default();
159 arguments.extend(args);
160 self.arguments = Some(arguments);
161 self
162 }
163
164 pub fn internet(mut self) -> Self {
166 let mut args = self.arguments.unwrap_or_default();
167 args.insert(X11dockerOption::Internet);
168 self.arguments = Some(args);
169 self
170 }
171
172 pub fn image_name(mut self, name: &str) -> Self {
177 let mut args = self.arguments.unwrap_or_default();
178 args.insert(X11dockerOption::ImageName(name.to_string()));
179 self.arguments = Some(args);
180 self
181 }
182
183 pub fn container_name(mut self, name: &str) -> Self {
188 let mut args = self.arguments.unwrap_or_default();
189 args.insert(X11dockerOption::ContainerName(name.to_string()));
190 self.arguments = Some(args);
191 self
192 }
193
194 pub fn xpra(mut self) -> Self {
196 let mut args = self.arguments.unwrap_or_default();
197 args.insert(X11dockerOption::Xpra);
198 self.arguments = Some(args);
199 self
200 }
201
202 pub fn desktop(mut self) -> Self {
204 let mut args = self.arguments.unwrap_or_default();
205 args.insert(X11dockerOption::Desktop);
206 self.arguments = Some(args);
207 self
208 }
209
210 pub fn interactive(mut self) -> Self {
212 let mut args = self.arguments.unwrap_or_default();
213 args.insert(X11dockerOption::Interactive);
214 self.arguments = Some(args);
215 self
216 }
217
218 pub fn backend(mut self, backend: &str) -> Self {
223 let mut args = self.arguments.unwrap_or_default();
224 args.insert(X11dockerOption::Backend(backend.to_owned()));
225 self.arguments = Some(args);
226 self
227 }
228
229 pub fn rootless(mut self, value: bool) -> Self {
234 let mut args = self.arguments.unwrap_or_default();
235 args.insert(X11dockerOption::Rootless(value));
236 self.arguments = Some(args);
237 self
238 }
239
240 pub fn xc(mut self, value: &str) -> Self {
245 let mut args = self.arguments.unwrap_or_default();
246 args.insert(X11dockerOption::Xc(value.to_owned()));
247 self.arguments = Some(args);
248 self
249 }
250
251 pub fn xonly(mut self) -> Self {
253 let mut args = self.arguments.unwrap_or_default();
254 args.insert(X11dockerOption::Xonly);
255 self.arguments = Some(args);
256 self
257 }
258
259 pub fn exec(&mut self) -> std::io::Result<()> {
265 if self.arguments.is_none() {
266 return Err(Error::new(ErrorKind::NotFound, "No arguments provided."));
267 }
268 let args = self.arguments.clone().unwrap_or_default();
269 let argsvec = args.iter().map(|x| x.to_string()).collect::<Vec<String>>();
270
271 self.proc_child = Some(Command::new("x11docker").args(argsvec).spawn()?);
273 Ok(())
274 }
275
276 pub fn terminate(self) -> std::io::Result<()> {
282 match self.proc_child {
283 Some(mut child) => {
284 let id = child.id() as i32;
285 unsafe {
286 kill(id, libc::SIGTERM);
287 }
288 child.wait()?;
289 Ok(())
290 }
291 None => Err(std::io::Error::new(
292 std::io::ErrorKind::NotFound,
293 "No child found to terminate.",
294 )),
295 }
296 }
297}
298
299impl fmt::Display for X11dockerOption {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 match self {
302 X11dockerOption::Internet => write!(f, "-I"),
303 X11dockerOption::ImageName(i) => write!(f, "{i}"),
304 X11dockerOption::ContainerName(c) => write!(f, "--name={c}"),
305 X11dockerOption::Xpra => write!(f, "--xpra"),
306 X11dockerOption::Desktop => write!(f, "--desktop"),
307 X11dockerOption::Interactive => write!(f, "--interactive"),
308 X11dockerOption::Backend(b) => write!(f, "--backend={b}"),
309 X11dockerOption::Rootless(val) => {
310 write!(f, "--rootless={}", if *val { "yes" } else { "no" })
311 }
312 X11dockerOption::Xc(b) => write!(f, "--xc={b}"),
313 X11dockerOption::Xonly => write!(f, "--xonly"),
314 X11dockerOption::Alsa(a) => write!(f, "--alsa={a}"),
315 X11dockerOption::Clipboard(c) => write!(f, "--clipboard={c}"),
316 X11dockerOption::Gpu(g) => write!(f, "--gpu={g}"),
317 X11dockerOption::Network(n) => write!(f, "--network={n}"),
318 X11dockerOption::Lang(l) => write!(f, "--lang={l}"),
319 X11dockerOption::Printer(p) => write!(f, "--printer={p}"),
320 X11dockerOption::Pulseaudio(p) => write!(f, "--pulseaudio={p}"),
321 X11dockerOption::Webcam => write!(f, "--webcam"),
322 X11dockerOption::Home(h) => write!(f, "--home={h}"),
323 X11dockerOption::Share(s) => write!(f, "--share={s}"),
324 X11dockerOption::Auto => write!(f, "--auto"),
325 X11dockerOption::Hostdisplay => write!(f, "--hostdisplay"),
326 X11dockerOption::Xpra2 => write!(f, "--xpra2"),
327 X11dockerOption::XpraXwayland => write!(f, "--xpra-xwayland"),
328 X11dockerOption::Xpra2Xwayland => write!(f, "--xpra2-xwayland"),
329 X11dockerOption::Nxagent => write!(f, "--nxagent"),
330 X11dockerOption::Xephyr => write!(f, "--xephyr"),
331 X11dockerOption::WestonXwayland => write!(f, "--weston-xwayland"),
332 X11dockerOption::Xorg => write!(f, "--xorg"),
333 X11dockerOption::Tty => write!(f, "--tty"),
334 X11dockerOption::Xvfb => write!(f, "--xvfb"),
335 X11dockerOption::Xwayland => write!(f, "--xwayland"),
336 X11dockerOption::Xwin => write!(f, "--xwin"),
337 X11dockerOption::Runx => write!(f, "--runx"),
338 X11dockerOption::Wayland => write!(f, "--wayland"),
339 X11dockerOption::Weston => write!(f, "--weston"),
340 X11dockerOption::Kwin => write!(f, "--kwin"),
341 X11dockerOption::Hostwayland => write!(f, "--hostwayland"),
342 X11dockerOption::Border(b) => write!(f, "--border={b}"),
343 X11dockerOption::Dpi(d) => write!(f, "--dpi={d}"),
344 X11dockerOption::Fullscreen => write!(f, "--fullscreen"),
345 X11dockerOption::OutputCount(o) => write!(f, "--output-count={o}"),
346 X11dockerOption::Rotate(r) => write!(f, "--rotate={r}"),
347 X11dockerOption::Scale(s) => write!(f, "--scale={s}"),
348 X11dockerOption::Size(s) => write!(f, "--size={s}"),
349 X11dockerOption::Wm(w) => write!(f, "--wm={w}"),
350 X11dockerOption::Xfishtank => write!(f, "--xfishtank"),
351 X11dockerOption::Checkwindow(c) => write!(f, "--checkwindow={c}"),
352 X11dockerOption::CleanXhost => write!(f, "--clean-xhost"),
353 X11dockerOption::Composite(c) => write!(f, "--composite={c}"),
354 X11dockerOption::Display(d) => write!(f, "--display={d}"),
355 X11dockerOption::Keymap(k) => write!(f, "--keymap={k}"),
356 X11dockerOption::Vt(v) => write!(f, "--vt={v}"),
357 X11dockerOption::Westonini(w) => write!(f, "--westonini={w}"),
358 X11dockerOption::Xhost(x) => write!(f, "--xhost={x}"),
359 X11dockerOption::Xoverip(x) => write!(f, "--xoverip={x}"),
360 X11dockerOption::Xauth(x) => write!(f, "--xauth={x}"),
361 X11dockerOption::Xtest(x) => write!(f, "--xtest={x}"),
362 X11dockerOption::GroupAdd(g) => write!(f, "--group-add={g}"),
363 X11dockerOption::Hostuser(h) => write!(f, "--hostuser={h}"),
364 X11dockerOption::Password(p) => write!(f, "--password={p}"),
365 X11dockerOption::Sudouser(s) => write!(f, "--sudouser={s}"),
366 X11dockerOption::User(u) => write!(f, "--user={u}"),
367 X11dockerOption::CapDefault => write!(f, "--cap-default"),
368 X11dockerOption::Ipc(i) => write!(f, "--ipc={i}"),
369 X11dockerOption::Limit(l) => write!(f, "--limit={l}"),
370 X11dockerOption::Newprivileges(n) => write!(f, "--newprivileges={n}"),
371 X11dockerOption::Dbus(d) => write!(f, "--dbus={d}"),
372 X11dockerOption::Hostdbus => write!(f, "--hostdbus"),
373 X11dockerOption::Init(i) => write!(f, "--init={i}"),
374 X11dockerOption::Sharecgroup => write!(f, "--sharecgroup"),
375 X11dockerOption::Env(e) => write!(f, "--env={e}"),
376 X11dockerOption::Name(n) => write!(f, "--name={n}"),
377 X11dockerOption::NoEntrypoint => write!(f, "--no-entrypoint"),
378 X11dockerOption::NoSetup => write!(f, "--no-setup"),
379 X11dockerOption::Runtime(r) => write!(f, "--runtime={r}"),
380 X11dockerOption::Shell(s) => write!(f, "--shell={s}"),
381 X11dockerOption::Snap => write!(f, "--snap"),
382 X11dockerOption::Stdin => write!(f, "--stdin"),
383 X11dockerOption::Workdir(w) => write!(f, "--workdir={w}"),
384 X11dockerOption::Runasroot(r) => write!(f, "--runasroot={r}"),
385 X11dockerOption::Runasuser(r) => write!(f, "--runasuser={r}"),
386 X11dockerOption::Runfromhost(r) => write!(f, "--runfromhost={r}"),
387 X11dockerOption::Build(b) => write!(f, "--build={b}"),
388 X11dockerOption::Cachebasedir(c) => write!(f, "--cachebasedir={c}"),
389 X11dockerOption::Homebasedir(h) => write!(f, "--homebasedir={h}"),
390 X11dockerOption::Fallback(b) => write!(f, "--fallback={b}"),
391 X11dockerOption::Launcher => write!(f, "--launcher"),
392 X11dockerOption::Mobyvm => write!(f, "--mobyvm"),
393 X11dockerOption::Preset(p) => write!(f, "--preset={p}"),
394 X11dockerOption::Printenv(p) => write!(f, "--printenv={p}"),
395 X11dockerOption::Printid(p) => write!(f, "--printid={p}"),
396 X11dockerOption::Printinfofile(p) => write!(f, "--printinfofile={p}"),
397 X11dockerOption::Printpid1(p) => write!(f, "--printpid1={p}"),
398 X11dockerOption::Debug => write!(f, "--debug"),
399 X11dockerOption::Printcheck => write!(f, "--printcheck"),
400 X11dockerOption::Quiet => write!(f, "--quiet"),
401 X11dockerOption::Verbose => write!(f, "--verbose"),
402 X11dockerOption::Cleanup => write!(f, "--cleanup"),
403 X11dockerOption::Install => write!(f, "--install"),
404 X11dockerOption::Update(u) => write!(f, "--update={u}"),
405 X11dockerOption::UpdateMaster(u) => write!(f, "--update-master={u}"),
406 X11dockerOption::Remove => write!(f, "--remove"),
407 X11dockerOption::RemoveOldprefix => write!(f, "--remove-oldprefix"),
408 }
409 }
410}
411
412#[cfg(test)]
413mod test {
414 use super::*;
415
416 #[test]
417 fn test_default_x11docker() {
418 let x11docker = X11docker::default();
419 assert!(x11docker.arguments.is_none());
420 assert!(x11docker.proc_child.is_none());
421 }
422
423 #[test]
424 fn test_add_internet_argument() {
425 let x11docker = X11docker::default().internet();
426 assert!(x11docker.arguments.is_some());
427 let args = x11docker.arguments.unwrap();
428 assert!(args.contains(&X11dockerOption::Internet));
429 }
430
431 #[test]
432 fn test_add_image_name_argument() {
433 let x11docker = X11docker::default().image_name("test_image");
434 assert!(x11docker.arguments.is_some());
435 let args = x11docker.arguments.unwrap();
436 assert!(args.contains(&X11dockerOption::ImageName("test_image".to_string())));
437 }
438
439 #[test]
440 fn test_add_container_name_argument() {
441 let x11docker = X11docker::default().container_name("test_container");
442 assert!(x11docker.arguments.is_some());
443 let args = x11docker.arguments.unwrap();
444 assert!(args.contains(&X11dockerOption::ContainerName(
445 "test_container".to_string()
446 )));
447 }
448
449 #[test]
450 fn test_add_xpra_argument() {
451 let x11docker = X11docker::default().xpra();
452 assert!(x11docker.arguments.is_some());
453 let args = x11docker.arguments.unwrap();
454 assert!(args.contains(&X11dockerOption::Xpra));
455 }
456
457 #[test]
458 fn test_multiple_arguments() {
459 let x11docker = X11docker::default()
460 .internet()
461 .image_name("test_image")
462 .container_name("test_container")
463 .xpra();
464 assert!(x11docker.arguments.is_some());
465 let args = x11docker.arguments.unwrap();
466 assert!(args.contains(&X11dockerOption::Internet));
467 assert!(args.contains(&X11dockerOption::ImageName("test_image".to_string())));
468 assert!(args.contains(&X11dockerOption::ContainerName(
469 "test_container".to_string()
470 )));
471 assert!(args.contains(&X11dockerOption::Xpra));
472 }
473
474 #[test]
475 fn test_exec_without_arguments() {
476 let mut x11docker = X11docker::default();
477 let result = x11docker.exec();
478 assert!(result.is_err());
479 }
480}