From 9ffa490d3f40f3f6d9163a49945af5bb9e7bf5f8 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Wed, 16 Aug 2017 09:02:20 -0700 Subject: [PATCH] refactor(compiler-cli): move ngc-wrapped to packages/bazel (#18733) See design: https://goo.gl/rAeYWx PR Close #18733 --- .pullapprove.yml | 3 +- packages/bazel/BUILD.bazel | 1 + packages/bazel/WORKSPACE | 21 +++ packages/bazel/index.bzl | 9 + packages/bazel/package.json | 15 ++ packages/bazel/src/BUILD.bazel | 1 + packages/bazel/src/ng_module.bzl | 155 ++++++++++++++++++ .../bazel/src}/ngc-wrapped/BUILD.bazel | 2 +- packages/bazel/src/ngc-wrapped/README.md | 3 + .../bazel/src}/ngc-wrapped/index.ts | 0 packages/core/BUILD.bazel | 2 +- packages/tsconfig.json | 1 + tools/ngc-wrapped/README.md | 6 - tools/tsconfig.json | 1 - 14 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 packages/bazel/BUILD.bazel create mode 100644 packages/bazel/WORKSPACE create mode 100644 packages/bazel/index.bzl create mode 100644 packages/bazel/package.json create mode 100644 packages/bazel/src/BUILD.bazel create mode 100644 packages/bazel/src/ng_module.bzl rename {tools => packages/bazel/src}/ngc-wrapped/BUILD.bazel (85%) create mode 100644 packages/bazel/src/ngc-wrapped/README.md rename {tools => packages/bazel/src}/ngc-wrapped/index.ts (100%) delete mode 100644 tools/ngc-wrapped/README.md diff --git a/.pullapprove.yml b/.pullapprove.yml index 9c9be7ca20..4f6089fa2a 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -70,7 +70,6 @@ groups: - "tools/*" exclude: - "tools/public_api_guard/*" - - "tools/ngc-wrapped/*" - "aio/*" users: - IgorMinar #primary @@ -138,7 +137,7 @@ groups: files: - "packages/tsc-wrapped/*" - "packages/compiler-cli/*" - - "tools/ngc-wrapped/*" + - "packages/bazel/*" users: - alexeagle - chuckjaz diff --git a/packages/bazel/BUILD.bazel b/packages/bazel/BUILD.bazel new file mode 100644 index 0000000000..00301d3053 --- /dev/null +++ b/packages/bazel/BUILD.bazel @@ -0,0 +1 @@ +# Empty marker file, indicating this directory is a Bazel package. diff --git a/packages/bazel/WORKSPACE b/packages/bazel/WORKSPACE new file mode 100644 index 0000000000..c0c1418247 --- /dev/null +++ b/packages/bazel/WORKSPACE @@ -0,0 +1,21 @@ +# By convention, the name should "describe the project in reverse-DNS form" +# https://docs.bazel.build/versions/master/be/functions.html#workspace +# But if we use "io_angular" then the loads used in BUILD files will +# be unfamiliar to Angular users who import from '@angular/pkg' in +# TypeScript files. We want to reduce the impedance between the Bazel +# and node naming schemes. +# We take the name "angular" so that users can write +# load("@angular//:index.bzl", "ng_module") +workspace(name = "angular") + +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +git_repository( + name = "build_bazel_rules_typescript", + remote = "https://github.com/bazelbuild/rules_typescript.git", + tag = "0.0.5", +) + +load("@build_bazel_rules_typescript//:defs.bzl", "node_repositories") + +node_repositories(package_json = ":package.json") diff --git a/packages/bazel/index.bzl b/packages/bazel/index.bzl new file mode 100644 index 0000000000..5db3236407 --- /dev/null +++ b/packages/bazel/index.bzl @@ -0,0 +1,9 @@ +# Copyright Google Inc. All Rights Reserved. +# +# Use of this source code is governed by an MIT-style license that can be +# found in the LICENSE file at https://angular.io/license +""" Public API surface is re-exported here. +Users should not load files under "/src" +""" + +load("//src:ng_module.bzl", "ng_module") diff --git a/packages/bazel/package.json b/packages/bazel/package.json new file mode 100644 index 0000000000..a055202d87 --- /dev/null +++ b/packages/bazel/package.json @@ -0,0 +1,15 @@ +{ + "name": "@angular/bazel", + "version": "0.0.0-PLACEHOLDER", + "description": "Angular - bazel build rules", + "author": "angular", + "license": "MIT", + "peerDependencies": { + "@angular/compiler-cli": "0.0.0-PLACEHOLDER", + "typescript": "~2.3" + }, + "repository": { + "type": "git", + "url": "https://github.com/angular/angular.git" + } +} diff --git a/packages/bazel/src/BUILD.bazel b/packages/bazel/src/BUILD.bazel new file mode 100644 index 0000000000..00301d3053 --- /dev/null +++ b/packages/bazel/src/BUILD.bazel @@ -0,0 +1 @@ +# Empty marker file, indicating this directory is a Bazel package. diff --git a/packages/bazel/src/ng_module.bzl b/packages/bazel/src/ng_module.bzl new file mode 100644 index 0000000000..16d66c3a74 --- /dev/null +++ b/packages/bazel/src/ng_module.bzl @@ -0,0 +1,155 @@ +# Copyright Google Inc. All Rights Reserved. +# +# Use of this source code is governed by an MIT-style license that can be +# found in the LICENSE file at https://angular.io/license + +load("@build_bazel_rules_typescript//internal:build_defs.bzl", "tsc_wrapped_tsconfig") + +load( + "@build_bazel_rules_typescript//internal:common/compilation.bzl", + "COMMON_ATTRIBUTES", "compile_ts", "ts_providers_dict_to_struct" +) + +load("@build_bazel_rules_typescript//internal:common/json_marshal.bzl", "json_marshal") + +# Calculate the expected output of the template compiler for every source in +# in the library. Most of these will be produced as empty files but it is +# unknown, without parsing, which will be empty. +def _expected_outs(ctx): + result = [] + + for src in ctx.files.srcs: + if src.short_path.endswith(".ts"): + basename = src.short_path[len(ctx.label.package) + 1:-3] + result += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in [ + ".ngfactory.js", + ".ngfactory.d.ts", + ".ngsummary.js", + ".ngsummary.d.ts", + ".ngsummary.json", + ]] + elif src.short_path.endswith(".css"): + basename = src.short_path[len(ctx.label.package) + 1:-4] + result += [ctx.new_file(ctx.bin_dir, basename + ext) for ext in [ + ".css.shim.ngstyle.js", + ".css.shim.ngstyle.d.ts", + ".css.ngstyle.js", + ".css.ngstyle.d.ts", + ]] + return result + +def _ngc_tsconfig(ctx, files, srcs, **kwargs): + return dict(tsc_wrapped_tsconfig(ctx, files, srcs, **kwargs), **{ + "angularCompilerOptions": { + "expectedOut": [o.path for o in _expected_outs(ctx)], + } + }) + +def _compile_action(ctx, inputs, outputs, config_file_path): + externs_files = [] + non_externs_files = [] + for output in outputs: + if output.basename.endswith(".es5.MF"): + ctx.file_action(output, content="") + else: + non_externs_files.append(output) + + # TODO(alexeagle): For now we mock creation of externs files + for externs_file in externs_files: + ctx.file_action(output=externs_file, content="") + + action_inputs = inputs + if hasattr(ctx.attr, "node_modules"): + action_inputs += [f for f in ctx.files.node_modules + if f.path.endswith(".ts") or f.path.endswith(".json")] + if ctx.file.tsconfig: + action_inputs += [ctx.file.tsconfig] + + # One at-sign makes this a params-file, enabling the worker strategy. + # Two at-signs escapes the argument so it's passed through to ngc + # rather than the contents getting expanded. + if ctx.attr.supports_workers: + arguments = ["@@" + config_file_path] + else: + arguments = ["-p", config_file_path] + + ctx.action( + progress_message = "Compiling Angular templates (ngc) %s" % ctx.label, + mnemonic = "AngularTemplateCompile", + inputs = action_inputs, + outputs = non_externs_files, + arguments = arguments, + executable = ctx.executable.compiler, + execution_requirements = { + "supports-workers": str(int(ctx.attr.supports_workers)), + }, + ) + +def _devmode_compile_action(ctx, inputs, outputs, config_file_path): + # TODO(alexeagle): compile for feeding to Closure Compiler + _compile_action(ctx, inputs, outputs + _expected_outs(ctx), config_file_path) + +def _compile_ng(ctx): + declarations = [] + for dep in ctx.attr.deps: + if hasattr(dep, "typescript"): + declarations += dep.typescript.transitive_declarations + + tsconfig_json = ctx.new_file(ctx.label.name + "_tsconfig.json") + ctx.file_action(output=tsconfig_json, content=json_marshal( + _ngc_tsconfig(ctx, ctx.files.srcs + declarations, ctx.files.srcs))) + + _devmode_compile_action(ctx, ctx.files.srcs + declarations + [tsconfig_json], [], tsconfig_json.path) + + return { + "files": depset(_expected_outs(ctx)), + "typescript": { + # FIXME: expose the right outputs so this looks like a ts_library + "declarations": [], + "transitive_declarations": [], + "type_blacklisted_declarations": [], + }, + } + +def _ng_module_impl(ctx): + if ctx.attr.write_ng_outputs_only: + ts_providers = _compile_ng(ctx) + else: + ts_providers = compile_ts(ctx, is_library=True, + compile_action=_compile_action, + devmode_compile_action=_devmode_compile_action, + tsc_wrapped_tsconfig=_ngc_tsconfig) + + addl_declarations = [o for o in _expected_outs(ctx) if o.path.endswith(".d.ts")] + ts_providers["typescript"]["declarations"] += addl_declarations + ts_providers["typescript"]["transitive_declarations"] += addl_declarations + + return ts_providers_dict_to_struct(ts_providers) + + +ng_module = rule( + implementation = _ng_module_impl, + attrs = dict(COMMON_ATTRIBUTES, **{ + "srcs": attr.label_list(allow_files = True), + + # To be used only to bootstrap @angular/core compilation, + # since we want to compile @angular/core with ngc, but ngc depends on + # @angular/core typescript output. + "write_ng_outputs_only": attr.bool(default = False), + "tsconfig": attr.label(allow_files = True, single_file = True), + "no_i18n": attr.bool(default = False), + # TODO(alexeagle): enable workers for ngc + "supports_workers": attr.bool(default = False), + "compiler": attr.label( + default = Label("//internal/ngc"), + executable = True, + cfg = "host", + ), + # @// is special syntax for the "main" repository + # The default assumes the user specified a target "node_modules" in their + # root BUILD file. + "node_modules": attr.label( + default = Label("@//:node_modules") + ), + }), +) \ No newline at end of file diff --git a/tools/ngc-wrapped/BUILD.bazel b/packages/bazel/src/ngc-wrapped/BUILD.bazel similarity index 85% rename from tools/ngc-wrapped/BUILD.bazel rename to packages/bazel/src/ngc-wrapped/BUILD.bazel index fb5d5cf7ac..00dc24e7e2 100644 --- a/tools/ngc-wrapped/BUILD.bazel +++ b/packages/bazel/src/ngc-wrapped/BUILD.bazel @@ -13,7 +13,7 @@ ts_library( nodejs_binary( name = "ngc-wrapped", - entry_point = "__main__/tools/ngc-wrapped/index.js", + entry_point = "__main__/packages/bazel/src/ngc-wrapped/index.js", data = [":ngc_lib"], visibility = ["//visibility:public"], ) \ No newline at end of file diff --git a/packages/bazel/src/ngc-wrapped/README.md b/packages/bazel/src/ngc-wrapped/README.md new file mode 100644 index 0000000000..b48a91a8b6 --- /dev/null +++ b/packages/bazel/src/ngc-wrapped/README.md @@ -0,0 +1,3 @@ +# ngc-wrapped + +This is a wrapper around @angular/compiler-cli that makes ngc run under Bazel. diff --git a/tools/ngc-wrapped/index.ts b/packages/bazel/src/ngc-wrapped/index.ts similarity index 100% rename from tools/ngc-wrapped/index.ts rename to packages/bazel/src/ngc-wrapped/index.ts diff --git a/packages/core/BUILD.bazel b/packages/core/BUILD.bazel index b0654c1ca6..1c2d80e76d 100644 --- a/packages/core/BUILD.bazel +++ b/packages/core/BUILD.bazel @@ -24,5 +24,5 @@ ng_module( write_ng_outputs_only = True, module_name = "@angular/core", tsconfig = ":tsconfig-build.json", - compiler = "//tools/ngc-wrapped" + compiler = "//packages/bazel/src/ngc-wrapped" ) \ No newline at end of file diff --git a/packages/tsconfig.json b/packages/tsconfig.json index d951d649f1..3794152202 100644 --- a/packages/tsconfig.json +++ b/packages/tsconfig.json @@ -25,6 +25,7 @@ "types": ["angularjs"] }, "exclude": [ + "bazel", "compiler-cli/integrationtest", "platform-server/integrationtest", "tsc-wrapped", diff --git a/tools/ngc-wrapped/README.md b/tools/ngc-wrapped/README.md deleted file mode 100644 index 4f4487e48b..0000000000 --- a/tools/ngc-wrapped/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# ngc-wrapped - -This is a wrapper around @angular/compiler-cli that makes ngc run under Bazel. -It should be identical to https://github.com/bazelbuild/rules_angular/tree/master/internal/ngc -however that is built against Angular packages from npm, while ngc-wrapped is -built using Bazel against Angular at HEAD. diff --git a/tools/tsconfig.json b/tools/tsconfig.json index 58702a2c06..114020a0d1 100644 --- a/tools/tsconfig.json +++ b/tools/tsconfig.json @@ -22,7 +22,6 @@ }, "exclude": [ "node_modules", - "ngc-wrapped", "typings-test", "public_api_guard", "docs"