Vendor dependencies

Let's see how I like this workflow.
This commit is contained in:
John Doty 2022-12-19 08:27:18 -08:00
parent 34d1830413
commit 9c435dc440
7500 changed files with 1665121 additions and 99 deletions

74
vendor/cxx/tools/buck/prelude/js/js.bzl vendored Normal file
View file

@ -0,0 +1,74 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//android:android.bzl", "android_toolchain")
load("@prelude//js:js_bundle.bzl", "js_bundle_impl")
load("@prelude//js:js_bundle_genrule.bzl", "js_bundle_genrule_impl")
load("@prelude//js:js_library.bzl", "js_library_impl")
load("@prelude//genrule.bzl", "genrule_attributes")
def _select_platform():
# FIXME: prelude// should be standalone (not refer to ovr_config//)
return select({
"DEFAULT": "android",
"ovr_config//os/constraints:iphoneos": "ios",
})
def _is_release():
# FIXME: prelude// should be standalone (not refer to ovr_config//)
return select({
"DEFAULT": False,
"ovr_config//build_mode/constraints:release": True,
})
def _is_build_only_native_code():
return select(
{
"DEFAULT": False,
"fbsource//xplat/buck2/platform/android:build_only_native_code": True,
},
)
implemented_rules = {
"js_bundle": js_bundle_impl,
"js_bundle_genrule": js_bundle_genrule_impl,
"js_library": js_library_impl,
}
extra_attributes = {
"js_bundle": {
"worker": attrs.exec_dep(),
"_android_toolchain": android_toolchain(),
"_is_release": attrs.bool(
default = _is_release(),
),
"_platform": attrs.string(
default = _select_platform(),
),
},
"js_bundle_genrule": genrule_attributes() | {
"type": attrs.string(
default = "js_bundle_genrule",
),
"_is_release": attrs.bool(
default = _is_release(),
),
"_platform": attrs.string(
default = _select_platform(),
),
},
"js_library": {
"worker": attrs.exec_dep(),
"_build_only_native_code": attrs.bool(default = _is_build_only_native_code()),
"_is_release": attrs.bool(
default = _is_release(),
),
"_platform": attrs.string(
default = _select_platform(),
),
},
}

View file

