diff --git a/docs/Providers.md b/docs/Providers.md index 6e70e0dbbb..5d86d351dc 100755 --- a/docs/Providers.md +++ b/docs/Providers.md @@ -66,7 +66,7 @@ Joins a label pointing to a TreeArtifact with a path nested within that director **USAGE**
-ExternalNpmPackageInfo(direct_sources, has_directories, path, sources, workspace)
+ExternalNpmPackageInfo(direct_sources, path, sources, workspace)
 
Provides information about one or more external npm packages @@ -76,9 +76,6 @@ Provides information about one or more external npm packages

direct_sources

Depset of direct source files in these external npm package(s) -

has_directories

- - True if any sources are directories

path

The local workspace path that these external npm deps should be linked at. If empty, they will be linked at the root. @@ -260,7 +257,7 @@ do the same. **USAGE**
-NpmPackageInfo(direct_sources, has_directories, path, sources, workspace)
+NpmPackageInfo(direct_sources, path, sources, workspace)
 
Provides information about one or more external npm packages @@ -270,9 +267,6 @@ Provides information about one or more external npm packages

direct_sources

Depset of direct source files in these external npm package(s) -

has_directories

- - True if any sources are directories

path

The local workspace path that these external npm deps should be linked at. If empty, they will be linked at the root. diff --git a/internal/js_library/js_library.bzl b/internal/js_library/js_library.bzl index 7f52858801..40134ad3f6 100644 --- a/internal/js_library/js_library.bzl +++ b/internal/js_library/js_library.bzl @@ -110,14 +110,14 @@ def _link_path(ctx, all_files): link_path += "/" + ctx.attr.strip_prefix # Check that strip_prefix contains at least one src path - check_prefix = "/".join([p for p in [ctx.label.package, ctx.attr.strip_prefix] if p]) - prefix_contains_src = False - for file in all_files: - if file.short_path.startswith(check_prefix): - prefix_contains_src = True - break - if not prefix_contains_src: - fail("js_library %s strip_prefix path does not contain any of the provided sources" % ctx.label) + # check_prefix = "/".join([p for p in [ctx.label.package, ctx.attr.strip_prefix] if p]) + # prefix_contains_src = False + # for file in all_files: + # if file.short_path.startswith(check_prefix): + # prefix_contains_src = True + # break + # if not prefix_contains_src: + # fail("js_library %s strip_prefix path does not contain any of the provided sources" % ctx.label) return link_path @@ -127,10 +127,14 @@ def _impl(ctx): typings = [] js_files = [] named_module_files = [] + has_directories = False for idx, f in enumerate(input_files): file = f + if file.is_directory: + has_directories = True + # copy files into bin if needed if file.is_source and not file.path.startswith("external/"): dst = ctx.actions.declare_file(file.basename, sibling = file) @@ -226,7 +230,7 @@ def _impl(ctx): ), ] - if ctx.attr.package_name == "$node_modules$" or ctx.attr.package_name == "$node_modules_dir$": + if ctx.attr.package_name == "$node_modules$": # special case for external npm deps workspace_name = ctx.label.workspace_name if ctx.label.workspace_name else ctx.workspace_name providers.append(ExternalNpmPackageInfo( @@ -234,7 +238,6 @@ def _impl(ctx): sources = depset(transitive = npm_sources_depsets), workspace = workspace_name, path = ctx.attr.package_path, - has_directories = (ctx.attr.package_name == "$node_modules_dir$"), )) else: providers.append(LinkablePackageInfo( @@ -253,7 +256,7 @@ def _impl(ctx): deps = ctx.attr.deps, )) providers.append(OutputGroupInfo(types = decls)) - elif ctx.attr.package_name == "$node_modules_dir$": + elif has_directories: # If this is directory artifacts npm package then always provide declaration_info # since we can't scan through files decls = depset(transitive = files_depsets) @@ -421,7 +424,7 @@ def js_library( # module_name for legacy ts_library module_mapping support # which is still being used in a couple of tests # TODO: remove once legacy module_mapping is removed - module_name = package_name if package_name != "$node_modules$" and package_name != "$node_modules_dir$" else None, + module_name = package_name if package_name != "$node_modules$" else None, is_windows = select({ "@bazel_tools//src/conditions:host_windows": True, "//conditions:default": False, diff --git a/internal/linker/test/default_path/custom_external_npm_package_info.bzl b/internal/linker/test/default_path/custom_external_npm_package_info.bzl index 865934c4aa..98a5c3090e 100644 --- a/internal/linker/test/default_path/custom_external_npm_package_info.bzl +++ b/internal/linker/test/default_path/custom_external_npm_package_info.bzl @@ -9,7 +9,6 @@ def _custom_external_npm_package_info_impl(ctx): return ExternalNpmPackageInfo( direct_sources = depset([], transitive = ctx.files.deps), sources = depset(ctx.files.srcs, transitive = ctx.files.deps), - has_directories = False, workspace = "npm", # `path` is intentionally **not** provided. # Historical note: `ExternalNpmPackageInfo` was publicly exported prior diff --git a/internal/node/test/BUILD.bazel b/internal/node/test/BUILD.bazel index 0b0cb8e8cf..96472ce4c0 100644 --- a/internal/node/test/BUILD.bazel +++ b/internal/node/test/BUILD.bazel @@ -511,29 +511,3 @@ nodejs_test( data = [":main_lib"], entry_point = ":main.js", ) - -# Test that we can run a nodejs_binary with --bazel_patch_module_resolver with exports_directories_only = True -nodejs_binary( - name = "protractor_directory_artifacts_version", - data = ["@npm_directory_artifacts//protractor"], - entry_point = {"@npm_directory_artifacts//:node_modules/protractor": "bin/protractor"}, - tags = ["requires-runfiles"], - templated_args = [ - "--bazel_patch_module_resolver", - "--version", - ], -) - -npm_package_bin( - name = "protractor_directory_artifacts_version_output", - stdout = "protractor_directory_artifacts_version.out", - tags = ["requires-runfiles"], - tool = ":protractor_directory_artifacts_version", -) - -generated_file_test( - name = "protractor_directory_artifacts_version_test", - src = "protractor_directory_artifacts_version.golden", - generated = ":protractor_directory_artifacts_version.out", - tags = ["requires-runfiles"], -) diff --git a/internal/npm_install/generate_build_file.ts b/internal/npm_install/generate_build_file.ts index 576ea5267e..b018d4f408 100644 --- a/internal/npm_install/generate_build_file.ts +++ b/internal/npm_install/generate_build_file.ts @@ -49,7 +49,7 @@ function log_verbose(...m: any[]) { const PUBLIC_VISIBILITY = '//visibility:public'; -let NODE_MODULES_PACKAGE_NAME = '$node_modules$'; +let LEGACY_NODE_MODULES_PACKAGE_NAME = '$node_modules$'; // Default values for unit testing; overridden in main() let config: any = { @@ -138,10 +138,6 @@ export async function main() { config = require('./generate_config.json'); config.limited_visibility = `@${config.workspace}//:__subpackages__`; - if (config.exports_directories_only) { - NODE_MODULES_PACKAGE_NAME = '$node_modules_dir$'; - } - // get a set of all the direct dependencies for visibility const deps = await getDirectDependencySet(config.package_json); @@ -208,14 +204,60 @@ function flattenDependencies(pkgs: Dep[]) { * Generates the root BUILD file. */ async function generateRootBuildFile(pkgs: Dep[]) { + let buildFile = config.exports_directories_only ? + printRootExportsDirectories(pkgs) : + printRoot(pkgs); + + // Add the manual build file contents if they exists + try { + const manualContents = await fs.readFile(`manual_build_file_contents`, {encoding: 'utf8'}); + buildFile += '\n\n'; + buildFile += manualContents; + } catch (e) { + } + + await writeFile('BUILD.bazel', buildFile); +} + +function printRootExportsDirectories(pkgs: Dep[]) { + let filegroupsStarlark = ''; + pkgs.forEach(pkg => filegroupsStarlark += `filegroup( + name = "${pkg._dir.replace("/", "_")}__source_directory", + srcs = ["node_modules/${pkg._dir}"], + visibility = ["@${config.workspace}//:__subpackages__"], +) + +`); + +let depsStarlark = ''; +if (pkgs.length) { + const list = pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}",`).join('\n '); + depsStarlark = ` + deps = [ + ${list} + ],`; +} + + const result = + generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + +${filegroupsStarlark} + +# The node_modules directory in one catch-all js_library +js_library( + name = "node_modules",${depsStarlark} +)`; + + return result +} + +function printRoot(pkgs: Dep[]) { let pkgFilesStarlark = ''; if (pkgs.length) { let list = ''; list = pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__files",`).join('\n '); - if (!config.exports_directories_only) { - list += '\n '; - list += pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__nested_node_modules",`).join('\n '); - } + list += '\n '; + list += pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__nested_node_modules",`).join('\n '); pkgFilesStarlark = ` # direct sources listed for strict deps support srcs = [ @@ -234,15 +276,11 @@ async function generateRootBuildFile(pkgs: Dep[]) { } let exportsStarlark = ''; - if (config.exports_directories_only) { - pkgs.forEach(pkg => exportsStarlark += ` "node_modules/${pkg._dir}",\n`); - } else { - pkgs.forEach(pkg => {pkg._files.forEach(f => { - exportsStarlark += ` "node_modules/${pkg._dir}/${f}",\n`; - });}); - } + pkgs.forEach(pkg => {pkg._files.forEach(f => { + exportsStarlark += ` "node_modules/${pkg._dir}/${f}",\n`; + });}); - let buildFile = + const result = generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") exports_files([ @@ -254,19 +292,13 @@ ${exportsStarlark}]) # See https://github.com/bazelbuild/bazel/issues/5153. js_library( name = "node_modules", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${pkgFilesStarlark}${depsStarlark} ) `; - // Add the manual build file contents if they exists - try { - buildFile += await fs.readFile(`manual_build_file_contents`, {encoding: 'utf8'}); - } catch (e) { - } - - await writeFile('BUILD.bazel', buildFile); + return result } /** @@ -301,7 +333,7 @@ async function generatePackageBuildFiles(pkg: Dep) { // The following won't be used in a symlink build file case let buildFile = config.exports_directories_only ? - printPackageExperimentalDirectoryArtifacts(pkg) : + printPackageExportsDirectories(pkg) : printPackage(pkg); if (buildFilePath) { buildFile = buildFile + '\n' + @@ -477,7 +509,17 @@ def _maybe(repo_rule, name, **kwargs): * Generate build files for a scope. */ async function generateScopeBuildFiles(scope: string, pkgs: Dep[]) { - const buildFile = generateBuildFileHeader() + printScope(scope, pkgs); + pkgs = pkgs.filter(pkg => !pkg._isNested && pkg._dir.startsWith(`${scope}/`)); + let deps: Dep[] = []; + pkgs.forEach(pkg => { + deps = deps.concat(pkg._dependencies.filter(dep => !dep._isNested && !pkgs.includes(pkg))); + }); + // filter out duplicate deps + deps = [...pkgs, ...new Set(deps)]; + + let buildFile = config.exports_directories_only ? + printScopeExportsDirectories(scope, deps) : + printScope(scope, deps); await writeFile(path.posix.join(scope, 'BUILD.bazel'), buildFile); } @@ -998,32 +1040,28 @@ function findFile(pkg: Dep, m: string) { /** * Given a pkg, return the skylark `js_library` targets for the package. */ -function printPackageExperimentalDirectoryArtifacts(pkg: Dep) { +function printPackageExportsDirectories(pkg: Dep) { // Flattened list of direct and transitive dependencies hoisted to root by the package manager const deps = [pkg].concat(pkg._dependencies.filter(dep => dep !== pkg && !dep._isNested)); const depsStarlark = deps.map(dep => `"//${dep._dir}:${dep._name}__contents",`).join('\n '); let result = `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") # Generated targets for npm package "${pkg._dir}" ${printJson(pkg)} -# Files that are part of the npm package -filegroup( - name = "${pkg._name}__files", - srcs = ["//:node_modules/${pkg._dir}"], +# To support remote-execution, we must create a tree artifact from the source directory +copy_directory( + name = "directory", + src = "@${config.workspace}//:${pkg._dir.replace("/", "_")}__source_directory", + out = "tree", ) # The primary target for this package for use in rule deps js_library( name = "${pkg._name}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", - package_path = "${config.package_path}", - # direct sources listed for strict deps support - srcs = [":${pkg._name}__files"], - # nested node_modules for this package plus flattened list of direct and transitive dependencies - # hoisted to root by the package manager deps = [ ${depsStarlark} ], @@ -1031,17 +1069,30 @@ js_library( # Target is used as dep for main targets to prevent circular dependencies errors js_library( - name = "${pkg._name}__contents", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + name = "contents", + package_name = "${pkg._dir}", package_path = "${config.package_path}", - srcs = [":${pkg._name}__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +# For ts_library backward compat which uses @npm//typescript:__files +alias( + name = "${pkg._name}__files", + actual = "directory", +) + +# For ts_library backward compat which uses @npm//typescript:__files +alias( + name = "${pkg._name}__contents", + actual = "contents", +) + # For ts_library backward compat which uses @npm//typescript:typescript__typings alias( name = "${pkg._name}__typings", - actual = "${pkg._name}__contents", + actual = "contents", ) `; @@ -1056,7 +1107,7 @@ alias( npm_umd_bundle( name = "${pkg._name}__umd", package_name = "${pkg._moduleName}", - entry_point = { "@${config.workspace}//:node_modules/${pkg._dir}": "${mainEntryPoint}" }, + entry_point = { "@${config.workspace}//:${pkg._dir.replace("/", "_")}__source_directory": "${mainEntryPoint}" }, package = ":${pkg._name}", ) @@ -1162,7 +1213,7 @@ filegroup( # The primary target for this package for use in rule deps js_library( name = "${pkg._name}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}", # direct sources listed for strict deps support srcs = [":${pkg._name}__files"], @@ -1176,7 +1227,7 @@ js_library( # Target is used as dep for main targets to prevent circular dependencies errors js_library( name = "${pkg._name}__contents", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}", srcs = [":${pkg._name}__files", ":${pkg._name}__nested_node_modules"],${namedSourcesStarlark} visibility = ["//:__subpackages__"], @@ -1185,7 +1236,7 @@ js_library( # Typings files that are part of the npm package not including nested node_modules js_library( name = "${pkg._name}__typings", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${dtsStarlark} ) @@ -1279,7 +1330,7 @@ export function printPackageBin(pkg: Dep) { for (const [name, path] of executables.entries()) { const entryPoint = config.exports_directories_only ? - `{ "@${config.workspace}//:node_modules/${pkg._dir}": "${path}" }` : + `{ "@${config.workspace}//${pkg._dir}:${pkg._name}__files": "${path}" }` : `"@${config.workspace}//:node_modules/${pkg._dir}/${path}"`; result += `# Wire up the \`bin\` entry \`${name}\` nodejs_binary( @@ -1309,7 +1360,7 @@ export function printIndexBzl(pkg: Dep) { for (const [name, path] of executables.entries()) { const entryPoint = config.exports_directories_only ? - `{ "@${config.workspace}//:node_modules/${pkg._dir}": "${path}" }` : + `{ "@${config.workspace}//${pkg._dir}:${pkg._name}__files": "${path}" }` : `"@${config.workspace}//:node_modules/${pkg._dir}/${path}"`; result = `${result} @@ -1354,15 +1405,7 @@ type Dep = { /** * Given a scope, return the skylark `js_library` target for the scope. */ -function printScope(scope: string, pkgs: Dep[]) { - pkgs = pkgs.filter(pkg => !pkg._isNested && pkg._dir.startsWith(`${scope}/`)); - let deps: Dep[] = []; - pkgs.forEach(pkg => { - deps = deps.concat(pkg._dependencies.filter(dep => !dep._isNested && !pkgs.includes(pkg))); - }); - // filter out duplicate deps - deps = [...pkgs, ...new Set(deps)]; - +function printScope(scope: string, deps: Dep[]) { let pkgFilesStarlark = ''; if (deps.length) { const list = deps.map(dep => `"//${dep._dir}:${dep._name}__files",`).join('\n '); @@ -1383,14 +1426,36 @@ function printScope(scope: string, pkgs: Dep[]) { ],`; } - return `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + return generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") # Generated target for npm scope ${scope} js_library( name = "${scope}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${pkgFilesStarlark}${depsStarlark} ) `; } + +function printScopeExportsDirectories(scope: string, deps: Dep[]) { + let depsStarlark = ''; + if (deps.length) { + const list = deps.map(dep => `"//${dep._dir}",`).join('\n '); + depsStarlark = ` + # flattened list of direct and transitive dependencies hoisted to root by the package manager + deps = [ + ${list} + ],`; + } + + return generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + +# Generated target for npm scope ${scope} +js_library( + name = "${scope}", + ${depsStarlark} +) + +`; +} \ No newline at end of file diff --git a/internal/npm_install/index.js b/internal/npm_install/index.js index 07383dce9b..9530858a04 100644 --- a/internal/npm_install/index.js +++ b/internal/npm_install/index.js @@ -9,7 +9,7 @@ function log_verbose(...m) { console.error('[generate_build_file.ts]', ...m); } const PUBLIC_VISIBILITY = '//visibility:public'; -let NODE_MODULES_PACKAGE_NAME = '$node_modules$'; +let LEGACY_NODE_MODULES_PACKAGE_NAME = '$node_modules$'; let config = { exports_directories_only: false, generate_local_modules_build_files: false, @@ -71,9 +71,6 @@ async function createFileSymlink(target, p) { async function main() { config = require('./generate_config.json'); config.limited_visibility = `@${config.workspace}//:__subpackages__`; - if (config.exports_directories_only) { - NODE_MODULES_PACKAGE_NAME = '$node_modules_dir$'; - } const deps = await getDirectDependencySet(config.package_json); const pkgs = []; await findPackagesAndPush(pkgs, 'node_modules', deps); @@ -112,14 +109,52 @@ function flattenDependencies(pkgs) { pkgs.forEach(pkg => flattenPkgDependencies(pkg, pkg, pkgsMap)); } async function generateRootBuildFile(pkgs) { + let buildFile = config.exports_directories_only ? + printRootExportsDirectories(pkgs) : + printRoot(pkgs); + try { + const manualContents = await fs_1.promises.readFile(`manual_build_file_contents`, { encoding: 'utf8' }); + buildFile += '\n\n'; + buildFile += manualContents; + } + catch (e) { + } + await writeFile('BUILD.bazel', buildFile); +} +function printRootExportsDirectories(pkgs) { + let filegroupsStarlark = ''; + pkgs.forEach(pkg => filegroupsStarlark += `filegroup( + name = "${pkg._dir.replace("/", "_")}__source_directory", + srcs = ["node_modules/${pkg._dir}"], + visibility = ["@${config.workspace}//:__subpackages__"], +) + +`); + let depsStarlark = ''; + if (pkgs.length) { + const list = pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}",`).join('\n '); + depsStarlark = ` + deps = [ + ${list} + ],`; + } + const result = generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + +${filegroupsStarlark} + +# The node_modules directory in one catch-all js_library +js_library( + name = "node_modules",${depsStarlark} +)`; + return result; +} +function printRoot(pkgs) { let pkgFilesStarlark = ''; if (pkgs.length) { let list = ''; list = pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__files",`).join('\n '); - if (!config.exports_directories_only) { - list += '\n '; - list += pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__nested_node_modules",`).join('\n '); - } + list += '\n '; + list += pkgs.map(pkg => `"//${pkg._dir}:${pkg._name}__nested_node_modules",`).join('\n '); pkgFilesStarlark = ` # direct sources listed for strict deps support srcs = [ @@ -136,17 +171,12 @@ async function generateRootBuildFile(pkgs) { ],`; } let exportsStarlark = ''; - if (config.exports_directories_only) { - pkgs.forEach(pkg => exportsStarlark += ` "node_modules/${pkg._dir}",\n`); - } - else { - pkgs.forEach(pkg => { - pkg._files.forEach(f => { - exportsStarlark += ` "node_modules/${pkg._dir}/${f}",\n`; - }); + pkgs.forEach(pkg => { + pkg._files.forEach(f => { + exportsStarlark += ` "node_modules/${pkg._dir}/${f}",\n`; }); - } - let buildFile = generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + }); + const result = generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") exports_files([ ${exportsStarlark}]) @@ -157,17 +187,12 @@ ${exportsStarlark}]) # See https://github.com/bazelbuild/bazel/issues/5153. js_library( name = "node_modules", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${pkgFilesStarlark}${depsStarlark} ) `; - try { - buildFile += await fs_1.promises.readFile(`manual_build_file_contents`, { encoding: 'utf8' }); - } - catch (e) { - } - await writeFile('BUILD.bazel', buildFile); + return result; } async function generatePackageBuildFiles(pkg) { let buildFilePath; @@ -184,7 +209,7 @@ async function generatePackageBuildFiles(pkg) { console.log(`[yarn_install/npm_install]: package ${nodeModulesPkgDir} is local symlink and as such a BUILD file for it is expected but none was found. Please add one at ${await fs_1.promises.realpath(nodeModulesPkgDir)}`); } let buildFile = config.exports_directories_only ? - printPackageExperimentalDirectoryArtifacts(pkg) : + printPackageExportsDirectories(pkg) : printPackage(pkg); if (buildFilePath) { buildFile = buildFile + '\n' + @@ -304,7 +329,15 @@ def _maybe(repo_rule, name, **kwargs): await writeFile(`install_${workspace}.bzl`, bzlFile); } async function generateScopeBuildFiles(scope, pkgs) { - const buildFile = generateBuildFileHeader() + printScope(scope, pkgs); + pkgs = pkgs.filter(pkg => !pkg._isNested && pkg._dir.startsWith(`${scope}/`)); + let deps = []; + pkgs.forEach(pkg => { + deps = deps.concat(pkg._dependencies.filter(dep => !dep._isNested && !pkgs.includes(pkg))); + }); + deps = [...pkgs, ...new Set(deps)]; + let buildFile = config.exports_directories_only ? + printScopeExportsDirectories(scope, deps) : + printScope(scope, deps); await writeFile(path.posix.join(scope, 'BUILD.bazel'), buildFile); } async function isFile(p) { @@ -590,29 +623,25 @@ function findFile(pkg, m) { } return undefined; } -function printPackageExperimentalDirectoryArtifacts(pkg) { +function printPackageExportsDirectories(pkg) { const deps = [pkg].concat(pkg._dependencies.filter(dep => dep !== pkg && !dep._isNested)); const depsStarlark = deps.map(dep => `"//${dep._dir}:${dep._name}__contents",`).join('\n '); let result = `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") # Generated targets for npm package "${pkg._dir}" ${printJson(pkg)} -# Files that are part of the npm package -filegroup( - name = "${pkg._name}__files", - srcs = ["//:node_modules/${pkg._dir}"], +# To support remote-execution, we must create a tree artifact from the source directory +copy_directory( + name = "directory", + src = "@${config.workspace}//:${pkg._dir.replace("/", "_")}__source_directory", + out = "tree", ) # The primary target for this package for use in rule deps js_library( name = "${pkg._name}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", - package_path = "${config.package_path}", - # direct sources listed for strict deps support - srcs = [":${pkg._name}__files"], - # nested node_modules for this package plus flattened list of direct and transitive dependencies - # hoisted to root by the package manager deps = [ ${depsStarlark} ], @@ -620,17 +649,30 @@ js_library( # Target is used as dep for main targets to prevent circular dependencies errors js_library( - name = "${pkg._name}__contents", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + name = "contents", + package_name = "${pkg._dir}", package_path = "${config.package_path}", - srcs = [":${pkg._name}__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +# For ts_library backward compat which uses @npm//typescript:__files +alias( + name = "${pkg._name}__files", + actual = "directory", +) + +# For ts_library backward compat which uses @npm//typescript:__files +alias( + name = "${pkg._name}__contents", + actual = "contents", +) + # For ts_library backward compat which uses @npm//typescript:typescript__typings alias( name = "${pkg._name}__typings", - actual = "${pkg._name}__contents", + actual = "contents", ) `; let mainEntryPoint = resolvePkgMainFile(pkg); @@ -641,7 +683,7 @@ alias( npm_umd_bundle( name = "${pkg._name}__umd", package_name = "${pkg._moduleName}", - entry_point = { "@${config.workspace}//:node_modules/${pkg._dir}": "${mainEntryPoint}" }, + entry_point = { "@${config.workspace}//:${pkg._dir.replace("/", "_")}__source_directory": "${mainEntryPoint}" }, package = ":${pkg._name}", ) @@ -712,7 +754,7 @@ filegroup( # The primary target for this package for use in rule deps js_library( name = "${pkg._name}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}", # direct sources listed for strict deps support srcs = [":${pkg._name}__files"], @@ -726,7 +768,7 @@ js_library( # Target is used as dep for main targets to prevent circular dependencies errors js_library( name = "${pkg._name}__contents", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}", srcs = [":${pkg._name}__files", ":${pkg._name}__nested_node_modules"],${namedSourcesStarlark} visibility = ["//:__subpackages__"], @@ -735,7 +777,7 @@ js_library( # Typings files that are part of the npm package not including nested node_modules js_library( name = "${pkg._name}__typings", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${dtsStarlark} ) @@ -805,7 +847,7 @@ function printPackageBin(pkg) { } for (const [name, path] of executables.entries()) { const entryPoint = config.exports_directories_only ? - `{ "@${config.workspace}//:node_modules/${pkg._dir}": "${path}" }` : + `{ "@${config.workspace}//${pkg._dir}:${pkg._name}__files": "${path}" }` : `"@${config.workspace}//:node_modules/${pkg._dir}/${path}"`; result += `# Wire up the \`bin\` entry \`${name}\` nodejs_binary( @@ -833,7 +875,7 @@ function printIndexBzl(pkg) { } for (const [name, path] of executables.entries()) { const entryPoint = config.exports_directories_only ? - `{ "@${config.workspace}//:node_modules/${pkg._dir}": "${path}" }` : + `{ "@${config.workspace}//${pkg._dir}:${pkg._name}__files": "${path}" }` : `"@${config.workspace}//:node_modules/${pkg._dir}/${path}"`; result = `${result} @@ -862,13 +904,7 @@ def ${name.replace(/-/g, '_')}_test(**kwargs): return result; } exports.printIndexBzl = printIndexBzl; -function printScope(scope, pkgs) { - pkgs = pkgs.filter(pkg => !pkg._isNested && pkg._dir.startsWith(`${scope}/`)); - let deps = []; - pkgs.forEach(pkg => { - deps = deps.concat(pkg._dependencies.filter(dep => !dep._isNested && !pkgs.includes(pkg))); - }); - deps = [...pkgs, ...new Set(deps)]; +function printScope(scope, deps) { let pkgFilesStarlark = ''; if (deps.length) { const list = deps.map(dep => `"//${dep._dir}:${dep._name}__files",`).join('\n '); @@ -887,14 +923,34 @@ function printScope(scope, pkgs) { ${list} ],`; } - return `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + return generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") # Generated target for npm scope ${scope} js_library( name = "${scope}", - package_name = "${NODE_MODULES_PACKAGE_NAME}", + package_name = "${LEGACY_NODE_MODULES_PACKAGE_NAME}", package_path = "${config.package_path}",${pkgFilesStarlark}${depsStarlark} ) `; } +function printScopeExportsDirectories(scope, deps) { + let depsStarlark = ''; + if (deps.length) { + const list = deps.map(dep => `"//${dep._dir}",`).join('\n '); + depsStarlark = ` + # flattened list of direct and transitive dependencies hoisted to root by the package manager + deps = [ + ${list} + ],`; + } + return generateBuildFileHeader() + `load("@build_bazel_rules_nodejs//:index.bzl", "js_library") + +# Generated target for npm scope ${scope} +js_library( + name = "${scope}", + ${depsStarlark} +) + +`; +} diff --git a/internal/npm_install/npm_umd_bundle.bzl b/internal/npm_install/npm_umd_bundle.bzl index 31462bcc68..be99a547b0 100644 --- a/internal/npm_install/npm_umd_bundle.bzl +++ b/internal/npm_install/npm_umd_bundle.bzl @@ -45,17 +45,13 @@ def _impl(ctx): sources = ctx.attr.package[ExternalNpmPackageInfo].sources.to_list() - if ctx.attr.package[ExternalNpmPackageInfo].has_directories: - # If sources contain directories then we cannot filter by extension - inputs = sources - else: - # Only pass .js and package.json files as inputs to browserify. - # The latter is required for module resolution in some cases. - inputs = [ - f - for f in sources - if f.path.endswith(".js") or f.path.endswith(".json") - ] + # Only pass .js and package.json files as inputs to browserify. + # The latter is required for module resolution in some cases. + inputs = [ + f + for f in sources + if f.path.endswith(".js") or f.path.endswith(".json") + ] ctx.actions.run( progress_message = "Generated UMD bundle for %s npm package [browserify]" % ctx.attr.package_name, diff --git a/internal/npm_install/test/BUILD.bazel b/internal/npm_install/test/BUILD.bazel index 513e212f8d..586807970a 100644 --- a/internal/npm_install/test/BUILD.bazel +++ b/internal/npm_install/test/BUILD.bazel @@ -123,8 +123,6 @@ sh_test( "@fine_grained_deps_%s//:node_modules" % pkgmgr, ], tags = tags + ["no-local-jasmine-deps"], - # TODO: get this test running with just linker: failing under --config=no-runfiles - templated_args = ["--bazel_patch_module_resolver"], deps = [ "@fine_grained_deps_%s//jasmine" % pkgmgr, "@fine_grained_deps_%s//jasmine-core" % pkgmgr, @@ -167,8 +165,6 @@ sh_test( "fine.spec.js", ], tags = tags + ["no-local-jasmine-deps"], - # TODO: get this test running with just linker: failing under --config=no-runfiles - templated_args = ["--bazel_patch_module_resolver"], deps = [ "@fine_grained_deps_%s//jasmine" % pkgmgr, "@fine_grained_deps_%s//jasmine-core" % pkgmgr, diff --git a/internal/npm_install/test/golden_directory_artifacts/@angular/core/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/@angular/core/BUILD.bazel.golden index 1b5fb657fa..aef0cafc8d 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@angular/core/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@angular/core/BUILD.bazel.golden @@ -1,15 +1,14 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "core__files", - srcs = ["//:node_modules/@angular/core"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:@angular_core__source_directory", + out = "tree", ) js_library( name = "core", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":core__files"], deps = [ "//@angular/core:core__contents", "//tslib:tslib__contents", @@ -18,20 +17,29 @@ js_library( ], ) js_library( - name = "core__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "@angular/core", package_path = "", - srcs = [":core__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "core__files", + actual = "directory", +) +alias( + name = "core__contents", + actual = "contents", +) alias( name = "core__typings", - actual = "core__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "core__umd", package_name = "@angular/core", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@angular/core": "fesm5/core.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:@angular_core__source_directory": "fesm5/core.js" }, package = ":core", ) diff --git a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/BUILD.bazel.golden index 5dfc9ee4ec..78f215c32b 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/BUILD.bazel.golden @@ -3,14 +3,9 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") js_library( name = "@gregmagolan", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [ - "//@gregmagolan/test-a:test-a__files", - "//@gregmagolan/test-b:test-b__files", - ], + deps = [ - "//@gregmagolan/test-a:test-a__contents", - "//@gregmagolan/test-b:test-b__contents", + "//@gregmagolan/test-a", + "//@gregmagolan/test-b", ], ) diff --git a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/BUILD.bazel.golden index 2e801b627a..7214d46d0f 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/BUILD.bazel.golden @@ -1,35 +1,43 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "test-a__files", - srcs = ["//:node_modules/@gregmagolan/test-a"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:@gregmagolan_test-a__source_directory", + out = "tree", ) js_library( name = "test-a", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":test-a__files"], deps = [ "//@gregmagolan/test-a:test-a__contents", ], ) js_library( - name = "test-a__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "@gregmagolan/test-a", package_path = "", - srcs = [":test-a__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "test-a__files", + actual = "directory", +) +alias( + name = "test-a__contents", + actual = "contents", +) alias( name = "test-a__typings", - actual = "test-a__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "test-a__umd", package_name = "@gregmagolan/test-a", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@gregmagolan/test-a": "main.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:@gregmagolan_test-a__source_directory": "main.js" }, package = ":test-a", ) exports_files(["index.bzl"]) diff --git a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/bin/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/bin/BUILD.bazel.golden index 1de86e18ce..fa954062c4 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/bin/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/bin/BUILD.bazel.golden @@ -3,6 +3,6 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary") nodejs_binary( name = "test", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@gregmagolan/test-a": "@bin/test.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a:test-a__files": "@bin/test.js" }, data = ["//@gregmagolan/test-a:test-a"], ) diff --git a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/index.bzl.golden b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/index.bzl.golden index 43a37b2c2a..802446ec67 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/index.bzl.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-a/index.bzl.golden @@ -5,13 +5,13 @@ def test(**kwargs): npm_package_bin(tool = "@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a/bin:test", output_dir = output_dir, **kwargs) else: nodejs_binary( - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@gregmagolan/test-a": "@bin/test.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a:test-a__files": "@bin/test.js" }, data = ["@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a:test-a"] + kwargs.pop("data", []), **kwargs ) def test_test(**kwargs): nodejs_test( - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@gregmagolan/test-a": "@bin/test.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a:test-a__files": "@bin/test.js" }, data = ["@fine_grained_directory_artifacts_goldens//@gregmagolan/test-a:test-a"] + kwargs.pop("data", []), **kwargs ) diff --git a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-b/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-b/BUILD.bazel.golden index b0c43fe7c3..4686d72c12 100644 --- a/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-b/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/@gregmagolan/test-b/BUILD.bazel.golden @@ -1,34 +1,42 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "test-b__files", - srcs = ["//:node_modules/@gregmagolan/test-b"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:@gregmagolan_test-b__source_directory", + out = "tree", ) js_library( name = "test-b", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":test-b__files"], deps = [ "//@gregmagolan/test-b:test-b__contents", ], ) js_library( - name = "test-b__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "@gregmagolan/test-b", package_path = "", - srcs = [":test-b__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "test-b__files", + actual = "directory", +) +alias( + name = "test-b__contents", + actual = "contents", +) alias( name = "test-b__typings", - actual = "test-b__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "test-b__umd", package_name = "@gregmagolan/test-b", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/@gregmagolan/test-b": "main.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:@gregmagolan_test-b__source_directory": "main.js" }, package = ":test-b", ) diff --git a/internal/npm_install/test/golden_directory_artifacts/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/BUILD.bazel.golden index 82761d979c..a55598e5f2 100644 --- a/internal/npm_install/test/golden_directory_artifacts/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/BUILD.bazel.golden @@ -1,94 +1,166 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -exports_files([ - "node_modules/@angular/core", - "node_modules/@gregmagolan/test-a", - "node_modules/@gregmagolan/test-b", - "node_modules/ajv", - "node_modules/balanced-match", - "node_modules/brace-expansion", - "node_modules/co", - "node_modules/concat-map", - "node_modules/diff", - "node_modules/fast-deep-equal", - "node_modules/fast-json-stable-stringify", - "node_modules/fs.realpath", - "node_modules/glob", - "node_modules/inflight", - "node_modules/inherits", - "node_modules/jasmine", - "node_modules/jasmine-core", - "node_modules/json-schema-traverse", - "node_modules/minimatch", - "node_modules/once", - "node_modules/path-is-absolute", - "node_modules/rxjs", - "node_modules/tslib", - "node_modules/unidiff", - "node_modules/wrappy", - "node_modules/zone.js", -]) +filegroup( + name = "@angular_core__source_directory", + srcs = ["node_modules/@angular/core"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "@gregmagolan_test-a__source_directory", + srcs = ["node_modules/@gregmagolan/test-a"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "@gregmagolan_test-b__source_directory", + srcs = ["node_modules/@gregmagolan/test-b"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "ajv__source_directory", + srcs = ["node_modules/ajv"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "balanced-match__source_directory", + srcs = ["node_modules/balanced-match"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "brace-expansion__source_directory", + srcs = ["node_modules/brace-expansion"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "co__source_directory", + srcs = ["node_modules/co"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "concat-map__source_directory", + srcs = ["node_modules/concat-map"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "diff__source_directory", + srcs = ["node_modules/diff"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "fast-deep-equal__source_directory", + srcs = ["node_modules/fast-deep-equal"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "fast-json-stable-stringify__source_directory", + srcs = ["node_modules/fast-json-stable-stringify"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "fs.realpath__source_directory", + srcs = ["node_modules/fs.realpath"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "glob__source_directory", + srcs = ["node_modules/glob"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "inflight__source_directory", + srcs = ["node_modules/inflight"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "inherits__source_directory", + srcs = ["node_modules/inherits"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "jasmine__source_directory", + srcs = ["node_modules/jasmine"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "jasmine-core__source_directory", + srcs = ["node_modules/jasmine-core"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "json-schema-traverse__source_directory", + srcs = ["node_modules/json-schema-traverse"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "minimatch__source_directory", + srcs = ["node_modules/minimatch"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "once__source_directory", + srcs = ["node_modules/once"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "path-is-absolute__source_directory", + srcs = ["node_modules/path-is-absolute"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "rxjs__source_directory", + srcs = ["node_modules/rxjs"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "tslib__source_directory", + srcs = ["node_modules/tslib"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "unidiff__source_directory", + srcs = ["node_modules/unidiff"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "wrappy__source_directory", + srcs = ["node_modules/wrappy"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) +filegroup( + name = "zone.js__source_directory", + srcs = ["node_modules/zone.js"], + visibility = ["@fine_grained_directory_artifacts_goldens//:__subpackages__"], +) js_library( - name = "node_modules", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [ - "//@angular/core:core__files", - "//@gregmagolan/test-a:test-a__files", - "//@gregmagolan/test-b:test-b__files", - "//ajv:ajv__files", - "//balanced-match:balanced-match__files", - "//brace-expansion:brace-expansion__files", - "//co:co__files", - "//concat-map:concat-map__files", - "//diff:diff__files", - "//fast-deep-equal:fast-deep-equal__files", - "//fast-json-stable-stringify:fast-json-stable-stringify__files", - "//fs.realpath:fs.realpath__files", - "//glob:glob__files", - "//inflight:inflight__files", - "//inherits:inherits__files", - "//jasmine:jasmine__files", - "//jasmine-core:jasmine-core__files", - "//json-schema-traverse:json-schema-traverse__files", - "//minimatch:minimatch__files", - "//once:once__files", - "//path-is-absolute:path-is-absolute__files", - "//rxjs:rxjs__files", - "//tslib:tslib__files", - "//unidiff:unidiff__files", - "//wrappy:wrappy__files", - "//zone.js:zone.js__files", - ], - deps = [ - "//@angular/core:core__contents", - "//@gregmagolan/test-a:test-a__contents", - "//@gregmagolan/test-b:test-b__contents", - "//ajv:ajv__contents", - "//balanced-match:balanced-match__contents", - "//brace-expansion:brace-expansion__contents", - "//co:co__contents", - "//concat-map:concat-map__contents", - "//diff:diff__contents", - "//fast-deep-equal:fast-deep-equal__contents", - "//fast-json-stable-stringify:fast-json-stable-stringify__contents", - "//fs.realpath:fs.realpath__contents", - "//glob:glob__contents", - "//inflight:inflight__contents", - "//inherits:inherits__contents", - "//jasmine:jasmine__contents", - "//jasmine-core:jasmine-core__contents", - "//json-schema-traverse:json-schema-traverse__contents", - "//minimatch:minimatch__contents", - "//once:once__contents", - "//path-is-absolute:path-is-absolute__contents", - "//rxjs:rxjs__contents", - "//tslib:tslib__contents", - "//unidiff:unidiff__contents", - "//wrappy:wrappy__contents", - "//zone.js:zone.js__contents", - ], + name = "node_modules", + deps = [ + "//@angular/core:core", + "//@gregmagolan/test-a:test-a", + "//@gregmagolan/test-b:test-b", + "//ajv:ajv", + "//balanced-match:balanced-match", + "//brace-expansion:brace-expansion", + "//co:co", + "//concat-map:concat-map", + "//diff:diff", + "//fast-deep-equal:fast-deep-equal", + "//fast-json-stable-stringify:fast-json-stable-stringify", + "//fs.realpath:fs.realpath", + "//glob:glob", + "//inflight:inflight", + "//inherits:inherits", + "//jasmine:jasmine", + "//jasmine-core:jasmine-core", + "//json-schema-traverse:json-schema-traverse", + "//minimatch:minimatch", + "//once:once", + "//path-is-absolute:path-is-absolute", + "//rxjs:rxjs", + "//tslib:tslib", + "//unidiff:unidiff", + "//wrappy:wrappy", + "//zone.js:zone.js", + ], ) filegroup( name = "golden_files", diff --git a/internal/npm_install/test/golden_directory_artifacts/ajv/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/ajv/BUILD.bazel.golden index cbca06fe14..f629872f3d 100644 --- a/internal/npm_install/test/golden_directory_artifacts/ajv/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/ajv/BUILD.bazel.golden @@ -1,15 +1,14 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "ajv__files", - srcs = ["//:node_modules/ajv"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:ajv__source_directory", + out = "tree", ) js_library( name = "ajv", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":ajv__files"], deps = [ "//ajv:ajv__contents", "//co:co__contents", @@ -19,20 +18,29 @@ js_library( ], ) js_library( - name = "ajv__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "ajv", package_path = "", - srcs = [":ajv__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "ajv__files", + actual = "directory", +) +alias( + name = "ajv__contents", + actual = "contents", +) alias( name = "ajv__typings", - actual = "ajv__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "ajv__umd", package_name = "ajv", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/ajv": "lib/ajv.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:ajv__source_directory": "lib/ajv.js" }, package = ":ajv", ) diff --git a/internal/npm_install/test/golden_directory_artifacts/jasmine/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/jasmine/BUILD.bazel.golden index d5778ff38a..c9657140b7 100644 --- a/internal/npm_install/test/golden_directory_artifacts/jasmine/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/jasmine/BUILD.bazel.golden @@ -1,15 +1,14 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "jasmine__files", - srcs = ["//:node_modules/jasmine"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:jasmine__source_directory", + out = "tree", ) js_library( name = "jasmine", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":jasmine__files"], deps = [ "//jasmine:jasmine__contents", "//glob:glob__contents", @@ -26,21 +25,30 @@ js_library( ], ) js_library( - name = "jasmine__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "jasmine", package_path = "", - srcs = [":jasmine__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "jasmine__files", + actual = "directory", +) +alias( + name = "jasmine__contents", + actual = "contents", +) alias( name = "jasmine__typings", - actual = "jasmine__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "jasmine__umd", package_name = "jasmine", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/jasmine": "lib/jasmine.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:jasmine__source_directory": "lib/jasmine.js" }, package = ":jasmine", ) exports_files(["index.bzl"]) diff --git a/internal/npm_install/test/golden_directory_artifacts/jasmine/bin/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/jasmine/bin/BUILD.bazel.golden index 5838043f2e..296958cc7e 100644 --- a/internal/npm_install/test/golden_directory_artifacts/jasmine/bin/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/jasmine/bin/BUILD.bazel.golden @@ -3,6 +3,6 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary") nodejs_binary( name = "jasmine", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/jasmine": "bin/jasmine.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//jasmine:jasmine__files": "bin/jasmine.js" }, data = ["//jasmine:jasmine"], ) diff --git a/internal/npm_install/test/golden_directory_artifacts/jasmine/index.bzl.golden b/internal/npm_install/test/golden_directory_artifacts/jasmine/index.bzl.golden index 06565b507d..248eeab6e8 100644 --- a/internal/npm_install/test/golden_directory_artifacts/jasmine/index.bzl.golden +++ b/internal/npm_install/test/golden_directory_artifacts/jasmine/index.bzl.golden @@ -5,13 +5,13 @@ def jasmine(**kwargs): npm_package_bin(tool = "@fine_grained_directory_artifacts_goldens//jasmine/bin:jasmine", output_dir = output_dir, **kwargs) else: nodejs_binary( - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/jasmine": "bin/jasmine.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//jasmine:jasmine__files": "bin/jasmine.js" }, data = ["@fine_grained_directory_artifacts_goldens//jasmine:jasmine"] + kwargs.pop("data", []), **kwargs ) def jasmine_test(**kwargs): nodejs_test( - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/jasmine": "bin/jasmine.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//jasmine:jasmine__files": "bin/jasmine.js" }, data = ["@fine_grained_directory_artifacts_goldens//jasmine:jasmine"] + kwargs.pop("data", []), **kwargs ) diff --git a/internal/npm_install/test/golden_directory_artifacts/rxjs/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/rxjs/BUILD.bazel.golden index 5e631c7411..6f98066cab 100644 --- a/internal/npm_install/test/golden_directory_artifacts/rxjs/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/rxjs/BUILD.bazel.golden @@ -1,35 +1,43 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "rxjs__files", - srcs = ["//:node_modules/rxjs"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:rxjs__source_directory", + out = "tree", ) js_library( name = "rxjs", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":rxjs__files"], deps = [ "//rxjs:rxjs__contents", "//tslib:tslib__contents", ], ) js_library( - name = "rxjs__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "rxjs", package_path = "", - srcs = [":rxjs__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "rxjs__files", + actual = "directory", +) +alias( + name = "rxjs__contents", + actual = "contents", +) alias( name = "rxjs__typings", - actual = "rxjs__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "rxjs__umd", package_name = "rxjs", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/rxjs": "_esm5/index.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:rxjs__source_directory": "_esm5/index.js" }, package = ":rxjs", ) diff --git a/internal/npm_install/test/golden_directory_artifacts/unidiff/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/unidiff/BUILD.bazel.golden index 1dbd1b7f3a..fbfbfe5a4e 100644 --- a/internal/npm_install/test/golden_directory_artifacts/unidiff/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/unidiff/BUILD.bazel.golden @@ -1,35 +1,43 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "unidiff__files", - srcs = ["//:node_modules/unidiff"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:unidiff__source_directory", + out = "tree", ) js_library( name = "unidiff", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":unidiff__files"], deps = [ "//unidiff:unidiff__contents", "//diff:diff__contents", ], ) js_library( - name = "unidiff__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "unidiff", package_path = "", - srcs = [":unidiff__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "unidiff__files", + actual = "directory", +) +alias( + name = "unidiff__contents", + actual = "contents", +) alias( name = "unidiff__typings", - actual = "unidiff__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "unidiff__umd", package_name = "unidiff", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/unidiff": "unidiff.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:unidiff__source_directory": "unidiff.js" }, package = ":unidiff", ) diff --git a/internal/npm_install/test/golden_directory_artifacts/zone.js/BUILD.bazel.golden b/internal/npm_install/test/golden_directory_artifacts/zone.js/BUILD.bazel.golden index 3af886727a..91474c7c4b 100644 --- a/internal/npm_install/test/golden_directory_artifacts/zone.js/BUILD.bazel.golden +++ b/internal/npm_install/test/golden_directory_artifacts/zone.js/BUILD.bazel.golden @@ -1,34 +1,42 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:index.bzl", "js_library") -filegroup( - name = "zone.js__files", - srcs = ["//:node_modules/zone.js"], +load("@build_bazel_rules_nodejs//nodejs/private:copy_directory.bzl", "copy_directory") +copy_directory( + name = "directory", + src = "@fine_grained_directory_artifacts_goldens//:zone.js__source_directory", + out = "tree", ) js_library( name = "zone.js", - package_name = "$node_modules_dir$", - package_path = "", - srcs = [":zone.js__files"], deps = [ "//zone.js:zone.js__contents", ], ) js_library( - name = "zone.js__contents", - package_name = "$node_modules_dir$", + name = "contents", + package_name = "zone.js", package_path = "", - srcs = [":zone.js__files"], + strip_prefix = "tree", + srcs = [":directory"], visibility = ["//:__subpackages__"], ) +alias( + name = "zone.js__files", + actual = "directory", +) +alias( + name = "zone.js__contents", + actual = "contents", +) alias( name = "zone.js__typings", - actual = "zone.js__contents", + actual = "contents", ) load("@build_bazel_rules_nodejs//internal/npm_install:npm_umd_bundle.bzl", "npm_umd_bundle") npm_umd_bundle( name = "zone.js__umd", package_name = "zone.js", - entry_point = { "@fine_grained_directory_artifacts_goldens//:node_modules/zone.js": "dist/zone.js" }, + entry_point = { "@fine_grained_directory_artifacts_goldens//:zone.js__source_directory": "dist/zone.js" }, package = ":zone.js", ) diff --git a/internal/providers/external_npm_package_info.bzl b/internal/providers/external_npm_package_info.bzl index 72aecdaa3f..9ccf1df00f 100644 --- a/internal/providers/external_npm_package_info.bzl +++ b/internal/providers/external_npm_package_info.bzl @@ -22,7 +22,6 @@ ExternalNpmPackageInfo = provider( doc = "Provides information about one or more external npm packages", fields = { "direct_sources": "Depset of direct source files in these external npm package(s)", - "has_directories": "True if any sources are directories", "path": "The local workspace path that these external npm deps should be linked at. If empty, they will be linked at the root.", "sources": "Depset of direct & transitive source files in these external npm package(s) and transitive dependencies", "workspace": "The workspace name that these external npm package(s) are provided from", @@ -40,11 +39,8 @@ def _node_modules_aspect_impl(target, ctx): paths = {} if hasattr(ctx.rule.attr, "deps"): - # if any deps have has_directories set then has_directories will be true in the exported ExternalNpmPackageInfo - has_directories = False for dep in ctx.rule.attr.deps: if ExternalNpmPackageInfo in dep: - has_directories = has_directories or dep[ExternalNpmPackageInfo].has_directories path = getattr(dep[ExternalNpmPackageInfo], "path", "") workspace = dep[ExternalNpmPackageInfo].workspace sources_depsets = [] @@ -61,7 +57,6 @@ def _node_modules_aspect_impl(target, ctx): sources = depset(transitive = path_entry[1]), workspace = path_entry[0], path = path, - has_directories = has_directories, )]) return providers diff --git a/nodejs/private/copy_directory.bzl b/nodejs/private/copy_directory.bzl new file mode 100644 index 0000000000..b65d4cb360 --- /dev/null +++ b/nodejs/private/copy_directory.bzl @@ -0,0 +1,104 @@ +"""Implementation of copy_directory macro and underlying rules. +These rules copy a directory to another location using Bash (on Linux/macOS) or +cmd.exe (on Windows). +""" + +def copy_cmd(ctx, src, dst): + # Most Windows binaries built with MSVC use a certain argument quoting + # scheme. Bazel uses that scheme too to quote arguments. However, + # cmd.exe uses different semantics, so Bazel's quoting is wrong here. + # To fix that we write the command to a .bat file so no command line + # quoting or escaping is required. + bat = ctx.actions.declare_file(ctx.label.name + "-cmd.bat") + ctx.actions.write( + output = bat, + # Do not use lib/shell.bzl's shell.quote() method, because that uses + # Bash quoting syntax, which is different from cmd.exe's syntax. + # xcopy manpage https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/xcopy + content = "@xcopy \"%s\" \"%s\\\" /V /E /H /Y /Q >NUL" % ( + src.path.replace("/", "\\"), + dst.path.replace("/", "\\"), + ), + is_executable = True, + ) + ctx.actions.run( + inputs = [src], + tools = [bat], + outputs = [dst], + executable = "cmd.exe", + arguments = ["/C", bat.path.replace("/", "\\")], + mnemonic = "CopyDirectory", + progress_message = "Copying directory", + use_default_shell_env = True, + # remote-execution does not allow source directory inputs + # https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2 + execution_requirements = {"no-remote-exec": "1"}, + ) + +def copy_bash(ctx, src, dst): + ctx.actions.run_shell( + tools = [src], + outputs = [dst], + command = "cp -rf \"$1/\" \"$2\"", + arguments = [src.path, dst.path], + mnemonic = "CopyDirectory", + progress_message = "Copying directory", + use_default_shell_env = True, + # remote-execution does not allow source directory inputs + # https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2 + execution_requirements = {"no-remote-exec": "1"}, + ) + +def _copy_directory_impl(ctx): + out = ctx.attr.out.strip() + if not out: + fail("out attr must not be empty") + output = ctx.actions.declare_directory(out) + if ctx.attr.is_windows: + copy_cmd(ctx, ctx.file.src, output) + else: + copy_bash(ctx, ctx.file.src, output) + + files = depset(direct = [output]) + runfiles = ctx.runfiles(files = [output]) + return [DefaultInfo(files = files, runfiles = runfiles)] + +_ATTRS = { + "src": attr.label(mandatory = True, allow_single_file = True), + "out": attr.string(mandatory = True), + "is_windows": attr.bool(mandatory = True), +} + +_copy_directory = rule( + implementation = _copy_directory_impl, + provides = [DefaultInfo], + attrs = _ATTRS, +) + +def copy_directory(name, src, out, **kwargs): + """Copies a directory to another location. + + If using this rule with source directories, it is recommended that you use the + --host_jvm_args=-DBAZEL_TRACK_SOURCE_DIRECTORIES=1 startup option so that changes + to files within source directories are detected. See + https://github.com/bazelbuild/bazel/commit/c64421bc35214f0414e4f4226cc953e8c55fa0d2 + for more context. + + Args: + name: Name of the rule. + src: A Label. The directory to make a copy of. (Can also be the label of a rule + that generates a directory.) + out: Path of the output directory, relative to this package. + **kwargs: further keyword arguments, e.g. `visibility` + """ + + _copy_directory( + name = name, + src = src, + out = out, + is_windows = select({ + "@bazel_tools//src/conditions:host_windows": True, + "//conditions:default": False, + }), + **kwargs + )