Skip to content

Commit

Permalink
Allow multiple runtime packs
Browse files Browse the repository at this point in the history
* Adds support for declaring multiple runtime packs in `publish_binary`
* Add AspNetCore example

To be able to do a self contained publish of an AspNetCore application you need to be able to
declare both the `microsoft.netcore.app.runtime.<rid>` and `microsoft.aspnetcore.app.runtime.<rid>`
runtime packs
  • Loading branch information
purkhusid committed Sep 15, 2022
1 parent b436d58 commit d087a36
Show file tree
Hide file tree
Showing 17 changed files with 229 additions and 233 deletions.
4 changes: 2 additions & 2 deletions dotnet/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -265,15 +265,15 @@ def fsharp_nunit_test(
**kwargs
)

def publish_binary(name, binary, target_framework, self_contained = False, runtime_pack = None, runtime_identifier = None, **kwargs):
def publish_binary(name, binary, target_framework, self_contained = False, runtime_packs = [], runtime_identifier = None, **kwargs):
runtime_identifier = _get_runtime_runtime_identifier(runtime_identifier)

_publish_binary(
name = "{}_wrapped".format(name),
binary = binary,
target_framework = target_framework,
self_contained = self_contained,
runtime_pack = runtime_pack,
runtime_packs = runtime_packs,
tags = ["manual"],
)

