Python: 2to3 is now a write_file, not sh_binary

Now py_* rules no longer depend on a sh_* rule, so
Bazel can analyze them even with
--shell_executable="".

Change-Id: I8e74d86daf385442df9e91c2dc2f7a27b7c4b236

Closes #8187.

Change-Id: I78057362c0f4e761362ae1d363eee9c52d3c1295
PiperOrigin-RevId: 245941481
diff --git a/scripts/bootstrap/compile.sh b/scripts/bootstrap/compile.sh
index db7be55..cd35202 100755
--- a/scripts/bootstrap/compile.sh
+++ b/scripts/bootstrap/compile.sh
@@ -226,7 +226,13 @@
   cat <<EOF >${BAZEL_TOOLS_REPO}/WORKSPACE
 workspace(name = 'bazel_tools')
 EOF
-  link_dir ${PWD}/src ${BAZEL_TOOLS_REPO}/src
+
+  mkdir -p "${BAZEL_TOOLS_REPO}/src/conditions"
+  link_file "${PWD}/src/conditions/BUILD.tools" \
+      "${BAZEL_TOOLS_REPO}/src/conditions/BUILD"
+  link_children "${PWD}" src/conditions "${BAZEL_TOOLS_REPO}"
+  link_children "${PWD}" src "${BAZEL_TOOLS_REPO}"
+
   link_dir ${PWD}/third_party ${BAZEL_TOOLS_REPO}/third_party
 
   # Create @bazel_tools//tools/cpp/runfiles
diff --git a/tools/python/2to3.sh b/tools/python/2to3.sh
deleted file mode 100755
index d87f29e..0000000
--- a/tools/python/2to3.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-exit 1
diff --git a/tools/python/BUILD.tools b/tools/python/BUILD.tools
index 5544e7d..d53871b 100644
--- a/tools/python/BUILD.tools
+++ b/tools/python/BUILD.tools
@@ -1,11 +1,34 @@
 load(":python_version.bzl", "define_python_version_flag")
 load(":toolchain.bzl", "define_autodetecting_toolchain")
 
+# Please do not use write_file.bzl outside of this package.
+# See https://groups.google.com/d/msg/bazel-dev/I8IvJyoyo-s/AttqDcnOCgAJ
+load(":write_file.bzl", "write_file")
+
 package(default_visibility = ["//visibility:public"])
 
-sh_binary(
+write_file(
     name = "2to3",
-    srcs = ["2to3.sh"],
+    out = select({
+        "//src/conditions:host_windows": "2to3.bat",
+        "//conditions:default": "2to3.sh",
+    }),
+    content = select({
+        "//src/conditions:host_windows": [
+            "@echo >&2 ERROR: 2to3 is not implemented.",
+            "@echo >&2 Please either build this target for PY2 or else set srcs_version to PY2ONLY instead of PY2.",
+            "@echo >&2 See https://github.com/bazelbuild/bazel/issues/1393#issuecomment-431110617",
+            "@exit /B 1",
+        ],
+        "//conditions:default": [
+            "#!/bin/bash",
+            "echo >&2 'ERROR: 2to3 is not implemented.'",
+            "echo >&2 'Please either build this target for PY2 or else set srcs_version to PY2ONLY instead of PY2.'",
+            "echo >&2 'See https://github.com/bazelbuild/bazel/issues/1393#issuecomment-431110617'",
+            "exit 1",
+        ],
+    }),
+    is_executable = True,
 )
 
 # This target can be used to inspect the current Python major version. To use,
diff --git a/tools/python/write_file.bzl b/tools/python/write_file.bzl
new file mode 100644
index 0000000..45ec1b6
--- /dev/null
+++ b/tools/python/write_file.bzl
@@ -0,0 +1,95 @@
+# Copyright 2019 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.
+
+"""write_file() rule from bazel-skylib 0.8.0.
+
+This file is a copy of rules/private/write_file_private.bzl [1] with some edits:
+  - this DocString is different
+  - the rule's 'out' attribute does not create a label, so it is select()-able
+
+IMPORTANT: please do not use this rule outside of this package.
+Related discussion here [2].
+
+
+[1] https://github.com/bazelbuild/bazel-skylib/blob/3721d32c14d3639ff94320c780a60a6e658fb033/rules/private/write_file_private.bzl
+
+[2] https://groups.google.com/d/msg/bazel-dev/I8IvJyoyo-s/AttqDcnOCgAJ
+"""
+
+def _common_impl(ctx, is_executable):
+    # ctx.actions.write creates a FileWriteAction which uses UTF-8 encoding.
+    out = ctx.actions.declare_file(ctx.attr.out)
+    ctx.actions.write(
+        output = out,
+        content = "\n".join(ctx.attr.content) if ctx.attr.content else "",
+        is_executable = is_executable,
+    )
+    files = depset(direct = [out])
+    runfiles = ctx.runfiles(files = [out])
+    if is_executable:
+        return [DefaultInfo(files = files, runfiles = runfiles, executable = out)]
+    else:
+        return [DefaultInfo(files = files, runfiles = runfiles)]
+
+def _impl(ctx):
+    return _common_impl(ctx, False)
+
+def _ximpl(ctx):
+    return _common_impl(ctx, True)
+
+_ATTRS = {
+    "content": attr.string_list(mandatory = False, allow_empty = True),
+    "out": attr.string(mandatory = True),
+}
+
+_write_file = rule(
+    implementation = _impl,
+    provides = [DefaultInfo],
+    attrs = _ATTRS,
+)
+
+_write_xfile = rule(
+    implementation = _ximpl,
+    executable = True,
+    provides = [DefaultInfo],
+    attrs = _ATTRS,
+)
+
+def write_file(name, out, content = [], is_executable = False, **kwargs):
+    """Creates a UTF-8 encoded text file.
+
+    Args:
+      name: Name of the rule.
+      out: Path of the output file, relative to this package.
+      content: A list of strings. Lines of text, the contents of the file.
+          Newlines are added automatically after every line except the last one.
+      is_executable: A boolean. Whether to make the output file executable. When
+          True, the rule's output can be executed using `bazel run` and can be
+          in the srcs of binary and test rules that require executable sources.
+      **kwargs: further keyword arguments, e.g. `visibility`
+    """
+    if is_executable:
+        _write_xfile(
+            name = name,
+            content = content,
+            out = out,
+            **kwargs
+        )
+    else:
+        _write_file(
+            name = name,
+            content = content,
+            out = out,
+            **kwargs
+        )