1616load ("@bazel_skylib//lib:paths.bzl" , "paths" )
1717load ("@rules_cc//cc/common:cc_common.bzl" , "cc_common" )
1818load ("@rules_cc//cc/common:cc_info.bzl" , "CcInfo" )
19+ load ("@rules_python_internal//:rules_python_config.bzl" , "config" )
20+ load ("//python/private:py_interpreter_program.bzl" , "PyInterpreterProgramInfo" )
21+ load ("//python/private:toolchain_types.bzl" , "EXEC_TOOLS_TOOLCHAIN_TYPE" )
22+ load (":builders.bzl" , "builders" )
1923load (":cc_helper.bzl" , "cc_helper" )
2024load (":py_cc_link_params_info.bzl" , "PyCcLinkParamsInfo" )
2125load (":py_info.bzl" , "PyInfo" , "PyInfoBuilder" )
@@ -41,6 +45,17 @@ PYTHON_FILE_EXTENSIONS = [
4145 "so" , # Python C modules, usually Linux
4246]
4347
48+ BUILTIN_BUILD_PYTHON_ZIP = [] if config .bazel_10_or_later else [
49+ "//command_line_option:build_python_zip" ,
50+ ]
51+
52+ def maybe_builtin_build_python_zip (value , settings = None ):
53+ settings = settings or {}
54+ if not config .bazel_10_or_later :
55+ settings ["//command_line_option:build_python_zip" ] = value
56+
57+ return settings
58+
4459def create_binary_semantics_struct (
4560 * ,
4661 get_native_deps_dso_name ,
@@ -463,3 +478,136 @@ def collect_deps(ctx, extra_deps = []):
463478 deps = list (deps )
464479 deps .extend (extra_deps )
465480 return deps
481+
482+ def maybe_create_repo_mapping (ctx , * , runfiles ):
483+ """Creates a repo mapping manifest if bzlmod is enabled.
484+
485+ There isn't a way to reference the repo mapping Bazel implicitly
486+ creates, so we have to manually create it ourselves.
487+
488+ Args:
489+ ctx: rule ctx.
490+ runfiles: runfiles object to generate mapping for.
491+
492+ Returns:
493+ File object if the repo mapping manifest was created, None otherwise.
494+ """
495+ if not py_internal .is_bzlmod_enabled (ctx ):
496+ return None
497+
498+ # We have to add `.custom` because `{name}.repo_mapping` is used by Bazel
499+ # internally.
500+ repo_mapping_manifest = ctx .actions .declare_file (ctx .label .name + ".custom.repo_mapping" )
501+ py_internal .create_repo_mapping_manifest (
502+ ctx = ctx ,
503+ runfiles = runfiles ,
504+ output = repo_mapping_manifest ,
505+ )
506+ return repo_mapping_manifest
507+
508+ def actions_run (
509+ ctx ,
510+ * ,
511+ executable ,
512+ toolchain = None ,
513+ ** kwargs ):
514+ """Runs a tool as an action, supporting py_interpreter_program targets.
515+
516+ This is wrapper around `ctx.actions.run()` that sets some useful defaults,
517+ supports handling `py_interpreter_program` targets, and some other features
518+ to let the target being run influence the action invocation.
519+
520+ Args:
521+ ctx: The rule context. The rule must have the
522+ `//python:exec_tools_toolchain_type` toolchain available.
523+ executable: The executable to run. This can be a target that provides
524+ `PyInterpreterProgramInfo` or a regular executable target. If it
525+ provides `testing.ExecutionInfo`, the requirements will be added to
526+ the execution requirements.
527+ toolchain: The toolchain type to use. Must be None or
528+ `//python:exec_tools_toolchain_type`.
529+ **kwargs: Additional arguments to pass to `ctx.actions.run()`.
530+ `mnemonic` and `progress_message` are required.
531+ """
532+ mnemonic = kwargs .pop ("mnemonic" , None )
533+ if not mnemonic :
534+ fail ("actions_run: missing required argument 'mnemonic'" )
535+
536+ progress_message = kwargs .pop ("progress_message" , None )
537+ if not progress_message :
538+ fail ("actions_run: missing required argument 'progress_message'" )
539+
540+ tools = kwargs .pop ("tools" , None )
541+ tools = list (tools ) if tools else []
542+
543+ action_arguments = []
544+ action_env = {
545+ "PYTHONHASHSEED" : "0" , # Helps avoid non-deterministic behavior
546+ "PYTHONNOUSERSITE" : "1" , # Helps avoid non-deterministic behavior
547+ "PYTHONSAFEPATH" : "1" , # Helps avoid incorrect import issues
548+ }
549+ default_info = executable [DefaultInfo ]
550+ action_inputs = builders .DepsetBuilder ()
551+ action_inputs .add (kwargs .pop ("inputs" , None ) or [])
552+ if PyInterpreterProgramInfo in executable :
553+ if toolchain and toolchain != EXEC_TOOLS_TOOLCHAIN_TYPE :
554+ fail (("Action {}: tool {} provides PyInterpreterProgramInfo, which " +
555+ "requires the `toolchain` arg be " +
556+ "None or {}, got: {}" ).format (
557+ mnemonic ,
558+ executable ,
559+ EXEC_TOOLS_TOOLCHAIN_TYPE ,
560+ toolchain ,
561+ ))
562+ exec_runtime = ctx .toolchains [EXEC_TOOLS_TOOLCHAIN_TYPE ].exec_tools .exec_runtime
563+ if exec_runtime .interpreter :
564+ action_exe = exec_runtime .interpreter
565+ action_inputs .add (exec_runtime .files )
566+ elif exec_runtime .interpreter_path :
567+ action_exe = exec_runtime .interpreter_path
568+ else :
569+ fail (("Action {}: PyRuntimeInfo from exec tools toolchain is " +
570+ "malformed: requires one of `interpreter` or " +
571+ "`interpreter_path` set" ).format (
572+ mnemonic ,
573+ ))
574+
575+ program_info = executable [PyInterpreterProgramInfo ]
576+
577+ interpreter_args = ctx .actions .args ()
578+ interpreter_args .add_all (program_info .interpreter_args )
579+ interpreter_args .add (default_info .files_to_run .executable )
580+ action_arguments .append (interpreter_args )
581+
582+ action_env .update (program_info .env )
583+
584+ tools .append (default_info .files_to_run )
585+ toolchain = EXEC_TOOLS_TOOLCHAIN_TYPE
586+ else :
587+ action_exe = executable [DefaultInfo ].files_to_run
588+
589+ execution_requirements = {}
590+ if testing .ExecutionInfo in executable :
591+ execution_requirements .update (executable [testing .ExecutionInfo ].requirements )
592+
593+ # Give precedence to caller's execution requirements.
594+ execution_requirements .update (kwargs .pop ("execution_requirements" , None ) or {})
595+
596+ # Give precedence to caller's env.
597+ action_env .update (kwargs .pop ("env" , None ) or {})
598+
599+ # Handle arguments=None
600+ action_arguments .extend (list (kwargs .pop ("arguments" , None ) or []))
601+
602+ ctx .actions .run (
603+ executable = action_exe ,
604+ arguments = action_arguments ,
605+ tools = tools ,
606+ env = action_env ,
607+ execution_requirements = execution_requirements ,
608+ toolchain = toolchain ,
609+ mnemonic = mnemonic ,
610+ progress_message = progress_message ,
611+ inputs = action_inputs .build (),
612+ ** kwargs
613+ )
0 commit comments