From d81caa9568e32c3c3575f8f86ff02ce8c36fe338 Mon Sep 17 00:00:00 2001 From: nickchapman-da <49153372+nickchapman-da@users.noreply.github.com> Date: Wed, 18 Mar 2020 23:06:55 +0000 Subject: [PATCH] rework daml_compile bazel rule (#5070) Avoiding `damlc compile/package` commands (which we would like to deprecate), and replace with plain `damlc build` together with a post dar->dalf extraction step in the couple of places where we actually want the .dalf for testing. changelog_begin changelog_end --- daml-lf/archive/BUILD.bazel | 5 +- daml-lf/tests/BUILD.bazel | 4 +- docs/BUILD.bazel | 3 +- .../upgrade/example/coin-1.0.0/daml.yaml | 2 +- .../upgrade/example/coin-2.0.0/daml.yaml | 2 +- .../upgrade/example/coin-upgrade/daml.yaml | 2 +- extractor/BUILD.bazel | 8 +- language-support/hs/bindings/BUILD.bazel | 4 +- .../hs/bindings/examples/chat/BUILD.bazel | 1 - .../bindings/examples/group-chat/BUILD.bazel | 1 - .../hs/bindings/examples/nim/BUILD.bazel | 1 - .../java/bindings-rxjava/BUILD.bazel | 2 +- language-support/java/codegen/BUILD.bazel | 4 +- .../scala/codegen-sample-app/BUILD.bazel | 4 +- language-support/ts/codegen/tests/BUILD.bazel | 12 +- ledger-service/http-json/BUILD.bazel | 2 +- ledger-service/lf-value-json/BUILD.bazel | 2 +- ledger/ledger-api-test-tool/BUILD.bazel | 4 +- ledger/sandbox-perf/BUILD.bazel | 2 +- ledger/test-common/BUILD.bazel | 4 +- rules_daml/daml-build.bzl | 131 ------- rules_daml/daml.bzl | 361 ++++++++++++++---- 22 files changed, 315 insertions(+), 246 deletions(-) delete mode 100644 rules_daml/daml-build.bzl diff --git a/daml-lf/archive/BUILD.bazel b/daml-lf/archive/BUILD.bazel index b1bea3f22dc3..322902b69dc2 100644 --- a/daml-lf/archive/BUILD.bazel +++ b/daml-lf/archive/BUILD.bazel @@ -14,6 +14,7 @@ load( load( "//rules_daml:daml.bzl", "daml_compile", + "daml_compile_with_dalf", ) load("//bazel_tools:pom_file.bzl", "pom_file") load("@os_info//:os_info.bzl", "is_windows") @@ -201,9 +202,9 @@ da_scala_test_suite( ], ) -daml_compile( +daml_compile_with_dalf( name = "DarReaderTest", - main_src = "src/test/daml/DarReaderTest.daml", + srcs = ["src/test/daml/DarReaderTest.daml"], ) # An ad-hoc tool for testing, benchmarking and profiling package decoding performance in isolation. diff --git a/daml-lf/tests/BUILD.bazel b/daml-lf/tests/BUILD.bazel index 67be06a89853..dff12d8d51e8 100644 --- a/daml-lf/tests/BUILD.bazel +++ b/daml-lf/tests/BUILD.bazel @@ -18,7 +18,7 @@ TEST_FILES = \ [ daml_compile( name = name, - main_src = "%s.daml" % name, + srcs = ["%s.daml" % name], visibility = ["//daml-lf:__subpackages__"], ) for name in TEST_FILES @@ -26,7 +26,7 @@ TEST_FILES = \ daml_compile( name = "Optional", - main_src = "Optional.daml", + srcs = ["Optional.daml"], visibility = ["//daml-lf:__subpackages__"], ) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index a0e17edf9e5a..e763740640e9 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -3,8 +3,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary") load("@os_info//:os_info.bzl", "is_linux", "is_windows") -load("//rules_daml:daml.bzl", "daml_compile", "daml_test") -load("//rules_daml:daml-build.bzl", "daml_build_test") +load("//rules_daml:daml.bzl", "daml_build_test", "daml_compile", "daml_test") load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar") load("@build_environment//:configuration.bzl", "mvn_version", "sdk_version") diff --git a/docs/source/upgrade/example/coin-1.0.0/daml.yaml b/docs/source/upgrade/example/coin-1.0.0/daml.yaml index ac172e952a80..6bf3d19df9e8 100644 --- a/docs/source/upgrade/example/coin-1.0.0/daml.yaml +++ b/docs/source/upgrade/example/coin-1.0.0/daml.yaml @@ -10,5 +10,5 @@ dependencies: - daml-stdlib # END parties: [Alice, Bob] -source: daml +source: . build-options: [--target=1.8] diff --git a/docs/source/upgrade/example/coin-2.0.0/daml.yaml b/docs/source/upgrade/example/coin-2.0.0/daml.yaml index bb89f096eceb..b4d37e40b682 100644 --- a/docs/source/upgrade/example/coin-2.0.0/daml.yaml +++ b/docs/source/upgrade/example/coin-2.0.0/daml.yaml @@ -10,5 +10,5 @@ dependencies: - daml-stdlib # END parties: [Alice, Bob] -source: daml +source: . build-options: [--target=1.8] diff --git a/docs/source/upgrade/example/coin-upgrade/daml.yaml b/docs/source/upgrade/example/coin-upgrade/daml.yaml index 7885c1283020..00a840c4bf0d 100644 --- a/docs/source/upgrade/example/coin-upgrade/daml.yaml +++ b/docs/source/upgrade/example/coin-upgrade/daml.yaml @@ -13,5 +13,5 @@ data-dependencies: - path/to/coin-2.0.0.dar # END parties: [Alice, Bob] -source: daml +source: . build-options: [--target=1.8] diff --git a/extractor/BUILD.bazel b/extractor/BUILD.bazel index e9135cb6471a..7d6dd5b87385 100644 --- a/extractor/BUILD.bazel +++ b/extractor/BUILD.bazel @@ -26,7 +26,7 @@ TEST_DARS = [ [ daml_compile( name = darmod, - main_src = "src/test/resources/damls/%s.daml" % darmod, + srcs = ["src/test/resources/damls/%s.daml" % darmod], # FixMe: https://github.com/digital-asset/daml/issues/2289 # change version to lf_latest_version when freezing numeric in the next language version target = lf_dev_version, @@ -68,8 +68,10 @@ module VeryLargeArchive.Blob1 where daml_compile( name = "VeryLargeArchive", - srcs = [":VeryLargeArchive_src"], - main_src = ":VeryLargeArchive/Blobs.daml", + srcs = [ + ":VeryLargeArchive/Blobs.daml", + ":VeryLargeArchive_src", + ], ) da_scala_library( diff --git a/language-support/hs/bindings/BUILD.bazel b/language-support/hs/bindings/BUILD.bazel index 74b08e0210de..83bd7f645aaf 100644 --- a/language-support/hs/bindings/BUILD.bazel +++ b/language-support/hs/bindings/BUILD.bazel @@ -36,13 +36,11 @@ da_haskell_library( daml_compile( name = "for-tests", srcs = glob(["test/daml/for-tests/*.daml"]), - main_src = "test/daml/for-tests/Main.daml", ) daml_compile( name = "for-upload", - srcs = glob(["test/daml/for-upload/ExtraModule.daml"]), - main_src = "test/daml/for-upload/ExtraModule.daml", + srcs = ["test/daml/for-upload/ExtraModule.daml"], ) da_haskell_test( diff --git a/language-support/hs/bindings/examples/chat/BUILD.bazel b/language-support/hs/bindings/examples/chat/BUILD.bazel index f3c42de328aa..f73ce284e4b5 100644 --- a/language-support/hs/bindings/examples/chat/BUILD.bazel +++ b/language-support/hs/bindings/examples/chat/BUILD.bazel @@ -7,7 +7,6 @@ load("//rules_daml:daml.bzl", "daml_compile") daml_compile( name = "Chat", srcs = glob(["daml/*.daml"]), - main_src = "daml/Chat.daml", ) da_haskell_binary( diff --git a/language-support/hs/bindings/examples/group-chat/BUILD.bazel b/language-support/hs/bindings/examples/group-chat/BUILD.bazel index 61d8715dc90b..5e9cc6fd10c7 100644 --- a/language-support/hs/bindings/examples/group-chat/BUILD.bazel +++ b/language-support/hs/bindings/examples/group-chat/BUILD.bazel @@ -8,7 +8,6 @@ load("@os_info//:os_info.bzl", "is_windows") daml_compile( name = "GroupChat", srcs = glob(["daml/GroupChat.daml"]), - main_src = "daml/GroupChat.daml", ) daml_test( diff --git a/language-support/hs/bindings/examples/nim/BUILD.bazel b/language-support/hs/bindings/examples/nim/BUILD.bazel index f82e5f57eb33..e806bfbc450b 100644 --- a/language-support/hs/bindings/examples/nim/BUILD.bazel +++ b/language-support/hs/bindings/examples/nim/BUILD.bazel @@ -7,7 +7,6 @@ load("//rules_daml:daml.bzl", "daml_compile") daml_compile( name = "Nim", srcs = glob(["daml/*.daml"]), - main_src = "daml/Nim.daml", ) da_haskell_binary( diff --git a/language-support/java/bindings-rxjava/BUILD.bazel b/language-support/java/bindings-rxjava/BUILD.bazel index 7d0f2326a07a..5291709c4bc8 100644 --- a/language-support/java/bindings-rxjava/BUILD.bazel +++ b/language-support/java/bindings-rxjava/BUILD.bazel @@ -117,7 +117,7 @@ da_scala_test_suite( daml_compile( name = "bindings-integration-tests-model-latest", - main_src = "src/main/daml/TemplateUtils.daml", + srcs = ["src/main/daml/TemplateUtils.daml"], target = lf_stable_version, ) diff --git a/language-support/java/codegen/BUILD.bazel b/language-support/java/codegen/BUILD.bazel index e19baee655e5..3c9eed89a6c3 100644 --- a/language-support/java/codegen/BUILD.bazel +++ b/language-support/java/codegen/BUILD.bazel @@ -92,7 +92,7 @@ da_scala_test( daml_compile( name = "test-daml", - main_src = "src/test/daml/Foo.daml", + srcs = ["src/test/daml/Foo.daml"], ) jar_jar( @@ -195,7 +195,6 @@ alias( daml_compile( name = "integration-tests-model-latest", srcs = glob(["src/it/daml/**/*.daml"]), - main_src = "src/it/daml/Lib.daml", target = lf_latest_version, ) @@ -247,7 +246,6 @@ daml_compile( daml_compile( name = "ledger-tests-model", srcs = glob(["src/ledger-tests/daml/**/*.daml"]), - main_src = "src/ledger-tests/daml/AllTests.daml", target = lf_stable_version, ) diff --git a/language-support/scala/codegen-sample-app/BUILD.bazel b/language-support/scala/codegen-sample-app/BUILD.bazel index efcc0ba159e3..1b5d48511189 100644 --- a/language-support/scala/codegen-sample-app/BUILD.bazel +++ b/language-support/scala/codegen-sample-app/BUILD.bazel @@ -19,7 +19,7 @@ load( daml_compile( name = "MyMain", - main_src = "src/main/daml/MyMain.daml", + srcs = ["src/main/daml/MyMain.daml"], # FIXME https://github.com/digital-asset/daml/issues/2256 # switch to latest once 1.9 is frozen target = lf_dev_version, @@ -27,7 +27,7 @@ daml_compile( daml_compile( name = "MySecondMain", - main_src = "src/main/daml/MySecondMain.daml", + srcs = ["src/main/daml/MySecondMain.daml"], target = lf_latest_version, ) diff --git a/language-support/ts/codegen/tests/BUILD.bazel b/language-support/ts/codegen/tests/BUILD.bazel index 7238a2d9c2f5..34b0268e1757 100644 --- a/language-support/ts/codegen/tests/BUILD.bazel +++ b/language-support/ts/codegen/tests/BUILD.bazel @@ -7,12 +7,12 @@ load("@build_environment//:configuration.bzl", "sdk_version") load("@os_info//:os_info.bzl", "is_windows") # This rule builds a dar from the daml sources under the 'daml' -# directory. It is referenced from the 'build-and-lint' test target that +# directory. It is referenced from the 'build-and-lint-test' target that # follows. daml_compile( - name = "build-and-lint-1.0.0", + name = "build-and-lint", srcs = glob(["daml/**/*.daml"]), - main_src = "daml/Main.daml", + version = "1.0.0", ) # build-and-lint @@ -70,7 +70,7 @@ daml_compile( # - Gracefully tears down the processes it started when its work is done. # All in all, a pretty slick bit of work! sh_test( - name = "build-and-lint", + name = "build-and-lint-test", size = "large", srcs = ["build-and-lint.sh"], args = [ @@ -79,7 +79,7 @@ sh_test( "$(location //:daml2ts)", "$(location //ledger/sandbox:sandbox-binary_deploy.jar)", "$(location //ledger-service/http-json:http-json-binary_deploy.jar)", - "$(location :build-and-lint-1.0.0.dar)", + "$(location :build-and-lint.dar)", "$(location ts/package.json)", "$(location //language-support/ts/daml-types:npm_package)", "$(location //language-support/ts/daml-ledger:npm_package)", @@ -91,7 +91,7 @@ sh_test( "//:daml2ts", "//ledger/sandbox:sandbox-binary_deploy.jar", "//ledger-service/http-json:http-json-binary_deploy.jar", - ":build-and-lint-1.0.0.dar", + ":build-and-lint.dar", "//language-support/ts/daml-types:npm_package", "//language-support/ts/daml-ledger:npm_package", ] + glob( diff --git a/ledger-service/http-json/BUILD.bazel b/ledger-service/http-json/BUILD.bazel index 11d468963c52..3425a4dc1092 100644 --- a/ledger-service/http-json/BUILD.bazel +++ b/ledger-service/http-json/BUILD.bazel @@ -104,7 +104,7 @@ da_scala_binary( daml_compile( name = "Account", - main_src = "src/test/daml/Account.daml", + srcs = ["src/test/daml/Account.daml"], ) da_scala_test( diff --git a/ledger-service/lf-value-json/BUILD.bazel b/ledger-service/lf-value-json/BUILD.bazel index 944dd3d27286..771a9ec48320 100644 --- a/ledger-service/lf-value-json/BUILD.bazel +++ b/ledger-service/lf-value-json/BUILD.bazel @@ -30,7 +30,7 @@ da_scala_library( daml_compile( name = "JsonEncodingTest", - main_src = "src/test/daml/JsonEncodingTest.daml", + srcs = ["src/test/daml/JsonEncodingTest.daml"], ) da_scala_test( diff --git a/ledger/ledger-api-test-tool/BUILD.bazel b/ledger/ledger-api-test-tool/BUILD.bazel index 150adc0dbb11..88071cd3e0d3 100644 --- a/ledger/ledger-api-test-tool/BUILD.bazel +++ b/ledger/ledger-api-test-tool/BUILD.bazel @@ -31,7 +31,7 @@ load( daml_compile( name = "PackageManagementTest", - main_src = "src/main/daml/PackageManagementTest.daml", + srcs = ["src/main/daml/PackageManagementTest.daml"], target = lf_stable_version, ) @@ -106,7 +106,7 @@ da_scala_binary( main_class = "com.daml.ledger.api.testtool.LedgerApiTestTool", resources = [ "src/main/resources/logback.xml", - ":PackageManagementTest", + ":PackageManagementTest.dar", "//ledger/test-common:dar-files", ], tags = [ diff --git a/ledger/sandbox-perf/BUILD.bazel b/ledger/sandbox-perf/BUILD.bazel index 9ad9a3bf93e4..2fc66acd6a45 100644 --- a/ledger/sandbox-perf/BUILD.bazel +++ b/ledger/sandbox-perf/BUILD.bazel @@ -46,7 +46,7 @@ da_scala_library( daml_compile( name = "LargeTransaction", - main_src = "src/perf/resources/damls/LargeTransaction.daml", + srcs = ["src/perf/resources/damls/LargeTransaction.daml"], visibility = ["//visibility:public"], ) diff --git a/ledger/test-common/BUILD.bazel b/ledger/test-common/BUILD.bazel index 18be80632558..444e5b4c1a7a 100644 --- a/ledger/test-common/BUILD.bazel +++ b/ledger/test-common/BUILD.bazel @@ -38,7 +38,7 @@ da_scala_library( daml_compile( name = "SemanticTests", - main_src = "src/main/daml/SemanticTests.daml", + srcs = ["src/main/daml/SemanticTests.daml"], target = lf_stable_version, visibility = ["//visibility:public"], ) @@ -76,8 +76,8 @@ lf_test_versions = [ srcs = [ "src/main/daml/Iou.daml", "src/main/daml/IouTrade.daml", + "src/main/daml/Test.daml", ], - main_src = "src/main/daml/Test.daml", target = target, visibility = ["//visibility:public"], ), diff --git a/rules_daml/daml-build.bzl b/rules_daml/daml-build.bzl deleted file mode 100644 index dede9019c334..000000000000 --- a/rules_daml/daml-build.bzl +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (c) 2020 The DAML Authors. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -def file_of_target(k): - [file] = k.files.to_list() - return file - -_damlc = attr.label( - allow_single_file = True, - default = Label("//compiler/damlc"), - executable = True, - cfg = "host", -) - -def _daml_build_impl(ctx): - name = ctx.label.name - config = ctx.file.config - damls = ctx.files.damls - dd = ctx.attr.dar_dict - damlc = ctx.file._damlc - input_dars = [file_of_target(k) for k in dd.keys()] - output_dar = ctx.actions.declare_file(name + ".dar") - ctx.actions.run_shell( - tools = depset([damlc]), - inputs = depset([config] + damls + input_dars), - outputs = [output_dar], - progress_message = "Building DAML project %s" % name, - command = """ - set -eou pipefail - tmpdir=$(mktemp -d) - trap "rm -rf $tmpdir" EXIT - mkdir -p $tmpdir/daml - cp -f {config} $tmpdir - {cp_damls} - {cp_dars} - {damlc} build --project-root $tmpdir -o $PWD/{output_dar} - """.format( - config = config.path, - cp_damls = "\n".join([ - "cp {daml} $tmpdir/daml".format( - daml = daml.path, - ) - for daml in damls - ]), - cp_dars = "\n".join([ - "mkdir -p $(dirname $tmpdir/{b}); cp -f {a} $tmpdir/{b}".format( - a = file_of_target(k).path, - b = v, - ) - for k, v in dd.items() - ]), - damlc = damlc.path, - output_dar = output_dar.path, - ), - ) - return [DefaultInfo(files = depset([output_dar]))] - -_daml_build = rule( - implementation = _daml_build_impl, - attrs = { - "config": attr.label( - allow_single_file = ["daml.yaml"], - mandatory = True, - doc = "DAML configuration file to build from.", - ), - "damls": attr.label_list( - allow_files = True, - mandatory = True, - doc = "DAML files in this DAML project.", - ), - "dar_dict": attr.label_keyed_string_dict( - default = {}, - doc = "Other DAML projects referenced by this DAML project.", - ), - "_damlc": _damlc, - }, -) - -def _daml_validate_test_impl(ctx): - name = ctx.label.name - project_dar = ctx.file.project_dar - script = ctx.actions.declare_file(name + ".sh") - damlc = ctx.file._damlc - script_content = """ - set -eou pipefail - DAMLC=$(rlocation $TEST_WORKSPACE/{damlc}) - DAR=$(rlocation $TEST_WORKSPACE/{dar}) - $DAMLC validate-dar $DAR - """.format( - damlc = damlc.short_path, - dar = project_dar.short_path, - ) - ctx.actions.write( - output = script, - content = script_content, - ) - runfiles = ctx.runfiles(files = [project_dar, damlc]) - return [DefaultInfo(executable = script, runfiles = runfiles)] - -_daml_validate_test = rule( - implementation = _daml_validate_test_impl, - attrs = { - "project_dar": attr.label( - allow_single_file = True, - mandatory = True, - doc = "The DAML project whose .dar we want to validate.", - ), - "_damlc": _damlc, - }, - test = True, -) - -def daml_build_test( - name, - project_dir, - daml_config_basename = "daml.yaml", - daml_subdir_basename = "daml", - **kwargs): - "Build a DAML project and validate the resulting .dar file." - config = project_dir + "/" + daml_config_basename - damls = native.glob([project_dir + "/" + daml_subdir_basename + "/**/*.daml"]) - _daml_build( - name = name, - config = config, - damls = damls, - **kwargs - ) - _daml_validate_test( - name = "{name}.test".format(name = name), - project_dar = name, - ) diff --git a/rules_daml/daml.bzl b/rules_daml/daml.bzl index a2b80a110b09..eee8afe15cfe 100644 --- a/rules_daml/daml.bzl +++ b/rules_daml/daml.bzl @@ -1,94 +1,299 @@ # Copyright (c) 2020 The DAML Authors. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -load("@bazel_skylib//lib:paths.bzl", "paths") -load("@build_environment//:configuration.bzl", "ghc_version") - -daml_provider = provider(doc = "DAML provider", fields = { - "dalf": "The DAML-LF file.", - "dar": "The packaged archive.", -}) - -def _daml_impl_compile_dalf(ctx): - # Call damlc compile - compile_args = ctx.actions.args() - compile_args.add("compile") - compile_args.add(ctx.file.main_src) - compile_args.add("--output", ctx.outputs.dalf.path) - if ctx.attr.target: - compile_args.add("--target", ctx.attr.target) - ctx.actions.run( - inputs = depset([ctx.file.main_src] + ctx.files.srcs), - outputs = [ctx.outputs.dalf], - arguments = [compile_args], - progress_message = "Compiling DAML into DAML-LF archive %s" % ctx.outputs.dalf.short_path, - executable = ctx.executable.damlc, - ) - -def _daml_impl_package_dar(ctx): - # Call damlc package - package_args = ctx.actions.args() - package_args.add("package") - package_args.add(ctx.file.main_src) - package_args.add(ctx.attr.name) - if ctx.attr.target: - package_args.add("--target", ctx.attr.target) - package_args.add("--output") - package_args.add(ctx.outputs.dar.path) - ctx.actions.run( - inputs = [ctx.file.main_src] + ctx.files.srcs, - outputs = [ctx.outputs.dar], - arguments = [package_args], - progress_message = "Creating DAR package %s" % ctx.outputs.dar.basename, - executable = ctx.executable.damlc, - ) - -def _daml_compile_impl(ctx): - _daml_impl_compile_dalf(ctx) - _daml_impl_package_dar(ctx) - - # DAML provider - daml = daml_provider( - dalf = ctx.outputs.dalf, - dar = ctx.outputs.dar, - ) - return [daml] - -def _daml_compile_outputs_impl(name): - patterns = { - "dalf": "{name}.dalf", - "dar": "{name}.dar", - } - return { - k: v.format(name = name) - for (k, v) in patterns.items() - } - -daml_compile = rule( - implementation = _daml_compile_impl, +load("@build_environment//:configuration.bzl", "ghc_version", "sdk_version") + +_damlc = attr.label( + allow_single_file = True, + default = Label("//compiler/damlc"), + executable = True, + cfg = "host", + doc = "The DAML compiler.", +) + +_zipper = attr.label( + allow_single_file = True, + default = Label("@bazel_tools//tools/zip:zipper"), + executable = True, + cfg = "host", +) + +def _daml_configure_impl(ctx): + project_name = ctx.attr.project_name + project_version = ctx.attr.project_version + daml_yaml = ctx.outputs.daml_yaml + target = ctx.attr.target + ctx.actions.write( + output = daml_yaml, + content = """ + sdk-version: {sdk} + name: {name} + version: {version} + source: . + dependencies: [] + build-options: [{target}] + """.format( + sdk = sdk_version, + name = project_name, + version = project_version, + target = "--target=" + target if (target) else "", + ), + ) + +_daml_configure = rule( + implementation = _daml_configure_impl, + attrs = { + "project_name": attr.string( + mandatory = True, + doc = "Name of the DAML project.", + ), + "project_version": attr.string( + mandatory = True, + doc = "Version of the DAML project.", + ), + "daml_yaml": attr.output( + mandatory = True, + doc = "The generated daml.yaml config file.", + ), + "target": attr.string( + doc = "DAML-LF version to output.", + ), + }, +) + +def file_of_target(k): + [file] = k.files.to_list() + return file + +def make_cp_command(src, dest): + return "mkdir -p $(dirname {dest}); cp -f {src} {dest}".format( + src = src, + dest = dest, + ) + +def _daml_build_impl(ctx): + name = ctx.label.name + daml_yaml = ctx.file.daml_yaml + srcs = ctx.files.srcs + dar_dict = ctx.attr.dar_dict + damlc = ctx.file._damlc + input_dars = [file_of_target(k) for k in dar_dict.keys()] + output_dar = ctx.outputs.dar + ctx.actions.run_shell( + tools = [damlc], + inputs = [daml_yaml] + srcs + input_dars, + outputs = [output_dar], + progress_message = "Building DAML project %s" % name, + command = """ + set -eou pipefail + tmpdir=$(mktemp -d) + trap "rm -rf $tmpdir" EXIT + cp -f {config} $tmpdir/daml.yaml + {cp_srcs} + {cp_dars} + {damlc} build --project-root $tmpdir -o $PWD/{output_dar} + """.format( + config = daml_yaml.path, + cp_srcs = "\n".join([ + make_cp_command( + src = src.path, + dest = "$tmpdir/" + src.path, + ) + for src in srcs + ]), + cp_dars = "\n".join([ + make_cp_command( + src = file_of_target(k).path, + dest = "$tmpdir/" + v, + ) + for k, v in dar_dict.items() + ]), + damlc = damlc.path, + output_dar = output_dar.path, + ), + ) + +_daml_build = rule( + implementation = _daml_build_impl, attrs = { - "main_src": attr.label( - allow_single_file = [".daml"], + "daml_yaml": attr.label( + allow_single_file = True, mandatory = True, - doc = "The main DAML file that will be passed to the compiler.", + doc = "The daml.yaml config file.", ), "srcs": attr.label_list( allow_files = [".daml"], - default = [], - doc = "Other DAML files that compilation depends on.", + mandatory = True, + doc = "DAML files in this DAML project.", ), - "target": attr.string(doc = "DAML-LF version to output"), - "damlc": attr.label( - executable = True, - cfg = "host", - allow_files = True, - default = Label("//compiler/damlc"), + "dar_dict": attr.label_keyed_string_dict( + mandatory = True, + doc = "Other DAML projects referenced by this DAML project.", ), + "dar": attr.output( + mandatory = True, + doc = "The generated DAR file.", + ), + "_damlc": _damlc, }, - executable = False, - outputs = _daml_compile_outputs_impl, ) +def _extract_main_dalf_impl(ctx): + project_name = ctx.attr.project_name + project_version = ctx.attr.project_version + input_dar = ctx.file.dar + output_dalf = ctx.outputs.dalf + zipper = ctx.file._zipper + posix = ctx.toolchains["@rules_sh//sh/posix:toolchain_type"] + ctx.actions.run_shell( + tools = [zipper], + inputs = [input_dar], + outputs = [output_dalf], + progress_message = "Extract DALF from DAR (%s)" % project_name, + command = """ + set -eou pipefail + {zipper} x {input_dar} + main_dalf=$({find} . -name '{project_name}-{project_version}-[a-z0-9]*.dalf') + cp $main_dalf {output_dalf} + """.format( + zipper = zipper.path, + find = posix.commands["find"], + project_name = project_name, + project_version = project_version, + input_dar = input_dar.path, + output_dalf = output_dalf.path, + ), + ) + +_extract_main_dalf = rule( + implementation = _extract_main_dalf_impl, + attrs = { + "project_name": attr.string( + mandatory = True, + doc = "Name of the DAML project.", + ), + "project_version": attr.string( + mandatory = True, + doc = "Version of the DAML project.", + ), + "dar": attr.label( + allow_single_file = [".dar"], + mandatory = True, + doc = "The DAR from which the DALF will be extracted.", + ), + "dalf": attr.output( + mandatory = True, + doc = "The extracted DALF.", + ), + "_zipper": _zipper, + }, + toolchains = ["@rules_sh//sh/posix:toolchain_type"], +) + +def _daml_validate_test_impl(ctx): + name = ctx.label.name + dar = ctx.file.dar + script = ctx.actions.declare_file(name + ".sh") + damlc = ctx.file._damlc + script_content = """ + set -eou pipefail + DAMLC=$(rlocation $TEST_WORKSPACE/{damlc}) + DAR=$(rlocation $TEST_WORKSPACE/{dar}) + $DAMLC validate-dar $DAR + """.format( + damlc = damlc.short_path, + dar = dar.short_path, + ) + ctx.actions.write( + output = script, + content = script_content, + ) + runfiles = ctx.runfiles(files = [dar, damlc]) + return [DefaultInfo(executable = script, runfiles = runfiles)] + +_daml_validate_test = rule( + implementation = _daml_validate_test_impl, + attrs = { + "dar": attr.label( + allow_single_file = True, + mandatory = True, + doc = "The DAR to validate.", + ), + "_damlc": _damlc, + }, + test = True, +) + +_default_project_version = "1.0.0" + +def daml_compile( + name, + srcs, + version = _default_project_version, + target = None, + **kwargs): + "Build a DAML project, with a generated daml.yaml." + if len(srcs) == 0: + fail("daml_compile: Expected `srcs' to be non-empty.") + daml_yaml = name + ".yaml" + _daml_configure( + name = name + ".configure", + project_name = name, + project_version = version, + daml_yaml = daml_yaml, + target = target, + **kwargs + ) + _daml_build( + name = name + ".build", + daml_yaml = daml_yaml, + srcs = srcs, + dar_dict = {}, + dar = name + ".dar", + **kwargs + ) + +def daml_compile_with_dalf( + name, + version = _default_project_version, + **kwargs): + "Build a DAML project, with a generated daml.yaml, and extract the main DALF." + daml_compile( + name = name, + version = version, + **kwargs + ) + _extract_main_dalf( + name = name + ".extract", + project_name = name, + project_version = version, + dar = name + ".dar", + dalf = name + ".dalf", + ) + +def daml_build_test( + name, + project_dir, + daml_config_basename = "daml.yaml", + daml_subdir_basename = "daml", + dar_dict = {}, + **kwargs): + "Build a DAML project and validate the resulting .dar file." + daml_yaml = project_dir + "/" + daml_config_basename + srcs = native.glob([project_dir + "/" + daml_subdir_basename + "/**/*.daml"]) + _daml_build( + name = name, + daml_yaml = daml_yaml, + srcs = srcs, + dar_dict = dar_dict, + dar = name + ".dar", + **kwargs + ) + _daml_validate_test( + name = name + ".test", + dar = name + ".dar", + ) + def _daml_test_impl(ctx): script = """ set -eou pipefail