refactor: detect and log duplicate package keys (#1744)
diff --git a/npm/private/npm_translate_lock_helpers.bzl b/npm/private/npm_translate_lock_helpers.bzl index fe78ee7..d7a14cb 100644 --- a/npm/private/npm_translate_lock_helpers.bzl +++ b/npm/private/npm_translate_lock_helpers.bzl
@@ -269,8 +269,8 @@ importer_links[import_path] = links patches_used = [] - result = [] - for package, package_info in packages.items(): + result = {} + for package_key, package_info in packages.items(): name = package_info.get("name") version = package_info.get("version") friendly_version = package_info.get("friendly_version") @@ -299,10 +299,10 @@ if resolution_type == "git": if not repo or not commit: - msg = "expected package {} resolution to have repo and commit fields when resolution type is git".format(package) + msg = "expected package {} resolution to have repo and commit fields when resolution type is git".format(package_key) fail(msg) elif not integrity and not tarball: - msg = "expected package {} resolution to have an integrity or tarball field but found none".format(package) + msg = "expected package {} resolution to have an integrity or tarball field but found none".format(package_key) fail(msg) if attr.prod and dev: @@ -383,7 +383,7 @@ link_packages = {} for import_path, links in importer_links.items(): linked_packages = links["packages"] - link_names = linked_packages.get(package, []) + link_names = linked_packages.get(package_key, []) if link_names: link_packages[links["link_package"]] = link_names @@ -440,7 +440,7 @@ npm_auth_bearer, npm_auth_basic, npm_auth_username, npm_auth_password = _select_npm_auth(url, npm_auth) - result.append(struct( + result_pkg = struct( custom_postinstall = custom_postinstall, deps = deps, integrity = integrity, @@ -467,7 +467,15 @@ package_info = package_info, dev = dev, replace_package = replace_package, - )) + ) + + if repo_name in result: + msg = "ERROR: duplicate package name: {}\n\t1: {}\n\t2: {}".format(repo_name, result[repo_name], result_pkg) + fail(msg) + + result[repo_name] = result_pkg + + result = result.values() # Check that all patches files specified were used; this is a defense-in-depth since it is too # easy to make a type in the patches keys or for a dep to change both of with could result
diff --git a/npm/private/transitive_closure.bzl b/npm/private/transitive_closure.bzl index edb54c1..1524cbd 100644 --- a/npm/private/transitive_closure.bzl +++ b/npm/private/transitive_closure.bzl
@@ -63,7 +63,7 @@ # Recurse into the next level of dependencies stack.append(_get_package_info_deps(packages[package_key], no_optional)) else: - msg = "Unknown package key: {} in {}".format(package_key, packages.keys()) + msg = "Unknown package key: {} ({} @ {}) in {}".format(package_key, name, version, packages.keys()) fail(msg) result = dict() @@ -155,12 +155,19 @@ package_version_map = {} for package_path, package_snapshot in lock_packages.items(): - package, package_info = _gather_package_info(package_path, package_snapshot) - packages[package] = package_info + package_key, package_info = _gather_package_info(package_path, package_snapshot) + + if package_key in packages: + msg = "ERROR: duplicate package info: {}\n\t{}\n\t{}".format(package_key, packages[package_key], package_info) + + # buildifier: disable=print + print(msg) + + packages[package_key] = package_info # tarbal versions if package_info["resolution"].get("tarball", None) and package_info["resolution"]["tarball"].startswith("file:"): - package_version_map[package] = package_info + package_version_map[package_key] = package_info # Collect deps of each importer (workspace projects) importers = {}
diff --git a/npm/private/utils.bzl b/npm/private/utils.bzl index f310c14..292ef41 100644 --- a/npm/private/utils.bzl +++ b/npm/private/utils.bzl
@@ -161,7 +161,13 @@ dependencies[dep_name] = _convert_pnpm_v6_package_name(dep_version) package_info[key] = dependencies - result[_convert_pnpm_v6_package_name(package)] = package_info + package_key = _convert_pnpm_v6_package_name(package) + + if package_key in result: + msg = "ERROR: duplicate package: {}\n\t{}\n\t{}".format(package_key, result[package_key], package_info) + fail(msg) + + result[package_key] = package_info return result @@ -228,7 +234,13 @@ for info_name, info_value in package_info.items(): snapshot_info[info_name] = info_value - result[_convert_pnpm_v9_package_name(package)] = snapshot_info + package_key = _convert_pnpm_v9_package_name(package) + + if package_key in result: + msg = "ERROR: duplicate package: {}\n\t{}\n\t{}".format(package_key, result[package_key], snapshot_info) + fail(msg) + + result[package_key] = snapshot_info return result