glory_cli/compile/
server.rs

1use std::sync::Arc;
2
3use super::ChangeSet;
4use crate::{
5    config::Project,
6    ext::anyhow::{Context, Result},
7    ext::sync::{wait_interruptible, CommandResult},
8    logger::GRAY,
9    signal::{Interrupt, Outcome, Product},
10};
11use tokio::{
12    process::{Child, Command},
13    task::JoinHandle,
14};
15
16pub async fn server(proj: &Arc<Project>, changes: &ChangeSet) -> JoinHandle<Result<Outcome<Product>>> {
17    let proj = proj.clone();
18    let changes = changes.clone();
19
20    tokio::spawn(async move {
21        if !changes.need_server_build() {
22            return Ok(Outcome::Success(Product::None));
23        }
24
25        let (envs, line, process) = server_cargo_process("build", &proj)?;
26
27        match wait_interruptible("Cargo", process, Interrupt::subscribe_any()).await? {
28            CommandResult::Success(_) => {
29                log::debug!("Cargo envs: {}", GRAY.paint(envs));
30                log::info!("Cargo finished {}", GRAY.paint(line));
31
32                let changed = proj.site.did_external_file_change(&proj.bin.exe_file).await.dot()?;
33                if changed {
34                    log::debug!("Cargo server bin changed");
35                    Ok(Outcome::Success(Product::Server))
36                } else {
37                    log::debug!("Cargo server bin unchanged");
38                    Ok(Outcome::Success(Product::None))
39                }
40            }
41            CommandResult::Interrupted => Ok(Outcome::Stopped),
42            CommandResult::Failure(_) => Ok(Outcome::Failed),
43        }
44    })
45}
46
47pub fn server_cargo_process(cmd: &str, proj: &Project) -> Result<(String, String, Child)> {
48    let mut command = Command::new(proj.bin.cargo_command.as_deref().unwrap_or("cargo"));
49    let (envs, line) = build_cargo_server_cmd(cmd, proj, &mut command);
50    Ok((envs, line, command.spawn()?))
51}
52
53pub fn build_cargo_server_cmd(cmd: &str, proj: &Project, command: &mut Command) -> (String, String) {
54    let mut args = vec![cmd.to_string(), format!("--package={}", proj.bin.name.as_str())];
55    if cmd != "test" {
56        args.push(format!("--bin={}", proj.bin.target))
57    }
58    args.push(format!("--target-dir={}", proj.bin.target_dir.as_deref().unwrap_or("target/server")));
59    if let Some(triple) = &proj.bin.target_triple {
60        args.push(format!("--target={triple}"));
61    }
62
63    if !proj.bin.default_features {
64        args.push("--no-default-features".to_string());
65    }
66
67    if !proj.bin.features.is_empty() {
68        args.push(format!("--features={}", proj.bin.features.join(",")));
69    }
70
71    proj.bin.profile.add_to_args(&mut args);
72
73    let envs = proj.to_envs();
74
75    let envs_str = envs.iter().map(|(name, val)| format!("{name}={val}")).collect::<Vec<_>>().join(" ");
76
77    command.args(&args).envs(envs);
78    let line = format!("cargo {}", args.join(" "));
79    println!("Build server: {}", line);
80    (envs_str, line)
81}