@ -0,0 +1,217 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//android:android_providers.bzl", "AndroidResourceInfo", "merge_android_packageable_info")
load("@prelude//android:android_resource.bzl", "JAVA_PACKAGE_FILENAME", "aapt2_compile", "get_text_symbols")
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
load("@prelude//js:js_providers.bzl", "JsBundleInfo", "JsLibraryInfo", "get_transitive_outputs")
load("@prelude//js:js_utils.bzl", "RAM_BUNDLE_TYPES", "TRANSFORM_PROFILES", "get_bundle_name", "get_flavors", "run_worker_command")
load("@prelude//utils:utils.bzl", "expect", "map_idx")
def _build_dependencies_file(
ctx: "context",
transform_profile: str.type,
flavors: [str.type],
transitive_js_library_outputs: "transitive_set_args_projection") -> "artifact":
dependencies_file = ctx.actions.declare_output("{}/dependencies_file", transform_profile)
# ctx.attrs.extra_json can contain attrs.arg().
#
# As a result, we need to pass extra_data_args as hidden arguments so that the rule
# it is referencing exists as an input.
extra_data_args = cmd_args(
ctx.attrs.extra_json if ctx.attrs.extra_json else "{}",
delimiter = "",
)
job_args = {
"command": "dependencies",
"entryPoints": [ctx.attrs.entry] if type(ctx.attrs.entry) == "string" else list(ctx.attrs.entry),
"extraData": extra_data_args,
"flavors": flavors,
"libraries": transitive_js_library_outputs,
"outputFilePath": dependencies_file,
"platform": ctx.attrs._platform,
"release": ctx.attrs._is_release,
}
command_args_file = ctx.actions.write_json(
"{}_dep_command_args".format(transform_profile),
job_args,
)
run_worker_command(
ctx = ctx,
worker_tool = ctx.attrs.worker,
command_args_file = command_args_file,
identifier = transform_profile,
category = "dependencies",
hidden_artifacts = cmd_args([
dependencies_file.as_output(),
extra_data_args,
]).add(transitive_js_library_outputs),
)
return dependencies_file
def _build_js_bundle(
ctx: "context",
bundle_name: str.type,
ram_bundle_name: str.type,
ram_bundle_command: str.type,
transform_profile: str.type,
flavors: [str.type],
transitive_js_library_outputs: "transitive_set_args_projection",
dependencies_file: "artifact") -> JsBundleInfo.type:
base_dir = "{}_{}".format(ram_bundle_name, transform_profile) if ram_bundle_name else transform_profile
assets_dir = ctx.actions.declare_output("{}/assets_dir".format(base_dir))
bundle_dir_output = ctx.actions.declare_output("{}/js".format(base_dir))
misc_dir_path = ctx.actions.declare_output("{}/misc_dir_path".format(base_dir))
source_map = ctx.actions.declare_output("{}/source_map".format(base_dir))
# ctx.attrs.extra_json can contain attrs.arg().
#
# As a result, we need to pass extra_data_args as hidden arguments so that the rule
# it is referencing exists as an input.
extra_data_args = cmd_args(
ctx.attrs.extra_json if ctx.attrs.extra_json else "{}",
delimiter = "",
)
job_args = {
"assetsDirPath": assets_dir,
"bundlePath": cmd_args(
[bundle_dir_output, bundle_name],
delimiter = "/",
),
"command": "bundle",
"entryPoints": [ctx.attrs.entry] if type(ctx.attrs.entry) == "string" else list(ctx.attrs.entry),
"extraData": extra_data_args,
"flavors": flavors,
"libraries": transitive_js_library_outputs,
"miscDirPath": misc_dir_path,
"platform": ctx.attrs._platform,
"release": ctx.attrs._is_release,
"sourceMapPath": source_map,
}
if ram_bundle_command:
job_args["ramBundle"] = ram_bundle_command
command_args_file = ctx.actions.write_json(
"{}_bundle_command_args".format(base_dir),
job_args,
)
run_worker_command(
ctx = ctx,
worker_tool = ctx.attrs.worker,
command_args_file = command_args_file,
identifier = base_dir,
category = job_args["command"],
hidden_artifacts = cmd_args([
bundle_dir_output.as_output(),
assets_dir.as_output(),
misc_dir_path.as_output(),
source_map.as_output(),
extra_data_args,
]).add(transitive_js_library_outputs),
)
return JsBundleInfo(
bundle_name = bundle_name,
built_js = bundle_dir_output,
source_map = source_map,
res = assets_dir,
misc = misc_dir_path,
dependencies_file = dependencies_file,
)
def _get_fallback_transform_profile(ctx: "context") -> str.type:
if ctx.attrs.fallback_transform_profile in TRANSFORM_PROFILES:
return ctx.attrs.fallback_transform_profile
if ctx.attrs.fallback_transform_profile == "default" or ctx.attrs.fallback_transform_profile == None:
return "transform-profile-default"
fail("Invalid fallback_transform_profile attribute {}!".format(ctx.attrs.fallback_transform_profile))
def _get_default_providers(js_bundle_info: JsBundleInfo.type) -> ["provider"]:
return [DefaultInfo(default_outputs = [js_bundle_info.built_js])]
def _get_android_resource_info(ctx: "context", js_bundle_info: JsBundleInfo.type, identifier: str.type) -> "AndroidResourceInfo":
aapt2_compile_output = aapt2_compile(
ctx,
js_bundle_info.res,
ctx.attrs._android_toolchain[AndroidToolchainInfo],
identifier = identifier,
)
expect(ctx.attrs.android_package != None, "Must provide android_package for android builds!")
r_dot_java_package = ctx.actions.write("{}_{}".format(identifier, JAVA_PACKAGE_FILENAME), ctx.attrs.android_package)
return AndroidResourceInfo(
aapt2_compile_output = aapt2_compile_output,
allow_strings_as_assets_resource_filtering = True,
assets = js_bundle_info.built_js,
manifest_file = None,
r_dot_java_package = r_dot_java_package,
res = js_bundle_info.res,
text_symbols = get_text_symbols(ctx, js_bundle_info.res, [], identifier),
)
def _get_extra_providers(ctx: "context", js_bundle_info: JsBundleInfo.type, identifier: str.type) -> ["provider"]:
providers = [js_bundle_info]
if ctx.attrs._platform == "android":
resource_info = _get_android_resource_info(ctx, js_bundle_info, identifier)
providers.append(resource_info)
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps, resource_info = resource_info))
return providers
def js_bundle_impl(ctx: "context") -> ["provider"]:
sub_targets = {}
default_outputs = []
extra_unnamed_output_providers = None
bundle_name = get_bundle_name(ctx, "{}.js".format(ctx.attrs.name))
flavors = get_flavors(ctx)
for transform_profile in TRANSFORM_PROFILES:
dep_infos = map_idx(JsLibraryInfo, [dep[DefaultInfo].sub_targets[transform_profile] for dep in ctx.attrs.deps])
transitive_js_library_tset = get_transitive_outputs(ctx.actions, deps = dep_infos)
transitive_js_library_outputs = transitive_js_library_tset.project_as_args("artifacts")
dependencies_file = _build_dependencies_file(ctx, transform_profile, flavors, transitive_js_library_outputs)
for ram_bundle_name, ram_bundle_command in RAM_BUNDLE_TYPES.items():
js_bundle_info = _build_js_bundle(ctx, bundle_name, ram_bundle_name, ram_bundle_command, transform_profile, flavors, transitive_js_library_outputs, dependencies_file)
simple_name = transform_profile if not ram_bundle_name else "{}-{}".format(ram_bundle_name, transform_profile)
built_js_providers = _get_default_providers(js_bundle_info)
extra_providers = _get_extra_providers(ctx, js_bundle_info, simple_name)
misc_providers = [DefaultInfo(default_outputs = [js_bundle_info.misc])]
source_map_providers = [DefaultInfo(default_outputs = [js_bundle_info.source_map])]
dependencies_providers = [DefaultInfo(default_outputs = [js_bundle_info.dependencies_file])]
sub_targets[simple_name] = built_js_providers + extra_providers
sub_targets["{}-misc".format(simple_name)] = misc_providers
sub_targets["{}-source_map".format(simple_name)] = source_map_providers
sub_targets["{}-dependencies".format(simple_name)] = dependencies_providers
fallback_transform_profile = _get_fallback_transform_profile(ctx)
if transform_profile == fallback_transform_profile:
if not ram_bundle_name:
default_outputs.append(js_bundle_info.built_js)
expect(extra_unnamed_output_providers == None, "Extra unnamed output providers should only be set once!")
extra_unnamed_output_providers = extra_providers
sub_targets["misc"] = misc_providers
sub_targets["source_map"] = source_map_providers
sub_targets["dependencies"] = dependencies_providers
else:
sub_targets[ram_bundle_name] = built_js_providers + extra_providers
sub_targets["{}-misc".format(ram_bundle_name)] = misc_providers
sub_targets["{}-source_map".format(ram_bundle_name)] = source_map_providers
sub_targets["{}-dependencies".format(ram_bundle_name)] = dependencies_providers
expect(len(default_outputs) == 1, "Should get exactly one default output!")
expect(extra_unnamed_output_providers != None, "Should set extra unnamed output providers once!")
return [
DefaultInfo(default_outputs = default_outputs, sub_targets = sub_targets),
] + extra_unnamed_output_providers

