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}