Skip to main content

lux_lib/operations/
generate_lockfile.rs

1use bon::Builder;
2use miette::Diagnostic;
3use thiserror::Error;
4
5use crate::{
6    config::Config,
7    drivers::sync::{gather_dependencies, DependencyKind, SyncError},
8    package_db::{PackageDB, PackageDBError},
9    pipeline::{
10        emit_lockfile::LockfileHandle,
11        materialise::{Error as MaterialiseError, Materialise},
12        resolve::{ResolveError, ResolvePackageDependencies},
13    },
14    workspace::{Workspace, WorkspaceError},
15};
16
17/// Generates a workspace's lockfile without installing anything.
18#[derive(Builder)]
19#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
20pub struct GenerateLockfile<'a> {
21    #[builder(start_fn)]
22    config: &'a Config,
23    #[builder(start_fn)]
24    workspace: &'a Workspace,
25}
26
27impl<State> GenerateLockfileBuilder<'_, State>
28where
29    State: generate_lockfile_builder::State + generate_lockfile_builder::IsComplete,
30{
31    pub async fn generate(self) -> Result<(), GenerateLockfileError> {
32        generate_lockfile(self._build()).await
33    }
34}
35
36async fn generate_lockfile(args: GenerateLockfile<'_>) -> Result<(), GenerateLockfileError> {
37    let GenerateLockfile { config, workspace } = args;
38
39    let members = workspace.member_names()?;
40    let package_db = PackageDB::open(config, workspace).await?;
41
42    let resolve = ResolvePackageDependencies::new(package_db, config)
43        .packages(gather_dependencies(
44            workspace,
45            DependencyKind::Regular,
46            &members,
47        )?)
48        .build_packages(gather_dependencies(
49            workspace,
50            DependencyKind::Build,
51            &members,
52        )?)
53        .test_packages(gather_dependencies(
54            workspace,
55            DependencyKind::Test,
56            &members,
57        )?);
58
59    let resolved = resolve.resolve().await?;
60    let artifacts = Materialise::new(config)
61        .resolved(resolved)
62        .materialise()
63        .await?;
64
65    let handle = LockfileHandle::from_artifacts(&artifacts);
66
67    let mut lockfile = workspace.lockfile()?.write_guard();
68    handle.commit(&mut lockfile);
69
70    Ok(())
71}
72
73#[derive(Error, Debug, Diagnostic)]
74pub enum GenerateLockfileError {
75    #[error(transparent)]
76    #[diagnostic(transparent)]
77    PackageDB(#[from] PackageDBError),
78    #[error(transparent)]
79    #[diagnostic(transparent)]
80    Workspace(#[from] WorkspaceError),
81    #[error(transparent)]
82    #[diagnostic(transparent)]
83    Sync(Box<SyncError>),
84    #[error(transparent)]
85    #[diagnostic(transparent)]
86    Resolve(#[from] ResolveError),
87    #[error(transparent)]
88    #[diagnostic(transparent)]
89    Materialise(#[from] MaterialiseError),
90}
91
92impl From<SyncError> for GenerateLockfileError {
93    fn from(source: SyncError) -> Self {
94        Self::Sync(Box::new(source))
95    }
96}