diff options
Diffstat (limited to '')
-rw-r--r-- | src/install/extract_tarball.zig | 4 | ||||
-rw-r--r-- | src/install/install.zig | 58 | ||||
-rw-r--r-- | src/install/lockfile.zig | 19 | ||||
-rw-r--r-- | src/install/npm.zig | 40 | ||||
-rw-r--r-- | src/install/resolution.zig | 15 | ||||
-rw-r--r-- | src/install/versioned_url.zig | 31 |
6 files changed, 124 insertions, 43 deletions
diff --git a/src/install/extract_tarball.zig b/src/install/extract_tarball.zig index fe50aa734..8dea0dfba 100644 --- a/src/install/extract_tarball.zig +++ b/src/install/extract_tarball.zig @@ -20,8 +20,8 @@ cache_dir: std.fs.Dir, temp_dir: std.fs.Dir, package_id: PackageID, skip_verify: bool = false, - integrity: Integrity = Integrity{}, +url: string = "", pub inline fn run(this: ExtractTarball, bytes: []const u8) !string { if (!this.skip_verify and this.integrity.tag.isSupported()) { @@ -220,7 +220,7 @@ fn extract(this: *const ExtractTarball, tgz_bytes: []const u8) !string { Output.flush(); } } - var folder_name = PackageManager.instance.cachedNPMPackageFolderNamePrint(&abs_buf2, name, this.resolution.value.npm); + var folder_name = PackageManager.instance.cachedNPMPackageFolderNamePrint(&abs_buf2, name, this.resolution.value.npm.version); if (folder_name.len == 0 or (folder_name.len == 1 and folder_name[0] == '/')) @panic("Tried to delete root and stopped it"); var cache_dir = this.cache_dir; cache_dir.deleteTree(folder_name) catch {}; diff --git a/src/install/install.zig b/src/install/install.zig index f8e0eb4c3..3f5f7a88f 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -358,12 +358,16 @@ const NetworkTask = struct { tarball: ExtractTarball, scope: *const Npm.Registry.Scope, ) !void { - this.url_buf = try ExtractTarball.buildURL( - scope.url.href, - tarball.name, - tarball.resolution.value.npm, - PackageManager.instance.lockfile.buffers.string_bytes.items, - ); + if (tarball.url.len == 0) { + this.url_buf = try ExtractTarball.buildURL( + scope.url.href, + tarball.name, + tarball.resolution.value.npm.version, + PackageManager.instance.lockfile.buffers.string_bytes.items, + ); + } else { + this.url_buf = tarball.url; + } this.request_buffer = try MutableString.init(allocator, 0); this.response_buffer = try MutableString.init(allocator, 0); @@ -379,7 +383,6 @@ const NetworkTask = struct { header_builder.content.cap += "Basic ".len + scope.auth.len; } - var header_entries = header_builder.entries; var header_buf: string = ""; if (header_builder.header_count > 0) { try header_builder.allocate(allocator); @@ -389,13 +392,15 @@ const NetworkTask = struct { } else if (scope.auth.len > 0) { header_builder.appendFmt("Authorization", "Basic {s}", .{scope.auth}); } + + header_buf = header_builder.content.ptr.?[0..header_builder.content.len]; } this.http = try AsyncHTTP.init( allocator, .GET, URL.parse(this.url_buf), - header_entries, + header_builder.entries, header_buf, &this.response_buffer, &this.request_buffer, @@ -445,6 +450,8 @@ pub const Features = struct { .optional_dependencies = true, }; + pub const tarball = npm; + pub const npm_manifest = Features{ .optional_dependencies = true, }; @@ -1300,7 +1307,7 @@ pub const PackageManager = struct { return .done; } - const folder_path = manager.cachedNPMPackageFolderName(this.name.slice(lockfile.buffers.string_bytes.items), this.resolution.value.npm); + const folder_path = manager.cachedNPMPackageFolderName(this.name.slice(lockfile.buffers.string_bytes.items), this.resolution.value.npm.version); if (manager.isFolderInCache(folder_path)) { manager.setPreinstallState(this.meta.id, lockfile, .done); return .done; @@ -1556,7 +1563,12 @@ pub const PackageManager = struct { if (behavior.isPeer()) version else null, .{ .tag = .npm, - .value = .{ .npm = find_result.version }, + .value = .{ + .npm = .{ + .version = find_result.version, + .url = find_result.package.tarball_url.value, + }, + }, }, )) |id| { this.lockfile.buffers.resolutions.items[dependency_id] = id; @@ -1606,10 +1618,10 @@ pub const PackageManager = struct { const task_id = Task.Id.forNPMPackage( Task.Tag.extract, name.slice(this.lockfile.buffers.string_bytes.items), - package.resolution.value.npm, + package.resolution.value.npm.version, ); - var network_task = (try this.generateNetworkTaskForTarball(task_id, package)).?; + var network_task = (try this.generateNetworkTaskForTarball(task_id, manifest.str(find_result.package.tarball_url), package)).?; return ResolvedPackageResult{ .package = package, @@ -1623,7 +1635,7 @@ pub const PackageManager = struct { return ResolvedPackageResult{ .package = package }; } - pub fn generateNetworkTaskForTarball(this: *PackageManager, task_id: u64, package: Lockfile.Package) !?*NetworkTask { + pub fn generateNetworkTaskForTarball(this: *PackageManager, task_id: u64, url: string, package: Lockfile.Package) !?*NetworkTask { const dedupe_entry = try this.network_dedupe_map.getOrPut(this.allocator, task_id); if (dedupe_entry.found_existing) return null; @@ -1656,6 +1668,7 @@ pub const PackageManager = struct { .registry = scope.url.href, .package_id = package.meta.id, .integrity = package.meta.integrity, + .url = url, }, scope, ); @@ -4171,7 +4184,7 @@ pub const PackageManager = struct { if (this.manager.task_queue.fetchRemove(Task.Id.forNPMPackage( Task.Tag.extract, name, - resolution.value.npm, + resolution.value.npm.version, ))) |removed| { var callbacks = removed.value; defer callbacks.deinit(this.manager.allocator); @@ -4214,7 +4227,7 @@ pub const PackageManager = struct { switch (resolution.tag) { .npm => { - installer.cache_dir_subpath = this.manager.cachedNPMPackageFolderName(name, resolution.value.npm); + installer.cache_dir_subpath = this.manager.cachedNPMPackageFolderName(name, resolution.value.npm.version); installer.cache_dir = this.manager.getCacheDirectory(); }, .folder => { @@ -4304,7 +4317,10 @@ pub const PackageManager = struct { }, .fail => |cause| { if (cause.isPackageMissingFromCache()) { - const task_id = Task.Id.forNPMPackage(Task.Tag.extract, name, resolution.value.npm); + std.debug.assert(resolution.tag == .npm); + std.debug.assert(resolution.value.npm.url.len() > 0); + + const task_id = Task.Id.forNPMPackage(Task.Tag.extract, name, resolution.value.npm.version); var task_queue = this.manager.task_queue.getOrPut(this.manager.allocator, task_id) catch unreachable; if (!task_queue.found_existing) { task_queue.value_ptr.* = .{}; @@ -4317,10 +4333,12 @@ pub const PackageManager = struct { }, ) catch unreachable; - if (this.manager.generateNetworkTaskForTarball(task_id, this.lockfile.packages.get(package_id)) catch unreachable) |task| { - task.schedule(&this.manager.network_tarball_batch); - if (this.manager.network_tarball_batch.len > 0) { - _ = this.manager.scheduleNetworkTasks(); + if (!task_queue.found_existing) { + if (this.manager.generateNetworkTaskForTarball(task_id, resolution.value.npm.url.slice(buf), this.lockfile.packages.get(package_id)) catch unreachable) |task| { + task.schedule(&this.manager.network_tarball_batch); + if (this.manager.network_tarball_batch.len > 0) { + _ = this.manager.scheduleNetworkTasks(); + } } } } else { diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig index eb53bb763..1c66056a1 100644 --- a/src/install/lockfile.zig +++ b/src/install/lockfile.zig @@ -1503,7 +1503,7 @@ pub fn getPackageID( switch (version_.tag) { .npm => { // is it a peerDependency satisfied by a parent package? - if (version_.value.npm.satisfies(resolutions[id].value.npm)) { + if (version_.value.npm.satisfies(resolutions[id].value.npm.version)) { return id; } }, @@ -1527,7 +1527,7 @@ pub fn getPackageID( return id; } - if (can_satisfy and version.?.value.npm.satisfies(resolutions[id].value.npm)) { + if (can_satisfy and version.?.value.npm.satisfies(resolutions[id].value.npm.version)) { return id; } } @@ -2002,6 +2002,8 @@ pub const Package = extern struct { bin_extern_strings_count = package_version.bin.count(string_buf, manifest.extern_strings_bin_entries, @TypeOf(&string_builder), &string_builder); } + string_builder.count(manifest.str(package_version_ptr.tarball_url)); + try string_builder.allocate(); defer string_builder.clamp(); var extern_strings_list = &lockfile.buffers.extern_strings; @@ -2020,11 +2022,14 @@ pub const Package = extern struct { package.name = package_name.value; package.resolution = Resolution{ .value = .{ - .npm = version.clone( - manifest.string_buf, - @TypeOf(&string_builder), - &string_builder, - ), + .npm = .{ + .version = version.clone( + manifest.string_buf, + @TypeOf(&string_builder), + &string_builder, + ), + .url = string_builder.append(String, manifest.str(package_version_ptr.tarball_url)), + }, }, .tag = .npm, }; diff --git a/src/install/npm.zig b/src/install/npm.zig index 8ea89b20a..24c8fa71c 100644 --- a/src/install/npm.zig +++ b/src/install/npm.zig @@ -25,7 +25,7 @@ const ArrayIdentityContext = @import("../identity_context.zig").ArrayIdentityCon const SlicedString = Semver.SlicedString; const FileSystem = @import("../fs.zig").FileSystem; const Dependency = @import("./dependency.zig"); - +const VersionedURL = @import("./versioned_url.zig"); const VersionSlice = @import("./install.zig").VersionSlice; const ObjectPool = @import("../pool.zig").ObjectPool; const Api = @import("../api/schema.zig").Api; @@ -822,6 +822,7 @@ pub const PackageManifest = struct { var dependency_sum: usize = 0; var extern_string_count: usize = 0; var extern_string_count_bin: usize = 0; + var tarball_urls_count: usize = 0; get_versions: { if (json.asProperty("versions")) |versions_q| { if (versions_q.expr.data != .e_object) break :get_versions; @@ -840,6 +841,16 @@ pub const PackageManifest = struct { string_builder.count(version_name); + if (prop.value.?.asProperty("dist")) |dist_q| { + if (dist_q.expr.get("tarball")) |tarball_prop| { + if (tarball_prop.data == .e_string) { + const tarball = tarball_prop.data.e_string.slice(allocator); + string_builder.count(tarball); + tarball_urls_count += @as(usize, @boolToInt(tarball.len > 0)); + } + } + } + bin: { if (prop.value.?.asProperty("bin")) |bin| { switch (bin.expr.data) { @@ -925,10 +936,12 @@ pub const PackageManifest = struct { var versioned_packages = try allocator.allocAdvanced(PackageVersion, null, release_versions_len + pre_versions_len, .exact); var all_semver_versions = try allocator.allocAdvanced(Semver.Version, null, release_versions_len + pre_versions_len + dist_tags_count, .exact); - var all_extern_strings = try allocator.allocAdvanced(ExternalString, null, extern_string_count, .exact); + var all_extern_strings = try allocator.allocAdvanced(ExternalString, null, extern_string_count + tarball_urls_count, .exact); var version_extern_strings = try allocator.allocAdvanced(ExternalString, null, dependency_sum, .exact); var extern_strings_bin_entries = try allocator.allocAdvanced(ExternalString, null, extern_string_count_bin, .exact); var all_extern_strings_bin_entries = extern_strings_bin_entries; + var all_tarball_url_strings = try allocator.allocAdvanced(ExternalString, null, tarball_urls_count, .exact); + var tarball_url_strings = all_tarball_url_strings; if (versioned_packages.len > 0) { var versioned_packages_bytes = std.mem.sliceAsBytes(versioned_packages); @@ -1159,6 +1172,14 @@ pub const PackageManifest = struct { integrity: { if (prop.value.?.asProperty("dist")) |dist| { if (dist.expr.data == .e_object) { + if (dist.expr.asProperty("tarball")) |tarball_q| { + if (tarball_q.expr.data == .e_string and tarball_q.expr.data.e_string.len() > 0) { + package_version.tarball_url = string_builder.append(ExternalString, tarball_q.expr.data.e_string.slice(allocator)); + tarball_url_strings[0] = package_version.tarball_url; + tarball_url_strings = tarball_url_strings[1..]; + } + } + if (dist.expr.asProperty("fileCount")) |file_count_| { if (file_count_.expr.data == .e_number) { package_version.file_count = file_count_.expr.data.e_number.toU32(); @@ -1183,6 +1204,12 @@ pub const PackageManifest = struct { package_version.integrity = Integrity.parseSHASum(shasum_str) catch Integrity{}; } } + + if (dist.expr.asProperty("shasum")) |shasum| { + if (shasum.expr.asString(allocator)) |shasum_str| { + package_version.integrity = Integrity.parseSHASum(shasum_str) catch Integrity{}; + } + } } } } @@ -1435,7 +1462,14 @@ pub const PackageManifest = struct { result.pkg.prereleases.keys = VersionSlice.init(all_semver_versions, all_prerelease_versions); result.pkg.prereleases.values = PackageVersionList.init(versioned_packages, all_versioned_package_prereleases); - if (extern_strings.len > 0) { + if (extern_strings.len + tarball_urls_count > 0) { + var src = std.mem.sliceAsBytes(all_tarball_url_strings[0 .. all_tarball_url_strings.len - tarball_url_strings.len]); + if (src.len > 0) { + var dst = std.mem.sliceAsBytes(all_extern_strings[all_extern_strings.len - extern_strings.len ..]); + std.debug.assert(dst.len >= src.len); + @memcpy(dst.ptr, src.ptr, src.len); + } + all_extern_strings = all_extern_strings[0 .. all_extern_strings.len - extern_strings.len]; } diff --git a/src/install/resolution.zig b/src/install/resolution.zig index ad9164c88..231ff3475 100644 --- a/src/install/resolution.zig +++ b/src/install/resolution.zig @@ -7,6 +7,7 @@ const Repository = @import("./repository.zig").Repository; const string = @import("../string_types.zig").string; const ExtractTarball = @import("./extract_tarball.zig"); const strings = @import("../string_immutable.zig"); +const VersionedURL = @import("./versioned_url.zig"); pub const Resolution = extern struct { tag: Tag = Tag.uninitialized, @@ -180,14 +181,7 @@ pub const Resolution = extern struct { pub fn format(formatter: URLFormatter, comptime layout: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { switch (formatter.resolution.tag) { - .npm => try ExtractTarball.buildURLWithWriter( - @TypeOf(writer), - writer, - formatter.options.scope.url.href, - strings.StringOrTinyString.init(formatter.package_name), - formatter.resolution.value.npm, - formatter.buf, - ), + .npm => try writer.writeAll(formatter.resolution.value.npm.url.slice(formatter.buf)), .local_tarball => try writer.writeAll(formatter.resolution.value.local_tarball.slice(formatter.buf)), .git_ssh => try std.fmt.format(writer, "git+ssh://{s}", .{formatter.resolution.value.git_ssh.slice(formatter.buf)}), .git_http => try std.fmt.format(writer, "https://{s}", .{formatter.resolution.value.git_http.slice(formatter.buf)}), @@ -209,7 +203,7 @@ pub const Resolution = extern struct { pub fn format(formatter: Formatter, comptime layout: []const u8, opts: std.fmt.FormatOptions, writer: anytype) !void { switch (formatter.resolution.tag) { - .npm => try formatter.resolution.value.npm.fmt(formatter.buf).format(layout, opts, writer), + .npm => try formatter.resolution.value.npm.version.fmt(formatter.buf).format(layout, opts, writer), .local_tarball => try writer.writeAll(formatter.resolution.value.local_tarball.slice(formatter.buf)), .git_ssh => try std.fmt.format(writer, "git+ssh://{s}", .{formatter.resolution.value.git_ssh.slice(formatter.buf)}), .git_http => try std.fmt.format(writer, "https://{s}", .{formatter.resolution.value.git_http.slice(formatter.buf)}), @@ -229,7 +223,7 @@ pub const Resolution = extern struct { uninitialized: void, root: void, - npm: Semver.Version, + npm: VersionedURL, /// File path to a tarball relative to the package root local_tarball: String, @@ -258,7 +252,6 @@ pub const Resolution = extern struct { uninitialized = 0, root = 1, npm = 2, - folder = 4, local_tarball = 8, diff --git a/src/install/versioned_url.zig b/src/install/versioned_url.zig new file mode 100644 index 000000000..c52a64d97 --- /dev/null +++ b/src/install/versioned_url.zig @@ -0,0 +1,31 @@ +const Semver = @import("./semver.zig"); +const String = @import("./semver.zig").String; + +const VersionedURL = @This(); + +url: String, +version: Semver.Version, + +pub fn eql(this: VersionedURL, other: VersionedURL) bool { + return this.version.eql(other.version); +} + +pub fn order(this: VersionedURL, other: VersionedURL, lhs_buf: []const u8, rhs_buf: []const u8) @import("std").math.Order { + return this.version.order(other.version, lhs_buf, rhs_buf); +} + +pub fn fmt(this: VersionedURL, buf: []const u8) Semver.Version.Formatter { + return this.version.fmt(buf); +} + +pub fn count(this: VersionedURL, buf: []const u8, comptime Builder: type, builder: Builder) void { + this.version.count(buf, comptime Builder, builder); + builder.count(this.url.slice(buf)); +} + +pub fn clone(this: VersionedURL, buf: []const u8, comptime Builder: type, builder: Builder) VersionedURL { + return VersionedURL{ + .version = this.version.clone(buf, Builder, builder), + .url = builder.append(String, this.url.slice(buf)), + }; +} |