aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.zig23
-rw-r--r--src/install/install.zig40
-rw-r--r--src/install/lockfile.zig46
3 files changed, 95 insertions, 14 deletions
diff --git a/src/bun.zig b/src/bun.zig
index 790ec5d04..c7b15340e 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -1841,3 +1841,26 @@ pub fn fdi32(fd_: anytype) i32 {
}
pub const OSPathSlice = if (Environment.isWindows) [:0]const u16 else [:0]const u8;
+pub const LazyBoolValue = enum {
+ unknown,
+ no,
+ yes,
+};
+/// Create a lazily computed boolean value.
+/// Getter must be a function that takes a pointer to the parent struct and returns a boolean.
+/// Parent must be a type which contains the field we are getting.
+pub fn LazyBool(comptime Getter: anytype, comptime Parent: type, comptime field: string) type {
+ return struct {
+ value: LazyBoolValue = .unknown,
+ pub fn get(self: *@This()) bool {
+ if (self.value == .unknown) {
+ self.value = switch (Getter(@fieldParentPtr(Parent, field, self))) {
+ true => .yes,
+ false => .no,
+ };
+ }
+
+ return self.value == .yes;
+ }
+ };
+}
diff --git a/src/install/install.zig b/src/install/install.zig
index 3757a6980..28a96643d 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -1697,6 +1697,7 @@ pub const PackageManager = struct {
wait_count: std.atomic.Atomic(usize) = std.atomic.Atomic(usize).init(0),
onWake: WakeHandler = .{},
+ ci_mode: bun.LazyBool(computeIsContinuousIntegration, @This(), "ci_mode") = .{},
const PreallocatedNetworkTasks = std.BoundedArray(NetworkTask, 1024);
const NetworkTaskQueue = std.HashMapUnmanaged(u64, void, IdentityContext(u64), 80);
@@ -1717,6 +1718,14 @@ pub const PackageManager = struct {
return this.env.getTLSRejectUnauthorized();
}
+ pub fn computeIsContinuousIntegration(this: *PackageManager) bool {
+ return this.env.isCI();
+ }
+
+ pub inline fn isContinuousIntegration(this: *PackageManager) bool {
+ return this.ci_mode.get();
+ }
+
pub const WakeHandler = struct {
// handler: fn (ctx: *anyopaque, pm: *PackageManager) void = undefined,
// onDependencyError: fn (ctx: *anyopaque, Dependency, PackageID, anyerror) void = undefined,
@@ -1886,6 +1895,37 @@ pub const PackageManager = struct {
@memset(this.preinstall_state.items[offset..], PreinstallState.unknown);
}
+ pub fn laterVersionInCache(this: *PackageManager, name: []const u8, name_hash: PackageNameHash, resolution: Resolution) ?Semver.Version {
+ switch (resolution.tag) {
+ Resolution.Tag.npm => {
+ if (resolution.value.npm.version.tag.hasPre())
+ // TODO:
+ return null;
+
+ const manifest: *const Npm.PackageManifest = this.manifests.getPtr(name_hash) orelse brk: {
+ // We skip this in CI because we don't want any performance impact in an environment you'll probably never use
+ if (this.isContinuousIntegration())
+ return null;
+
+ if (Npm.PackageManifest.Serializer.load(this.allocator, this.getCacheDirectory(), name) catch null) |manifest_| {
+ this.manifests.put(this.allocator, name_hash, manifest_) catch return null;
+ break :brk this.manifests.getPtr(name_hash).?;
+ }
+
+ return null;
+ };
+
+ if (manifest.findByDistTag("latest")) |latest_version| {
+ if (latest_version.version.order(resolution.value.npm.version, this.lockfile.buffers.string_bytes.items, this.lockfile.buffers.string_bytes.items) != .gt) return null;
+ return latest_version.version;
+ }
+
+ return null;
+ },
+ else => return null,
+ }
+ }
+
pub fn setPreinstallState(this: *PackageManager, package_id: PackageID, lockfile: *Lockfile, value: PreinstallState) void {
this.ensurePreinstallStateListCapacity(lockfile.packages.len) catch return;
this.preinstall_state.items[package_id] = value;
diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig
index a3e51f59f..fd742d559 100644
--- a/src/install/lockfile.zig
+++ b/src/install/lockfile.zig
@@ -1057,21 +1057,39 @@ pub const Printer = struct {
if (!installed.isSet(package_id)) continue;
- const fmt = comptime brk: {
- if (enable_ansi_colors) {
- break :brk Output.prettyFmt("<r> <green>+<r> <b>{s}<r><d>@{}<r>\n", enable_ansi_colors);
- } else {
- break :brk Output.prettyFmt("<r> + {s}<r><d>@{}<r>\n", enable_ansi_colors);
- }
- };
+ if (PackageManager.instance.laterVersionInCache(package_name, dependency.name_hash, resolved[package_id])) |later_version| {
+ const fmt = comptime brk: {
+ if (enable_ansi_colors) {
+ break :brk Output.prettyFmt("<r> <green>+<r> <b>{s}<r><d>@{}<r> <d>(<blue>v{} available<r><d>)<r>\n", enable_ansi_colors);
+ } else {
+ break :brk Output.prettyFmt("<r> + {s}<r><d>@{}<r> <d>(v{} available)<r>\n", enable_ansi_colors);
+ }
+ };
+ try writer.print(
+ fmt,
+ .{
+ package_name,
+ resolved[package_id].fmt(string_buf),
+ later_version.fmt(string_buf),
+ },
+ );
+ } else {
+ const fmt = comptime brk: {
+ if (enable_ansi_colors) {
+ break :brk Output.prettyFmt("<r> <green>+<r> <b>{s}<r><d>@{}<r>\n", enable_ansi_colors);
+ } else {
+ break :brk Output.prettyFmt("<r> + {s}<r><d>@{}<r>\n", enable_ansi_colors);
+ }
+ };
- try writer.print(
- fmt,
- .{
- package_name,
- resolved[package_id].fmt(string_buf),
- },
- );
+ try writer.print(
+ fmt,
+ .{
+ package_name,
+ resolved[package_id].fmt(string_buf),
+ },
+ );
+ }
}
} else {
outer: for (dependencies_buffer, resolutions_buffer, 0..) |dependency, package_id, dep_id| {