Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bazel: Output UMD modules for NodeJS #194

Merged
merged 1 commit into from
Aug 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 88 additions & 74 deletions defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ TypescriptProtoLibraryAspect = provider(
},
)

def proto_path(proto):
def _proto_path(proto):
"""
The proto path is not really a file path
It's the path to the proto that was seen when the descriptor file was generated.
Expand All @@ -31,57 +31,86 @@ def proto_path(proto):
path = path[1:]
return path

def append_to_outputs(ctx, file_name, js_outputs, dts_outputs):
generated_filenames = ["_pb.d.ts", "_pb.js", "_pb_service.js", "_pb_service.d.ts"]

for f in generated_filenames:
output = ctx.actions.declare_file(file_name + f)
if f.endswith(".d.ts"):
dts_outputs.append(output)
else:
js_outputs.append(output)
def _get_protoc_inputs(target, ctx):
inputs = []
inputs += target.proto.direct_sources
inputs += target.proto.transitive_descriptor_sets.to_list()
return inputs

def _change_js_file_import_style(ctx, js_protoc_outputs, style):
def _get_input_proto_names(target):
"""
Calls the convert_to_amd tool to convert the generated JS code into AMD modules.
Builds a string containing all of the input proto file names separated by spaces.
"""
proto_inputs = []
for src in target.proto.direct_sources:
if src.extension != "proto":
fail("Input must be a proto file")
normalized_file = _proto_path(src)
proto_inputs.append(normalized_file)
return " ".join(proto_inputs)

js_outputs = []
for js_file in js_protoc_outputs:
def _build_protoc_command(target, ctx):
protoc_command = "%s" % (ctx.file._protoc.path)

protoc_command += " --plugin=protoc-gen-ts=%s" % (ctx.files._ts_protoc_gen[1].path)

protoc_output_dir = ctx.var["BINDIR"]
protoc_command += " --ts_out=service=true:%s" % (protoc_output_dir)
protoc_command += " --js_out=import_style=commonjs,binary:%s" % (protoc_output_dir)

descriptor_sets_paths = [desc.path for desc in target.proto.transitive_descriptor_sets.to_list()]
protoc_command += " --descriptor_set_in=%s" % (":".join(descriptor_sets_paths))

protoc_command += " %s" % (_get_input_proto_names(target))

return protoc_command

def _create_post_process_command(target, ctx, js_outputs, js_outputs_es6):
"""
Builds a post-processing command that:
- Updates the existing protoc output files to be UMD modules
- Creates a new es6 file from the original protoc output
"""
convert_commands = []
for [output, output_es6] in zip(js_outputs, js_outputs_es6):
file_path = "/".join([p for p in [
ctx.workspace_name,
ctx.label.package,
] if p])
file_name = js_file.basename[:-len(js_file.extension) - 1]

ext = "amd"
if style == "commonjs":
ext = "closure"

output = ctx.actions.declare_file("{}.{}.{}".format(file_name, ext, js_file.extension))
js_outputs.append(output)
ctx.actions.run(
inputs = [js_file],
outputs = [output],
arguments = [
"--workspace_name",
ctx.workspace_name,
"--input_base_path",
file_path,
"--output_module_name",
file_name,
"--input_file_path",
js_file.path,
"--output_file_path",
output.path,
"--style",
style,
],
progress_message = "Creating an {} module for {}".format(style, ctx.label),
executable = ctx.executable._change_import_style,
)
file_name = output.basename[:-len(output.extension) - 1]

convert_command = ctx.files._change_import_style[1].path
convert_command += " --workspace_name {}".format(ctx.workspace_name)
convert_command += " --input_base_path {}".format(file_path)
convert_command += " --output_module_name {}".format(file_name)
convert_command += " --input_file_path {}".format(output.path)
convert_command += " --output_umd_path {}".format(output.path)
convert_command += " --output_es6_path {}".format(output_es6.path)
convert_commands.append(convert_command)

return " && ".join(convert_commands)

return js_outputs
def _get_outputs(target, ctx):
"""
Calculates all of the files that will be generated by the aspect.
"""
js_outputs = []
js_outputs_es6 = []
dts_outputs = []
for src in target.proto.direct_sources:
file_name = src.basename[:-len(src.extension) - 1]
for f in ["_pb", "_pb_service"]:
full_name = file_name + f
output = ctx.actions.declare_file(full_name + ".js")
js_outputs.append(output)
output_es6 = ctx.actions.declare_file(full_name + ".closure.js")
js_outputs_es6.append(output_es6)

for f in ["_pb.d.ts", "_pb_service.d.ts"]:
output = ctx.actions.declare_file(file_name + f)
dts_outputs.append(output)

return [js_outputs, js_outputs_es6, dts_outputs]

def typescript_proto_library_aspect_(target, ctx):
"""
Expand All @@ -90,46 +119,31 @@ def typescript_proto_library_aspect_(target, ctx):

Handles running protoc to produce the generated JS and TS files.
"""
js_protoc_outputs = []
dts_outputs = []
proto_inputs = []

inputs = [ctx.file._protoc]
for src in target.proto.direct_sources:
if src.extension != "proto":
fail("Input must be a proto file")
[js_outputs, js_outputs_es6, dts_outputs] = _get_outputs(target, ctx)
protoc_outputs = dts_outputs + js_outputs + js_outputs_es6

file_name = src.basename[:-len(src.extension) - 1]
normalized_file = proto_path(src)
proto_inputs.append(normalized_file)
append_to_outputs(ctx, file_name, js_protoc_outputs, dts_outputs)

outputs = dts_outputs + js_protoc_outputs

inputs += target.proto.direct_sources
inputs += target.proto.transitive_descriptor_sets.to_list()

descriptor_sets_paths = [desc.path for desc in target.proto.transitive_descriptor_sets.to_list()]
all_commands = [
_build_protoc_command(target, ctx),
_create_post_process_command(target, ctx, js_outputs, js_outputs_es6),
]

protoc_output_dir = ctx.var["BINDIR"]
protoc_command = "%s" % (ctx.file._protoc.path)
tools = []
tools.extend(ctx.files._protoc)
tools.extend(ctx.files._ts_protoc_gen)
tools.extend(ctx.files._change_import_style)

protoc_command += " --plugin=protoc-gen-ts=%s" % (ctx.files._ts_protoc_gen[1].path)
protoc_command += " --ts_out=service=true:%s" % (protoc_output_dir)
protoc_command += " --js_out=import_style=commonjs,binary:%s" % (protoc_output_dir)
protoc_command += " --descriptor_set_in=%s" % (":".join(descriptor_sets_paths))
protoc_command += " %s" % (" ".join(proto_inputs))
ctx.actions.run_shell(
inputs = depset(inputs),
outputs = outputs,
inputs = depset(_get_protoc_inputs(target, ctx)),
outputs = protoc_outputs,
progress_message = "Creating Typescript pb files %s" % ctx.label,
command = protoc_command,
tools = depset(ctx.files._ts_protoc_gen),
command = " && ".join(all_commands),
tools = depset(tools),
)

dts_outputs = depset(dts_outputs)
es5_outputs = depset(_change_js_file_import_style(ctx, js_protoc_outputs, style = "amd"))
es6_outputs = depset(_change_js_file_import_style(ctx, js_protoc_outputs, style = "commonjs"))
es5_outputs = depset(js_outputs)
es6_outputs = depset(js_outputs_es6)
deps_dts = []
deps_es5 = []
deps_es6 = []
Expand Down
Loading