1use std::{
2 error::Error,
3 process::Command,
4 sync::{
5 atomic::{AtomicBool, Ordering},
6 Arc,
7 },
8};
9
10use clap::Args;
11
12use crate::{cmd::run, net::kill_port};
13
14#[derive(Args, Debug, Clone)]
16pub struct ExportOptions {
17 #[arg(long, default_value = "slides.pdf")]
19 pub output: String,
20 #[arg(long, default_value_t = 3000)]
22 pub port: u16,
23}
24
25pub fn export(opts: ExportOptions) -> Result<(), Box<dyn Error>> {
27 if kill_port(opts.port).is_err() {
28 eprintln!("Warning, could not kill value on desired port")
29 }
30
31 let output = Command::new("npm")
32 .args(["install", "decktape@3.15.0"])
33 .current_dir(".")
34 .output()?;
35
36 if !output.status.success() {
37 eprintln!(
38 "Decktape installation failure: {}",
39 String::from_utf8_lossy(&output.stderr)
40 );
41 return Err("npm init failed".into());
42 }
43
44 let shutdown_flag = Arc::new(AtomicBool::new(false));
47 let run_flag = shutdown_flag.clone();
48
49 let run_handle = std::thread::spawn(move || run::run_with_shutdown(run_flag));
50
51 std::thread::sleep(std::time::Duration::from_millis(10000));
53
54 let addr = format!("http://localhost:{}", opts.port);
55
56 let export_output = Command::new("decktape")
58 .args(["automatic", &addr, &opts.output])
59 .output()?;
60
61 shutdown_flag.store(true, Ordering::SeqCst);
63 let _ = run_handle.join();
65
66 if !export_output.status.success() {
67 eprintln!(
68 "Decktape PDF export failure: {}",
69 String::from_utf8_lossy(&export_output.stderr)
70 );
71 return Err("npm init failed".into());
72 }
73
74 Ok(())
75}