View file

@ -0,0 +1,129 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//:genrule.bzl", "process_genrule")
load("@prelude//android:android_providers.bzl", "AndroidResourceInfo", "merge_android_packageable_info")
load("@prelude//js:js_providers.bzl", "JsBundleInfo")
load("@prelude//js:js_utils.bzl", "RAM_BUNDLE_TYPES", "TRANSFORM_PROFILES", "get_bundle_name")
load("@prelude//utils:utils.bzl", "expect")
def _build_js_bundle(
ctx: "context",
bundle_name_out: str.type,
js_bundle_info: JsBundleInfo.type,
named_output: str.type) -> JsBundleInfo.type:
env_vars = {
"DEPENDENCIES": cmd_args(js_bundle_info.dependencies_file),
"JS_BUNDLE_NAME": cmd_args(js_bundle_info.bundle_name),
"JS_BUNDLE_NAME_OUT": cmd_args(bundle_name_out),
"JS_DIR": cmd_args(js_bundle_info.built_js),
"MISC_DIR": cmd_args(js_bundle_info.misc),
"PLATFORM": cmd_args(ctx.attrs._platform),
"RELEASE": cmd_args("1" if ctx.attrs._is_release else ""),
"RES_DIR": cmd_args(js_bundle_info.res),
"SOURCEMAP": cmd_args(js_bundle_info.source_map),
}
if ctx.attrs.rewrite_sourcemap:
source_map_out = ctx.actions.declare_output("{}/source_map".format(named_output))
env_vars["SOURCEMAP_OUT"] = cmd_args(source_map_out.as_output())
else:
source_map_out = js_bundle_info.source_map
if ctx.attrs.rewrite_misc:
misc_out = ctx.actions.declare_output("{}/misc".format(named_output))
env_vars["MISC_OUT"] = cmd_args(misc_out.as_output())
else:
misc_out = js_bundle_info.misc
if ctx.attrs.rewrite_deps_file:
dependencies_out = ctx.actions.declare_output("{}/dependencies".format(named_output))
env_vars["DEPENDENCIES_OUT"] = cmd_args(dependencies_out.as_output())
else:
dependencies_out = js_bundle_info.dependencies_file
providers = process_genrule(ctx, "{}-js".format(named_output), None, env_vars, named_output)
expect(
len(providers) == 1,
"expected exactly one provider of type DefaultInfo from {} ({})"
.format(ctx.label.name, providers),
)
default_info = providers[0] # DefaultInfo type
outputs = default_info.default_outputs
expect(
len(outputs) == 1,
"expected exactly one output from {} ({})"
.format(ctx.label.name, outputs),
)
built_js = outputs[0]
return JsBundleInfo(
bundle_name = bundle_name_out,
built_js = built_js,
source_map = source_map_out,
res = js_bundle_info.res,
misc = misc_out,
dependencies_file = dependencies_out,
)
def _get_extra_providers(
ctx: "context",
skip_resources: bool.type,
initial_target: ["provider_collection", "dependency"],
js_bundle_out: JsBundleInfo.type) -> ["provider"]:
providers = []
android_resource_info = initial_target[AndroidResourceInfo]
if android_resource_info:
new_android_resource_info = AndroidResourceInfo(
aapt2_compile_output = None if skip_resources else android_resource_info.aapt2_compile_output,
allow_strings_as_assets_resource_filtering = True,
assets = js_bundle_out.built_js,
manifest_file = None,
r_dot_java_package = None if skip_resources else android_resource_info.r_dot_java_package,
res = None if skip_resources else android_resource_info.res,
text_symbols = None if skip_resources else android_resource_info.text_symbols,
)
providers.append(new_android_resource_info)
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, deps = [], resource_info = new_android_resource_info))
return providers
def js_bundle_genrule_impl(ctx: "context") -> ["provider"]:
sub_targets = {}
for transform_profile in TRANSFORM_PROFILES:
for ram_bundle_name in RAM_BUNDLE_TYPES.keys():
simple_named_output = transform_profile if not ram_bundle_name else "{}-{}".format(ram_bundle_name, transform_profile)
js_bundle = ctx.attrs.js_bundle[DefaultInfo].sub_targets[simple_named_output]
js_bundle_info = js_bundle[JsBundleInfo]
bundle_name_out = get_bundle_name(ctx, js_bundle_info.bundle_name)
js_bundle_out = _build_js_bundle(ctx, bundle_name_out, js_bundle_info, simple_named_output)
sub_targets[simple_named_output] = [
DefaultInfo(default_outputs = [js_bundle_out.built_js]),
js_bundle_out,
] + _get_extra_providers(ctx, ctx.attrs.skip_resources, js_bundle, js_bundle_out)
sub_targets["{}-misc".format(simple_named_output)] = [DefaultInfo(default_outputs = [js_bundle_out.misc])]
sub_targets["{}-source_map".format(simple_named_output)] = [DefaultInfo(default_outputs = [js_bundle_out.source_map])]
sub_targets["{}-dependencies".format(simple_named_output)] = [DefaultInfo(default_outputs = [js_bundle_out.dependencies_file])]
js_bundle_info = ctx.attrs.js_bundle[JsBundleInfo]
bundle_name_out = get_bundle_name(ctx, js_bundle_info.bundle_name)
js_bundle_out = _build_js_bundle(ctx, bundle_name_out, js_bundle_info, "default")
sub_targets["dependencies"] = [DefaultInfo(default_outputs = [js_bundle_out.dependencies_file])]
sub_targets["misc"] = [DefaultInfo(default_outputs = [js_bundle_out.misc])]
sub_targets["source_map"] = [DefaultInfo(default_outputs = [js_bundle_out.source_map])]
default_info_out = DefaultInfo(
default_outputs = [js_bundle_out.built_js],
sub_targets = sub_targets,
)
return [default_info_out, js_bundle_out] + _get_extra_providers(ctx, ctx.attrs.skip_resources, ctx.attrs.js_bundle, js_bundle_out)

