diff --git a/README.md b/README.md index bbb1ddb0128d2d..33da0a433b65fb 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ ## 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) __WARNING:__ Theses rules are not compatible with @@ -28,7 +28,7 @@ Add the following to your `WORKSPACE` file to add the external repositories: git_repository( name = "io_bazel_rules_dotnet", remote = "https://github.com/bazelbuild/rules_dotnet.git", - tag = "0.0.1", + tag = "0.0.3", ) load( @@ -46,10 +46,11 @@ nuget_package( ) ``` -The `csharp_repositories` rule fetches external dependencies, namely the NUnit -binaries and the mono repository. Setting `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 +The `csharp_repositories` rule fetches external dependencies, namely +the mono repository, the nuget binary, and the nunit binary. Setting +`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 @@ -93,12 +94,46 @@ file. ```python nuget_package( - name="ndesk_options", # referenced via path @ndesk_options//:ndesk_options + name="ndesk_options", # referenced via path @ndesk_options//:dylibs package="NDesk.Options", version="0.2.1", ) ``` +### 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. diff --git a/dotnet/NUGET_BUILD.tpl b/dotnet/NUGET_BUILD.tpl index 09c1628ee55ab5..e352e165cabdbe 100644 --- a/dotnet/NUGET_BUILD.tpl +++ b/dotnet/NUGET_BUILD.tpl @@ -1,7 +1,7 @@ load("@io_bazel_rules_dotnet//dotnet:csharp.bzl", "dll_import") dll_import( - name = "%{package}", + name = "dylibs", srcs = glob(["**/*.dll"]), visibility = ["//visibility:public"], -) \ No newline at end of file +) diff --git a/dotnet/csharp.bzl b/dotnet/csharp.bzl index f9acc74dea6020..7d62db55218d51 100644 --- a/dotnet/csharp.bzl +++ b/dotnet/csharp.bzl @@ -128,18 +128,20 @@ def _make_nunit_launcher(ctx, depinfo, output): _LAUNCHER_SCRIPT = """\ #!/bin/bash +set -e + if [[ -e "$0.runfiles" ]]; then cd $0.runfiles/{workspace} fi # TODO(jeremy): This is a gross and fragile hack. # We should be able to do better than this. -ln -s -f {workspace}/{exe} $(basename {exe}) +ln -s -f {exe} $(basename {exe}) for l in {libs}; do - ln -s -f {workspace}/$l $(basename {workspace}/$l) + ln -s -f $l $(basename {workspace}/$l) done -{workspace}/{mono_exe} $(basename {exe}) "$@" +{mono_exe} $(basename {exe}) "$@" """ def _make_launcher(ctx, depinfo, output): @@ -412,14 +414,21 @@ dll_import = rule( attrs = _NUGET_ATTRS, ) -def _nuget_package_impl(repository_ctx): +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 = [ - repository_ctx.attr.nuget_bin_path, + mono, + "--config", "%s/../etc/mono/config" % mono.dirname, + nuget, "install", "-Version", repository_ctx.attr.version, "-OutputDirectory", output_dir, @@ -431,48 +440,80 @@ def _nuget_package_impl(repository_ctx): # Lastly we add the nuget package name. nuget_cmd += [repository_ctx.attr.package] # execute nuget download. - repository_ctx.execute(nuget_cmd) - # TODO(jeremy): report errors if there were any - - 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}) - -# This rule is a repository rule and is only usable in WORKSPACE files. -# due to some limitations of repository_rules it does require you to -# tell it where your nuget.exe is located. You may want to manage that binary -# in your repository as a result. + 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"), + ), + # Reference to the nuget.exe file + "nuget_exe":attr.label( + default=Label("@nuget//:nuget.exe"), + ), +} + nuget_package = repository_rule( implementation=_nuget_package_impl, - #local=False, - attrs={ - # TODO(jeremy): use repository_ctx.which("mono") in the impl? - "mono_bin_path":attr.string(default=_MONO_UNIX_BIN), - # Location of the nuget exe - "nuget_bin_path":attr.string(default="/usr/local/bin/nuget"), - # 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), - # content of the BUILD file for this external resource. - }) + attrs=_nuget_package_attrs, +) """Fetches a nuget package as an external dependency. -This rule is a repository rule and is only usable in WORKSPACE files. -due to some current limitations of repository_rules it does require you to -tell it where your nuget.exe is located. You may want to manage that binary -in your repository as a result. +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=_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( @@ -520,6 +561,7 @@ mono_package = repository_rule( 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", @@ -529,4 +571,17 @@ def csharp_repositories(use_local_mono=False): # 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)