Skip to content

Commit 031ddee

Browse files
committed
using classpath shrinker plugin to warn about indirect dependency usage
1 parent 49fae27 commit 031ddee

File tree

9 files changed

+139
-43
lines changed

9 files changed

+139
-43
lines changed

WORKSPACE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ maven_jar(
2929
sha1 = "e5b3e2753d0817b622c32aedcb888bcf39e275b4")
3030

3131

32+
http_jar(
33+
name = "classpath_shrinker",
34+
url = "file:///Users/natans/work/classpath-shrinker/plugin/target/scala-2.11/classpath-shrinker_2.11-0.1.1.jar",
35+
)

scala/scala.bzl

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def _collect_plugin_paths(plugins):
149149
return paths
150150

151151

152-
def _compile(ctx, cjars, dep_srcjars, buildijar):
152+
def _compile(ctx, cjars, dep_srcjars, buildijar, rjars=[], labels = {}):
153153
ijar_output_path = ""
154154
ijar_cmd_path = ""
155155
if buildijar:
@@ -164,7 +164,11 @@ def _compile(ctx, cjars, dep_srcjars, buildijar):
164164
plugins = _collect_plugin_paths(ctx.attr.plugins)
165165
plugin_arg = ",".join(list(plugins))
166166

167-
compiler_classpath = ":".join([j.path for j in cjars])
167+
all_jars = cjars + rjars
168+
compiler_classpath = ":".join([j.path for j in all_jars])
169+
direct_jars = ":".join([j.path for j in cjars])
170+
indirect_jars = ":".join([j.path for j in rjars])
171+
indirect_targets = ":".join([labels[j.path] for j in rjars])
168172

