diff options
author | 2023-10-14 12:58:30 -0700 | |
---|---|---|
committer | 2023-10-14 12:58:30 -0700 | |
commit | f9add8b6bea4df3cdbd56a21f17e4cab1a854e4e (patch) | |
tree | 8e5306104d81c67b771181337bba02cd9ec39453 /src/install/dependency.zig | |
parent | 81a1a58d66c598ea35c42453d0ba4c6341a940fc (diff) | |
parent | 9b5e66453b0879ed77b71dcdbe50e4efa184261e (diff) | |
download | bun-f9add8b6bea4df3cdbd56a21f17e4cab1a854e4e.tar.gz bun-f9add8b6bea4df3cdbd56a21f17e4cab1a854e4e.tar.zst bun-f9add8b6bea4df3cdbd56a21f17e4cab1a854e4e.zip |
Merge branch 'main' into sdlsdl
Diffstat (limited to 'src/install/dependency.zig')
-rw-r--r-- | src/install/dependency.zig | 160 |
1 files changed, 107 insertions, 53 deletions
diff --git a/src/install/dependency.zig b/src/install/dependency.zig index cb73c04e1..ca0d702aa 100644 --- a/src/install/dependency.zig +++ b/src/install/dependency.zig @@ -49,10 +49,10 @@ version: Dependency.Version = .{}, /// - `peerDependencies` /// Technically, having the same package name specified under multiple fields is invalid /// But we don't want to allocate extra arrays for them. So we use a bitfield instead. -behavior: Behavior = .uninitialized, +behavior: Behavior = Behavior.uninitialized, /// Sorting order for dependencies is: -/// 1. [`dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies`] +/// 1. [ `peerDependencies`, `optionalDependencies`, `devDependencies`, `dependencies` ] /// 2. name ASC /// "name" must be ASC so that later, when we rebuild the lockfile /// we insert it back in reverse order without an extra sorting pass @@ -147,7 +147,7 @@ pub fn toDependency( return Dependency{ .name = name, .name_hash = @as(u64, @bitCast(this[8..16].*)), - .behavior = @as(Dependency.Behavior, @enumFromInt(this[16])), + .behavior = @bitCast(this[16]), .version = Dependency.Version.toVersion(name, this[17..this.len].*, ctx), }; } @@ -156,7 +156,7 @@ pub fn toExternal(this: Dependency) External { var bytes: External = undefined; bytes[0..this.name.bytes.len].* = this.name.bytes; bytes[8..16].* = @as([8]u8, @bitCast(this.name_hash)); - bytes[16] = @intFromEnum(this.behavior); + bytes[16] = @bitCast(this.behavior); bytes[17..bytes.len].* = this.version.toExternal(); return bytes; } @@ -221,12 +221,16 @@ pub inline fn isGitHubRepoPath(dependency: string) bool { return hash_index != dependency.len - 1 and first_slash_index > 0 and first_slash_index != dependency.len - 1; } -// Github allows for the following format of URL: -// https://github.com/<org>/<repo>/tarball/<ref> -// This is a legacy (but still supported) method of retrieving a tarball of an -// entire source tree at some git reference. (ref = branch, tag, etc. Note: branch -// can have arbitrary number of slashes) +/// Github allows for the following format of URL: +/// https://github.com/<org>/<repo>/tarball/<ref> +/// This is a legacy (but still supported) method of retrieving a tarball of an +/// entire source tree at some git reference. (ref = branch, tag, etc. Note: branch +/// can have arbitrary number of slashes) +/// +/// This also checks for a github url that ends with ".tar.gz" pub inline fn isGitHubTarballPath(dependency: string) bool { + if (isTarball(dependency)) return true; + var parts = strings.split(dependency, "/"); var n_parts: usize = 0; @@ -248,7 +252,7 @@ pub inline fn isTarball(dependency: string) bool { } pub const Version = struct { - tag: Dependency.Version.Tag = .uninitialized, + tag: Tag = .uninitialized, literal: String = .{}, value: Value = .{ .uninitialized = {} }, @@ -610,7 +614,7 @@ pub const Version = struct { } }; - const NpmInfo = struct { + pub const NpmInfo = struct { name: String, version: Semver.Query.Group, @@ -619,7 +623,7 @@ pub const Version = struct { } }; - const TagInfo = struct { + pub const TagInfo = struct { name: String, tag: String, @@ -628,7 +632,7 @@ pub const Version = struct { } }; - const TarballInfo = struct { + pub const TarballInfo = struct { uri: URI, package_name: String = .{}, @@ -670,7 +674,8 @@ pub inline fn parse( sliced: *const SlicedString, log: ?*logger.Log, ) ?Version { - return parseWithOptionalTag(allocator, alias, dependency, null, sliced, log); + const dep = std.mem.trimLeft(u8, dependency, " \t\n\r"); + return parseWithTag(allocator, alias, dep, Version.Tag.infer(dep), sliced, log); } pub fn parseWithOptionalTag( @@ -888,6 +893,12 @@ pub fn parseWithTag( .literal = sliced.value(), .value = .{ .tarball = .{ .uri = .{ .local = sliced.sub(dependency[7..]).value() } } }, }; + } else if (strings.hasPrefixComptime(dependency, "file:")) { + return .{ + .tag = .tarball, + .literal = sliced.value(), + .value = .{ .tarball = .{ .uri = .{ .local = sliced.sub(dependency[5..]).value() } } }, + }; } else if (strings.contains(dependency, "://")) { if (log_) |log| log.addErrorFmt(null, logger.Loc.Empty, allocator, "invalid or unsupported dependency \"{s}\"", .{dependency}) catch unreachable; return null; @@ -950,78 +961,83 @@ pub fn parseWithTag( } } -pub const Behavior = enum(u8) { - uninitialized = 0, - _, +pub const Behavior = packed struct(u8) { + pub const uninitialized: Behavior = .{}; + + // these padding fields are to have compatibility + // with older versions of lockfile v2 + _unused_1: u1 = 0, + + normal: bool = false, + optional: bool = false, + dev: bool = false, + peer: bool = false, + workspace: bool = false, + + _unused_2: u2 = 0, - pub const normal: u8 = 1 << 1; - pub const optional: u8 = 1 << 2; - pub const dev: u8 = 1 << 3; - pub const peer: u8 = 1 << 4; - pub const workspace: u8 = 1 << 5; + pub const normal = Behavior{ .normal = true }; + pub const optional = Behavior{ .optional = true }; + pub const dev = Behavior{ .dev = true }; + pub const peer = Behavior{ .peer = true }; + pub const workspace = Behavior{ .workspace = true }; pub inline fn isNormal(this: Behavior) bool { - return (@intFromEnum(this) & Behavior.normal) != 0; + return this.normal; } pub inline fn isOptional(this: Behavior) bool { - return (@intFromEnum(this) & Behavior.optional) != 0 and !this.isPeer(); + return this.optional and !this.isPeer(); } pub inline fn isDev(this: Behavior) bool { - return (@intFromEnum(this) & Behavior.dev) != 0; + return this.dev; } pub inline fn isPeer(this: Behavior) bool { - return (@intFromEnum(this) & Behavior.peer) != 0; + return this.peer; } pub inline fn isWorkspace(this: Behavior) bool { - return (@intFromEnum(this) & Behavior.workspace) != 0; + return this.workspace; } pub inline fn setNormal(this: Behavior, value: bool) Behavior { - if (value) { - return @as(Behavior, @enumFromInt(@intFromEnum(this) | Behavior.normal)); - } else { - return @as(Behavior, @enumFromInt(@intFromEnum(this) & ~Behavior.normal)); - } + var b = this; + b.normal = value; + return b; } pub inline fn setOptional(this: Behavior, value: bool) Behavior { - if (value) { - return @as(Behavior, @enumFromInt(@intFromEnum(this) | Behavior.optional)); - } else { - return @as(Behavior, @enumFromInt(@intFromEnum(this) & ~Behavior.optional)); - } + var b = this; + b.optional = value; + return b; } pub inline fn setDev(this: Behavior, value: bool) Behavior { - if (value) { - return @as(Behavior, @enumFromInt(@intFromEnum(this) | Behavior.dev)); - } else { - return @as(Behavior, @enumFromInt(@intFromEnum(this) & ~Behavior.dev)); - } + var b = this; + b.dev = value; + return b; } pub inline fn setPeer(this: Behavior, value: bool) Behavior { - if (value) { - return @as(Behavior, @enumFromInt(@intFromEnum(this) | Behavior.peer)); - } else { - return @as(Behavior, @enumFromInt(@intFromEnum(this) & ~Behavior.peer)); - } + var b = this; + b.peer = value; + return b; } pub inline fn setWorkspace(this: Behavior, value: bool) Behavior { - if (value) { - return @as(Behavior, @enumFromInt(@intFromEnum(this) | Behavior.workspace)); - } else { - return @as(Behavior, @enumFromInt(@intFromEnum(this) & ~Behavior.workspace)); - } + var b = this; + b.workspace = value; + return b; + } + + pub inline fn eq(lhs: Behavior, rhs: Behavior) bool { + return @as(u8, @bitCast(lhs)) == @as(u8, @bitCast(rhs)); } pub inline fn cmp(lhs: Behavior, rhs: Behavior) std.math.Order { - if (@intFromEnum(lhs) == @intFromEnum(rhs)) { + if (eq(lhs, rhs)) { return .eq; } @@ -1074,4 +1090,42 @@ pub const Behavior = enum(u8) { (features.peer_dependencies and this.isPeer()) or this.isWorkspace(); } + + pub fn format(self: Behavior, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + const fields = std.meta.fields(Behavior); + var num_fields: u8 = 0; + inline for (fields) |f| { + if (f.type == bool and @field(self, f.name)) { + num_fields += 1; + } + } + switch (num_fields) { + 0 => try writer.writeAll("Behavior.uninitialized"), + 1 => { + inline for (fields) |f| { + if (f.type == bool and @field(self, f.name)) { + try writer.writeAll("Behavior." ++ f.name); + break; + } + } + }, + else => { + try writer.writeAll("Behavior{"); + inline for (fields) |f| { + if (f.type == bool and @field(self, f.name)) { + try writer.writeAll(" " ++ f.name); + } + } + try writer.writeAll(" }"); + }, + } + } + + comptime { + std.debug.assert(@as(u8, @bitCast(Behavior.normal)) == (1 << 1)); + std.debug.assert(@as(u8, @bitCast(Behavior.optional)) == (1 << 2)); + std.debug.assert(@as(u8, @bitCast(Behavior.dev)) == (1 << 3)); + std.debug.assert(@as(u8, @bitCast(Behavior.peer)) == (1 << 4)); + std.debug.assert(@as(u8, @bitCast(Behavior.workspace)) == (1 << 5)); + } }; |