willbe/entity/
dependency.rs

1mod private
2{
3
4
5  use crate :: *;
6
7  // use crates_tools ::CrateArchive;
8  // use workspace ::Workspace;
9  use error ::
10  {
11  // untyped ::Result,
12  // typed ::Error,
13  untyped ::format_err,
14 };
15
16  /// A dependency of the main crate
17  #[ derive( Debug, Clone, Copy ) ]
18  #[ repr( transparent ) ]
19  pub struct DependencyRef< 'a >
20  {
21  inner: &'a cargo_metadata ::Dependency,
22 }
23  // fix clippy
24  impl DependencyRef< '_ >
25  {
26
27  /// The file system path for a local path dependency.
28  /// Only produced on cargo 1.51+
29  #[ must_use ]
30  pub fn crate_dir( &self ) -> Option< CrateDir >
31  {
32   match &self.inner.path
33   {
34  Some( path ) => path.as_path().try_into().ok(),
35  None => None,
36 }
37 }
38
39  /// Name as given in the Cargo.toml.
40  #[ must_use ]
41  pub fn name( &self ) -> String
42  {
43   self.inner.name.clone()
44 }
45
46  /// The kind of dependency this is.
47  #[ must_use ]
48  pub fn kind( &self ) -> DependencyKind
49  {
50   match self.inner.kind
51   {
52  cargo_metadata ::DependencyKind ::Normal => DependencyKind ::Normal,
53  cargo_metadata ::DependencyKind ::Development => DependencyKind ::Development,
54  cargo_metadata ::DependencyKind ::Build => DependencyKind ::Build,
55  cargo_metadata ::DependencyKind ::Unknown => DependencyKind ::Unknown,
56 }
57 }
58
59  /// Required version
60  #[ must_use ]
61  pub fn req( &self ) -> semver ::VersionReq
62  {
63   self.inner.req.clone()
64 }
65 }
66
67  impl< 'a > From< &'a cargo_metadata ::Dependency > for DependencyRef< 'a >
68  {
69  #[ inline( always ) ]
70  fn from( inner: &'a cargo_metadata ::Dependency ) -> Self
71  {
72   Self { inner }
73 }
74 }
75
76  /// Dependencies can come in three kinds
77  #[ derive( Eq, PartialEq, Debug, Clone, Copy ) ]
78  pub enum DependencyKind
79  {
80  /// The 'normal' kind
81  Normal,
82  /// Those used in tests only
83  Development,
84  /// Those used in build scripts only
85  Build,
86  /// The 'unknown' kind
87  Unknown,
88 }
89
90  //
91
92  /// Identifier of any crate (local and remote).
93  #[ derive( Debug, Clone, Hash, Eq, PartialEq ) ]
94  pub struct CrateId
95  {
96  /// The name of the crate.
97  pub name: String, // qqq: that should be Arc< str >
98  /// The absolute path to the crate, if available.
99  pub crate_dir: Option< CrateDir >, // qqq: that should be Option< Arc< CrateDir > >
100  // pub path: Option< AbsolutePath >,
101 }
102
103  impl< 'a > From< &WorkspacePackageRef< 'a > > for CrateId
104  {
105  fn from( value: &WorkspacePackageRef< 'a > ) -> Self
106  {
107   Self
108   {
109  name: value.name().into(),
110  crate_dir: Some( value.crate_dir().unwrap() )
111  // path: Some( AbsolutePath ::try_from( value.manifest_file().parent().unwrap() ).unwrap() ),
112 }
113 }
114 }
115
116  impl From< &DependencyRef< '_ > > for CrateId
117  {
118  fn from( value: &DependencyRef< '_ > ) -> Self
119  {
120   Self
121   {
122  name: value.name(),
123  crate_dir: value.crate_dir(),
124  // path: value.path().clone().map( | path | AbsolutePath ::try_from( path ).unwrap() ),
125 }
126 }
127 }
128
129  /// Sorting variants for dependencies.
130  #[ derive( Debug, Copy, Clone ) ]
131  pub enum DependenciesSort
132  {
133  /// List will be topologically sorted.
134  Topological,
135  /// List will be unsorted.
136  Unordered,
137 }
138
139  #[ derive( Debug, Clone ) ]
140  /// Args for `local_dependencies` function.
141  pub struct DependenciesOptions
142  {
143  /// With dependencies of dependencies.
144  pub recursive: bool,
145  /// With sorting.
146  pub sort: DependenciesSort,
147  /// Include dev dependencies.
148  pub with_dev: bool,
149  /// Include remote dependencies.
150  pub with_remote: bool,
151 }
152
153  impl Default for DependenciesOptions
154  {
155  fn default() -> Self
156  {
157   Self
158   {
159  recursive: true,
160  sort: DependenciesSort ::Unordered,
161  with_dev: false,
162  with_remote: false,
163 }
164 }
165 }
166
167  // qqq: for Bohdan: poor description
168  /// Recursive implementation of the `list` function
169  /// # Errors
170  /// qqq: doc
171  ///
172  /// # Panics
173  /// qqq: doc
174  #[ allow( clippy ::needless_pass_by_value, clippy ::implicit_hasher ) ]
175  pub fn list_rec
176  (
177  workspace: &Workspace, // aaa: for Bohdan: no mut // aaa: no mut
178  package: &Package< '_ >,
179  graph: &mut collection ::HashMap< CrateId, collection ::HashSet< CrateId > >,
180  opts: DependenciesOptions
181 )
182  // qqq: use typed error
183  -> error ::untyped ::Result< CrateId >
184  {
185  let DependenciesOptions
186  {
187   recursive,
188   sort: _,
189   with_dev,
190   with_remote,
191 } = opts;
192  if recursive && with_remote { unimplemented!( "`recursive` + `with_remote` options") }
193
194  let manifest_file = &package.manifest_file();
195
196  let package = workspace
197  .package_find_by_manifest( manifest_file )
198  .ok_or( format_err!( "Package not found in the workspace with path: `{}`", manifest_file.as_ref().display() ) )?;
199
200  let deps: collection ::HashSet< _ > = package
201  .dependencies()
202  // .iter()
203  .filter( | dep | ( with_remote || dep.crate_dir().is_some() ) && ( with_dev || dep.kind() != DependencyKind ::Development ) )
204  .map( | dep | CrateId ::from( &dep ) )
205  .collect();
206
207  let package = CrateId ::from( &package );
208  graph.insert( package.clone(), deps.clone() );
209
210  if recursive
211  {
212   for dep in deps
213   {
214  if graph.get( &dep ).is_none()
215  {
216   // unwrap because `recursive` + `with_remote` not yet implemented
217   list_rec
218   (
219  workspace,
220  &dep.crate_dir.unwrap().try_into()?,
221  // &dep.path.as_ref().unwrap().join( "Cargo.toml" ).try_into().unwrap(),
222  graph,
223  opts.clone(),
224 )?;
225 }
226 }
227 }
228
229  Ok( package )
230 }
231
232  /// Returns local dependencies of a specified package by its package path from a workspace.
233  ///
234  /// # Arguments
235  ///
236  /// - `workspace` - holds cached information about the workspace, such as the packages it contains and their dependencies. By passing it as a mutable reference, function can update the cache as needed.
237  /// - `package` - The package package file contains package about the package such as its name, version, and dependencies.
238  /// - `opts` - used to specify options or configurations for fetching local dependencies.
239  ///
240  /// # Returns
241  ///
242  /// If the operation is successful, returns a vector of `PathBuf` objects, where each `PathBuf` represents the path to a local dependency of the specified package.
243  /// # Errors
244  /// qqq: doc
245  // qqq: typed error?
246  #[ allow( clippy ::needless_pass_by_value ) ]
247  pub fn list
248  (
249  workspace: &mut Workspace,
250  package: &Package< '_ >,
251  opts: DependenciesOptions
252 )
253  // qqq: use typed error
254  -> error ::untyped ::Result< Vec< CrateId > >
255  {
256  let mut graph = collection ::HashMap ::new();
257  let root = list_rec( workspace, package, &mut graph, opts.clone() )?;
258
259  let output = match opts.sort
260  {
261   DependenciesSort ::Unordered =>
262   {
263  graph
264  .into_iter()
265  .flat_map( | ( id, dependency ) |
266  {
267   dependency
268   .into_iter()
269   .chain( Some( id ) )
270 })
271  .unique()
272  .filter( | x | x != &root )
273  .collect()
274 }
275   DependenciesSort ::Topological =>
276   {
277  // aaa: too long line
278  // aaa: splited
279  graph ::toposort( graph ::construct( &graph ) )
280  .map_err( | err | format_err!( "{err}" ) )?
281  .into_iter()
282  .filter( | x | x != &root )
283  .collect()
284 },
285 };
286
287  Ok( output )
288 }
289
290}
291
292//
293
294crate ::mod_interface!
295{
296
297  exposed use DependencyRef;
298  exposed use DependencyKind;
299
300  own use CrateId;
301  own use DependenciesSort;
302  own use DependenciesOptions;
303  own use list_rec;
304  own use list;
305
306}