mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-20 09:17:43 +03:00
47f9ce18cb
I started with wanting to remove the warning on incomplete pattern match, thinking example code should be "good". Then I decided I should skim the corresponding docs to check if that warning, or the pragma, were actually mentioned in the text. It turns out the warning should be there, but the pragma is not explained and not necessary to get the warning. So the pargma can go. But in the process I noticed a couple things that I belive can be improved in the wording of the document, so I went agead and made a few changes. CHANGELOG_BEGIN CHANGELOG_END
470 lines
14 KiB
Python
470 lines
14 KiB
Python
# Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
load("@build_environment//:configuration.bzl", "ghc_version", "sdk_version")
|
|
load("//bazel_tools/sh:sh.bzl", "sh_inline_test")
|
|
load("//daml-lf/language:daml-lf.bzl", "COMPILER_LF_VERSIONS", "versions")
|
|
load("@bazel_skylib//lib:paths.bzl", "paths")
|
|
|
|
_damlc = attr.label(
|
|
default = Label("//compiler/damlc:damlc-compile-only"),
|
|
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
|
|
dependencies = ctx.attr.dependencies
|
|
data_dependencies = ctx.attr.data_dependencies
|
|
daml_yaml = ctx.outputs.daml_yaml
|
|
target = ctx.attr.target
|
|
opts = ["--target={}".format(target)] if target else []
|
|
ctx.actions.write(
|
|
output = daml_yaml,
|
|
content = """
|
|
sdk-version: {sdk}
|
|
name: {name}
|
|
version: {version}
|
|
source: .
|
|
data-dependencies: [{data_dependencies}]
|
|
dependencies: [{dependencies}]
|
|
build-options: [{opts}]
|
|
""".format(
|
|
sdk = sdk_version,
|
|
name = project_name,
|
|
version = project_version,
|
|
opts = ", ".join(opts),
|
|
dependencies = ", ".join(dependencies),
|
|
data_dependencies = ", ".join(data_dependencies),
|
|
),
|
|
)
|
|
|
|
_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.",
|
|
),
|
|
"dependencies": attr.string_list(
|
|
doc = "Dependencies.",
|
|
),
|
|
"data_dependencies": attr.string_list(
|
|
doc = "Data dependencies.",
|
|
),
|
|
},
|
|
)
|
|
|
|
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.executable.damlc
|
|
input_dars = [file_of_target(k) for k in dar_dict.keys()]
|
|
output_dar = ctx.outputs.dar
|
|
posix = ctx.toolchains["@rules_sh//sh/posix:toolchain_type"]
|
|
ghc_opts = ctx.attr.ghc_options
|
|
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
|
|
# Having to produce all the daml.yaml files via a genrule is annoying
|
|
# so we allow hardcoded version numbers and patch them here.
|
|
{sed} -i 's/^sdk-version:.*$/sdk-version: {sdk_version}/' $tmpdir/daml.yaml
|
|
{sed} -i 's/daml-script$/daml-script.dar/;s/daml-trigger$/daml-trigger.dar/' $tmpdir/daml.yaml
|
|
{cp_srcs}
|
|
{cp_dars}
|
|
{damlc} build --project-root $tmpdir {ghc_opts} -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()
|
|
]),
|
|
sed = posix.commands["sed"],
|
|
damlc = damlc.path,
|
|
output_dar = output_dar.path,
|
|
sdk_version = sdk_version,
|
|
ghc_opts = " ".join(ghc_opts),
|
|
),
|
|
)
|
|
|
|
_daml_build = rule(
|
|
implementation = _daml_build_impl,
|
|
attrs = {
|
|
"daml_yaml": attr.label(
|
|
allow_single_file = True,
|
|
mandatory = True,
|
|
doc = "The daml.yaml config file.",
|
|
),
|
|
"srcs": attr.label_list(
|
|
allow_files = [".daml"],
|
|
mandatory = True,
|
|
doc = "Daml files in this Daml project.",
|
|
),
|
|
"dar_dict": attr.label_keyed_string_dict(
|
|
mandatory = True,
|
|
allow_files = True,
|
|
doc = "Other Daml projects referenced by this Daml project.",
|
|
),
|
|
"dar": attr.output(
|
|
mandatory = True,
|
|
doc = "The generated DAR file.",
|
|
),
|
|
"ghc_options": attr.string_list(
|
|
doc = "Options passed to GHC.",
|
|
default = ["--ghc-option=-Werror", "--log-level=WARNING"],
|
|
),
|
|
"damlc": _damlc,
|
|
},
|
|
toolchains = ["@rules_sh//sh/posix:toolchain_type"],
|
|
)
|
|
|
|
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
|
|
TMPDIR=$(mktemp -d)
|
|
trap "rm -rf $TMPDIR" EXIT
|
|
# While zipper has a -d option, it insists on it
|
|
# being a relative path so we don't use it.
|
|
ZIPPER=$PWD/{zipper}
|
|
DAR=$PWD/{input_dar}
|
|
(cd $TMPDIR && $ZIPPER x $DAR)
|
|
main_dalf=$({find} $TMPDIR/ -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(
|
|
name,
|
|
dar,
|
|
**kwargs):
|
|
damlc = "//compiler/damlc:damlc-compile-only"
|
|
sh_inline_test(
|
|
name = name,
|
|
data = [damlc, dar],
|
|
cmd = """\
|
|
DAMLC=$$(canonicalize_rlocation $(rootpath {damlc}))
|
|
|
|
$$DAMLC validate-dar $$(canonicalize_rlocation $(rootpath {dar}))
|
|
""".format(
|
|
damlc = damlc,
|
|
dar = dar,
|
|
),
|
|
**kwargs
|
|
)
|
|
|
|
def _inspect_dar_impl(ctx):
|
|
dar = ctx.file.dar
|
|
damlc = ctx.executable.damlc
|
|
pp = ctx.outputs.pp
|
|
ctx.actions.run(
|
|
executable = damlc,
|
|
inputs = [dar],
|
|
outputs = [pp],
|
|
arguments = ["inspect", dar.path, "-o", pp.path],
|
|
)
|
|
|
|
_inspect_dar = rule(
|
|
implementation = _inspect_dar_impl,
|
|
attrs = {
|
|
"dar": attr.label(
|
|
allow_single_file = True,
|
|
mandatory = True,
|
|
),
|
|
"damlc": _damlc,
|
|
"pp": attr.output(mandatory = True),
|
|
},
|
|
)
|
|
|
|
_default_project_version = "1.0.0"
|
|
|
|
default_damlc_opts = ["--ghc-option=-Werror", "--log-level=WARNING"]
|
|
|
|
def damlc_for_target(target):
|
|
if not target or target in COMPILER_LF_VERSIONS:
|
|
return "//compiler/damlc:damlc-compile-only"
|
|
else:
|
|
return "@damlc_legacy//:damlc_legacy"
|
|
|
|
def path_to_dar(data):
|
|
return Label(data).name + ".dar"
|
|
|
|
def daml_compile(
|
|
name,
|
|
srcs,
|
|
version = _default_project_version,
|
|
target = None,
|
|
project_name = None,
|
|
ghc_options = default_damlc_opts,
|
|
enable_scenarios = False,
|
|
dependencies = [],
|
|
data_dependencies = [],
|
|
**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(
|
|
dependencies = [path_to_dar(dep) for dep in dependencies],
|
|
data_dependencies = [path_to_dar(data) for data in data_dependencies],
|
|
name = name + ".configure",
|
|
project_name = project_name or 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: path_to_dar(dar) for dar in (dependencies + data_dependencies)},
|
|
dar = name + ".dar",
|
|
ghc_options =
|
|
ghc_options +
|
|
(["--enable-scenarios=yes"] if enable_scenarios and (target == None or versions.gte(target, "1.14")) else []),
|
|
damlc = damlc_for_target(target),
|
|
**kwargs
|
|
)
|
|
_inspect_dar(
|
|
name = "{}-inspect".format(name),
|
|
dar = "{}.dar".format(name),
|
|
pp = "{}.dar.pp".format(name),
|
|
damlc = damlc_for_target(target),
|
|
)
|
|
|
|
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",
|
|
daml_yaml = None,
|
|
dar_dict = {},
|
|
ghc_options = default_damlc_opts,
|
|
**kwargs):
|
|
"Build a Daml project and validate the resulting .dar file."
|
|
if not daml_yaml:
|
|
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",
|
|
ghc_options = ghc_options,
|
|
**kwargs
|
|
)
|
|
_daml_validate_test(
|
|
name = name + ".test",
|
|
dar = name + ".dar",
|
|
)
|
|
|
|
def daml_test(
|
|
name,
|
|
srcs = [],
|
|
deps = [],
|
|
data_deps = [],
|
|
damlc = "//compiler/damlc:damlc",
|
|
additional_compiler_flags = [],
|
|
target = None,
|
|
**kwargs):
|
|
sh_inline_test(
|
|
name = name,
|
|
data = [damlc] + srcs + deps + data_deps,
|
|
cmd = """\
|
|
set -eou pipefail
|
|
tmpdir=$$(mktemp -d)
|
|
trap "rm -rf $$tmpdir" EXIT
|
|
DAMLC=$$(canonicalize_rlocation $(rootpath {damlc}))
|
|
rlocations () {{ for i in $$@; do echo $$(canonicalize_rlocation $$i); done; }}
|
|
DEPS=($$(rlocations {deps}))
|
|
DATA_DEPS=($$(rlocations {data_deps}))
|
|
JOINED_DATA_DEPS="$$(printf ',"%s"' $${{DATA_DEPS[@]}})"
|
|
echo "$$JOINED_DATA_DEPS"
|
|
cat << EOF > $$tmpdir/daml.yaml
|
|
build-options: [{target}]
|
|
sdk-version: {sdk_version}
|
|
name: test
|
|
version: 0.0.1
|
|
source: .
|
|
dependencies: [daml-stdlib, daml-prim $$([ $${{#DEPS[@]}} -gt 0 ] && printf ',"%s"' $${{DEPS[@]}})]
|
|
data-dependencies: [$$([ $${{#DATA_DEPS[@]}} -gt 0 ] && printf '%s' $${{JOINED_DATA_DEPS:1}})]
|
|
EOF
|
|
cat $$tmpdir/daml.yaml
|
|
{cp_srcs}
|
|
cd $$tmpdir
|
|
$$DAMLC test {damlc_opts} --files {files}
|
|
""".format(
|
|
damlc = damlc,
|
|
files = " ".join(["$(rootpaths %s)" % src for src in srcs]),
|
|
sdk_version = sdk_version,
|
|
deps = " ".join(["$(rootpaths %s)" % dep for dep in deps]),
|
|
data_deps = " ".join(["$(rootpaths %s)" % dep for dep in data_deps]),
|
|
damlc_opts = " ".join(default_damlc_opts + additional_compiler_flags),
|
|
cp_srcs = "\n".join([
|
|
"mkdir -p $$(dirname {dest}); cp -f {src} {dest}".format(
|
|
src = "$$(canonicalize_rlocation $(rootpath {}))".format(src),
|
|
dest = "$$tmpdir/$(rootpath {})".format(src),
|
|
)
|
|
for src in srcs
|
|
]),
|
|
target = "--target=" + target if (target) else "",
|
|
),
|
|
**kwargs
|
|
)
|
|
|
|
def daml_doc_test(
|
|
name,
|
|
package_name,
|
|
srcs = [],
|
|
ignored_srcs = [],
|
|
flags = [],
|
|
cpp = "@stackage-exe//hpp",
|
|
damlc = "//compiler/damlc:damlc",
|
|
**kwargs):
|
|
sh_inline_test(
|
|
name = name,
|
|
data = [cpp, damlc] + srcs,
|
|
cmd = """\
|
|
set -eou pipefail
|
|
CPP=$$(canonicalize_rlocation $(rootpath {cpp}))
|
|
DAMLC=$$(canonicalize_rlocation $(rootpath {damlc}))
|
|
FILES=($$(
|
|
for file in {files}; do
|
|
IGNORED=false
|
|
for pattern in {ignored}; do
|
|
if [[ $$file = *$$pattern ]]; then
|
|
IGNORED=true
|
|
continue
|
|
fi
|
|
done
|
|
if [[ $$IGNORED == "false" ]]; then
|
|
echo $$(canonicalize_rlocation $$file)
|
|
fi
|
|
done
|
|
))
|
|
|
|
$$DAMLC doctest {flags} --cpp $$CPP --package-name {package_name}-{version} "$${{FILES[@]}}"
|
|
""".format(
|
|
cpp = cpp,
|
|
damlc = damlc,
|
|
package_name = package_name,
|
|
flags = " ".join(flags),
|
|
version = ghc_version,
|
|
files = " ".join(["$(rootpaths %s)" % src for src in srcs]),
|
|
ignored = " ".join(ignored_srcs),
|
|
),
|
|
**kwargs
|
|
)
|