Add toolchain_rule to enable rule authors to define toolchains.

Change-Id: I407240708f4aacc89ec5c00bf3e8ff46a1d6d6d6
PiperOrigin-RevId: 152692981
diff --git a/src/create_embedded_tools.sh b/src/create_embedded_tools.sh
index 9a0eee5..0c510ee 100755
--- a/src/create_embedded_tools.sh
+++ b/src/create_embedded_tools.sh
@@ -42,6 +42,7 @@
   case "$i" in
     *tools/jdk/BUILD*) OUTPUT_PATH=tools/jdk/BUILD ;;
     *tools/platforms/platforms.BUILD) OUTPUT_PATH=platforms/BUILD ;;
+    *tools/platforms/*) OUTPUT_PATH=platforms/${i##*/} ;;
     *JavaBuilder*_deploy.jar) OUTPUT_PATH=tools/jdk/${i##*/} ;;
     *JacocoCoverage*_deploy.jar) OUTPUT_PATH=tools/jdk/JacocoCoverage_deploy.jar ;;
     *turbine_deploy.jar) OUTPUT_PATH=tools/jdk/turbine_deploy.jar ;;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformCommon.java b/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformCommon.java
index 147d872..3a67979 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/PlatformCommon.java
@@ -62,7 +62,7 @@
   public ClassObjectConstructor getConstraintValueInfoConstructor() {
     return ConstraintValueInfo.SKYLARK_CONSTRUCTOR;
   }
-
+  
   @SkylarkCallable(
       name = ToolchainInfo.SKYLARK_NAME,
       doc = "The key used to retrieve the provider containing toolchain data.",
diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD
index 8a479e6..ce77f9c 100644
--- a/src/test/shell/bazel/BUILD
+++ b/src/test/shell/bazel/BUILD
@@ -434,6 +434,13 @@
     data = [":test-deps"],
 )
 
+sh_test(
+    name = "toolchain_test",
+    size = "small",
+    srcs = ["toolchain_test.sh"],
+    data = [":test-deps"],
+)
+
 test_suite(
     name = "all_tests",
     visibility = ["//visibility:public"],
diff --git a/src/test/shell/bazel/toolchain_test.sh b/src/test/shell/bazel/toolchain_test.sh
new file mode 100644
index 0000000..fc9b9b1
--- /dev/null
+++ b/src/test/shell/bazel/toolchain_test.sh
@@ -0,0 +1,150 @@
+#!/bin/bash
+#
+# 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.
+#
+# Test the providers and rules related to toolchains.
+#
+
+# Load the test setup defined in the parent directory
+CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+source "${CURRENT_DIR}/../integration_test_setup.sh" \
+  || { echo "integration_test_setup.sh not found!" >&2; exit 1; }
+
+function set_up() {
+  create_new_workspace
+
+  # Create shared constraints.
+  mkdir -p constraints
+  cat >>constraints/BUILD <<EOF
+package(default_visibility = ['//visibility:public'])
+constraint_setting(name = 'os')
+constraint_value(name = 'linux',
+    constraint_setting = ':os')
+constraint_value(name = 'mac',
+    constraint_setting = ':os')
+EOF
+
+  # Create shared report rule for printing info.
+  mkdir report
+  touch report/BUILD
+  cat >>report/report.bzl <<EOF
+def _report_impl(ctx):
+  toolchain = ctx.attr.toolchain[platform_common.ToolchainInfo]
+  for field in ctx.attr.fields:
+    value = getattr(toolchain, field)
+    if type(value) == 'Target':
+      value = value.label
+    print('%s = "%s"' % (field, value))
+
+report_toolchain = rule(
+  _report_impl,
+  attrs = {
+    'fields': attr.string_list(),
+    'toolchain': attr.label(providers = [platform_common.ToolchainInfo]),
+  }
+)
+EOF
+}
+
+function test_toolchain_rule() {
+
+  mkdir -p toolchain
+  cat >> toolchain/toolchain.bzl <<EOF
+load('@bazel_tools//platforms:toolchains.bzl', 'toolchain_rule')
+test_toolchain = toolchain_rule(
+    extra_attrs = {
+       'extra_label': attr.label(),
+       'extra_str': attr.string(),
+    }
+)
+EOF
+
+  cat >> toolchain/BUILD <<EOF
+load('//report:report.bzl', 'report_toolchain')
+load(':toolchain.bzl', 'test_toolchain')
+filegroup(name = 'dep_rule')
+test_toolchain(
+    name = 'linux_toolchain',
+    exec_compatible_with = [
+      '//constraints:linux',
+    ],
+    target_compatible_with = [
+      '//constraints:mac',
+    ],
+    extra_label = ':dep_rule',
+    extra_str = 'bar',
+)
+report_toolchain(
+  name = 'report',
+  fields = ['extra_label', 'extra_str'],
+  toolchain = ':linux_toolchain',
+)
+EOF
+
+  bazel build //toolchain:report &> $TEST_log || fail "Build failed"
+  expect_log 'extra_label = "//toolchain:dep_rule"'
+  expect_log 'extra_str = "bar"'
+}
+
+function test_toolchain_rule_override_impl() {
+
+  mkdir -p toolchain
+  cat >> toolchain/toolchain.bzl <<EOF
+load('@bazel_tools//platforms:toolchains.bzl', 'toolchain_rule', 'default_toolchain_rule_impl')
+def _impl(ctx):
+  overridde_attrs = {
+    'extra_label': 'override:' + ctx.attr.extra_str,
+    'extra_str': 'foo',
+  }
+  return default_toolchain_rule_impl(ctx, overridde_attrs)
+
+test_toolchain = toolchain_rule(
+    implementation = _impl,
+    extra_attrs = {
+       'extra_label': attr.label(),
+       'extra_str': attr.string(),
+    }
+)
+
+EOF
+
+  cat >> toolchain/BUILD <<EOF
+load('//report:report.bzl', 'report_toolchain')
+load(':toolchain.bzl', 'test_toolchain')
+filegroup(name = 'dep_rule')
+test_toolchain(
+    name = 'linux_toolchain',
+    exec_compatible_with = [
+      '//constraints:linux',
+    ],
+    target_compatible_with = [
+      '//constraints:mac',
+    ],
+    extra_label = ':dep_rule',
+    extra_str = 'bar',
+)
+report_toolchain(
+  name = 'report',
+  fields = ['extra_label', 'extra_str'],
+  toolchain = ':linux_toolchain',
+)
+EOF
+
+  bazel build //toolchain:report &> $TEST_log || fail "Build failed"
+  expect_log 'extra_label = "override:bar"'
+  expect_log 'extra_str = "foo"'
+}
+
+run_suite "toolchain tests"