Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visibility: documentation fixes and clarifications. #19438

Merged
merged 5 commits into from
Jul 19, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions docs/markdown/Using Pants/validating-dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,32 @@ __dependencies_rules__(
# Due to the `extend=True` flag, which inherits the parent rules after those just declared.
```

> 📘 Any rule globs using the declaration path anchoring mode that is inherited using `extend=True` will be anchored to the path of the current BUILD file, not the original one where the rule was extended from.
>
> See [glob syntax](doc:targets#glob-syntax) for details on anchoring modes.

For example:
```python
# src/BUILD
__dependencies_rules__(
(files,
"/relative/to/BUILD/file/**",
"!*",
),
)

# src/subdir/BUILD
__dependencies_rules__(
(resources,
"/relative/to/BUILD/file/**",
"!*",
),
extend=True,
)
```

The above rules when applied to `resources` _as well as_ `files` targets in `src/subdir` will allow dependencies only to other targets in the subtree of `src/subdir/relative/to/BUILD/file/` despite the inherited rule declared in `src/BUILD`. For `files` targets in other directories in the `src/` subtree (e.g. `src/another/dir`) dependencies will be allowed only to other targets in the subtree of `src/relative/to/BUILD/file/`.


Rule sets
---------
Expand All @@ -181,11 +207,17 @@ __dependencies_rules__(

The selector and rule share a common syntax (refered to as a __target rule spec__), that is a dictionary value with properties describing what targets it applies to. Together, this pair of selector(s) and rules is called a __rule set__. A rule set may have multiple selectors wrapped in a list/tuple and the rules may be spread out or grouped in any fashion. Grouping rules like this makes it easier to re-use/insert rules from macros or similar.

> 📘 An empty selector (`{}` or `""`) will never match anything and is as such pointless and will result in an error.
>
> For every dependency link, only a single set of rules will ever be applied. The first rule set
> with a matching selector will be the only one used and any remaining rule sets are never
> consulted.

The __target rule spec__ has four properties: `type`, `name`, `tags`, and `path`. From the above example, when determining which rule set to apply for the dependencies of `src/a/main.py` Pants will look for the first selector for `src/a/BUILD` that satisifies the properties `type=python_sources`, `tags=["apps"]`, and `path=src/a/main.py`. The selection is based on exclusion so only when there is a property value and it doesn't match the target's property it will move on to the next selector; the lack of a property will be considered to match anything. Consequently an empty target spec would match all targets, but this is disallowed and will raise an error if used because it is conceptually not very clear when reading the rules.

The values of a __target rule spec__ supports wildcard patterns (or globs) in order to have a single selector match multiple different targets, as described in [glob syntax](doc:targets#glob-syntax). When listing multiple values for the `tags` property, the target must have all of them in order to match. Spread the tags over multiple selectors in order to switch from _AND_ to _OR_ as required. The target `type` to match against will be that of the type used in the BUILD file, as the path (and target address) may refer to a generated target it is the target generators type that will be used during the selector matching process.

The selectors are matched against the target in the order they are defined in the BUILD file, and the first rule set with a selector that is a match will be selected. The rules from the selected rule set is then matched in order against the path of the **target on the other end** of the dependency link. This is worth reading again; Using the above example again, the rules defined in `src/a/BUILD` will be matched against `src/b/lib.py` while the `path` selector will be matched against `src/a/main.py`.
The selectors are matched against the target in the order they are defined in the BUILD file, and the first rule set with a selector that is a match will be selected. The rules from the selected rule set is then matched in order against the path of the **target on the other end** of the dependency link. This is worth reading again; Using the above example, the rules defined in `src/a/BUILD` will be matched against `src/b/lib.py` while the `path` selector will be matched against `src/a/main.py`.

Providing some example rule sets for the above example (see [rule actions](doc:targets#rule-actions) on how to mark a rule as "allow" or "deny"):

Expand All @@ -201,7 +233,7 @@ __dependencies_rules__(

# We need another rule set, in case we have non-python sources in here, to avoid fall-through.
# Sticking in a generic catch-all allow-all rule.
({}, "*"),
("*", "*"),
)


Expand All @@ -228,7 +260,7 @@ __dependents_rules__(

# We need another rule set, in case we have non-python sources in here, to avoid fall-through.
# Sticking in a generic catch-all allow-all rule.
({}, "*"),
("*", "*"),
)
```

Expand Down Expand Up @@ -299,9 +331,11 @@ The glob prefix specifies which "anchoring mode" to use, and are:
Example: `//src/python/**` will match all files from the `src/python/` tree.

- `/` - Anchor the glob to the declaration path.
This is the path of the BUILD file where the rule is declared, using one of the rules keywords (i.e. `__dependencies_rules__` or `__dependents_rules__`)
This is the path of the BUILD file where the rule is declared or extended to, using one of the rules keywords (i.e. `__dependencies_rules__` or `__dependents_rules__`)
Example: in `src/python/BUILD` there is a rule `/proj/**` which will match all files from the `src/python/proj/` tree.

Note: When a rule is extended (using `extend=True` in a rules keyword), it is treated as declared in that new BUILD with the `extend=True` argument.

- `.` - Anchor the glob to the invocation path.
This is the file path of the target for which the rule will apply for. Relative paths are supported, so `../../cousin/path` is valid.
Example: there is a rule `./lib/*` when applied for the file `src/python/proj/main.py` it would match `src/python/proj/lib/*`.
Expand Down