View file

@ -0,0 +1,215 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//:paths.bzl", "paths")
load("@prelude//js:js_providers.bzl", "JsLibraryInfo", "get_transitive_outputs")
load("@prelude//js:js_utils.bzl", "TRANSFORM_PROFILES", "get_canonical_src_name", "get_flavors", "run_worker_command")
load("@prelude//utils:utils.bzl", "expect", "map_idx")
# A group of sources that all have the same canonical name. The main_source is arbitrary but
# consistent (it is just the first source encountered when processing the src files).
GroupedSource = record(
canonical_name = str.type,
main_source = "artifact",
additional_sources = ["artifact"],
)
def _get_grouped_srcs(ctx: "context") -> [GroupedSource.type]:
grouped_srcs = {}
for src in ctx.attrs.srcs:
# TODO(ianc) also support sources with an "inner path".
expect(
type(src) == "artifact",
"src {} is not an artifact, its type is: {}".format(src, type(src)),
)
canonical_src_name = get_canonical_src_name(src.short_path)
if grouped_srcs.get(canonical_src_name, None) == None:
grouped_srcs[canonical_src_name] = GroupedSource(
canonical_name = canonical_src_name,
main_source = src,
additional_sources = [],
)
else:
grouped_srcs[canonical_src_name].additional_sources.append(src)
return grouped_srcs.values()
def _get_virtual_path(ctx: "context", src: "artifact", base_path: [str.type, None]) -> str.type:
package = ctx.label.package
if base_path and base_path not in ["", "."]:
package = paths.join(package, base_path)
return paths.join(package, src.short_path)
def _build_js_file(
ctx: "context",
transform_profile: str.type,
flavors: [str.type],
grouped_src: GroupedSource.type) -> "artifact":
identifier = "{}/{}".format(transform_profile, grouped_src.canonical_name)
output_path = ctx.actions.declare_output(identifier)
job_args = {
"additionalSources": [{
"sourcePath": additional_source,
"virtualPath": _get_virtual_path(ctx, additional_source, ctx.attrs.base_path),
} for additional_source in grouped_src.additional_sources],
"command": "transform",
"flavors": flavors,
"outputFilePath": output_path,
"release": ctx.attrs._is_release,
"sourceJsFileName": _get_virtual_path(ctx, grouped_src.main_source, ctx.attrs.base_path),
"sourceJsFilePath": grouped_src.main_source,
"transformProfile": "default" if transform_profile == "transform-profile-default" else transform_profile,
}
if ctx.attrs.extra_json:
job_args["extraData"] = cmd_args(ctx.attrs.extra_json, delimiter = "")
command_args_file = ctx.actions.write_json(
"{}_command_args".format(identifier),
job_args,
)
run_worker_command(
ctx = ctx,
worker_tool = ctx.attrs.worker,
command_args_file = command_args_file,
identifier = identifier,
category = "transform",
hidden_artifacts = cmd_args([
output_path.as_output(),
grouped_src.main_source,
] + grouped_src.additional_sources),
)
return output_path
def _build_library_files(
ctx: "context",
transform_profile: str.type,
flavors: [str.type],
js_files: ["artifact"]) -> "artifact":
output_path = ctx.actions.declare_output("{}/library_files".format(transform_profile))
command_args_file = ctx.actions.write_json(
"library_files_{}_command_args".format(transform_profile),
{
"command": "library-files",
"flavors": flavors,
"outputFilePath": output_path,
"platform": ctx.attrs._platform,
"release": ctx.attrs._is_release,
"sourceFilePaths": js_files,
},
)
run_worker_command(
ctx = ctx,
worker_tool = ctx.attrs.worker,
command_args_file = command_args_file,
identifier = transform_profile,
category = "library_files",
hidden_artifacts = cmd_args([output_path.as_output()] + js_files),
)
return output_path
def _build_js_library(
ctx: "context",
transform_profile: str.type,
library_files: "artifact",
flavors: [str.type],
js_library_deps: ["artifact"]) -> "artifact":
output_path = ctx.actions.declare_output("{}.jslib".format(transform_profile))
job_args = {
"aggregatedSourceFilesFilePath": library_files,
"command": "library-dependencies",
"dependencyLibraryFilePaths": js_library_deps,
"flavors": flavors,
"outputPath": output_path,
"platform": ctx.attrs._platform,
"release": ctx.attrs._is_release,
}
if ctx.attrs.extra_json:
job_args["extraData"] = cmd_args(ctx.attrs.extra_json, delimiter = "")
command_args_file = ctx.actions.write_json(
"library_deps_{}_args".format(transform_profile),
job_args,
)
run_worker_command(
ctx = ctx,
worker_tool = ctx.attrs.worker,
command_args_file = command_args_file,
identifier = transform_profile,
category = "library_dependencies",
hidden_artifacts = cmd_args([
output_path.as_output(),
library_files,
] + js_library_deps),
)
return output_path
def js_library_impl(ctx: "context") -> ["provider"]:
if ctx.attrs._build_only_native_code:
sub_targets = {}
unused_output = ctx.actions.write("unused.js", [])
for transform_profile in TRANSFORM_PROFILES:
sub_targets[transform_profile] = [
DefaultInfo(default_outputs = [unused_output]),
JsLibraryInfo(
output = unused_output,
transitive_outputs = None,
),
]
return [
DefaultInfo(default_outputs = [], sub_targets = sub_targets),
]
grouped_srcs = _get_grouped_srcs(ctx)
flavors = get_flavors(ctx)
sub_targets = {}
for transform_profile in TRANSFORM_PROFILES:
built_js_files = [
_build_js_file(ctx, transform_profile, flavors, grouped_src)
for grouped_src in grouped_srcs
]
library_files = _build_library_files(ctx, transform_profile, flavors, built_js_files)
js_library_deps = dedupe(map_idx(
JsLibraryInfo,
[dep[DefaultInfo].sub_targets[transform_profile] for dep in ctx.attrs.deps],
))
js_library = _build_js_library(
ctx,
transform_profile,
library_files,
flavors,
[js_library_dep.output for js_library_dep in js_library_deps],
)
transitive_outputs = get_transitive_outputs(
ctx.actions,
value = js_library,
deps = js_library_deps,
)
sub_targets[transform_profile] = [
DefaultInfo(default_outputs = [js_library]),
JsLibraryInfo(
output = js_library,
transitive_outputs = transitive_outputs,
),
]
return [
DefaultInfo(default_outputs = [], sub_targets = sub_targets),
]

