11//! A module for configuration information
22
3- mod label_injection;
3+ pub ( crate ) mod label_injection;
44
55use std:: cmp:: Ordering ;
66use std:: collections:: { BTreeMap , BTreeSet } ;
@@ -719,6 +719,18 @@ pub(crate) struct Config {
719719 /// A set of platform triples to use in generated select statements
720720 #[ serde( default , skip_serializing_if = "BTreeSet::is_empty" ) ]
721721 pub ( crate ) supported_platform_triples : BTreeSet < TargetTriple > ,
722+
723+ /// Apparent -> canonical label_injection map extracted from each
724+ /// annotation's `label_injections` field at load time. Populated by
725+ /// `Config::try_from_path`; not present in config.json itself
726+ /// (`deny_unknown_fields` is fine because `extract_global_mapping`
727+ /// strips `label_injections` before deserialization). Sanitized to
728+ /// `Default::default()` in `Digest::new` before hashing — same trick
729+ /// as `Context.checksum = None` in `lockfile.rs` — so consumer-side
730+ /// `single_version_override` shifts (which change the canonical names
731+ /// here) don't perturb the digest and force a producer-side repin.
732+ #[ serde( default , skip_serializing_if = "BTreeMap::is_empty" ) ]
733+ pub ( crate ) label_injection_mapping : LabelInjectionMapping ,
722734}
723735
724736// rules_rust/crate_universe/private/generate_utils.bzl:generate_config
@@ -744,14 +756,34 @@ where
744756}
745757
746758impl Config {
759+ /// Load a config JSON and extract its per-annotation `label_injections`
760+ /// into a single `label_injection_mapping` on the Config. The Config
761+ /// itself keeps the user's APPARENT labels in annotation strings — the
762+ /// rewrite to canonical happens via
763+ /// [`label_injection::apply_mapping_to_value`] just before each render
764+ /// (see [`crate::context::Context::apply_label_injection_mapping`]),
765+ /// using whatever mapping the current bazel session resolved (reflecting
766+ /// any root-level `single_version_override` / `multiple_version_override`).
767+ ///
768+ /// The mapping is excluded from the digest hash via
769+ /// [`crate::lockfile::Digest::new`], mirroring the
770+ /// `Context.checksum = None` clear in the same file. That's what keeps
771+ /// the digest stable across consumer-side overrides.
747772 pub ( crate ) fn try_from_path < T : AsRef < Path > > ( path : T ) -> Result < Self > {
748773 let data = fs:: read_to_string ( path) ?;
749774 let mut value: serde_json:: Value = serde_json:: from_str ( & data) ?;
750- label_injection:: apply ( & mut value) ;
751- Ok ( serde_json:: from_value ( value) ?)
775+ let mapping = label_injection:: extract_global_mapping ( & mut value) ?;
776+ let mut config: Self = serde_json:: from_value ( value) ?;
777+ config. label_injection_mapping = mapping;
778+ Ok ( config)
752779 }
753780}
754781
782+ /// Apparent-repo-prefix -> canonical-repo-prefix map carried on
783+ /// [`Config::label_injection_mapping`]. See [`label_injection`] for the WHY
784+ /// of the deferred-substitution design.
785+ pub ( crate ) type LabelInjectionMapping = std:: collections:: BTreeMap < String , String > ;
786+
755787#[ derive( Clone , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
756788pub struct CrateNameAndVersionReq {
757789 /// The name of the crate
0 commit comments