avoid using deprecated `@bazel_tools//src/conditions:host_windows` (#23119) (#23122)

#test-continuous

We here imitate the current practice in bazel-skylib to avoid depending on `@bazel_tools//src/conditions:host_windows`, which is deprecated as of Bazel 8.3.0.

Closes #23116

Closes #23119

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/23119 from dws:host_windows 0e7079aaf0f048b522285e9fd4d91427cced5b6f
FUTURE_COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/23119 from dws:host_windows 0e7079aaf0f048b522285e9fd4d91427cced5b6f
PiperOrigin-RevId: 793844449

Co-authored-by: David Sanderson <32687193+dws@users.noreply.github.com>
diff --git a/python/build_targets.bzl b/python/build_targets.bzl
index b62d5f0..1b09ca0 100644
--- a/python/build_targets.bzl
+++ b/python/build_targets.bzl
@@ -17,7 +17,7 @@
 load("//build_defs:cpp_opts.bzl", "COPTS")
 load("//conformance:defs.bzl", "conformance_test")
 load("//editions:defaults.bzl", "compile_edition_defaults", "embed_edition_defaults")
-load(":internal.bzl", "internal_copy_files", "internal_py_test")
+load(":internal.bzl", "internal_copy_files", "internal_is_windows", "internal_py_test")
 
 def build_targets(name):
     """
@@ -63,6 +63,12 @@
         ],
     )
 
+    # Visibility needs to be public per https://github.com/bazelbuild/bazel-skylib/pull/584
+    internal_is_windows(
+        name = "is_windows",
+        visibility = ["//visibility:public"],
+    )
+
     internal_copy_files(
         name = "copied_wkt_proto_files",
         srcs = [
diff --git a/python/internal.bzl b/python/internal.bzl
index c9be66e..9d498b2 100644
--- a/python/internal.bzl
+++ b/python/internal.bzl
@@ -4,6 +4,22 @@
 
 load("@rules_python//python:py_test.bzl", "py_test")
 
+# Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_common.bzl#L47
+InternalOsInfo = provider(
+    doc = "Information about the target platform's OS.",
+    fields = ["is_windows"],
+)
+
+# Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_common.bzl#L52
+internal_is_windows = rule(
+    implementation = lambda ctx: InternalOsInfo(
+        is_windows = ctx.target_platform_has_constraint(ctx.attr._windows_constraint[platform_common.ConstraintValueInfo]),
+    ),
+    attrs = {
+        "_windows_constraint": attr.label(default = "@platforms//os:windows"),
+    },
+)
+
 def _remove_cross_repo_path(path):
     components = path.split("/")
     if components[0] == "..":
@@ -24,7 +40,9 @@
         dest = ctx.actions.declare_file(short_path[len(strip_prefix):])
         src_dests.append([src, dest])
 
-    if ctx.attr.is_windows:
+    # Windows check adapted from
+    # https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_file_private.bzl#L71C10-L71C54
+    if ctx.attr._exec_is_windows[InternalOsInfo].is_windows:
         bat_file = ctx.actions.declare_file(ctx.label.name + "_copy.bat")
         ctx.actions.write(
             output = bat_file,
@@ -83,7 +101,13 @@
     attrs = {
         "srcs": attr.label_list(allow_files = True, providers = [DefaultInfo]),
         "strip_prefix": attr.string(),
-        "is_windows": attr.bool(),
+        # Adapted from https://github.com/bazelbuild/bazel-skylib/blob/main/rules/private/copy_file_private.bzl#L91C1-L96C7
+        "_exec_is_windows": attr.label(
+            default = ":is_windows",
+            # The exec transition must match the exec group of the actions, which in
+            # this case is the default exec group.
+            cfg = "exec",
+        ),
     },
 )
 
@@ -113,10 +137,6 @@
         name = name,
         srcs = srcs,
         strip_prefix = strip_prefix,
-        is_windows = select({
-            "@bazel_tools//src/conditions:host_windows": True,
-            "//conditions:default": False,
-        }),
         **kwargs
     )