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
61 changes: 32 additions & 29 deletions src/install/lockfile/bun.lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,18 @@ impl<'a> TreeDepsSortCtx<'a> {
r.name.slice(self.string_buf),
)
}

fn sort(&self, dep_ids: &mut [DependencyID]) {
index_sort::sort_indices(dep_ids, &mut |a, b| {
if self.is_less_than(a, b) {
core::cmp::Ordering::Less
} else if self.is_less_than(b, a) {
core::cmp::Ordering::Greater
} else {
core::cmp::Ordering::Equal
}
});
}
}

/// The slot order every existing bun.lock has its `trustedDependencies` and
Expand Down Expand Up @@ -673,21 +685,11 @@ impl Stringifier {
tree_deps_sort_buf.clear();
tree_deps_sort_buf.extend_from_slice(dependencies);

{
let ctx = TreeDepsSortCtx {
string_buf: buf,
deps_buf,
};
index_sort::sort_indices(&mut tree_deps_sort_buf, &mut |a, b| {
if ctx.is_less_than(a, b) {
core::cmp::Ordering::Less
} else if ctx.is_less_than(b, a) {
core::cmp::Ordering::Greater
} else {
core::cmp::Ordering::Equal
}
});
TreeDepsSortCtx {
string_buf: buf,
deps_buf,
}
.sort(&mut tree_deps_sort_buf);

for &dep_id in &tree_deps_sort_buf {
let pkg_id = resolution_buf[dep_id as usize];
Expand Down Expand Up @@ -772,21 +774,11 @@ impl Stringifier {
// there might be duplicate names due to dependency behaviors,
// but we print behaviors in different groups so it won't affect
// the result
{
let ctx = TreeDepsSortCtx {
string_buf: buf,
deps_buf,
};
index_sort::sort_indices(&mut pkg_deps_sort_buf, &mut |a, b| {
if ctx.is_less_than(a, b) {
core::cmp::Ordering::Less
} else if ctx.is_less_than(b, a) {
core::cmp::Ordering::Greater
} else {
core::cmp::Ordering::Equal
}
});
TreeDepsSortCtx {
string_buf: buf,
deps_buf,
}
.sort(&mut pkg_deps_sort_buf);

// INFO = { prod/dev/optional/peer dependencies, os, cpu, libc (TODO), bin, binDir }

Expand Down Expand Up @@ -1336,9 +1328,20 @@ impl Stringifier {
any = true;
}

// Re-sort by current name: a no-alias git/tarball dep sorts under its version
// literal at parse time, and `assign_resolution` renames it without a re-sort.
Comment thread
robobun marked this conversation as resolved.
let deps_list = pkg_deps[pkg_id as usize];
let mut deps_sort_buf: Vec<DependencyID> = (deps_list.begin()..deps_list.end()).collect();
TreeDepsSortCtx {
string_buf: buf,
deps_buf,
}
.sort(&mut deps_sort_buf);

for &(group_name, group_behavior) in WORKSPACE_DEPENDENCY_GROUPS.iter() {
let mut first = true;
for dep in pkg_deps[pkg_id as usize].get(deps_buf) {
for &dep_id in &deps_sort_buf {
let dep = &deps_buf[dep_id as usize];
if !dep.behavior.intersects(group_behavior) {
continue;
}
Expand Down
33 changes: 33 additions & 0 deletions test/cli/install/bun-install-git-deps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,36 @@ test.concurrent("installs a git+file:// dependency", async () => {
expect(await lockedPackages(project)).toEqual(locked);
expect(exitCode).toBe(0);
});

// issue #40803: `bun install <git url>` (no alias) sorted the workspace dep
// under its version literal. The real name is only known once the repo is
// fetched; it is rewritten in place after resolution, so the written key
// landed at the literal's position ("git..." here, between nothing and
// "hhh-first") instead of its own.
test.concurrent("bun install <git url> sorts the workspace dependency by its resolved name", async () => {
using dir = tempDir("git-dep-sort", {
"project/package.json": JSON.stringify({
name: "project",
version: "1.0.0",
dependencies: { "hhh-first": "file:./hhh-first", "jjj-last": "file:./jjj-last" },
}),
"project/hhh-first/package.json": JSON.stringify({ name: "hhh-first", version: "1.0.0" }),
"project/jjj-last/package.json": JSON.stringify({ name: "jjj-last", version: "1.0.0" }),
});
const root = String(dir);
const project = join(root, "project");
const bare = await makeSharedRepo(root, [{ name: "iii-middle", branch: "main" }], "sort-repo.git");

const first = await runInstall(project, join(root, "cache"), {});
expect(first.stderr).toContain("Saved lockfile");
expect(first.exitCode).toBe(0);

const second = await runInstall(project, join(root, "cache"), {}, `git+${pathToFileURL(bare)}#main`);
expect(second.stderr).toContain("Saved lockfile");
expect(second.exitCode).toBe(0);

const lockfile = Bun.JSONC.parse(await Bun.file(join(project, "bun.lock")).text()) as {
workspaces: Record<string, { dependencies: Record<string, string> }>;
};
expect(Object.keys(lockfile.workspaces[""].dependencies)).toEqual(["hhh-first", "iii-middle", "jjj-last"]);
});
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,15 @@ exports[`yarn.lock migration basic migration with realistic complex yarn.lock: c
"": {
"name": "complex-app",
"dependencies": {
"@babel/core": "^7.20.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@babel/core": "^7.20.0",
"webpack": "^5.75.0",
},
"devDependencies": {
"@types/react": "^18.0.0",
"typescript": "^4.9.0",
"eslint": "^8.0.0",
"typescript": "^4.9.0",
},
"optionalDependencies": {
"fsevents": "^2.3.2",
Expand Down Expand Up @@ -3186,8 +3186,8 @@ exports[`bun pm migrate for existing yarn.lock yarn.lock with packages that have
"": {
"name": "os-cpu-test",
"dependencies": {
"fsevents": "^2.3.2",
"esbuild": "^0.17.0",
"fsevents": "^2.3.2",
},
},
},
Expand Down
Loading