169173
scalac_args = """
170174
Classpath: {cp}
@@ -186,6 +190,9 @@ ResourceSrcs: {resource_src}
186190
ResourceStripPrefix: {resource_strip_prefix}
187191
ScalacOpts: {scala_opts}
188192
SourceJars: {srcjars}
193+
DirectJars: {direct_jars}
194+
IndirectJars: {indirect_jars}
195+
IndirectTargets: {indirect_targets}
189196
""".format(
190197
out=ctx.outputs.jar.path,
191198
manifest=ctx.outputs.manifest.path,
@@ -209,6 +216,9 @@ SourceJars: {srcjars}
209216
),
210217
resource_strip_prefix=ctx.attr.resource_strip_prefix,
211218
resource_jars=",".join([f.path for f in ctx.files.resource_jars]),
219+
direct_jars=direct_jars,
220+
indirect_jars=indirect_jars,
221+
indirect_targets=indirect_targets
212222
)
213223
argfile = ctx.new_file(
214224
ctx.outputs.jar,
@@ -222,7 +232,7 @@ SourceJars: {srcjars}
222232
# _jdk added manually since _java doesn't currently setup runfiles
223233
# _scalac, as a java_binary, should already have it in its runfiles; however,
224234
# adding does ensure _java not orphaned if _scalac ever was not a java_binary
225-
ins = (list(cjars) +
235+
ins = (list(all_jars) +
226236
list(dep_srcjars) +
227237
list(srcjars) +
228238
list(sources) +
@@ -256,14 +266,14 @@ SourceJars: {srcjars}
256266
)
257267

258268

259-
def _compile_or_empty(ctx, jars, srcjars, buildijar):
269+
def _compile_or_empty(ctx, jars, srcjars, buildijar, transitive_jars, jars2labels):
260270
# We assume that if a srcjar is present, it is not empty
261271
if len(ctx.files.srcs) + len(srcjars) == 0:
262272
_build_nosrc_jar(ctx, buildijar)
263273
# no need to build ijar when empty
264274
return struct(ijar=ctx.outputs.jar, class_jar=ctx.outputs.jar)
265275
else:
266-
_compile(ctx, jars, srcjars, buildijar)
276+
_compile(ctx, jars, srcjars, buildijar, transitive_jars, jars2labels)
267277
ijar = None
268278
if buildijar:
269279
ijar = ctx.outputs.ijar
@@ -357,18 +367,21 @@ def _collect_jars(targets):
357367
"""Compute the runtime and compile-time dependencies from the given targets""" # noqa
358368
compile_jars = depset()
359369
runtime_jars = depset()
370+
jars2labels = {}
360371
for target in targets:
361372
if java_common.provider in target:
362373
java_provider = target[java_common.provider]
363374
compile_jars += java_provider.compile_jars
364375
runtime_jars += java_provider.transitive_runtime_jars
376+
jars2labels.update(dict([(jar.path, target.label)
377+
for jar in (java_provider.compile_jars + java_provider.transitive_runtime_jars)]))
365378
else:
366379
# support http_file pointed at a jar. http_jar uses ijar,
367380
# which breaks scala macros
368381
compile_jars += target.files
369382
runtime_jars += target.files
370383

371-
return struct(compile_jars = compile_jars, transitive_runtime_jars = runtime_jars)
384+
return struct(compile_jars = compile_jars, transitive_runtime_jars = runtime_jars, jars2labels=jars2labels)
372385

373386
# Extract very common code out from dependency analysis into single place
374387
# automatically adds dependency on scala-library and scala-reflect
@@ -377,10 +390,13 @@ def _collect_jars_from_common_ctx(ctx, extra_deps = [], extra_runtime_deps = [])
377390
# Get jars from deps
378391
auto_deps = [ctx.attr._scalalib, ctx.attr._scalareflect]
379392
deps_jars = _collect_jars(ctx.attr.deps + auto_deps + extra_deps)
380-
(cjars, transitive_rjars) = (deps_jars.compile_jars, deps_jars.transitive_runtime_jars)
381-
transitive_rjars += _collect_jars(
382-
ctx.attr.runtime_deps + extra_runtime_deps).transitive_runtime_jars
383-
return struct(compile_jars = cjars, transitive_runtime_jars = transitive_rjars)
393+
(cjars, transitive_rjars, jars2labels) = (deps_jars.compile_jars, deps_jars.transitive_runtime_jars, deps_jars.jars2labels)
394+
395+
runtime_dep_jars = _collect_jars(ctx.attr.runtime_deps + extra_runtime_deps)
396+
transitive_rjars += runtime_dep_jars.transitive_runtime_jars
397+
398+
jars2labels.update(runtime_dep_jars.jars2labels)
399+
return struct(compile_jars = cjars, transitive_runtime_jars = transitive_rjars, jars2labels=jars2labels)
384400

385401
def _lib(ctx, non_macro_lib):
386402
# Build up information from dependency-like attributes
@@ -392,7 +408,7 @@ def _lib(ctx, non_macro_lib):
392408
(cjars, transitive_rjars) = (jars.compile_jars, jars.transitive_runtime_jars)
393409

394410
write_manifest(ctx)
395-
outputs = _compile_or_empty(ctx, cjars, srcjars, non_macro_lib)
411+
outputs = _compile_or_empty(ctx, cjars, srcjars, non_macro_lib, transitive_rjars, jars.jars2labels)
396412

397413
transitive_rjars += [ctx.outputs.jar]
398414

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class CompileOptions {
2323
final public Map<String, String> resourceFiles;
2424
final public String resourceStripPrefix;
2525
final public String[] resourceJars;
26+
final public String[] directJars;
27+
final public String[] indirectJars;
28+
final public String[] indirectTargets;
2629

2730
public CompileOptions(List<String> args) {
2831
Map<String, String> argMap = buildArgMap(args);
@@ -54,6 +57,10 @@ public CompileOptions(List<String> args) {
5457
resourceFiles = getResources(argMap);
5558
resourceStripPrefix = getOrEmpty(argMap, "ResourceStripPrefix");
5659
resourceJars = getCommaList(argMap, "ResourceJars");
60+
61+
directJars = getCommaList(argMap, "DirectJars");
62+
indirectJars = getCommaList(argMap, "IndirectJars");
63+
indirectTargets = getCommaList(argMap, "IndirectTargets");
5764
}
5865

5966
private static Map<String, String> getResources(Map<String, String> args) {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ private static void compileScalaSources(CompileOptions ops, String[] scalaSource
192192
"-classpath",
193193
ops.classpath,
194194
"-d",
195-
tmpPath.toString()
195+
tmpPath.toString(),
196+
"-P:classpath-shrinker:direct-jars:" + String.join(":", ops.directJars),
197+
"-P:classpath-shrinker:indirect-jars:" + String.join(":", ops.indirectJars),
198+
"-P:classpath-shrinker:indirect-targets:" + String.join(":", ops.indirectTargets),
196199
};
197200

198201
String[] compilerArgs = GenericWorker.merge(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package test_expect_logs.missing_direct_deps
2+
3+
object A {
4+
def foo = {
5+
B.foo
6+
C.foo
7+
}
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package test_expect_logs.missing_direct_deps
2+
3+
object B {
4+
def foo = {
5+
C.foo
6+
}
7+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package(default_visibility = ["//visibility:public"])
2+
load("//scala:scala.bzl", "scala_library", "scala_test")
3+
4+
scala_library(
5+
name="transitive_dependency_user",
6+
srcs=[
7+
"A.scala",
8+
],
9+
deps = ["direct_dependency"],
10+
plugins = ["@classpath_shrinker//jar"],
11+
)
12+
13+
scala_library(
14+
name="direct_dependency",
15+
srcs=[
16+
"B.scala",
17+
],
18+
deps = ["transitive_dependency"],
19+
plugins = ["@classpath_shrinker//jar"],
20+
21+
)
22+
23+
scala_library(
24+
name="transitive_dependency",
25+
srcs=[
26+
"C.scala",
27+
],
28+
plugins = ["@classpath_shrinker//jar"],
29+
30+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package test_expect_logs.missing_direct_deps
2+
3+
object C {
4+
def foo = {
5+
println("in C")
6+
}
7+
}

test_run.sh

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ test_scala_library_suite() {
7171
exit 0
7272
}
7373

74+
test_scala_library_expect_warning_on_missing_direct_deps() {
75+
expected_message="target 'transitive_dependency' should be added to deps"
76+
command='bazel build test_expect_logs/missing_direct_deps:transitive_dependency_user'
77+
output=$($command 2>&1)
78+
echo "$output"
79+
echo $output | grep "$expected_message"
80+
if [ $? -ne 0 ]; then
81+
echo "'bazel build test_expect_logs/missing_direct_deps:transitive_dependency_user' should have logged \"$expected_message\"."
82+
exit 1
83+
fi
84+
exit 0
85+
}
86+
7487
test_scala_junit_test_can_fail() {
7588
set +e
7689

@@ -339,34 +352,35 @@ else
339352
runner="run_test_ci"
340353
fi
341354

342-
$runner bazel build test/...
343-
$runner bazel test test/...
344-
$runner bazel run test/src/main/scala/scala/test/twitter_scrooge:justscrooges
345-
$runner bazel run test:JavaBinary
346-
$runner bazel run test:JavaBinary2
347-
$runner bazel run test:MixJavaScalaLibBinary
348-
$runner bazel run test:MixJavaScalaSrcjarLibBinary
349-
$runner bazel run test:ScalaBinary
350-
$runner bazel run test:ScalaLibBinary
351-
$runner test_disappearing_class
352-
$runner find -L ./bazel-testlogs -iname "*.xml"
353-
$runner xmllint_test
354-
$runner test_build_is_identical
355-
$runner test_transitive_deps
356-
$runner test_scala_library_suite
357-
$runner test_repl
358-
$runner bazel run test:JavaOnlySources
359-
$runner test_benchmark_jmh
360-
$runner multiple_junit_suffixes
361-
$runner multiple_junit_prefixes
362-
$runner test_scala_junit_test_can_fail
363-
$runner junit_generates_xml_logs
364-
$runner scala_library_jar_without_srcs_must_fail_on_mismatching_resource_strip_prefix
365-
$runner multiple_junit_patterns
366-
$runner test_junit_test_must_have_prefix_or_suffix
367-
$runner test_junit_test_errors_when_no_tests_found
368-
$runner scala_library_jar_without_srcs_must_include_direct_file_resources
369-
$runner scala_library_jar_without_srcs_must_include_filegroup_resources
370-
$runner bazel run test/src/main/scala/scala/test/large_classpath:largeClasspath
371-
$runner scala_test_test_filters
372-
$runner scala_junit_test_test_filter
355+
$runner test_scala_library_expect_warning_on_missing_direct_deps
356+
#$runner bazel build test/...
357+
#$runner bazel test test/...
358+
#$runner bazel run test/src/main/scala/scala/test/twitter_scrooge:justscrooges
359+
#$runner bazel run test:JavaBinary
360+
#$runner bazel run test:JavaBinary2
361+
#$runner bazel run test:MixJavaScalaLibBinary
362+
#$runner bazel run test:MixJavaScalaSrcjarLibBinary
363+
#$runner bazel run test:ScalaBinary
364+
#$runner bazel run test:ScalaLibBinary
365+
#$runner test_disappearing_class
366+
#$runner find -L ./bazel-testlogs -iname "*.xml"
367+
#$runner xmllint_test
368+
#$runner test_build_is_identical
369+
#$runner test_transitive_deps
370+
#$runner test_scala_library_suite
371+
#$runner test_repl
372+
#$runner bazel run test:JavaOnlySources
373+
#$runner test_benchmark_jmh
374+
#$runner multiple_junit_suffixes
375+
#$runner multiple_junit_prefixes
376+
#$runner test_scala_junit_test_can_fail
377+
#$runner junit_generates_xml_logs
378+
#$runner scala_library_jar_without_srcs_must_fail_on_mismatching_resource_strip_prefix
379+
#$runner multiple_junit_patterns
380+
#$runner test_junit_test_must_have_prefix_or_suffix
381+
#$runner test_junit_test_errors_when_no_tests_found
382+
#$runner scala_library_jar_without_srcs_must_include_direct_file_resources
383+
#$runner scala_library_jar_without_srcs_must_include_filegroup_resources
384+
#$runner bazel run test/src/main/scala/scala/test/large_classpath:largeClasspath
385+
#$runner scala_test_test_filters
386+
#$runner scala_junit_test_test_filter

0 commit comments

Comments
 (0)