Skip to content

Commit

Permalink
refactor(cli): Use cargo metadata to detect the workspace root and …
Browse files Browse the repository at this point in the history
…target directory, closes #4632, #4928. (#4932)
  • Loading branch information
FabianLars authored Aug 21, 2022
1 parent e16b366 commit fea70ef
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 103 deletions.
6 changes: 6 additions & 0 deletions .changes/cli-detect-target-dir.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"cli.rs": "patch"
"cli.js": "patch"
---

Use `cargo metadata` to detect the workspace root and target directory.
11 changes: 4 additions & 7 deletions tooling/cli/src/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())),
Expand Down
135 changes: 39 additions & 96 deletions tooling/cli/src/interface/rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -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;
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
}
}

#[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 where 'target' dir is and suffixes it with 'release' or 'debug'
/// 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)]
Expand Down

0 comments on commit fea70ef

Please sign in to comment.