Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion crates/vt_bin/src/vtt/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ mod print_color;
mod print_cwd;
mod print_env;
mod print_file;
mod read_link;
mod read_stdin;
mod replace_file_content;
mod rm;
Expand All @@ -38,7 +39,7 @@ fn main() {
if args.len() < 2 {
eprintln!("Usage: vtt <subcommand> [args...]");
eprintln!(
"Subcommands: barrier, check-tty, cp, exit, exit-on-ctrlc, grep-file, list-dir, mkdir, pipe-stdin, print, print-color, print-cwd, print-env, print-file, read-stdin, replace-file-content, rm, small_dev_shm, stalled-remote-cache, stat-file, stat-many, symlink, touch-file, write-file"
"Subcommands: barrier, check-tty, cp, exit, exit-on-ctrlc, grep-file, list-dir, mkdir, pipe-stdin, print, print-color, print-cwd, print-env, print-file, read-link, read-stdin, replace-file-content, rm, small_dev_shm, stalled-remote-cache, stat-file, stat-many, symlink, touch-file, write-file"
);
std::process::exit(1);
}
Expand Down Expand Up @@ -67,6 +68,7 @@ fn main() {
"print-cwd" => print_cwd::run(),
"print-env" => print_env::run(&args[2..]),
"print-file" => print_file::run(&args[2..]),
"read-link" => read_link::run(&args[2..]),
"read-stdin" => read_stdin::run(),
"replace-file-content" => replace_file_content::run(&args[2..]),
"rm" => rm::run(&args[2..]),
Expand Down
9 changes: 9 additions & 0 deletions crates/vt_bin/src/vtt/read_link.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/// Print the target of the symbolic link at `<path>`, like `readlink`. Fails if
/// `<path>` isn't a symbolic link.
pub fn run(args: &[String]) -> Result<(), Box<dyn std::error::Error>> {
let [path] = args else {
return Err("Usage: vtt read-link <path>".into());
};
println!("{}", std::fs::read_link(path)?.display());
Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
// Prints the `tslib` version each traced package resolves to in the server output.
const modules = './.output/server/node_modules/';
// Checks that each path nf3 links is a symbolic link into `.nf3`, then prints
// the `tslib` version each traced package resolves to through the links.
const fs = require('node:fs');
const path = require('node:path');

const modules = path.resolve('.output/server/node_modules');
for (const link of ['tslib', 'dep-a/node_modules/tslib', 'dep-b/node_modules/tslib']) {
const linkPath = path.join(modules, link);
const kind = fs.lstatSync(linkPath).isSymbolicLink() ? 'link' : 'not a link';
// Resolve both ends, so the output is the same whether the target is
// relative (Unix) or an absolute junction target (Windows).
const target = path.relative(fs.realpathSync(path.dirname(linkPath)), fs.realpathSync(linkPath));
console.log(`${link}: ${kind} to ${target.split(path.sep).join('/')}`);
}
for (const name of ['dep-a', 'dep-b']) {
console.log(`${name}: tslib ${require(modules + name)()}`);
console.log(`${name}: tslib ${require(path.join(modules, name))()}`);
}
console.log(`hoisted: tslib ${require(modules + 'tslib').version}`);
console.log(`hoisted: tslib ${require(path.join(modules, 'tslib')).version}`);
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[[e2e]]
name = "nitro_build_restores_traced_dependency_links"
comment = """
A real Nitro server build traces `dep-a` and `dep-b`, which depend on different versions of `tslib` (small stand-ins committed in the fixture's `node_modules`). nf3 writes each version under `.output/server/node_modules/.nf3/tslib@<version>`, links `node_modules/tslib` to the hoisted one, and links each package's `node_modules/tslib` to the one it needs. A cache hit restores those links, so each package still resolves its own version from the restored output. On Windows, nf3 creates junctions, whose targets are absolute paths.
A real Nitro server build traces `dep-a` and `dep-b`, which depend on different versions of `tslib` (small stand-ins committed in the fixture's `node_modules`). nf3 writes each version under `.output/server/node_modules/.nf3/tslib@<version>`, links `node_modules/tslib` to the hoisted one, and links each package's `node_modules/tslib` to the one it needs. A cache hit restores those links as links, so each package still resolves its own version from the restored output. On Windows, nf3 creates junctions, whose targets are absolute paths.
"""
ignore = true
steps = [
Expand All @@ -13,7 +13,7 @@ steps = [
{ argv = [
"node",
"check.cjs",
], comment = "each package resolves its own tslib through nf3's links" },
], comment = "nf3 linked each package's tslib into .nf3, so each resolves its own version" },
{ argv = [
"vtt",
"rm",
Expand All @@ -28,5 +28,5 @@ steps = [
{ argv = [
"node",
"check.cjs",
], comment = "the restored output resolves the same versions" },
], comment = "the restored output has the same links, not copies, and resolves the same versions" },
]
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# nitro_build_restores_traced_dependency_links

A real Nitro server build traces `dep-a` and `dep-b`, which depend on different versions of `tslib` (small stand-ins committed in the fixture's `node_modules`). nf3 writes each version under `.output/server/node_modules/.nf3/tslib@<version>`, links `node_modules/tslib` to the hoisted one, and links each package's `node_modules/tslib` to the one it needs. A cache hit restores those links, so each package still resolves its own version from the restored output. On Windows, nf3 creates junctions, whose targets are absolute paths.
A real Nitro server build traces `dep-a` and `dep-b`, which depend on different versions of `tslib` (small stand-ins committed in the fixture's `node_modules`). nf3 writes each version under `.output/server/node_modules/.nf3/tslib@<version>`, links `node_modules/tslib` to the hoisted one, and links each package's `node_modules/tslib` to the one it needs. A cache hit restores those links as links, so each package still resolves its own version from the restored output. On Windows, nf3 creates junctions, whose targets are absolute paths.

## `vt run build`

Expand All @@ -12,9 +12,12 @@ $ CONSOLA_LEVEL=0 nitro build

## `node check.cjs`

each package resolves its own tslib through nf3's links
nf3 linked each package's tslib into .nf3, so each resolves its own version

```
tslib: link to .nf3/tslib@2.8.1
dep-a/node_modules/tslib: link to ../../.nf3/tslib@1.14.1
dep-b/node_modules/tslib: link to ../../.nf3/tslib@2.8.1
dep-a: tslib 1.14.1
dep-b: tslib 2.8.1
hoisted: tslib 2.8.1
Expand All @@ -40,9 +43,12 @@ vt run: cache hit.

## `node check.cjs`

the restored output resolves the same versions
the restored output has the same links, not copies, and resolves the same versions

```
tslib: link to .nf3/tslib@2.8.1
dep-a/node_modules/tslib: link to ../../.nf3/tslib@1.14.1
dep-b/node_modules/tslib: link to ../../.nf3/tslib@2.8.1
dep-a: tslib 1.14.1
dep-b: tslib 2.8.1
hoisted: tslib 2.8.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ steps = [
[[e2e]]
name = "output_globs___symlinks_restored_on_cache_hit"
comment = """
A symbolic link matched by an output glob is archived as a link, so a cache hit restores it. Restoring also replaces a link that is already there. Unix only: on Windows, `tar` restores the target `store/pkg` with its `/` separator, which Windows doesn't resolve, and can't replace the directory link already there.
A symbolic link matched by an output glob is archived as a link, so a cache hit restores it as a link with the same target. Restoring also replaces a link that is already there. Unix only: on Windows, `tar` restores the target `store/pkg` with its `/` separator, which Windows doesn't resolve, and can't replace the directory link already there.
"""
cfg = "unix"
steps = [
Expand All @@ -184,6 +184,11 @@ steps = [
"print-file",
"dist/pkg/index.js",
], comment = "the file is reachable through the restored link" },
{ argv = [
"vtt",
"read-link",
"dist/pkg",
], comment = "dist/pkg is restored as a link to store/pkg, not as a copy" },
{ argv = [
"vt",
"run",
Expand All @@ -194,4 +199,9 @@ steps = [
"print-file",
"dist/pkg/index.js",
], comment = "the file is still reachable through the link" },
{ argv = [
"vtt",
"read-link",
"dist/pkg",
], comment = "dist/pkg is still a link to store/pkg" },
]
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# output_globs___symlinks_restored_on_cache_hit

A symbolic link matched by an output glob is archived as a link, so a cache hit restores it. Restoring also replaces a link that is already there. Unix only: on Windows, `tar` restores the target `store/pkg` with its `/` separator, which Windows doesn't resolve, and can't replace the directory link already there.
A symbolic link matched by an output glob is archived as a link, so a cache hit restores it as a link with the same target. Restoring also replaces a link that is already there. Unix only: on Windows, `tar` restores the target `store/pkg` with its `/` separator, which Windows doesn't resolve, and can't replace the directory link already there.

## `vt run build-with-symlink`

Expand Down Expand Up @@ -43,6 +43,14 @@ the file is reachable through the restored link
built
```

## `vtt read-link dist/pkg`

dist/pkg is restored as a link to store/pkg, not as a copy

```
store/pkg
```

## `vt run build-with-symlink`

third run — cache hit, restores over the link the second run left
Expand All @@ -63,3 +71,11 @@ the file is still reachable through the link
```
built
```

## `vtt read-link dist/pkg`

dist/pkg is still a link to store/pkg

```
store/pkg
```
Loading