diff --git a/.gitignore b/.gitignore index 828c4b638b034f..601a6a232949b7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ /bazel-out /bazel-rules_dotnet /bazel-testlogs +.vscode +_build +_static +_templates diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000000..3ba794aab30bd0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,85 @@ +# trusty beta image has jdk8, gcc4.8.4 +dist: trusty +sudo: required +# xcode8 has jdk8 +osx_image: xcode8.3 +# Not technically required but suppresses 'Ruby' in Job status message. +language: java + +os: + - linux + - osx + +env: + # TODO(bazelbuild/continuous-integration#95): re-enable HEAD builds with stable URL + # - V=HEAD + - V=0.10.0 + +before_install: + - | + if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then + OS=darwin + brew install mono + else + sysctl kernel.unprivileged_userns_clone=1 + sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF + sudo apt install apt-transport-https + echo "deb https://download.mono-project.com/repo/ubuntu stable-trusty main" | sudo tee /etc/apt/sources.list.d/mono-official-stable.list + sudo apt update + sudo apt install mono-devel + export RULES_DOTNET_USE_LOCAL_MONO=true + OS=linux + fi + if [[ "${V}" == "HEAD" ]]; then + # Determine last successful build number. This may change while we are + # downloading, so it's important to determine ahead of time, in case + # we need to resume the download. + CI_BASE="http://ci.bazel.io/view/Bazel%20bootstrap%20and%20maintenance/job/Bazel/PLATFORM_NAME=${OS}-x86_64/" + CI_INDEX_URL="${CI_BASE}/lastSuccessfulBuild/" + wget -q -O build-index.html "${CI_INDEX_URL}" + CI_BUILD=$(grep '' build-index.html | sed -e 's/^.*#\([0-9]*\).*$/\1/') + # Determine the artifact name. This is normally, bazel--installer.sh, + # but it may be, for example, bazel-0.5rc2-installer.sh before a release. + CI_ARTIFACT=$(grep -o 'bazel-[^\"-]*-installer.sh' build-index.html | head -n 1) + URL="${CI_BASE}/${CI_BUILD}/artifact/output/ci/${CI_ARTIFACT}" + rm build-index.html + else + URL="https://github.com/bazelbuild/bazel/releases/download/${V}/bazel-${V}-installer-${OS}-x86_64.sh" + fi + wget -O install.sh "${URL}" + chmod +x install.sh + ./install.sh --user + rm -f install.sh + +script: + - | + bazel \ + --batch \ + --host_jvm_args=-Xmx500m \ + --host_jvm_args=-Xms500m \ + build \ + -s \ + --local_resources=400,1,1.0 \ + //... + - | + bazel \ + --batch \ + --host_jvm_args=-Xmx500m \ + --host_jvm_args=-Xms500m \ + run \ + -s \ + --local_resources=400,1,1.0 \ + //tests/examples/example_binary:hello + - | + bazel \ + --batch \ + --host_jvm_args=-Xmx500m \ + --host_jvm_args=-Xms500m \ + test \ + -s \ + --local_resources=400,1,1.0 \ + --test_summary=detailed \ + --test_output=all \ + //... +notifications: + email: false \ No newline at end of file diff --git a/BUILD b/BUILD new file mode 100644 index 00000000000000..f11861d445ebdf --- /dev/null +++ b/BUILD @@ -0,0 +1,8 @@ +load("@io_bazel_rules_dotnet//dotnet/private:context.bzl", "dotnet_context_data") + +dotnet_context_data( + name = "dotnet_context_data", + visibility = ["//visibility:public"], +) + +exports_files(["AUTHORS"]) diff --git a/README.md b/README.md deleted file mode 100644 index e7eb0081edf11f..00000000000000 --- a/README.md +++ /dev/null @@ -1,478 +0,0 @@ -# C# Rules - -| Bazel CI | -| :---: | -| [![Build Status](https://ci.bazel.build/buildStatus/icon?job=rules_dotnet)](https://ci.bazel.build/job/rules_dotnet/) | - -## Rules - -* [csharp_library](#csharp_library) -* [csharp_binary](#csharp_library) -* [csharp_nunit_test](#csharp_nunit_test) -* [nuget_package](#nuget_package) -* [new_nuget_package](#new_nuget_package) -* [dll_import](#dll_import) - -## Overview - -This is a minimal viable set of C# bindings for building C# code with -[Mono](http://www.mono-project.com/). It's still pretty rough but it -works as a proof of concept that could grow into something more. - -## Caveats - -These rules are not compatible with -[sandboxing](https://bazel.io/blog/2015/09/11/sandboxing.html). - -These rules do not currently support Windows and the.NET Framework. -Issue [#54](https://github.com/bazelbuild/rules_dotnet/issues/54) -tracks the necessary work. Bazel support for Windows is currently in -[beta](https://blog.bazel.build/2017/10/16/windows-retrospect.html). - -These rules do not currently support .NET Core/Standard built with -the official compiler on any platform. - -## Setup - -Add the following to your `WORKSPACE` file to add the external repositories: - -```python -# A newer version should be fine -http_archive( - name = "bazel_skylib", - url = "https://github.com/bazelbuild/bazel-skylib/archive/ff23a62c57d2912c3073a69c12f42c3d6e58a957.zip", - strip_prefix = "bazel-skylib-ff23a62c57d2912c3073a69c12f42c3d6e58a957", - sha256 = "ccf83f162e4a265b3aa09445c84fbc470215e392b250c86f0ce00536c99d5c17", -) - -git_repository( - name = "io_bazel_rules_dotnet", - remote = "https://github.com/bazelbuild/rules_dotnet.git", - tag = "0.0.3", -) - -load( - "@io_bazel_rules_dotnet//dotnet:csharp.bzl", - "csharp_repositories", - "nuget_package", -) - -csharp_repositories(use_local_mono = True) - -nuget_package( - name = "Netwonsoft.Json", - package = "Newtonsoft.Json", - version = "10.0.3", -) -``` - -The `csharp_repositories` rule fetches external dependencies, namely -the mono repository, the nuget binary, and the nunit binary. Setting -the environment variable `RULES_DOTNET_USE_LOCAL_MONO=1` or the rule -argument `use_local_mono` to `True` will use your installed mono -framework instead of downloading one. If you are on OS X you can set -`use_local_mono` to `False` and mono will be downloaded for you by -bazel. - -Support for downloading mono on Linux is coming soon. - -## Examples - -### csharp_library - -```python -csharp_library( - name = "MyLib", - srcs = ["MyLib.cs"], - deps = ["//my/dependency:SomeLib"], -) -``` - -### csharp_binary - -```python -csharp_binary( - name = "MyApp", - main = "MyApp", # optional name of the main class. - srcs = ["MyApp.cs"], - deps = ["//my/dependency:MyLib"], -) -``` - -### csharp\_nunit\_test - -```python -csharp_nunit_test( - name = "MyApp", - srcs = ["MyApp.cs"], - deps = ["//my/dependency:MyLib"], -) -``` - -### nuget\_package - -In the `WORKSPACE` file for your project record a nuget dependency like so. -This is a repository rule so it will not work unless it is in a workspace -file. - -```python -nuget_package( - name = "ndesk_options", - package = "NDesk.Options", - version = "0.2.1", -) -``` - -Now, in a `BUILD` file, you can add the package to your `deps`: - -``` -csharp_binary( - name = "MyApp", - srcs = ["MyApp.cs"], - deps = ["@ndesk_options//:dylibs"], -) -``` - - - -### new\_nuget\_package - -This repository rule accepts either a `BUILD` file label or -`build_file_content` string. Typically the build content will include -`dll_import` rules that expose the correct set of libraries to the -project. For example: - -```python - -new_nuget_package( - name = "nuget_grpc", - package = "Grpc", - version = "1.0.0", - build_file_content = -""" -load("@io_bazel_rules_dotnet//dotnet:csharp.bzl", "dll_import") -dll_import( - name = "system_interactive_async", - srcs = glob(["System.Interactive.Async.3.0.0/lib/net45/**/*.dll"]), - visibility = ["//visibility:public"], -) -dll_import( - name = "core", - srcs = glob(["Grpc.Core.1.0.0/lib/net45/**/*.dll"]), - visibility = ["//visibility:public"], -) -""" -) -``` - -The structure of the nuget_grpc external workspace can be examined -once downloaded and extracted via `cd $(bazel info -output_base)/external/nuget_grpc`. - -### dll\_import - -Add a collection of dotnet assembly dll's to be used as a dependency. - -```python -dll_import( - name="some_lib", - srcs=[ - "Some.dll" - "Some.Other.dll", - ] -) -``` - -## Things still missing: - -- Handle .resx files correctly. See issue [#51](https://github.com/bazelbuild/rules_dotnet/issues/51). -- .Net Modules -- Conditionally building documentation. -- Pulling Mono in through a mono.WORKSPACE file. - - Still need to implement this for linux. -- Multiple target framework support for nuget packages. - -## Future nice to haves: - -- nuget_packages repository rule that will handle multiple different nuget packages in one rule. -- Building csproj and sln files for VS and MonoDevelop. - -<a name="csharp_library"></a> -## csharp_library - -```python -csharp_library(name, srcs, deps, warn=4, csc) -``` - -Builds a C# .NET library and its corresponding documentation. - -<table class="table table-condensed table-bordered table-params"> - <colgroup> - <col class="col-param" /> - <col class="param-description" /> - </colgroup> - <thead> - <tr> - <th colspan="2">Attributes</th> - </tr> - </thead> - <tbody> - <tr> - <td><code>name</code></td> - <td> - <p><code>Name, required</code></p> - <p>Unique name for this rule</p> - </td> - </tr> - <tr> - <td><code>srcs</code></td> - <td> - <p><code>List of Labels; required</code></p> - <p>Csharp .cs or .resx files.</p> - </td> - </tr> - <tr> - <td><code>deps</code></td> - <td> - <p><code>List of Labels; optional</code></p> - <p>Dependencies for this rule.</p> - </td> - </tr> - <tr> - <td><code>warn</code></td> - <td> - <p><code>Int; optional; default is 4</code></p> - <p>Compiler warn level for this library. (Defaults to 4.)</p> - </td> - </tr> - <tr> - <td><code>csc</code></td> - <td> - <p><code>string; optional</code></p> - <p>Override the default csharp compiler.</p> - <p> - <strong>Note:</strong> This attribute may removed in future - versions. - </p> - </td> - </tr> - </tbody> -</table> - -<a name="csharp_binary"></a> -## csharp_binary - -```python -csharp_binary(name, srcs, deps, main_class, warn=4, csc) -``` - -Builds a C# .NET binary. - -<table class="table table-condensed table-bordered table-params"> - <colgroup> - <col class="col-param" /> - <col class="param-description" /> - </colgroup> - <thead> - <tr> - <th colspan="2">Attributes</th> - </tr> - </thead> - <tbody> - <tr> - <td><code>name</code></td> - <td> - <p><code>Name, required</code></p> - <p>Unique name for this rule</p> - </td> - </tr> - <tr> - <td><code>srcs</code></td> - <td> - <p><code>List of Labels; required</code></p> - <p>Csharp .cs or .resx files.</p> - </td> - </tr> - <tr> - <td><code>deps</code></td> - <td> - <p><code>List of Labels; optional</code></p> - <p>Dependencies for this rule.</p> - </td> - </tr> - <tr> - <td><code>main_class</code></td> - <td> - <p><code>String; optional</code> - <p>Name of class with <code>main()</code> method to use as entry point.</p> - </td> - </tr> - <tr> - <td><code>warn</code></td> - <td> - <p><code>Int; optional; default is 4</code></p> - <p>Compiler warn level for this binary. (Defaults to 4.)</p> - </td> - </tr> - <tr> - <td><code>csc</code></td> - <td> - <p><code>string; optional</code></p> - <p>Override the default csharp compiler.</p> - <p> - <strong>Note:</strong> This attribute may removed in future - versions. - </p> - </td> - </tr> - </tbody> -</table> - -<a name="csharp_nunit_test"></a> -## csharp\_nunit\_test - -```python -csharp_nunit_test(name, srcs, deps, warn=4, csc) -``` - -Builds a C# .NET test binary that uses the [NUnit](http://www.nunit.org/) unit -testing framework. - -<table class="table table-condensed table-bordered table-params"> - <colgroup> - <col class="col-param" /> - <col class="param-description" /> - </colgroup> - <thead> - <tr> - <th colspan="2">Attributes</th> - </tr> - </thead> - <tbody> - <tr> - <td><code>name</code></td> - <td> - <p><code>Name, required</code></p> - <p>Unique name for this rule</p> - </td> - </tr> - <tr> - <td><code>srcs</code></td> - <td> - <p><code>List of Labels; required</code></p> - <p>Csharp .cs or .resx files.</p> - </td> - </tr> - <tr> - <td><code>deps</code></td> - <td> - <p><code>List of Labels; optional</code></p> - <p>Dependencies for this rule.</p> - </td> - </tr> - <tr> - <td><code>warn</code></td> - <td> - <p><code>Int; optional; default is 4</code></p> - <p>Compiler warn level for this test. (Defaults to 4.)</p> - </td> - </tr> - <tr> - <td><code>csc</code></td> - <td> - <p><code>string; optional</code></p> - <p>Override the default csharp compiler.</p> - <p> - <strong>Note:</strong> This attribute may removed in future - versions. - </p> - </td> - </tr> - </tbody> -</table> - -<a name="nuget_package"></a> -## nuget\_package - -```python -nuget_package(name, package, version, package_sources) -``` - -A repository_rule that adds a nuget package dependency for the Workspace. - - -<table class="table table-condensed table-bordered table-params"> - <colgroup> - <col class="col-param" /> - <col class="param-description" /> - </colgroup> - <thead> - <tr> - <th colspan="2">Attributes</th> - </tr> - </thead> - <tbody> - <tr> - <td><code>name</code></td> - <td> - <p><code>Name, required</code></p> - <p>Unique name for this rule</p> - </td> - <tr> - <td><code>package</code></td> - <td> - <p><code>String, Required</code></p> - <p>Name of the nuget package.</p> - </td> - </tr> - <tr> - <td><code>version</code></td> - <td> - <p><code>String, Required</code></p> - <p>Version of the nuget package to install.</p> - </td> - </tr> - <tr> - <td><code>package\_sources</code></td> - <td> - <p><code>List of strings, optional</code></p> - <p>Sources to pull nuget packages from. Either url or path.</p> - </td> - </tr> - </tbody> -</table> - -```python -dll_import(name, srcs) -``` - -A repository_rule that adds a nuget package dependency for the Workspace. - - -<table class="table table-condensed table-bordered table-params"> - <colgroup> - <col class="col-param" /> - <col class="param-description" /> - </colgroup> - <thead> - <tr> - <th colspan="2">Attributes</th> - </tr> - </thead> - <tbody> - <tr> - <td><code>name</code></td> - <td> - <p><code>Name, required</code></p> - <p>Unique name for this rule</p> - </td> - <tr> - <tr> - <td><code>srcs</code></td> - <td> - <p><code>Labels, required</code></p> - <p>List of dotnet dll assemblies to use.</p> - </td> - <tr> - </tbody> -</table> diff --git a/README.rst b/README.rst new file mode 100644 index 00000000000000..ec7093b4b9ab34 --- /dev/null +++ b/README.rst @@ -0,0 +1,207 @@ +C# Rules for Bazel_ +=================== + +.. All external links are here +.. _Bazel: https://bazel.build/ +.. |travis| image:: https://travis-ci.org/tomaszstrejczek/rules_dotnet.svg?branch=toolchain + :target: https://travis-ci.org/tomaszstrejczek/rules_dotnet +.. |appvey| image:: https://ci.appveyor.com/api/projects/status/4wlsdo9kgwvt8b97/branch/toolchain?svg=true + :target: https://ci.appveyor.com/project/tomaszstrejczek/rules-dotnet/branch/toolchain +.. _Mono: http://www.mono-project.com/ +.. _sandboxing: https://bazel.io/blog/2015/09/11/sandboxing.html +.. _dotnet_library: dotnet/core.rst#dotnet_library +.. _dotnet_binary: dotnet/core.rst#dotnet_binary +.. _dotnet_nunit_test: dotnet/core.rst#dotnet_nunit_test +.. _dotnet_resx: dotnet/core.rst#dotnet_resx +.. _dotnet_import_library: dotnet/core.rst#dotnet_import_library +.. _dotnet_repositories: dotnet/workspace.rst#dotnet_repositories +.. _dotnet_register_toolchains: dotnet/toolchains.rst#dotnet_register_toolchains +.. _dotnet_nuget_new: dotnet/workspace.rst#dotnet_nuget_new +.. ;; + +======== ======== +Travis Appveyor +======== ======== +|travis| |appvey| +======== ======== + +.. contents:: + :depth: 2 + + +Documentation +~~~~~~~~~~~~~ + +* `Core API <dotnet/core.rst>`_ + + * `dotnet_library`_ + * `dotnet_binary`_ + * `dotnet_nunit_test`_ + * `dotnet_resx`_ + * `dotnet_import_library`_ + +* `Workspace rules <dotnet/workspace.rst>`_ + +* `Toolchains <dotnet/toolchains.rst>`_ + + +Overview +~~~~~~~~ + +This is a minimal viable set of C# bindings for building C# code with +Mono_. It's still pretty rough but it works as a proof of concept that +could grow into something more. + +Caveats +~~~~~~~ + +These rules are not compatible with sandboxing_. + +These rules do not currently support the .NET Framework. + +These rules do not currently support .NET Core/Standard built with +the official compiler on any platform. + +Downloading Mono currently does not work. + +Due to Windows short path limit (260) of cl compiler TMP env variable should be +set to something short (like X:\ or c:\TEMP). + +Setup +~~~~~ + +* Add the following to your `WORKSPACE` file to add the external repositories: + + .. code:: python + + # A newer version should be fine + git_repository( + name = "io_bazel_rules_dotnet", + remote = "https://github.com/tomek1909/rules_dotnet", + tag = "0.0.1", + ) + + load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_register_toolchains", "dotnet_repositories") + + dotnet_register_toolchains("host") + + dotnet_repositories() + + The dotnet_repositories_ rule fetches external dependencies, namely the nuget binary. + The dotnet_register_toolchains_ tries to locate mono binaries and configure toolchains to use it. + Support for downloading mono is coming soon. + +* Add a file named ``BUILD.bazel`` in the root directory of your + project. In general, you need one of these files in every directory + with dotnet code. + At the top of the file used rules should be imported: + + .. code:: python + + load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_library", "dotnet_binary") + + +Examples +~~~~~~~~ + +* dotnet_library_ + + .. code:: python + + dotnet_library( + name = "foo_bar", + srcs = [ + "foo.cs", + "bar.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], + visibility = ["//visibility:public"], + ) + +* dotnet_binary_ + + .. code:: python + + dotnet_binary( + name = "foo_bar", + srcs = [ + "foo.cs", + "bar.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], + visibility = ["//visibility:public"], + ) + +* dotnet_nunit_test_ + + .. code:: python + + dotnet_nunit_test( + name = "MyTest", + srcs = [ + "MyTest.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "//dotnet/externals/nunit2:nunit.framework", + ], + ) + +* dotnet_resx_ + + .. code:: python + + dotnet_resx( + name = "Transform", + src = "//dotnet/externals/nunit2/nunitv2:src/ClientUtilities/util/Transform.resx", + ) + + +* dotnet_nuget_new_ + + In the `WORKSPACE` file for your project record a nuget dependency like so. + This is a repository rule so it will not work unless it is in a workspace + file. + + .. code:: python + + dotnet_nuget_new( + name = "npgsql", + package="Npgsql", + version="3.2.7", + sha256="fa3e0cfbb2caa9946d2ce3d8174031a06320aad2c9e69a60f7739b9ddf19f172", + build_file_content = """ + package(default_visibility = [ "//visibility:public" ]) + load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_import_library") + + dotnet_import_library( + name = "npgsqllib", + src = "lib/net451/Npgsql.dll" + ) + """ + ) + + Now, in a `BUILD` file, you can add the package to your `deps`: + + .. code:: python + + dotnet_binary( + name = "foo_bar", + srcs = [ + "foo.cs", + "bar.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], + visibility = ["//visibility:public"], + ) + + diff --git a/WORKSPACE b/WORKSPACE index 5b823ed3c1853c..b6d91038e08fa1 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,11 +1,27 @@ workspace(name = "io_bazel_rules_dotnet") -http_archive( - name = "bazel_skylib", - url = "https://github.com/bazelbuild/bazel-skylib/archive/ff23a62c57d2912c3073a69c12f42c3d6e58a957.zip", - strip_prefix = "bazel-skylib-ff23a62c57d2912c3073a69c12f42c3d6e58a957", - sha256 = "ccf83f162e4a265b3aa09445c84fbc470215e392b250c86f0ce00536c99d5c17", +load("//dotnet:defs.bzl", "dotnet_register_toolchains", "dotnet_repositories", "dotnet_nuget_new") + +dotnet_repositories() +dotnet_register_toolchains("host") + +dotnet_nuget_new( + name = "npgsql", + package="Npgsql", + version="3.2.7", + sha256="fa3e0cfbb2caa9946d2ce3d8174031a06320aad2c9e69a60f7739b9ddf19f172", + build_file_content = """ +package(default_visibility = [ "//visibility:public" ]) +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_import_library") + +dotnet_import_library( + name = "npgsqllib", + src = "lib/net451/Npgsql.dll" +) + """ ) -load("//dotnet:csharp.bzl", "csharp_repositories") -csharp_repositories() + +load("@io_bazel_rules_dotnet//tests:bazel_tests.bzl", "test_environment") + +test_environment() diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000000000..41794a84b65497 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,36 @@ +version: 1.0.{build} + +# Maximum number of concurrent jobs for the project +max_jobs: 1 + +#---------------------------------# +# environment configuration # +#---------------------------------# + +# Build worker image (VM template) +image: Visual Studio 2017 + +# scripts that are called at very beginning, before repo cloning +init: + - git config --global core.autocrlf input + +clone_script: +- cmd: git clone -q --branch=%APPVEYOR_REPO_BRANCH% https://github.com/%APPVEYOR_REPO_NAME%.git %APPVEYOR_BUILD_FOLDER% +- cmd: cd %APPVEYOR_BUILD_FOLDER% +- cmd: git checkout -qf %APPVEYOR_REPO_COMMIT% +- cmd: git submodule update --init --recursive + +install: + - choco install mono + - choco install bazel + +build_script: + - ver + - bazel --batch --host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m build -s --local_resources=400,1,1.0 //... + - bazel --batch --host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m run -s --local_resources=400,1,1.0 //tests/examples/example_binary:hello + - bazel --batch --host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m test --test_summary=detailed --test_output=all -s --local_resources=400,1,1.0 //... + +test: off + +deploy: off + diff --git a/conf.py b/conf.py new file mode 100644 index 00000000000000..c3456dbd8abb0c --- /dev/null +++ b/conf.py @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = u'rules_dotnet' +copyright = u'2018, Tomek Strejczek' +author = u'Tomek Strejczek' + +# The short X.Y version +version = u'' +# The full version, including alpha/beta/rc tags +release = u'0.0.1' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'rules_dotnetdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'rules_dotnet.tex', u'rules\\_dotnet Documentation', + u'Tomek Strejczek', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'rules_dotnet', u'rules_dotnet Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'rules_dotnet', u'rules_dotnet Documentation', + author, 'rules_dotnet', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True \ No newline at end of file diff --git a/dotnet/BUILD b/dotnet/BUILD index 0622f058b90dd0..0bc9afca3f47c9 100644 --- a/dotnet/BUILD +++ b/dotnet/BUILD @@ -1,17 +1,5 @@ -# Detect our platform, -# mac os x -config_setting( - name = "darwin", - values = {"host_cpu": "darwin"}, -) - -# linux amd64 -config_setting( - name = "linux", - values = {"host_cpu": "k8"}, -) - -config_setting( - name = "debug", - values = {"compilation_mode": "dbg"}, +filegroup( + name = "all_rules", + srcs = glob(["*.bzl"]) + ["//dotnet/private:all_rules"], + visibility = ["//visibility:public"], ) diff --git a/dotnet/NUGET_BUILD.tpl b/dotnet/NUGET_BUILD.tpl deleted file mode 100644 index e352e165cabdbe..00000000000000 --- a/dotnet/NUGET_BUILD.tpl +++ /dev/null @@ -1,7 +0,0 @@ -load("@io_bazel_rules_dotnet//dotnet:csharp.bzl", "dll_import") - -dll_import( - name = "dylibs", - srcs = glob(["**/*.dll"]), - visibility = ["//visibility:public"], -) diff --git a/dotnet/core.rst b/dotnet/core.rst new file mode 100644 index 00000000000000..c3c4db16f8b509 --- /dev/null +++ b/dotnet/core.rst @@ -0,0 +1,309 @@ +Core dotnet rules +================= + +.. _test_filter: https://docs.bazel.build/versions/master/user-manual.html#flag--test_filter +.. _test_arg: https://docs.bazel.build/versions/master/user-manual.html#flag--test_arg +.. _DotnetLibrary: providers.rst#DotnetLibrary +.. _DotnetResource: providers.rst#DotnetResource +.. _"Make variable": https://docs.bazel.build/versions/master/be/make-variables.html +.. _Bourne shell tokenization: https://docs.bazel.build/versions/master/be/common-definitions.html#sh-tokenization +.. _data dependencies: https://docs.bazel.build/versions/master/build-ref.html#data +.. _shard_count: https://docs.bazel.build/versions/master/be/common-definitions.html#test.shard_count +.. _build constraints: https://golang.org/pkg/go/build/#hdr-Build_Constraints +.. _select: https://docs.bazel.build/versions/master/be/functions.html#select +.. _config_setting: https://docs.bazel.build/versions/master/be/general.html#config_setting +.. _dotnet_nuget_new: workspace.rst#dotnet_nuget_new + +.. role:: param(kbd) +.. role:: type(emphasis) +.. role:: value(code) +.. |mandatory| replace:: **mandatory value** + +These are the core dotnet rules, required for basic operation. +The intent is that theses rules are sufficient to match the capabilities of the normal dotnet tools. + +.. contents:: :depth: 2 + +----- + +API +--- + +dotnet_library +~~~~~~~~~~~~~~ + +This builds a dotnet assembly from a set of source files. + +Providers +^^^^^^^^^ + +* DotnetLibrary_ +* DotnetResource_ + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`deps` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The direct dependencies of this library. | +| These may be dotnet_library rules or compatible rules with the DotnetLibrary_ provider. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`resources` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of resources to compile with. Usually provided via reference to dotnet_resx_ | +| or the rules compatible with DotnetResource_ provider | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`srcs` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of .cs source files that are compiled to create the assembly. | +| Only :value:`.cs` files are permitted | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| An alternative name of the output file | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`defines` | :type:`string_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of defines passed via /define compiler option | ++----------------------------+-----------------------------+---------------------------------------+ + +Example +^^^^^^^ + +.. code:: python + + dotnet_library( + name = "foo_bar", + srcs = [ + "foo.cs", + "bar.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], + visibility = ["//visibility:public"], + ) + +dotnet_binary +~~~~~~~~~~~~~ + +This builds an executable from a set of source files. +You can run the binary with ``bazel run``, or you can +build it with ``bazel build`` and run it directly. + +Providers +^^^^^^^^^ + +* DotnetLibrary_ +* DotnetResource_ + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`deps` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The direct dependencies of this library. | +| These may be dotnet_library rules or compatible rules with the DotnetLibrary_ provider. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`resources` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of resources to compile with. Usually provided via reference to dotnet_resx_ | +| or the rules compatible with DotnetResource_ provider | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`srcs` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of .cs source files that are compiled to create the assembly. | +| Only :value:`.cs` files are permitted | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| An alternative name of the output file | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`defines` | :type:`string_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of defines passed via /define compiler option | ++----------------------------+-----------------------------+---------------------------------------+ + +Example +^^^^^^^ + +.. code:: python + + dotnet_binary( + name = "foo_bar", + srcs = [ + "foo.cs", + "bar.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], + visibility = ["//visibility:public"], + ) + +dotnet_nunit_test +~~~~~~~~~~~~~~~~~ + +This builds a set of tests that can be run with ``bazel test``. +Currently it uses nunit2. + +To run all tests in the workspace, and print output on failure, run + +:: + + bazel test --test_output=errors //... + +You can run specific tests by passing the `--test_filter=pattern <test_filter_>`_ argument to Bazel. +You can pass arguments to tests by passing `--test_arg=arg <test_arg_>`_ arguments to Bazel. + + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`deps` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The direct dependencies of this library. | +| These may be dotnet_library rules or compatible rules with the DotnetLibrary_ provider. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`resources` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of resources to compile with. Usually provided via reference to dotnet_resx_ | +| or the rules compatible with DotnetResource_ provider | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`srcs` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of .cs source files that are compiled to create the assembly. | +| Only :value:`.cs` files are permitted | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| An alternative name of the output file | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`defines` | :type:`string_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The list of defines passed via /define compiler option | ++----------------------------+-----------------------------+---------------------------------------+ + + +Test example +^^^^^^^^^^^^ + +.. code:: python + + dotnet_nunit_test( + name = "MyTest", + srcs = [ + "MyTest.cs", + ], + deps = [ + "//examples/example_lib:MyClass", + "@nunit2//:nunit.framework", + ], + ) + + +dotnet_resx +~~~~~~~~~~~ + +This builds a dotnet .resources file from a single .resx file. + +Providers +^^^^^^^^^ + +* DotnetResource_ + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`src` | :type:`label` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| The .resx source file that is transformed into .resources file. | +| Only :value:`.resx` files are permitted | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`identifer` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| The logical name for the resource; the name that is used to load the resource. | +| The default is the basename of the file name (no subfolder). | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| An alternative name of the output file | ++----------------------------+-----------------------------+---------------------------------------+ + +Example +^^^^^^^ + +.. code:: python + + dotnet_resx( + name = "Transform", + src = ":src/ClientUtilities/util/Transform.resx", + ) + + +dotnet_import_library +~~~~~~~~~~~~~~~~~~~~~ + +This imports an external dll and transforms it into DotnetLibrary_ so it can be referenced +as dependency by other rules. Often used with dotnet_nuget_new_. + +Providers +^^^^^^^^^ + +* DotnetLibrary_ + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`deps` | :type:`label_list` | :value:`None` | ++----------------------------+-----------------------------+---------------------------------------+ +| The direct dependencies of this dll. | +| These may be dotnet_library rules or compatible rules with the DotnetLibrary_ provider. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`src` | :type:`label` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| The file to be transformed into DotnetLibrary_ provider | ++----------------------------+-----------------------------+---------------------------------------+ + +Example +^^^^^^^ +See dotnet_nuget_new_. + + diff --git a/dotnet/csharp.bzl b/dotnet/csharp.bzl deleted file mode 100644 index 69e9dd961f040a..00000000000000 --- a/dotnet/csharp.bzl +++ /dev/null @@ -1,615 +0,0 @@ -# Copyright 2015 The Bazel Authors. All rights reserved. -# -# Licensed 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. - -"""CSharp bazel rules""" - -load("@bazel_skylib//lib:dicts.bzl", "dicts") - -_MONO_UNIX_BIN = "/usr/local/bin/mono" - -# TODO(jeremy): Windows when it's available. - -def _make_csc_deps(deps, extra_files=[]): - dlls = depset() - refs = depset() - transitive_dlls = depset() - for dep in deps: - if hasattr(dep, "target_type"): - dep_type = getattr(dep, "target_type") - if dep_type == "exe": - fail("You can't use a binary target as a dependency", "deps") - if dep_type == "library": - dlls += [dep.out] - refs += [dep.name] - if dep_type == "library_set": - dlls += dep.out - refs += [d.basename for d in dep.out] - if dep.transitive_dlls: - transitive_dlls += dep.transitive_dlls - - return struct( - dlls = dlls + depset(extra_files), - refs = refs, - transitive_dlls = transitive_dlls) - -def _get_libdirs(dlls, libdirs=[]): - return [dep.dirname for dep in dlls] + libdirs - -def _make_csc_arglist(ctx, output, depinfo, extra_refs=[]): - args = ctx.actions.args() - - # /out:<file> - args.add(format="/out:%s", value=output.path) - - # /target (exe for binary, library for lib, module for module) - args.add(format="/target:%s", value=ctx.attr._target_type) - - # /fullpaths - args.add("/fullpaths") - - # /warn - args.add(format="/warn:%s", value=str(ctx.attr.warn)) - - # /nologo - args.add("/nologo") - - # /modulename:<string> only used for modules - libdirs = _get_libdirs(depinfo.dlls) - libdirs = _get_libdirs(depinfo.transitive_dlls, libdirs) - - # /lib:dir1,[dir1] - if libdirs: - args.add(format="/lib:%s", value=libdirs) - - # /reference:filename[,filename2] - if depinfo.refs or extra_refs: - args.add(format="/reference:%s", value=depinfo.refs + extra_refs) - else: - args.add(extra_refs) - - # /doc - if hasattr(ctx.outputs, "doc_xml"): - args.add(format="/doc:%s", value=ctx.outputs.doc_xml.path) - - # /debug - debug = ctx.var.get("BINMODE", "") == "-dbg" - if debug: - args.add("/debug") - - # /warnaserror - # TODO(jeremy): /define:name[;name2] - # TODO(jeremy): /resource:filename[,identifier[,accesibility-modifier]] - - # /main:class - if hasattr(ctx.attr, "main_class") and ctx.attr.main_class: - args.add(format="/main:%s", value=ctx.attr.main_class) - - args.add(format="/resource:%s", value=ctx.files.resources) - - # TODO(jwall): /parallel - - return args - -_NUNIT_LAUNCHER_SCRIPT = """\ -#!/bin/bash - -if [[ -e "$0.runfiles" ]]; then - cd $0.runfiles/{workspace} -fi - -# Create top-level symlinks for lib files. -# TODO(jeremy): This is a gross and fragile hack. -# We should be able to do better than this. -for l in {libs}; do - if [[ ! -e $(basename $l) ]]; then - # Note: -f required because the symlink may exist - # even though its current target does not exist. - ln -s -f $l $(basename $l) - fi -done - -{mono_exe} {nunit_exe} {libs} "$@" -""" - -def _make_nunit_launcher(ctx, depinfo, output): - libs = ([d.short_path for d in depinfo.dlls] + - [d.short_path for d in depinfo.transitive_dlls]) - - content = _NUNIT_LAUNCHER_SCRIPT.format( - mono_exe=ctx.file.mono.short_path, - nunit_exe=ctx.files._nunit_exe[0].short_path, - libs=" ".join({lib: None for lib in libs}.keys()), - workspace=ctx.workspace_name) - - ctx.file_action(output=ctx.outputs.executable, content=content) - -_LAUNCHER_SCRIPT = """\ -#!/bin/bash - -set -e - -RUNFILES=$0.runfiles/{workspace} - -pushd $RUNFILES - -# Create top-level symlinks for .exe and lib files. -# TODO(jeremy): This is a gross and fragile hack. -# We should be able to do better than this. -if [[ ! -e $(basename {exe}) ]]; then - # Note: -f required because the symlink may exist - # even though its current target does not exist. - ln -s -f {exe} $(basename {exe}) -fi -for l in {libs}; do - if [[ ! -e $(basename {workspace}/$l) ]]; then - ln -s -f $l $(basename {workspace}/$l) - fi -done - -popd - -$RUNFILES/{mono_exe} $RUNFILES/$(basename {exe}) "$@" -""" - -def _make_launcher(ctx, depinfo, output): - libs = ([d.short_path for d in depinfo.dlls] + - [d.short_path for d in depinfo.transitive_dlls]) - - content = _LAUNCHER_SCRIPT.format(mono_exe=ctx.file.mono.path, - workspace=ctx.workspace_name, - exe=output.short_path, - libs=" ".join(libs)) - ctx.file_action(output=ctx.outputs.executable, content=content) - -def _csc_get_output(ctx): - output = None - if hasattr(ctx.outputs, "csc_lib"): - output = ctx.outputs.csc_lib - elif hasattr(ctx.outputs, "csc_exe"): - output = ctx.outputs.csc_exe - else: - fail("You must supply one of csc_lib or csc_exe") - return output - -def _csc_collect_inputs(ctx, extra_files=[]): - depinfo = _make_csc_deps(ctx.attr.deps, extra_files=extra_files) - inputs = (depset(ctx.files.srcs) + depset(ctx.files.resources) + depinfo.dlls - + depinfo.transitive_dlls + [ctx.file.csc]) - srcs = [src.path for src in ctx.files.srcs] - return struct(depinfo=depinfo, - inputs=inputs, - srcs=srcs) - -def _csc_compile_action(ctx, assembly, all_outputs, collected_inputs, - extra_refs=[]): - csc_args = _make_csc_arglist(ctx, assembly, collected_inputs.depinfo, - extra_refs=extra_refs) - - csc_args.add(collected_inputs.srcs) - - csc_args.set_param_file_format("multiline") - - # Use a "response file" to pass arguments to csc. - # Windows has a max command-line length of around 32k bytes. The default for - # Args is to spill to param files if the length of the executable, params - # and spaces between them sum to that number. Unfortunately the math doesn't - # work out exactly like that on Windows (e.g. there is also a null - # terminator, escaping.) For now, setting use_always to True is the - # conservative option. Long command lines are probable with C# due to - # organizing files by namespace. - csc_args.use_param_file("@%s", use_always=True) - - ctx.actions.run( - inputs = list(collected_inputs.inputs), - outputs = all_outputs, - executable = ctx.file.csc.path, - arguments = [csc_args], - progress_message = ( - "Compiling " + ctx.label.package + ":" + ctx.label.name)) - -def _cs_runfiles(ctx, outputs, depinfo, add_mono=False): - mono_file = [] - if add_mono: - mono_file = [ctx.file.mono] - - return ctx.runfiles( - files = outputs, - transitive_files = depset(depinfo.dlls + depinfo.transitive_dlls + mono_file) or None) - -def _csc_compile_impl(ctx): - if hasattr(ctx.outputs, "csc_lib") and hasattr(ctx.outputs, "csc_exe"): - fail("exactly one of csc_lib and csc_exe must be defined") - - output = _csc_get_output(ctx) - outputs = [output] + ( - [ctx.outputs.doc_xml] if hasattr(ctx.outputs, "doc_xml") else []) - - collected = _csc_collect_inputs(ctx) - - depinfo = collected.depinfo - inputs = collected.inputs - srcs = collected.srcs - - runfiles = _cs_runfiles(ctx, outputs, depinfo, add_mono=True) - - _csc_compile_action(ctx, output, outputs, collected) - - if hasattr(ctx.outputs, "csc_exe"): - _make_launcher(ctx, depinfo, output) - - return struct(name = ctx.label.name, - srcs = srcs, - target_type=ctx.attr._target_type, - out = output, - dlls = depset([output]), - transitive_dlls = depinfo.dlls, - runfiles = runfiles) - -def _cs_nunit_run_impl(ctx): - if hasattr(ctx.outputs, "csc_lib") and hasattr(ctx.outputs, "csc_exe"): - fail("exactly one of csc_lib and csc_exe must be defined") - - output = _csc_get_output(ctx) - outputs = [output] + ( - [ctx.outputs.doc_xml] if hasattr(ctx.outputs, "doc_xml") else []) - outputs = outputs - - collected_inputs = _csc_collect_inputs(ctx, ctx.files._nunit_framework) - - depinfo = collected_inputs.depinfo - inputs = collected_inputs.inputs - srcs = collected_inputs.srcs - - runfiles = _cs_runfiles( - ctx, - outputs + ctx.files._nunit_exe + ctx.files._nunit_exe_libs, - depinfo, - add_mono=True) - - _csc_compile_action(ctx, output, outputs, collected_inputs, - extra_refs=["Nunit.Framework"]) - - _make_nunit_launcher(ctx, depinfo, output) - - return struct(name=ctx.label.name, - srcs=srcs, - target_type=ctx.attr._target_type, - out=output, - dlls = (depset([output]) - if hasattr(ctx.outputs, "csc_lib") else None), - transitive_dlls = depinfo.dlls, - runfiles=runfiles) - -def _find_and_symlink(repository_ctx, binary, env_variable): - #repository_ctx.file("bin/empty") - if env_variable in repository_ctx.os.environ: - return repository_ctx.path(repository_ctx.os.environ[env_variable]) - else: - found_binary = repository_ctx.which(binary) - if found_binary == None: - fail("Cannot find %s. Either correct your path or set the " % binary + - "%s environment variable." % env_variable) - repository_ctx.symlink(found_binary, "bin/%s" % binary) - -def _csharp_autoconf(repository_ctx): - _find_and_symlink(repository_ctx, "mono", "MONO") - _find_and_symlink(repository_ctx, "mcs", "CSC") - toolchain_build = """\ -package(default_visibility = ["//visibility:public"]) -exports_files(["mono", "mcs"]) -""" - repository_ctx.file("bin/BUILD", toolchain_build) - -_COMMON_ATTRS = { - # code dependencies for this rule. - # all dependencies must provide an out field. - "deps": attr.label_list(providers=["out", "target_type"]), - # source files for this target. - "srcs": attr.label_list(allow_files = FileType([".cs", ".resx"])), - # resources to use as dependencies. - "resources": attr.label_list(allow_files = True), - # TODO(jeremy): # name of the module if you are creating a module. - # TODO(jeremy): "modulename": attri.string(), - # warn level to use - "warn": attr.int(default=4), - # define preprocessor symbols. - # TODO(jeremy): "define": attr.string_list(), - # The mono binary and csharp compiler. - "mono": attr.label( - default = Label("@mono//bin:mono"), - allow_files = True, - single_file = True, - executable = True, - cfg = "host", - ), - "csc": attr.label( - default = Label("@mono//bin:mcs"), - allow_files = True, - single_file = True, - executable = True, - cfg = "host", - ), -} - -_LIB_ATTRS = { - "_target_type": attr.string(default="library") -} - -_NUGET_ATTRS = { - "srcs": attr.label_list(allow_files = FileType([".dll"])), - "_target_type": attr.string(default="library_set") -} - -_EXE_ATTRS = { - "_target_type": attr.string(default="exe"), - # main class to use as entry point. - "main_class": attr.string(), -} - -_NUNIT_ATTRS = { - "_nunit_exe": attr.label(default=Label("@nunit//:nunit_exe"), - single_file=True), - "_nunit_framework": attr.label(default=Label("@nunit//:nunit_framework")), - "_nunit_exe_libs": attr.label(default=Label("@nunit//:nunit_exe_libs")), -} - -_LIB_OUTPUTS = { - "csc_lib": "%{name}.dll", - "doc_xml": "%{name}.xml", -} - -_BIN_OUTPUTS = { - "csc_exe": "%{name}.exe", -} - -csharp_library = rule( - implementation = _csc_compile_impl, - attrs = dict(_COMMON_ATTRS.items() + _LIB_ATTRS.items()), - outputs = _LIB_OUTPUTS, -) -"""Builds a C# .NET library and its corresponding documentation. - -Args: - name: A unique name for this rule. - srcs: C# `.cs` or `.resx` files. - deps: Dependencies for this rule - warn: Compiler warning level for this library. (Defaults to 4). - csc: Override the default C# compiler. - - **Note:** This attribute may be removed in future versions. -""" - -csharp_binary = rule( - implementation = _csc_compile_impl, - attrs = dict(_COMMON_ATTRS.items() + _EXE_ATTRS.items()), - outputs = _BIN_OUTPUTS, - executable = True, -) -"""Builds a C# .NET binary. - -Args: - name: A unique name for this rule. - srcs: C# `.cs` or `.resx` files. - deps: Dependencies for this rule - main_class: Name of class with `main()` method to use as entry point. - warn: Compiler warning level for this library. (Defaults to 4). - csc: Override the default C# compiler. - - **Note:** This attribute may be removed in future versions. -""" - -csharp_nunit_test = rule( - implementation = _cs_nunit_run_impl, - executable = True, - attrs = dict(_COMMON_ATTRS.items() + _LIB_ATTRS.items() + - _NUNIT_ATTRS.items()), - outputs = _LIB_OUTPUTS, - test = True, -) -"""Builds a C# .NET test binary that uses the [NUnit](http://nunit.org) unit -testing framework. - -Args: - name: A unique name for this rule. - srcs: C# `.cs` or `.resx` files. - deps: Dependencies for this rule - warn: Compiler warning level for this library. (Defaults to 4). - csc: Override the default C# compiler. - - **Note:** This attribute may be removed in future versions. -""" - -def _dll_import_impl(ctx): - inputs = depset(ctx.files.srcs) - return struct( - name = ctx.label.name, - target_type = ctx.attr._target_type, - out = inputs, - dlls = inputs, - transitive_dlls = depset(), - ) - -dll_import = rule( - implementation = _dll_import_impl, - attrs = _NUGET_ATTRS, -) - -def _nuget_package_impl(repository_ctx, - build_file = None, - build_file_content = None): - # figure out the output_path - package = repository_ctx.attr.package - output_dir = repository_ctx.path("") - - mono = repository_ctx.path(repository_ctx.attr.mono_exe) - nuget = repository_ctx.path(repository_ctx.attr.nuget_exe) - - # assemble our nuget command - nuget_cmd = [ - mono, - "--config", "%s/../etc/mono/config" % mono.dirname, - nuget, - "install", - "-Version", repository_ctx.attr.version, - "-OutputDirectory", output_dir, - ] - # add the sources from our source list to the command - for source in repository_ctx.attr.package_sources: - nuget_cmd += ["-Source", source] - - # Lastly we add the nuget package name. - nuget_cmd += [repository_ctx.attr.package] - # execute nuget download. - result = repository_ctx.execute(nuget_cmd) - if result.return_code: - fail("Nuget command failed: %s (%s)" % (result.stderr, " ".join(nuget_cmd))) - - if build_file_content: - repository_ctx.file("BUILD", build_file_content) - elif build_file: - repository_ctx.symlink(repository_ctx.path(build_file), "BUILD") - else: - tpl_file = Label("//dotnet:NUGET_BUILD.tpl") - # add the BUILD file - repository_ctx.template( - "BUILD", - tpl_file, - {"%{package}": repository_ctx.name, - "%{output_dir}": "%s" % output_dir}) - -_nuget_package_attrs = { - # Sources to download the nuget packages from - "package_sources":attr.string_list(), - # The name of the nuget package - "package":attr.string(mandatory=True), - # The version of the nuget package - "version":attr.string(mandatory=True), - # Reference to the mono binary - "mono_exe":attr.label( - executable=True, - default=Label("@mono//bin:mono"), - cfg="host", - ), - # Reference to the nuget.exe file - "nuget_exe":attr.label( - default=Label("@nuget//:nuget.exe"), - ), -} - -nuget_package = repository_rule( - implementation=_nuget_package_impl, - attrs=_nuget_package_attrs, -) -"""Fetches a nuget package as an external dependency. - -Args: - package_sources: list of sources to use for nuget package feeds. - package: name of the nuget package. - version: version of the nuget package (e.g. 0.1.2) - mono_exe: optional label to the mono executable. - nuget_exe: optional label to the nuget.exe file. -""" - -def _new_nuget_package_impl(repository_ctx): - build_file = repository_ctx.attr.build_file - build_file_content = repository_ctx.attr.build_file_content - if not (build_file_content or build_file): - fail("build_file or build_file_content is required") - _nuget_package_impl(repository_ctx, build_file, build_file_content) - -new_nuget_package = repository_rule( - implementation=_new_nuget_package_impl, - attrs=dicts.add(_nuget_package_attrs, { - "build_file": attr.label( - allow_files = True, - ), - "build_file_content": attr.string(), - })) -"""Fetches a nuget package as an external dependency with custom BUILD content. - -Args: - package_sources: list of sources to use for nuget package feeds. - package: name of the nuget package. - version: version of the nuget package (e.g. 0.1.2) - mono_exe: optional label to the mono executable. - nuget_exe: optional label to the nuget.exe file. - build_file: label to the BUILD file. - build_file_content: content for the BUILD file. -""" - -csharp_autoconf = repository_rule( - implementation = _csharp_autoconf, - local = True, -) - -def _mono_osx_repository_impl(repository_ctx): - download_output = repository_ctx.path("") - # download the package - repository_ctx.download_and_extract( - "http://bazel-mirror.storage.googleapis.com/download.mono-project.com/archive/4.2.3/macos-10-x86/MonoFramework-MDK-4.2.3.4.macos10.xamarin.x86.tar.gz", - download_output, - "a7afb92d4a81f17664a040c8f36147e57a46bb3c33314b73ec737ad73608e08b", - "", "mono") - - # now we create the build file. - toolchain_build = """ -package(default_visibility = ["//visibility:public"]) -exports_files(["mono", "mcs"]) -""" - repository_ctx.file("bin/BUILD", toolchain_build) - -def _mono_repository_impl(repository_ctx): - use_local = repository_ctx.os.environ.get( - "RULES_DOTNET_USE_LOCAL_MONO", repository_ctx.attr.use_local) - if use_local: - _csharp_autoconf(repository_ctx) - elif repository_ctx.os.name.find("mac") != -1: - _mono_osx_repository_impl(repository_ctx) - else: - fail("Unsupported operating system: %s" % repository_ctx.os.name) - -mono_package = repository_rule( - implementation = _mono_repository_impl, - attrs = { - "use_local": attr.bool(default=False), - }, - local = True, -) - -def csharp_repositories(use_local_mono=False): - """Adds the repository rules needed for using the C# rules.""" - - native.new_http_archive( - name = "nunit", - url = "http://bazel-mirror.storage.googleapis.com/github.com/nunit/nunitv2/releases/download/2.6.4/NUnit-2.6.4.zip", - sha256 = "1bd925514f31e7729ccde40a38a512c2accd86895f93465f3dfe6d0b593d7170", - type = "zip", - # This is a little weird but is necessary for the build file reference to - # work when Workspaces import this using a repository rule. - build_file = str(Label("//dotnet:nunit.BUILD")), - ) - - native.new_http_archive( - name = "nuget", - url = "https://github.com/mono/nuget-binary/archive/0811ba888a80aaff66a93a4c98567ce904ab2663.zip", # Sept 6, 2016 - sha256 = "28323d23b7e6e02d3ba8892f525a1457ad23adb7e3a48908d37c1b5ae37519f6", - strip_prefix = "nuget-binary-0811ba888a80aaff66a93a4c98567ce904ab2663", - type = "zip", - build_file_content = """ - package(default_visibility = ["//visibility:public"]) - exports_files(["nuget.exe"]) - """ - ) - - mono_package(name="mono", use_local=use_local_mono) diff --git a/dotnet/defs.bzl b/dotnet/defs.bzl new file mode 100644 index 00000000000000..9eeb4001706348 --- /dev/null +++ b/dotnet/defs.bzl @@ -0,0 +1,53 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + dotnet_context = "dotnet_context", +) +load( + "@io_bazel_rules_dotnet//dotnet/toolchain:toolchains.bzl", + "dotnet_register_toolchains", +) +load( + "@io_bazel_rules_dotnet//dotnet/private:sdk.bzl", + dotnet_download_sdk = "dotnet_download_sdk", + dotnet_host_sdk = "dotnet_host_sdk", + dotnet_local_sdk = "dotnet_local_sdk", +) +load( + "@io_bazel_rules_dotnet//dotnet/private:dotnet_toolchain.bzl", + dotnet_toolchain = "dotnet_toolchain", +) +load( + "@io_bazel_rules_dotnet//dotnet/private:repositories.bzl", + dotnet_repositories = "dotnet_repositories", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/binary.bzl", + dotnet_binary = "dotnet_binary" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/library.bzl", + dotnet_library = "dotnet_library" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/resx.bzl", + dotnet_resx = "dotnet_resx" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/test.bzl", + dotnet_nunit_test = "dotnet_nunit_test" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/nuget.bzl", + dotnet_nuget = "dotnet_nuget", + dotnet_nuget_new = "dotnet_nuget_new" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/import.bzl", + dotnet_import_library = "dotnet_import_library" +) diff --git a/dotnet/externals/BUILD b/dotnet/externals/BUILD new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/dotnet/externals/BUILD.nunit2 b/dotnet/externals/BUILD.nunit2 new file mode 100644 index 00000000000000..aaaf53ec0b3741 --- /dev/null +++ b/dotnet/externals/BUILD.nunit2 @@ -0,0 +1,494 @@ +package(default_visibility = ["//visibility:public"]) + +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_library", "dotnet_binary", "dotnet_resx") + +dotnet_library( + name = "nunit.core.interfaces", + srcs = [":NUnitCore_Interfaces_files"], + defines = ["CLR_4_0"], + visibility = ["//visibility:public"], + deps = ["@io_bazel_rules_dotnet//dotnet/stdlib:System.dll"] +) + +dotnet_library( + name = "nunit.framework", + srcs = [":NUnitFramework_framework_files"], + defines = ["CLR_4_0"], + visibility = ["//visibility:public"], + deps = [ + "@io_bazel_rules_dotnet//dotnet/stdlib:System.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Data.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Xml.dll", + ] +) + +dotnet_library( + name = "nunit.core", + srcs = [":NUnitCore_core_files"], + defines = ["CLR_4_0"], + visibility = ["//visibility:public"], + deps = [ + "@io_bazel_rules_dotnet//dotnet/stdlib:System.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Configuration.dll", + ":nunit.core.interfaces", + ] +) + +dotnet_library( + name = "nunit.util", + srcs = [":ClientUtilities_util_files"], + resources = [":Transform"], + defines = ["CLR_4_0"], + visibility = ["//visibility:public"], + deps = [ + "@io_bazel_rules_dotnet//dotnet/stdlib:System.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Configuration.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Runtime.Remoting.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Drawing.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Xml.dll", + ":nunit.core.interfaces", + ":nunit.core", + ] +) + +dotnet_resx( + name = "Transform", + src = ":src/ClientUtilities/util/Transform.resx", +) + +dotnet_library( + name = "nunit-console-runner", + srcs = [":ConsoleRunner_nunit_console_files"], + visibility = ["//visibility:public"], + deps = [ + "@io_bazel_rules_dotnet//dotnet/stdlib:System.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Xml.dll", + "@io_bazel_rules_dotnet//dotnet/stdlib:System.Drawing.dll", + ":nunit.core.interfaces", + ":nunit.core", + ":nunit.util", + ] +) + +dotnet_binary( + name = "nunit-console-runner-exe", + srcs = [":ConsoleRunner_nunit_console_exe_files"], + deps = [ + "@io_bazel_rules_dotnet//dotnet/stdlib:System.dll", + ":nunit-console-runner", + ":nunit.core", + ":nunit.util", + ] +) + + +filegroup( + name = "common_assembly_info_files", + srcs = [":src/CommonAssemblyInfo.cs"], +) + +filegroup( + name = "NUnitCore_Interfaces_files", + srcs = [":common_assembly_info_files", + ":src/NUnitFramework/framework/ITestCaseData.cs", + ":src/NUnitCore/interfaces/EventListener.cs", + ":src/NUnitCore/interfaces/IAgency.cs", + ":src/NUnitCore/interfaces/IService.cs", + ":src/NUnitCore/interfaces/ITest.cs", + ":src/NUnitCore/interfaces/ITestFilter.cs", + ":src/NUnitCore/interfaces/LoggingThreshold.cs", + ":src/NUnitCore/interfaces/OSPlatform.cs", + ":src/NUnitCore/interfaces/PropertyNames.cs", + ":src/NUnitCore/interfaces/ResultState.cs", + ":src/NUnitCore/interfaces/RunState.cs", + ":src/NUnitCore/interfaces/RuntimeFramework.cs", + ":src/NUnitCore/interfaces/Test.cs", + ":src/NUnitCore/interfaces/TestAgent.cs", + ":src/NUnitCore/interfaces/TestAssemblyInfo.cs", + ":src/NUnitCore/interfaces/TestFilter.cs", + ":src/NUnitCore/interfaces/TestID.cs", + ":src/NUnitCore/interfaces/TestInfo.cs", + ":src/NUnitCore/interfaces/TestName.cs", + ":src/NUnitCore/interfaces/TestNode.cs", + ":src/NUnitCore/interfaces/TestOutput.cs", + ":src/NUnitCore/interfaces/TestPackage.cs", + ":src/NUnitCore/interfaces/TestResult.cs", + ":src/NUnitCore/interfaces/TestRunner.cs", + ":src/NUnitCore/interfaces/Extensibility/Addin.cs", + ":src/NUnitCore/interfaces/Extensibility/AddinStatus.cs", + ":src/NUnitCore/interfaces/Extensibility/ExtensionType.cs", + ":src/NUnitCore/interfaces/Extensibility/IAddin.cs", + ":src/NUnitCore/interfaces/Extensibility/IAddinRegistry.cs", + ":src/NUnitCore/interfaces/Extensibility/IDataPointProvider.cs", + ":src/NUnitCore/interfaces/Extensibility/IExtensionHost.cs", + ":src/NUnitCore/interfaces/Extensibility/IExtensionPoint.cs", + ":src/NUnitCore/interfaces/Extensibility/IFrameworkRegistry.cs", + ":src/NUnitCore/interfaces/Extensibility/ISuiteBuilder.cs", + ":src/NUnitCore/interfaces/Extensibility/ITestCaseBuilder.cs", + ":src/NUnitCore/interfaces/Extensibility/ITestCaseProvider.cs", + ":src/NUnitCore/interfaces/Extensibility/ITestDecorator.cs", + ":src/NUnitCore/interfaces/Extensibility/NUnitAddinAttribute.cs", + ":src/NUnitCore/interfaces/Extensibility/ParameterSet.cs", + ":src/NUnitCore/interfaces/Extensibility/TestFramework.cs", + ":src/NUnitCore/interfaces/Filters/AndFilter.cs", + ":src/NUnitCore/interfaces/Filters/CategoryFilter.cs", + ":src/NUnitCore/interfaces/Filters/NameFilter.cs", + ":src/NUnitCore/interfaces/Filters/NotFilter.cs", + ":src/NUnitCore/interfaces/Filters/OrFilter.cs", + ":src/NUnitCore/interfaces/Filters/SimpleNameFilter.cs", + ] +) + +filegroup( + name = "NUnitFramework_framework_files", + srcs = [":common_assembly_info_files", + ":src/NUnitFramework/framework/AsyncSynchronizationContext.cs", + ":src/NUnitFramework/framework/AsyncInvocationRegion.cs", + ":src/NUnitFramework/framework/Attributes/CategoryAttribute.cs", + ":src/NUnitFramework/framework/Attributes/DatapointAttributes.cs", + ":src/NUnitFramework/framework/Attributes/DescriptionAttribute.cs", + ":src/NUnitFramework/framework/Attributes/ExpectedExceptionAttribute.cs", + ":src/NUnitFramework/framework/Attributes/ExplicitAttribute.cs", + ":src/NUnitFramework/framework/Attributes/IgnoreAttribute.cs", + ":src/NUnitFramework/framework/Attributes/IncludeExcludeAttributes.cs", + ":src/NUnitFramework/framework/Attributes/JoinTypeAttributes.cs", + ":src/NUnitFramework/framework/Attributes/MaxTimeAttribute.cs", + ":src/NUnitFramework/framework/Attributes/PropertyAttribute.cs", + ":src/NUnitFramework/framework/Attributes/RandomAttribute.cs", + ":src/NUnitFramework/framework/Attributes/RangeAttribute.cs", + ":src/NUnitFramework/framework/Attributes/RepeatAttribute.cs", + ":src/NUnitFramework/framework/Attributes/RequiredAddinAttribute.cs", + ":src/NUnitFramework/framework/Attributes/SetCultureAttribute.cs", + ":src/NUnitFramework/framework/Attributes/SetUICultureAttribute.cs", + ":src/NUnitFramework/framework/Attributes/SetUpAttribute.cs", + ":src/NUnitFramework/framework/Attributes/SetUpFixtureAttribute.cs", + ":src/NUnitFramework/framework/Attributes/SuiteAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TearDownAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestActionAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestCaseAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestCaseSourceAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestFixtureAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestFixtureSetUpAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TestFixtureTearDownAttribute.cs", + ":src/NUnitFramework/framework/Attributes/TheoryAttribute.cs", + ":src/NUnitFramework/framework/Attributes/ThreadingAttributes.cs", + ":src/NUnitFramework/framework/Attributes/ValuesAttribute.cs", + ":src/NUnitFramework/framework/Attributes/ValueSourceAttribute.cs", + ":src/NUnitFramework/framework/Exceptions/AssertionException.cs", + ":src/NUnitFramework/framework/Exceptions/IgnoreException.cs", + ":src/NUnitFramework/framework/Exceptions/InconclusiveException.cs", + ":src/NUnitFramework/framework/Exceptions/SuccessException.cs", + ":src/NUnitFramework/framework/Interfaces/INUnitEqualityComparer.cs", + ":src/NUnitFramework/framework/Interfaces/ITestAction.cs", + ":src/NUnitFramework/framework/ActionTargets.cs", + ":src/NUnitFramework/framework/Assert.cs", + ":src/NUnitFramework/framework/AssertionHelper.cs", + ":src/NUnitFramework/framework/Assume.cs", + ":src/NUnitFramework/framework/CollectionAssert.cs", + ":src/NUnitFramework/framework/Contains.cs", + ":src/NUnitFramework/framework/DirectoryAssert.cs", + ":src/NUnitFramework/framework/FileAssert.cs", + ":src/NUnitFramework/framework/GlobalSettings.cs", + ":src/NUnitFramework/framework/Guard.cs", + ":src/NUnitFramework/framework/Has.cs", + ":src/NUnitFramework/framework/IExpectException.cs", + ":src/NUnitFramework/framework/Is.cs", + ":src/NUnitFramework/framework/Iz.cs", + ":src/NUnitFramework/framework/ITestCaseData.cs", + ":src/NUnitFramework/framework/List.cs", + ":src/NUnitFramework/framework/ListMapper.cs", + ":src/NUnitFramework/framework/Randomizer.cs", + ":src/NUnitFramework/framework/SpecialValue.cs", + ":src/NUnitFramework/framework/StringAssert.cs", + ":src/NUnitFramework/framework/TestCaseData.cs", + ":src/NUnitFramework/framework/TestContext.cs", + ":src/NUnitFramework/framework/TestDetails.cs", + ":src/NUnitFramework/framework/TestState.cs", + ":src/NUnitFramework/framework/TestStatus.cs", + ":src/NUnitFramework/framework/Text.cs", + ":src/NUnitFramework/framework/TextMessageWriter.cs", + ":src/NUnitFramework/framework/Throws.cs", + ":src/NUnitFramework/framework/Constraints/AllItemsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/AndConstraint.cs", + ":src/NUnitFramework/framework/Constraints/AssignableFromConstraint.cs", + ":src/NUnitFramework/framework/Constraints/AssignableToConstraint.cs", + ":src/NUnitFramework/framework/Constraints/AttributeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/AttributeExistsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/BasicConstraint.cs", + ":src/NUnitFramework/framework/Constraints/BinaryConstraint.cs", + ":src/NUnitFramework/framework/Constraints/BinarySerializableConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionContainsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionEquivalentConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionItemsEqualConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionOrderedConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionSubsetConstraint.cs", + ":src/NUnitFramework/framework/Constraints/CollectionTally.cs", + ":src/NUnitFramework/framework/Constraints/ComparisonAdapter.cs", + ":src/NUnitFramework/framework/Constraints/ComparisonConstraint.cs", + ":src/NUnitFramework/framework/Constraints/Constraint.cs", + ":src/NUnitFramework/framework/Constraints/ConstraintBuilder.cs", + ":src/NUnitFramework/framework/Constraints/ConstraintExpression.cs", + ":src/NUnitFramework/framework/Constraints/ConstraintExpressionBase.cs", + ":src/NUnitFramework/framework/Constraints/ConstraintFactory.cs", + ":src/NUnitFramework/framework/Constraints/ContainsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/DelayedConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EmptyCollectionConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EmptyConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EmptyDirectoryConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EmptyStringConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EndsWithConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EqualConstraint.cs", + ":src/NUnitFramework/framework/Constraints/EqualityAdapter.cs", + ":src/NUnitFramework/framework/Constraints/ExactCountConstraint.cs", + ":src/NUnitFramework/framework/Constraints/ExactTypeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/ExceptionTypeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/FailurePoint.cs", + ":src/NUnitFramework/framework/Constraints/FalseConstraint.cs", + ":src/NUnitFramework/framework/Constraints/FloatingPointNumerics.cs", + ":src/NUnitFramework/framework/Constraints/GreaterThanConstraint.cs", + ":src/NUnitFramework/framework/Constraints/GreaterThanOrEqualConstraint.cs", + ":src/NUnitFramework/framework/Constraints/IResolveConstraint.cs", + ":src/NUnitFramework/framework/Constraints/InstanceOfTypeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/LessThanConstraint.cs", + ":src/NUnitFramework/framework/Constraints/LessThanOrEqualConstraint.cs", + ":src/NUnitFramework/framework/Constraints/MessageWriter.cs", + ":src/NUnitFramework/framework/Constraints/MsgUtils.cs", + ":src/NUnitFramework/framework/Constraints/NUnitComparer.cs", + ":src/NUnitFramework/framework/Constraints/NUnitEqualityComparer.cs", + ":src/NUnitFramework/framework/Constraints/NaNConstraint.cs", + ":src/NUnitFramework/framework/Constraints/NoItemConstraint.cs", + ":src/NUnitFramework/framework/Constraints/NotConstraint.cs", + ":src/NUnitFramework/framework/Constraints/NullConstraint.cs", + ":src/NUnitFramework/framework/Constraints/NullOrEmptyStringConstraint.cs", + ":src/NUnitFramework/framework/Constraints/Numerics.cs", + ":src/NUnitFramework/framework/Constraints/OrConstraint.cs", + ":src/NUnitFramework/framework/Constraints/PathConstraint.cs", + ":src/NUnitFramework/framework/Constraints/PredicateConstraint.cs", + ":src/NUnitFramework/framework/Constraints/PrefixConstraint.cs", + ":src/NUnitFramework/framework/Constraints/PropertyConstraint.cs", + ":src/NUnitFramework/framework/Constraints/PropertyExistsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/RangeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/RegexConstraint.cs", + ":src/NUnitFramework/framework/Constraints/ResolvableConstraintExpression.cs", + ":src/NUnitFramework/framework/Constraints/ReusableConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SameAsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SamePathConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SamePathOrUnderConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SomeItemsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/StartsWithConstraint.cs", + ":src/NUnitFramework/framework/Constraints/StringConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SubPathConstraint.cs", + ":src/NUnitFramework/framework/Constraints/SubstringConstraint.cs", + ":src/NUnitFramework/framework/Constraints/ThrowsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/ThrowsNothingConstraint.cs", + ":src/NUnitFramework/framework/Constraints/Tolerance.cs", + ":src/NUnitFramework/framework/Constraints/ToleranceMode.cs", + ":src/NUnitFramework/framework/Constraints/TrueConstraint.cs", + ":src/NUnitFramework/framework/Constraints/TypeConstraint.cs", + ":src/NUnitFramework/framework/Constraints/UniqueItemsConstraint.cs", + ":src/NUnitFramework/framework/Constraints/XmlSerializableConstraint.cs", + ":src/NUnitFramework/framework/Constraints/Operators/AllOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/AndOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/AttributeOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/BinaryOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/CollectionOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/ConstraintOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/ExactCountOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/NoneOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/NotOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/OrOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/PrefixOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/PropOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/SelfResolvingOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/SomeOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/ThrowsOperator.cs", + ":src/NUnitFramework/framework/Constraints/Operators/WithOperator.cs", + ] +) + +filegroup( + name = "NUnitCore_core_files", + srcs = [":common_assembly_info_files", + ":src/NUnitFramework/framework/AsyncSynchronizationContext.cs", + ":src/NUnitFramework/framework/AsyncInvocationRegion.cs", + ":src/NUnitCore/core/AbstractTestCaseDecoration.cs", + ":src/NUnitCore/core/AssemblyHelper.cs", + ":src/NUnitCore/core/AssemblyReader.cs", + ":src/NUnitCore/core/AssemblyResolver.cs", + ":src/NUnitCore/core/ActionsHelper.cs", + ":src/NUnitCore/core/Builders/CombinatorialStrategy.cs", + ":src/NUnitCore/core/Builders/CombinatorialTestCaseProvider.cs", + ":src/NUnitCore/core/Builders/CombiningStrategy.cs", + ":src/NUnitCore/core/Builders/DatapointProvider.cs", + ":src/NUnitCore/core/Builders/InlineDataPointProvider.cs", + ":src/NUnitCore/core/Builders/LegacySuiteBuilder.cs", + ":src/NUnitCore/core/Builders/NUnitTestCaseBuilder.cs", + ":src/NUnitCore/core/Builders/NUnitTestFixtureBuilder.cs", + ":src/NUnitCore/core/Builders/PairwiseStrategy.cs", + ":src/NUnitCore/core/Builders/ProviderCache.cs", + ":src/NUnitCore/core/Builders/ProviderInfo.cs", + ":src/NUnitCore/core/Builders/SequentialStrategy.cs", + ":src/NUnitCore/core/Builders/SetUpFixtureBuilder.cs", + ":src/NUnitCore/core/Builders/TestAssemblyBuilder.cs", + ":src/NUnitCore/core/Builders/TestCaseParameterProvider.cs", + ":src/NUnitCore/core/Builders/TestCaseSourceProvider.cs", + ":src/NUnitCore/core/UnsupportedFrameworkException.cs", + ":src/NUnitCore/core/Builders/ValueSourceProvider.cs", + ":src/NUnitCore/core/ContextDictionary.cs", + ":src/NUnitCore/core/CoreExtensions.cs", + ":src/NUnitCore/core/CultureDetector.cs", + ":src/NUnitCore/core/DirectorySwapper.cs", + ":src/NUnitCore/core/DomainAgent.cs", + ":src/NUnitCore/core/EventListenerTextWriter.cs", + ":src/NUnitCore/core/EventPump.cs", + ":src/NUnitCore/core/EventQueue.cs", + ":src/NUnitCore/core/ExpectedExceptionProcessor.cs", + ":src/NUnitCore/core/Extensibility/DataPointProviders.cs", + ":src/NUnitCore/core/Extensibility/EventListenerCollection.cs", + ":src/NUnitCore/core/Extensibility/FrameworkRegistry.cs", + ":src/NUnitCore/core/Extensibility/SuiteBuilderCollection.cs", + ":src/NUnitCore/core/Extensibility/TestCaseBuilderCollection.cs", + ":src/NUnitCore/core/Extensibility/TestCaseProviders.cs", + ":src/NUnitCore/core/Extensibility/TestDecoratorCollection.cs", + ":src/NUnitCore/core/ExtensionHost.cs", + ":src/NUnitCore/core/ExtensionPoint.cs", + ":src/NUnitCore/core/IgnoreDecorator.cs", + ":src/NUnitCore/core/InternalTrace.cs", + ":src/NUnitCore/core/InternalTraceWriter.cs", + ":src/NUnitCore/core/InvalidSuiteException.cs", + ":src/NUnitCore/core/InvalidTestFixtureException.cs", + ":src/NUnitCore/core/LegacySuite.cs", + ":src/NUnitCore/core/Log4NetCapture.cs", + ":src/NUnitCore/core/Logger.cs", + ":src/NUnitCore/core/MethodHelper.cs", + ":src/NUnitCore/core/NamespaceSuite.cs", + ":src/NUnitCore/core/NamespaceTreeBuilder.cs", + ":src/NUnitCore/core/NoTestFixturesException.cs", + ":src/NUnitCore/core/NullListener.cs", + ":src/NUnitCore/core/NUnitAsyncTestMethod.cs", + ":src/NUnitCore/core/NUnitConfiguration.cs", + ":src/NUnitCore/core/NUnitException.cs", + ":src/NUnitCore/core/NUnitFramework.cs", + ":src/NUnitCore/core/NUnitTestFixture.cs", + ":src/NUnitCore/core/NUnitTestMethod.cs", + ":src/NUnitCore/core/ParameterizedFixtureSuite.cs", + ":src/NUnitCore/core/ParameterizedTestMethodSuite.cs", + ":src/NUnitCore/core/PlatformHelper.cs", + ":src/NUnitCore/core/ProjectRootSuite.cs", + ":src/NUnitCore/core/ProxyTestRunner.cs", + ":src/NUnitCore/core/QueuingEventListener.cs", + ":src/NUnitCore/core/Reflect.cs", + ":src/NUnitCore/core/RemoteTestRunner.cs", + ":src/NUnitCore/core/SetUpFixture.cs", + ":src/NUnitCore/core/SimpleTestRunner.cs", + ":src/NUnitCore/core/StringTextWriter.cs", + ":src/NUnitCore/core/SuiteBuilderAttribute.cs", + ":src/NUnitCore/core/TestAction.cs", + ":src/NUnitCore/core/TestAssembly.cs", + ":src/NUnitCore/core/TestBuilderAttribute.cs", + ":src/NUnitCore/core/TestCaseBuilderAttribute.cs", + ":src/NUnitCore/core/TestDecoratorAttribute.cs", + ":src/NUnitCore/core/TestExecutionContext.cs", + ":src/NUnitCore/core/TestFixture.cs", + ":src/NUnitCore/core/TestFixtureBuilder.cs", + ":src/NUnitCore/core/TestMethod.cs", + ":src/NUnitCore/core/TestRunnerThread.cs", + ":src/NUnitCore/core/TestSuite.cs", + ":src/NUnitCore/core/TestSuiteBuilder.cs", + ":src/NUnitCore/core/TestThread.cs", + ":src/NUnitCore/core/TextCapture.cs", + ":src/NUnitCore/core/ThreadedTestRunner.cs", + ":src/NUnitCore/core/ThreadUtility.cs", + ":src/NUnitCore/core/TypeHelper.cs", + ] +) + +filegroup( + name = "ClientUtilities_util_files", + srcs = [":common_assembly_info_files", + ":src/ClientUtilities/util/AggregatingTestRunner.cs", + ":src/ClientUtilities/util/AssemblyList.cs", + ":src/ClientUtilities/util/AssemblyWatcher.cs", + ":src/ClientUtilities/util/CategoryExpression.cs", + ":src/ClientUtilities/util/CategoryManager.cs", + ":src/ClientUtilities/util/CommandLineOptions.cs", + ":src/ClientUtilities/util/ConsoleWriter.cs", + ":src/ClientUtilities/util/DefaultTestRunnerFactory.cs", + ":src/ClientUtilities/util/FileWatcher.cs", + ":src/ClientUtilities/util/Guard.cs", + ":src/ClientUtilities/util/IAssemblyWatcher.cs", + ":src/ClientUtilities/util/InProcessTestRunnerFactory.cs", + ":src/ClientUtilities/util/MemorySettingsStorage.cs", + ":src/ClientUtilities/util/NUnitProject.cs", + ":src/ClientUtilities/util/NUnitRegistry.cs", + ":src/ClientUtilities/util/PathUtils.cs", + ":src/ClientUtilities/util/ProcessRunner.cs", + ":src/ClientUtilities/util/ProjectConfig.cs", + ":src/ClientUtilities/util/ProjectConfigCollection.cs", + ":src/ClientUtilities/util/ProjectFormatException.cs", + ":src/ClientUtilities/util/RecentFileEntry.cs", + ":src/ClientUtilities/util/RecentFiles.cs", + ":src/ClientUtilities/util/RecentFilesCollection.cs", + ":src/ClientUtilities/util/RegistrySettingsStorage.cs", + ":src/ClientUtilities/util/RemoteTestAgent.cs", + ":src/ClientUtilities/util/ResultSummarizer.cs", + ":src/ClientUtilities/util/RuntimeFrameworkSelector.cs", + ":src/ClientUtilities/util/ServerBase.cs", + ":src/ClientUtilities/util/ServerUtilities.cs", + ":src/ClientUtilities/util/Services.cs", + ":src/ClientUtilities/util/SettingsGroup.cs", + ":src/ClientUtilities/util/SettingsStorage.cs", + ":src/ClientUtilities/util/StackTraceFilter.cs", + ":src/ClientUtilities/util/TestDomain.cs", + ":src/ClientUtilities/util/TestEventArgs.cs", + ":src/ClientUtilities/util/TestEventDispatcher.cs", + ":src/ClientUtilities/util/TestExceptionHandler.cs", + ":src/ClientUtilities/util/TestLabelLevel.cs", + ":src/ClientUtilities/util/TestLoader.cs", + ":src/ClientUtilities/util/TestObserver.cs", + ":src/ClientUtilities/util/TestResultItem.cs", + ":src/ClientUtilities/util/TestServer.cs", + ":src/ClientUtilities/util/VSProject.cs", + ":src/ClientUtilities/util/VSProjectConfig.cs", + ":src/ClientUtilities/util/VSProjectConfigCollection.cs", + ":src/ClientUtilities/util/XmlResultTransform.cs", + ":src/ClientUtilities/util/XmlResultWriter.cs", + ":src/ClientUtilities/util/XmlSettingsStorage.cs", + ":src/ClientUtilities/util/Extensibility/IProjectConverter.cs", + ":src/ClientUtilities/util/Extensibility/ProjectConverterCollection.cs", + ":src/ClientUtilities/util/Interfaces/IRuntimeFrameworkSelector.cs", + ":src/ClientUtilities/util/Interfaces/ISettings.cs", + ":src/ClientUtilities/util/Interfaces/ITestEvents.cs", + ":src/ClientUtilities/util/Interfaces/ITestLoader.cs", + ":src/ClientUtilities/util/Interfaces/ITestRunnerFactory.cs", + ":src/ClientUtilities/util/ProjectConverters/VisualStudioConverter.cs", + ":src/ClientUtilities/util/Services/AddinManager.cs", + ":src/ClientUtilities/util/Services/AddinRegistry.cs", + ":src/ClientUtilities/util/Services/DomainManager.cs", + ":src/ClientUtilities/util/Services/ProjectService.cs", + ":src/ClientUtilities/util/Services/RecentFilesService.cs", + ":src/ClientUtilities/util/Services/ServiceManager.cs", + ":src/ClientUtilities/util/Services/SettingsService.cs", + ":src/ClientUtilities/util/Services/TestAgency.cs", + ] +) + +filegroup( + name = "ConsoleRunner_nunit_console_files", + srcs = [":common_assembly_info_files", + ":src/ConsoleRunner/nunit-console/ConsoleOptions.cs", + ":src/ConsoleRunner/nunit-console/ConsoleUi.cs", + ":src/ConsoleRunner/nunit-console/EventCollector.cs", + ":src/ConsoleRunner/nunit-console/Runner.cs", + ":src/ConsoleRunner/nunit-console/TestNameParser.cs", + ] +) + +filegroup( + name = "ConsoleRunner_nunit_console_exe_files", + srcs = [":common_assembly_info_files", + ":src/ConsoleRunner/nunit-console-exe/Class1.cs", + ] +) diff --git a/dotnet/platform/BUILD b/dotnet/platform/BUILD new file mode 100644 index 00000000000000..d5e37e854017fc --- /dev/null +++ b/dotnet/platform/BUILD @@ -0,0 +1,13 @@ +# This file declares a config_setting for each platform supported by the +# Dotnet. These rules follow a os_arch naming convention, for example, +# //dotnet/platform:linux_amd64 +# +# These can be used in select expressions to choose platform-specifc +# sources and dependencies. + +package(default_visibility = ["//visibility:public"]) + +load(":list.bzl", "declare_config_settings") + +declare_config_settings() + diff --git a/dotnet/platform/list.bzl b/dotnet/platform/list.bzl new file mode 100644 index 00000000000000..75fcb06a341ada --- /dev/null +++ b/dotnet/platform/list.bzl @@ -0,0 +1,48 @@ +DOTNETIMPL = { + "mono": None, +} + +DOTNETOS = { + "darwin": "@bazel_tools//platforms:osx", + "linux": "@bazel_tools//platforms:linux", + "windows": "@bazel_tools//platforms:windows", +} + +DOTNETARCH = { + "amd64": "@bazel_tools//platforms:x86_64", +} + +DOTNETIMPL_OS_ARCH = ( + ("mono", "darwin", "amd64"), + ("mono", "linux", "amd64"), + ("mono", "windows", "amd64"), +) + +def declare_config_settings(): + for impl in DOTNETIMPL: + native.config_setting( + name = impl, + #constraint_values = ["//dotnet/toolchain:" + impl], + values = { + "compilation_mode": impl + } + ) + for os in DOTNETOS: + native.config_setting( + name = os, + constraint_values = ["//dotnet/toolchain:" + os], + ) + for arch in DOTNETARCH: + native.config_setting( + name = arch, + constraint_values = ["//dotnet/toolchain:" + arch], + ) + for arch, os, arch in DOTNETIMPL_OS_ARCH: + native.config_setting( + name = arch + "_" + os + "_" + arch, + constraint_values = [ + "//dotnet/toolchain:" + os, + "//dotnet/toolchain:" + arch, + "//dotnet/toolchain:" + impl, + ], + ) diff --git a/dotnet/private/BUILD b/dotnet/private/BUILD new file mode 100644 index 00000000000000..307f7845ee61d3 --- /dev/null +++ b/dotnet/private/BUILD @@ -0,0 +1,7 @@ + +filegroup( + name = "all_rules", + srcs = glob(["**/*.bzl"]), + visibility = ["//visibility:public"], +) + diff --git a/dotnet/private/BUILD.nuget.bazel b/dotnet/private/BUILD.nuget.bazel new file mode 100644 index 00000000000000..890f810ea75500 --- /dev/null +++ b/dotnet/private/BUILD.nuget.bazel @@ -0,0 +1,8 @@ +package(default_visibility = [ "//visibility:public" ]) + +filegroup( + name = "files", + srcs = glob([ + "**/*.dll", + ]), +) diff --git a/dotnet/private/BUILD.sdk.bazel b/dotnet/private/BUILD.sdk.bazel new file mode 100644 index 00000000000000..04daea87b1a35b --- /dev/null +++ b/dotnet/private/BUILD.sdk.bazel @@ -0,0 +1,22 @@ +package(default_visibility = [ "//visibility:public" ]) + +filegroup( + name = "mcs_bin", + srcs = glob([ + "mcs_bin/*", + ]), +) + +filegroup( + name = "mono_bin", + srcs = glob([ + "mono_bin/*", + ]), +) + +filegroup( + name = "lib", + srcs = glob([ + "lib/**/*", + ]), +) diff --git a/dotnet/private/actions/assembly.bzl b/dotnet/private/actions/assembly.bzl new file mode 100644 index 00000000000000..3e81ffb802c9b1 --- /dev/null +++ b/dotnet/private/actions/assembly.bzl @@ -0,0 +1,144 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "as_iterable", + "sets" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", + "DotnetResource", +) + + +def _map_dep(deps): + return [d[DotnetLibrary].result for d in deps] + +def _map_resource(resources): + return [d[DotnetResource].result.path + "," + d[DotnetResource].identifier for d in resources] + +def _make_runner_arglist(dotnet, deps, resources, output, executable, defines): + args = dotnet.actions.args() + + # /out:<file> + args.add(format="/out:%s", value=output.path) + + if executable: + target = "exe" + else: + target = "library" + + # /target (exe for binary, library for lib, module for module) + args.add(format="/target:%s", value=target) + + args.add("/fullpaths") + args.add("/noconfig") + args.add("/nostdlib") + + # /warn + #args.add(format="/warn:%s", value=str(ctx.attr.warn)) + + # /nologo + args.add("/nologo") + + # /modulename:<string> only used for modules + #libdirs = _get_libdirs(depinfo.dlls) + #libdirs = _get_libdirs(depinfo.transitive_dlls, libdirs) + + # /lib:dir1,[dir1] + #if libdirs: + # args.add(format="/lib:%s", value=libdirs) + + if deps and len(deps)>0: + args.add(format="/reference:%s", value=deps, map_fn=_map_dep) + + args.add(format="/reference:%s", value=dotnet.stdlib) + + if defines and len(defines)>0: + args.add(format="/define:%s", value=defines) + + # /debug + #debug = ctx.var.get("BINMODE", "") == "-dbg" + #if debug: + # args.add("/debug") + + # /warnaserror + # TODO(jeremy): /define:name[;name2] + + if resources and len(resources)>0: + args.add(format="/resource:%s", value=resources, map_fn=_map_resource) + + # TODO(jeremy): /resource:filename[,identifier[,accesibility-modifier]] + + # /main:class + #if hasattr(ctx.attr, "main_class") and ctx.attr.main_class: + # args.add(format="/main:%s", value=ctx.attr.main_class) + + #args.add(format="/resource:%s", value=ctx.files.resources) + + # TODO(jwall): /parallel + + return args + +def emit_assembly(dotnet, + name = "", + srcs = None, + deps = None, + out = None, + resources = None, + executable = True, + defines = None): + """See dotnet/toolchains.rst#binary for full documentation.""" + + if name == "" and out == None: + fail("either name or out must be set") + + if not out: + if executable: + extension = ".exe" + else: + extension = ".dll" + result = dotnet.declare_file(dotnet, path=name+extension) + else: + result = dotnet.declare_file(dotnet, path=out) + extension = "" + + runner_args = _make_runner_arglist(dotnet, deps, resources, result, executable, defines) + + attr_srcs = [f for t in srcs for f in as_iterable(t.files)] + runner_args.add(attr_srcs) + + runner_args.set_param_file_format("multiline") + + # Use a "response file" to pass arguments to csc. + # Windows has a max command-line length of around 32k bytes. The default for + # Args is to spill to param files if the length of the executable, params + # and spaces between them sum to that number. Unfortunately the math doesn't + # work out exactly like that on Windows (e.g. there is also a null + # terminator, escaping.) For now, setting use_always to True is the + # conservative option. Long command lines are probable with C# due to + # organizing files by namespace. + paramfilepath = name+extension+".param" + paramfile = dotnet.declare_file(dotnet, path=paramfilepath) + + dotnet.actions.write(output = paramfile, content = runner_args) + + deps_files = _map_dep(deps) + dotnet.actions.run( + inputs = attr_srcs + [paramfile] + deps_files + [dotnet.stdlib] + [r[DotnetResource].result for r in resources], + outputs = [result], + executable = dotnet.runner, + arguments = [dotnet.mcs.path, "@"+paramfile.path], + progress_message = ( + "Compiling " + dotnet.label.package + ":" + dotnet.label.name)) + + deps_libraries = [d[DotnetLibrary] for d in deps] + transitive = sets.union(deps_libraries, *[a[DotnetLibrary].transitive for a in deps]) + + return dotnet.new_library( + dotnet = dotnet, + name = name, + deps = deps, + transitive = transitive, + result = result) + diff --git a/dotnet/private/actions/binary.bzl b/dotnet/private/actions/binary.bzl new file mode 100644 index 00000000000000..6c0a3cb01cf8e8 --- /dev/null +++ b/dotnet/private/actions/binary.bzl @@ -0,0 +1,23 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:actions/assembly.bzl", + "emit_assembly", +) + +def emit_binary(dotnet, + name = "", + srcs = None, + deps = None, + resources = None, + out = None, + defines = None): + + return emit_assembly( + dotnet = dotnet, + name = name, + srcs = srcs, + deps = deps, + resources = resources, + out = out, + executable = True, + defines = defines, + ) diff --git a/dotnet/private/actions/library.bzl b/dotnet/private/actions/library.bzl new file mode 100644 index 00000000000000..14f6836cfc5baa --- /dev/null +++ b/dotnet/private/actions/library.bzl @@ -0,0 +1,23 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:actions/assembly.bzl", + "emit_assembly", +) + +def emit_library(dotnet, + name = "", + srcs = None, + deps = None, + resources = None, + out = None, + defines = None): + + return emit_assembly( + dotnet = dotnet, + name = name, + srcs = srcs, + deps = deps, + resources = resources, + out = out, + executable = False, + defines = defines, + ) diff --git a/dotnet/private/actions/resx.bzl b/dotnet/private/actions/resx.bzl new file mode 100644 index 00000000000000..105657139046ff --- /dev/null +++ b/dotnet/private/actions/resx.bzl @@ -0,0 +1,65 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "as_iterable", + "sets" +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "paths", +) + + +def _make_runner_arglist(dotnet, source, output): + args = dotnet.actions.args() + + args.add(dotnet.resgen.path) + args.add(format = "%s", value = source.files) + + return args + +def emit_resx(dotnet, + name = "", + src = None, + identifier = None, + out = None): + + if name == "" and out == None: + fail("either name or out must be set") + + if not out: + result = dotnet.declare_file(dotnet, path=name+".resources") + else: + result = dotnet.declare_file(dotnet, path=out) + + # Unfortunately, resgen always produces the output in the same directory as the input file + # Therefore we have to copy the source file to the target directory + copied_source = dotnet.declare_file(dotnet, path=paths.replace_extension(result.basename, ".resx")) + + dotnet.actions.run_shell( + inputs = src.files, + outputs = [copied_source], + command = "cp {} {}".format(src.files.to_list()[0].path, copied_source.path), + ) + + args = _make_runner_arglist(dotnet, src, result) + + dotnet.actions.run( + inputs = [copied_source], + outputs = [result], + executable = dotnet.runner, + arguments = [dotnet.resgen.path, copied_source.path], + progress_message = ( + "Compiling resoources" + dotnet.label.package + ":" + dotnet.label.name)) + + return dotnet.new_resource( + dotnet = dotnet, + name = name, + result = result, + identifier = identifier) + diff --git a/dotnet/private/common.bzl b/dotnet/private/common.bzl new file mode 100644 index 00000000000000..7aaaaf436a6ee5 --- /dev/null +++ b/dotnet/private/common.bzl @@ -0,0 +1,44 @@ +load("//dotnet/private:skylib/lib/paths.bzl", "paths") +load("//dotnet/private:skylib/lib/sets.bzl", "sets") + + +def executable_extension(ctx): + extension = "" + if ctx.os.name.startswith('windows'): + extension = ".exe" + return extension + +def bat_extension(ctx): + extension = "" + if ctx.os.name.startswith('windows'): + extension = ".bat" + return extension + +def as_iterable(v): + if type(v) == "list": + return v + if type(v) == "tuple": + return v + if type(v) == "depset": + return v.to_list() + fail("as_iterator failed on {}".format(v)) + +def env_execute(ctx, arguments, environment = {}, **kwargs): + """env_executes a command in a repository context. It prepends "env -i" + to "arguments" before calling "ctx.execute". + + Variables that aren't explicitly mentioned in "environment" + are removed from the environment. This should be preferred to "ctx.execut"e + in most situations. + """ + if ctx.os.name.startswith('windows'): + return ctx.execute(arguments, environment=environment, **kwargs) + env_args = ["env", "-i"] + environment = dict(environment) + for var in ["TMP", "TMPDIR"]: + if var in ctx.os.environ and not var in environment: + environment[var] = ctx.os.environ[var] + for k, v in environment.items(): + env_args.append("%s=%s" % (k, v)) + arguments = env_args + arguments + return ctx.execute(arguments, **kwargs) diff --git a/dotnet/private/context.bzl b/dotnet/private/context.bzl new file mode 100644 index 00000000000000..73c22059da9fa8 --- /dev/null +++ b/dotnet/private/context.bzl @@ -0,0 +1,153 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", + "DotnetResource", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "paths", +) + + +DotnetContext = provider() + +def _get_dotnet_runner(context_data, ext): + for f in context_data._mono_bin.files: + basename = paths.basename(f.path) + if basename != "mono" + ext: + continue + return f + fail("Could not find mono executable in dotnet_sdk (mono_bin)") + +def _get_dotnet_mcs(context_data): + for f in context_data._mcs_bin.files: + basename = paths.basename(f.path) + if basename != "mcs.exe": + continue + return f + + for f in context_data._lib.files: + basename = paths.basename(f.path) + if basename != "mcs.exe": + continue + return f + fail("Could not find mcs.exe in dotnet_sdk (mcs_bin, lib)") + +def _get_dotnet_resgen(context_data): + for f in context_data._mcs_bin.files: + basename = paths.basename(f.path) + if basename != "resgen.exe": + continue + return f + + for f in context_data._lib.files: + basename = paths.basename(f.path) + if basename != "resgen.exe": + continue + return f + + fail("Could not find resgen.exe in dotnet_sdk (mcs_bin, lib)") + +def _get_dotnet_stdlib(context_data): + for f in context_data._lib.files: + basename = paths.basename(f.path) + if basename != "mscorlib.dll": + continue + dirname = paths.dirname(f.path) + if dirname.find(context_data._libVersion)==-1: + continue + return f + fail("Could not find mscorlib in dotnet_sdk (lib, %s)" % context_data._libVersion) + +def _declare_file(dotnet, path = None, ext = None): + result = path if path else dotnet._ctx.label.name + if ext: + result += ext + return dotnet.actions.declare_file(result) + + +def _new_library(dotnet, name=None, deps=None, transitive=None, **kwargs): + return DotnetLibrary( + name = dotnet.label.name if not name else name, + label = dotnet.label, + deps = deps, + transitive = transitive, + **kwargs + ) + +def _new_resource(dotnet, name, result, identifier=None, **kwargs): + return DotnetResource( + name = name, + label = dotnet.label, + result = result, + identifier = result.basename if not identifier else identifier, + **kwargs + ) + +def dotnet_context(ctx, attr=None): + toolchain = ctx.toolchains["@io_bazel_rules_dotnet//dotnet:toolchain"] + + if not attr: + attr = ctx.attr + + context_data = attr._dotnet_context_data + ext = "" + if toolchain.default_dotnetos == "windows": + ext = ".exe" + runner = _get_dotnet_runner(context_data, ext) + mcs = _get_dotnet_mcs(context_data) + stdlib = _get_dotnet_stdlib(context_data) + resgen = _get_dotnet_resgen(context_data) + + return DotnetContext( + # Fields + label = ctx.label, + toolchain = toolchain, + actions = ctx.actions, + binary = toolchain.actions.binary, + library = toolchain.actions.library, + resx = toolchain.actions.resx, + exe_extension = ext, + runner = runner, + mcs = mcs, + stdlib = stdlib, + resgen = resgen, + declare_file = _declare_file, + new_library = _new_library, + new_resource = _new_resource, + workspace_name = ctx.workspace_name, + libVersion = context_data._libVersion, + lib = context_data._lib, + _ctx = ctx + ) + +def _dotnet_context_data(ctx): + return struct( + _mcs_bin = ctx.attr._mcs_bin, + _mono_bin = ctx.attr._mono_bin, + _lib = ctx.attr._lib, + _libVersion = ctx.attr._libVersion, + ) + +dotnet_context_data = rule( + _dotnet_context_data, + attrs = { + "_mcs_bin": attr.label( + allow_files = True, + default="@dotnet_sdk//:mcs_bin", + ), + "_mono_bin": attr.label( + allow_files = True, + default="@dotnet_sdk//:mono_bin", + ), + "_lib": attr.label( + allow_files = True, + default="@dotnet_sdk//:lib", + ), + "_libVersion": attr.string( + default="4.5", + ), + }, +) + diff --git a/dotnet/private/dotnet_toolchain.bzl b/dotnet/private/dotnet_toolchain.bzl new file mode 100644 index 00000000000000..031a89ac6b53ae --- /dev/null +++ b/dotnet/private/dotnet_toolchain.bzl @@ -0,0 +1,75 @@ +# Copyright 2016 The Bazel Go Rules Authors. All rights reserved. +# +# Licensed 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. +""" +Toolchain rules used by dotnet. +""" + +load("@io_bazel_rules_dotnet//dotnet/private:actions/binary.bzl", "emit_binary") +load("@io_bazel_rules_dotnet//dotnet/private:actions/library.bzl", "emit_library") +load("@io_bazel_rules_dotnet//dotnet/private:actions/resx.bzl", "emit_resx") + +def _dotnet_toolchain_impl(ctx): + return [platform_common.ToolchainInfo( + name = ctx.label.name, + default_dotnetimpl = ctx.attr.dotnetimpl, + default_dotnetos = ctx.attr.dotnetos, + default_dotnetarch = ctx.attr.dotnetarch, + actions = struct( + binary = emit_binary, + library = emit_library, + resx = emit_resx, + ), + flags = struct( + compile = (), + ), + )] + +_dotnet_toolchain = rule( + _dotnet_toolchain_impl, + attrs = { + # Minimum requirements to specify a toolchain + "dotnetimpl": attr.string(mandatory = True), + "dotnetos": attr.string(mandatory = True), + "dotnetarch": attr.string(mandatory = True), + }, +) + +def dotnet_toolchain(name, host, constraints=[], **kwargs): + """See dotnet/toolchains.rst#dotnet-toolchain for full documentation.""" + + elems = host.split("_") + impl, os, arch = elems[0], elems[1], elems[2] + host_constraints = constraints + [ + #"@io_bazel_rules_dotnet//dotnet/toolchain:" + impl, + "@io_bazel_rules_dotnet//dotnet/toolchain:" + os, + "@io_bazel_rules_dotnet//dotnet/toolchain:" + arch, + ] + + impl_name = name + "-impl" + _dotnet_toolchain( + name = impl_name, + dotnetimpl = impl, + dotnetos = os, + dotnetarch = arch, + tags = ["manual"], + visibility = ["//visibility:public"], + **kwargs + ) + native.toolchain( + name = name, + toolchain_type = "@io_bazel_rules_dotnet//dotnet:toolchain", + exec_compatible_with = host_constraints, + #target_compatible_with = host_constraints, + toolchain = ":"+impl_name, + ) diff --git a/dotnet/private/providers.bzl b/dotnet/private/providers.bzl new file mode 100644 index 00000000000000..37c8cf7b6e84ca --- /dev/null +++ b/dotnet/private/providers.bzl @@ -0,0 +1,12 @@ + +DotnetLibrary = provider() +""" +A represenatation of the dotnet binary. +See dotnet/providers.rst#DotnetLibrary for full documentation. +""" + +DotnetResource = provider() +""" +A represenatation of the dotnet compiled resource (.resources). +See dotnet/providers.rst#DotnetResource for full documentation. +""" diff --git a/dotnet/private/repositories.bzl b/dotnet/private/repositories.bzl new file mode 100644 index 00000000000000..a3f6387dfade1c --- /dev/null +++ b/dotnet/private/repositories.bzl @@ -0,0 +1,16 @@ +def dotnet_repositories(): + native.http_file( + name = "nuget", + url = "https://dist.nuget.org/win-x86-commandline/v4.6.2/nuget.exe", + sha256 = "2c562c1a18d720d4885546083ec8eaad6773a6b80befb02564088cc1e55b304e", + ) + + native.new_http_archive( + name = "nunit2", + url = "https://github.com/nunit/nunitv2/archive/2.6.4.zip", + sha256 = "2db7b4356e7cd9ac022c3f211853e39ae7b3587915124b555c7c39f712902c28", + strip_prefix = "nunitv2-2.6.4", + build_file = "@io_bazel_rules_dotnet//dotnet/externals:BUILD.nunit2", + ) + + diff --git a/dotnet/private/rules/binary.bzl b/dotnet/private/rules/binary.bzl new file mode 100644 index 00000000000000..f8055d50f664bd --- /dev/null +++ b/dotnet/private/rules/binary.bzl @@ -0,0 +1,65 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", + "DotnetResource", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/launcher_gen.bzl", + "dotnet_launcher_gen", +) + +def _dotnet_binary_impl(ctx): + """dotnet_binary_impl emits actions for compiling dotnet executable assembly.""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + + executable = dotnet.binary(dotnet, + name = name, + srcs = ctx.attr.srcs, + deps = ctx.attr.deps, + resources = ctx.attr.resources, + out = ctx.attr.out, + defines = ctx.attr.defines, + ) + + transitive_files = [d.result for d in executable.transitive.to_list()] + + return [ + DefaultInfo( + files = depset([executable.result]), + runfiles = ctx.runfiles(files = [dotnet.stdlib, dotnet.runner], transitive_files=depset(direct=transitive_files)), + executable = executable.result, + ), + ] + +_dotnet_binary = rule( + _dotnet_binary_impl, + attrs = { + "deps": attr.label_list(providers=[DotnetLibrary]), + "resources": attr.label_list(providers=[DotnetResource]), + "srcs": attr.label_list(allow_files = FileType([".cs"])), + "out": attr.string(), + "defines": attr.string_list(), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")), + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = True, +) + +def dotnet_binary(name, srcs, deps = [], defines = None, out = None): + _dotnet_binary(name = "%s_exe" % name, deps = deps, srcs = srcs, out = out, defines = defines) + exe = ":%s_exe" % name + dotnet_launcher_gen(name = "%s_launcher" % name, exe = exe) + + native.cc_binary( + name=name, + srcs = [":%s_launcher" % name], + deps = ["@io_bazel_rules_dotnet//dotnet/tools/runner", "@io_bazel_rules_dotnet//dotnet/tools/common"], + data = [exe], + ) \ No newline at end of file diff --git a/dotnet/private/rules/import.bzl b/dotnet/private/rules/import.bzl new file mode 100644 index 00000000000000..eaf2e87e52a550 --- /dev/null +++ b/dotnet/private/rules/import.bzl @@ -0,0 +1,54 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "sets" +) + + +def _dotnet_imort_library_impl(ctx): + """dotnet_import_library_impl emits actions for importing an external dll (for example provided by nuget).""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + + deps = ctx.attr.deps + src = ctx.attr.src + + deps_libraries = [d[DotnetLibrary] for d in deps] + transitive = sets.union(deps_libraries, *[a[DotnetLibrary].transitive for a in deps]) + + library = dotnet.new_library( + dotnet = dotnet, + name = name, + deps = deps, + transitive = transitive, + result = src.files.to_list()[0]) + + transitive_files = [d.result for d in library.transitive.to_list()] + + return [ + library, + DefaultInfo( + files = depset([library.result]), + runfiles = ctx.runfiles(files = [dotnet.stdlib, library.result], transitive_files=depset(direct=transitive_files)), + ), + ] + +dotnet_import_library = rule( + _dotnet_imort_library_impl, + attrs = { + "deps": attr.label_list(providers=[DotnetLibrary]), + "src": attr.label(allow_files = FileType([".dll"]), mandatory=True), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = False, +) \ No newline at end of file diff --git a/dotnet/private/rules/launcher_gen.bzl b/dotnet/private/rules/launcher_gen.bzl new file mode 100644 index 00000000000000..95f789a9adf0b0 --- /dev/null +++ b/dotnet/private/rules/launcher_gen.bzl @@ -0,0 +1,44 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", +) + +_TEMPLATE = """ +const char * Exe = "{}"; +const char * Nunit = "{}"; +""" + +def _dotnet_launcher_gen_impl(ctx): + """dotnet_launcher_gen_impl emits actions that generates .c file necessary to build launcher.""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + exe = ctx.attr.exe.files.to_list()[0] + nunit = "" + if ctx.attr.nunit: + nunit = ctx.attr.nunit.files.to_list()[0].path + + generated_file = dotnet.declare_file(dotnet, "{}_generated.c".format(name)) + content = _TEMPLATE.format(exe.path, nunit) + dotnet.actions.write(output = generated_file, content = content, is_executable=False) + + return [ + DefaultInfo( + files = depset([generated_file]), + ), + ] + +dotnet_launcher_gen = rule( + _dotnet_launcher_gen_impl, + attrs = { + "exe": attr.label(), + "nunit": attr.label(), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")), + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = False, +) diff --git a/dotnet/private/rules/library.bzl b/dotnet/private/rules/library.bzl new file mode 100644 index 00000000000000..10d4bcea32b68d --- /dev/null +++ b/dotnet/private/rules/library.bzl @@ -0,0 +1,50 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", + "DotnetResource", +) + + +def _dotnet_library_impl(ctx): + """dotnet_library_impl emits actions for compiling dotnet executable assembly.""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + + library = dotnet.library(dotnet, + name = name, + srcs = ctx.attr.srcs, + deps = ctx.attr.deps, + resources = ctx.attr.resources, + out = ctx.attr.out, + defines = ctx.attr.defines, + + ) + + transitive_files = [d.result for d in library.transitive.to_list()] + + return [ + library, + DefaultInfo( + files = depset([library.result]), + runfiles = ctx.runfiles(files = [dotnet.stdlib, library.result], transitive_files=depset(direct=transitive_files)), + ), + ] + +dotnet_library = rule( + _dotnet_library_impl, + attrs = { + "deps": attr.label_list(providers=[DotnetLibrary]), + "resources": attr.label_list(providers=[DotnetResource]), + "srcs": attr.label_list(allow_files = FileType([".cs"])), + "out": attr.string(), + "defines": attr.string_list(), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = False, +) \ No newline at end of file diff --git a/dotnet/private/rules/nuget.bzl b/dotnet/private/rules/nuget.bzl new file mode 100644 index 00000000000000..06d7cfe4583ab6 --- /dev/null +++ b/dotnet/private/rules/nuget.bzl @@ -0,0 +1,74 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "paths", +) + + +def _dotnet_nuget_impl(ctx, + build_file = None, + build_file_content = None): + """dotnet_nuget_impl emits actions for exposing nunit assmebly.""" + + package = ctx.attr.package + output_dir = ctx.path("") + + url = ctx.attr.source + "/" + ctx.attr.package + "/" + ctx.attr.version + ctx.download_and_extract(url, output_dir, ctx.attr.sha256, type="zip") + + if build_file_content: + ctx.file("BUILD", build_file_content) + elif build_file: + ctx.symlink(ctx.path(build_file), "BUILD") + else: + ctx.template("BUILD.bazel", + Label("@io_bazel_rules_dotnet//dotnet/private:BUILD.nuget.bazel"), + executable = False, + ) + + +dotnet_nuget = repository_rule( + _dotnet_nuget_impl, + attrs = { + # Sources to download the nuget packages from + "source":attr.string(default = "https://www.nuget.org/api/v2/package"), + # The name of the nuget package + "package":attr.string(mandatory=True), + # The version of the nuget package + "version":attr.string(mandatory=True), + "sha256":attr.string(mandatory=True), + }, +) + +def _dotnet_nuget_new_impl(repository_ctx): + build_file = repository_ctx.attr.build_file + build_file_content = repository_ctx.attr.build_file_content + if not (build_file_content or build_file): + fail("build_file or build_file_content is required") + _dotnet_nuget_impl(repository_ctx, build_file, build_file_content) + +dotnet_nuget_new = repository_rule( + _dotnet_nuget_new_impl, + attrs = { + # Sources to download the nuget packages from + "source":attr.string(default = "https://www.nuget.org/api/v2/package"), + # The name of the nuget package + "package":attr.string(mandatory=True), + # The version of the nuget package + "version":attr.string(mandatory=True), + "sha256":attr.string(mandatory=True), + "build_file": attr.label( + allow_files = True, + ), + "build_file_content": attr.string(), + }, +) \ No newline at end of file diff --git a/dotnet/private/rules/resx.bzl b/dotnet/private/rules/resx.bzl new file mode 100644 index 00000000000000..759f26a87b6fd1 --- /dev/null +++ b/dotnet/private/rules/resx.bzl @@ -0,0 +1,35 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +def _dotnet_resx_impl(ctx): + """dotnet_resx_impl emits actions for compiling resx to resource.""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + + resource = dotnet.resx(dotnet, + name = name, + src = ctx.attr.src, + identifier = ctx.attr.identifier, + out = ctx.attr.out, + ) + return [ + resource, + DefaultInfo( + files = depset([resource.result]), + ), + ] + +dotnet_resx = rule( + _dotnet_resx_impl, + attrs = { + # source files for this target. + "src": attr.label(allow_files = FileType([".resx"]), mandatory=True), + "identifier": attr.string(), + "out": attr.string(), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = False, +) \ No newline at end of file diff --git a/dotnet/private/rules/stdlib.bzl b/dotnet/private/rules/stdlib.bzl new file mode 100644 index 00000000000000..55357cc2018e2a --- /dev/null +++ b/dotnet/private/rules/stdlib.bzl @@ -0,0 +1,52 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:common.bzl", + "paths", +) + +def _get_dotnet_stdlib_byname(lib, libVersion, name): + lname = name.lower() + for f in lib.files: + basename = paths.basename(f.path) + if basename.lower() != lname: + continue + dirname = paths.dirname(f.path) + if dirname.find(libVersion)==-1: + continue + return f + fail("Could not find %s in dotnet_sdk (lib)" % name) + + +# TODO(tomek) we don't need special treatment for mscorlib.dll +def _dotnet_stdlib_impl(ctx): + """dotnet_stdlib_impl emits the assembly from @dotnet_sdk//:lib.""" + dotnet = dotnet_context(ctx) + name = ctx.label.name + result = _get_dotnet_stdlib_byname(dotnet.lib, dotnet.libVersion, name) + + library = dotnet.new_library( + dotnet = dotnet, + name = name, + deps = None, + transitive = depset([]), + result = result) + + return [ + library, + DefaultInfo( + files = depset([library.result]), + ), + ] + +dotnet_stdlib = rule( + _dotnet_stdlib_impl, + attrs = { + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + executable = False, +) \ No newline at end of file diff --git a/dotnet/private/rules/test.bzl b/dotnet/private/rules/test.bzl new file mode 100644 index 00000000000000..e971099ff4c3c0 --- /dev/null +++ b/dotnet/private/rules/test.bzl @@ -0,0 +1,34 @@ +load( + "@io_bazel_rules_dotnet//dotnet/private:context.bzl", + "dotnet_context", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:providers.bzl", + "DotnetLibrary", + "DotnetResource", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/launcher_gen.bzl", + "dotnet_launcher_gen", +) + +load( + "@io_bazel_rules_dotnet//dotnet/private:rules/library.bzl", + "dotnet_library", +) + + +def dotnet_nunit_test(name, deps, srcs, data = [], defines = None, out = None, **kwargs): + dotnet_library(name = "%s_exe" % name, deps = deps, srcs = srcs, out = out, defines = defines) + exe = ":%s_exe" % name + dotnet_launcher_gen(name = "%s_launcher" % name, exe = exe, nunit="@nunit2//:nunit-console-runner-exe_exe") + + native.cc_test( + name=name, + srcs = [":%s_launcher" % name], + deps = ["@io_bazel_rules_dotnet//dotnet/tools/runner", "@io_bazel_rules_dotnet//dotnet/tools/common"], + data = [exe, "@nunit2//:nunit-console-runner-exe_exe"] + data, + **kwargs + ) \ No newline at end of file diff --git a/dotnet/private/sdk.bzl b/dotnet/private/sdk.bzl new file mode 100644 index 00000000000000..25b1dad071e3bb --- /dev/null +++ b/dotnet/private/sdk.bzl @@ -0,0 +1,144 @@ +load("@io_bazel_rules_dotnet//dotnet/private:common.bzl", "executable_extension", "bat_extension", "paths") + +# Mono for linux, windows and macos layouts fies differentely +# So we provide an implementation for each host +def _dotnet_host_sdk_impl_windows(ctx): + mono, mcs = _detect_host_sdk(ctx) + _sdk_build_file(ctx) + bin = ctx.path(mcs).dirname + ctx.symlink(bin, "mcs_bin") + bin = ctx.path(mono).dirname + ctx.symlink(bin, "mono_bin") + lib = paths.join("{}".format(ctx.path(mcs).dirname), "../lib") + ctx.symlink(lib, "lib") + + +# Mono launcher is on Linux usually placed in /usr/bin. Since the directory +# may contain forbidden file names ('[') we cannot link it in dotnet_sdk +# Instead we create a directory (named mono_bin) and put link to mono in it +def _dotnet_host_sdk_impl_linux(ctx): + mono, mcs = _detect_host_sdk(ctx) + _sdk_build_file(ctx) + ctx.file("mono_bin/README.md", + "Directory to hold link to mono executable", + False + ) + ctx.symlink(mono, "mono_bin/mono") + monoroot = ctx.path("/usr/lib/mono/") + if not monoroot.exists: + fail("Can't find mono in /usr/lib/mono/") + ctx.symlink(monoroot, "lib") + bin = paths.join("{}".format(monoroot), "4.5") + ctx.symlink(bin, "mcs_bin") + +def _dotnet_host_sdk_impl_osx(ctx): + mono, mcs = _detect_host_sdk(ctx) + _sdk_build_file(ctx) + ctx.file("mono_bin/README.md", + "Directory to hold link to mono executable", + False + ) + ctx.symlink(mono, "mono_bin/mono") + monoroot = ctx.path("/usr/local/Cellar/mono/5.4.1.6/lib/mono") + if not monoroot.exists: + current = ctx.path(mono).dirname + monodir = paths.join("{}".format(current), "..", "lib", "mono") + monoroot = ctx.path(monodir) + if not monoroot.exists: + fail("Can't find mono in /usr/local/Cellar/mono/5.4.1.6/lib/mono") + ctx.symlink(monoroot, "lib") + bin = paths.join("{}".format(monoroot), "4.5") + ctx.symlink(bin, "mcs_bin") + +def _dotnet_host_sdk_impl(ctx): + if ctx.os.name == 'linux': + _dotnet_host_sdk_impl_linux(ctx) + elif ctx.os.name == 'mac os x': + _dotnet_host_sdk_impl_osx(ctx) + elif ctx.os.name.startswith('windows'): + _dotnet_host_sdk_impl_windows(ctx) + + +dotnet_host_sdk = repository_rule( + implementation = _dotnet_host_sdk_impl, + local=True, +) + +def _dotnet_download_sdk_impl(ctx): + if ctx.os.name == 'linux': + host = "mono_linux_amd64" + elif ctx.os.name == 'mac os x': + host = "mono_darwin_amd64" + elif ctx.os.name.startswith('windows'): + host = "mono_windows_amd64" + else: + fail("Unsupported operating system: " + ctx.os.name) + sdks = ctx.attr.sdks + if host not in sdks: fail("Unsupported host {}".format(host)) + filename, sha256 = ctx.attr.sdks[host] + _sdk_build_file(ctx) + _remote_sdk(ctx, [filename], ctx.attr.strip_prefix, sha256) + ctx.symlink("mono/lib/mono/4.5", "mcs_bin") + ctx.symlink("mono/bin", "mono_bin") + ctx.symlink("mono/lib/mono", "lib") + + +dotnet_download_sdk = repository_rule( + _dotnet_download_sdk_impl, + attrs = { + "sdks": attr.string_list_dict(), + "urls": attr.string_list(), + "strip_prefix": attr.string(default = ""), + }, +) + +def _dotnet_local_sdk_impl(ctx): + _sdk_build_file(ctx) + bin = paths.join(ctx.attr.path, "/bin") + ctx.symlink(bin, "bin") + lib = paths.join(ctx.attr.path, "/lib") + ctx.symlink(lib, "lib") + +dotnet_local_sdk = repository_rule( + _dotnet_local_sdk_impl, + attrs = { + "path": attr.string(), + }, +) + +"""See /dotnet/toolchains.rst#dotnet-sdk for full documentation.""" + +def _remote_sdk(ctx, urls, strip_prefix, sha256): + ctx.download_and_extract( + url = urls, + stripPrefix = strip_prefix, + sha256 = sha256, + ) + +def _sdk_build_file(ctx): + ctx.file("ROOT") + ctx.template("BUILD.bazel", + Label("@io_bazel_rules_dotnet//dotnet/private:BUILD.sdk.bazel"), + executable = False, + ) + + +def _detect_host_sdk(ctx): + mcs = ctx.which("mcs" + bat_extension(ctx)) + if not mcs: + defmono = ctx.path("c:/program files/mono/bin") + if defmono.exists: + mcs = ctx.path("c:/program files/mono/bin/mcs") + else: + fail("Failed to find mcs") + + mono = ctx.which("mono" + executable_extension(ctx)) + if not mono: + defmono = ctx.path("c:/program files/mono/bin") + if defmono.exists: + mono = ctx.path("c:/program files/mono/bin/mono.exe") + else: + fail("Failed to find mono") + + return (mono, mcs) + diff --git a/dotnet/private/skylib/README.rst b/dotnet/private/skylib/README.rst new file mode 100644 index 00000000000000..65aa2f22f692b8 --- /dev/null +++ b/dotnet/private/skylib/README.rst @@ -0,0 +1,7 @@ +This directory is a copy of github.com/bazelbuild/bazel-skylib/lib. +Commit 2169ae1, retrieved on 2018-01-12 + +This is needed only until nested workspaces works. +It has to be copied in because we use the functionality inside code that +go_rules_dependencies itself depends on, which means we cannot automatically +add the skylib dependency. diff --git a/dotnet/private/skylib/lib/collections.bzl b/dotnet/private/skylib/lib/collections.bzl new file mode 100644 index 00000000000000..c86842b3e76c90 --- /dev/null +++ b/dotnet/private/skylib/lib/collections.bzl @@ -0,0 +1,70 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing functions that operate on collections.""" + + +def _after_each(separator, iterable): + """Inserts `separator` after each item in `iterable`. + + Args: + separator: The value to insert after each item in `iterable`. + iterable: The list into which to intersperse the separator. + Returns: + A new list with `separator` after each item in `iterable`. + """ + result = [] + for x in iterable: + result.append(x) + result.append(separator) + + return result + + +def _before_each(separator, iterable): + """Inserts `separator` before each item in `iterable`. + + Args: + separator: The value to insert before each item in `iterable`. + iterable: The list into which to intersperse the separator. + Returns: + A new list with `separator` before each item in `iterable`. + """ + result = [] + for x in iterable: + result.append(separator) + result.append(x) + + return result + + +def _uniq(iterable): + """Returns a list of unique elements in `iterable`. + + Requires all the elements to be hashable. + + Args: + iterable: An iterable to filter. + Returns: + A new list with all unique elements from `iterable`. + """ + unique_elements = {element: None for element in iterable} + return unique_elements.keys() + + +collections = struct( + after_each=_after_each, + before_each=_before_each, + uniq=_uniq, +) diff --git a/dotnet/private/skylib/lib/dicts.bzl b/dotnet/private/skylib/lib/dicts.bzl new file mode 100644 index 00000000000000..ee1076cb016d41 --- /dev/null +++ b/dotnet/private/skylib/lib/dicts.bzl @@ -0,0 +1,42 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing functions that operate on dictionaries.""" + + +def _add(*dictionaries): + """Returns a new `dict` that has all the entries of the given dictionaries. + + If the same key is present in more than one of the input dictionaries, the + last of them in the argument list overrides any earlier ones. + + This function is designed to take zero or one arguments as well as multiple + dictionaries, so that it follows arithmetic identities and callers can avoid + special cases for their inputs: the sum of zero dictionaries is the empty + dictionary, and the sum of a single dictionary is a copy of itself. + + Args: + *dictionaries: Zero or more dictionaries to be added. + Returns: + A new `dict` that has all the entries of the given dictionaries. + """ + result = {} + for d in dictionaries: + result.update(d) + return result + + +dicts = struct( + add=_add, +) diff --git a/dotnet/private/skylib/lib/paths.bzl b/dotnet/private/skylib/lib/paths.bzl new file mode 100644 index 00000000000000..378fa4537939c0 --- /dev/null +++ b/dotnet/private/skylib/lib/paths.bzl @@ -0,0 +1,245 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing file path manipulation functions. + +NOTE: The functions in this module currently only support paths with Unix-style +path separators (forward slash, "/"); they do not handle Windows-style paths +with backslash separators or drive letters. +""" + + +def _basename(p): + """Returns the basename (i.e., the file portion) of a path. + + Note that if `p` ends with a slash, this function returns an empty string. + This matches the behavior of Python's `os.path.basename`, but differs from + the Unix `basename` command (which would return the path segment preceding + the final slash). + + Args: + p: The path whose basename should be returned. + Returns: + The basename of the path, which includes the extension. + """ + return p.rpartition("/")[-1] + + +def _dirname(p): + """Returns the dirname of a path. + + The dirname is the portion of `p` up to but not including the file portion + (i.e., the basename). Any slashes immediately preceding the basename are not + included, unless omitting them would make the dirname empty. + + Args: + p: The path whose dirname should be returned. + Returns: + The dirname of the path. + """ + prefix, sep, _ = p.rpartition("/") + if not prefix: + return sep + else: + # If there are multiple consecutive slashes, strip them all out as Python's + # os.path.dirname does. + return prefix.rstrip("/") + + +def _is_absolute(path): + """Returns `True` if `path` is an absolute path. + + Args: + path: A path (which is a string). + Returns: + `True` if `path` is an absolute path. + """ + return path.startswith("/") or path[1] == ":" + + +def _join(path, *others): + """Joins one or more path components intelligently. + + This function mimics the behavior of Python's `os.path.join` function on POSIX + platform. It returns the concatenation of `path` and any members of `others`, + inserting directory separators before each component except the first. The + separator is not inserted if the path up until that point is either empty or + already ends in a separator. + + If any component is an absolute path, all previous components are discarded. + + Args: + path: A path segment. + *others: Additional path segments. + Returns: + A string containing the joined paths. + """ + result = path + + for p in others: + if _is_absolute(p): + result = p + elif not result or result.endswith("/"): + result += p + else: + result += "/" + p + + return result + + +def _normalize(path): + """Normalizes a path, eliminating double slashes and other redundant segments. + + This function mimics the behavior of Python's `os.path.normpath` function on + POSIX platforms; specifically: + + - If the entire path is empty, "." is returned. + - All "." segments are removed, unless the path consists solely of a single + "." segment. + - Trailing slashes are removed, unless the path consists solely of slashes. + - ".." segments are removed as long as there are corresponding segments + earlier in the path to remove; otherwise, they are retained as leading ".." + segments. + - Single and double leading slashes are preserved, but three or more leading + slashes are collapsed into a single leading slash. + - Multiple adjacent internal slashes are collapsed into a single slash. + + Args: + path: A path. + Returns: + The normalized path. + """ + if not path: + return "." + + if path.startswith("//") and not path.startswith("///"): + initial_slashes = 2 + elif path.startswith("/"): + initial_slashes = 1 + else: + initial_slashes = 0 + is_relative = (initial_slashes == 0) + + components = path.split("/") + new_components = [] + + for component in components: + if component in ("", "."): + continue + if component == "..": + if new_components and new_components[-1] != "..": + # Only pop the last segment if it isn't another "..". + new_components.pop() + elif is_relative: + # Preserve leading ".." segments for relative paths. + new_components.append(component) + else: + new_components.append(component) + + path = "/".join(new_components) + if not is_relative: + path = ("/" * initial_slashes) + path + + return path or "." + + +def _relativize(path, start): + """Returns the portion of `path` that is relative to `start`. + + Because we do not have access to the underlying file system, this + implementation differs slightly from Python's `os.path.relpath` in that it + will fail if `path` is not beneath `start` (rather than use parent segments to + walk up to the common file system root). + + Relativizing paths that start with parent directory references is not allowed. + + Args: + path: The path to relativize. + start: The ancestor path against which to relativize. + Returns: + The portion of `path` that is relative to `start`. + """ + segments = _normalize(path).split("/") + start_segments = _normalize(start).split("/") + if start_segments == ["."]: + start_segments = [] + start_length = len(start_segments) + + if (path.startswith("..") or start.startswith("..")): + fail("Cannot relativize paths above the current (unknown) directory") + + if (path.startswith("/") != start.startswith("/") or + len(segments) < start_length): + fail("Path '%s' is not beneath '%s'" % (path, start)) + + for ancestor_segment, segment in zip(start_segments, segments): + if ancestor_segment != segment: + fail("Path '%s' is not beneath '%s'" % (path, start)) + + length = len(segments) - start_length + result_segments = segments[-length:] + return "/".join(result_segments) + + +def _replace_extension(p, new_extension): + """Replaces the extension of the file at the end of a path. + + If the path has no extension, the new extension is added to it. + + Args: + p: The path whose extension should be replaced. + new_extension: The new extension for the file. The new extension should + begin with a dot if you want the new filename to have one. + Returns: + The path with the extension replaced (or added, if it did not have one). + """ + return _split_extension(p)[0] + new_extension + + +def _split_extension(p): + """Splits the path `p` into a tuple containing the root and extension. + + Leading periods on the basename are ignored, so + `path.split_extension(".bashrc")` returns `(".bashrc", "")`. + + Args: + p: The path whose root and extension should be split. + Returns: + A tuple `(root, ext)` such that the root is the path without the file + extension, and `ext` is the file extension (which, if non-empty, contains + the leading dot). The returned tuple always satisfies the relationship + `root + ext == p`. + """ + b = _basename(p) + last_dot_in_basename = b.rfind(".") + + # If there is no dot or the only dot in the basename is at the front, then + # there is no extension. + if last_dot_in_basename <= 0: + return (p, "") + + dot_distance_from_end = len(b) - last_dot_in_basename + return (p[:-dot_distance_from_end], p[-dot_distance_from_end:]) + + +paths = struct( + basename=_basename, + dirname=_dirname, + is_absolute=_is_absolute, + join=_join, + normalize=_normalize, + relativize=_relativize, + replace_extension=_replace_extension, + split_extension=_split_extension, +) diff --git a/dotnet/private/skylib/lib/selects.bzl b/dotnet/private/skylib/lib/selects.bzl new file mode 100644 index 00000000000000..daf15c7aa43116 --- /dev/null +++ b/dotnet/private/skylib/lib/selects.bzl @@ -0,0 +1,83 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing convenience interfaces for select().""" + +def _with_or(input_dict): + """Drop-in replacement for `select()` that supports ORed keys. + + Args: + input_dict: The same dictionary `select()` takes, except keys may take + either the usual form `"//foo:config1"` or + `("//foo:config1", "//foo:config2", ...)` to signify + `//foo:config1` OR `//foo:config2` OR `...`. + + Example: + + ```build + deps = selects.with_or({ + "//configs:one": [":dep1"], + ("//configs:two", "//configs:three"): [":dep2or3"], + "//configs:four": [":dep4"], + "//conditions:default": [":default"] + }) + ``` + + Key labels may appear at most once anywhere in the input. + + Returns: + A native `select()` that expands + + `("//configs:two", "//configs:three"): [":dep2or3"]` + + to + + ```build + "//configs:two": [":dep2or3"], + "//configs:three": [":dep2or3"], + ``` + """ + return select(_with_or_dict(input_dict)) + + +def _with_or_dict(input_dict): + """Variation of `with_or` that returns the dict of the `select()`. + + Unlike `select()`, the contents of the dict can be inspected by Skylark + macros. + + Args: + input_dict: Same as `with_or`. + + Returns: + A dictionary usable by a native `select()`. + """ + output_dict = {} + for (key, value) in input_dict.items(): + if type(key) == type(()): + for config_setting in key: + if config_setting in output_dict.keys(): + fail("key %s appears multiple times" % config_setting) + output_dict[config_setting] = value + else: + if key in output_dict.keys(): + fail("key %s appears multiple times" % config_setting) + output_dict[key] = value + return output_dict + + +selects = struct( + with_or=_with_or, + with_or_dict=_with_or_dict +) diff --git a/dotnet/private/skylib/lib/sets.bzl b/dotnet/private/skylib/lib/sets.bzl new file mode 100644 index 00000000000000..edaf8275c30256 --- /dev/null +++ b/dotnet/private/skylib/lib/sets.bzl @@ -0,0 +1,145 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing common set algorithms. + +CAUTION: Operating on sets, particularly sets contained in providers, may +asymptotically slow down the analysis phase. While constructing large sets with +addition/union is fast (there is no linear-time copy involved), the +`difference` function and various comparison predicates involve linear-time +traversals. + +For convenience, the functions in this module can take either sets or lists as +inputs; operations that take lists treat them as if they were sets (i.e., +duplicate elements are ignored). Functions that return new sets always return +them as the `set` type, regardless of the types of the inputs. +""" + + +def _precondition_only_sets_or_lists(*args): + """Verifies that all arguments are either sets or lists. + + The build will fail if any of the arguments is neither a set nor a list. + + Args: + *args: A list of values that must be sets or lists. + """ + for a in args: + t = type(a) + if t not in("depset", "list"): + fail("Expected arguments to be depset or list, but found type %s: %r" % + (t, a)) + + +def _is_equal(a, b): + """Returns whether two sets are equal. + + Args: + a: A depset or a list. + b: A depset or a list. + Returns: + True if `a` is equal to `b`, False otherwise. + """ + _precondition_only_sets_or_lists(a, b) + return sorted(depset(a)) == sorted(depset(b)) + + +def _is_subset(a, b): + """Returns whether `a` is a subset of `b`. + + Args: + a: A depset or a list. + b: A depset or a list. + + Returns: + True if `a` is a subset of `b`, False otherwise. + """ + _precondition_only_sets_or_lists(a, b) + for e in a: + if e not in b: + return False + return True + + +def _disjoint(a, b): + """Returns whether two sets are disjoint. + + Two sets are disjoint if they have no elements in common. + + Args: + a: A set or list. + b: A set or list. + + Returns: + True if `a` and `b` are disjoint, False otherwise. + """ + _precondition_only_sets_or_lists(a, b) + for e in a: + if e in b: + return False + return True + + +def _intersection(a, b): + """Returns the intersection of two sets. + + Args: + a: A set or list. + b: A set or list. + + Returns: + A set containing the elements that are in both `a` and `b`. + """ + _precondition_only_sets_or_lists(a, b) + return depset([e for e in a if e in b]) + + +def _union(*args): + """Returns the union of several sets. + + Args: + *args: An arbitrary number of sets or lists. + + Returns: + The set union of all sets or lists in `*args`. + """ + _precondition_only_sets_or_lists(*args) + r = depset() + for a in args: + r += a + return r + + +def _difference(a, b): + """Returns the elements in `a` that are not in `b`. + + Args: + a: A set or list. + b: A set or list. + + Returns: + A set containing the elements that are in `a` but not in `b`. + """ + _precondition_only_sets_or_lists(a, b) + return depset([e for e in a if e not in b]) + + +sets = struct( + difference = _difference, + disjoint = _disjoint, + intersection = _intersection, + is_equal = _is_equal, + is_subset = _is_subset, + union = _union, +) diff --git a/dotnet/private/skylib/lib/shell.bzl b/dotnet/private/skylib/lib/shell.bzl new file mode 100644 index 00000000000000..4173fe7ba851cc --- /dev/null +++ b/dotnet/private/skylib/lib/shell.bzl @@ -0,0 +1,55 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing shell utility functions.""" + + +def _array_literal(iterable): + """Creates a string from a sequence that can be used as a shell array. + + For example, `shell.array_literal(["a", "b", "c"])` would return the string + `("a" "b" "c")`, which can be used in a shell script wherever an array + literal is needed. + + Note that all elements in the array are quoted (using `shell.quote`) for + safety, even if they do not need to be. + + Args: + iterable: A sequence of elements. Elements that are not strings will be + converted to strings first, by calling `str()`. + Returns: + A string that represents the sequence as a shell array; that is, + parentheses containing the quoted elements. + """ + return "(" + " ".join([_quote(str(i)) for i in iterable]) + ")" + + +def _quote(s): + """Quotes the given string for use in a shell command. + + This function quotes the given string (in case it contains spaces or other + shell metacharacters.) + + Args: + s: The string to quote. + Returns: + A quoted version of the string that can be passed to a shell command. + """ + return "'" + s.replace("'", "'\\''") + "'" + + +shell = struct( + array_literal=_array_literal, + quote=_quote, +) diff --git a/dotnet/private/skylib/lib/structs.bzl b/dotnet/private/skylib/lib/structs.bzl new file mode 100644 index 00000000000000..78715cca9f1067 --- /dev/null +++ b/dotnet/private/skylib/lib/structs.bzl @@ -0,0 +1,36 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing functions that operate on structs.""" + + +def _to_dict(s): + """Converts a `struct` to a `dict`. + + Args: + s: A `struct`. + Returns: + A `dict` whose keys and values are the same as the fields in `s`. The + transformation is only applied to the struct's fields and not to any + nested values. + """ + attributes = dir(s) + attributes.remove("to_json") + attributes.remove("to_proto") + return {key: getattr(s, key) for key in attributes} + + +structs = struct( + to_dict=_to_dict, +) diff --git a/dotnet/private/skylib/lib/unittest.bzl b/dotnet/private/skylib/lib/unittest.bzl new file mode 100644 index 00000000000000..f1208a3cf48723 --- /dev/null +++ b/dotnet/private/skylib/lib/unittest.bzl @@ -0,0 +1,270 @@ +# Copyright 2017 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Unit testing support. + +Unlike most Skylib files, this exports two modules: `unittest` which contains +functions to declare and define unit tests, and `asserts` which contains the +assertions used to within tests. +""" + +load(":sets.bzl", "sets") + + +def _make(impl, attrs=None): + """Creates a unit test rule from its implementation function. + + Each unit test is defined in an implementation function that must then be + associated with a rule so that a target can be built. This function handles + the boilerplate to create and return a test rule and captures the + implementation function's name so that it can be printed in test feedback. + + The optional `attrs` argument can be used to define dependencies for this + test, in order to form unit tests of rules. + + An example of a unit test: + + ``` + def _your_test(ctx): + env = unittest.begin(ctx) + + # Assert statements go here + + unittest.end(env) + + your_test = unittest.make(_your_test) + ``` + + Recall that names of test rules must end in `_test`. + + Args: + impl: The implementation function of the unit test. + attrs: An optional dictionary to supplement the attrs passed to the + unit test's `rule()` constructor. + Returns: + A rule definition that should be stored in a global whose name ends in + `_test`. + """ + + # Derive the name of the implementation function for better test feedback. + # Skylark currently stringifies a function as "<function NAME>", so we use + # that knowledge to parse the "NAME" portion out. If this behavior ever + # changes, we'll need to update this. + # TODO(bazel-team): Expose a ._name field on functions to avoid this. + impl_name = str(impl) + impl_name = impl_name.partition("<function ")[-1] + impl_name = impl_name.rpartition(">")[0] + + attrs = dict(attrs) if attrs else {} + attrs["_impl_name"] = attr.string(default=impl_name) + + return rule( + impl, + attrs=attrs, + _skylark_testable=True, + test=True, + ) + + +def _suite(name, *test_rules): + """Defines a `test_suite` target that contains multiple tests. + + After defining your test rules in a `.bzl` file, you need to create targets + from those rules so that `blaze test` can execute them. Doing this manually + in a BUILD file would consist of listing each test in your `load` statement + and then creating each target one by one. To reduce duplication, we recommend + writing a macro in your `.bzl` file to instantiate all targets, and calling + that macro from your BUILD file so you only have to load one symbol. + + For the case where your unit tests do not take any (non-default) attributes -- + i.e., if your unit tests do not test rules -- you can use this function to + create the targets and wrap them in a single test_suite target. In your + `.bzl` file, write: + + ``` + def your_test_suite(): + unittest.suite( + "your_test_suite", + your_test, + your_other_test, + yet_another_test, + ) + ``` + + Then, in your `BUILD` file, simply load the macro and invoke it to have all + of the targets created: + + ``` + load("//path/to/your/package:tests.bzl", "your_test_suite") + your_test_suite() + ``` + + If you pass _N_ unit test rules to `unittest.suite`, _N_ + 1 targets will be + created: a `test_suite` target named `${name}` (where `${name}` is the name + argument passed in here) and targets named `${name}_test_${i}`, where `${i}` + is the index of the test in the `test_rules` list, which is used to uniquely + name each target. + + Args: + name: The name of the `test_suite` target, and the prefix of all the test + target names. + *test_rules: A list of test rules defines by `unittest.test`. + """ + test_names = [] + for index, test_rule in enumerate(test_rules): + test_name = "%s_test_%d" % (name, index) + test_rule(name=test_name) + test_names.append(test_name) + + native.test_suite( + name=name, + tests=[":%s" % t for t in test_names] + ) + + +def _begin(ctx): + """Begins a unit test. + + This should be the first function called in a unit test implementation + function. It initializes a "test environment" that is used to collect + assertion failures so that they can be reported and logged at the end of the + test. + + Args: + ctx: The Skylark context. Pass the implementation function's `ctx` argument + in verbatim. + Returns: + A test environment struct that must be passed to assertions and finally to + `unittest.end`. Do not rely on internal details about the fields in this + struct as it may change. + """ + return struct(ctx=ctx, failures=[]) + + +def _end(env): + """Ends a unit test and logs the results. + + This must be called before the end of a unit test implementation function so + that the results are reported. + + Args: + env: The test environment returned by `unittest.begin`. + """ + cmd = "\n".join([ + "cat << EOF", + "\n".join(env.failures), + "EOF", + "exit %d" % len(env.failures), + ]) + env.ctx.file_action( + output=env.ctx.outputs.executable, + content=cmd, + executable=True, + ) + + +def _fail(env, msg): + """Unconditionally causes the current test to fail. + + Args: + env: The test environment returned by `unittest.begin`. + msg: The message to log describing the failure. + """ + full_msg = "In test %s: %s" % (env.ctx.attr._impl_name, msg) + print(full_msg) + env.failures.append(full_msg) + + +def _assert_true(env, + condition, + msg="Expected condition to be true, but was false."): + """Asserts that the given `condition` is true. + + Args: + env: The test environment returned by `unittest.begin`. + condition: A value that will be evaluated in a Boolean context. + msg: An optional message that will be printed that describes the failure. + If omitted, a default will be used. + """ + if not condition: + _fail(env, msg) + + +def _assert_false(env, + condition, + msg="Expected condition to be false, but was true."): + """Asserts that the given `condition` is false. + + Args: + env: The test environment returned by `unittest.begin`. + condition: A value that will be evaluated in a Boolean context. + msg: An optional message that will be printed that describes the failure. + If omitted, a default will be used. + """ + if condition: + _fail(env, msg) + + +def _assert_equals(env, expected, actual, msg=None): + """Asserts that the given `expected` and `actual` values are equal. + + Args: + env: The test environment returned by `unittest.begin`. + expected: The expected value of some computation. + actual: The actual value returned by some computation. + msg: An optional message that will be printed that describes the failure. + If omitted, a default will be used. + """ + if expected != actual: + expectation_msg = 'Expected "%s", but got "%s"' % (expected, actual) + if msg: + full_msg = "%s (%s)" % (msg, expectation_msg) + else: + full_msg = expectation_msg + _fail(env, full_msg) + + +def _assert_set_equals(env, expected, actual, msg=None): + """Asserts that the given `expected` and `actual` sets are equal. + + Args: + env: The test environment returned by `unittest.begin`. + expected: The expected set resulting from some computation. + actual: The actual set returned by some computation. + msg: An optional message that will be printed that describes the failure. + If omitted, a default will be used. + """ + if type(actual) != type(depset()) or not sets.is_equal(expected, actual): + expectation_msg = "Expected %r, but got %r" % (expected, actual) + if msg: + full_msg = "%s (%s)" % (msg, expectation_msg) + else: + full_msg = expectation_msg + _fail(env, full_msg) + + +asserts = struct( + equals=_assert_equals, + false=_assert_false, + set_equals=_assert_set_equals, + true=_assert_true, +) + +unittest = struct( + make=_make, + suite=_suite, + begin=_begin, + end=_end, + fail=_fail, +) diff --git a/dotnet/private/skylib/lib/versions.bzl b/dotnet/private/skylib/lib/versions.bzl new file mode 100644 index 00000000000000..d77b2ed6063b48 --- /dev/null +++ b/dotnet/private/skylib/lib/versions.bzl @@ -0,0 +1,126 @@ +# Copyright 2018 The Bazel Authors. All rights reserved. +# +# Licensed 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. + +"""Skylib module containing functions for checking Bazel versions.""" + +def _get_bazel_version(): + """Returns the current Bazel version""" + + return native.bazel_version + + +def _extract_version_number(bazel_version): + """Extracts the semantic version number from a version string + + Args: + bazel_version: the version string that begins with the semantic version + e.g. "1.2.3rc1 abc1234" where "abc1234" is a commit hash. + + Returns: + The semantic version string, like "1.2.3". + """ + for i in range(len(bazel_version)): + c = bazel_version[i] + if not (c.isdigit() or c == "."): + return bazel_version[:i] + return bazel_version + +# Parse the bazel version string from `native.bazel_version`. +# e.g. +# "0.10.0rc1 abc123d" => (0, 10, 0) +# "0.3.0" => (0, 3, 0) +def _parse_bazel_version(bazel_version): + """Parses a version string into a 3-tuple of ints + + int tuples can be compared directly using binary operators (<, >). + + Args: + bazel_version: the Bazel version string + + Returns: + An int 3-tuple of a (major, minor, patch) version. + """ + + version = _extract_version_number(bazel_version) + return tuple([int(n) for n in version.split(".")]) + + +def _is_at_most(threshold, version): + """Check that a version is lower or equals to a threshold. + + Args: + threshold: the maximum version string + version: the version string to be compared to the threshold + + Returns: + True if version <= threshold. + """ + return _parse_bazel_version(version) <= _parse_bazel_version(threshold) + + +def _is_at_least(threshold, version): + """Check that a version is higher or equals to a threshold. + + Args: + threshold: the minimum version string + version: the version string to be compared to the threshold + + Returns: + True if version >= threshold. + """ + + return _parse_bazel_version(version) >= _parse_bazel_version(threshold) + + +def _check_bazel_version(minimum_bazel_version, maximum_bazel_version=None, bazel_version=None): + """Check that the version of Bazel is valid within the specified range. + + Args: + minimum_bazel_version: minimum version of Bazel expected + maximum_bazel_version: maximum version of Bazel expected + bazel_version: the version of Bazel to check. Used for testing, defaults to native.bazel_version + """ + if not bazel_version: + if "bazel_version" not in dir(native): + fail("\nCurrent Bazel version is lower than 0.2.1, expected at least %s\n" % minimum_bazel_version) + elif not native.bazel_version: + print("\nCurrent Bazel is not a release version, cannot check for compatibility.") + print("Make sure that you are running at least Bazel %s.\n" % minimum_bazel_version) + return + else: + bazel_version = native.bazel_version + + if not _is_at_least( + threshold = minimum_bazel_version, + version = bazel_version): + fail("\nCurrent Bazel version is {}, expected at least {}\n".format( + bazel_version, minimum_bazel_version)) + + if maximum_bazel_version: + max_bazel_version = _parse_bazel_version(maximum_bazel_version) + if not _is_at_most( + threshold = maximum_bazel_version, + version = bazel_version): + fail("\nCurrent Bazel version is {}, expected at most {}\n".format( + bazel_version, maximum_bazel_version)) + + pass + +versions = struct( + get=_get_bazel_version, + parse=_parse_bazel_version, + check=_check_bazel_version, + is_at_most=_is_at_most, + is_at_least=_is_at_least, +) diff --git a/dotnet/providers.rst b/dotnet/providers.rst new file mode 100644 index 00000000000000..346b06fdca6bb5 --- /dev/null +++ b/dotnet/providers.rst @@ -0,0 +1,69 @@ +Dotnet providers +================ + +.. _providers: https://docs.bazel.build/versions/master/skylark/rules.html#providers +.. _runfiles: https://docs.bazel.build/versions/master/skylark/lib/runfiles.html +.. _File: https://docs.bazel.build/versions/master/skylark/lib/File.html + +.. role:: param(emphasis) +.. role:: type(emphasis) +.. role:: value(code) +.. |mandatory| replace:: **mandatory value** + + +The providers_ are the outputs of the rules, you generaly get them by having a dependency on a rule, +and then asking for a provider of a specific type. + +.. contents:: :depth: 2 + +----- + +Design +------ + +The Dotnet providers are designed primarily for the efficiency of the dotnet rules, the information +they share is mostly there because it is required for the core rules to work. + +All the providers are designed to hold only immutable data. This is partly because its a cleaner +design choice to be able to assume a provider will never change, but also because only immutable +objects are allowed to be stored in a depset, and it's really useful to have depsets of providers. +Specifically the :param:`deps` and :param:`transitive` fields on DotnetLibrary_ only work because +it is immutable. + +API +--- + + +DotnetLibrary +~~~~~~~~~~~~~ + +DotnetLibrary is a provider that exposes a compiled library along with it's full transitive +dependencies. +This represents a compile dotnet binary. + ++--------------------------------+-----------------------------------------------------------------+ +| **Name** | **Type** | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`deps` | :type:`list of DotnetLibrary` | ++--------------------------------+-----------------------------------------------------------------+ +| The direct dependencies of this library. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`transitive` | :type:`depset of DotnetLibrary` | ++--------------------------------+-----------------------------------------------------------------+ +| The full set of transitive dependencies. This includes ``deps`` for this | +| library and all ``deps`` members transitively reachable through ``deps``. | ++--------------------------------+-----------------------------------------------------------------+ + +DotnetResource +~~~~~~~~~~~~~~ + +DotnetResource is a provider that exposes a compiled resource (.resources file). + ++--------------------------------+-----------------------------------------------------------------+ +| **Name** | **Type** | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`identifer` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The logical name for the resource; the name that is used to load the resource. | +| The default is the basename of the file name (no subfolder). | ++--------------------------------+-----------------------------------------------------------------+ diff --git a/dotnet/stdlib/BUILD.bazel b/dotnet/stdlib/BUILD.bazel new file mode 100644 index 00000000000000..e53a4e3bde609b --- /dev/null +++ b/dotnet/stdlib/BUILD.bazel @@ -0,0 +1,128 @@ +package(default_visibility = [ "//visibility:public" ]) + +load("@io_bazel_rules_dotnet//dotnet/private:rules/stdlib.bzl", "dotnet_stdlib") + +dotnet_stdlib(name="Accessibility.dll") +dotnet_stdlib(name="Commons.Xml.Relaxng.dll") +dotnet_stdlib(name="CustomMarshalers.dll") +dotnet_stdlib(name="I18N.CJK.dll") +dotnet_stdlib(name="I18N.MidEast.dll") +dotnet_stdlib(name="I18N.Other.dll") +dotnet_stdlib(name="I18N.Rare.dll") +dotnet_stdlib(name="I18N.West.dll") +dotnet_stdlib(name="I18N.dll") +dotnet_stdlib(name="IBM.Data.DB2.dll") +dotnet_stdlib(name="Microsoft.Build.Engine.dll") +dotnet_stdlib(name="Microsoft.Build.Framework.dll") +dotnet_stdlib(name="Microsoft.Build.Tasks.v4.0.dll") +dotnet_stdlib(name="Microsoft.Build.Utilities.v4.0.dll") +dotnet_stdlib(name="Microsoft.Build.dll") +dotnet_stdlib(name="Microsoft.CSharp.dll") +dotnet_stdlib(name="Microsoft.VisualBasic.dll") +dotnet_stdlib(name="Microsoft.VisualC.dll") +dotnet_stdlib(name="Microsoft.Web.Infrastructure.dll") +dotnet_stdlib(name="Mono.CSharp.dll") +dotnet_stdlib(name="Mono.Cairo.dll") +dotnet_stdlib(name="Mono.CodeContracts.dll") +dotnet_stdlib(name="Mono.CompilerServices.SymbolWriter.dll") +dotnet_stdlib(name="Mono.Data.Sqlite.dll") +dotnet_stdlib(name="Mono.Data.Tds.dll") +dotnet_stdlib(name="Mono.Debugger.Soft.dll") +dotnet_stdlib(name="Mono.Http.dll") +dotnet_stdlib(name="Mono.Management.dll") +dotnet_stdlib(name="Mono.Messaging.RabbitMQ.dll") +dotnet_stdlib(name="Mono.Messaging.dll") +dotnet_stdlib(name="Mono.Parallel.dll") +dotnet_stdlib(name="Mono.Posix.dll") +dotnet_stdlib(name="Mono.Security.dll") +dotnet_stdlib(name="Mono.Simd.dll") +dotnet_stdlib(name="Mono.Tasklets.dll") +dotnet_stdlib(name="Mono.WebBrowser.dll") +dotnet_stdlib(name="Novell.Directory.Ldap.dll") +dotnet_stdlib(name="PEAPI.dll") +dotnet_stdlib(name="RabbitMQ.Client.dll") +dotnet_stdlib(name="System.ComponentModel.Composition.dll") +dotnet_stdlib(name="System.ComponentModel.DataAnnotations.dll") +dotnet_stdlib(name="System.Configuration.Install.dll") +dotnet_stdlib(name="System.Configuration.dll") +dotnet_stdlib(name="System.Core.dll") +dotnet_stdlib(name="System.Data.DataSetExtensions.dll") +dotnet_stdlib(name="System.Data.Entity.dll") +dotnet_stdlib(name="System.Data.Linq.dll") +dotnet_stdlib(name="System.Data.OracleClient.dll") +dotnet_stdlib(name="System.Data.Services.Client.dll") +dotnet_stdlib(name="System.Data.Services.dll") +dotnet_stdlib(name="System.Data.dll") +dotnet_stdlib(name="System.Design.dll") +dotnet_stdlib(name="System.Diagnostics.Tracing.dll") +dotnet_stdlib(name="System.DirectoryServices.Protocols.dll") +dotnet_stdlib(name="System.DirectoryServices.dll") +dotnet_stdlib(name="System.Drawing.Design.dll") +dotnet_stdlib(name="System.Drawing.dll") +dotnet_stdlib(name="System.Dynamic.dll") +dotnet_stdlib(name="System.EnterpriseServices.dll") +dotnet_stdlib(name="System.IO.Compression.FileSystem.dll") +dotnet_stdlib(name="System.IO.Compression.dll") +dotnet_stdlib(name="System.IdentityModel.Selectors.dll") +dotnet_stdlib(name="System.IdentityModel.dll") +dotnet_stdlib(name="System.Json.Microsoft.dll") +dotnet_stdlib(name="System.Json.dll") +dotnet_stdlib(name="System.Management.dll") +dotnet_stdlib(name="System.Messaging.dll") +dotnet_stdlib(name="System.Net.Http.Formatting.dll") +dotnet_stdlib(name="System.Net.Http.WebRequest.dll") +dotnet_stdlib(name="System.Net.Http.dll") +dotnet_stdlib(name="System.Net.dll") +dotnet_stdlib(name="System.Numerics.dll") +dotnet_stdlib(name="System.Reactive.Core.dll") +dotnet_stdlib(name="System.Reactive.Debugger.dll") +dotnet_stdlib(name="System.Reactive.Experimental.dll") +dotnet_stdlib(name="System.Reactive.Interfaces.dll") +dotnet_stdlib(name="System.Reactive.Linq.dll") +dotnet_stdlib(name="System.Reactive.Observable.Aliases.dll") +dotnet_stdlib(name="System.Reactive.PlatformServices.dll") +dotnet_stdlib(name="System.Reactive.Providers.dll") +dotnet_stdlib(name="System.Reactive.Runtime.Remoting.dll") +dotnet_stdlib(name="System.Reactive.Windows.Forms.dll") +dotnet_stdlib(name="System.Reactive.Windows.Threading.dll") +dotnet_stdlib(name="System.Reflection.Context.dll") +dotnet_stdlib(name="System.Runtime.Caching.dll") +dotnet_stdlib(name="System.Runtime.DurableInstancing.dll") +dotnet_stdlib(name="System.Runtime.Remoting.dll") +dotnet_stdlib(name="System.Runtime.Serialization.Formatters.Soap.dll") +dotnet_stdlib(name="System.Runtime.Serialization.dll") +dotnet_stdlib(name="System.Security.dll") +dotnet_stdlib(name="System.ServiceModel.Activation.dll") +dotnet_stdlib(name="System.ServiceModel.Discovery.dll") +dotnet_stdlib(name="System.ServiceModel.Routing.dll") +dotnet_stdlib(name="System.ServiceModel.Web.dll") +dotnet_stdlib(name="System.ServiceModel.dll") +dotnet_stdlib(name="System.ServiceProcess.dll") +dotnet_stdlib(name="System.Threading.Tasks.Dataflow.dll") +dotnet_stdlib(name="System.Transactions.dll") +dotnet_stdlib(name="System.Web.Abstractions.dll") +dotnet_stdlib(name="System.Web.ApplicationServices.dll") +dotnet_stdlib(name="System.Web.DynamicData.dll") +dotnet_stdlib(name="System.Web.Extensions.Design.dll") +dotnet_stdlib(name="System.Web.Extensions.dll") +dotnet_stdlib(name="System.Web.Http.SelfHost.dll") +dotnet_stdlib(name="System.Web.Http.WebHost.dll") +dotnet_stdlib(name="System.Web.Http.dll") +dotnet_stdlib(name="System.Web.Mvc.dll") +dotnet_stdlib(name="System.Web.Razor.dll") +dotnet_stdlib(name="System.Web.Routing.dll") +dotnet_stdlib(name="System.Web.Services.dll") +dotnet_stdlib(name="System.Web.WebPages.Deployment.dll") +dotnet_stdlib(name="System.Web.WebPages.Razor.dll") +dotnet_stdlib(name="System.Web.WebPages.dll") +dotnet_stdlib(name="System.Web.dll") +dotnet_stdlib(name="System.Windows.Forms.DataVisualization.dll") +dotnet_stdlib(name="System.Windows.Forms.dll") +dotnet_stdlib(name="System.Windows.dll") +dotnet_stdlib(name="System.Xaml.dll") +dotnet_stdlib(name="System.Xml.Linq.dll") +dotnet_stdlib(name="System.Xml.Serialization.dll") +dotnet_stdlib(name="System.Xml.dll") +dotnet_stdlib(name="System.dll") +dotnet_stdlib(name="WebMatrix.Data.dll") +dotnet_stdlib(name="WindowsBase.dll") diff --git a/dotnet/toolchain/BUILD.bazel b/dotnet/toolchain/BUILD.bazel new file mode 100644 index 00000000000000..fb56e2e8af331d --- /dev/null +++ b/dotnet/toolchain/BUILD.bazel @@ -0,0 +1,12 @@ +load( + ":toolchains.bzl", + "declare_constraints", + "declare_toolchains", +) + +package(default_visibility = ["//visibility:public"]) + +declare_toolchains() + +declare_constraints() + diff --git a/dotnet/toolchain/toolchains.bzl b/dotnet/toolchain/toolchains.bzl new file mode 100644 index 00000000000000..f4e77fe9e932c3 --- /dev/null +++ b/dotnet/toolchain/toolchains.bzl @@ -0,0 +1,115 @@ +load( + "//dotnet/private:dotnet_toolchain.bzl", + "dotnet_toolchain", +) +load( + "//dotnet/private:sdk.bzl", + "dotnet_download_sdk", + "dotnet_host_sdk", + "dotnet_local_sdk", +) +load( + "//dotnet/platform:list.bzl", + "DOTNETARCH", + "DOTNETOS", + "DOTNETIMPL", + "DOTNETIMPL_OS_ARCH", +) + +DEFAULT_VERSION = "4.2.3" + +SDK_REPOSITORIES = { + "4.2.3": { + "mono_darwin_amd64": ("http://bazel-mirror.storage.googleapis.com/download.mono-project.com/archive/4.2.3/macos-10-x86/MonoFramework-MDK-4.2.3.4.macos10.xamarin.x86.tar.gz", + "a7afb92d4a81f17664a040c8f36147e57a46bb3c33314b73ec737ad73608e08b"), + }, +} + +def _generate_toolchains(): + # Use all the above information to generate all the possible toolchains we might support + toolchains = [] + for impl, os, arch in DOTNETIMPL_OS_ARCH: + host = "{}_{}_{}".format(impl, os, arch) + toolchain_name = "dotnet_{}".format(host) + csc_flags = [] + toolchains.append(dict( + name = toolchain_name, + host = host, + csc_flags = csc_flags, + )) + return toolchains + +_toolchains = _generate_toolchains() + + +_label_prefix = "@io_bazel_rules_dotnet//dotnet/toolchain:" + +def dotnet_register_toolchains(dotnet_version=DEFAULT_VERSION): + """See /dotnet/toolchains.rst#dostnet-register-toolchains for full documentation.""" + if "dotnet_download_sdk" not in native.existing_rules() and "dotnet_host_sdk" not in native.existing_rules() and "dotnet_local_sdk" not in native.existing_rules(): + if dotnet_version in SDK_REPOSITORIES: + dotnet_download_sdk( + name = "dotnet_sdk", + sdks = SDK_REPOSITORIES[dotnet_version], + ) + elif dotnet_version == "host": + dotnet_host_sdk( + name = "dotnet_sdk" + ) + else: + fail("Unknown dotnet version {}".format(dotnet_version)) + + # Use the final dictionaries to register all the toolchains + for toolchain in _toolchains: + name = _label_prefix + toolchain["name"] + native.register_toolchains(name) + + +def declare_constraints(): + for os, constraint in DOTNETOS.items(): + if constraint: + native.alias( + name = os, + actual = constraint, + ) + else: + native.constraint_value( + name = os, + constraint_setting = "@bazel_tools//platforms:os", + ) + for arch, constraint in DOTNETARCH.items(): + if constraint: + native.alias( + name = arch, + actual = constraint, + ) + else: + native.constraint_value( + name = arch, + constraint_setting = "@bazel_tools//platforms:cpu", + ) + native.constraint_setting(name = "dotnetimpl") + for impl, constraint in DOTNETIMPL.items(): + native.constraint_value( + name = impl, + constraint_setting = ":dotnetimpl", + ) + + + for impl, os, arch in DOTNETIMPL_OS_ARCH: + native.platform( + name = impl + "_" + os + "_" + arch, + constraint_values = [ + ":" + impl, + ":" + os, + ":" + arch, + ], + ) +def declare_toolchains(): + # Use the final dictionaries to create all the toolchains + for toolchain in _toolchains: + dotnet_toolchain( + # Required fields + name = toolchain["name"], + host = toolchain["host"], + ) diff --git a/dotnet/toolchains.rst b/dotnet/toolchains.rst new file mode 100644 index 00000000000000..71bae5102944f0 --- /dev/null +++ b/dotnet/toolchains.rst @@ -0,0 +1,571 @@ +Dotnet toolchains +================= +.. _core: core.bzl +.. _rules_go: https://github.com/bazelbuild/rules_go +.. _go_toolchains: https://github.com/bazelbuild/rules_go/blob/master/go/toolchains.rst +.. _DotnetLibrary: providers.bzl#DotnetLibrary +.. _DotnetResource: providers.bzl#DotnetResource + +.. role:: param(kbd) +.. role:: type(emphasis) +.. role:: value(code) +.. |mandatory| replace:: **mandatory value** + + +The design and implementation is heavily based on rules_go_ `toolchains <go_toolchains_>`_. + +----- + +Design +------ + +The Dotnet toolchain consists of three main layers, `the sdk`_ and `the toolchain`_ and `the context`_. + +The SDK +~~~~~~~ + +At the bottom is the Mono MDK. + +This is always bound to ``@dotnet_sdk`` and can be referred to directly if needed, but in general +you should always access it through the toolchain. + +The dotnet_download_sdk_ and dotnet_host_sdk_ family of rules are responsible for downloading +these, and adding just enough of a build file to expose the contents to Bazel. + +If you don't do anything special, the dotnet rules will download the most recent official SDK for +your host (if available). +If you need a forked version of dotnet/mono, want to control the version or just use the +installed sdk then it is easy to do, you just need to make sure you have bound the dotnet_sdk +repository before you call dotnet_register_toolchains_. + +The toolchain +~~~~~~~~~~~~~ + +This a wrapper over the sdk that provides enough extras to match, target and work on a specific +platforms. It should be considered an opaqute type, you only ever use it through `the context`_. + +Declaration +^^^^^^^^^^^ + +Toolchains are declared using the dotnet_toolchain_ macro. + +Toolchains are pre-declared for all the known combinations of host and target, and the names +are a predictable +"<**host**>" +So for instance if the rules_dotnet repository is loaded with +it's default name, the following toolchain labels (along with many others) will be available + +.. code:: + + @io_bazel_rules_dotnet//dotnet/toolchain:linux_amd64 + +The toolchains are not usable until you register them. + +Registration +^^^^^^^^^^^^ + +Normally you would just call dotnet_register_toolchains_ from your WORKSPACE to register all the +pre-declared toolchains, and allow normal selection logic to pick the right one. + +It is fine to add more toolchains to the available set if you like. Because the normal +toolchain matching mechanism prefers the first declared match, you can also override individual +toolchains by declaring and registering toolchains with the same constraints *before* calling +dotnet_register_toolchains_. + +If you wish to have more control over the toolchains you can instead just make direct +calls to dotnet_register_toolchains_ with only the toolchains you wish to install. You can see an +example of this in `limiting the available toolchains`_. + + +The context +~~~~~~~~~~~ + +This is the type you use if you are writing custom rules that need dotnet toochain. + +Use +^^^ + +If you are writing a new rule that wants to use the Dotnet toolchain, you need to do a couple of things. +First, you have to declare that you want to consume the toolchain on the rule declaration. +The easiest way to do this is to use the dotnet_rule wrapper, which adds in the toolchain and some +hidden attributes that it consumes. + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_context") + + my_rule = rule( + _my_rule_impl, + attrs = { + ... + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + ) + +And then in the rule body, you need to get the toolchain itself and use it's action generators. + +.. code:: python + + def _my_rule_impl(ctx): + dotnet = dotnet_context(ctx) + + +Customizing +----------- + +Normal usage +~~~~~~~~~~~~ + +This is an example of normal usage for the other examples to be compared against. + +WORKSPACE +^^^^^^^^^ + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_rules_dependencies", "dotnet_register_toolchains") + + dotnet_rules_dependencies() + dotnet_register_toolchains() + + +Forcing the Dotnet version +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can select the version of the Mono to use by specifying it when you call +dotnet_register_toolchains_ but you must use a value that matches a known toolchain. + +WORKSPACE +^^^^^^^^^ + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_rules_dependencies", "dotnet_register_toolchains") + + dotnet_rules_dependencies() + dotnet_register_toolchains(dotnet_version="4.2.3") + + +Using the installed Mono +~~~~~~~~~~~~~~~~~~~~~~~~ + +The "host" version is a special toolchain that breaks the hermetic seal to use the host installed +toolchain. + +WORKSPACE +^^^^^^^^^ + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_rules_dependencies", "dotnet_register_toolchains") + + dotnet_rules_dependencies() + dotnet_register_toolchains(go_version="host") + + + +Registering a custom Mono +~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to register your own toolchain that takes precedence over the pre-declared ones you can +just add it and register it before the normal ones. + +WORKSPACE +^^^^^^^^^ + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_rules_dependencies", "dotnet_register_toolchains", "dotnet_download_sdk") + + dotnet_download_sdk(name="my_macos_sdk", url="http://bazel-mirror.storage.googleapis.com/download.mono-project.com/archive/4.2.3/macos-10-x86/MonoFramework-MDK-4.2.3.4.macos10.xamarin.x86.tar.gz") + register_toolchains( + "@//:my_macos_toolchain", + ) + + dotnet_rules_dependencies() + dotnet_register_toolchains() + + +BUILD.bazel +^^^^^^^^^^^ + +.. code:: python + + dotnet_toolchain(name="my_macos_toolchain", sdk="my_macos_sdk") + + +Limiting the available toolchains +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you wanted to only allow your project to be compiled on mac at Mono version 4.2.3, +instead of calling dotnet_register_toolchains_ you can put + +WORKSPACE +^^^^^^^^^ + +.. code:: python + + load("@io_bazel_rules_dotnet//dotnet:def.bzl", "dotnet_rules_dependencies") + + dotnet_rules_dependencies() + register_toolchains( + "@io_bazel_rules_dotnet//dotnet/toolchain:4.2.3_darwin_amd64", + ) + + +API +--- + +dotnet_register_toolchains +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Installs the Dotnet toolchains. If :param:`dotnet_version` is specified, it sets the +Mono version to use (for example, :value:`"4.2.3"`). By default, the latest +Mono will be used. + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`dotnet_version` | :type:`string` | :value:`"4.2.3"` | ++--------------------------------+-----------------------------+-----------------------------------+ +| This specifies the Mono version to select. | +| It will match the version specification of the toochain which for normal sdk toolchains is | +| also the string part of the binary distribution you want to use. | +| You can also use it to select the "host" sdk toolchain, or a custom toolchain with a | +| specialized version string. | ++--------------------------------+-----------------------------+-----------------------------------+ + +dotnet_download_sdk +~~~~~~~~~~~~~~~~~~~ + +This downloads Mono for use in toolchains. + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| A unique name for this sdk. This should almost always be :value:`dotnet_sdk` if you want the SDK | +| to be used by toolchains. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`urls` | :type:`string_list` | :value:`official distributions` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A list of mirror urls to the binary distribution of Mono. These must contain the `{}` | +| used to substitute the sdk filename being fetched (using `.format`. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`strip_prefix` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A directory prefix to strip from the extracted files. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`sdks` | :type:`string_list_dict` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| This consists of a set of mappings from the host platform tuple to a list of filename and | +| sha256 for that file. The filename is combined the :param:`urls` to produce the final download | +| urls to use. | +| | +| As an example: | +| | +| .. code:: python | +| | +| dotnet_download_sdk( | +| name = "dotnet_sdk", | +| sdks = { | +| "linux_amd64": ("go1.8.1.linux-amd64.tar.gz", | +| "a579ab19d5237e263254f1eac5352efcf1d70b9dacadb6d6bb12b0911ede8994"), | +| "darwin_amd64": ("go1.8.1.darwin-amd64.tar.gz", | +| "25b026fe2f4de7c80b227f69588b06b93787f5b5f134fbf2d652926c08c04bcd"), | +| }, | +| ) | +| | ++--------------------------------+-----------------------------+-----------------------------------+ + + +dotnet_host_sdk +~~~~~~~~~~~~~~~ + +This detects the host Mono for use in toolchains. + +It searches the PATH. You can achive the same result by setting +the version to "host" when registering toolchains to select the installed sdk so it should +never be neccesary to use this feature directly. + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| A unique name for this sdk. This should almost always be :value:`dotnet_sdk` if you want the SDK | +| to be used by toolchains. | ++--------------------------------+-----------------------------+-----------------------------------+ + + +dotnet_context +~~~~~~~~~~~~~~ + +This collects the information needed to form and return a :type:`DotnetContext` from a rule ctx. +It uses the attrbutes and the toolchains. +It can only be used in the implementation of a rule that has the dotnet toolchain attached and +the dotnet context data as an attribute. + +.. code:: python + + my_rule = rule( + _my_rule_impl, + attrs = { + ... + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")) + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], + ) + + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`ctx` | :type:`ctx` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| The Bazel ctx object for the current rule. | ++--------------------------------+-----------------------------+-----------------------------------+ + +The context object +~~~~~~~~~~~~~~~~~~ + +DotnetContext is never returned by a rule, instead you build one using dotnet_context(ctx) in the +top of any custom skylark rule that wants to interact with the go rules. +It provides all the information needed to create dotnet actions, and create or interact with the +other dotnet providers. + +When you get a DotnetContext from a context (see use_) it exposes a number of fields and methods. + +All methods take the DotnetContext as the only positional argument, all other arguments even if +mandatory must be specified by name, to allow us to re-order and deprecate individual parameters +over time. + + +Methods +^^^^^^^ + +* Action generators + + * library_ + * binary_ + * resx_ + +* Helpers + + * declare_file_ + * new_library_ + * new_resource_ + + +Fields +^^^^^^ + ++--------------------------------+-----------------------------------------------------------------+ +| **Name** | **Type** | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`toolchain` | :type:`DotnetToolchain` | ++--------------------------------+-----------------------------------------------------------------+ +| The underlying toolchain. This should be considered an opaque type subject to change. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`exe_extension` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The suffix to use for all executables in this build mode. Mostly used when generating the output | +| filenames of binary rules. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`runner` | :type:`File` | ++--------------------------------+-----------------------------------------------------------------+ +| The "mono" binary used to run dotnet executables | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`mcs` | :type:`File` | ++--------------------------------+-----------------------------------------------------------------+ +| The main "mcs" (C# compiler) binary used. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`resgen` | :type:`File` | ++--------------------------------+-----------------------------------------------------------------+ +| The resource compiler (dotnet executable). | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`stdlib` | :type:`File` | ++--------------------------------+-----------------------------------------------------------------+ +| The standard library (mscorlib.dll) to use in the build. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`libVersion` | :type:`string` | ++--------------------------------+-----------------------------------------------------------------+ +| The mono library version to used. The default is 4.7-api | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`actions` | :type:`ctx.actions` | ++--------------------------------+-----------------------------------------------------------------+ +| The actions structure from the Bazel context, which has all the methods for building new | +| bazel actions. | ++--------------------------------+-----------------------------------------------------------------+ +| :param:`lib` | :type:`label` | ++--------------------------------+-----------------------------------------------------------------+ +| The label for directory with the selected libraryVersion assemblies | ++--------------------------------+-----------------------------------------------------------------+ + + +library +~~~~~~~ + +The library function adds an action that compiles the set of sources into assembly. + +It returns DotnetLibrary_ provider. + ++--------------------------------+--------------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`dotnet` | :type:`DotnetContext` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| This must be the same DotnetContext object you got this function from. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`srcs` | :type:`File iterable` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of source code artifacts. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`deps` | :type:`DotnetLibrary iterable` | :value:`[]` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of all directly imported libraries. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`resources` | :type:`DotnetResource iterable`| :value:`[]` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of all directly imported libraries. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An alternative name of the output file | ++--------------------------------+--------------------------------+-----------------------------------+ + +binary +~~~~~~ + +The function adds an action that compiles the set of sources into executable assembly. + +It returns DotnetLibrary_ provider. + ++--------------------------------+--------------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`dotnet` | :type:`DotnetContext` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| This must be the same DotnetContext object you got this function from. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`srcs` | :type:`File iterable` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of source code artifacts. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`deps` | :type:`DotnetLibrary iterable` | :value:`[]` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of all directly imported libraries. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`resources` | :type:`DotnetResource iterable`| :value:`[]` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An iterable of all directly imported libraries. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++--------------------------------+--------------------------------+-----------------------------------+ +| An alternative name of the output file | ++--------------------------------+--------------------------------+-----------------------------------+ + +resx +~~~~ + +The function adds an action that compiles a single .resx file into .resources file. + +It returns DotnetResource_ provider. + ++----------------------------+-----------------------------+---------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`src` | :type:`label` | |mandatory| | ++----------------------------+-----------------------------+---------------------------------------+ +| The .resx source file that is transformed into .resources file. | +| Only :value:`.resx` files are permitted | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`identifer` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| The logical name for the resource; the name that is used to load the resource. | +| The default is the basename of the file name (no subfolder). | ++----------------------------+-----------------------------+---------------------------------------+ +| :param:`out` | :type:`string` | :value:`""` | ++----------------------------+-----------------------------+---------------------------------------+ +| An alternative name of the output file | ++----------------------------+-----------------------------+---------------------------------------+ + + +declare_file +~~~~~~~~~~~~ + +This is the equivalent of ctx.actions.declare_file. + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`dotnet` | :type:`DotnetContext` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| This must be the same DotnetContext object you got this function from. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`path` | :type:`string` | :value:`""` | ++--------------------------------+-----------------------------+-----------------------------------+ +| A path for this file, including the basename of the file. | ++--------------------------------+-----------------------------+-----------------------------------+ + +new_library +~~~~~~~~~~~ + +This creates a new DotnetLibrary_. +You can add extra fields to the go library by providing extra named parameters to this function, +they will be visible to the resolver when it is invoked. + ++--------------------------------+--------------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| A unique name for this library. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`dotnet` | :type:`DotnetContext` | |mandatory| | ++--------------------------------+--------------------------------+-----------------------------------+ +| This must be the same DotnetContext object you got this function from. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`deps` | :type:`list of DotnetLibrary` | | ++--------------------------------+--------------------------------+-----------------------------------+ +| The direct dependencies of this library. | ++--------------------------------+--------------------------------+-----------------------------------+ +| :param:`transitive` | :type:`depset of DotnetLibrary`| | ++--------------------------------+--------------------------------+-----------------------------------+ +| The full set of transitive dependencies. This includes ``deps`` for this | +| library and all ``deps`` members transitively reachable through ``deps``. | ++--------------------------------+--------------------------------+-----------------------------------+ + +new_resource +~~~~~~~~~~~~ + +This creates a new DotnetResource_. +You can add extra fields to the go library by providing extra named parameters to this function, +they will be visible to the resolver when it is invoked. + ++--------------------------------+-----------------------------+-----------------------------------+ +| **Name** | **Type** | **Default value** | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| A unique name for this library. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`dotnet` | :type:`DotnetContext` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| This must be the same DotnetContext object you got this function from. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`result` | :type:`File` | |mandatory| | ++--------------------------------+-----------------------------+-----------------------------------+ +| The .resources file. | ++--------------------------------+-----------------------------+-----------------------------------+ +| :param:`identifier` | :type:`string` | :value:`None` | ++--------------------------------+-----------------------------+-----------------------------------+ +| Identifier passed to -resource flag of mcs compiler. If empty the basename of the result | +| is used. | ++--------------------------------+-----------------------------+-----------------------------------+ diff --git a/dotnet/tools/BUILD b/dotnet/tools/BUILD new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/dotnet/tools/common/BUILD b/dotnet/tools/common/BUILD new file mode 100644 index 00000000000000..702efa5dd346b0 --- /dev/null +++ b/dotnet/tools/common/BUILD @@ -0,0 +1,13 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "common", + srcs = glob([ + "*.c", + ]), + hdrs = glob([ + "*.h", + ]), +) + +exports_files(["manifest.h"]) \ No newline at end of file diff --git a/dotnet/tools/common/manifest.c b/dotnet/tools/common/manifest.c new file mode 100644 index 00000000000000..28e90df40d00a0 --- /dev/null +++ b/dotnet/tools/common/manifest.c @@ -0,0 +1,281 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef _MSC_VER +#include <direct.h> +#include <windows.h> +#include <Shlwapi.h> +#include <io.h> +#include <process.h> +#define F_OK 0 +#pragma comment(lib, "shlwapi.lib") +#else +#include <unistd.h> +#include <errno.h> +#endif + +#include "manifest.h" + +extern const char * Exe; +struct Entry* g_Entries = NULL; + + +void ReadManifest(const char *manifestDir) +{ + char buffer[64*1024]; + FILE *f; + char *p; + int line = 0; + struct Entry *entry; + + strcpy(buffer, manifestDir); + strcat(buffer, "/MANIFEST"); + /* read manifest file */ + f = fopen(buffer, "r"); + if (f == NULL) { + p = getcwd(buffer, sizeof(buffer)); + printf("Can't open file MANIFEST in %s\n", p); + exit(-1); + } + while (fgets(buffer, sizeof(buffer), f) != NULL ) + { + ++line; + p = strchr(buffer, '\n'); + if (p != NULL) + *p = '\0'; + p = strchr(buffer, '\r'); + if (p != NULL) + *p = '\0'; + + p = strchr(buffer, ' '); + if (p == NULL) { + printf("Line %d is malformatted (no space)\n", line); + exit(-1); + } + *p = '\0'; + entry = (struct Entry*) malloc(sizeof(struct Entry)); + entry->Key = strdup(buffer); + entry->Path = strdup(p+1); + entry->Next = g_Entries; + g_Entries = entry; + } + fclose (f); +} + +#ifdef _MSC_VER +static void CreateLinkIfNeeded(const char* target, const char *toCreate) +{ + BOOL result; + DWORD error; + DWORD flag; + + if (!PathFileExists(target)) { + printf("File %s does not exist\n", target); + exit(-1); + } + + flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + retry: + result = CreateSymbolicLinkA(toCreate, target, flag); + if (!result) { + error = GetLastError(); + if (error == 87 && flag!=0) { + printf("SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE seems not supported\n"); + flag = 0; + goto retry; + } + if (error != ERROR_ALREADY_EXISTS) { + printf("Error %d on linking %s to %s\n", error, toCreate, target); + exit(-1); + } + } +} +#else +static void CreateLinkIfNeeded(const char* target, const char *toCreate) +{ + int result; + if (access(target, F_OK)==-1) { + printf("File %s does not exist\n", target); + exit(-1); + } + + result = symlink(target, toCreate); + if (result!=0) { + int error = errno; + if (error != EEXIST) { + printf("Error %d on linking %s to %s\n", error, toCreate, target); + exit(-1); + } + } +} +#endif + +void LinkFiles(const char *manifestDir) { + const struct Entry *p = g_Entries; + const char *basename; + char toCreate[64*1024]; + + while(p != NULL) { + basename = strrchr(p->Key, '/'); + if (basename == NULL) + basename = p->Key; + else + ++basename; + + sprintf(toCreate, "%s/%s", manifestDir, basename); + + CreateLinkIfNeeded(p->Path, toCreate); + p = p->Next; + } +} + +#ifdef _MSC_VER +typedef struct _stat Stat; +static void do_mkdir(const char *path) +{ + Stat st; + + if (access(path, F_OK) == 0) { + return; + } + + /* Directory does not exist. EEXIST for race condition */ + if (CreateDirectoryA(path, NULL) == 0) { + printf("Error %d creating directory for %s\n", GetLastError(), path); + exit(-1); + } +} + +#else + +typedef struct stat Stat; +static void do_mkdir(const char *path) +{ + Stat st; + int status = 0; + + if (stat(path, &st) != 0) + { + /* Directory does not exist. EEXIST for race condition */ + if (mkdir(path, 0777) != 0 && errno != EEXIST) + status = -1; + } + else if (!S_ISDIR(st.st_mode)) + { + errno = ENOTDIR; + status = -1; + } + + if (status != 0) { + printf("Error %d creating directory for %s\n", errno, path); + //exit(-1); + } +} +#endif + +static void NormalizeDir(char *path) +{ + char *q, *p; + while ((q = strchr(path, '\\'))!= NULL) { + *q = '/'; + } + + while((p = strstr(path, "../"))!=NULL) { + q = strchr(p+3, '/'); + if (q == NULL) { + printf("Failed to normalize dir %s\n", path); + exit(-1); + } + + memcpy(p, q+1, strlen(q+1)+1); + } +} +static void CreateDirTreeForFile(const char * path) +{ + char *pp; + char *sp; + char copypath[64*1024]; + + strcpy(copypath, path); + + pp = strrchr(copypath, '/'); + *(pp+1) = '\0'; + + pp = copypath; + while ((sp = strchr(pp, '/')) != NULL) + { + if (sp != pp) + { + /* Neither root nor double slash in path */ + *sp = '\0'; + do_mkdir(copypath); + *sp = '/'; + } + pp = sp + 1; + } +} + + +void LinkFilesTree(const char *manifestDir) { + const struct Entry *p = g_Entries; + char toCreate[64*1024]; + + while(p != NULL) { + sprintf(toCreate, "%s%s", manifestDir, p->Key); + NormalizeDir(toCreate); + + CreateDirTreeForFile(toCreate); + CreateLinkIfNeeded(p->Path, toCreate); + p = p->Next; + } +} + +/* I didn't find an easy way to locate MANIFEST file. + Until now, I have identified the following cases: + 1. Current directory (run on Windows). + 2. Parrent directory (run on Linux and osx). + 3. <currentdir>/<launcher>.runfiles (when used as a tool and launcher is this program) + This function tries to locate the MANIFEST file and returns + an absolute path to directory with it. +*/ +const char *GetManifestDir() { + static char buffer[64*1024]; + char *p; + p = getcwd(buffer, sizeof(buffer)); + if (access("MANIFEST", F_OK)!=-1) + return buffer; + + + strcat(buffer, "/../MANIFEST"); + if (access(buffer, F_OK)!=-1) { + p = strrchr(buffer, '/'); + *(p+1) = '\0'; + + return buffer; + } + + p = getcwd(buffer, sizeof(buffer)); + strcat(buffer, "/"); + strcat(buffer, Exe); + /* We have to convert Exe name to this launcher name (by removing _exe suffix and possibly .exe + on non-Windows platforms) */ + p = strrchr(buffer, '_'); + #ifdef _MSC_VER + strcpy(p, p+4); + #else + strcpy(p, p+8); + #endif + + strcat(buffer, ".runfiles/MANIFEST"); + printf("Checking %s\n", buffer); + if (access(buffer, F_OK)!=-1) { + p = strrchr(buffer, '/'); + *(p+1) = '\0'; + return buffer; + } + + printf("Couldn't find MANIFEST file\n"); + exit(-1); +} diff --git a/dotnet/tools/common/manifest.h b/dotnet/tools/common/manifest.h new file mode 100644 index 00000000000000..7d34381247e72b --- /dev/null +++ b/dotnet/tools/common/manifest.h @@ -0,0 +1,13 @@ +struct Entry { + const char *Key; + const char *Path; + const struct Entry* Next; +}; + +extern struct Entry* g_Entries; + +void ReadManifest(const char *manifestDir); +void LinkFiles(const char *manifestDir); +void LinkFilesTree(const char *manifestDir); +const char *GetManifestDir(); + diff --git a/dotnet/tools/runner/BUILD b/dotnet/tools/runner/BUILD new file mode 100644 index 00000000000000..64e1b6413edff7 --- /dev/null +++ b/dotnet/tools/runner/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "runner", + srcs = glob([ + "*.c", + ]), + deps = ["//dotnet/tools/common:common"], +) diff --git a/dotnet/tools/runner/main.c b/dotnet/tools/runner/main.c new file mode 100644 index 00000000000000..5da6d3c8895e4c --- /dev/null +++ b/dotnet/tools/runner/main.c @@ -0,0 +1,120 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef _MSC_VER +#include <direct.h> +#include <windows.h> +#include <Shlwapi.h> +#include <io.h> +#include <process.h> +#define F_OK 0 +#pragma comment(lib, "shlwapi.lib") +#else +#include <unistd.h> +#include <errno.h> +#endif + +#include "dotnet/tools/common/manifest.h" + +extern const char * Exe; +extern const char * Nunit; + + + +static void RunExe(const char *manifestDir, int argc, char **argv) { + char fullpath[64*1024]; + char **args; + int i, c; + int test = strlen(Nunit) > 0; +#ifndef _MSC_VER + char monofullpath[64*1024]; +#endif + + getcwd(fullpath, sizeof(fullpath)); + printf("cwd %s\n", fullpath); + + /* Find Exe's real path */ + const char *found = strrchr(Exe, '/'); + if (found == NULL) { + found = Exe; + } else { + ++found; + } +#ifdef _MSC_VER + c = argc+1; + if (test) c = c + 2; + args = malloc( (c) * sizeof(char*)); + c = 0; + if (test) { + sprintf(fullpath, "%s/nunit-console-runner-exe_exe.exe", manifestDir); + args[c++] = strdup(fullpath); + sprintf(fullpath, "-result=%s", getenv("XML_OUTPUT_FILE")); + args[c++] = strdup(fullpath); + } + sprintf(fullpath, "%s/%s", manifestDir, found); + args[c++] = strdup(fullpath); + for(i = 1; i < argc; ++i) { + args[c++] = argv[i]; + } + args[c] = NULL; + for(i = 0; args[i]!=NULL; ++i) { + printf("Arg %d = %s\n", i, args[i]); + } + i = _spawnvp(_P_WAIT, args[0], args); + if (i != 0) { + printf("Couldn't execute %s or returned status code != 0\n", fullpath); + exit(-1); + } +#else + c = argc+2; + + if (test) c = c+2; + args = malloc( (c) * sizeof(char*)); + c = 0; + sprintf(monofullpath, "%s/mono", manifestDir); + args[c++] = strdup(monofullpath); + if (test) { + sprintf(fullpath, "%s/nunit-console-runner-exe_exe.exe", manifestDir); + args[c++] = strdup(fullpath); + sprintf(fullpath, "-result=%s", getenv("XML_OUTPUT_FILE")); + args[c++] = strdup(fullpath); + } + sprintf(fullpath, "%s/%s", manifestDir, found); + args[c++] = strdup(fullpath); + for(i = 1; i < argc; ++i) { + args[c++] = argv[i]; + } + args[c] = NULL; + for(i = 0; args[i]!=NULL; ++i) { + printf("Arg %d = %s\n", i, args[i]); + } + for(i = 0; args[i]!=NULL; ++i) { + printf("Arg %d = %s\n", i, args[i]); + } + if (execvp(args[0], args) == -1) { + printf("Couldn't execute %s, (%d)\n", found, errno); + exit(-1); + } +#endif +} + + +int main(int argc, char *argv[], char *envp[]) +{ + const char *manifestDir; + char buffer[64*1024]; + + printf("Launcher running %s (%s)\n", Exe, Nunit); + if (strlen(Exe) > 32*1024) { + printf("File path %s too long\n", Exe); + return -1; + } + manifestDir = GetManifestDir(); + sprintf(buffer, "MONO_PATH=%s", manifestDir); + putenv(buffer); + ReadManifest(manifestDir); + LinkFiles(manifestDir); + RunExe(manifestDir, argc, argv); + + return 0; +} \ No newline at end of file diff --git a/dotnet/tools/test_prep/BUILD b/dotnet/tools/test_prep/BUILD new file mode 100644 index 00000000000000..ab925f76f2cf09 --- /dev/null +++ b/dotnet/tools/test_prep/BUILD @@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "test_prep", + srcs = glob([ + "*.c", + ]), + deps = ["//dotnet/tools/common:common"], +) diff --git a/dotnet/tools/test_prep/main.c b/dotnet/tools/test_prep/main.c new file mode 100644 index 00000000000000..086a8f90a4a868 --- /dev/null +++ b/dotnet/tools/test_prep/main.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef _MSC_VER +#include <direct.h> +#include <windows.h> +#include <Shlwapi.h> +#include <io.h> +#include <process.h> +#define F_OK 0 +#pragma comment(lib, "shlwapi.lib") +#else +#include <unistd.h> +#include <errno.h> +#endif + +#include "dotnet/tools/common/manifest.h" + +extern const char * Exe; + +int main(int argc, char *argv[], char *envp[]) +{ + const char *manifestDir; + printf("Test prep running %s)\n", Exe); + if (strlen(Exe) > 32*1024) { + printf("File path %s too long\n", Exe); + return -1; + } + + manifestDir = GetManifestDir(); + ReadManifest(manifestDir); + LinkFilesTree(manifestDir); + + return 0; +} \ No newline at end of file diff --git a/dotnet/workspace.rst b/dotnet/workspace.rst new file mode 100644 index 00000000000000..ea7834506abb3d --- /dev/null +++ b/dotnet/workspace.rst @@ -0,0 +1,131 @@ +Dotnet workspace rules +====================== + +.. _dotnet_library: core.rst#dotnet_library +.. _toolchains: toolchains.rst +.. _dotnet_register_toolchains: toolchains.rst#dotnet_register_toolchains +.. _dotnet_toolchain: toolchains.rst#dotnet_toolchain +.. _http_archive: https://docs.bazel.build/versions/master/be/workspace.html#http_archive +.. _git_repository: https://docs.bazel.build/versions/master/be/workspace.html#git_repository +.. _nested workspaces: https://bazel.build/designs/2016/09/19/recursive-ws-parsing.html +.. _dotnet_import_library: core.rst#dotnet_import_library + +.. role:: param(kbd) +.. role:: type(emphasis) +.. role:: value(code) +.. |mandatory| replace:: **mandatory value** + +Workspace rules are either repository rules, or macros that are intended to be used from the +WORKSPACE file. + +See also the toolchains_ rules, which contains the dotnet_register_toolchains_ +workspace rule. + +.. contents:: :depth: 1 + +----- + + +dotnet_repositories +~~~~~~~~~~~~~~~~~~~ + +Fetches remote repositories required by dotnet rules. + +dotnet_nuget +~~~~~~~~~~~~ + +A simple repository rule to download and extract nuget package. Using dotnet_nuget_new_ is usually +a better idea. + + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+-----------------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`source` | :type:`string` | :value:`https://www.nuget.org/api/v2/package` | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget base url for downloading the package. The final url is in the format | +| {source}/{package}/{version}. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`package` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package name | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`version` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package version. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`sha256` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package sha256 digest. | ++----------------------------+-----------------------------+-----------------------------------------------+ + + +dotnet_nuget_new +~~~~~~~~~~~~~~~~ + +Repository rule to download and extract nuget package. Usually used with dotnet_import_library_. + + +Attributes +^^^^^^^^^^ + ++----------------------------+-----------------------------+-----------------------------------------------+ +| **Name** | **Type** | **Default value** | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`name` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| A unique name for this rule. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`source` | :type:`string` | :value:`https://www.nuget.org/api/v2/package` | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget base url for downloading the package. The final url is in the format | +| {source}/{package}/{version}. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`package` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package name | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`version` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package version. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`sha256` | :type:`string` | |mandatory| | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The nuget package sha256 digest. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`build_file` | :type:`label` | :value:`None` | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The build file to link into downloaded nnuget package. | ++----------------------------+-----------------------------+-----------------------------------------------+ +| :param:`build_file_content`| :type:`string` | :value:`""` | ++----------------------------+-----------------------------+-----------------------------------------------+ +| The build file content to put into downloaded nnuget package. | ++----------------------------+-----------------------------+-----------------------------------------------+ + +Example +^^^^^^^ + +.. code:: python + + dotnet_nuget_new( + name = "npgsql", + package="Npgsql", + version="3.2.7", + sha256="fa3e0cfbb2caa9946d2ce3d8174031a06320aad2c9e69a60f7739b9ddf19f172", + build_file_content = """ + package(default_visibility = [ "//visibility:public" ]) + load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_import_library") + + dotnet_import_library( + name = "npgsqllib", + src = "lib/net451/Npgsql.dll" + ) + """ + ) diff --git a/examples/example_binary/BUILD b/examples/example_binary/BUILD deleted file mode 100644 index a899294e4d5f72..00000000000000 --- a/examples/example_binary/BUILD +++ /dev/null @@ -1,12 +0,0 @@ -load("//dotnet:csharp.bzl", "csharp_binary") - -csharp_binary( - name = "hello", - srcs = [ - "Program.cs", - "Properties/AssemblyInfo.cs", - ], - deps = [ - "//examples/example_lib:MyClass", - ], -) diff --git a/examples/example_lib/BUILD b/examples/example_lib/BUILD deleted file mode 100644 index 7b5e971e046ed9..00000000000000 --- a/examples/example_lib/BUILD +++ /dev/null @@ -1,14 +0,0 @@ -load("//dotnet:csharp.bzl", "csharp_library") - -csharp_library( - name = "MyClass", - srcs = [ - "MyClass.cs", - "Properties/AssemblyInfo.cs", - ], - resources = [ "hello.txt" ], - visibility = ["//visibility:public"], - deps = [ - "//examples/example_transitive_lib:TransitiveClass", - ], -) diff --git a/examples/example_test/BUILD b/examples/example_test/BUILD deleted file mode 100644 index e00017ab4b2838..00000000000000 --- a/examples/example_test/BUILD +++ /dev/null @@ -1,11 +0,0 @@ -load("//dotnet:csharp.bzl", "csharp_nunit_test") - -csharp_nunit_test( - name = "MyTest", - srcs = [ - "MyTest.cs", - ], - deps = [ - "//examples/example_lib:MyClass", - ], -) diff --git a/index.rst b/index.rst new file mode 100644 index 00000000000000..da6d87380ac721 --- /dev/null +++ b/index.rst @@ -0,0 +1,26 @@ +.. rules_dotnet documentation master file, created by + sphinx-quickstart on Tue May 08 22:36:57 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to rules_dotnet's documentation! +======================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + README + dotnet/core + dotnet/workspace + dotnet/providers + dotnet/toolchains + dotnet/private/skylib/README + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel new file mode 100644 index 00000000000000..cdf7ea22e58329 --- /dev/null +++ b/tests/BUILD.bazel @@ -0,0 +1,9 @@ + +# Consuming the above md5_sum rule directly into the data deps of a sh_test results in the +# files just not appearing, and the dependancy not triggering. +# If we wrap it in a filegroup first however it just works. +filegroup( + name = "rules_dotnet_deps", + srcs = ["//dotnet:all_rules"], + visibility = ["//visibility:public"], +) diff --git a/tests/README.rst b/tests/README.rst new file mode 100644 index 00000000000000..d82e400ef80274 --- /dev/null +++ b/tests/README.rst @@ -0,0 +1,53 @@ +Dotnet rules test suite +======================= + +Main test areas +--------------- + +.. Child list start + +* `Dotnet rules examples <examples/README.rst>`_ +* `Core Dotnet rules tests <core/README.rst>`_ + +.. Child list end + +Adding a new test +----------------- + +All tests in the test suite are expected to obey certain rules. + +They must be documented + Each test folder must contain a README.rst that documents the area of + reponsability for the folder. That README must have a section with + the same name as each of the test rules that documents exactly what the + test is supposed to be checking for. + If the test is in response to a previous issue, the documentation must + also link to the issue being addressed. + +Test one thing at a time + Each test should have a clear and specific responsability, and it should be + as tightly targeted as possible. + Prefer writing multiple tests in a single folder to a single test that + excercises multiple things. + +They must be turned on + Test that do not run by default on the CI machines are not much use, + especially as it's often the only way changes get tested in environments + that are not the one they are authored on, and the rules are very sensitive + to platform specific variations. + +They must not be flakey + We will generally just delete tests that flake, and if features cannot be + tested without flakes we will probably delete the feature as well. + +They must work on all platforms + We support mac, linux and windows, and all our code must work across all + hosts. There are some tests that need to be platform specific, but it's + very rare, and needs a really strong rationale to be accepted. + +They must be as fast as possible + Some tests need to be large and expensive, but most do not. In particular, + downloading large external dependancies to perform a small unit test is not + ok, prefer creating a small local replication of the problem instead. + Anything that requires external dependancies beyond those of the rules + belongs in the integration tests. \ No newline at end of file diff --git a/tests/bazel_tests.bzl b/tests/bazel_tests.bzl new file mode 100644 index 00000000000000..11b1980dfb3ebe --- /dev/null +++ b/tests/bazel_tests.bzl @@ -0,0 +1,294 @@ +load("@io_bazel_rules_dotnet//dotnet/private:common.bzl", "env_execute") +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_context") +load("@io_bazel_rules_dotnet//dotnet/private:rules/launcher_gen.bzl", "dotnet_launcher_gen") + + +# _bazelrc is the bazel.rc file that sets the default options for tests +_bazelrc = """ +build --verbose_failures +build --sandbox_debug +build --test_output=errors +build --spawn_strategy=standalone +build --genrule_strategy=standalone + +test --test_strategy=standalone +test --nocache_test_results + +build:isolate -- +build:fetch --fetch=True +""" + +# _env_build_template is the template for the bazel test environment repository build file +_env_build_template = """ +load("@io_bazel_rules_dotnet//tests:bazel_tests.bzl", "bazel_test_settings") +bazel_test_settings( + name = "settings", + bazel = "{bazel}", + exec_root = "{exec_root}", + scratch_dir = "{scratch_dir}", + visibility = ["//visibility:public"], +) +filegroup( + name = "bazelrc", + srcs = ["test.bazelrc"], + visibility = ["//visibility:public"], +) +""" + +# _bazel_test_script_template is the template for the bazel invocation script +_bazel_test_script_template = """ +set -u + +echo pwd is `pwd` +echo command is {command} +echo running in {work_dir} +unset TEST_TMPDIR +RULES_DOTNET_OUTPUT={output} + +mkdir -p {work_dir} +mkdir -p {cache_dir} +../../{test_prep} +cp -f {workspace} {work_dir}/WORKSPACE +cp -f {build} {work_dir}/BUILD.bazel +cd {work_dir} + +{bazel} --bazelrc {bazelrc} --nomaster_blazerc {command} --config {config} {args} {target} >& bazel-output.txt +result=$? + +function at_exit {{ + echo "bazel exited with status $result" + echo "----- bazel-output.txt begin -----" + cat bazel-output.txt + echo "----- bazel-output.txt end -----" + for log in {logs}; do + if [ ! -e "$log" ]; then + echo "----- $log not found -----" + else + echo "----- $log begin -----" + cat "$log" + echo "----- $log end -----" + fi + done +}} +trap at_exit EXIT + +{check} + +exit $result +""" + +# _basic_workspace is the content appended to all test workspace files +# it contains the calls required to make the dotnet rules work +_basic_workspace = """ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_repositories", "dotnet_register_toolchains") +dotnet_repositories() +""" + + +def _test_environment_impl(ctx): + # Find bazel + bazel = "" + if "BAZEL" in ctx.os.environ: + bazel = ctx.os.environ["BAZEL"] + elif "BAZEL_VERSION" in ctx.os.environ: + home = ctx.os.environ["HOME"] + bazel = home + "/.bazel/{0}/bin/bazel".format(ctx.os.environ["BAZEL_VERSION"]) + if bazel == "" or not ctx.path(bazel).exists: + bazel = ctx.which("bazel") + + # Get a temporary directory to use as our scratch workspace + if ctx.os.name.startswith('windows'): + scratch_dir = ctx.os.environ["TMP"].replace("\\","/") + "/bazel_go_test" + else: + result = env_execute(ctx, ["mktemp", "-d"]) + if result.return_code: + fail("failed to create temporary directory for bazel tests: {}".format(result.stderr)) + scratch_dir = result.stdout.strip() + + # Work out where we are running so we can find externals + exec_root, _, _ = str(ctx.path(".")).rpartition("/external/") + + # build the basic environment + ctx.file("WORKSPACE", 'workspace(name = "{}")'.format(ctx.name)) + ctx.file("BUILD.bazel", _env_build_template.format( + bazel = bazel, + exec_root = exec_root, + scratch_dir = scratch_dir, + )) + ctx.file("test.bazelrc", content=_bazelrc) + +_test_environment = repository_rule( + implementation = _test_environment_impl, + attrs = {}, + environ = [ + "BAZEL", + "BAZEL_VERSION", + "HOME", + ], +) + +def test_environment(): + _test_environment(name="bazel_test") + + +CURRENT_VERSION = "current" + +def _bazel_test_script_impl(ctx): + dotnet = dotnet_context(ctx) + script_file = dotnet.declare_file(dotnet, ext=".bash") + + if not ctx.attr.targets: + # Skip test when there are no targets. Targets may be platform-specific, + # and we may not have any targets on some platforms. + ctx.actions.write(script_file, "", is_executable = True) + return [DefaultInfo(files = depset([script_file]))] + + if ctx.attr.dotnet_version == CURRENT_VERSION: + register = 'dotnet_register_toolchains()\n' + elif ctx.attr.dotnet_version != None: + register = 'dotnet_register_toolchains(dotnet_version="{}")\n'.format(ctx.attr.dotnet_version) + + workspace_content = 'workspace(name = "bazel_test")\n\n' + for ext in ctx.attr.externals: + root = ext.label.workspace_root + _,_,name = ext.label.workspace_root.rpartition("/") + workspace_content += 'local_repository(name="{name}", path="{exec_root}/{root}")\n'.format( + name = name, + root = root, + exec_root = ctx.attr._settings.exec_root, + ) + if ctx.attr.workspace: + workspace_content += ctx.attr.workspace + else: + workspace_content += _basic_workspace.format() + workspace_content += register + + workspace_file = dotnet.declare_file(dotnet, path="WORKSPACE.in") + ctx.actions.write(workspace_file, workspace_content) + build_file = dotnet.declare_file(dotnet, path="BUILD.in") + ctx.actions.write(build_file, ctx.attr.build) + + output = "external/" + ctx.workspace_name + "/" + ctx.label.package + targets = ["@" + ctx.workspace_name + "//" + ctx.label.package + t if t.startswith(":") else t for t in ctx.attr.targets] + logs = [] + if ctx.attr.command in ("test", "coverage"): + # TODO(jayconrod): read logs for other packages + logs = ["bazel-testlogs/{}/{}/test.log".format(output, t[1:]) + for t in ctx.attr.targets if t.startswith(":")] + + script_content = _bazel_test_script_template.format( + test_prep = ctx.attr.test_prep, + bazelrc = ctx.attr._settings.exec_root+"/"+ctx.file._bazelrc.path, + config = ctx.attr.config, + command = ctx.attr.command, + args = " ".join(ctx.attr.args), + target = " ".join(targets), + logs = " ".join(logs), + check = ctx.attr.check, + workspace = workspace_file.short_path, + build = build_file.short_path, + output = output, + bazel = ctx.attr._settings.bazel, + work_dir = ctx.attr._settings.scratch_dir + "/" + ctx.attr.config, + cache_dir = ctx.attr._settings.scratch_dir + "/cache", + ) + ctx.actions.write(output=script_file, is_executable=True, content=script_content) + return struct( + files = depset([script_file]), + runfiles = ctx.runfiles([workspace_file, build_file], collect_data=True) + ) + +_bazel_test_script = rule( + _bazel_test_script_impl, + attrs = { + "command": attr.string( + mandatory = True, + values = [ + "build", + "test", + "coverage", + "run", + ], + ), + "args": attr.string_list(default = []), + "targets": attr.string_list(mandatory = True), + "externals": attr.label_list(allow_files = True), + "dotnet_version": attr.string(default = CURRENT_VERSION), + "workspace": attr.string(), + "build": attr.string(), + "check": attr.string(), + "test_prep": attr.string(), + "config": attr.string(default = "isolate"), + "data": attr.label_list( + allow_files = True, + cfg = "data", + ), + "_bazelrc": attr.label( + allow_files = True, + single_file = True, + default = "@bazel_test//:bazelrc", + ), + "_settings": attr.label(default = Label("@bazel_test//:settings")), + "_dotnet_context_data": attr.label(default = Label("@io_bazel_rules_dotnet//:dotnet_context_data")), + }, + toolchains = ["@io_bazel_rules_dotnet//dotnet:toolchain"], +) + + +def bazel_test(name, command = None, args=None, targets = None, dotnet_version = None, tags=[], externals=[], workspace="", build="", check="", config=None): + script_name = name+"_script" + externals = externals + [ + "@io_bazel_rules_dotnet//:AUTHORS", + ] + #if dotnet_version == None or dotnet_version == CURRENT_VERSION: + # externals.append("@go_sdk//:packages.txt") + + _bazel_test_script( + name = script_name, + command = command, + args = args, + targets = targets, + externals = externals, + dotnet_version = dotnet_version, + workspace = workspace, + build = build, + check = check, + config = config, + test_prep = name + "_test_prep", + ) + + dotnet_launcher_gen(name = "%s_test_prep_gen" % name, exe = script_name) + + native.cc_binary( + name=name + "_test_prep", + srcs = [":%s_test_prep_gen" % name], + deps = ["@io_bazel_rules_dotnet//dotnet/tools/test_prep", "@io_bazel_rules_dotnet//dotnet/tools/common"], + data = [script_name], + ) + native.sh_test( + name = name, + size = "large", + timeout = "moderate", + srcs = [":" + script_name], + tags = ["local", "bazel", "exclusive"] + tags, + data = [ + "@bazel_test//:bazelrc", + "@io_bazel_rules_dotnet//tests:rules_dotnet_deps", + ], + ) + +def _bazel_test_settings_impl(ctx): + return struct( + bazel = ctx.attr.bazel, + exec_root = ctx.attr.exec_root, + scratch_dir = ctx.attr.scratch_dir, + ) + +bazel_test_settings = rule( + _bazel_test_settings_impl, + attrs = { + "bazel": attr.string(mandatory = True), + "exec_root": attr.string(mandatory = True), + "scratch_dir": attr.string(mandatory = True), + }, +) diff --git a/tests/core/README.rst b/tests/core/README.rst new file mode 100644 index 00000000000000..87a2b8759f2164 --- /dev/null +++ b/tests/core/README.rst @@ -0,0 +1,15 @@ +Core dotnet rules tests +======================= + +This contains tests of the core go rules. + +Contents +-------- + +.. Child list start + +* `Basic dotnet_binary functionality <dotnet_binary/README.rst>`_ +* `Basic dotnet_library functionality <dotnet_library/README.rst>`_ + +.. Child list end + diff --git a/tests/core/dotnet_binary/BUILD.bazel b/tests/core/dotnet_binary/BUILD.bazel new file mode 100644 index 00000000000000..0d6f12a3452e1b --- /dev/null +++ b/tests/core/dotnet_binary/BUILD.bazel @@ -0,0 +1,21 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_binary", "dotnet_nunit_test") + +dotnet_binary( + name = "custom_bin", + srcs = [ + "main.cs", + ], + out = "alt_bin.exe", +) + +dotnet_nunit_test( + name = "custom_bin_test", + srcs = [ + "main_test.cs", + ], + deps = [ + "@nunit2//:nunit.framework", + ], + data = [":custom_bin"], + size = "small", +) diff --git a/tests/core/dotnet_binary/README.rst b/tests/core/dotnet_binary/README.rst new file mode 100644 index 00000000000000..ac87581b21869f --- /dev/null +++ b/tests/core/dotnet_binary/README.rst @@ -0,0 +1,11 @@ +Basic dotnet_binary functionality +================================= + +.. _dotnet_binary: /dotnet/core.rst#_dotnet_binary + +Tests to ensure the basic features of dotnet_binary are working as expected. + +custom_bin +---------- + +Test that a dotnet_binary_ rule can write its executable file with a custom name. diff --git a/tests/core/dotnet_binary/main.cs b/tests/core/dotnet_binary/main.cs new file mode 100644 index 00000000000000..c80e1b8cea2b73 --- /dev/null +++ b/tests/core/dotnet_binary/main.cs @@ -0,0 +1,12 @@ +using System; + +namespace example_binary +{ + class MainClass + { + public static void Main(string[] args) + { + Console.WriteLine("Ok"); + } + } +} diff --git a/tests/core/dotnet_binary/main_test.cs b/tests/core/dotnet_binary/main_test.cs new file mode 100644 index 00000000000000..1fa0d11e3a2d45 --- /dev/null +++ b/tests/core/dotnet_binary/main_test.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +using NUnit.Framework; + +namespace example_test +{ + [TestFixture] + public class MyTest + { + [Test] + public void MyTest2() + { + Assert.AreEqual(true, File.Exists("alt_bin.exe")); + } + } +} diff --git a/tests/core/dotnet_library/BUILD.bazel b/tests/core/dotnet_library/BUILD.bazel new file mode 100644 index 00000000000000..fb67b90c00a383 --- /dev/null +++ b/tests/core/dotnet_library/BUILD.bazel @@ -0,0 +1,21 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_library", "dotnet_nunit_test") + +dotnet_library( + name = "custom_bin", + srcs = [ + "main.cs", + ], + out = "alt_bin.dll", +) + +dotnet_nunit_test( + name = "custom_bin_test", + srcs = [ + "main_test.cs", + ], + deps = [ + "@nunit2//:nunit.framework", + ], + data = [":custom_bin"], + size = "small", +) diff --git a/tests/core/dotnet_library/README.rst b/tests/core/dotnet_library/README.rst new file mode 100644 index 00000000000000..956d6856217234 --- /dev/null +++ b/tests/core/dotnet_library/README.rst @@ -0,0 +1,11 @@ +Basic dotnet_library functionality +================================== + +.. _dotnet_library: /dotnet/core.rst#_dotnet_library + +Tests to ensure the basic features of dotnet_library are working as expected. + +custom_bin +---------- + +Test that a dotnet_library_ rule can write its assembly file with a custom name. diff --git a/tests/core/dotnet_library/main.cs b/tests/core/dotnet_library/main.cs new file mode 100644 index 00000000000000..973d61f65edb50 --- /dev/null +++ b/tests/core/dotnet_library/main.cs @@ -0,0 +1,12 @@ +using System; + +namespace example_library +{ + public class MainClass + { + public void Method() + { + Console.WriteLine("Ok"); + } + } +} diff --git a/tests/core/dotnet_library/main_test.cs b/tests/core/dotnet_library/main_test.cs new file mode 100644 index 00000000000000..d9b7f72d2ebc20 --- /dev/null +++ b/tests/core/dotnet_library/main_test.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +using NUnit.Framework; + +namespace example_test +{ + [TestFixture] + public class MyTest + { + [Test] + public void MyTest2() + { + Assert.AreEqual(true, File.Exists("alt_bin.dll")); + } + } +} diff --git a/tests/core/download_sdk/BUILD.bazel b/tests/core/download_sdk/BUILD.bazel new file mode 100644 index 00000000000000..7b26a155c5e464 --- /dev/null +++ b/tests/core/download_sdk/BUILD.bazel @@ -0,0 +1,20 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_binary", "dotnet_nunit_test") +load("@io_bazel_rules_dotnet//tests:bazel_tests.bzl", "bazel_test") + +dotnet_nunit_test( + name = "empty_test", + srcs = [ + "main_test.cs", + ], + deps = [ + "@nunit2//:nunit.framework", + ], + size = "small", +) + +bazel_test( + name = "download_sdk_test", + command = "test", + dotnet_version = "host", + targets = [":empty_test"], +) diff --git a/tests/core/download_sdk/README.rst b/tests/core/download_sdk/README.rst new file mode 100644 index 00000000000000..8ecabf0f0dc478 --- /dev/null +++ b/tests/core/download_sdk/README.rst @@ -0,0 +1,12 @@ +Download sdk functionality +========================== + +.. _dotnet_register_toolchains: /dotnet/core.rst#_dotnet_register_toolchains + +Tests to ensure the basic features of dotnet_register_toolchains_ works downloading sdk (at the moment +only on osx) . + +download_sdk_test +----------------- + +Test that a dotnet_register_toolchains_ can download sdk. diff --git a/tests/core/download_sdk/main.cs b/tests/core/download_sdk/main.cs new file mode 100644 index 00000000000000..c80e1b8cea2b73 --- /dev/null +++ b/tests/core/download_sdk/main.cs @@ -0,0 +1,12 @@ +using System; + +namespace example_binary +{ + class MainClass + { + public static void Main(string[] args) + { + Console.WriteLine("Ok"); + } + } +} diff --git a/tests/core/download_sdk/main_test.cs b/tests/core/download_sdk/main_test.cs new file mode 100644 index 00000000000000..3e84c89bd41fae --- /dev/null +++ b/tests/core/download_sdk/main_test.cs @@ -0,0 +1,16 @@ +using System; +using System.IO; + +using NUnit.Framework; + +namespace example_test +{ + [TestFixture] + public class MyTest + { + [Test] + public void MyTest2() + { + } + } +} diff --git a/tests/examples/example_binary/BUILD b/tests/examples/example_binary/BUILD new file mode 100644 index 00000000000000..73a54100f38a6c --- /dev/null +++ b/tests/examples/example_binary/BUILD @@ -0,0 +1,14 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_binary") + + +dotnet_binary( + name = "hello", + srcs = [ + "Program.cs", + "Properties/AssemblyInfo.cs", + ], + deps = [ + "//tests/examples/example_lib:MyClass", + "@npgsql//:npgsqllib", + ], +) diff --git a/examples/example_binary/Program.cs b/tests/examples/example_binary/Program.cs similarity index 100% rename from examples/example_binary/Program.cs rename to tests/examples/example_binary/Program.cs diff --git a/examples/example_binary/Properties/AssemblyInfo.cs b/tests/examples/example_binary/Properties/AssemblyInfo.cs similarity index 100% rename from examples/example_binary/Properties/AssemblyInfo.cs rename to tests/examples/example_binary/Properties/AssemblyInfo.cs diff --git a/tests/examples/example_lib/BUILD b/tests/examples/example_lib/BUILD new file mode 100644 index 00000000000000..b42fbd98c75fae --- /dev/null +++ b/tests/examples/example_lib/BUILD @@ -0,0 +1,14 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_library") + +dotnet_library( + name = "MyClass", + srcs = [ + "MyClass.cs", + "Properties/AssemblyInfo.cs", + ], + #resources = [ "hello.txt" ], + visibility = ["//visibility:public"], + deps = [ + "//tests/examples/example_transitive_lib:TransitiveClass", + ], +) diff --git a/examples/example_lib/MyClass.cs b/tests/examples/example_lib/MyClass.cs similarity index 100% rename from examples/example_lib/MyClass.cs rename to tests/examples/example_lib/MyClass.cs diff --git a/examples/example_lib/Properties/AssemblyInfo.cs b/tests/examples/example_lib/Properties/AssemblyInfo.cs similarity index 100% rename from examples/example_lib/Properties/AssemblyInfo.cs rename to tests/examples/example_lib/Properties/AssemblyInfo.cs diff --git a/examples/example_lib/hello.txt b/tests/examples/example_lib/hello.txt similarity index 100% rename from examples/example_lib/hello.txt rename to tests/examples/example_lib/hello.txt diff --git a/tests/examples/example_test/BUILD b/tests/examples/example_test/BUILD new file mode 100644 index 00000000000000..17a89a959117ee --- /dev/null +++ b/tests/examples/example_test/BUILD @@ -0,0 +1,13 @@ +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_nunit_test") + +dotnet_nunit_test( + name = "example_test", + srcs = [ + "MyTest.cs", + ], + deps = [ + "//tests/examples/example_lib:MyClass", + "@nunit2//:nunit.framework", + ], + size = "small", +) diff --git a/examples/example_test/MyTest.cs b/tests/examples/example_test/MyTest.cs similarity index 60% rename from examples/example_test/MyTest.cs rename to tests/examples/example_test/MyTest.cs index d5d5d3e5c71879..c033261c21bb2f 100644 --- a/examples/example_test/MyTest.cs +++ b/tests/examples/example_test/MyTest.cs @@ -10,9 +10,10 @@ namespace example_test public class MyTest { [Test] + [ExpectedException( typeof( ArgumentException ) )] public void MyTest1() { - Assert.That("foo", Is.EqualTo("Foo")); + throw new ArgumentException(); } [Test] @@ -20,5 +21,10 @@ public void MyTest2() { Assert.That("bar", Is.EqualTo("bar")); } + [Test] + public void MyTest3() + { + Assert.That(1, Is.EqualTo(1)); + } } } \ No newline at end of file diff --git a/examples/example_tool/BUILD b/tests/examples/example_tool/BUILD similarity index 79% rename from examples/example_tool/BUILD rename to tests/examples/example_tool/BUILD index 1445aee3e4b892..5b459333082334 100644 --- a/examples/example_tool/BUILD +++ b/tests/examples/example_tool/BUILD @@ -1,12 +1,12 @@ -load("//dotnet:csharp.bzl", "csharp_binary") +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_binary") -csharp_binary( +dotnet_binary( name = "hello_tool", srcs = [ "MyTool.cs", ], deps = [ - "//examples/example_lib:MyClass", + "//tests/examples/example_lib:MyClass", ], ) diff --git a/examples/example_tool/MyTool.cs b/tests/examples/example_tool/MyTool.cs similarity index 81% rename from examples/example_tool/MyTool.cs rename to tests/examples/example_tool/MyTool.cs index 1cf8d5647f5391..4fdcd42bf7dcc3 100644 --- a/examples/example_tool/MyTool.cs +++ b/tests/examples/example_tool/MyTool.cs @@ -7,6 +7,7 @@ class MainClass { public static void Main(string[] args) { + Console.WriteLine("Invoked"); if (args.Length == 0) { Console.Error.WriteLine("No output files specified!"); Environment.Exit(1); @@ -14,6 +15,7 @@ public static void Main(string[] args) var mc = new MyClass(); foreach (string output_file in args) { + Console.WriteLine("Generating {0}", output_file); System.IO.File.WriteAllText(output_file, mc.Message); } } diff --git a/examples/example_transitive_lib/BUILD b/tests/examples/example_transitive_lib/BUILD similarity index 66% rename from examples/example_transitive_lib/BUILD rename to tests/examples/example_transitive_lib/BUILD index 6788294ce38e22..761ada3f90b9f6 100644 --- a/examples/example_transitive_lib/BUILD +++ b/tests/examples/example_transitive_lib/BUILD @@ -1,6 +1,6 @@ -load("//dotnet:csharp.bzl", "csharp_library") +load("@io_bazel_rules_dotnet//dotnet:defs.bzl", "dotnet_library") -csharp_library( +dotnet_library( name = "TransitiveClass", srcs = [ "Properties/AssemblyInfo.cs", diff --git a/examples/example_transitive_lib/Properties/AssemblyInfo.cs b/tests/examples/example_transitive_lib/Properties/AssemblyInfo.cs similarity index 100% rename from examples/example_transitive_lib/Properties/AssemblyInfo.cs rename to tests/examples/example_transitive_lib/Properties/AssemblyInfo.cs diff --git a/examples/example_transitive_lib/TransitiveClass.cs b/tests/examples/example_transitive_lib/TransitiveClass.cs similarity index 100% rename from examples/example_transitive_lib/TransitiveClass.cs rename to tests/examples/example_transitive_lib/TransitiveClass.cs