Skip to content

Commit 5462d52

Browse files
committed
fix(std): fix artifact path lookup
The artifacts directory may get mounted at a different path on macOS, so search for a directory containing ID file names. On Linux, fall back to /.tangram/artifacts if we hit the root. - bump deps - script tweak
1 parent 03890ae commit 5462d52

File tree

11 files changed

+118
-53
lines changed

11 files changed

+118
-53
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
node_modules
33
tangram.lock
44
target
5+
Claude.md

bun.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"": {
55
"dependencies": {
66
"@biomejs/biome": "^2.2.4",
7-
"@types/bun": "^1.2.22",
7+
"@types/bun": "^1.2.23",
88
},
99
},
1010
},

packages/rust/proxy/Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/rust/proxy/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ futures = "0.3"
2020
itertools = "0.14"
2121
serde = { version = "1", features = ["derive"] }
2222
serde_json = "1"
23-
tangram_client = { default-features = false, git = "https://github.com/tangramdotdev/tangram", rev = "ba37f71dc591a2c917d75374fa36cb8d1dbcc7f4" }
23+
tangram_client = { default-features = false, git = "https://github.com/tangramdotdev/tangram", rev = "b7e649add4a5a903883dcf90860886fb50714e21" }
2424
tokio = { version = "1", default-features = false, features = [
2525
"rt",
2626
"fs",

packages/rust/proxy/src/main.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,21 @@ pub fn template_data_to_symlink_data(
661661
}
662662
}
663663

664+
/// Check if a directory looks like a Tangram artifacts directory by examining its contents.
665+
/// Returns true if the directory contains at least one entry that parses as a valid Tangram ID.
666+
fn looks_like_artifacts_dir(path: &Path) -> bool {
667+
let Ok(entries) = std::fs::read_dir(path) else {
668+
return false;
669+
};
670+
671+
entries.filter_map(Result::ok).any(|entry| {
672+
let name = entry.file_name();
673+
name.to_str()
674+
.and_then(|s| s.parse::<tg::Id>().ok())
675+
.is_some()
676+
})
677+
}
678+
664679
/// Compute the closest located artifact path for the current running process, reusing the result for subsequent lookups.
665680
pub static CLOSEST_ARTIFACT_PATH: LazyLock<String> = LazyLock::new(|| {
666681
let mut closest_artifact_path = None;
@@ -671,8 +686,8 @@ pub static CLOSEST_ARTIFACT_PATH: LazyLock<String> = LazyLock::new(|| {
671686
vec![]
672687
};
673688
for path in paths.into_iter().chain(cwd.ancestors().skip(1)) {
674-
let directory = path.join(".tangram/artifacts");
675-
if directory.exists() {
689+
let directory = path.join("artifacts");
690+
if directory.exists() && looks_like_artifacts_dir(&directory) {
676691
closest_artifact_path = Some(
677692
directory
678693
.to_str()
@@ -681,6 +696,21 @@ pub static CLOSEST_ARTIFACT_PATH: LazyLock<String> = LazyLock::new(|| {
681696
);
682697
break;
683698
}
699+
700+
// On Linux, when we reach the root, check /.tangram/artifacts (chroot path)
701+
#[cfg(target_os = "linux")]
702+
if path == Path::new("/") {
703+
let directory = path.join(".tangram/artifacts");
704+
if directory.exists() && looks_like_artifacts_dir(&directory) {
705+
closest_artifact_path = Some(
706+
directory
707+
.to_str()
708+
.expect("artifacts directory should be valid UTF-8")
709+
.to_string(),
710+
);
711+
break;
712+
}
713+
}
684714
}
685715
closest_artifact_path.expect("Failed to find the closest artifact path")
686716
});

packages/std/Cargo.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/std/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ itertools = "0.14"
3434
libc = "0.2"
3535
serde = { version = "1", features = ["derive"] }
3636
serde_json = "1"
37-
tangram_client = { default-features = false, git = "https://github.com/tangramdotdev/tangram", rev = "ba37f71dc591a2c917d75374fa36cb8d1dbcc7f4" }
37+
tangram_client = { default-features = false, git = "https://github.com/tangramdotdev/tangram", rev = "b7e649add4a5a903883dcf90860886fb50714e21" }
3838
tempfile = "3"
3939
tokio = { version = "1", default-features = false, features = [
4040
"rt",

packages/std/packages/cc_proxy/src/main.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -412,17 +412,10 @@ async fn run_proxy(environment: Environment, args: Args) -> tg::Result<()> {
412412
.map_err(|error| tg::error!(source = error, "cc failed: no output"))?;
413413

414414
// Verify we did everything correctly.
415-
let mut tangram_path = std::env::current_dir()
415+
let tangram_path = std::env::current_dir()
416416
.map_err(|error| tg::error!(source = error, "failed to get current working directory"))?;
417-
while !tangram_path.join(".tangram").exists() {
418-
let Some(parent) = tangram_path.parent() else {
419-
return Err(tg::error!("failed to find .tangram directory."));
420-
};
421-
tangram_path = parent.into();
422-
}
423-
let artifact_path = tangram_path
424-
.join(".tangram/artifacts")
425-
.join(output_file.id().to_string());
417+
let artifacts_dir = tangram_std::find_artifacts_dir(&tangram_path)?;
418+
let artifact_path = artifacts_dir.join(output_file.id().to_string());
426419
eprintln!("Copying {} to {output:#?}", artifact_path.display());
427420
std::fs::copy(artifact_path, output)
428421
.map_err(|error| tg::error!(source = error, "failed to copy file"))?;
@@ -465,6 +458,11 @@ async fn create_remapping_table(
465458
let mut table = BTreeMap::new();
466459
let mut subtrees = Vec::new();
467460

461+
// Find the artifacts directory once for checking if paths are already artifacts.
462+
let artifacts_dir = std::env::current_dir()
463+
.ok()
464+
.and_then(|cwd| tangram_std::find_artifacts_dir(&cwd).ok());
465+
468466
for remap_target in remap_targets {
469467
// Canonicalize the source path.
470468
let path: &Path = remap_target.value.as_ref();
@@ -478,7 +476,10 @@ async fn create_remapping_table(
478476
}
479477

480478
// Check if this is a path that should be a template. Needs to happen after canonicalization in case a local symlink was created pointing to an artifact.
481-
if path.starts_with("/.tangram/artifacts") {
479+
if artifacts_dir
480+
.as_ref()
481+
.is_some_and(|dir| path.starts_with(dir))
482+
{
482483
let template = tangram_std::unrender(path.to_str().unwrap())?;
483484
table.insert(remap_target, template);
484485
continue;

packages/std/packages/std/lib.rs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,59 @@ pub fn template_from_artifact_and_subpath(
6565
])
6666
}
6767

68+
/// Check if a directory looks like a Tangram artifacts directory by examining its contents.
69+
/// Returns true if the directory contains at least one entry that parses as a valid Tangram ID.
70+
pub fn looks_like_artifacts_dir(path: &std::path::Path) -> bool {
71+
let Ok(entries) = std::fs::read_dir(path) else {
72+
return false;
73+
};
74+
75+
entries.filter_map(Result::ok).any(|entry| {
76+
let name = entry.file_name();
77+
name.to_str()
78+
.and_then(|s| s.parse::<tg::Id>().ok())
79+
.is_some()
80+
})
81+
}
82+
83+
/// Find the artifacts directory by searching up from the given path.
84+
/// On Linux, falls back to /.tangram/artifacts when reaching the root.
85+
pub fn find_artifacts_dir(start_path: &std::path::Path) -> tg::Result<PathBuf> {
86+
for path in start_path.ancestors() {
87+
let directory = path.join("artifacts");
88+
if directory.exists() && looks_like_artifacts_dir(&directory) {
89+
return Ok(directory);
90+
}
91+
92+
// On Linux, when we reach the root, check /.tangram/artifacts (chroot path)
93+
#[cfg(target_os = "linux")]
94+
if path == std::path::Path::new("/") {
95+
let directory = path.join(".tangram/artifacts");
96+
if directory.exists() && looks_like_artifacts_dir(&directory) {
97+
return Ok(directory);
98+
}
99+
}
100+
}
101+
Err(tg::error!("failed to find artifacts directory"))
102+
}
103+
68104
/// Compute the closest located artifact path for the current running process, reusing the result for subsequent lookups.
69105
pub static CLOSEST_ARTIFACT_PATH: LazyLock<String> = LazyLock::new(|| {
70-
let mut closest_artifact_path = None;
71106
let cwd = std::env::current_exe()
72107
.expect("Failed to get the current directory")
73108
.canonicalize()
74109
.expect("failed to canonicalize current directory");
75-
for path in cwd.ancestors().skip(1) {
76-
let directory = path.join(".tangram/artifacts");
77-
if directory.exists() {
78-
closest_artifact_path = Some(
79-
directory
80-
.to_str()
81-
.expect("artifacts directory should be valid UTF-8")
82-
.to_string(),
83-
);
84-
break;
85-
}
86-
}
87-
closest_artifact_path.expect("Failed to find the closest artifact path")
110+
111+
let parent = cwd
112+
.parent()
113+
.expect("executable should have a parent directory");
114+
let artifacts_dir =
115+
find_artifacts_dir(parent).expect("Failed to find the closest artifact path");
116+
117+
artifacts_dir
118+
.to_str()
119+
.expect("artifacts directory should be valid UTF-8")
120+
.to_string()
88121
});
89122

90123
/// Render a [`tg::template::Data`] to a `String` using the closest located artifact path.

packages/std/wrap.tg.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,13 +2543,13 @@ export const testSingleArgObjectNoMutations = async () => {
25432543
} else if (os === "darwin") {
25442544
tg.assert(
25452545
text.match(
2546-
new RegExp(`_NSGetExecutablePath: .*\\.tangram/artifacts/${wrapperID}`),
2546+
new RegExp(`_NSGetExecutablePath: .*artifacts/${wrapperID}`),
25472547
),
25482548
"Expected _NSGetExecutablePath to point to the wrapper",
25492549
);
25502550
tg.assert(
25512551
text.match(
2552-
new RegExp(`argv\\[0\\]: .*\\.tangram/artifacts/${wrapperID}`),
2552+
new RegExp(`argv\\[0\\]: .*artifacts/${wrapperID}`),
25532553
),
25542554
"Expected argv[0] to point to the wrapper that was invoked",
25552555
);

0 commit comments

Comments
 (0)