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)