aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/install/install.zig2
-rw-r--r--src/install/lockfile.zig48
2 files changed, 47 insertions, 3 deletions
diff --git a/src/install/install.zig b/src/install/install.zig
index f4695cc34..88c8f653f 100644
--- a/src/install/install.zig
+++ b/src/install/install.zig
@@ -7565,7 +7565,7 @@ pub const PackageManager = struct {
const needs_clean_lockfile = had_any_diffs or needs_new_lockfile or manager.package_json_updates.len > 0;
var did_meta_hash_change = needs_clean_lockfile;
if (needs_clean_lockfile) {
- manager.lockfile = try manager.lockfile.clean(manager.package_json_updates);
+ manager.lockfile = try manager.lockfile.cleanWithLogger(manager.package_json_updates, manager.log);
}
if (manager.lockfile.packages.len > 0) {
diff --git a/src/install/lockfile.zig b/src/install/lockfile.zig
index f5ad3681b..5c27c1a69 100644
--- a/src/install/lockfile.zig
+++ b/src/install/lockfile.zig
@@ -343,6 +343,32 @@ pub const Tree = struct {
dependencies: []const Dependency,
resolution_lists: []const Lockfile.DependencyIDSlice,
queue: Lockfile.TreeFiller,
+ log: ?*logger.Log = null,
+ old_lockfile: ?*Lockfile = null,
+
+ pub fn maybeReportError(this: *Builder, comptime fmt: string, args: anytype) void {
+ var log = this.log orelse return;
+ if (this.old_lockfile == null) return;
+
+ log.addErrorFmt(null, logger.Loc.Empty, this.allocator, fmt, args) catch {};
+ }
+
+ pub fn buf(this: *const Builder) []const u8 {
+ var lockfile = this.old_lockfile orelse return "";
+ return lockfile.buffers.string_bytes.items;
+ }
+
+ pub fn packageName(this: *Builder, id: PackageID) String.Formatter {
+ var lockfile = this.old_lockfile orelse return undefined;
+
+ return lockfile.packages.items(.name)[id].fmt(lockfile.buffers.string_bytes.items);
+ }
+
+ pub fn packageVersion(this: *Builder, id: PackageID) Resolution.Formatter {
+ var lockfile = this.old_lockfile orelse return undefined;
+
+ return lockfile.packages.items(.resolution)[id].fmt(lockfile.buffers.string_bytes.items);
+ }
pub const Entry = struct {
tree: Tree,
@@ -472,7 +498,18 @@ pub const Tree = struct {
const dep = builder.dependencies[dep_id];
if (dep.name_hash != dependency.name_hash) continue;
if (builder.resolutions[dep_id] != package_id) {
- if (as_defined and !dep.behavior.isPeer()) return error.DependencyLoop;
+ if (as_defined and !dep.behavior.isPeer()) {
+ if (builder.log != null)
+ builder.maybeReportError("Package \"{}@{}\" has a dependency loop\n Resolution: \"{}@{}\"\n Dependency: \"{}@{}\"", .{
+ builder.packageName(package_id),
+ builder.packageVersion(package_id),
+ builder.packageName(builder.resolutions[dep_id]),
+ builder.packageVersion(builder.resolutions[dep_id]),
+ dependency.name.fmt(builder.buf()),
+ dependency.version.literal.fmt(builder.buf()),
+ });
+ return error.DependencyLoop;
+ }
// ignore versioning conflicts caused by peer dependencies
return dependency_loop;
}
@@ -591,8 +628,11 @@ fn preprocessUpdateRequests(old: *Lockfile, updates: []PackageManager.UpdateRequ
}
}
}
-
pub fn clean(old: *Lockfile, updates: []PackageManager.UpdateRequest) !*Lockfile {
+ return old.cleanWithLogger(updates, null);
+}
+
+pub fn cleanWithLogger(old: *Lockfile, updates: []PackageManager.UpdateRequest, log: ?*logger.Log) !*Lockfile {
const old_scripts = old.scripts;
// We will only shrink the number of packages here.
// never grow
@@ -664,6 +704,7 @@ pub fn clean(old: *Lockfile, updates: []PackageManager.UpdateRequest) !*Lockfile
.lockfile = new,
.mapping = package_id_mapping,
.clone_queue = clone_queue_,
+ .log = log,
};
// try clone_queue.ensureUnusedCapacity(root.dependencies.len);
_ = try root.clone(old, new, package_id_mapping, &cloner);
@@ -740,6 +781,7 @@ const Cloner = struct {
mapping: []PackageID,
trees: Tree.List = Tree.List{},
trees_count: u32 = 1,
+ log: ?*logger.Log = null,
pub fn flush(this: *Cloner) anyerror!void {
const max_package_id = this.old.packages.len;
@@ -783,6 +825,8 @@ const Cloner = struct {
.resolutions = this.lockfile.buffers.resolutions.items,
.allocator = allocator,
.dependencies = this.lockfile.buffers.dependencies.items,
+ .log = this.log,
+ .old_lockfile = this.old,
};
try (Tree{}).processSubtree(Tree.root_dep_id, &builder);