Skip to content

Commit

Permalink
Add cwd option to before commands, add wait option to dev #4740 #3551
Browse files Browse the repository at this point in the history
… (#4834)
  • Loading branch information
lucasfernog authored Aug 2, 2022
1 parent 90d5929 commit d6f7d3c
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 50 deletions.
7 changes: 7 additions & 0 deletions .changes/before-command-cwd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri-utils": minor
"cli.rs": minor
"cli.js": minor
---

Change `before_dev_command` and `before_build_command` config value to allow configuring the current working directory.
7 changes: 7 additions & 0 deletions .changes/before-dev-command-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"tauri-utils": minor
"cli.rs": minor
"cli.js": minor
---

Allow configuring the `before_dev_command` to force the CLI to wait for the command to finish before proceeding.
39 changes: 37 additions & 2 deletions core/tauri-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2377,6 +2377,41 @@ impl std::fmt::Display for AppUrl {
}
}

/// Describes the shell command to run before `tauri dev`.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", untagged)]
pub enum BeforeDevCommand {
/// Run the given script with the default options.
Script(String),
/// Run the given script with custom options.
ScriptWithOptions {
/// The script to execute.
script: String,
/// The current working directory.
cwd: Option<String>,
/// Whether `tauri dev` should wait for the command to finish or not. Defaults to `false`.
#[serde(default)]
wait: bool,
},
}

/// Describes the shell command to run before `tauri build`.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", untagged)]
pub enum BeforeBuildCommand {
/// Run the given script with the default options.
Script(String),
/// Run the given script with custom options.
ScriptWithOptions {
/// The script to execute.
script: String,
/// The current working directory.
cwd: Option<String>,
},
}

