mirror of
https://github.com/tauri-apps/tauri.git
synced 2025-01-01 23:42:33 +03:00
refactor(cli): Use cargo metadata
to detect the workspace root and target directory, closes #4632, #4928. (#4932)
This commit is contained in:
parent
e16b366174
commit
fea70effad
6
.changes/cli-detect-target-dir.md
Normal file
6
.changes/cli-detect-target-dir.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"cli.rs": "patch"
|
||||
"cli.js": "patch"
|
||||
---
|
||||
|
||||
Use `cargo metadata` to detect the workspace root and target directory.
|
@ -794,13 +794,10 @@ pub fn command(_options: Options) -> Result<()> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let lock: Option<CargoLock> = if let Ok(lock_contents) =
|
||||
read_to_string(get_workspace_dir(&tauri_dir).join("Cargo.lock"))
|
||||
{
|
||||
toml::from_str(&lock_contents).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let lock: Option<CargoLock> = get_workspace_dir()
|
||||
.ok()
|
||||
.and_then(|p| read_to_string(p.join("Cargo.lock")).ok())
|
||||
.and_then(|s| toml::from_str(&s).ok());
|
||||
|
||||
for (dep, label) in [
|
||||
("tauri", format!("{} {}", "tauri", "[RUST]".dimmed())),
|
||||
|
@ -7,7 +7,7 @@ use std::{
|
||||
fs::{File, FileType},
|
||||
io::{Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::ExitStatus,
|
||||
process::{Command, ExitStatus},
|
||||
str::FromStr,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@ -20,7 +20,6 @@ use std::{
|
||||
use anyhow::Context;
|
||||
#[cfg(target_os = "linux")]
|
||||
use heck::ToKebabCase;
|
||||
use log::warn;
|
||||
use log::{debug, info};
|
||||
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
|
||||
use serde::Deserialize;
|
||||
@ -287,7 +286,7 @@ impl Rust {
|
||||
let process = Arc::new(Mutex::new(child));
|
||||
let (tx, rx) = channel();
|
||||
let tauri_path = tauri_dir();
|
||||
let workspace_path = get_workspace_dir(&tauri_path);
|
||||
let workspace_path = get_workspace_dir()?;
|
||||
|
||||
let watch_folders = if tauri_path == workspace_path {
|
||||
vec![tauri_path]
|
||||
@ -423,17 +422,6 @@ impl CargoSettings {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CargoBuildConfig {
|
||||
#[serde(rename = "target-dir")]
|
||||
target_dir: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CargoConfig {
|
||||
build: Option<CargoBuildConfig>,
|
||||
}
|
||||
|
||||
pub struct RustAppSettings {
|
||||
manifest: Manifest,
|
||||
cargo_settings: CargoSettings,
|
||||
@ -639,100 +627,55 @@ impl RustAppSettings {
|
||||
}
|
||||
|
||||
pub fn out_dir(&self, target: Option<String>, debug: bool) -> crate::Result<PathBuf> {
|
||||
let tauri_dir = tauri_dir();
|
||||
let workspace_dir = get_workspace_dir(&tauri_dir);
|
||||
get_target_dir(&workspace_dir, target, !debug)
|
||||
get_target_dir(target, !debug)
|
||||
}
|
||||
}
|
||||
|
||||
/// This function determines where 'target' dir is and suffixes it with 'release' or 'debug'
|
||||
#[derive(Deserialize)]
|
||||
struct CargoMetadata {
|
||||
target_directory: PathBuf,
|
||||
workspace_root: PathBuf,
|
||||
}
|
||||
|
||||
fn get_cargo_metadata() -> crate::Result<CargoMetadata> {
|
||||
let output = Command::new("cargo")
|
||||
.args(["metadata", "--no-deps", "--format-version", "1"])
|
||||
.current_dir(tauri_dir())
|
||||
.output()?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"cargo metadata command exited with a non zero exit code: {}",
|
||||
String::from_utf8(output.stderr)?
|
||||
));
|
||||
}
|
||||
|
||||
Ok(serde_json::from_slice(&output.stdout)?)
|
||||
}
|
||||
|
||||
/// This function determines the 'target' directory and suffixes it with 'release' or 'debug'
|
||||
/// to determine where the compiled binary will be located.
|
||||
fn get_target_dir(
|
||||
project_root_dir: &Path,
|
||||
target: Option<String>,
|
||||
is_release: bool,
|
||||
) -> crate::Result<PathBuf> {
|
||||
let mut path: PathBuf = match std::env::var_os("CARGO_TARGET_DIR") {
|
||||
Some(target_dir) => target_dir.into(),
|
||||
None => {
|
||||
let mut root_dir = project_root_dir.to_path_buf();
|
||||
let target_path: Option<PathBuf> = loop {
|
||||
// cargo reads configs under .cargo/config.toml or .cargo/config
|
||||
let mut cargo_config_path = root_dir.join(".cargo/config");
|
||||
if !cargo_config_path.exists() {
|
||||
cargo_config_path = root_dir.join(".cargo/config.toml");
|
||||
}
|
||||
// if the path exists, parse it
|
||||
if cargo_config_path.exists() {
|
||||
let mut config_str = String::new();
|
||||
let mut config_file = File::open(&cargo_config_path)
|
||||
.with_context(|| format!("failed to open {:?}", cargo_config_path))?;
|
||||
config_file
|
||||
.read_to_string(&mut config_str)
|
||||
.with_context(|| "failed to read cargo config file")?;
|
||||
let config: CargoConfig =
|
||||
toml::from_str(&config_str).with_context(|| "failed to parse cargo config file")?;
|
||||
if let Some(build) = config.build {
|
||||
if let Some(target_dir) = build.target_dir {
|
||||
break Some(target_dir.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !root_dir.pop() {
|
||||
break None;
|
||||
}
|
||||
};
|
||||
target_path.unwrap_or_else(|| project_root_dir.join("target"))
|
||||
}
|
||||
};
|
||||
fn get_target_dir(target: Option<String>, is_release: bool) -> crate::Result<PathBuf> {
|
||||
let mut path = get_cargo_metadata()
|
||||
.with_context(|| "failed to get cargo metadata")?
|
||||
.target_directory;
|
||||
|
||||
if let Some(ref triple) = target {
|
||||
path.push(triple);
|
||||
}
|
||||
|
||||
path.push(if is_release { "release" } else { "debug" });
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// Walks up the file system, looking for a Cargo.toml file
|
||||
/// If one is found before reaching the root, then the current_dir's package belongs to that parent workspace if it's listed on [workspace.members].
|
||||
///
|
||||
/// If this package is part of a workspace, returns the path to the workspace directory
|
||||
/// Otherwise returns the current directory.
|
||||
pub fn get_workspace_dir(current_dir: &Path) -> PathBuf {
|
||||
let mut dir = current_dir.to_path_buf();
|
||||
let project_path = dir.clone();
|
||||
|
||||
while dir.pop() {
|
||||
if dir.join("Cargo.toml").exists() {
|
||||
match CargoSettings::load(&dir) {
|
||||
Ok(cargo_settings) => {
|
||||
if let Some(workspace_settings) = cargo_settings.workspace {
|
||||
if let Some(members) = workspace_settings.members {
|
||||
if members.iter().any(|member| {
|
||||
glob::glob(&dir.join(member).to_string_lossy())
|
||||
.unwrap()
|
||||
.any(|p| p.unwrap() == project_path)
|
||||
}) {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Found `{}`, which may define a parent workspace, but \
|
||||
failed to parse it. If this is indeed a parent workspace, undefined behavior may occur: \
|
||||
\n {:#}",
|
||||
dir.display(),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found walking up the file system, return the starting directory
|
||||
current_dir.to_path_buf()
|
||||
/// Executes `cargo metadata` to get the workspace directory.
|
||||
pub fn get_workspace_dir() -> crate::Result<PathBuf> {
|
||||
Ok(
|
||||
get_cargo_metadata()
|
||||
.with_context(|| "failed to get cargo metadata")?
|
||||
.workspace_root,
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
Loading…
Reference in New Issue
Block a user