Skip to content

Commit 936c8ff

Browse files
authored
Fix resource strip prefix (#1476)
1 parent dcfb788 commit 936c8ff

File tree

6 files changed

+197
-30
lines changed

6 files changed

+197
-30
lines changed
Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,77 @@
1-
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary")
1+
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary", "kt_jvm_library", "kt_jvm_test")
22

33
kt_jvm_binary(
44
name = "main",
5-
srcs = glob(["*.kt"]),
5+
srcs = ["Main.kt"],
66
main_class = "MainKt",
77
deps = ["@nested//:printer"],
88
)
9+
10+
# --- Resource libraries for integration testing ---
11+
12+
# Case 1: Source resource WITH resource_strip_prefix
13+
kt_jvm_library(
14+
name = "source_with_prefix",
15+
resource_strip_prefix = "strip_prefix_resources",
16+
resources = ["strip_prefix_resources/source_data.txt"],
17+
)
18+
19+
# Case 2: Source resource WITHOUT resource_strip_prefix (no conventional prefix)
20+
kt_jvm_library(
21+
name = "source_without_prefix",
22+
resources = ["static_resources/source_no_prefix.txt"],
23+
)
24+
25+
# Case 3: Generated resource WITH resource_strip_prefix
26+
genrule(
27+
name = "gen_with_prefix",
28+
outs = ["gen_prefix_out/generated_data.txt"],
29+
cmd = "echo -n 'generated_with_prefix' > $@",
30+
)
31+
32+
kt_jvm_library(
33+
name = "generated_with_prefix",
34+
resource_strip_prefix = "gen_prefix_out",
35+
resources = [":gen_with_prefix"],
36+
)
37+
38+
# Case 4: Generated resource WITHOUT resource_strip_prefix (core bug from #1469)
39+
genrule(
40+
name = "gen_no_prefix",
41+
outs = ["generated_no_prefix.txt"],
42+
cmd = "echo -n 'generated_without_prefix' > $@",
43+
)
44+
45+
kt_jvm_library(
46+
name = "generated_without_prefix",
47+
resources = [":gen_no_prefix"],
48+
)
49+
50+
# Case 5: Generated resource under conventional prefix (src/main/resources/)
51+
genrule(
52+
name = "gen_conventional",
53+
outs = ["src/main/resources/conventional.txt"],
54+
cmd = "echo -n 'generated_conventional' > $@",
55+
)
56+
57+
kt_jvm_library(
58+
name = "generated_conventional_prefix",
59+
resources = [":gen_conventional"],
60+
)
61+
62+
# --- Integration test: verifies resources are at correct classpath paths ---
63+
64+
kt_jvm_test(
65+
name = "resource_test",
66+
srcs = ["ResourceTest.kt"],
67+
main_class = "ResourceTest",
68+
test_class = "ResourceTest",
69+
deps = [
70+
":generated_conventional_prefix",
71+
":generated_with_prefix",
72+
":generated_without_prefix",
73+
":source_with_prefix",
74+
":source_without_prefix",
75+
"@nested//:printer",
76+
],
77+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
object ResourceTest {
2+
private fun loadResource(path: String): String? =
3+
Thread.currentThread().contextClassLoader.getResource(path)?.readText()?.trim()
4+
5+
private fun assertResource(path: String, expected: String, description: String) {
6+
val content = loadResource(path)
7+
check(content != null) { "FAIL [$description]: resource '$path' not found on classpath" }
8+
check(content == expected) {
9+
"FAIL [$description]: expected '$expected' but got '$content'"
10+
}
11+
println("PASS [$description]: '$path' = '$expected'")
12+
}
13+
14+
@JvmStatic
15+
fun main(args: Array<String>) {
16+
assertResource(
17+
"source_data.txt", "source_with_prefix",
18+
"source resource with resource_strip_prefix",
19+
)
20+
assertResource(
21+
"static_resources/source_no_prefix.txt", "source_without_prefix",
22+
"source resource without resource_strip_prefix",
23+
)
24+
assertResource(
25+
"generated_data.txt", "generated_with_prefix",
26+
"generated resource with resource_strip_prefix",
27+
)
28+
assertResource(
29+
"generated_no_prefix.txt", "generated_without_prefix",
30+
"generated resource without resource_strip_prefix (issue #1469)",
31+
)
32+
assertResource(
33+
"conventional.txt", "generated_conventional",
34+
"generated resource under src/main/resources/ conventional prefix",
35+
)
36+
assertResource(
37+
"resource.txt", "world",
38+
"cross-module resource with resource_strip_prefix",
39+
)
40+
println("\nAll resource loading tests passed.")
41+
}
42+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
source_without_prefix
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
source_with_prefix

kotlin/internal/jvm/compile.bzl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,16 @@ def _adjust_resources_path(path, resource_strip_prefix):
164164
else:
165165
return _adjust_resources_path_by_default_prefixes(path)
166166

167+
def _resource_path_relative_to_root(resource):
168+
if not resource.root.path:
169+
return resource.path
170+
171+
root_prefix = resource.root.path + "/"
172+
if resource.path.startswith(root_prefix):
173+
return resource.path[len(root_prefix):]
174+
175+
return resource.path
176+
167177
def _format_compile_plugin_options(o):
168178
"""Format compiler option into id:value for cmd line."""
169179
return [
@@ -298,7 +308,8 @@ def _resourcejar_args_action(ctx, extra_resources = {}):
298308
strip_prefix = ctx.files.resources[0].root.path + "/" + strip_prefix
299309

300310
for f in ctx.files.resources:
301-
target_path = _adjust_resources_path(f.path, strip_prefix)
311+
resource_path = f.path if strip_prefix else _resource_path_relative_to_root(f)
312+
target_path = _adjust_resources_path(resource_path, strip_prefix)
302313
if target_path[0] == "/":
303314
target_path = target_path[1:]
304315
line = "{target_path}={f_path}\n".format(

src/test/starlark/internal/jvm/resource_strip_prefix_test.bzl

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
22
load("@bazel_skylib//rules:write_file.bzl", "write_file")
33
load("//kotlin:jvm.bzl", "kt_jvm_library")
44

5-
def _strip_resource_prefix_test_impl(ctx):
5+
def _resource_path_test_impl(ctx):
66
env = analysistest.begin(ctx)
77

88
actions = analysistest.target_actions(env)
@@ -17,16 +17,14 @@ def _strip_resource_prefix_test_impl(ctx):
1717

1818
arguments = file_write_actions[0].content
1919

20-
pkg = ctx.attr.pkg
21-
2220
# The only line should be of the form:
2321
# data.txt=<some prefix>/<pkg>/resourcez/data.txt
2422
lines = arguments.splitlines()
2523
asserts.equals(env, expected = 1, actual = len(lines))
2624
line_parts = lines[0].split("=", 1)
2725
asserts.equals(env, expected = 2, actual = len(line_parts))
2826
source_path = line_parts[1]
29-
expected_suffix = pkg + "/" + ctx.attr.resource_strip_prefix + "/" + ctx.attr.resource_path
27+
expected_suffix = ctx.attr.expected_source_suffix
3028
asserts.true(
3129
env,
3230
source_path.endswith(expected_suffix),
@@ -35,22 +33,27 @@ def _strip_resource_prefix_test_impl(ctx):
3533

3634
destination_path = line_parts[0]
3735

38-
# The destination path should have the resource_strip_prefix removed
39-
asserts.equals(env, expected = ctx.attr.resource_path, actual = destination_path, msg = "resource_strip_prefix was not applied correctly")
36+
asserts.equals(
37+
env,
38+
expected = ctx.attr.expected_destination_path,
39+
actual = destination_path,
40+
msg = "resource path was not normalized correctly",
41+
)
4042

4143
return analysistest.end(env)
4244

43-
strip_resource_prefix_test = analysistest.make(
44-
_strip_resource_prefix_test_impl,
45+
resource_path_test = analysistest.make(
46+
_resource_path_test_impl,
4547
attrs = {
46-
"pkg": attr.string(),
47-
"resource_path": attr.string(),
48-
"resource_strip_prefix": attr.string(),
48+
"expected_destination_path": attr.string(),
49+
"expected_source_suffix": attr.string(),
4950
},
5051
)
5152

5253
# Macro to setup the test.
5354
def _strip_resource_prefix_contents():
55+
pkg = native.package_name()
56+
5457
write_file(
5558
name = "file",
5659
out = "resourcez/resource.txt",
@@ -63,6 +66,18 @@ def _strip_resource_prefix_contents():
6366
tags = ["manual"],
6467
)
6568

69+
write_file(
70+
name = "generated_default_file",
71+
out = "generated/resource.txt",
72+
tags = ["manual"],
73+
)
74+
75+
write_file(
76+
name = "generated_standard_resource",
77+
out = "src/main/resources/generated_resource.txt",
78+
tags = ["manual"],
79+
)
80+
6681
kt_jvm_library(
6782
name = "dynamically_created_file",
6883
srcs = ["source"],
@@ -86,6 +101,20 @@ def _strip_resource_prefix_contents():
86101
tags = ["manual"],
87102
)
88103

104+
kt_jvm_library(
105+
name = "generated_default_package",
106+
srcs = ["source"],
107+
resources = ["generated_default_file"],
108+
tags = ["manual"],
109+
)
110+
111+
kt_jvm_library(
112+
name = "generated_standard_package",
113+
srcs = ["source"],
114+
resources = ["generated_standard_resource"],
115+
tags = ["manual"],
116+
)
117+
89118
package_name = native.package_name().split("/")[-1]
90119
native.filegroup(
91120
name = package_name,
@@ -100,40 +129,52 @@ def _strip_resource_prefix_contents():
100129
tags = ["manual"],
101130
)
102131

103-
strip_resource_prefix_test(
132+
resource_path_test(
104133
name = "dynamically_created_file_test",
105134
target_under_test = ":dynamically_created_file",
106135
tags = ["manual"],
107-
pkg = native.package_name(),
108-
resource_strip_prefix = "resourcez",
109-
resource_path = "resource.txt",
136+
expected_destination_path = "resource.txt",
137+
expected_source_suffix = pkg + "/resourcez/resource.txt",
110138
)
111139

112-
strip_resource_prefix_test(
140+
resource_path_test(
113141
name = "static_file_test",
114142
target_under_test = ":static_file",
115143
tags = ["manual"],
116-
pkg = native.package_name(),
117-
resource_strip_prefix = "test_resources",
118-
resource_path = "resource.txt",
144+
expected_destination_path = "resource.txt",
145+
expected_source_suffix = pkg + "/test_resources/resource.txt",
119146
)
120147

121-
strip_resource_prefix_test(
148+
resource_path_test(
122149
name = "standard_package_test",
123150
target_under_test = ":standard_package",
124151
tags = ["manual"],
125-
pkg = native.package_name(),
126-
resource_strip_prefix = "src/main/resources",
127-
resource_path = "resource.txt",
152+
expected_destination_path = "resource.txt",
153+
expected_source_suffix = pkg + "/src/main/resources/resource.txt",
128154
)
129155

130-
strip_resource_prefix_test(
156+
resource_path_test(
157+
name = "generated_default_package_test",
158+
target_under_test = ":generated_default_package",
159+
tags = ["manual"],
160+
expected_destination_path = pkg + "/generated/resource.txt",
161+
expected_source_suffix = pkg + "/generated/resource.txt",
162+
)
163+
164+
resource_path_test(
165+
name = "generated_standard_package_test",
166+
target_under_test = ":generated_standard_package",
167+
tags = ["manual"],
168+
expected_destination_path = "generated_resource.txt",
169+
expected_source_suffix = pkg + "/src/main/resources/generated_resource.txt",
170+
)
171+
172+
resource_path_test(
131173
name = "same_as_package_name_test",
132174
target_under_test = ":same_as_package_name",
133175
tags = ["manual"],
134-
pkg = native.package_name(),
135-
resource_strip_prefix = "test_resources",
136-
resource_path = "actual_file.txt",
176+
expected_destination_path = "actual_file.txt",
177+
expected_source_suffix = pkg + "/test_resources/actual_file.txt",
137178
)
138179

139180
# Entry point from the BUILD file; macro for running each test case's macro and
@@ -146,6 +187,8 @@ def strip_resource_prefix_test_suite(name):
146187
name = name,
147188
tests = [
148189
":dynamically_created_file_test",
190+
":generated_default_package_test",
191+
":generated_standard_package_test",
149192
":static_file_test",
150193
":standard_package_test",
151194
":same_as_package_name_test",

0 commit comments

Comments
 (0)