Skip to content

Commit db00e1a

Browse files
committed
more self-review fixes
1 parent 0e08578 commit db00e1a

4 files changed

Lines changed: 68 additions & 63 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-tools/ls-apis/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ newtype_derive.workspace = true
1818
parse-display.workspace = true
1919
petgraph.workspace = true
2020
serde.workspace = true
21+
swrite.workspace = true
2122
toml.workspace = true
2223
omicron-workspace-hack.workspace = true
2324

dev-tools/ls-apis/src/api_metadata.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ impl AllApiMetadata {
8686

8787
/// Returns how we should filter the given dependency.
8888
///
89-
/// Returns all matching evaluations: a dependency may match up to one
90-
/// server rule and up to one ancestor rule. This allows filters to check if
91-
/// any matching rule would cause exclusion.
89+
/// A dependency may match up to one server rule and up to one ancestor
90+
/// rule. Filters can then check if any matching rule would cause exclusion.
9291
pub(crate) fn evaluate_dependency(
9392
&self,
9493
workspaces: &Workspaces,
@@ -482,11 +481,11 @@ pub struct DependencyFilterRule {
482481
pub matcher: RuleMatcher,
483482
pub client: ClientPackageName,
484483
pub evaluation: Evaluation,
485-
// These notes and permalinks are not currently used, but they are required.
486-
// They could as well just be TOML comments. But it seems nice to enforce
487-
// that they're present. And this would let us include this explanation in
488-
// output in the future (e.g., to explain why some dependency was filtered
489-
// out).
484+
// These notes and permalinks are not currently used, but are stored in
485+
// api-manifest.toml (and notes are required). They could as well just be
486+
// TOML comments. But it seems nice to enforce that notes are present. And
487+
// this would let us include this explanation in output in the future (e.g.,
488+
// to explain why some dependency was filtered out).
490489
pub note: String,
491490
pub permalinks: Vec<String>,
492491
}

dev-tools/ls-apis/src/system_apis.rs

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use petgraph::graph::NodeIndex;
3535
use std::collections::BTreeMap;
3636
use std::collections::BTreeSet;
3737
use std::fmt;
38+
use swrite::{SWrite, swriteln};
3839

3940
/// Query information about the Dropshot/OpenAPI/Progenitor-based APIs within
4041
/// the Oxide system
@@ -63,6 +64,10 @@ pub struct SystemApis {
6364
/// maps an API name to the server component(s) that expose that API
6465
api_producers: BTreeMap<ClientPackageName, ApiProducerMap>,
6566

67+
/// index of (server, client) pairs configured as same-deployment-unit edges
68+
same_deployment_unit_edges:
69+
BTreeSet<(ServerComponentName, ClientPackageName)>,
70+
6671
/// source of developer-maintained API metadata
6772
api_metadata: AllApiMetadata,
6873
/// source of Cargo package metadata
@@ -126,6 +131,22 @@ impl SystemApis {
126131
// Load the API manifest.
127132
let api_metadata: AllApiMetadata =
128133
parse_toml_file(&args.api_manifest_path)?;
134+
135+
// Build an index of configured same-deployment-unit edges. We use this
136+
// index for validation and lookups.
137+
let same_deployment_unit_edges: BTreeSet<_> = api_metadata
138+
.same_deployment_unit_rules()
139+
.filter_map(|rule| match &rule.matcher {
140+
RuleMatcher::Server(server) => {
141+
Some((server.clone(), rule.client.clone()))
142+
}
143+
RuleMatcher::Ancestor(_) => {
144+
// This case is rejected at API construction time.
145+
None
146+
}
147+
})
148+
.collect();
149+
129150
// Load Cargo metadata and validate it against the manifest.
130151
let (workspaces, warnings) = Workspaces::load(&api_metadata)?;
131152
if !warnings.is_empty() {
@@ -295,6 +316,7 @@ impl SystemApis {
295316
api_consumers,
296317
missing_expected_consumers,
297318
api_producers,
319+
same_deployment_unit_edges,
298320
api_metadata,
299321
workspaces,
300322
})
@@ -339,15 +361,8 @@ impl SystemApis {
339361
server: &ServerComponentName,
340362
client: &ClientPackageName,
341363
) -> bool {
342-
self.api_metadata.same_deployment_unit_rules().any(|rule| {
343-
if rule.client != *client {
344-
return false;
345-
}
346-
match &rule.matcher {
347-
RuleMatcher::Server(s) => s == server,
348-
RuleMatcher::Ancestor(_) => false,
349-
}
350-
})
364+
self.same_deployment_unit_edges
365+
.contains(&(server.clone(), client.clone()))
351366
}
352367

353368
/// Given a server component, return the APIs consumed by this component
@@ -507,7 +522,7 @@ impl SystemApis {
507522
fn make_deployment_unit_graph(
508523
&self,
509524
dependency_filter: ApiDependencyFilter,
510-
versioned_how_filter: VersionedHowFilter<'_>,
525+
versioned_how_filter: VersionedHowFilter,
511526
) -> Result<(
512527
Graph<&DeploymentUnitName, &ClientPackageName>,
513528
BTreeMap<&DeploymentUnitName, NodeIndex>,
@@ -532,9 +547,8 @@ impl SystemApis {
532547
// When building a server-side-versioned-only graph,
533548
// filter to only server-versioned APIs and skip edges
534549
// that represent same-deployment-unit communication.
535-
if let VersionedHowFilter::ServerSideOnly {
536-
same_unit_edges,
537-
} = &versioned_how_filter
550+
if let VersionedHowFilter::ServerSideOnly =
551+
versioned_how_filter
538552
{
539553
let api = self
540554
.api_metadata
@@ -544,7 +558,8 @@ impl SystemApis {
544558
continue;
545559
}
546560

547-
if same_unit_edges
561+
if self
562+
.same_deployment_unit_edges
548563
.contains(&(server_pkg.clone(), client_pkg.clone()))
549564
{
550565
continue;
@@ -644,7 +659,7 @@ impl SystemApis {
644659
/// 3. The server and API producer are in the same deployment unit.
645660
///
646661
/// Returns a set of (server, client) pairs.
647-
fn compute_required_localhost_edges(
662+
fn compute_required_same_deployment_unit_edges(
648663
&self,
649664
) -> Result<BTreeSet<(ServerComponentName, ClientPackageName)>> {
650665
// Use the IncludeNonDag filter to include SameDeploymentUnit edges. We
@@ -655,7 +670,6 @@ impl SystemApis {
655670
let mut required = BTreeSet::new();
656671

657672
for (server, server_unit) in &self.server_component_units {
658-
659673
for (client, _) in self.component_apis_consumed(server, filter)? {
660674
// Only consider server-side-versioned APIs.
661675
let Some(api) = self.api_metadata.client_pkgname_lookup(client)
@@ -690,26 +704,11 @@ impl SystemApis {
690704

691705
/// Validates that the configured same-deployment-unit rules exactly match
692706
/// the required set of edges that must be excluded.
693-
///
694-
/// Returns the validated set of edges for use by `make_deployment_unit_graph`.
695-
fn validate_same_deployment_unit_rules(
696-
&self,
697-
) -> Result<BTreeSet<(ServerComponentName, ClientPackageName)>> {
698-
let required = self.compute_required_localhost_edges()?;
699-
700-
// Build the configured set from the manifest.
701-
let mut configured = BTreeSet::new();
702-
for rule in self.api_metadata.same_deployment_unit_rules() {
703-
let RuleMatcher::Server(server) = &rule.matcher else {
704-
unreachable!(
705-
"same-deployment-unit rules must have server matcher \
706-
(validated in api_metadata.rs)"
707-
);
708-
};
709-
configured.insert((server.clone(), rule.client.clone()));
710-
}
707+
fn validate_same_deployment_unit_rules(&self) -> Result<()> {
708+
let required = self.compute_required_same_deployment_unit_edges()?;
709+
let configured = &self.same_deployment_unit_edges;
711710

712-
let missing: BTreeSet<_> = required.difference(&configured).collect();
711+
let missing: BTreeSet<_> = required.difference(configured).collect();
713712
let extra: BTreeSet<_> = configured.difference(&required).collect();
714713

715714
if !missing.is_empty() || !extra.is_empty() {
@@ -718,29 +717,37 @@ impl SystemApis {
718717
);
719718

720719
if !missing.is_empty() {
721-
msg.push_str("\nmissing entries (these edges exist and need same-deployment-unit exclusion):\n");
720+
swriteln!(
721+
msg,
722+
"\nmissing entries (these edges exist and need \
723+
same-deployment-unit exclusion):"
724+
);
722725
for (server, client) in &missing {
723-
msg.push_str(&format!(
724-
" - server = {:?}, client = {:?}\n",
725-
server, client
726-
));
726+
swriteln!(
727+
msg,
728+
" - server = {server:?}, client = {client:?}"
729+
);
727730
}
728731
}
729732

730733
if !extra.is_empty() {
731-
msg.push_str("\nextra entries (these edges don't exist or don't need exclusion):\n");
734+
swriteln!(
735+
msg,
736+
"\nextra entries (these edges don't exist or don't need \
737+
exclusion):"
738+
);
732739
for (server, client) in &extra {
733-
msg.push_str(&format!(
734-
" - server = {:?}, client = {:?}\n",
735-
server, client
736-
));
740+
swriteln!(
741+
msg,
742+
" - server = {server:?}, client = {client:?}"
743+
);
737744
}
738745
}
739746

740747
bail!("{}", msg);
741748
}
742749

743-
Ok(required)
750+
Ok(())
744751
}
745752

746753
/// Verifies various important properties about the assignment of which APIs
@@ -799,7 +806,7 @@ impl SystemApis {
799806

800807
// Validate that all configured same-deployment-unit rules are correct
801808
// and match the required set exactly.
802-
let same_unit_edges = self.validate_same_deployment_unit_rules()?;
809+
self.validate_same_deployment_unit_rules()?;
803810

804811
// Construct a graph where:
805812
//
@@ -822,9 +829,7 @@ impl SystemApis {
822829
// Do the same with a graph of deployment units.
823830
let (graph, nodes) = self.make_deployment_unit_graph(
824831
filter,
825-
VersionedHowFilter::ServerSideOnly {
826-
same_unit_edges: &same_unit_edges,
827-
},
832+
VersionedHowFilter::ServerSideOnly,
828833
)?;
829834
let reverse_nodes: BTreeMap<_, _> =
830835
nodes.iter().map(|(d_u, node)| (node, d_u)).collect();
@@ -1433,14 +1438,12 @@ impl<'a> ClientDependenciesTracker<'a> {
14331438
/// Specifies whether to filter to only server-versioned APIs when building
14341439
/// dependency graphs.
14351440
#[derive(Clone, Debug)]
1436-
pub enum VersionedHowFilter<'a> {
1441+
pub enum VersionedHowFilter {
14371442
/// Include all APIs regardless of versioning strategy.
14381443
All,
14391444
/// Include only APIs with server-side versioning, and skip edges that
14401445
/// represent same-deployment-unit communication.
1441-
ServerSideOnly {
1442-
same_unit_edges: &'a BTreeSet<(ServerComponentName, ClientPackageName)>,
1443-
},
1446+
ServerSideOnly,
14441447
}
14451448

14461449
/// Specifies which API dependencies to include vs. ignore when iterating
@@ -1479,7 +1482,8 @@ pub enum ApiDependencyFilter {
14791482

14801483
impl ApiDependencyFilter {
14811484
/// Return whether this filter should include a dependency on
1482-
/// `client_pkgname` that goes through dependency path `dep_path`.
1485+
/// `client_pkgname` that goes either through `server` or through
1486+
/// `dep_path`.
14831487
///
14841488
/// Note: `Evaluation::SameDeploymentUnit` edges are included by all filters
14851489
/// here. These edges represent real dependencies and should appear in

0 commit comments

Comments
 (0)