chaste_types/
chastefile.rs1use std::collections::{HashMap, HashSet, VecDeque};
5
6use crate::dependency::Dependency;
7use crate::error::{Error, Result};
8use crate::installation::Installation;
9use crate::package::{Package, PackageID};
10
11#[derive(Debug, Clone)]
12pub struct Chastefile {
13 packages: HashMap<PackageID, Package>,
14 installations: Vec<Installation>,
15 dependencies: Vec<Dependency>,
16 root_package_id: PackageID,
17 workspace_members: Vec<PackageID>,
18}
19
20impl<'a> Chastefile {
21 pub fn package(&'a self, package_id: PackageID) -> &'a Package {
22 self.packages.get(&package_id).unwrap()
23 }
24
25 pub fn packages(&'a self) -> Vec<&'a Package> {
26 self.packages.values().collect()
27 }
28
29 pub fn packages_with_ids(&'a self) -> Vec<(PackageID, &'a Package)> {
30 self.packages.iter().map(|(pid, pkg)| (*pid, pkg)).collect()
31 }
32
33 fn package_dependencies_iter(
34 &'a self,
35 package_id: PackageID,
36 ) -> impl Iterator<Item = &'a Dependency> {
37 self.dependencies
38 .iter()
39 .filter(move |d| d.from == package_id)
40 }
41
42 fn package_prod_dependencies_iter(
43 &'a self,
44 package_id: PackageID,
45 ) -> impl Iterator<Item = &'a Dependency> {
46 self.dependencies
47 .iter()
48 .filter(move |d| d.kind.is_prod() && d.from == package_id)
49 }
50
51 pub fn package_dependencies(&'a self, package_id: PackageID) -> Vec<&'a Dependency> {
53 self.package_dependencies_iter(package_id).collect()
54 }
55
56 pub fn package_prod_dependencies(&'a self, package_id: PackageID) -> Vec<&'a Dependency> {
58 self.package_prod_dependencies_iter(package_id).collect()
59 }
60
61 pub fn recursive_package_dependencies(&'a self, package_id: PackageID) -> Vec<&'a Dependency> {
63 let mut result = self.package_dependencies(package_id);
64 let mut seen = HashSet::with_capacity(result.len());
65 let mut q = VecDeque::with_capacity(result.len());
66 result.iter().for_each(|d| {
67 seen.insert(d.on);
68 q.push_back(d.on);
69 });
70 while let Some(pid) = q.pop_front() {
71 for dep in self.package_dependencies_iter(pid) {
72 if seen.insert(dep.on) {
73 q.push_back(dep.on);
74 result.push(dep);
75 }
76 }
77 }
78 result
79 }
80
81 pub fn recursive_prod_package_dependencies(
84 &'a self,
85 package_id: PackageID,
86 ) -> Vec<&'a Dependency> {
87 let mut result = self.package_prod_dependencies(package_id);
88 let mut seen = HashSet::with_capacity(result.len());
89 let mut q = VecDeque::with_capacity(result.len());
90 result.iter().for_each(|d| {
91 seen.insert(d.on);
92 q.push_back(d.on);
93 });
94 while let Some(pid) = q.pop_front() {
95 for dep in self.package_prod_dependencies_iter(pid) {
96 if seen.insert(dep.on) {
97 q.push_back(dep.on);
98 result.push(dep);
99 }
100 }
101 }
102 result
103 }
104
105 fn package_dependents_iter(
106 &'a self,
107 package_id: PackageID,
108 ) -> impl Iterator<Item = &'a Dependency> {
109 self.dependencies.iter().filter(move |d| d.on == package_id)
110 }
111
112 pub fn package_dependents(&'a self, package_id: PackageID) -> Vec<&'a Dependency> {
114 self.package_dependents_iter(package_id).collect()
115 }
116
117 pub fn root_package_id(&'a self) -> PackageID {
118 self.root_package_id
119 }
120
121 pub fn root_package(&'a self) -> &'a Package {
122 self.packages.get(&self.root_package_id).unwrap()
123 }
124
125 pub fn root_package_dependencies(&'a self) -> Vec<&'a Dependency> {
126 self.package_dependencies(self.root_package_id)
127 }
128
129 pub fn root_package_prod_dependencies(&'a self) -> Vec<&'a Dependency> {
130 self.package_prod_dependencies(self.root_package_id)
131 }
132
133 pub fn workspace_member_ids(&'a self) -> &'a [PackageID] {
134 &self.workspace_members
135 }
136
137 pub fn workspace_members(&'a self) -> Vec<&'a Package> {
138 self.workspace_members
139 .iter()
140 .map(|pid| self.package(*pid))
141 .collect()
142 }
143
144 pub fn package_installations(&'a self, package_id: PackageID) -> Vec<&'a Installation> {
145 self.installations
146 .iter()
147 .filter(|i| i.package_id() == package_id)
148 .collect()
149 }
150}
151
152#[derive(Debug)]
153pub struct ChastefileBuilder {
154 packages: HashMap<PackageID, Package>,
155 dependencies: Vec<Dependency>,
156 installations: Vec<Installation>,
157 next_pid: u64,
158 root_package_id: Option<PackageID>,
159 workspace_members: Vec<PackageID>,
160}
161
162impl ChastefileBuilder {
163 #[allow(clippy::new_without_default)]
164 pub fn new() -> Self {
165 Self {
166 packages: HashMap::new(),
167 dependencies: Vec::new(),
168 installations: Vec::new(),
169 next_pid: 0,
170 root_package_id: None,
171 workspace_members: Vec::new(),
172 }
173 }
174
175 fn new_pid(&mut self) -> PackageID {
176 let pid = PackageID(self.next_pid);
177 self.next_pid += 1;
178 pid
179 }
180
181 pub fn add_package(&mut self, package: Package) -> Result<PackageID> {
182 if let Some((original_pid, _)) = self.packages.iter().find(|(_, p)| *p == &package) {
183 return Err(Error::DuplicatePackage(*original_pid));
184 }
185 let pid = self.new_pid();
186 self.packages.insert(pid, package);
187 Ok(pid)
188 }
189
190 pub fn add_package_installation(&mut self, installation: Installation) {
191 self.installations.push(installation);
192 }
193
194 pub fn add_dependency(&mut self, dependency: Dependency) {
195 self.dependencies.push(dependency);
196 }
197
198 pub fn add_dependencies(&mut self, dependencies: impl Iterator<Item = Dependency>) {
199 self.dependencies.extend(dependencies);
200 }
201
202 pub fn set_root_package_id(&mut self, root_pid: PackageID) -> Result<()> {
203 self.root_package_id = Some(root_pid);
204 Ok(())
205 }
206
207 pub fn set_as_workspace_member(&mut self, member_pid: PackageID) -> Result<()> {
208 self.workspace_members.push(member_pid);
209 Ok(())
210 }
211
212 pub fn build(self) -> Result<Chastefile> {
213 Ok(Chastefile {
214 packages: self.packages,
215 dependencies: self.dependencies,
216 installations: self.installations,
217 root_package_id: self.root_package_id.ok_or(Error::MissingRootPackageID)?,
218 workspace_members: self.workspace_members,
219 })
220 }
221}