Skip to content

Commit beefdfc

Browse files
committed
Windows support - code review fixes
1 parent 73ba62a commit beefdfc

File tree

9 files changed

+156
-116
lines changed

9 files changed

+156
-116
lines changed

scala/private/rule_impls.bzl

Lines changed: 92 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -592,94 +592,102 @@ def _jar_path_based_on_java_bin(ctx):
592592

593593
def _write_executable(ctx, executable, rjars, main_class, jvm_flags, wrapper, use_jacoco):
594594
if (_is_windows(ctx)):
595-
classpath = ";".join(
596-
[("external/%s" % (j.short_path[3:]) if j.short_path.startswith("../") else j.short_path) for j in rjars.to_list()],
595+
return _write_executable_windows(ctx, executable, rjars, main_class, jvm_flags, wrapper, use_jacoco)
596+
else:
597+
return _write_executable_non_windows(ctx, executable, rjars, main_class, jvm_flags, wrapper, use_jacoco)
598+
599+
def _write_executable_windows(ctx, executable, rjars, main_class, jvm_flags, wrapper, use_jacoco):
600+
# NOTE: `use_jacoco` is currently ignored on Windows.
601+
# TODO: tests coverage support for Windows
602+
classpath = ";".join(
603+
[("external/%s" % (j.short_path[3:]) if j.short_path.startswith("../") else j.short_path) for j in rjars.to_list()],
604+
)
605+
jvm_flags_str = ";".join(jvm_flags)
606+
java_for_exe = str(ctx.attr._java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path)
607+
608+
cpfile = ctx.actions.declare_file("%s.classpath" % ctx.label.name)
609+
ctx.actions.write(cpfile, classpath)
610+
611+
ctx.actions.run(
612+
outputs = [executable],
613+
inputs = [cpfile],
614+
executable = ctx.attr._exe.files_to_run.executable,
615+
arguments = [executable.path, ctx.workspace_name, java_for_exe, main_class, cpfile.path, jvm_flags_str],
616+
mnemonic = "ExeLauncher",
617+
progress_message = "Creating exe launcher",
618+
)
619+
return []
620+
621+
def _write_executable_non_windows(ctx, executable, rjars, main_class, jvm_flags, wrapper, use_jacoco):
622+
template = ctx.attr._java_stub_template.files.to_list()[0]
623+
624+
jvm_flags = " ".join(
625+
[ctx.expand_location(f, ctx.attr.data) for f in jvm_flags],
626+
)
627+
628+
javabin = "export REAL_EXTERNAL_JAVA_BIN=${JAVABIN};JAVABIN=%s/%s" % (
629+
_runfiles_root(ctx),
630+
wrapper.short_path,
631+
)
632+
633+
if use_jacoco and _coverage_replacements_provider.is_enabled(ctx):
634+
classpath = ":".join(
635+
["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list() + ctx.files._jacocorunner + ctx.files._lcov_merger],
597636
)
598-
jvm_flags_str = ";".join(jvm_flags)
599-
java_for_exe = str(ctx.attr._java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path)
600-
601-
cpfile = ctx.actions.declare_file("%s.classpath" % ctx.label.name)
602-
ctx.actions.write(cpfile, classpath)
603-
604-
ctx.actions.run(
605-
outputs = [executable],
606-
inputs = [cpfile],
607-
executable = ctx.attr._exe.files_to_run.executable,
608-
arguments = [executable.path, ctx.workspace_name, java_for_exe, main_class, cpfile.path, jvm_flags_str],
609-
mnemonic = "ExeLauncher",
610-
progress_message = "Creating exe launcher",
637+
jacoco_metadata_file = ctx.actions.declare_file(
638+
"%s.jacoco_metadata.txt" % ctx.attr.name,
639+
sibling = executable,
611640
)
612-
return []
641+
ctx.actions.write(jacoco_metadata_file, "\n".join([
642+
jar.short_path.replace("../", "external/")
643+
for jar in rjars
644+
]))
645+
ctx.actions.expand_template(
646+
template = template,
647+
output = executable,
648+
substitutions = {
649+
"%classpath%": classpath,
650+
"%javabin%": javabin,
651+
"%jarbin%": _jar_path_based_on_java_bin(ctx),
652+
"%jvm_flags%": jvm_flags,
653+
"%needs_runfiles%": "",
654+
"%runfiles_manifest_only%": "",
655+
"%workspace_prefix%": ctx.workspace_name + "/",
656+
"%java_start_class%": "com.google.testing.coverage.JacocoCoverageRunner",
657+
"%set_jacoco_metadata%": "export JACOCO_METADATA_JAR=\"$JAVA_RUNFILES/{}/{}\"".format(ctx.workspace_name, jacoco_metadata_file.short_path),
658+
"%set_jacoco_main_class%": """export JACOCO_MAIN_CLASS={}""".format(main_class),
659+
"%set_jacoco_java_runfiles_root%": """export JACOCO_JAVA_RUNFILES_ROOT=$JAVA_RUNFILES/{}/""".format(ctx.workspace_name),
660+
"%set_java_coverage_new_implementation%": """export JAVA_COVERAGE_NEW_IMPLEMENTATION=YES""",
661+
},
662+
is_executable = True,
663+
)
664+
return [jacoco_metadata_file]
613665
else:
614-
template = ctx.attr._java_stub_template.files.to_list()[0]
615-
616-
jvm_flags = " ".join(
617-
[ctx.expand_location(f, ctx.attr.data) for f in jvm_flags],
666+
# RUNPATH is defined here:
667+
# https://github.com/bazelbuild/bazel/blob/0.4.5/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt#L227
668+
classpath = ":".join(
669+
["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list()],
618670
)
619-
620-
javabin = "export REAL_EXTERNAL_JAVA_BIN=${JAVABIN};JAVABIN=%s/%s" % (
621-
_runfiles_root(ctx),
622-
wrapper.short_path,
671+
ctx.actions.expand_template(
672+
template = template,
673+
output = executable,
674+
substitutions = {
675+
"%classpath%": classpath,
676+
"%java_start_class%": main_class,
677+
"%javabin%": javabin,
678+
"%jarbin%": _jar_path_based_on_java_bin(ctx),
679+
"%jvm_flags%": jvm_flags,
680+
"%needs_runfiles%": "",
681+
"%runfiles_manifest_only%": "",
682+
"%set_jacoco_metadata%": "",
683+
"%set_jacoco_main_class%": "",
684+
"%set_jacoco_java_runfiles_root%": "",
685+
"%workspace_prefix%": ctx.workspace_name + "/",
686+
"%set_java_coverage_new_implementation%": """export JAVA_COVERAGE_NEW_IMPLEMENTATION=NO""",
687+
},
688+
is_executable = True,
623689
)
624-
625-
if use_jacoco and _coverage_replacements_provider.is_enabled(ctx):
626-
classpath = ":".join(
627-
["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list() + ctx.files._jacocorunner + ctx.files._lcov_merger],
628-
)
629-
jacoco_metadata_file = ctx.actions.declare_file(
630-
"%s.jacoco_metadata.txt" % ctx.attr.name,
631-
sibling = executable,
632-
)
633-
ctx.actions.write(jacoco_metadata_file, "\n".join([
634-
jar.short_path.replace("../", "external/")
635-
for jar in rjars
636-
]))
637-
ctx.actions.expand_template(
638-
template = template,
639-
output = executable,
640-
substitutions = {
641-
"%classpath%": classpath,
642-
"%javabin%": javabin,
643-
"%jarbin%": _jar_path_based_on_java_bin(ctx),
644-
"%jvm_flags%": jvm_flags,
645-
"%needs_runfiles%": "",
646-
"%runfiles_manifest_only%": "",
647-
"%workspace_prefix%": ctx.workspace_name + "/",
648-
"%java_start_class%": "com.google.testing.coverage.JacocoCoverageRunner",
649-
"%set_jacoco_metadata%": "export JACOCO_METADATA_JAR=\"$JAVA_RUNFILES/{}/{}\"".format(ctx.workspace_name, jacoco_metadata_file.short_path),
650-
"%set_jacoco_main_class%": """export JACOCO_MAIN_CLASS={}""".format(main_class),
651-
"%set_jacoco_java_runfiles_root%": """export JACOCO_JAVA_RUNFILES_ROOT=$JAVA_RUNFILES/{}/""".format(ctx.workspace_name),
652-
"%set_java_coverage_new_implementation%": """export JAVA_COVERAGE_NEW_IMPLEMENTATION=YES""",
653-
},
654-
is_executable = True,
655-
)
656-
return [jacoco_metadata_file]
657-
else:
658-
# RUNPATH is defined here:
659-
# https://github.com/bazelbuild/bazel/blob/0.4.5/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt#L227
660-
classpath = ":".join(
661-
["${RUNPATH}%s" % (j.short_path) for j in rjars.to_list()],
662-
)
663-
ctx.actions.expand_template(
664-
template = template,
665-
output = executable,
666-
substitutions = {
667-
"%classpath%": classpath,
668-
"%java_start_class%": main_class,
669-
"%javabin%": javabin,
670-
"%jarbin%": _jar_path_based_on_java_bin(ctx),
671-
"%jvm_flags%": jvm_flags,
672-
"%needs_runfiles%": "",
673-
"%runfiles_manifest_only%": "",
674-
"%set_jacoco_metadata%": "",
675-
"%set_jacoco_main_class%": "",
676-
"%set_jacoco_java_runfiles_root%": "",
677-
"%workspace_prefix%": ctx.workspace_name + "/",
678-
"%set_java_coverage_new_implementation%": """export JAVA_COVERAGE_NEW_IMPLEMENTATION=NO""",
679-
},
680-
is_executable = True,
681-
)
682-
return []
690+
return []
683691

684692
def _declare_executable(ctx):
685693
if (_is_windows(ctx)):
@@ -1166,7 +1174,7 @@ def scala_test_impl(ctx):
11661174
ctx = ctx,
11671175
executable = executable,
11681176
jvm_flags = [
1169-
"-DRULES_SCALA_WS=%s" % ctx.workspace_name,
1177+
"-DRULES_SCALA_MAIN_WS_NAME=%s" % ctx.workspace_name,
11701178
"-DRULES_SCALA_ARGS_FILE=%s" % argsFile.short_path
11711179
] + ctx.attr.jvm_flags,
11721180
main_class = ctx.attr.main_class,

src/java/io/bazel/rulesscala/exe/BUILD

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ java_library(
55
"LaunchInfo.java",
66
],
77
deps = [
8-
"@bazel_tools//tools/java/runfiles:runfiles",
8+
"@bazel_tools//tools/java/runfiles",
99
"//external:io_bazel_rules_scala/dependency/scala/guava",
1010
],
11-
visibility = ["//visibility:public"],
11+
visibility = ["//visibility:private"],
1212
)
1313

1414
java_binary(
1515
name = "exe",
1616
main_class = "io.bazel.rulesscala.exe.LauncherFileWriter",
17-
visibility = ["//visibility:public"],
1817
runtime_deps = [
1918
":exe-lib",
2019
],
2120
data = [
22-
"@bazel_tools//tools/launcher:launcher",
21+
"@bazel_tools//tools/launcher",
2322
],
23+
visibility = ["//visibility:public"],
2424
)

src/java/io/bazel/rulesscala/exe/LaunchInfo.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
package io.bazel.rulesscala.exe;
1616

17-
import com.google.common.annotations.VisibleForTesting;
1817
import com.google.common.base.Preconditions;
1918
import com.google.common.collect.ImmutableList;
2019
import java.io.IOException;
@@ -41,7 +40,6 @@ public static Builder builder() {
4140
}
4241

4342
/** Writes this object's entries to {@code out}, returns the total written amount in bytes. */
44-
@VisibleForTesting
4543
long write(OutputStream out) throws IOException {
4644
long len = 0;
4745
for (Entry e : entries) {

src/java/io/bazel/rulesscala/scala_test/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ java_library(
44
visibility = ["//visibility:public"],
55
deps = [
66
"//external:io_bazel_rules_scala/dependency/scalatest/scalatest",
7-
"@bazel_tools//tools/java/runfiles:runfiles",
7+
"@bazel_tools//tools/java/runfiles",
88
],
99
)

src/java/io/bazel/rulesscala/scala_test/Runner.java

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@
22

33
import com.google.devtools.build.runfiles.Runfiles;
44
import java.io.IOException;
5+
import java.io.File;
56
import java.util.List;
67
import java.util.Map;
78
import java.nio.charset.Charset;
89
import java.nio.file.Files;
910
import java.nio.file.Paths;
1011

11-
/** This exists only as a proxy for scala tests's runner to provide access to env variables */
12+
/** This exists only as a proxy for scala tests's runner to:
13+
* - provide access to env variables
14+
* - unwrap runner's arguments from a file (passed via file to overcome command-line string limitation on Windows)
15+
**/
1216
public class Runner {
1317
/**
1418
* This is the name of the env var set by bazel when a user provides a `--test_filter` test option
1519
*/
1620
private static final String TESTBRIDGE_TEST_ONLY = "TESTBRIDGE_TEST_ONLY";
1721

1822
/**
19-
* This is the name of the system property used to pass Bazel's workspace name
23+
* This is the name of the system property used to pass the main workspace name
2024
*/
21-
private static final String RULES_SCALA_WS = "RULES_SCALA_WS";
25+
private static final String RULES_SCALA_MAIN_WS_NAME = "RULES_SCALA_MAIN_WS_NAME";
2226

2327
/**
2428
* This is the name of the system property used to pass a short path of the file, which includes
@@ -31,32 +35,26 @@ public static void main(String[] args) throws IOException {
3135
}
3236

3337
private static String[] extendArgs(String[] args, Map<String, String> env) throws IOException {
34-
args = extendFromSystemPropArgs(args);
38+
args = extendFromFileArgs(args);
3539
args = extendFromEnvVar(args, env, TESTBRIDGE_TEST_ONLY, "-s");
3640
return args;
3741
}
3842

39-
private static String[] extendFromSystemPropArgs(String[] args) throws IOException {
40-
String rulesWorkspace = System.getProperty(RULES_SCALA_WS);
41-
if (rulesWorkspace == null || rulesWorkspace.trim().isEmpty())
42-
throw new IllegalArgumentException(RULES_SCALA_WS + " is null or empty.");
43-
44-
String rulesArgsKey = System.getProperty(RULES_SCALA_ARGS_FILE);
45-
if (rulesArgsKey == null || rulesArgsKey.trim().isEmpty())
43+
private static String[] extendFromFileArgs(String[] args) throws IOException {
44+
String runnerArgsFileKey = System.getProperty(RULES_SCALA_ARGS_FILE);
45+
if (runnerArgsFileKey == null || runnerArgsFileKey.trim().isEmpty())
4646
throw new IllegalArgumentException(RULES_SCALA_ARGS_FILE + " is null or empty.");
4747

48-
String rulesArgsPath = Runfiles.create().rlocation(rulesWorkspace + "/" + rulesArgsKey);
49-
if (rulesArgsPath == null)
50-
throw new IllegalArgumentException("rlocation value is null for key: " + rulesArgsKey);
48+
String workspace = System.getProperty(RULES_SCALA_MAIN_WS_NAME);
49+
if (workspace == null || workspace.trim().isEmpty())
50+
throw new IllegalArgumentException(RULES_SCALA_MAIN_WS_NAME + " is null or empty.");
5151

52-
List<String> runnerArgs = Files.readAllLines(Paths.get(rulesArgsPath), Charset.forName("UTF-8"));
52+
String runnerArgsFilePath = Runfiles.create().rlocation(workspace + "/" + runnerArgsFileKey);
53+
if (runnerArgsFilePath == null)
54+
throw new IllegalArgumentException("rlocation value is null for key: " + runnerArgsFileKey);
5355

54-
int runpathFlag = runnerArgs.indexOf("-R");
55-
if (runpathFlag >= 0) {
56-
String runpathKey = runnerArgs.get(runpathFlag + 1);
57-
String runpath = Runfiles.create().rlocation(rulesWorkspace + "/" + runpathKey);
58-
runnerArgs.set(runpathFlag + 1, runpath);
59-
}
56+
List<String> runnerArgs = Files.readAllLines(Paths.get(runnerArgsFilePath), Charset.forName("UTF-8"));
57+
rlocateRunpathValue(workspace, runnerArgs);
6058

6159
String[] runnerArgsArray = runnerArgs.toArray(new String[runnerArgs.size()]);
6260

@@ -73,12 +71,28 @@ private static String[] extendFromEnvVar(
7371
if (value == null) {
7472
return args;
7573
}
76-
;
7774
String[] flag = new String[] {flagName, value};
7875
String[] result = new String[args.length + flag.length];
7976
System.arraycopy(args, 0, result, 0, args.length);
8077
System.arraycopy(flag, 0, result, args.length, flag.length);
8178

8279
return result;
8380
}
81+
82+
/**
83+
* Replaces ScalaTest Runner's runpath elements paths (see http://www.scalatest.org/user_guide/using_the_runner)
84+
* with values from Bazel's runfiles
85+
*/
86+
private static void rlocateRunpathValue(String rulesWorkspace, List<String> runnerArgs) throws IOException {
87+
int runpathFlag = runnerArgs.indexOf("-R");
88+
if (runpathFlag >= 0) {
89+
String[] runpathElements = runnerArgs.get(runpathFlag + 1).split(File.pathSeparator);
90+
Runfiles runfiles = Runfiles.create();
91+
for (int i = 0; i < runpathElements.length; i++) {
92+
runpathElements[i] = runfiles.rlocation(rulesWorkspace + "/" + runpathElements[i]);
93+
}
94+
String runpath = String.join(File.separator, runpathElements);
95+
runnerArgs.set(runpathFlag + 1, runpath);
96+
}
97+
}
8498
}

src/java/io/bazel/rulesscala/scalac/ScalacProcessor.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import scala.tools.nsc.reporters.ConsoleReporter;
2323

2424
class ScalacProcessor implements Processor {
25+
private static boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
26+
2527
/** This is the reporter field for scalac, which we want to access */
2628
private static Field reporterField;
2729

@@ -251,7 +253,7 @@ private static void removeTmp(Path tmp) throws IOException {
251253
@Override
252254
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
253255
throws IOException {
254-
file.toFile().setWritable(true);
256+
if (isWindows) file.toFile().setWritable(true);
255257
Files.delete(file);
256258
return FileVisitResult.CONTINUE;
257259
}
@@ -288,11 +290,12 @@ private static void copyResources(
288290
} else {
289291
dstr = resource.destination;
290292
}
291-
if (dstr.charAt(0) == '/' || dstr.charAt(0) == '\\') {
293+
294+
if (dstr.charAt(0) == '/') {
292295
// we don't want to copy to an absolute destination
293296
dstr = dstr.substring(1);
294297
}
295-
if (dstr.startsWith("../") || dstr.startsWith("..\\")) {
298+
if (dstr.startsWith("../")) {
296299
// paths to external repositories, for some reason, start with a leading ../
297300
// we don't want to copy the resource out of our temporary directory, so
298301
// instead we replace ../ with external/

test/BUILD

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ scala_test_suite(
101101
],
102102
)
103103

104+
scala_test_suite(
105+
name = "LongTestSuiteNamesSuite",
106+
size = "small",
107+
srcs = glob(["longnames/**/*.scala"]),
108+
use_short_names = True,
109+
)
110+
104111
scala_test_suite(
105112
name = "TestSuitePassesKwArgs",
106113
size = "small", # Not a macro, can pass test-specific attributes.

0 commit comments

Comments
 (0)