diff --git a/docs/BUILD b/docs/BUILD
index c6191aa..fe48abd 100644
--- a/docs/BUILD
+++ b/docs/BUILD
@@ -19,7 +19,7 @@
# under the License.
#
-exports_files(["cpp/doxyfile.template"])
+exports_files(["doxygen/doxyfile.template"])
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@vaticle_dependencies_tool_docs//:requirements.bzl", docs_requirement = "requirement")
@@ -37,7 +37,7 @@ py_binary(
bzl_library(
name = "lib",
srcs = [
- "cpp/rules.bzl",
+ "doxygen/rules.bzl",
"python/rules.bzl",
],
deps = [],
diff --git a/docs/cpp/doxyfile.template b/docs/doxygen/doxyfile.template
similarity index 94%
rename from docs/cpp/doxyfile.template
rename to docs/doxygen/doxyfile.template
index b3654a1..883efd4 100644
--- a/docs/cpp/doxyfile.template
+++ b/docs/doxygen/doxyfile.template
@@ -98,3 +98,8 @@ GENERATE_LATEX = NO
HIDE_UNDOC_RELATIONS = YES
CLASS_GRAPH = YES
HAVE_DOT = NO ## Disables many details
+
+#---------------------------------------------------------------------------
+# Configuration options related to optional content included to the output
+#---------------------------------------------------------------------------
+EXTRACT_STATIC = YES
diff --git a/docs/cpp/rules.bzl b/docs/doxygen/rules.bzl
similarity index 94%
rename from docs/cpp/rules.bzl
rename to docs/doxygen/rules.bzl
index 6b02d2a..7a887fc 100644
--- a/docs/cpp/rules.bzl
+++ b/docs/doxygen/rules.bzl
@@ -26,7 +26,7 @@ def _doxygen_docs_impl(ctx):
files.extend(target.files.to_list())
replacements = {
- "PROJECT_NAME": ctx.attr.project_name,
+ "PROJECT_NAME": '"' + ctx.attr.project_name + '"',
"PROJECT_NUMBER" : ctx.attr.version,
"PROJECT_BRIEF" : ctx.attr.desc,
"OUTPUT_DIRECTORY" : output_directory.path,
@@ -90,7 +90,7 @@ doxygen_docs = rule(
),
"_doxyfile_template" : attr.label(
allow_single_file = True,
- default = "//docs:cpp/doxyfile.template"
+ default = "//docs:doxygen/doxyfile.template"
),
"_output_directory" : attr.string(
doc = "The output directory for the doxygen docs",
@@ -98,7 +98,7 @@ doxygen_docs = rule(
)
},
doc = """
- Creates HTML documentation for C++ projects using Doxygen.
+ Creates HTML documentation for C++ and C# projects using Doxygen.
This rule is not hermetic, and requires doxygen to be installed on the host.
"""
)
diff --git a/nuget/BUILD b/nuget/BUILD
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/nuget/BUILD
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/nuget/rules.bzl b/nuget/rules.bzl
new file mode 100644
index 0000000..c94176a
--- /dev/null
+++ b/nuget/rules.bzl
@@ -0,0 +1,356 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# This file is based on the original implementation of https://github.com/SeleniumHQ/selenium/.
+
+load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
+load("@rules_dotnet//dotnet/private:common.bzl", "is_debug")
+load("@rules_dotnet//dotnet/private:providers.bzl", "DotnetAssemblyRuntimeInfo")
+
+# The change to the PATH is recommended here:
+# https://learn.microsoft.com/en-us/dotnet/core/install/linux-scripted-manual?source=recommendations#set-environment-variables-system-wide
+# We list our .Net installation first because we
+# want it to be picked up first
+
+# The `MSBuildEnableWorkloadResolver` is disabled to prevent warnings
+# about a missing Microsoft.NET.SDK.WorkloadAutoImportPropsLocator
+
+def dotnet_preamble(toolchain):
+ return """
+export DOTNET="$(pwd)/{dotnet}"
+export DOTNET_CLI_HOME="$(dirname $DOTNET)"
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+export DOTNET_NOLOGO=1
+export DOTNET_ROOT="$(dirname $DOTNET)"
+export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH
+export MSBuildEnableWorkloadResolver=false
+export CWD=$(pwd)
+
+# Required to make packing work on Windows
+export APPDATA="$(pwd)"
+export PROGRAMFILES="$(pwd)"
+
+# Required to make NuGet tool work on non-writable home path like GitHub actions
+export XDG_DATA_HOME=$(mktemp -d)
+
+# Create `global.json` to trick .Net into using the hermetic toolchain
+# https://learn.microsoft.com/en-us/dotnet/core/tools/global-json
+echo '{{"sdk": {{"version": "{version}"}} }}' >$(pwd)/global.json
+
+""".format(
+ dotnet = toolchain.runtime.files_to_run.executable.path,
+ version = toolchain.dotnetinfo.sdk_version,
+ )
+
+
+def _check_platform(platform):
+ allowed_values = ("osx-arm64", "osx-x64", "linux-arm64", "linux-x64", "win-arm64", "win-x64")
+ if platform not in allowed_values:
+ fail("Platform must be set to any of {}. Got {} instead!".format(allowed_values, platform))
+
+
+def _parse_version(ctx):
+ version = ctx.attr.version
+ if not version:
+ version = ctx.var.get("version", "0.0.0")
+
+ return version
+
+
+def _nuget_pack_impl(ctx):
+ version = _parse_version(ctx)
+ nuspec = ctx.actions.declare_file("{}-generated.nuspec".format(ctx.label.name))
+
+ # A mapping of files to the paths in which we expect to find them in the package
+ paths = {}
+ native_lib_declrs = ""
+
+ if ctx.attr.platform:
+ platform_suffix = ".{}".format(ctx.attr.platform)
+ else:
+ platform_suffix = ""
+
+ package_name = "{}{}".format(ctx.attr.id, platform_suffix)
+
+ if ctx.files.native_libs:
+ _check_platform(ctx.attr.platform)
+ native_target_dir = "runtimes/{}/native".format(ctx.attr.platform)
+
+ for native_lib in ctx.files.native_libs:
+ paths[native_lib] = native_lib.short_path
+ native_lib_declrs += """
+""".format(native_lib.short_path, native_target_dir)
+
+ ctx.actions.expand_template(
+ template = ctx.file.nuspec_template,
+ output = nuspec,
+ substitutions = {
+ "$packageid$": package_name,
+ "$version$": version,
+ "$native_lib_declrs$": native_lib_declrs,
+ "$target_framework$": ctx.attr.target_framework,
+ },
+ )
+
+ build_flavor = "Debug" if is_debug(ctx) else "Release"
+
+ for (lib, name) in ctx.attr.libs.items():
+ assembly_info = lib[DotnetAssemblyRuntimeInfo]
+
+ for dll in assembly_info.libs:
+ paths[dll] = "lib/{}/{}.dll".format(ctx.attr.target_framework, name)
+ for pdb in assembly_info.pdbs:
+ paths[pdb] = "lib/{}/{}.pdb".format(ctx.attr.target_framework, name)
+ for doc in assembly_info.xml_docs:
+ paths[doc] = "lib/{}/{}.xml".format(ctx.attr.target_framework, name)
+
+ csproj_template = """
+
+ {}
+ {}
+ {}
+
+
+""".format(ctx.attr.target_framework, package_name, ctx.attr.id)
+
+ csproj_file = ctx.actions.declare_file("{}-generated.csproj".format(ctx.label.name))
+ ctx.actions.write(csproj_file, csproj_template)
+ paths[csproj_file] = "project.csproj"
+
+ for (file, name) in ctx.attr.files.items():
+ paths[file.files.to_list()[0]] = name
+
+ # Zip everything up so we have the right file structure
+ zip_file = ctx.actions.declare_file("{}-intermediate.zip".format(ctx.label.name))
+ args = ctx.actions.args()
+ args.add_all(["Cc", zip_file])
+ for (file, path) in paths.items():
+ args.add("{}={}".format(path, file.path))
+ args.add("project.nuspec={}".format(nuspec.path))
+
+ ctx.actions.run(
+ executable = ctx.executable._zip,
+ arguments = [args],
+ inputs = paths.keys() + [nuspec],
+ outputs = [zip_file],
+ )
+
+ # Now lay everything out on disk and execute the dotnet pack rule
+
+ # Now we have everything, let's build our package
+ toolchain = ctx.toolchains["@rules_dotnet//dotnet:toolchain_type"]
+
+ nupkg_name_stem = "{}.{}".format(package_name, version)
+
+ dotnet = toolchain.runtime.files_to_run.executable
+ pkg = ctx.actions.declare_file("{}.nupkg".format(nupkg_name_stem))
+ symbols_pkg = ctx.actions.declare_file("{}.snupkg".format(nupkg_name_stem))
+
+ # Prepare our cache of nupkg files
+ packages = ctx.actions.declare_directory("{}-nuget-packages".format(ctx.label.name))
+ packages_cmd = "mkdir -p {} ".format(packages.path)
+
+ transitive_libs = depset(transitive = [l[DotnetAssemblyRuntimeInfo].deps for l in ctx.attr.libs]).to_list()
+ package_files = depset([lib.nuget_info.nupkg for lib in transitive_libs if lib.nuget_info]).to_list()
+
+ if len(package_files):
+ packages_cmd += "&& cp " + " ".join([f.path for f in package_files]) + " " + packages.path
+
+ ctx.actions.run_shell(
+ outputs = [packages],
+ inputs = package_files,
+ command = packages_cmd,
+ mnemonic = "LayoutNugetPackages",
+ )
+
+ cmd = dotnet_preamble(toolchain) + \
+ "mkdir {}-working-dir && ".format(ctx.label.name) + \
+ "echo $(pwd) && " + \
+ "$(location @bazel_tools//tools/zip:zipper) x {} -d {}-working-dir && ".format(zip_file.path, ctx.label.name) + \
+ "cd {}-working-dir && ".format(ctx.label.name) + \
+ "echo '' >nuget.config && ".format(packages.path) + \
+ "$DOTNET restore --no-dependencies && " + \
+ "$DOTNET pack --no-build --include-symbols -p:NuspecFile=project.nuspec --include-symbols -p:SymbolPackageFormat=snupkg -p:Configuration={} -p:PackageId={} -p:Version={} -p:PackageVersion={} -p:NuspecProperties=\"version={}\" && ".format(build_flavor, package_name, version, version, version) + \
+ "cp bin/{}/{}.{}.nupkg ../{} && ".format(build_flavor, package_name, version, pkg.path) + \
+ "cp bin/{}/{}.{}.snupkg ../{}".format(build_flavor, package_name, version, symbols_pkg.path)
+
+ cmd = ctx.expand_location(
+ cmd,
+ targets = [
+ ctx.attr._zip,
+ ],
+ )
+
+ ctx.actions.run_shell(
+ outputs = [pkg, symbols_pkg],
+ inputs = [
+ zip_file,
+ dotnet,
+ packages,
+ ],
+ tools = [ctx.executable._zip, dotnet]
+ + toolchain.default.files.to_list()
+ + toolchain.runtime.default_runfiles.files.to_list()
+ + toolchain.runtime.data_runfiles.files.to_list(),
+ command = cmd,
+ mnemonic = "CreateNupkg",
+ )
+
+ return [
+ DefaultInfo(
+ files = depset([pkg, symbols_pkg]),
+ runfiles = ctx.runfiles(files = [pkg, symbols_pkg]),
+ ),
+ ]
+
+nuget_pack = rule(
+ _nuget_pack_impl,
+ attrs = {
+ "id": attr.string(
+ doc = "Nuget ID of the package",
+ mandatory = True,
+ ),
+ "version": attr.string(
+ doc = """
+ Target package's version.
+ Alternatively, pass --define version=VERSION to Bazel invocation.
+ Not specifying version at all defaults to '0.0.0'
+ """,
+ ),
+ "libs": attr.label_keyed_string_dict(
+ doc = "The .Net libraries that are being published",
+ providers = [DotnetAssemblyRuntimeInfo],
+ ),
+ "files": attr.label_keyed_string_dict(
+ doc = "Mapping of files to paths within the nuget package",
+ allow_empty = True,
+ allow_files = True,
+ ),
+ "platform": attr.string(
+ doc = "Target platform and architecture for platform-specific packages: {platform}-{arch}.",
+ default = "",
+ ),
+ "native_libs": attr.label_list(
+ doc = "Native libs to include into the package",
+ ),
+ "target_framework": attr.string(
+ doc = "Target C# build framework",
+ mandatory = True,
+ ),
+ "property_group_vars": attr.string_dict(
+ doc = "Keys and values for variables declared in `PropertyGroup`s in the `csproj_file`",
+ allow_empty = True,
+ ),
+ "nuspec_template": attr.label(
+ doc = "Template .nuspec file with the project description",
+ mandatory = True,
+ allow_single_file = True,
+ ),
+ "_zip": attr.label(
+ default = "@bazel_tools//tools/zip:zipper",
+ executable = True,
+ cfg = "exec",
+ ),
+ },
+ toolchains = ["@rules_dotnet//dotnet:toolchain_type"],
+)
+
+def _nuget_push_impl(ctx):
+ all_srcs = ctx.attr.src.files.to_list()
+
+ package_files = []
+ for package_file in ctx.attr.src.files.to_list():
+ if package_file.extension == "snupkg":
+ continue # .snupkg are automatically included by the nuget push command if they are in the same dir
+ package_files.append(package_file)
+
+ toolchain = ctx.toolchains["@rules_dotnet//dotnet:toolchain_type"]
+ dotnet_runtime = toolchain.runtime.files_to_run.executable
+
+ package_file_paths = []
+ for package_file in package_files:
+ package_file_paths.append(ctx.expand_location(package_file.short_path))
+
+ push_file = ctx.actions.declare_file(ctx.attr.script_file_name)
+
+ ctx.actions.expand_template(
+ template = ctx.file._push_script_template,
+ output = push_file,
+ substitutions = {
+ '{dotnet_runtime_path}': dotnet_runtime.path,
+ '{nupkg_paths}': " ".join(package_file_paths),
+ '{snapshot_url}': ctx.attr.snapshot_url,
+ '{release_url}': ctx.attr.release_url,
+ },
+ is_executable = True,
+ )
+
+ return DefaultInfo(
+ executable = push_file,
+ runfiles = ctx.runfiles(files = all_srcs + toolchain.dotnetinfo.runtime_files),
+ )
+
+
+_nuget_push = rule(
+ implementation = _nuget_push_impl,
+ executable = True,
+ attrs = {
+ "src": attr.label(
+ allow_files = [".nupkg", ".snupkg"],
+ doc = "Nuget packages (and their debug symbol packages) to push",
+ ),
+ "snapshot_url" : attr.string(
+ mandatory = True,
+ doc = "URL of the target snapshot repository",
+ ),
+ "release_url" : attr.string(
+ mandatory = True,
+ doc = "URL of the target release repository",
+ ),
+ "script_file_name": attr.string(
+ mandatory = True,
+ doc = "Name of instantiated deployment script"
+ ),
+ "_push_script_template": attr.label(
+ allow_single_file = True,
+ default = "//nuget/templates:push.py",
+ ),
+ },
+ toolchains = [
+ "@rules_dotnet//dotnet:toolchain_type",
+ ],
+)
+
+
+def nuget_push(name, src, snapshot_url, release_url, **kwargs):
+ push_script_name = "{}_script".format(name)
+ push_script_file_name = "{}-push.py".format(push_script_name)
+
+ _nuget_push(
+ name = push_script_name,
+ script_file_name = push_script_file_name,
+ src = src,
+ snapshot_url = snapshot_url,
+ release_url = release_url,
+ **kwargs
+ )
+
+ native.py_binary(
+ name = name,
+ srcs = [push_script_name],
+ main = push_script_file_name
+ )
diff --git a/nuget/templates/BUILD b/nuget/templates/BUILD
new file mode 100644
index 0000000..40a5992
--- /dev/null
+++ b/nuget/templates/BUILD
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+exports_files(["push.py"])
diff --git a/nuget/templates/push.py b/nuget/templates/push.py
new file mode 100644
index 0000000..07de561
--- /dev/null
+++ b/nuget/templates/push.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+import subprocess
+import sys
+
+def unpack_args(_, arg1):
+ return arg1
+
+if len(sys.argv) < 2:
+ raise ValueError("Should pass as arguments")
+
+repo_type = unpack_args(*sys.argv)
+
+nuget_repositories = {
+ "snapshot": "{snapshot_url}",
+ "release": "{release_url}",
+}
+target_repo_url = nuget_repositories[repo_type]
+
+api_key = os.getenv('DEPLOY_NUGET_API_KEY')
+
+if not api_key:
+ raise ValueError('Error: API key should be passed via $DEPLOY_NUGET_API_KEY env variable')
+
+args = [
+ "{dotnet_runtime_path}",
+ "nuget",
+ "push",
+]
+args += "{nupkg_paths}".split()
+args += [
+ "-k",
+ f"{api_key}",
+ "-s",
+ f"{target_repo_url}",
+]
+
+print(f"Executing nuget push for {nupkg_paths}...")
+
+subprocess.check_call(args)
+
+print("Done executing nuget push!")