Skip to content

Commit 70cdf5d

Browse files
committed
further fixes
1 parent dbb6eab commit 70cdf5d

File tree

31 files changed

+260
-167
lines changed

31 files changed

+260
-167
lines changed

codegen/crates/crate_feature_graph/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ clap = { workspace = true, features = ["derive"] }
2626
serde = { workspace = true, features = ["derive"], optional = true }
2727
serde_json = { workspace = true, optional = true }
2828
pretty_env_logger = { workspace = true }
29+
indexmap = { workspace = true, features = ["serde"] }
2930

3031
[dev-dependencies]
3132
petgraph = { workspace = true, features = ["dot_parser"] }

codegen/crates/crate_feature_graph/README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,22 @@ A tool for visualising feature flow in a rust workspace, from the perspective of
77
## Features
88
- Compute feature flow throughout your workspace
99
- Filter out crates you don't want to see from the graph, but retain the connections
10-
- Output as a dot graph or if the `dot_parser` feature is disabled as a text representation
10+
- Output as a dot graph or if the `dot_parser` feature is disabled as a text representation
11+
12+
## Usage
13+
You can either filter the output or generate the entire graph.
14+
If you filter out any crates, the edges will be "collapsed" at the edges of the filtered crates, so you can still see how features propagate through the graph.
15+
16+
For larger workspaces it is recommended to generate an svg so you can properly view the entire graph.
17+
18+
features obey the following syntax:
19+
- `feature1` - enable feature1 in the root crate
20+
- `crate/feature2` - enable feature2 in the crate crate (and implicitly enable crate as a dependency)
21+
- `crate/default` - enable the default feature for the crate
22+
- `default` - enable the default feature for the root crate
23+
24+
```bash
25+
cargo install crate_feature_graph --features dot_parser
26+
27+
RUST_LOG=info cargo_feature_graph --manifest-path path/to/Cargo.toml --features="feature1,feature2" --only-show-crates="maybe_crate1,maybe_crate2"
28+
```

codegen/crates/crate_feature_graph/src/feature.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
use std::{
22
borrow::{Borrow, Cow},
3-
collections::{HashMap, HashSet, VecDeque},
3+
collections::VecDeque,
44
fmt::Display,
55
};
66

77
use cargo_metadata::{
88
Metadata, Package,
99
semver::{Version, VersionReq},
1010
};
11+
use indexmap::{IndexMap, IndexSet};
1112
use itertools::{Either, Itertools};
1213
use log::error;
1314

14-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
15+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
1516
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1617
pub struct CrateName(pub(crate) String);
1718

@@ -34,7 +35,7 @@ impl Display for CrateName {
3435
}
3536

3637
/// A feature name
37-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
38+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
3839
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3940
pub struct FeatureName(Cow<'static, str>);
4041

@@ -56,7 +57,7 @@ impl Display for FeatureName {
5657
}
5758
}
5859

59-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
60+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
6061
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6162
pub enum FeatureEffect {
6263
/// I.e. `foo=["feature"]` is represented as `EnableFeature("feature")`
@@ -91,7 +92,7 @@ impl FeatureEffect {
9192
}
9293
}
9394

94-
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
95+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9596
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9697
pub struct Feature {
9798
pub name: FeatureName,
@@ -198,14 +199,26 @@ impl DependencyKind {
198199
}
199200
}
200201

201-
#[derive(Clone, Debug)]
202+
#[derive(Clone, Debug, PartialEq, Eq)]
202203
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
203204
pub struct CrateDependency {
204205
pub name: CrateName,
205206
pub version: VersionReq,
206207
}
207208

