Skip to content

Commit 53611c4

Browse files
fix(cli): only watch dependent workspace members (#14747)
* fix(cli): only watch dependent workspace members * Use manifest path instead of `workspace_default_members` * Add change file * Merge remote-tracking branch 'upstream/dev' into only-watch-dependencies * `bug` not `fix` * Merge branch 'dev' into only-watch-dependencies * Remove `CargoMetadataExpended` * Merge remote-tracking branch 'upstream/dev' into only-watch-dependencies * Remove top level `.taurignore` * Load ignore files from workspace root
1 parent 62aa13a commit 53611c4

File tree

3 files changed

+88
-57
lines changed

3 files changed

+88
-57
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@tauri-apps/cli": patch:bug
3+
"tauri-cli": patch:bug
4+
---
5+
6+
Only watch dependent workspace members when running `tauri dev` instead of watching on all members

.taurignore

Lines changed: 0 additions & 16 deletions
This file was deleted.

crates/tauri-cli/src/interface/rust.rs

Lines changed: 82 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::{
77
ffi::OsStr,
88
fs::FileType,
99
io::{BufRead, Write},
10+
iter::once,
1011
path::{Path, PathBuf},
1112
process::Command,
1213
str::FromStr,
@@ -15,7 +16,6 @@ use std::{
1516
};
1617

1718
use dunce::canonicalize;
18-
use glob::glob;
1919
use ignore::gitignore::{Gitignore, GitignoreBuilder};
2020
use notify::RecursiveMode;
2121
use notify_debouncer_full::new_debouncer;
@@ -449,25 +449,15 @@ fn dev_options(
449449
}
450450
}
451451

452-
// Copied from https://github.com/rust-lang/cargo/blob/69255bb10de7f74511b5cef900a9d102247b6029/src/cargo/core/workspace.rs#L665
453-
fn expand_member_path(path: &Path) -> crate::Result<Vec<PathBuf>> {
454-
let path = path.to_str().context("path is not UTF-8 compatible")?;
455-
let res = glob(path).with_context(|| format!("failed to expand glob pattern for {path}"))?;
456-
let res = res
457-
.map(|p| p.with_context(|| format!("failed to expand glob pattern for {path}")))
458-
.collect::<Result<Vec<_>, _>>()?;
459-
Ok(res)
460-
}
461-
462452
fn get_watch_folders(
463453
additional_watch_folders: &[PathBuf],
464454
tauri_dir: &Path,
465455
) -> crate::Result<Vec<PathBuf>> {
466-
let workspace_path = get_workspace_dir(tauri_dir)?;
467-
468456
// We always want to watch the main tauri folder.
469457
let mut watch_folders = vec![tauri_dir.to_path_buf()];
470458

459+
watch_folders.extend(get_in_workspace_dependency_paths(tauri_dir)?);
460+
471461
// Add the additional watch folders, resolving the path from the tauri path if it is relative
472462
watch_folders.extend(additional_watch_folders.iter().filter_map(|dir| {
473463
let path = if dir.is_absolute() {
@@ -486,30 +476,6 @@ fn get_watch_folders(
486476
canonicalized
487477
}));
488478

489-
// We also try to watch workspace members, no matter if the tauri cargo project is the workspace root or a workspace member
490-
let cargo_settings = CargoSettings::load(&workspace_path)?;
491-
if let Some(members) = cargo_settings.workspace.and_then(|w| w.members) {
492-
for p in members {
493-
let p = workspace_path.join(p);
494-
match expand_member_path(&p) {
495-
// Sometimes expand_member_path returns an empty vec, for example if the path contains `[]` as in `C:/[abc]/project/`.
496-
// Cargo won't complain unless theres a workspace.members config with glob patterns so we should support it too.
497-
Ok(expanded_paths) => {
498-
if expanded_paths.is_empty() {
499-
watch_folders.push(p);
500-
} else {
501-
watch_folders.extend(expanded_paths);
502-
}
503-
}
504-
Err(err) => {
505-
// If this fails cargo itself should fail too. But we still try to keep going with the unexpanded path.
506-
log::error!("Error watching {}: {}", p.display(), err);
507-
watch_folders.push(p);
508-
}
509-
};
510-
}
511-
}
512-
513479
Ok(watch_folders)
514480
}
515481

@@ -556,8 +522,13 @@ impl Rust {
556522

557523
let watch_folders = get_watch_folders(additional_watch_folders, dirs.tauri)?;
558524

559-
let common_ancestor = common_path::common_path_all(watch_folders.iter().map(Path::new))
560-
.expect("watch_folders should not be empty");
525+
let common_ancestor = common_path::common_path_all(
526+
watch_folders
527+
.iter()
528+
.map(Path::new)
529+
.chain(once(self.app_settings.workspace_dir.as_path())),
530+
)
531+
.expect("watch_folders should not be empty");
561532
let ignore_matcher = build_ignore_matcher(&common_ancestor);
562533

563534
let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| {
@@ -692,7 +663,7 @@ pub struct TomlWorkspaceField {
692663
#[derive(Clone, Debug, Deserialize)]
693664
struct WorkspaceSettings {
694665
/// the workspace members.
695-
members: Option<Vec<String>>,
666+
// members: Option<Vec<String>>,
696667
package: Option<WorkspacePackageSettings>,
697668
}
698669

@@ -779,6 +750,7 @@ pub struct RustAppSettings {
779750
cargo_config: CargoConfig,
780751
target_triple: String,
781752
target_platform: TargetPlatform,
753+
workspace_dir: PathBuf,
782754
}
783755

784756
#[derive(Deserialize)]
@@ -1096,7 +1068,8 @@ impl RustAppSettings {
10961068
}
10971069
};
10981070

1099-
let ws_package_settings = CargoSettings::load(&get_workspace_dir(tauri_dir)?)
1071+
let workspace_dir = get_workspace_dir(tauri_dir)?;
1072+
let ws_package_settings = CargoSettings::load(&workspace_dir)
11001073
.context("failed to load Cargo settings from workspace root")?
11011074
.workspace
11021075
.and_then(|v| v.package);
@@ -1191,6 +1164,7 @@ impl RustAppSettings {
11911164
cargo_config,
11921165
target_triple,
11931166
target_platform,
1167+
workspace_dir,
11941168
})
11951169
}
11961170

@@ -1210,6 +1184,23 @@ impl RustAppSettings {
12101184
pub(crate) struct CargoMetadata {
12111185
pub(crate) target_directory: PathBuf,
12121186
pub(crate) workspace_root: PathBuf,
1187+
workspace_members: Vec<String>,
1188+
packages: Vec<Package>,
1189+
}
1190+
1191+
#[derive(Deserialize)]
1192+
struct Package {
1193+
name: String,
1194+
id: String,
1195+
manifest_path: PathBuf,
1196+
dependencies: Vec<Dependency>,
1197+
}
1198+
1199+
#[derive(Deserialize)]
1200+
struct Dependency {
1201+
name: String,
1202+
/// Local package
1203+
path: Option<PathBuf>,
12131204
}
12141205

12151206
pub(crate) fn get_cargo_metadata(tauri_dir: &Path) -> crate::Result<CargoMetadata> {
@@ -1232,6 +1223,56 @@ pub(crate) fn get_cargo_metadata(tauri_dir: &Path) -> crate::Result<CargoMetadat
12321223
serde_json::from_slice(&output.stdout).context("failed to parse cargo metadata")
12331224
}
12341225

1226+
/// Get the tauri project crate's dependencies that are inside the workspace
1227+
fn get_in_workspace_dependency_paths(tauri_dir: &Path) -> crate::Result<Vec<PathBuf>> {
1228+
let metadata = get_cargo_metadata(tauri_dir)?;
1229+
let tauri_project_manifest_path = tauri_dir.join("Cargo.toml");
1230+
let tauri_project_package = metadata
1231+
.packages
1232+
.iter()
1233+
.find(|package| package.manifest_path == tauri_project_manifest_path)
1234+
.context("tauri project package doesn't exist in cargo metadata output `packages`")?;
1235+
1236+
let workspace_packages = metadata
1237+
.workspace_members
1238+
.iter()
1239+
.map(|member_package_id| {
1240+
metadata
1241+
.packages
1242+
.iter()
1243+
.find(|package| package.id == *member_package_id)
1244+
.context("workspace member doesn't exist in cargo metadata output `packages`")
1245+
})
1246+
.collect::<crate::Result<Vec<_>>>()?;
1247+
1248+
let mut found_dependency_paths = Vec::new();
1249+
find_dependencies(
1250+
tauri_project_package,
1251+
&workspace_packages,
1252+
&mut found_dependency_paths,
1253+
);
1254+
Ok(found_dependency_paths)
1255+
}
1256+
1257+
fn find_dependencies(
1258+
package: &Package,
1259+
workspace_packages: &Vec<&Package>,
1260+
found_dependency_paths: &mut Vec<PathBuf>,
1261+
) {
1262+
for dependency in &package.dependencies {
1263+
if let Some(path) = &dependency.path {
1264+
if let Some(package) = workspace_packages.iter().find(|workspace_package| {
1265+
workspace_package.name == dependency.name
1266+
&& path.join("Cargo.toml") == workspace_package.manifest_path
1267+
&& !found_dependency_paths.contains(path)
1268+
}) {
1269+
found_dependency_paths.push(path.to_owned());
1270+
find_dependencies(package, workspace_packages, found_dependency_paths);
1271+
}
1272+
}
1273+
}
1274+
}
1275+
12351276
/// Get the cargo target directory based on the provided arguments.
12361277
/// If "--target-dir" is specified in args, use it as the target directory (relative to current directory).
12371278
/// Otherwise, use the target directory from cargo metadata.

0 commit comments

Comments
 (0)