diff --git a/CHANGELOG.md b/CHANGELOG.md index 3160ee1..9124e7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev) +### Added + +* `--dry` flag to inspect command that will be run + ## [0.2.0](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.2.0) ### Added diff --git a/Dockerfile b/Dockerfile index cb3b9e0..d754728 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN cargo build && \ # We use ${:-} instead of a default value because the argument is always passed # to the build, it'll just be blank most likely -FROM eclipse-temurin:17-jre-alpine +FROM eclipse-temurin:18-jre-alpine # Build arguments ARG MC_VERSION=1.19.4 diff --git a/src/main.rs b/src/main.rs index 9f993a9..10500b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,6 +66,11 @@ struct Cli { /// How frequently to perform a backup, in minutes; 0 to disable. #[arg(short = 't', long, default_value_t = 0, env = "ALEX_FREQUENCY")] frequency: u64, + + /// Don't actually run the server, but simply output the server configuration that would have + /// been ran + #[arg(short, long, default_value_t = false)] + dry: bool, } fn backups_thread(counter: Arc>, frequency: u64) { @@ -85,7 +90,7 @@ fn main() -> io::Result<()> { let (_, mut signals) = signals::install_signal_handlers()?; let cli = Cli::parse(); - let cmd = server::ServerCommand::new(cli.type_, &cli.server_version) + let mut cmd = server::ServerCommand::new(cli.type_, &cli.server_version) .java(&cli.java) .jar(cli.jar) .config(cli.config) @@ -94,6 +99,14 @@ fn main() -> io::Result<()> { .xms(cli.xms) .xmx(cli.xmx) .max_backups(cli.max_backups); + cmd.canonicalize()?; + + if cli.dry { + print!("{}", cmd); + + return Ok(()); + } + let counter = Arc::new(Mutex::new(cmd.spawn()?)); if cli.frequency > 0 { diff --git a/src/server/command.rs b/src/server/command.rs index 7b6d948..f410c88 100644 --- a/src/server/command.rs +++ b/src/server/command.rs @@ -105,14 +105,19 @@ impl ServerCommand { Ok(()) } - pub fn spawn(self) -> std::io::Result { + /// Canonicalize all paths to absolute paths. Without this command, all paths will be + /// interpreted relatively from the config directory. + pub fn canonicalize(&mut self) -> std::io::Result<()> { // To avoid any issues, we use absolute paths for everything when spawning the process - let jar = self.jar.canonicalize()?; - let config_dir = self.config_dir.canonicalize()?; - let world_dir = self.world_dir.canonicalize()?; - let backup_dir = self.backup_dir.canonicalize()?; + self.jar = self.jar.canonicalize()?; + self.config_dir = self.config_dir.canonicalize()?; + self.world_dir = self.world_dir.canonicalize()?; + self.backup_dir = self.backup_dir.canonicalize()?; - self.accept_eula()?; + Ok(()) + } + + fn create_cmd(&self) -> std::process::Command { let mut cmd = Command::new(&self.java); // Apply JVM optimisation flags @@ -155,24 +160,56 @@ impl ServerCommand { ]); } - cmd.current_dir(&config_dir) + cmd.current_dir(&self.config_dir) .arg("-jar") - .arg(&jar) + .arg(&self.jar) .arg("--universe") - .arg(&world_dir) + .arg(&self.world_dir) .arg("--nogui") .stdin(Stdio::piped()); + cmd + } + + pub fn spawn(&mut self) -> std::io::Result { + let mut cmd = self.create_cmd(); + self.accept_eula()?; let child = cmd.spawn()?; Ok(ServerProcess::new( self.type_, - self.version, - config_dir, - world_dir, - backup_dir, + self.version.clone(), + self.config_dir.clone(), + self.world_dir.clone(), + self.backup_dir.clone(), self.max_backups, child, )) } } + +impl fmt::Display for ServerCommand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let cmd = self.create_cmd(); + + write!(f, "Command: {}\n", self.java)?; + write!(f, "Working dir: {}\n", self.config_dir.as_path().display())?; + + // Print command env vars + write!(f, "Environment:\n")?; + + for (key, val) in cmd.get_envs().filter(|(_, v)| v.is_some()) { + let val = val.unwrap(); + write!(f, " {}={}\n", key.to_string_lossy(), val.to_string_lossy())?; + } + + // Print command arguments + write!(f, "Arguments:\n")?; + + for arg in cmd.get_args() { + write!(f, " {}\n", arg.to_string_lossy())?; + } + + Ok(()) + } +}