Skip to content
Merged
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 133 additions & 5 deletions crates/turborepo-lib/src/shim/local_turbo_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,122 @@ impl LocalTurboState {
// leading to the wrong place. We could separate the Windows
// implementation, but this workaround works for other platforms as
// well.
let canonical_path =
fs_canonicalize(root_path.as_path().join("node_modules").join("turbo")).ok()?;
let turbo_path = root_path.as_path().join("node_modules").join("turbo");
debug!(
"generate_linked_path: Attempting to canonicalize: {}",
turbo_path
);

AbsoluteSystemPathBuf::try_from(canonical_path.parent()?).ok()
match fs_canonicalize(&turbo_path) {
Ok(canonical_path) => {
debug!(
"generate_linked_path: Canonicalized to: {}",
canonical_path.display()
);
match canonical_path.parent() {
Some(parent) => {
debug!(
"generate_linked_path: Parent directory: {}",
parent.display()
);
match AbsoluteSystemPathBuf::try_from(parent) {
Ok(path) => {
debug!(
"generate_linked_path: Successfully created \
AbsoluteSystemPathBuf"
);
Some(path)
}
Err(e) => {
debug!(
"generate_linked_path: Failed to create \
AbsoluteSystemPathBuf: {:?}",
e
);
None
}
}
}
None => {
debug!("generate_linked_path: Canonicalized path has no parent");
None
}
}
}
Err(e) => {
debug!(
"generate_linked_path: Failed to canonicalize {}: {}",
turbo_path, e
);

// On Windows, canonicalize can fail with permission errors even when
// the symlink is valid. Try using read_link instead.
#[cfg(target_os = "windows")]
{
debug!("generate_linked_path: Attempting Windows fallback with read_link");
match fs::read_link(turbo_path.as_std_path()) {
Ok(link_target) => {
debug!(
"generate_linked_path: read_link succeeded, target: {}",
link_target.display()
);

// The link target is relative to the symlink location
// e.g., ".pnpm/[email protected]/node_modules/turbo"
// We need to resolve it relative to node_modules directory
let node_modules =
PathBuf::from(root_path.as_path().as_str()).join("node_modules");
let resolved = node_modules.join(&link_target);

debug!(
"generate_linked_path: Resolved path: {}",
resolved.display()
);

// Get the parent directory (should be .pnpm/[email protected]/node_modules)
match resolved.parent() {
Some(parent) => {
debug!(
"generate_linked_path: Parent directory: {}",
parent.display()
);
match AbsoluteSystemPathBuf::try_from(parent) {
Ok(path) => {
debug!(
"generate_linked_path: Successfully created \
AbsoluteSystemPathBuf from read_link fallback"
);
Some(path)
}
Err(e) => {
debug!(
"generate_linked_path: Failed to create \
AbsoluteSystemPathBuf: {:?}",
e
);
None
}
}
}
None => {
debug!("generate_linked_path: Resolved path has no parent");
None
}
}
}
Err(e) => {
debug!("generate_linked_path: read_link also failed: {}", e);
None
}
}
}

#[cfg(not(target_os = "windows"))]
{
None
}
}
}
}

// The unplugged directory doesn't have a fixed path.
Expand Down Expand Up @@ -117,6 +229,11 @@ impl LocalTurboState {
let platform_package_name = TurboState::platform_package_name();
let binary_name = TurboState::binary_name();

debug!(
"Searching for local turbo. Platform: {}, Binary: {}",
platform_package_name, binary_name
);

let platform_package_json_path_components = [platform_package_name, "package.json"];
let platform_package_executable_path_components =
[platform_package_name, "bin", binary_name];
Expand All @@ -131,13 +248,20 @@ impl LocalTurboState {

// Detecting the package manager is more expensive than just doing an exhaustive
// search.
for root in search_functions
for (idx, root) in search_functions
.iter()
.filter_map(|search_function| search_function(root_path))
.enumerate()
{
debug!("Trying search path #{}: {}", idx + 1, root);
// Needs borrow because of the loop.
#[allow(clippy::needless_borrow)]
let bin_path = root.join_components(&platform_package_executable_path_components);
debug!("Looking for binary at: {}", bin_path);

let exists = bin_path.exists();
debug!("Binary exists: {}", exists);

match fs_canonicalize(&bin_path) {
Ok(bin_path) => {
let resolved_package_json_path =
Expand All @@ -153,10 +277,14 @@ impl LocalTurboState {
version: local_version,
});
}
Err(_) => debug!("No local turbo binary found at: {}", bin_path),
Err(e) => debug!(
"No local turbo binary found at: {} (error: {})",
bin_path, e
),
}
}

debug!("No local turbo found after searching all paths");
None
}

Expand Down
Loading