1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- """Common util functions for java_* rules"""
15+ """Common util functions for java_* rules implementations """
1616
1717load ("@bazel_skylib//lib:paths.bzl" , "paths" )
1818load ("@rules_cc//cc:find_cc_toolchain.bzl" , "find_cc_toolchain" )
1919load ("@rules_cc//cc/common:cc_common.bzl" , "cc_common" )
2020load ("//java/common:java_semantics.bzl" , "semantics" )
21+ load ("//java/common/rules:java_helper.bzl" , _loading_phase_helper = "helper" )
2122
2223# copybara: rules_java visibility
2324
@@ -93,7 +94,7 @@ def _primary_class(ctx):
9394 for src in ctx .files .srcs :
9495 if src .basename == main :
9596 return _full_classname (_strip_extension (src ))
96- return _full_classname (_get_relative (ctx .label .package , ctx .label .name ))
97+ return _full_classname (helper . get_relative (ctx .label .package , ctx .label .name ))
9798
9899def _strip_extension (file ):
99100 return file .dirname + "/" + (
@@ -102,41 +103,9 @@ def _strip_extension(file):
102103
103104# TODO(b/193629418): once out of builtins, create a canonical implementation and remove duplicates in depot
104105def _full_classname (path ):
105- java_segments = _java_segments (path )
106+ java_segments = _loading_phase_helper . java_segments (path )
106107 return "." .join (java_segments ) if java_segments != None else None
107108
108- def _java_segments (path ):
109- if path .startswith ("/" ):
110- fail ("path must not be absolute: '%s'" % path )
111- segments = path .split ("/" )
112- root_idx = - 1
113- for idx , segment in enumerate (segments ):
114- if segment in ["java" , "javatests" , "src" , "testsrc" ]:
115- root_idx = idx
116- break
117- if root_idx < 0 :
118- return None
119- is_src = "src" == segments [root_idx ]
120- check_mvn_idx = root_idx if is_src else - 1
121- if (root_idx == 0 or is_src ):
122- for i in range (root_idx + 1 , len (segments ) - 1 ):
123- segment = segments [i ]
124- if "src" == segment or (is_src and (segment in ["java" , "javatests" ])):
125- next = segments [i + 1 ]
126- if next in ["com" , "org" , "net" ]:
127- root_idx = i
128- elif "src" == segment :
129- check_mvn_idx = i
130- break
131-
132- if check_mvn_idx >= 0 and check_mvn_idx < len (segments ) - 2 :
133- next = segments [check_mvn_idx + 1 ]
134- if next in ["main" , "test" ]:
135- next = segments [check_mvn_idx + 2 ]
136- if next in ["java" , "resources" ]:
137- root_idx = check_mvn_idx + 2
138- return segments [(root_idx + 1 ):]
139-
140109def _concat (* lists ):
141110 result = []
142111 for list in lists :
@@ -250,19 +219,8 @@ def _get_java_executable(ctx, java_runtime_toolchain, launcher):
250219 java_executable = ctx .workspace_name + "/" + java_executable
251220 return paths .normalize (java_executable )
252221
253- def _has_target_constraints (ctx , constraints ):
254- # Constraints is a label_list.
255- for constraint in constraints :
256- constraint_value = constraint [platform_common .ConstraintValueInfo ]
257- if ctx .target_platform_has_constraint (constraint_value ):
258- return True
259- return False
260-
261- def _is_target_platform_windows (ctx ):
262- return _has_target_constraints (ctx , ctx .attr ._windows_constraints )
263-
264222def _is_absolute_target_platform_path (ctx , path ):
265- if _is_target_platform_windows (ctx ):
223+ if helper . is_target_platform_windows (ctx ):
266224 return len (path ) > 2 and path [1 ] == ":"
267225 return path .startswith ("/" )
268226
@@ -274,139 +232,6 @@ def _get_test_support(ctx):
274232 return ctx .attr ._test_support
275233 return None
276234
277- def _resource_mapper (file ):
278- root_relative_path = paths .relativize (
279- path = file .path ,
280- start = paths .join (file .root .path , file .owner .workspace_root ),
281- )
282- return "%s:%s" % (
283- file .path ,
284- semantics .get_default_resource_path (root_relative_path , segment_extractor = _java_segments ),
285- )
286-
287- def _create_single_jar (
288- actions ,
289- toolchain ,
290- output ,
291- sources = depset (),
292- resources = depset (),
293- mnemonic = "JavaSingleJar" ,
294- progress_message = "Building singlejar jar %{output}" ,
295- build_target = None ,
296- output_creator = None ):
297- """Register singlejar action for the output jar.
298-
299- Args:
300- actions: (actions) ctx.actions
301- toolchain: (JavaToolchainInfo) The java toolchain
302- output: (File) Output file of the action.
303- sources: (depset[File]) The jar files to merge into the output jar.
304- resources: (depset[File]) The files to add to the output jar.
305- mnemonic: (str) The action identifier
306- progress_message: (str) The action progress message
307- build_target: (Label) The target label to stamp in the manifest. Optional.
308- output_creator: (str) The name of the tool to stamp in the manifest. Optional,
309- defaults to 'singlejar'
310- Returns:
311- (File) Output file which was used for registering the action.
312- """
313- args = actions .args ()
314- args .set_param_file_format ("shell" ).use_param_file ("@%s" , use_always = True )
315- args .add ("--output" , output )
316- args .add_all (
317- [
318- "--compression" ,
319- "--normalize" ,
320- "--exclude_build_data" ,
321- "--warn_duplicate_resources" ,
322- ],
323- )
324- args .add_all ("--sources" , sources )
325- args .add_all ("--resources" , resources , map_each = _resource_mapper )
326-
327- args .add ("--build_target" , build_target )
328- args .add ("--output_jar_creator" , output_creator )
329-
330- actions .run (
331- mnemonic = mnemonic ,
332- progress_message = progress_message ,
333- executable = toolchain .single_jar ,
334- toolchain = semantics .JAVA_TOOLCHAIN_TYPE ,
335- inputs = depset (transitive = [resources , sources ]),
336- tools = [toolchain .single_jar ],
337- outputs = [output ],
338- arguments = [args ],
339- use_default_shell_env = True ,
340- )
341- return output
342-
343- # TODO(hvd): use skylib shell.quote()
344- def _shell_escape (s ):
345- """Shell-escape a string
346-
347- Quotes a word so that it can be used, without further quoting, as an argument
348- (or part of an argument) in a shell command.
349-
350- Args:
351- s: (str) the string to escape
352-
353- Returns:
354- (str) the shell-escaped string
355- """
356- if not s :
357- # Empty string is a special case: needs to be quoted to ensure that it
358- # gets treated as a separate argument.
359- return "''"
360- for c in s .elems ():
361- # We do this positively so as to be sure we don't inadvertently forget
362- # any unsafe characters.
363- if not c .isalnum () and c not in "@%-_+:,./" :
364- return "'" + s .replace ("'" , "'\\ ''" ) + "'"
365- return s
366-
367- def _detokenize_javacopts (opts ):
368- """Detokenizes a list of options to a depset.
369-
370- Args:
371- opts: ([str]) the javac options to detokenize
372-
373- Returns:
374- (depset[str]) depset of detokenized options
375- """
376- return depset (
377- [" " .join ([_shell_escape (opt ) for opt in opts ])],
378- order = "preorder" ,
379- )
380-
381- def _derive_output_file (ctx , base_file , * , name_suffix = "" , extension = None , extension_suffix = "" ):
382- """Declares a new file whose name is derived from the given file
383-
384- This method allows appending a suffix to the name (before extension), changing
385- the extension or appending a suffix after the extension. The new file is declared
386- as a sibling of the given base file. At least one of the three options must be
387- specified. It is an error to specify both `extension` and `extension_suffix`.
388-
389- Args:
390- ctx: (RuleContext) the rule context.
391- base_file: (File) the file from which to derive the resultant file.
392- name_suffix: (str) Optional. The suffix to append to the name before the
393- extension.
394- extension: (str) Optional. The new extension to use (without '.'). By default,
395- the base_file's extension is used.
396- extension_suffix: (str) Optional. The suffix to append to the base_file's extension
397-
398- Returns:
399- (File) the derived file
400- """
401- if not name_suffix and not extension_suffix and not extension :
402- fail ("At least one of name_suffix, extension or extension_suffix is required" )
403- if extension and extension_suffix :
404- fail ("only one of extension or extension_suffix can be specified" )
405- if extension == None :
406- extension = base_file .extension
407- new_basename = paths .replace_extension (base_file .basename , name_suffix + "." + extension + extension_suffix )
408- return ctx .actions .declare_file (new_basename , sibling = base_file )
409-
410235def _is_stamping_enabled (ctx , stamp ):
411236 if ctx .configuration .is_tool_configuration ():
412237 return 0
@@ -416,40 +241,6 @@ def _is_stamping_enabled(ctx, stamp):
416241 # stamp == -1 / auto
417242 return int (ctx .configuration .stamp_binaries ())
418243
419- def _get_relative (path_a , path_b ):
420- if paths .is_absolute (path_b ):
421- return path_b
422- return paths .normalize (paths .join (path_a , path_b ))
423-
424- def _tokenize_javacopts (ctx = None , opts = []):
425- """Tokenizes a list or depset of options to a list.
426-
427- Iff opts is a depset, we reverse the flattened list to ensure right-most
428- duplicates are preserved in their correct position.
429-
430- If the ctx parameter is omitted, a slow, but pure Starlark, implementation
431- of shell tokenization is used. Otherwise, tokenization is performed using
432- ctx.tokenize() which has significantly better performance (up to 100x for
433- large options lists).
434-
435- Args:
436- ctx: (RuleContext|None) the rule context
437- opts: (depset[str]|[str]) the javac options to tokenize
438- Returns:
439- [str] list of tokenized options
440- """
441- if hasattr (opts , "to_list" ):
442- opts = reversed (opts .to_list ())
443- if ctx :
444- return [
445- token
446- for opt in opts
447- for token in ctx .tokenize (opt )
448- ]
449- else :
450- # TODO: optimize and use the pure Starlark implementation in cc_helper
451- return semantics .tokenize_javacopts (opts )
452-
453244helper = struct (
454245 collect_all_targets_as_deps = _collect_all_targets_as_deps ,
455246 filter_launcher_for_target = _filter_launcher_for_target ,
@@ -466,15 +257,14 @@ helper = struct(
466257 get_coverage_config = _get_coverage_config ,
467258 get_java_executable = _get_java_executable ,
468259 is_absolute_target_platform_path = _is_absolute_target_platform_path ,
469- is_target_platform_windows = _is_target_platform_windows ,
260+ is_target_platform_windows = _loading_phase_helper . is_target_platform_windows ,
470261 runfiles_enabled = _runfiles_enabled ,
471262 get_test_support = _get_test_support ,
472- create_single_jar = _create_single_jar ,
473- shell_escape = _shell_escape ,
474- detokenize_javacopts = _detokenize_javacopts ,
475- tokenize_javacopts = _tokenize_javacopts ,
476- derive_output_file = _derive_output_file ,
263+ create_single_jar = _loading_phase_helper .create_single_jar ,
264+ shell_escape = _loading_phase_helper .shell_escape ,
265+ detokenize_javacopts = _loading_phase_helper .detokenize_javacopts ,
266+ tokenize_javacopts = _loading_phase_helper .tokenize_javacopts ,
477267 is_stamping_enabled = _is_stamping_enabled ,
478- get_relative = _get_relative ,
479- has_target_constraints = _has_target_constraints ,
268+ get_relative = _loading_phase_helper . get_relative ,
269+ has_target_constraints = _loading_phase_helper . has_target_constraints ,
480270)
0 commit comments