-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathjava_helper.bzl
More file actions
212 lines (187 loc) · 7.14 KB
/
Copy pathjava_helper.bzl
File metadata and controls
212 lines (187 loc) · 7.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# Copyright 2025 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.
"""Common util functions for java_* rules"""
load("@bazel_skylib//lib:paths.bzl", "paths")
load("//java/common:java_semantics.bzl", "semantics")
# copybara: rules_java visibility
def _java_segments(path):
if path.startswith("/"):
fail("path must not be absolute: '%s'" % path)
segments = path.split("/")
root_idx = -1
for idx, segment in enumerate(segments):
if segment in ["java", "javatests", "src", "testsrc"]:
root_idx = idx
break
if root_idx < 0:
return None
is_src = "src" == segments[root_idx]
check_mvn_idx = root_idx if is_src else -1
if (root_idx == 0 or is_src):
for i in range(root_idx + 1, len(segments) - 1):
segment = segments[i]
if "src" == segment or (is_src and (segment in ["java", "javatests"])):
next = segments[i + 1]
if next in ["com", "org", "net"]:
root_idx = i
elif "src" == segment:
check_mvn_idx = i
break
if check_mvn_idx >= 0 and check_mvn_idx < len(segments) - 2:
next = segments[check_mvn_idx + 1]
if next in ["main", "test"]:
next = segments[check_mvn_idx + 2]
if next in ["java", "resources"]:
root_idx = check_mvn_idx + 2
return segments[(root_idx + 1):]
def _has_target_constraints(ctx, constraints):
# Constraints is a label_list.
for constraint in constraints:
constraint_value = constraint[platform_common.ConstraintValueInfo]
if ctx.target_platform_has_constraint(constraint_value):
return True
return False
def _is_target_platform_windows(ctx):
return _has_target_constraints(ctx, ctx.attr._windows_constraints)
def _resource_mapper(file):
root_relative_path = paths.relativize(
path = file.path,
start = paths.join(file.root.path, file.owner.workspace_root),
)
return "%s:%s" % (
file.path,
semantics.get_default_resource_path(root_relative_path, segment_extractor = _java_segments),
)
def _create_single_jar(
actions,
toolchain,
output,
sources = depset(),
resources = depset(),
mnemonic = "JavaSingleJar",
progress_message = "Building singlejar jar %{output}",
build_target = None,
output_creator = None):
"""Register singlejar action for the output jar.
Args:
actions: (actions) ctx.actions
toolchain: (JavaToolchainInfo) The java toolchain
output: (File) Output file of the action.
sources: (depset[File]) The jar files to merge into the output jar.
resources: (depset[File]) The files to add to the output jar.
mnemonic: (str) The action identifier
progress_message: (str) The action progress message
build_target: (Label) The target label to stamp in the manifest. Optional.
output_creator: (str) The name of the tool to stamp in the manifest. Optional,
defaults to 'singlejar'
Returns:
(File) Output file which was used for registering the action.
"""
args = actions.args()
args.set_param_file_format("shell").use_param_file("@%s", use_always = True)
args.add("--output", output)
args.add_all(
[
"--compression",
"--normalize",
"--exclude_build_data",
"--warn_duplicate_resources",
],
)
args.add_all("--sources", sources)
args.add_all("--resources", resources, map_each = _resource_mapper)
args.add("--build_target", build_target)
args.add("--output_jar_creator", output_creator)
actions.run(
mnemonic = mnemonic,
progress_message = progress_message,
executable = toolchain.single_jar,
toolchain = semantics.JAVA_TOOLCHAIN_TYPE,
inputs = depset(transitive = [resources, sources]),
tools = [toolchain.single_jar],
outputs = [output],
arguments = [args],
use_default_shell_env = True,
)
return output
# TODO(hvd): use skylib shell.quote()
def _shell_escape(s):
"""Shell-escape a string
Quotes a word so that it can be used, without further quoting, as an argument
(or part of an argument) in a shell command.
Args:
s: (str) the string to escape
Returns:
(str) the shell-escaped string
"""
if not s:
# Empty string is a special case: needs to be quoted to ensure that it
# gets treated as a separate argument.
return "''"
for c in s.elems():
# We do this positively so as to be sure we don't inadvertently forget
# any unsafe characters.
if not c.isalnum() and c not in "@%-_+:,./":
return "'" + s.replace("'", "'\\''") + "'"
return s
def _detokenize_javacopts(opts):
"""Detokenizes a list of options to a depset.
Args:
opts: ([str]) the javac options to detokenize
Returns:
(depset[str]) depset of detokenized options
"""
return depset(
[" ".join([_shell_escape(opt) for opt in opts])],
order = "preorder",
)
def _get_relative(path_a, path_b):
if paths.is_absolute(path_b):
return path_b
return paths.normalize(paths.join(path_a, path_b))
def _tokenize_javacopts(ctx = None, opts = []):
"""Tokenizes a list or depset of options to a list.
Iff opts is a depset, we reverse the flattened list to ensure right-most
duplicates are preserved in their correct position.
If the ctx parameter is omitted, a slow, but pure Starlark, implementation
of shell tokenization is used. Otherwise, tokenization is performed using
ctx.tokenize() which has significantly better performance (up to 100x for
large options lists).
Args:
ctx: (RuleContext|None) the rule context
opts: (depset[str]|[str]) the javac options to tokenize
Returns:
[str] list of tokenized options
"""
if hasattr(opts, "to_list"):
opts = reversed(opts.to_list())
if ctx:
return [
token
for opt in opts
for token in ctx.tokenize(opt)
]
else:
# TODO: optimize and use the pure Starlark implementation in cc_helper
return semantics.tokenize_javacopts(opts)
helper = struct(
is_target_platform_windows = _is_target_platform_windows,
create_single_jar = _create_single_jar,
shell_escape = _shell_escape,
detokenize_javacopts = _detokenize_javacopts,
tokenize_javacopts = _tokenize_javacopts,
get_relative = _get_relative,
has_target_constraints = _has_target_constraints,
java_segments = _java_segments,
)