mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
bun.lock migration: fix packages with long version string (#21753)
### What does this PR do? cases like `@prisma/engines-version` with version of `6.14.0-17.fba13060ef3cfbe5e95af3aaba61eabf2b8a8a20` was having issues with the version and using a "corrupted" string instead ### How did you verify your code works? --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -475,81 +475,79 @@ const DependencyType = enum {
|
||||
optional,
|
||||
peer,
|
||||
};
|
||||
const processDeps = struct {
|
||||
fn process(
|
||||
deps: bun.StringHashMap(string),
|
||||
dep_type: DependencyType,
|
||||
yarn_lock_: *YarnLock,
|
||||
string_buf_: *Semver.String.Buf,
|
||||
deps_buf: []Dependency,
|
||||
res_buf: []Install.PackageID,
|
||||
log: *logger.Log,
|
||||
manager: *Install.PackageManager,
|
||||
yarn_entry_to_package_id: []const Install.PackageID,
|
||||
) ![]Install.PackageID {
|
||||
var deps_it = deps.iterator();
|
||||
var count: usize = 0;
|
||||
var dep_spec_name_stack = std.heap.stackFallback(1024, bun.default_allocator);
|
||||
const temp_allocator = dep_spec_name_stack.get();
|
||||
fn processDeps(
|
||||
deps: bun.StringHashMap(string),
|
||||
dep_type: DependencyType,
|
||||
yarn_lock_: *YarnLock,
|
||||
string_buf_: *Semver.String.Buf,
|
||||
deps_buf: []Dependency,
|
||||
res_buf: []Install.PackageID,
|
||||
log: *logger.Log,
|
||||
manager: *Install.PackageManager,
|
||||
yarn_entry_to_package_id: []const Install.PackageID,
|
||||
) ![]Install.PackageID {
|
||||
var deps_it = deps.iterator();
|
||||
var count: usize = 0;
|
||||
var dep_spec_name_stack = std.heap.stackFallback(1024, bun.default_allocator);
|
||||
const temp_allocator = dep_spec_name_stack.get();
|
||||
|
||||
while (deps_it.next()) |dep| {
|
||||
const dep_name = dep.key_ptr.*;
|
||||
const dep_version = dep.value_ptr.*;
|
||||
const dep_spec = try std.fmt.allocPrint(
|
||||
temp_allocator,
|
||||
"{s}@{s}",
|
||||
.{ dep_name, dep_version },
|
||||
);
|
||||
defer temp_allocator.free(dep_spec);
|
||||
while (deps_it.next()) |dep| {
|
||||
const dep_name = dep.key_ptr.*;
|
||||
const dep_version = dep.value_ptr.*;
|
||||
const dep_spec = try std.fmt.allocPrint(
|
||||
temp_allocator,
|
||||
"{s}@{s}",
|
||||
.{ dep_name, dep_version },
|
||||
);
|
||||
defer temp_allocator.free(dep_spec);
|
||||
|
||||
if (yarn_lock_.findEntryBySpec(dep_spec)) |dep_entry| {
|
||||
const dep_name_hash = stringHash(dep_name);
|
||||
const dep_name_str = try string_buf_.appendWithHash(dep_name, dep_name_hash);
|
||||
if (yarn_lock_.findEntryBySpec(dep_spec)) |dep_entry| {
|
||||
const dep_name_hash = stringHash(dep_name);
|
||||
const dep_name_str = try string_buf_.appendWithHash(dep_name, dep_name_hash);
|
||||
|
||||
const parsed_version = if (YarnLock.Entry.isNpmAlias(dep_version)) blk: {
|
||||
const alias_info = YarnLock.Entry.parseNpmAlias(dep_version);
|
||||
break :blk alias_info.version;
|
||||
} else dep_version;
|
||||
const parsed_version = if (YarnLock.Entry.isNpmAlias(dep_version)) blk: {
|
||||
const alias_info = YarnLock.Entry.parseNpmAlias(dep_version);
|
||||
break :blk alias_info.version;
|
||||
} else dep_version;
|
||||
|
||||
deps_buf[count] = Dependency{
|
||||
.name = dep_name_str,
|
||||
.name_hash = dep_name_hash,
|
||||
.version = Dependency.parse(
|
||||
yarn_lock_.allocator,
|
||||
dep_name_str,
|
||||
dep_name_hash,
|
||||
parsed_version,
|
||||
&Semver.SlicedString.init(parsed_version, parsed_version),
|
||||
log,
|
||||
manager,
|
||||
) orelse Dependency.Version{},
|
||||
.behavior = .{
|
||||
.prod = dep_type == .production,
|
||||
.optional = dep_type == .optional,
|
||||
.dev = dep_type == .development,
|
||||
.peer = dep_type == .peer,
|
||||
.workspace = dep_entry.workspace,
|
||||
},
|
||||
};
|
||||
var found_package_id: ?Install.PackageID = null;
|
||||
outer: for (yarn_lock_.entries.items, 0..) |entry_, yarn_idx| {
|
||||
for (entry_.specs) |entry_spec| {
|
||||
if (strings.eql(entry_spec, dep_spec)) {
|
||||
found_package_id = yarn_entry_to_package_id[yarn_idx];
|
||||
break :outer;
|
||||
}
|
||||
deps_buf[count] = Dependency{
|
||||
.name = dep_name_str,
|
||||
.name_hash = dep_name_hash,
|
||||
.version = Dependency.parse(
|
||||
yarn_lock_.allocator,
|
||||
dep_name_str,
|
||||
dep_name_hash,
|
||||
parsed_version,
|
||||
&Semver.SlicedString.init(parsed_version, parsed_version),
|
||||
log,
|
||||
manager,
|
||||
) orelse Dependency.Version{},
|
||||
.behavior = .{
|
||||
.prod = dep_type == .production,
|
||||
.optional = dep_type == .optional,
|
||||
.dev = dep_type == .development,
|
||||
.peer = dep_type == .peer,
|
||||
.workspace = dep_entry.workspace,
|
||||
},
|
||||
};
|
||||
var found_package_id: ?Install.PackageID = null;
|
||||
outer: for (yarn_lock_.entries.items, 0..) |entry_, yarn_idx| {
|
||||
for (entry_.specs) |entry_spec| {
|
||||
if (strings.eql(entry_spec, dep_spec)) {
|
||||
found_package_id = yarn_entry_to_package_id[yarn_idx];
|
||||
break :outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_package_id) |pkg_id| {
|
||||
res_buf[count] = pkg_id;
|
||||
count += 1;
|
||||
}
|
||||
if (found_package_id) |pkg_id| {
|
||||
res_buf[count] = pkg_id;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return res_buf[0..count];
|
||||
}
|
||||
}.process;
|
||||
return res_buf[0..count];
|
||||
}
|
||||
|
||||
pub fn migrateYarnLockfile(
|
||||
this: *Lockfile,
|
||||
@@ -956,9 +954,8 @@ pub fn migrateYarnLockfile(
|
||||
});
|
||||
}
|
||||
|
||||
const version = entry.version;
|
||||
const sliced_version = Semver.SlicedString.init(version, version);
|
||||
const result = Semver.Version.parse(sliced_version);
|
||||
const version = try string_buf.append(entry.version);
|
||||
const result = Semver.Version.parse(version.sliced(this.buffers.string_bytes.items));
|
||||
if (!result.valid) {
|
||||
break :blk Resolution{};
|
||||
}
|
||||
@@ -1033,6 +1030,7 @@ pub fn migrateYarnLockfile(
|
||||
if (found_idx) |idx| {
|
||||
const name_hash = stringHash(dep.name);
|
||||
const dep_name_string = try string_buf.appendWithHash(dep.name, name_hash);
|
||||
const version_string = try string_buf.append(dep.version);
|
||||
|
||||
dependencies_buf[actual_root_dep_count] = Dependency{
|
||||
.name = dep_name_string,
|
||||
@@ -1041,8 +1039,8 @@ pub fn migrateYarnLockfile(
|
||||
allocator,
|
||||
dep_name_string,
|
||||
name_hash,
|
||||
dep.version,
|
||||
&Semver.SlicedString.init(dep.version, dep.version),
|
||||
version_string.slice(this.buffers.string_bytes.items),
|
||||
&version_string.sliced(this.buffers.string_bytes.items),
|
||||
log,
|
||||
manager,
|
||||
) orelse Dependency.Version{},
|
||||
|
||||
@@ -51,6 +51,180 @@ is-number@^7.0.0:
|
||||
expect(bunLockContent).toMatchSnapshot("simple-yarn-migration");
|
||||
});
|
||||
|
||||
test("yarn.lock with packages containing long build tags", async () => {
|
||||
const tempDir = tempDirWithFiles("yarn-migration-build-tags", {
|
||||
"package.json": JSON.stringify(
|
||||
{
|
||||
name: "build-tags-test",
|
||||
version: "1.0.0",
|
||||
dependencies: {
|
||||
"@prisma/engines-version": "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81",
|
||||
"@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
|
||||
"@babel/preset-modules": "0.1.6-no-external-plugins",
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
"yarn.lock": `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
|
||||
version "7.21.0-placeholder-for-preset-env.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
|
||||
integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
|
||||
|
||||
"@babel/preset-modules@0.1.6-no-external-plugins":
|
||||
version "0.1.6-no-external-plugins"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a"
|
||||
integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.0.0"
|
||||
"@babel/types" "^7.4.4"
|
||||
esutils "^2.0.2"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.0.0":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295"
|
||||
integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==
|
||||
|
||||
"@babel/types@^7.4.4":
|
||||
version "7.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#61c5b592274a82bb7addc5073ee1d989799e75e4"
|
||||
integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.22.5"
|
||||
"@babel/helper-validator-identifier" "^7.22.20"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/helper-string-parser@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
|
||||
integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.22.20":
|
||||
version "7.22.20"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
|
||||
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
|
||||
|
||||
"@prisma/engines-version@4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81":
|
||||
version "4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81.tgz#5512069ca14c44af7f38e7c39d9a169480e63a33"
|
||||
integrity sha512-q617EUWfRIDTriWADZ4YiWRZXCa/WuhNgLTVd+HqWLffjMSPzyM5uOWoauX91wvQClSKZU4pzI4JJLQ9Kl62Qg==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
|
||||
|
||||
to-fast-properties@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
|
||||
`,
|
||||
});
|
||||
|
||||
// Run bun pm migrate
|
||||
const migrateResult = await Bun.spawn({
|
||||
cmd: [bunExe(), "pm", "migrate", "-f"],
|
||||
cwd: tempDir,
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdin: "ignore",
|
||||
});
|
||||
|
||||
const [stdout, stderr, exitCode] = await Promise.all([
|
||||
new Response(migrateResult.stdout).text(),
|
||||
new Response(migrateResult.stderr).text(),
|
||||
migrateResult.exited,
|
||||
]);
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(fs.existsSync(join(tempDir, "bun.lock"))).toBe(true);
|
||||
|
||||
const bunLockContent = fs.readFileSync(join(tempDir, "bun.lock"), "utf8");
|
||||
|
||||
// Verify that long build tags are preserved correctly
|
||||
expect(bunLockContent).toContain("4.16.1-1.4bc8b6e1b66cb932731fb1bdbbc550d1e010de81");
|
||||
expect(bunLockContent).toContain("7.21.0-placeholder-for-preset-env.2");
|
||||
expect(bunLockContent).toContain("0.1.6-no-external-plugins");
|
||||
|
||||
// Ensure no corrupted version strings
|
||||
expect(bunLockContent).not.toContain("monoreporeact");
|
||||
expect(bunLockContent).not.toContain("@types/react");
|
||||
expect(bunLockContent).not.toContain("<22>");
|
||||
|
||||
// Install should work after migration
|
||||
const installResult = await Bun.spawn({
|
||||
cmd: [bunExe(), "install"],
|
||||
cwd: tempDir,
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdin: "ignore",
|
||||
});
|
||||
|
||||
const installExitCode = await installResult.exited;
|
||||
expect(installExitCode).toBe(0);
|
||||
});
|
||||
|
||||
test("yarn.lock with extremely long build tags (regression test)", async () => {
|
||||
const tempDir = tempDirWithFiles("yarn-migration-extreme-build-tags", {
|
||||
"package.json": JSON.stringify(
|
||||
{
|
||||
name: "extreme-build-tags-test",
|
||||
version: "1.0.0",
|
||||
dependencies: {
|
||||
"test-package":
|
||||
"1.0.0-alpha.beta.gamma.delta.epsilon.zeta.eta.theta.iota.kappa.lambda.mu.nu.xi.omicron.pi.rho.sigma.tau.upsilon.phi.chi.psi.omega.0123456789abcdef",
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
"yarn.lock": `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
test-package@1.0.0-alpha.beta.gamma.delta.epsilon.zeta.eta.theta.iota.kappa.lambda.mu.nu.xi.omicron.pi.rho.sigma.tau.upsilon.phi.chi.psi.omega.0123456789abcdef:
|
||||
version "1.0.0-alpha.beta.gamma.delta.epsilon.zeta.eta.theta.iota.kappa.lambda.mu.nu.xi.omicron.pi.rho.sigma.tau.upsilon.phi.chi.psi.omega.0123456789abcdef"
|
||||
resolved "https://registry.yarnpkg.com/test-package/-/test-package-1.0.0-alpha.beta.gamma.delta.epsilon.zeta.eta.theta.iota.kappa.lambda.mu.nu.xi.omicron.pi.rho.sigma.tau.upsilon.phi.chi.psi.omega.0123456789abcdef.tgz#abc123"
|
||||
integrity sha512-xjEohWws8kKwCqz1IbvMrLynEfS7pFdO0CwjbPvzkt+rpL6tpnAKHS0N8d6diEBSp2BAIkUENc6H6H9SEqf0uA==
|
||||
`,
|
||||
});
|
||||
|
||||
// Run bun pm migrate
|
||||
const migrateResult = await Bun.spawn({
|
||||
cmd: [bunExe(), "pm", "migrate", "-f"],
|
||||
cwd: tempDir,
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdin: "ignore",
|
||||
});
|
||||
|
||||
const exitCode = await migrateResult.exited;
|
||||
expect(exitCode).toBe(0);
|
||||
|
||||
const bunLockPath = join(tempDir, "bun.lock");
|
||||
expect(fs.existsSync(bunLockPath)).toBe(true);
|
||||
|
||||
const bunLockContent = fs.readFileSync(bunLockPath, "utf8");
|
||||
|
||||
// The entire long version string should be preserved
|
||||
const expectedVersion =
|
||||
"1.0.0-alpha.beta.gamma.delta.epsilon.zeta.eta.theta.iota.kappa.lambda.mu.nu.xi.omicron.pi.rho.sigma.tau.upsilon.phi.chi.psi.omega.0123456789abcdef";
|
||||
expect(bunLockContent).toContain(expectedVersion);
|
||||
|
||||
// Should not contain any corruption artifacts
|
||||
expect(bunLockContent).not.toContain("<22>");
|
||||
expect(bunLockContent).not.toContain("\0");
|
||||
expect(bunLockContent).not.toContain("undefined");
|
||||
expect(bunLockContent).not.toContain("null");
|
||||
});
|
||||
|
||||
test("complex yarn.lock with multiple dependencies and versions", async () => {
|
||||
const tempDir = tempDirWithFiles("yarn-migration-complex", {
|
||||
"package.json": JSON.stringify(
|
||||
|
||||
Reference in New Issue
Block a user