Expand Down
6 changes: 3 additions & 3 deletions dotnet/private/common.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ def generate_depsjson(
runtime_deps,
transitive_runtime_deps,
runtime_identifier,
runtime_pack_info = None):
runtime_pack_infos = []):
"""Generates a deps.json file.
Args:
Expand All @@ -443,7 +443,7 @@ def generate_depsjson(
runtime_deps: The runtime dependencies of the target.
transitive_runtime_deps: The transitive runtime dependencies of the target.
runtime_identifier: The runtime identifier of the target.
runtime_pack_info: The DotnetAssemblyInfo of the runtime pack that is used for a self contained publish.
runtime_pack_infos: The DotnetAssemblyInfo of the runtime packs that are used for a self contained publish.
Returns:
The deps.json file as a struct.
"""
Expand All @@ -465,7 +465,7 @@ def generate_depsjson(
base["targets"][runtime_target] = {}
base["libraries"] = {}

if runtime_pack_info:
for runtime_pack_info in runtime_pack_infos:
runtime_pack_name = "runtimepack.{}/{}".format(runtime_pack_info.name, runtime_pack_info.version)
base["libraries"][runtime_pack_name] = {
"type": "runtimepack",
Expand Down
2 changes: 1 addition & 1 deletion dotnet/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ DotnetBinaryInfo = provider(
DotnetPublishBinaryInfo = provider(
doc = "Information about a published .Net binary",
fields = {
"runtime_pack": "AssemblyInfo: Optional information about the used runtime pack. Used by self-contained publishing",
"runtime_packs": "list[AssemblyInfo]: Optional information about the used runtime packs. Used by self-contained publishing",
"target_framework": "string: The target framework of the published binary",
"self_contained": "bool: True if the binary is self-contained",
},
Expand Down
58 changes: 32 additions & 26 deletions dotnet/private/rules/publish_binary/publish_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@ load("//dotnet/private/transitions:tfm_transition.bzl", "tfm_transition")
load("//dotnet/private:common.bzl", "generate_depsjson", "generate_runtimeconfig")

def _publish_binary_impl(ctx):
runtime_pack_info = None
runtime_pack_infos = []
if ctx.attr.self_contained == True:
if ctx.attr.runtime_pack == None or len(ctx.attr.runtime_pack) == 0:
if len(ctx.attr.runtime_packs) == 0:
fail("Can not publish self-contained binaries without a runtime pack")

runtime_pack_info = ctx.attr.runtime_pack[0][DotnetAssemblyInfo]
for runtime_pack in ctx.attr.runtime_packs:
runtime_pack_infos.append(runtime_pack[DotnetAssemblyInfo])
elif len(ctx.attr.runtime_packs) > 0:
fail("Can not do a framework dependent publish with a runtime pack")

return [
ctx.attr.binary[0][DotnetAssemblyInfo],
ctx.attr.binary[0][DotnetBinaryInfo],
DotnetPublishBinaryInfo(
runtime_pack = runtime_pack_info,
runtime_packs = runtime_pack_infos,
target_framework = ctx.attr.target_framework,
self_contained = ctx.attr.self_contained,
),
Expand All @@ -44,26 +47,28 @@ publish_binary = rule(
Whether the binary should be self-contained.
If true, the binary will be published as a self-contained but you need to provide
a runtime pack in the `runtime_pack` attribute. At some point the rules might
a runtime pack in the `runtime_packs` attribute. At some point the rules might
resolve the runtime pack automatically.
If false, the binary will be published as a non-self-contained. That means that to be
able to run the binary you need to have a .Net runtime installed on the host system.
""",
default = False,
),
"runtime_pack": attr.label(
"runtime_packs": attr.label_list(
doc = """
The runtime pack that should be used to publish the binary.
The runtime packs that should be used to publish the binary.
Should only be declared if `self_contained` is true.
The runtime pack is a NuGet package that contains the runtime that should be
used to run the binary.
A runtime pack is a NuGet package that contains the runtime that should be
used to run the binary. There can be multiple runtime packs for a given
publish e.g. when a AspNetCore application is published you need the base
runtime pack and the AspNetCore runtime pack.
Example runtime pack: https://www.nuget.org/packages/Microsoft.NETCore.App.Runtime.linux-x64/6.0.8
""",
providers = [DotnetAssemblyInfo],
default = None,
default = [],
cfg = tfm_transition,
),
# TODO:
Expand Down Expand Up @@ -155,18 +160,19 @@ def _copy_to_publish(ctx, runtime_identifier, publish_binary_info, binary_info,
# In case the publish is self-contained there needs to be a runtime pack available
# with the runtime dependencies that are required for the targeted runtime.
# The runtime pack contents should always be copied to the root of the publish folder
if publish_binary_info.runtime_pack:
runtime_pack_files = depset(
publish_binary_info.runtime_pack.libs +
publish_binary_info.runtime_pack.native +
publish_binary_info.runtime_pack.data,
transitive = [publish_binary_info.runtime_pack.transitive_libs, publish_binary_info.runtime_pack.transitive_native, publish_binary_info.runtime_pack.transitive_data],
)
for file in runtime_pack_files.to_list():
output = ctx.actions.declare_file(file.basename, sibling = app_host_copy)
outputs.append(output)
inputs.append(file)
_copy_file(script_body, file, output, is_windows = is_windows)
if len(publish_binary_info.runtime_packs) > 0:
for runtime_pack in publish_binary_info.runtime_packs:
runtime_pack_files = depset(
runtime_pack.libs +
runtime_pack.native +
runtime_pack.data,
transitive = [runtime_pack.transitive_libs, runtime_pack.transitive_native, runtime_pack.transitive_data],
)
for file in runtime_pack_files.to_list():
output = ctx.actions.declare_file(file.basename, sibling = app_host_copy)
outputs.append(output)
inputs.append(file)
_copy_file(script_body, file, output, is_windows = is_windows)

copy_script = ctx.actions.declare_file(ctx.label.name + ".copy.bat" if is_windows else ctx.label.name + ".copy.sh")
ctx.actions.write(
Expand Down Expand Up @@ -204,8 +210,8 @@ def _generate_depsjson(
runtime_deps,
transitive_runtime_deps,
runtime_identifier,
runtime_pack_info):
depsjson_struct = generate_depsjson(target_framework, is_self_contained, runtime_deps, transitive_runtime_deps, runtime_identifier, runtime_pack_info)
runtime_pack_infos):
depsjson_struct = generate_depsjson(target_framework, is_self_contained, runtime_deps, transitive_runtime_deps, runtime_identifier, runtime_pack_infos)

ctx.actions.write(
output = output,
Expand Down Expand Up @@ -251,7 +257,7 @@ def _publish_binary_wrapper_impl(ctx):
assembly_info.runtime_deps,
assembly_info.transitive_runtime_deps,
runtime_identifier,
publish_binary_info.runtime_pack,
publish_binary_info.runtime_packs,
)

return [
Expand All @@ -264,7 +270,7 @@ def _publish_binary_wrapper_impl(ctx):

# This wrapper is only needed so that we can turn the incoming transition in `publish_binary`
# into an outgoing transition in the wrapper. This allows us to select on the runtime_identifier
# and runtime_pack attributes. We also need to have all the file copying in the wrapper rule
# and runtime_packs attributes. We also need to have all the file copying in the wrapper rule
# because Bazel does not allow forwarding executable files as they have to be created by the wrapper rule.
publish_binary_wrapper = rule(
_publish_binary_wrapper_impl,
Expand Down
8 changes: 4 additions & 4 deletions dotnet/private/tests/publish/self_contained/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
publish_binary(
name = "self_contained",
binary = "//dotnet/private/tests/publish/app_to_publish",
runtime_pack = select({
"@rules_dotnet//dotnet:rid_linux-x64": "@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.linux-x64",
"@rules_dotnet//dotnet:rid_osx-x64": "@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.osx-x64",
"@rules_dotnet//dotnet:rid_win-x64": "@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.win-x64",
runtime_packs = select({
"@rules_dotnet//dotnet:rid_linux-x64": ["@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.linux-x64"],
"@rules_dotnet//dotnet:rid_osx-x64": ["@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.osx-x64"],
"@rules_dotnet//dotnet:rid_win-x64": ["@rules_dotnet_dev_nuget_packages//microsoft.netcore.app.runtime.win-x64"],
}),
self_contained = True,
target_framework = "net6.0",
Expand Down
Empty file added examples/BUILD.bazel
Empty file.
Loading

0 comments on commit d087a36

Please sign in to comment.