View file

@ -0,0 +1,47 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
def _artifacts(value: "artifact"):
return value
TransitiveOutputsTSet = transitive_set(args_projections = {"artifacts": _artifacts})
JsLibraryInfo = provider(
fields = [
"output", # "artifact"
"transitive_outputs", # ["TransitiveOutputsTSet", None]
],
)
JsBundleInfo = provider(
fields = [
"bundle_name", # str.type
# Directory containing the built JavaScript.
"built_js", # "artifact",
# Source map belonging to the built JavaScript.
"source_map", # "artifact",
# Directory containing the resources (or assets) used by the bundled JavaScript source code.
"res", # ["artifact", None]
# Directory containing various metadata that can be used by dependent rules but are not
# meant to be shipped with the application.
"misc", # "artifact"
# Dependencies graph file associated with the built JavaScript.
"dependencies_file", # "artifact"
],
)
def get_transitive_outputs(
actions: "actions",
value: ["artifact", None] = None,
deps: [JsLibraryInfo.type] = []) -> TransitiveOutputsTSet.type:
kwargs = {}
if value:
kwargs["value"] = value
if deps:
kwargs["children"] = filter(None, [js_library_info.transitive_outputs for js_library_info in deps])
return actions.tset(TransitiveOutputsTSet, **kwargs)