208-
#[derive(Clone, Debug)]
209+
impl PartialOrd for CrateDependency {
210+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
211+
Some(self.cmp(other))
212+
}
213+
}
214+
215+
impl Ord for CrateDependency {
216+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
217+
self.name.cmp(&other.name)
218+
}
219+
}
220+
221+
#[derive(Clone, Debug, PartialEq, Eq)]
209222
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
210223
pub struct Crate {
211224
pub name: CrateName,
@@ -214,11 +227,23 @@ pub struct Crate {
214227
pub optional_dependencies: Vec<CrateDependency>,
215228
pub version: Version,
216229
pub in_workspace: Option<bool>,
217-
pub active_features: Option<HashSet<FeatureName>>,
218-
pub active_dependency_features: Option<HashMap<CrateName, Vec<FeatureName>>>,
230+
pub active_features: Option<IndexSet<FeatureName>>,
231+
pub active_dependency_features: Option<IndexMap<CrateName, Vec<FeatureName>>>,
219232
pub is_enabled: Option<bool>,
220233
}
221234

235+
impl PartialOrd for Crate {
236+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
237+
Some(self.cmp(other))
238+
}
239+
}
240+
241+
impl Ord for Crate {
242+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
243+
self.name.cmp(&other.name)
244+
}
245+
}
246+
222247
struct DependencyIter<'a> {
223248
krate: &'a Crate,
224249
index: usize,
@@ -282,10 +307,10 @@ impl Crate {
282307
/// if `enable_default` is true, the "default" feature is considered enabled initially if it exists.
283308
pub fn compute_active_features(
284309
&mut self,
285-
enabled_features: &HashSet<FeatureName>,
310+
enabled_features: &IndexSet<FeatureName>,
286311
keep_trails: bool,
287312
) {
288-
let mut all_features = HashSet::default();
313+
let mut all_features = IndexSet::default();
289314
let mut to_process = enabled_features
290315
.clone()
291316
.into_iter()
@@ -536,7 +561,7 @@ impl From<&Metadata> for Workspace {
536561
.workspace_packages()
537562
.iter()
538563
.map(CrateName::from)
539-
.collect::<HashSet<_>>();
564+
.collect::<IndexSet<_>>();
540565

541566
let (mut workspace_crates, mut other_crates): (Vec<_>, Vec<_>) = meta
542567
.packages
@@ -638,7 +663,7 @@ mod tests {
638663
active_dependency_features: None,
639664
};
640665

641-
krate.compute_active_features(&HashSet::from([FeatureName("default".into())]), true);
666+
krate.compute_active_features(&IndexSet::from([FeatureName("default".into())]), true);
642667

643668
let active_features = krate.active_features.unwrap();
644669
assert!(active_features.contains(&FeatureName("default".into())));

codegen/crates/crate_feature_graph/src/graph.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::{HashMap, HashSet, VecDeque};
22

3+
use indexmap::{IndexMap, IndexSet};
34
use log::error;
45
use petgraph::Directed;
56

@@ -405,6 +406,27 @@ impl WorkspaceGraph {
405406
self.calculate_enabled_features_and_dependencies(features_map, false);
406407
}
407408

409+
pub fn stable_sort(&mut self) {
410+
// sort everything
411+
self.workspace.other_crates.sort();
412+
self.workspace.workspace_crates.sort();
413+
for krate in self.workspace.all_crates_mut() {
414+
krate.features.sort();
415+
krate.dependencies.sort_by(|a, b| a.name.cmp(&b.name));
416+
krate
417+
.optional_dependencies
418+
.sort_by(|a, b| a.name.cmp(&b.name));
419+
if let Some(f) = krate.active_features.as_mut() {
420+
f.sort()
421+
}
422+
if let Some(m) = krate.active_dependency_features.as_mut() {
423+
for v in m.values_mut() {
424+
v.sort();
425+
}
426+
}
427+
}
428+
}
429+
408430
/// Calculate the enabled features and dependencies for the workspace
409431
/// The set of enabled feature/crate pairs is treated as the set of explicitly enabled crates
410432
/// For a workspace this should be the workspace root with the desired features enabled..
@@ -434,7 +456,7 @@ impl WorkspaceGraph {
434456
match enabled_crates.remove(&krate) {
435457
Some((features, enable_default)) => {
436458
// a top level enabled crate, process only explicitly enabled features, we know nothing else will be there to enable more
437-
let features = HashSet::from_iter(features.iter().cloned());
459+
let features = IndexSet::from_iter(features.iter().cloned());
438460
if enable_default
439461
&& let Some(c) = self.workspace.find_crate_mut(&krate, || format!(
440462
"package from workspace manifest: `{krate}` was not found in the parsed workspace list. This might lead to missing default features."))
@@ -477,7 +499,7 @@ impl WorkspaceGraph {
477499
.filter_map(|f| f.effects().find_map(|e| e.enables_feature_in_crate(&krate).cloned())))
478500
})
479501
.flatten()
480-
.collect::<HashSet<_>>();
502+
.collect::<IndexSet<_>>();
481503

482504
log::trace!(
483505
"Crate `{krate}` is being enabled with parent features: {parent_features:?}"
@@ -586,7 +608,7 @@ impl WorkspaceGraph {
586608
map.insert(dependency, features);
587609
}
588610
None => {
589-
let mut map = HashMap::new();
611+
let mut map = IndexMap::new();
590612
map.insert(dependency, features);
591613
krate.active_dependency_features = Some(map);
592614
}
@@ -600,7 +622,7 @@ impl WorkspaceGraph {
600622
fn process_crate(
601623
&mut self,
602624
krate: &CrateName,
603-
enable_features: HashSet<FeatureName>,
625+
enable_features: IndexSet<FeatureName>,
604626
trace_features: bool,
605627
) {
606628
// find all conditional features in this crate, only consider the crates in the open set.

codegen/crates/crate_feature_graph/src/lib.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ pub use graph::*;
66

77
#[cfg(test)]
88
mod test {
9-
use std::{
10-
collections::{HashMap, HashSet},
11-
path::PathBuf,
12-
};
9+
use std::{collections::HashMap, hash::RandomState, path::PathBuf};
1310

11+
use indexmap::IndexSet;
1412
use petgraph::dot::Dot;
1513

1614
use super::*;
@@ -102,7 +100,7 @@ mod test {
102100
// assert features
103101
pretty_assertions::assert_eq!(
104102
root_crate.active_features.as_ref().unwrap(),
105-
&HashSet::from_iter([
103+
&IndexSet::<_, RandomState>::from_iter([
106104
FeatureName::new("default"),
107105
FeatureName::new("enable_crate_a"),
108106
])
@@ -111,7 +109,7 @@ mod test {
111109

112110
pretty_assertions::assert_eq!(
113111
crate_a.active_features.as_ref().unwrap(),
114-
&HashSet::from_iter([
112+
&IndexSet::<_, RandomState>::from_iter([
115113
FeatureName::new("crate_a_default"),
116114
FeatureName::new("default"),
117115
])

codegen/src/modifying_file_loader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{
22
io,
33
sync::{
4-
atomic::{AtomicBool, Ordering},
54
Arc,
5+
atomic::{AtomicBool, Ordering},
66
},
77
};
88

codegen/src/passes/find_reflect_types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use log::{debug, info};
22
use rustc_hir::def_id::LOCAL_CRATE;
33

4-
use crate::{Args, BevyCtxt, ReflectType, DEF_PATHS_REFLECT};
4+
use crate::{Args, BevyCtxt, DEF_PATHS_REFLECT, ReflectType};
55

66
/// Finds all reflect types which we can wrap in the crate as well as sorts the final list.
77
pub(crate) fn find_reflect_types(ctxt: &mut BevyCtxt<'_>, args: &Args) -> bool {

codegen_bevy_features.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
bevy_asset,bevy_animation,bevy_core_pipeline,bevy_ui,bevy_pbr,bevy_render,bevy_text,bevy_sprite,file_watcher,multi_threaded,std,async_executor,bevy_reflect/glam,bevy_reflect/uuid,bevy_reflect/smol_str,bevy_sprite/bevy_sprite_picking_backend
1+
default,bevy_asset,bevy_animation,bevy_core_pipeline,bevy_ui,bevy_pbr,bevy_render,bevy_text,bevy_sprite,file_watcher,multi_threaded,std,async_executor,bevy_reflect/glam,bevy_reflect/uuid,bevy_reflect/smol_str,bevy_sprite/bevy_sprite_picking_backend

crates/bindings/bevy_a11y_bms_bindings/Cargo.toml

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

crates/bindings/bevy_asset_bms_bindings/Cargo.toml

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

0 commit comments

Comments
 (0)