diff options
Diffstat (limited to 'src/install/install.zig')
-rw-r--r-- | src/install/install.zig | 139 |
1 files changed, 119 insertions, 20 deletions
diff --git a/src/install/install.zig b/src/install/install.zig index 57ef430c1..9fba86e7d 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1759,7 +1759,7 @@ pub const PackageManager = struct { package_json_updates: []UpdateRequest = &[_]UpdateRequest{}, // used for looking up workspaces that aren't loaded into Lockfile.workspace_paths - workspaces: std.StringArrayHashMap(?Semver.Version), + workspaces: std.StringArrayHashMap(Semver.Version), // progress bar stuff when not stack allocated root_progress_node: *std.Progress.Node = undefined, @@ -1802,7 +1802,7 @@ pub const PackageManager = struct { onWake: WakeHandler = .{}, ci_mode: bun.LazyBool(computeIsContinuousIntegration, @This(), "ci_mode") = .{}, - peer_dependencies: std.ArrayListUnmanaged(DependencyID) = .{}, + peer_dependencies: std.fifo.LinearFifo(DependencyID, .Dynamic) = std.fifo.LinearFifo(DependencyID, .Dynamic).init(default_allocator), // name hash from alias package name -> aliased package dependency version info known_npm_aliases: NpmAliasMap = .{}, @@ -2539,7 +2539,7 @@ pub const PackageManager = struct { Semver.Version.sortGt, ); for (installed_versions.items) |installed_version| { - if (version.value.npm.version.satisfies(installed_version)) { + if (version.value.npm.version.satisfies(installed_version, this.lockfile.buffers.string_bytes.items)) { var buf: [bun.MAX_PATH_BYTES]u8 = undefined; var npm_package_path = this.pathForCachedNPMPath(&buf, package_name, installed_version) catch |err| { Output.debug("error getting path for cached npm path: {s}", .{bun.span(@errorName(err))}); @@ -2600,7 +2600,7 @@ pub const PackageManager = struct { // Was this package already allocated? Let's reuse the existing one. if (this.lockfile.getPackageID( name_hash, - if (behavior.isPeer() and !install_peer) version else null, + if (this.to_update) null else version, &.{ .tag = .npm, .value = .{ @@ -2748,6 +2748,23 @@ pub const PackageManager = struct { } } + fn resolutionSatisfiesDependency(this: *PackageManager, resolution: Resolution, dependency: Dependency.Version) bool { + const buf = this.lockfile.buffers.string_bytes.items; + if (resolution.tag == .npm and dependency.tag == .npm) { + return dependency.value.npm.version.satisfies(resolution.value.npm.version, buf); + } + + if (resolution.tag == .git and dependency.tag == .git) { + return resolution.value.git.eql(&dependency.value.git, buf, buf); + } + + if (resolution.tag == .github and dependency.tag == .github) { + return resolution.value.github.eql(&dependency.value.github, buf, buf); + } + + return false; + } + fn getOrPutResolvedPackage( this: *PackageManager, name_hash: PackageNameHash, @@ -2765,12 +2782,57 @@ pub const PackageManager = struct { return .{ .package = this.lockfile.packages.get(resolution) }; } + if (install_peer and behavior.isPeer()) { + if (this.lockfile.package_index.get(name_hash)) |index| { + const resolutions: []Resolution = this.lockfile.packages.items(.resolution); + switch (index) { + .PackageID => |existing_id| { + if (existing_id < resolutions.len) { + const res_tag = resolutions[existing_id].tag; + const ver_tag = version.tag; + if ((res_tag == .npm and ver_tag == .npm) or (res_tag == .git and ver_tag == .git) or (res_tag == .github and ver_tag == .github)) { + successFn(this, dependency_id, existing_id); + return .{ + .package = this.lockfile.packages.get(existing_id), + }; + } + } + }, + .PackageIDMultiple => |list| { + for (list.items) |existing_id| { + if (existing_id < resolutions.len) { + const existing_resolution = resolutions[existing_id]; + if (this.resolutionSatisfiesDependency(existing_resolution, version)) { + successFn(this, dependency_id, existing_id); + return .{ + .package = this.lockfile.packages.get(existing_id), + }; + } + } + } + + if (list.items[0] < resolutions.len) { + const res_tag = resolutions[list.items[0]].tag; + const ver_tag = version.tag; + if ((res_tag == .npm and ver_tag == .npm) or (res_tag == .git and ver_tag == .git) or (res_tag == .github and ver_tag == .github)) { + successFn(this, dependency_id, list.items[0]); + return .{ + .package = this.lockfile.packages.get(list.items[0]), + }; + } + } + }, + } + } + } + switch (version.tag) { .npm, .dist_tag => { if (version.tag == .npm) { if (this.lockfile.workspace_versions.count() > 0) resolve_from_workspace: { if (this.lockfile.workspace_versions.get(name_hash)) |workspace_version| { - if (version.value.npm.version.satisfies(workspace_version)) { + const buf = this.lockfile.buffers.string_bytes.items; + if (version.value.npm.version.satisfies(workspace_version, buf)) { const root_package = this.lockfile.rootPackage() orelse break :resolve_from_workspace; const root_dependencies = root_package.dependencies.get(this.lockfile.buffers.dependencies.items); const root_resolutions = root_package.resolutions.get(this.lockfile.buffers.resolutions.items); @@ -2778,7 +2840,7 @@ pub const PackageManager = struct { for (root_dependencies, root_resolutions) |root_dep, workspace_package_id| { if (workspace_package_id != invalid_package_id and root_dep.version.tag == .workspace and root_dep.name_hash == name_hash) { // make sure verifyResolutions sees this resolution as a valid package id - this.lockfile.buffers.resolutions.items[dependency_id] = workspace_package_id; + successFn(this, dependency_id, workspace_package_id); return .{ .package = this.lockfile.packages.get(workspace_package_id), .is_first_time = false, @@ -3121,11 +3183,12 @@ pub const PackageManager = struct { if (dependency.version.tag == .npm) { if (this.known_npm_aliases.get(name_hash)) |aliased| { const group = dependency.version.value.npm.version; + const buf = this.lockfile.buffers.string_bytes.items; var curr_list: ?*const Semver.Query.List = &aliased.value.npm.version.head; while (curr_list) |queries| { var curr: ?*const Semver.Query = &queries.head; while (curr) |query| { - if (group.satisfies(query.range.left.version) or group.satisfies(query.range.right.version)) { + if (group.satisfies(query.range.left.version, buf) or group.satisfies(query.range.right.version, buf)) { name = aliased.value.npm.name; name_hash = String.Builder.stringHash(this.lockfile.str(&name)); break :version aliased; @@ -3363,13 +3426,13 @@ pub const PackageManager = struct { this.allocator, this.scopeForPackageName(name_str), loaded_manifest, - dependency.behavior.isOptional() or dependency.behavior.isPeer(), + dependency.behavior.isOptional() or !this.options.do.install_peer_dependencies, ); this.enqueueNetworkTask(network_task); } } else { if (this.options.do.install_peer_dependencies and !dependency.behavior.isOptionalPeer()) { - try this.peer_dependencies.append(this.allocator, id); + try this.peer_dependencies.writeItem(id); } } @@ -3439,7 +3502,14 @@ pub const PackageManager = struct { try entry.value_ptr.append(this.allocator, ctx); } - if (dependency.behavior.isPeer()) return; + if (dependency.behavior.isPeer()) { + if (!install_peer) { + if (this.options.do.install_peer_dependencies and !dependency.behavior.isOptionalPeer()) { + try this.peer_dependencies.writeItem(id); + } + return; + } + } const network_entry = try this.network_dedupe_map.getOrPutContext(this.allocator, checkout_id, .{}); if (network_entry.found_existing) return; @@ -3503,7 +3573,15 @@ pub const PackageManager = struct { const callback_tag = comptime if (successFn == assignRootResolution) "root_dependency" else "dependency"; try entry.value_ptr.append(this.allocator, @unionInit(TaskCallbackContext, callback_tag, id)); - if (dependency.behavior.isPeer()) return; + if (dependency.behavior.isPeer()) { + if (!install_peer) { + if (this.options.do.install_peer_dependencies and !dependency.behavior.isOptionalPeer()) { + try this.peer_dependencies.writeItem(id); + } + return; + } + } + if (try this.generateNetworkTaskForTarball(task_id, url, id, .{ .name = dependency.name, .name_hash = dependency.name_hash, @@ -3675,7 +3753,15 @@ pub const PackageManager = struct { const callback_tag = comptime if (successFn == assignRootResolution) "root_dependency" else "dependency"; try entry.value_ptr.append(this.allocator, @unionInit(TaskCallbackContext, callback_tag, id)); - if (dependency.behavior.isPeer()) return; + if (dependency.behavior.isPeer()) { + if (!install_peer) { + if (this.options.do.install_peer_dependencies and !dependency.behavior.isOptionalPeer()) { + try this.peer_dependencies.writeItem(id); + } + return; + } + } + switch (version.value.tarball.uri) { .local => { const network_entry = try this.network_dedupe_map.getOrPutContext(this.allocator, task_id, .{}); @@ -3878,10 +3964,10 @@ pub const PackageManager = struct { fn processPeerDependencyList( this: *PackageManager, ) !void { - while (this.peer_dependencies.popOrNull()) |peer_dependency_id| { - try this.processDependencyListItem(.{ .dependency = peer_dependency_id }, null, true); + while (this.peer_dependencies.readItem()) |peer_dependency_id| { const dependency = this.lockfile.buffers.dependencies.items[peer_dependency_id]; const resolution = this.lockfile.buffers.resolutions.items[peer_dependency_id]; + try this.enqueueDependencyWithMain( peer_dependency_id, &dependency, @@ -4298,7 +4384,13 @@ pub const PackageManager = struct { var dependency_list = dependency_list_entry.value_ptr.*; dependency_list_entry.value_ptr.* = .{}; - try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks, install_peer); + try manager.processDependencyList( + dependency_list, + ExtractCompletionContext, + extract_ctx, + callbacks, + install_peer, + ); continue; } @@ -5712,9 +5804,16 @@ pub const PackageManager = struct { } else |_| {} } - var workspaces = std.StringArrayHashMap(?Semver.Version).init(ctx.allocator); + var workspaces = std.StringArrayHashMap(Semver.Version).init(ctx.allocator); for (workspace_names.values()) |entry| { - try workspaces.put(entry.name, entry.version); + if (entry.version) |version_string| { + const sliced_version = SlicedString.init(version_string, version_string); + const result = Semver.Version.parse(sliced_version); + if (result.valid and result.wildcard == .none) { + try workspaces.put(entry.name, result.version.fill()); + continue; + } + } } workspace_names.map.deinit(); @@ -5816,7 +5915,7 @@ pub const PackageManager = struct { .lockfile = undefined, .root_package_json_file = undefined, .waiter = if (Environment.isPosix) try Waker.init(allocator) else bun.uws.Loop.get(), - .workspaces = std.StringArrayHashMap(?Semver.Version).init(allocator), + .workspaces = std.StringArrayHashMap(Semver.Version).init(allocator), }; manager.lockfile = try allocator.create(Lockfile); @@ -8196,7 +8295,7 @@ pub const PackageManager = struct { manager.drainDependencyList(); } - if (manager.pending_tasks > 0 or manager.peer_dependencies.items.len > 0) { + if (manager.pending_tasks > 0 or manager.peer_dependencies.readableLength() > 0) { if (root.dependencies.len > 0) { _ = manager.getCacheDirectory(); _ = manager.getTemporaryDirectory(); @@ -8233,7 +8332,7 @@ pub const PackageManager = struct { } if (manager.options.do.install_peer_dependencies) { - while (manager.pending_tasks > 0 or manager.peer_dependencies.items.len > 0) { + while (manager.pending_tasks > 0 or manager.peer_dependencies.readableLength() > 0) { try manager.processPeerDependencyList(); manager.drainDependencyList(); |