View file

@ -0,0 +1,129 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.
load("@prelude//:paths.bzl", "paths")
load("@prelude//:worker_tool.bzl", "WorkerToolInfo")
load("@prelude//utils:utils.bzl", "expect")
RAM_BUNDLE_TYPES = {
"": "",
"rambundle-indexed": "--indexed-rambundle",
}
TRANSFORM_PROFILES = ["transform-profile-default", "hermes-stable", "hermes-canary"]
# Matches the default value for resolver.assetExts in metro-config
ASSET_EXTENSIONS = [
# Image formats
"bmp",
"gif",
"jpg",
"jpeg",
"png",
"psd",
"svg",
"webp",
# Video formats
"m4v",
"mov",
"mp4",
"mpeg",
"mpg",
"webm",
# Audio formats
"aac",
"aiff",
"caf",
"m4a",
"mp3",
"wav",
# Document formats
"html",
"pdf",
"yaml",
"yml",
# Font formats
"otf",
"ttf",
# Archives (virtual files)
"zip",
]
# Matches the default value for resolver.platforms in metro-config
ASSET_PLATFORMS = ["ios", "android", "windows", "web"]
def _strip_platform_from_asset_name(name: str.type) -> str.type:
name_without_extension, extension = paths.split_extension(name)
return name_without_extension if extension[1:] in ASSET_PLATFORMS else name
def _strip_scale_from_asset_name(name: str.type) -> str.type:
scale_start = -1
for i in range(len(name)):
char = name[i]
if scale_start != -1:
if char == "x":
return name[:scale_start] + name[i + 1:]
if char.isdigit() or char == ".":
continue
fail("Invalid format for scale of asset {}!".format(name))
if name[i] == "@":
scale_start = i
expect(scale_start == -1, "Found scale_start but not its end {}!".format(name))
return name
def get_canonical_src_name(src: str.type) -> str.type:
basename, extension = paths.split_extension(src)
if extension[1:] not in ASSET_EXTENSIONS:
return src
basename = _strip_platform_from_asset_name(basename)
basename = _strip_scale_from_asset_name(basename)
return basename + extension
def get_flavors(ctx: "context") -> [str.type]:
flavors = [ctx.attrs._platform]
if ctx.attrs._is_release:
flavors.append("release")
return flavors
def get_bundle_name(ctx: "context", default_bundle_name: str.type) -> str.type:
bundle_name_for_flavor_map = {key: value for key, value in ctx.attrs.bundle_name_for_flavor}
flavors = bundle_name_for_flavor_map.keys()
for flavor in flavors:
expect(
flavor == "android" or flavor == "ios",
"Currently only support picking bundle name by platform!",
)
platform = ctx.attrs._platform
if platform in flavors:
return bundle_name_for_flavor_map[platform]
else:
return default_bundle_name
def run_worker_command(
ctx: "context",
worker_tool: "dependency",
command_args_file: "artifact",
identifier: str.type,
category: str.type,
hidden_artifacts = "cmd_args"):
worker_tool_info = worker_tool[WorkerToolInfo]
worker_command = worker_tool_info.command.copy()
worker_command.add("--command-args-file", command_args_file)
worker_command.hidden(hidden_artifacts)
worker_command.add("--command-args-file-extra-data-fixup-hack=true")
ctx.actions.run(
worker_command,
category = category.replace("-", "_"),
identifier = identifier,
)