1 //! Runner (runtime) detection for a working directory.
2
3 use crate::{error::DeployError, report::Reporter};
4 use smbcloud_model::runner::Runner;
5 use smbcloud_utils::config::Config;
6 use std::{env::current_dir, path::Path};
7
8 /// Detect which runtime this project uses: Next.js, Rails, Rust, Swift, or a
9 /// build-less static site.
10 ///
11 /// The detection itself lives in [`Runner::from`]; this wraps it with progress
12 /// reporting and the monorepo short-circuit. It owns no spinner and prints
13 /// nothing directly. All progress goes through `reporter`, so the same call
14 /// works under the CLI, in CI, or on the server.
15 pub fn detect_runner(config: &Config, reporter: &dyn Reporter) -> Result<Runner, DeployError> {
16 reporter.step_start("Checking runner");
17
18 // A monorepo declares its runner explicitly and defers per-app detection to
19 // the selected `[[projects]]` entry.
20 if config.project.runner == Runner::Monorepo && config.projects.is_some() {
21 reporter.step_done("Monorepo universal runner");
22 return Ok(Runner::Monorepo);
23 }
24
25 let path = current_dir().map_err(|_| {
26 reporter.step_fail("Could not read the current directory.");
27 DeployError::RunnerNotDetected
28 })?;
29
30 let runner = Runner::from(&path).map_err(|_| {
31 reporter.step_fail("Could not detect a runner.");
32 DeployError::RunnerNotDetected
33 })?;
34
35 reporter.step_done(label_for(runner));
36 Ok(runner)
37 }
38
39 /// Human-readable confirmation line for a detected runner.
40 fn label_for(runner: Runner) -> &'static str {
41 match runner {
42 Runner::Monorepo => "Monorepo universal runner",
43 Runner::NodeJs => "Node.js runner detected",
44 Runner::Static => "Static site, no build step required",
45 Runner::Ruby if Path::new("Gemfile").exists() => "Ruby runner with Rails app detected",
46 Runner::Swift if Path::new("Package.swift").exists() => {
47 "Swift runner with Vapor app detected"
48 }
49 Runner::Rust if Path::new("Cargo.toml").exists() => {
50 "Rust runner with Cargo project detected"
51 }
52 _ => "Runner detected",
53 }
54 }