/// The Build configuration object.
#[skip_serializing_none]
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -2411,12 +2446,12 @@ pub struct BuildConfig {
///
/// The TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG environment variables are set if you perform conditional compilation.
#[serde(alias = "before-dev-command")]
pub before_dev_command: Option<String>,
pub before_dev_command: Option<BeforeDevCommand>,
/// A shell command to run before `tauri build` kicks in.
///
/// The TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG environment variables are set if you perform conditional compilation.
#[serde(alias = "before-build-command")]
pub before_build_command: Option<String>,
pub before_build_command: Option<BeforeBuildCommand>,
/// Features passed to `cargo` commands.
pub features: Option<Vec<String>>,
/// Whether we should inject the Tauri API on `window.__TAURI__` or not.
Expand Down
83 changes: 77 additions & 6 deletions tooling/cli/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2449,16 +2449,24 @@
},
"beforeDevCommand": {
"description": "A shell command to run before `tauri dev` kicks in.\n\nThe TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG environment variables are set if you perform conditional compilation.",
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/definitions/BeforeDevCommand"
},
{
"type": "null"
}
]
},
"beforeBuildCommand": {
"description": "A shell command to run before `tauri build` kicks in.\n\nThe TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG environment variables are set if you perform conditional compilation.",
"type": [
"string",
"null"
"anyOf": [
{
"$ref": "#/definitions/BeforeBuildCommand"
},
{
"type": "null"
}
]
},
"features": {
Expand Down Expand Up @@ -2499,6 +2507,69 @@
}
]
},
"BeforeDevCommand": {
"description": "Describes the shell command to run before `tauri dev`.",
"anyOf": [
{
"description": "Run the given script with the default options.",
"type": "string"
},
{
"description": "Run the given script with custom options.",
"type": "object",
"required": [
"script"
],
"properties": {
"script": {
"description": "The script to execute.",
"type": "string"
},
"cwd": {
"description": "The current working directory.",
"type": [
"string",
"null"
]
},
"wait": {
"description": "Whether `tauri dev` should wait for the command to finish or not. Defaults to `false`.",
"default": false,
"type": "boolean"
}
}
}
]
},
"BeforeBuildCommand": {
"description": "Describes the shell command to run before `tauri build`.",
"anyOf": [
{
"description": "Run the given script with the default options.",
"type": "string"
},
{
"description": "Run the given script with custom options.",
"type": "object",
"required": [
"script"
],
"properties": {
"script": {
"description": "The script to execute.",
"type": "string"
},
"cwd": {
"description": "The current working directory.",
"type": [
"string",
"null"
]
}
}
}
]
},
"PluginConfig": {
"description": "The plugin configs holds a HashMap mapping a plugin name to its configuration object.",
"type": "object",
Expand Down
22 changes: 15 additions & 7 deletions tooling/cli/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::{
helpers::{
app_paths::{app_dir, tauri_dir},
command_env,
config::{get as get_config, AppUrl, WindowUrl, MERGE_CONFIG_EXTENSION_NAME},
config::{
get as get_config, AppUrl, BeforeBuildCommand, WindowUrl, MERGE_CONFIG_EXTENSION_NAME,
},
updater_signature::{read_key_from_file, secret_key as updater_secret_key, sign_file},
},
interface::{AppInterface, AppSettings, Interface},
Expand Down Expand Up @@ -112,23 +114,29 @@ pub fn command(mut options: Options) -> Result<()> {
std::process::exit(1);
}

if let Some(before_build) = &config_.build.before_build_command {
if !before_build.is_empty() {
if let Some(before_build) = config_.build.before_build_command.clone() {
let (script, script_cwd) = match before_build {
BeforeBuildCommand::Script(s) if s.is_empty() => (None, None),
BeforeBuildCommand::Script(s) => (Some(s), None),
BeforeBuildCommand::ScriptWithOptions { script, cwd } => (Some(script), cwd.map(Into::into)),
};
let cwd = script_cwd.unwrap_or_else(|| app_dir().clone());
if let Some(before_build) = script {
info!(action = "Running"; "beforeBuildCommand `{}`", before_build);
#[cfg(target_os = "windows")]
let status = Command::new("cmd")
.arg("/S")
.arg("/C")
.arg(before_build)
.current_dir(app_dir())
.arg(&before_build)
.current_dir(cwd)
.envs(command_env(options.debug))
.piped()
.with_context(|| format!("failed to run `{}` with `cmd /C`", before_build))?;
#[cfg(not(target_os = "windows"))]
let status = Command::new("sh")
.arg("-c")
.arg(before_build)
.current_dir(app_dir())
.arg(&before_build)
.current_dir(cwd)
.envs(command_env(options.debug))
.piped()
.with_context(|| format!("failed to run `{}` with `sh -c`", before_build))?;
Expand Down
97 changes: 62 additions & 35 deletions tooling/cli/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use crate::{
helpers::{
app_paths::{app_dir, tauri_dir},
command_env,
config::{get as get_config, AppUrl, WindowUrl},
config::{get as get_config, AppUrl, BeforeDevCommand, WindowUrl},
},
interface::{AppInterface, ExitReason, Interface},
Result,
CommandExt, Result,
};
use clap::Parser;

use anyhow::Context;
use anyhow::{bail, Context};
use log::{error, info, warn};
use once_cell::sync::OnceCell;
use shared_child::SharedChild;
Expand Down Expand Up @@ -89,65 +89,92 @@ fn command_internal(mut options: Options) -> Result<()> {

let config = get_config(options.config.as_deref())?;

if let Some(before_dev) = &config
if let Some(before_dev) = config
.lock()
.unwrap()
.as_ref()
.unwrap()
.build
.before_dev_command
.clone()
{
if !before_dev.is_empty() {
let (script, script_cwd, wait) = match before_dev {
BeforeDevCommand::Script(s) if s.is_empty() => (None, None, false),
BeforeDevCommand::Script(s) => (Some(s), None, false),
BeforeDevCommand::ScriptWithOptions { script, cwd, wait } => {
(Some(script), cwd.map(Into::into), wait)
}
};
let cwd = script_cwd.unwrap_or_else(|| app_dir().clone());
if let Some(before_dev) = script {
info!(action = "Running"; "BeforeDevCommand (`{}`)", before_dev);
#[cfg(target_os = "windows")]
#[cfg(windows)]
let mut command = {
let mut command = Command::new("cmd");
command
.arg("/S")
.arg("/C")
.arg(before_dev)
.current_dir(app_dir())
.arg(&before_dev)
.current_dir(cwd)
.envs(command_env(true));
command
};
#[cfg(not(target_os = "windows"))]
#[cfg(not(windows))]
let mut command = {
let mut command = Command::new("sh");
command
.arg("-c")
.arg(before_dev)
.current_dir(app_dir())
.arg(&before_dev)
.current_dir(cwd)
.envs(command_env(true));
command
};
command.stdin(Stdio::piped());
command.stdout(os_pipe::dup_stdout()?);
command.stderr(os_pipe::dup_stderr()?);

let child = SharedChild::spawn(&mut command)
.unwrap_or_else(|_| panic!("failed to run `{}`", before_dev));
let child = Arc::new(child);
let child_ = child.clone();

std::thread::spawn(move || {
let status = child_
.wait()
.expect("failed to wait on \"beforeDevCommand\"");
if !(status.success() || KILL_BEFORE_DEV_FLAG.get().unwrap().load(Ordering::Relaxed)) {
error!("The \"beforeDevCommand\" terminated with a non-zero status code.");
exit(status.code().unwrap_or(1));
if wait {
let status = command.piped().with_context(|| {
format!(
"failed to run `{}` with `{}`",
before_dev,
if cfg!(windows) { "cmd /S /C" } else { "sh -c" }
)
})?;
if !status.success() {
bail!(
"beforeDevCommand `{}` failed with exit code {}",
before_dev,
status.code().unwrap_or_default()
);
}
});
} else {
command.stdin(Stdio::piped());
command.stdout(os_pipe::dup_stdout()?);
command.stderr(os_pipe::dup_stderr()?);

let child = SharedChild::spawn(&mut command)
.unwrap_or_else(|_| panic!("failed to run `{}`", before_dev));
let child = Arc::new(child);
let child_ = child.clone();

BEFORE_DEV.set(Mutex::new(child)).unwrap();
KILL_BEFORE_DEV_FLAG.set(AtomicBool::default()).unwrap();
std::thread::spawn(move || {
let status = child_
.wait()
.expect("failed to wait on \"beforeDevCommand\"");
if !(status.success() || KILL_BEFORE_DEV_FLAG.get().unwrap().load(Ordering::Relaxed)) {
error!("The \"beforeDevCommand\" terminated with a non-zero status code.");
exit(status.code().unwrap_or(1));
}
});

let _ = ctrlc::set_handler(move || {
kill_before_dev_process();
#[cfg(not(debug_assertions))]
let _ = check_for_updates();
exit(130);
});
BEFORE_DEV.set(Mutex::new(child)).unwrap();
KILL_BEFORE_DEV_FLAG.set(AtomicBool::default()).unwrap();

let _ = ctrlc::set_handler(move || {
kill_before_dev_process();
#[cfg(not(debug_assertions))]
let _ = check_for_updates();
exit(130);
});
}
}
}

Expand Down

0 comments on commit d6f7d3c

Please sign in to comment.