-
Notifications
You must be signed in to change notification settings - Fork 33
refactor: expose bundle target metadata #841
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,7 +38,10 @@ load("@score_docs_as_code//:bzl/basics.bzl", "join_path") | |
| DocsBundleInfo = provider( | ||
| doc = "A documentation bundle with its source and placement metadata.", | ||
| fields = { | ||
| "entries": "Ordered entries, one per source directory, including its final documentation-tree location.", | ||
| # Each entry carries the source and placement information needed by | ||
| # the runtime manifest, plus the identity and direct-target metadata | ||
| # of the bundle that declared it. | ||
| "entries": "Ordered entries with source, placement, and direct-target metadata.", | ||
| "own_source_files": "This bundle's direct source files, excluding nested bundles.", | ||
| "source_dir_execroot_path": "Execution-root-relative path of this bundle's direct source root.", | ||
| "sourcelinks": "Source-code-link JSON files together with their owning repository.", | ||
|
|
@@ -53,6 +56,7 @@ CodeTargetSourcesInfo = provider( | |
| doc = "Source files collected from an implementation target and its dependencies.", | ||
| fields = { | ||
| "sources": "Depset of direct and transitive source files.", | ||
| "kind": "Bazel rule kind of the selected code target.", | ||
| }, | ||
| ) | ||
|
|
||
|
|
@@ -82,6 +86,10 @@ def _collect_code_target_sources_impl(target, ctx): | |
| direct = _source_files_from_attributes(ctx), | ||
| transitive = dependency_sources, | ||
| ), | ||
| # The aspect follows dependencies to collect source files, but the | ||
| # manifest needs the kind of the target explicitly selected by the | ||
| # bundle rather than the kinds of those transitive dependencies. | ||
| kind = ctx.rule.kind, | ||
| )] | ||
|
|
||
| _collect_code_target_sources = aspect( | ||
|
|
@@ -216,10 +224,15 @@ def _rebase_bundle_entry(entry, mount_at, attach_to): | |
| bundle's aggregate data would associate the same file with unrelated | ||
| mounts, so the mounts resolver could select the wrong destination. | ||
| """ | ||
| is_bundle_root = not entry.mount_at | ||
| if is_bundle_root: | ||
| if not entry.mount_at: | ||
| # The child bundle's own root has not been placed below the parent yet. | ||
| # Its default attachment is therefore the parent directory's index; | ||
| # an explicit attach_to still overrides that default. | ||
| rebased_attach_to = attach_to or _parent_index_docname(mount_at) | ||
| else: | ||
| # This entry is already below another location in the child bundle. | ||
| # Keep its attachment relative to that location and prefix the whole | ||
| # placement with the mount point chosen by the parent. | ||
| rebased_attach_to = join_path(mount_at, entry.attach_to) | ||
|
|
||
| return struct( | ||
|
|
@@ -236,6 +249,16 @@ def _rebase_bundle_entry(entry, mount_at, attach_to): | |
| # Preserve the explicit file allowlist when the entry is rebased. | ||
| files = entry.files, | ||
| data = entry.data, | ||
| # Rebasing changes only placement. Keep the declaring bundle identity | ||
| # and direct targets attached to the source entry as it moves through | ||
| # the composition graph. | ||
| bundle_label = entry.bundle_label, | ||
| bundle_name = entry.bundle_name, | ||
| code_targets = entry.code_targets, | ||
| # This entry is now part of a parent composition. It may have been the | ||
| # root of its own standalone bundle, but it is a child entry here and | ||
| # must be handled as a mounted source rather than as the parent's root. | ||
| root_bundle = False, | ||
| ) | ||
|
|
||
| def _entries_visible_through(ctx, child): | ||
|
|
@@ -283,6 +306,15 @@ def _docs_bundle_impl(ctx): | |
| source_dir_execroot_path = "" | ||
| own_external_runfiles = [] | ||
| own_data = depset(direct = ctx.files.data) | ||
| own_bundle_label = str(ctx.label) | ||
| own_bundle_name = ctx.label.name | ||
| own_code_targets = [ | ||
| struct( | ||
| label = str(target.label), | ||
| type = target[CodeTargetSourcesInfo].kind, | ||
| ) | ||
| for target in ctx.attr.code_targets | ||
| ] | ||
|
|
||
| # The macro validates this combination before creating the rule; retain | ||
| # the rule-level check for callers of the internal helper as well. | ||
|
|
@@ -310,6 +342,13 @@ def _docs_bundle_impl(ctx): | |
| # Directory mounts discover all supported files below this root. | ||
| files = [], | ||
| data = own_data, | ||
| bundle_label = own_bundle_label, | ||
| bundle_name = own_bundle_name, | ||
| # This direct entry belongs to the current composition's root | ||
| # bundle. _rebase_bundle_entry changes this to false if a parent | ||
| # embeds the bundle as a child. | ||
| root_bundle = True, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do you know that this is a root_bundle at this point?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All bundles start with the assumption that they are roots, until they are placed somewhere. And _rebase_bundle_entry sets it to false.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Automated response: At this point _docs_bundle_impl is creating an entry directly from the current bundle's own source or data. Direct entries are root entries of the current composition and are therefore marked true. If a parent embeds the bundle, _rebase_bundle_entry creates the composed entry and sets root_bundle to false. Root status is composition-specific, not a permanent property of the bundle. |
||
| code_targets = own_code_targets, | ||
| )) | ||
| own_source_files.extend(ctx.files.source_dir_globbed) | ||
| # Local sources are read directly from the workspace by ``bazel run``. | ||
|
|
@@ -342,6 +381,13 @@ def _docs_bundle_impl(ctx): | |
| # original source root and therefore visits only declared files. | ||
| files = source_files, | ||
| data = own_data, | ||
| bundle_label = own_bundle_label, | ||
| bundle_name = own_bundle_name, | ||
| # This direct entry belongs to the current composition's root | ||
| # bundle. _rebase_bundle_entry changes this to false if a parent | ||
| # embeds the bundle as a child. | ||
| root_bundle = True, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question as above
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Automated response: The same explanation applies here: this is the current bundle's direct explicit-source entry, so it starts as a root entry of the current composition. When a parent embeds it, _rebase_bundle_entry marks the resulting child entry as false. |
||
| code_targets = own_code_targets, | ||
| )) | ||
| own_source_files.extend(ctx.files.source_targets) | ||
| # Explicit artifacts outside the workspace source tree need to be | ||
|
|
@@ -363,6 +409,13 @@ def _docs_bundle_impl(ctx): | |
| # Pure-data entries have no documentation source allowlist. | ||
| files = [], | ||
| data = own_data, | ||
| bundle_label = own_bundle_label, | ||
| bundle_name = own_bundle_name, | ||
| # This direct entry belongs to the current composition's root | ||
| # bundle. _rebase_bundle_entry changes this to false if a parent | ||
| # embeds the bundle as a child. | ||
| root_bundle = True, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm guessing data bundles are root_bundles by defintion?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as normal bundles, until they are wrapped somewhere they are root bundles
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Automated response: A pure-data bundle gets a root entry when considered as a standalone composition because that entry is needed to carry the bundle's data. Root here means root entry of the current composition, not a documentation source. When the bundle is nested, rebasing changes the entry to root_bundle = false so its data can be mounted as child data. |
||
| code_targets = own_code_targets, | ||
| )) | ||
|
|
||
| child_source_files = [] | ||
|
|
@@ -427,6 +480,9 @@ _docs_bundle = rule( | |
| "bundle_mount_ats": attr.string_list(), | ||
| "bundle_attach_tos": attr.string_list(), | ||
| "data": attr.label_list(allow_files = True), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this already has the other things?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Automated response: These fields are introduced as one manifest contract. The previous manifest did not carry the bundle label, bundle name, root status, or direct code targets. code_targets is the new payload, while label, name, and root_bundle identify which bundle the targets belong to and how the entry participates in the current composition. |
||
| # The aspect preserves the selected target's rule kind while | ||
| # recursively collecting its source files for source-link generation. | ||
| "code_targets": attr.label_list(aspects = [_collect_code_target_sources]), | ||
| }, | ||
| doc = "Internal rule that carries bundle files and their documentation-tree locations.", | ||
| ) | ||
|
|
@@ -440,6 +496,7 @@ def create_bundle( | |
| source_dir = None, | ||
| entry_doc = "index", | ||
| data = [], | ||
| code_targets = [], | ||
| visibility = None, | ||
| **kwargs): | ||
| """Create a bundle from directory-discovered files and source targets. | ||
|
|
@@ -459,6 +516,7 @@ def create_bundle( | |
| bundle_mount_ats = [bundle.mount_at for bundle in parsed_bundles], | ||
| bundle_attach_tos = [bundle.attach_to for bundle in parsed_bundles], | ||
| data = data, | ||
| code_targets = code_targets, | ||
| visibility = visibility, | ||
| **kwargs | ||
| ) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between
root_gundleandis_unplaced_bundle_root?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So e.g. a child mount has is_unplaced_bundle_root = True, until it is finally mounted somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Automated response: root_bundle is the persisted flag on the final manifest entry. It says whether the entry belongs to the root bundle of the current composition. The old is_unplaced_bundle_root expression was only a temporary condition while rebasing and has now been removed. A bundle can therefore be a root in a standalone composition and a child when embedded.