github.phpd.cn/thought-machine/please@v12.2.0+incompatible/src/parse/rules/misc_rules.build_defs (about)

     1  """Miscellaneous rules that aren't language-specific."""
     2  
     3  
     4  def genrule(name:str, cmd:str|list|dict, srcs:list|dict=None, out:str=None, outs:list|dict=None, deps:list=None,
     5              labels:list&features&tags=None, visibility:list=None, building_description:str='Building...',
     6              hashes:list=None, timeout:int=0, binary:bool=False, sandbox:bool=None,
     7              needs_transitive_deps:bool=False, output_is_complete:bool=True, test_only:bool&testonly=False,
     8              secrets:list=None, requires:list=None, provides:dict=None, pre_build:function=None,
     9              post_build:function=None, tools:list|dict=None):
    10      """A general build rule which allows the user to specify a command.
    11  
    12      Args:
    13        name (str): Name of the rule
    14        cmd (str | dict | list): Command to run.
    15             If given as a string, it's a single command that's used always (the most common case).
    16             If given as a list, it's a sequence of commands run one after another if the
    17             preceding command is successful (i.e. it's equivalent to ' && '.join(cmd)).
    18             If given as a dict, the keys correspond to the build config to run and the values
    19             are the command to run in that config. The typical use case here is 'opt' vs. 'dbg'
    20             but arbitrary names can be given and specified with `plz build -c name`.
    21             See https://please.build/build_rules.html for more information about the sequence
    22             replacements and environment variables that are made available to this rule.
    23        srcs (list | dict): Sources of this rule. Can be a list of files or rules, or a dict of names
    24                            to lists. In the latter case they can be accessed separately which is useful
    25                            to be able to refer to them distinctly in the command.
    26        outs (list | dict): Outputs of this rule. All are files relative to this package.
    27                            If given as a dict, it declares a series of named outputs which work
    28                            similarly to named srcs; they have separate environment variables and
    29                            can be accessed directly by other rules.
    30        out (str): A single output of this rule, as a string. Discouraged in favour of 'outs'.
    31        deps (list): Dependencies of this rule.
    32        tools (list | dict): Tools used to build this rule; similar to srcs but are not copied to the
    33                             temporary build directory. Should be accessed via $(exe //path/to:tool)
    34                             or similar.
    35                             Entries that are not build labels are assumed to be system-level commands
    36                             and resolved within the path given in the config file (note that the
    37                             value of $PATH in the outside environment is not propagated to the build
    38                             rule).
    39                             If tools is given as a dict then the keys of the dict name the various
    40                             tools and they can be accessed with $TOOLS_KEY.
    41        secrets (list): Files containing secrets (credentials etc) used to build this rule. These are
    42                        all absolute paths (beginning with / or ~) and are not copied to the build
    43                        directory. They can be accessed through the environment variable $SECRETS.
    44                        They don't contribute to the key used to retrieve outputs from the cache; this
    45                        means it's possible for one machine to build a target with the secret and then
    46                        share the output with others. That also implies that secrets are things like
    47                        credentials or signing keys and shouldn't be copied directly to outputs, otherwise
    48                        they might become more widely known.
    49        labels (list): Labels to apply to this rule.
    50        visibility (list): Visibility declaration of this rule
    51        building_description (str): Description to display to the user while the rule is building.
    52        hashes (list): List of hashes; if given the outputs must match one of these. They can be
    53                optionally preceded by their method. Currently the only supported method is sha1.
    54        timeout (int): Maximum time in seconds this rule can run for before being killed.
    55        binary (bool): True to mark a rule that produces a runnable output. Its output will be placed into
    56                plz-out/bin instead of plz-out/gen and can be run with 'plz run'. Binary rules
    57                can only have a single output.
    58        sandbox (bool): If True, the build action is sandboxed within a separate network and process
    59                        namespace. Only works on Linux and requires plz_sandbox to be installed
    60                        separately.
    61                        If False, it opts the target out of sandboxing when that is turned on.
    62        needs_transitive_deps (bool): If True, all transitive dependencies of the rule will be made
    63                               available to it when it builds (although see below...). By default
    64                               rules only get their immediate dependencies.
    65        output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive
    66                            dependencies by other rules (ie. it will be available to them, but not
    67                            its dependencies as well).
    68        test_only (bool): If True it can only be used by test rules.
    69        requires (list): A list of arbitrary strings that define kinds of output that this rule might want.
    70                  See 'provides' for more detail; it's mostly useful to match up rules with multiple
    71                  kinds of output with ones that only need one of them, eg. a proto_library with
    72                  a python_library that doesn't want the C++ or Java proto outputs.
    73                  Entries in 'requires' are also implicitly labels on the rule.
    74        provides (dict): A map of arbitrary strings to dependencies of the rule that provide some specific
    75                  type of thing. For example:
    76                    provides = {'py': ':python_rule', 'go': ':go_rule'},
    77                  A Python rule would have requires = ['py'] and so if it depended on a rule like
    78                  this it would pick up a dependency on :python_rule instead. See the proto rules
    79                  for an example of where this is useful.
    80                  Note that the keys of provides and entries in requires are arbitrary and
    81                  have no effect until a matched pair meet one another.
    82        pre_build (function): A function to be executed immediately before the rule builds. It receives one
    83                   argument, the name of the building rule. This is mostly useful to interrogate
    84                   the metadata of dependent rules which isn't generally available at parse time;
    85                   see the get_labels function for a motivating example.
    86        post_build (function): A function to be executed immediately after the rule builds. It receives two
    87                    arguments, the rule name and its command line output.
    88                    This is significantly more useful than the pre_build function, it can be used
    89                    to dynamically create new rules based on the output of another.
    90      """
    91      if out and outs:
    92          raise TypeError('Can\'t specify both "out" and "outs".')
    93      return build_rule(
    94          name=name,
    95          srcs=srcs,
    96          outs=[out] if out else outs,
    97          cmd=' && '.join(cmd) if isinstance(cmd, list) else cmd,
    98          deps=deps,
    99          tools=tools,
   100          secrets=secrets,
   101          labels=labels,
   102          visibility = visibility,
   103          output_is_complete=output_is_complete,
   104          building_description=building_description,
   105          hashes=hashes,
   106          post_build=post_build,
   107          binary=binary,
   108          sandbox=sandbox,
   109          build_timeout=timeout,
   110          needs_transitive_deps=needs_transitive_deps,
   111          requires=requires,
   112          provides=provides,
   113          test_only=test_only,
   114      )
   115  
   116  
   117  def gentest(name:str, test_cmd:str|dict, labels:list&features&tags=None, cmd:str|dict=None, srcs:list|dict=None, outs:list=None,
   118              deps:list=None, tools:list|dict=None, data:list=None, visibility:list=None, timeout:int=0,
   119              needs_transitive_deps:bool=False, flaky:bool|int=0, secrets:list=None, no_test_output:bool=False,
   120              output_is_complete:bool=True, requires:list=None, container:bool|dict=False, sandbox:bool=None,
   121              size:str=''):
   122      """A rule which creates a test with an arbitrary command.
   123  
   124      The command must return zero on success and nonzero on failure. Test results are written
   125      to test.results (or not if no_test_output is True).
   126      Most arguments are similar to genrule() so we cover them in less detail here.
   127  
   128      Args:
   129        name (str): Name of the rule
   130        test_cmd (str | dict): Command to run for the test. It works similarly to the cmd attribute;
   131                               see genrule for a more detailed discussion of its properties.
   132        labels (list): Labels to apply to this test.
   133        cmd (str | dict): Command to run to build the test.
   134        srcs (list | dict): Source files for this rule.
   135        outs (list): Output files of this rule.
   136        deps (list): Dependencies of this rule.
   137        tools (list): Tools used to build this rule; similar to srcs but are not copied to the temporary
   138                      build directory. Should be accessed via $(exe //path/to:tool) or similar.
   139        secrets (list): Secrets available to this rule while building.
   140        data (list): Runtime data files for the test.
   141        visibility (list): Visibility declaration of this rule.
   142        timeout (int): Length of time in seconds to allow the test to run for before killing it.
   143        needs_transitive_deps (bool): True if building the rule requires all transitive dependencies to
   144                               be made available.
   145        flaky (bool | int): If true the test will be marked as flaky and automatically retried.
   146        no_test_output (bool): If true the test is not expected to write any output results, it's only
   147                        judged on its return value.
   148        output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive
   149                            dependencies by other rules.
   150        requires (list): Kinds of output from other rules that this one requires.
   151        container (bool | dict): If true the test is run in a container (eg. Docker).
   152        sandbox (bool): If True, the test is run within a sandbox that restricts some cgroups
   153                        including networking, process, IPC, etc. Only has an effect on Linux.
   154                        If this is on by default then tests can opt out by setting this to False.
   155        size (str): Test size (enormous, large, medium or small).
   156      """
   157      timeout, labels = _test_size_and_timeout(size, timeout, labels)
   158      return build_rule(
   159          name=name,
   160          srcs=srcs,
   161          outs=outs,
   162          deps=deps,
   163          data=data,
   164          tools=tools,
   165          secrets=secrets,
   166          test_cmd = test_cmd,
   167          cmd=cmd or 'true',  # By default, do nothing
   168          visibility=visibility,
   169          output_is_complete=output_is_complete,
   170          labels=labels,
   171          binary=True,
   172          test=True,
   173          test_timeout=timeout,
   174          needs_transitive_deps=needs_transitive_deps,
   175          requires=requires,
   176          container=container,
   177          test_sandbox=sandbox,
   178          no_test_output=no_test_output,
   179          flaky=flaky,
   180      )
   181  
   182  
   183  def export_file(name:str, src:str, visibility:list=None, binary:bool=False, test_only:bool&testonly=False):
   184      """Essentially a single-file alias for filegroup.
   185  
   186      Args:
   187        name (str): Name of the rule
   188        src (str): Source file for the rule
   189        visibility (list): Visibility declaration
   190        binary (bool): True to mark the rule outputs as binary
   191        test_only (bool): If true the exported file can only be used by test targets.
   192      """
   193      filegroup(
   194          name = name,
   195          srcs = [src],
   196          visibility = visibility,
   197          binary = binary,
   198          test_only = test_only,
   199      )
   200  
   201  
   202  def filegroup(name:str, tag:str='', srcs:list=None, deps:list=None, exported_deps:list=None,
   203                visibility:list=None, labels:list&features&tags=None, binary:bool=False, output_is_complete:bool=True,
   204                requires:list=None, provides:dict=None, hashes:list=None, test_only:bool&testonly=False):
   205      """Defines a collection of files which other rules can depend on.
   206  
   207      Sources can be omitted entirely in which case it acts simply as a rule to collect other rules,
   208      which is often more handy than you might think.
   209  
   210      Args:
   211        name (str): Name of the rule
   212        tag (str): Tag applied to name; generates a private rule, for example name='a',tag='b' gives
   213                   _a#b. Typically used for "private" rules.
   214        srcs (list): Source files for the rule.
   215        deps (list): Dependencies of the rule.
   216        exported_deps (list): Dependencies that will become visible to any rules that depend on this rule.
   217        visibility (list): Visibility declaration
   218        labels (list): Labels to apply to this rule
   219        binary (bool): True to mark the rule outputs as binary
   220        output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive
   221                                   dependencies by other rules.
   222        requires (list): Kinds of output from other rules that this one requires.
   223        provides (dict): Kinds of output that this provides for other rules (see genrule() for a more
   224                         in-depth discussion of this).
   225        hashes (list): List of acceptable output hashes for this rule.
   226        test_only (bool): If true the exported file can only be used by test targets.
   227      """
   228      return build_rule(
   229          name=name,
   230          tag=tag,
   231          cmd='',
   232          srcs=srcs,
   233          deps=deps,
   234          exported_deps=exported_deps,
   235          visibility=visibility,
   236          building_description='Copying...',
   237          output_is_complete=output_is_complete,
   238          requires=requires,
   239          provides=provides,
   240          test_only=test_only,
   241          labels=labels,
   242          binary=binary,
   243          hashes=hashes,
   244          _filegroup=True,
   245      )
   246  
   247  
   248  def hash_filegroup(name:str, srcs:list=None, deps:list=None, exported_deps:list=None, visibility:list=None,
   249                     labels:list&features&tags=None, test_only:bool&testonly=False, requires:list=None):
   250      """Copies a set of files to output names which are uniquely hashed based on their contents.
   251  
   252      For example, srcs = ["test.txt"] might output "test-b250cnf30f3h.txt".
   253  
   254      Args:
   255        name (str): Name of the rule.
   256        srcs (list): Source files for the rule.
   257        deps (list): Dependencies of the rule.
   258        exported_deps (list): Dependencies that will become visible to any rules that depend on this rule.
   259        visibility (list): Visibility declaration
   260        labels (list): Labels to apply to this rule
   261        test_only (bool): If true the exported file can only be used by test targets.
   262        requires (list): Kinds of output from other rules that this one requires.
   263      """
   264      return build_rule(
   265          name=name,
   266          srcs=srcs,
   267          cmd='',
   268          deps=deps,
   269          exported_deps=exported_deps,
   270          visibility=visibility,
   271          building_description='Copying...',
   272          output_is_complete=True,
   273          test_only=test_only,
   274          labels=labels,
   275          requires=requires,
   276          _hash_filegroup=True,
   277      )
   278  
   279  
   280  def system_library(name:str, srcs:list, deps:list=None, hashes:list=None,
   281                     visibility:list=None, test_only:bool&testonly=False):
   282      """Defines a rule to collect some dependencies from outside the build tree.
   283  
   284      This is essentially the same as a filegroup; it will simply copy files from the system
   285      into the build tree, you must add additional rules if compilation is necessary.
   286  
   287      Args:
   288        name (str): Name of the rule.
   289        srcs (list): System-level sources. Should all be absolute paths.
   290        deps (list): Dependencies of the rule.
   291        hashes (list): List of hashes; the output must match at least one of these. This is not required
   292                       but could be used to assert that the system lib is of some known version.
   293        visibility (list): Visibility declaration of the rule.
   294        test_only (bool): If true the rule is only visible to test targets.
   295      """
   296      build_rule(
   297          name = name,
   298          system_srcs = srcs,
   299          outs = [basename(src) for src in srcs],
   300          deps = deps,
   301          cmd = 'cp $SRCS .',
   302          hashes = hashes,
   303          visibility = visibility,
   304          test_only = test_only,
   305          sandbox = False,
   306      )
   307  
   308  
   309  def remote_file(name:str, url:str|list, hashes:list=None, out:str=None, binary:bool=False,
   310                  visibility:list=None, licences:list=None, test_only:bool&testonly=False,
   311                  labels:list=[], deps:list=None, exported_deps:list=None, _tag=''):
   312      """Defines a rule to fetch a file over HTTP(S).
   313  
   314      Args:
   315        name (str): Name of the rule
   316        url (str | list): URL or URLs to fetch. If multiple are passed then they will be tried
   317                          in sequence until one succeeds.
   318        hashes (list): List of hashes; the output must match at least one of these.
   319        out (str): Output name of the file. Chosen automatically if not given.
   320        binary (bool): True to mark the output as binary and runnable.
   321        visibility (list): Visibility declaration of the rule.
   322        licences (list): List of licences that apply to this rule.
   323        test_only (bool): If true the rule is only visible to test targets.
   324        deps (list): List of extra dependencies for this rule.
   325        exported_deps (list): Dependencies that will become visible to any rules that depend on this rule.
   326      """
   327      urls = [url] if isinstance(url, str) else url
   328      url = urls[0]
   329      return build_rule(
   330          name = name,
   331          tag = _tag,
   332          cmd = '',
   333          _urls = urls,
   334          outs = [out or url[url.rfind('/') + 1:]],
   335          binary = binary,
   336          visibility = visibility,
   337          hashes = hashes,
   338          licences = licences,
   339          building_description = 'Fetching...',
   340          deps = deps,
   341          exported_deps = exported_deps,
   342          test_only = test_only,
   343          labels = labels,
   344          sandbox = False,
   345      )
   346  
   347  
   348  def tarball(name:str, srcs:list, out:str=None, deps:list=None, subdir:str=None, gzip:bool=True,
   349              visibility:list=None, labels:list&features&tags=[]):
   350      """Defines a rule to create a tarball containing outputs of other rules.
   351  
   352      File mode and ownership are preserved. However, the atime and mtime of all
   353      files will be set to 1 Jan 1970 00:00:00.
   354  
   355      Args:
   356        name (str): Rule name
   357        srcs (list): Source files to include in the tarball
   358        out (str): Name of output tarball (defaults to `name`.tar.gz, but see below re compression)
   359        subdir (str): Subdirectory to create in. All files will be flattened into this directory.
   360        gzip (bool): If True, the output will be gzipped. If False, it will just be a tarball.
   361        deps (list): Dependencies
   362        visibility (list): Visibility specification.
   363        labels (list): Labels associated with this rule.
   364      """
   365      out = out or (name + ('.tar.gz' if gzip else '.tar'))
   366      cmd = '$TOOL tar '
   367      if gzip:
   368          cmd += ' -z'
   369      if subdir:
   370          cmd += ' --prefix ' + subdir
   371  
   372      return build_rule(
   373          name = name,
   374          cmd = cmd,
   375          srcs = srcs,
   376          tools = [CONFIG.JARCAT_TOOL],
   377          outs = [out],
   378          deps = deps,
   379          visibility = visibility,
   380          labels = labels + ['tar'],
   381          output_is_complete = True,
   382      )
   383  
   384  
   385  def decompose(label:str):
   386      """Decomposes a build label into the package and name parts.
   387  
   388      Consider carefully when you should use this - command replacements may be more appropriate.
   389      Most rules should be able to accept labels without having to know anything about their structure.
   390  
   391      Args:
   392        label (str): A build label in either relative or absolute form.
   393      Raises:
   394        ValueError: if the given label is not a correctly formatted build label.
   395      """
   396      if label.startswith(':'):
   397          return get_base_path(), label.lstrip(':')
   398      elif label.startswith('//'):
   399          package, _, name = label.partition(':')
   400          return package.lstrip('/'), name
   401      else:
   402          raise ValueError("%s doesn't look like a build label" % label)
   403  
   404  
   405  def check_config(key:str, section:str='buildconfig', rule:str='', example:str='...'):
   406      """Checks the configuration for the given item and raises an exception if it's not set.
   407  
   408      Args:
   409        key (str): Config key that must be set, e.g. ANDROID_HOME
   410        section (str): Section of the configuration that it must be set in.
   411                       Defaults to buildconfig since most external rules will have to use that.
   412        rule (str): Kind of rule that will be using this, e.g. "Android". Affects the output message.
   413        example (str): Example that they might consider setting.
   414      """
   415      if not CONFIG.get(key):
   416          key = key.lower().replace('_', '-')
   417          rule_msg = (' to use %s rules' % rule) if rule else ''
   418          msg = 'You must set %s.%s in your .plzconfig%s' % (section, key, rule_msg)
   419          msg = '%s, e.g.\n[%s]\n%s = %s\n' % (msg, section, key, example)
   420          raise ConfigError(msg)
   421  
   422  
   423  def _test_size_and_timeout(size, timeout, labels):
   424      """Resolves size and timeout arguments for a test. For Buck compatibility."""
   425      if size:
   426          labels = labels or []
   427          labels.append(size)
   428          if not timeout:
   429              timeout = _SIZE_TIMEOUTS.get(size, 0)
   430      if isinstance(timeout, str):
   431          timeout = _TIMEOUT_NAMES[timeout]
   432      return timeout, labels
   433  
   434  
   435  _SIZE_TIMEOUTS = {
   436      'enormous': 3600,
   437      'large': 900,
   438      'medium': 300,
   439      'small': 60,
   440  }
   441  
   442  _TIMEOUT_NAMES = {
   443      'eternal': 0,  # means unlimited
   444      'long': 900,
   445      'moderate': 300,
   446      'short': 60,
   447  }
   448  
   449  
   450  if CONFIG.BAZEL_COMPATIBILITY:
   451      def bind(name, actual=None):
   452          """Mimics the Bazel bind() function which binds some target or sub-target into our repo.
   453  
   454          TODO(peterebden): Remove, it seems to be deprecated in Bazel so may not be much value having it here.
   455          """
   456          if not actual:
   457              return
   458          if actual.startswith('@') and actual.endswith('//jar'):
   459              actual = ':' + actual[:-len('//jar')].lstrip('@')
   460          filegroup(
   461              name = name,
   462              srcs = [actual],
   463              visibility = ['PUBLIC'],
   464          )
   465  
   466      def exports_files(srcs, name='exported_files', visibility=['PUBLIC'], licenses=None):
   467          """Makes a bunch of files available as a filegroup.
   468  
   469          Note that the semantics are not the same as Bazel; it lifts the restrictions on those
   470          files being available to other packages, whereas we're just creating a rule. It's not
   471          impossible to extend Please to support that but right now we're not bothering.
   472          """
   473          filegroup(
   474              name = name,
   475              srcs = srcs,
   476              visibility = visibility,
   477          )
   478  
   479      def licenses(licences):
   480          """Sets the default licences for the package."""
   481          package(default_licences = licences)