Skip to main content

lux_cli/
update.rs

1use clap::Args;
2use itertools::Itertools;
3use lux_lib::package::{PackageName, PackageReq};
4
5use lux_lib::remote_package_db::RemotePackageDB;
6use lux_lib::rockspec::lua_dependency::LuaDependencyType;
7use lux_lib::workspace::Workspace;
8use lux_lib::{config::Config, operations};
9use miette::{miette, Context, Result};
10
11#[derive(Args)]
12pub struct Update {
13    /// Skip the integrity checks for installed rocks when syncing the project lockfile.
14    #[arg(long)]
15    no_integrity_check: bool,
16
17    /// Upgrade packages in the project's lux.toml (if operating on a project)
18    #[arg(long)]
19    toml: bool,
20
21    /// Packages to update.
22    /// When used with the --toml flag in a project, these must be package names.
23    packages: Option<Vec<PackageReq>>,
24
25    /// Build dependencies to update.
26    /// Also called `dev`.
27    /// When used with the --toml flag in a project, these must be package names.
28    #[arg(short, long, alias = "dev", visible_short_aliases = ['d', 'b'])]
29    build: Option<Vec<PackageReq>>,
30
31    /// Build dependencies to update.
32    /// When used with the --toml flag in a project, these must be package names.
33    #[arg(short, long)]
34    test: Option<Vec<PackageReq>>,
35
36    /// Project to modify.
37    #[arg(short, long, visible_short_alias = 'p')]
38    pub(crate) package: Option<PackageName>,
39}
40
41pub async fn update(args: Update, config: Config) -> Result<()> {
42    if args.toml {
43        let mut workspace = Workspace::current_or_err()?;
44
45        let db = RemotePackageDB::from_config(&config).await?;
46        let package_names = to_package_names(args.packages.as_ref())?;
47        let mut upgrade_all = true;
48        if let Some(packages) = package_names {
49            upgrade_all = false;
50            if let Some(package) = &args.package {
51                let project = workspace.select_member_mut(package)?;
52                project
53                    .upgrade(
54                        LuaDependencyType::Regular(packages.iter().collect()),
55                        &db,
56                        &config,
57                    )
58                    .await?;
59            } else {
60                for project in workspace.members_mut().iter_mut() {
61                    project
62                        .upgrade(
63                            LuaDependencyType::Regular(packages.iter().collect()),
64                            &db,
65                            &config,
66                        )
67                        .await?;
68                }
69            }
70        }
71        let build_package_names = to_package_names(args.build.as_ref())?;
72        if let Some(packages) = build_package_names {
73            upgrade_all = false;
74            if let Some(package) = &args.package {
75                let project = workspace.select_member_mut(package)?;
76                project
77                    .upgrade(
78                        LuaDependencyType::Build(packages.iter().collect()),
79                        &db,
80                        &config,
81                    )
82                    .await?;
83            } else {
84                for project in workspace.members_mut().iter_mut() {
85                    project
86                        .upgrade(
87                            LuaDependencyType::Build(packages.iter().collect()),
88                            &db,
89                            &config,
90                        )
91                        .await?;
92                }
93            }
94        }
95        let test_package_names = to_package_names(args.test.as_ref())?;
96        if let Some(packages) = test_package_names {
97            upgrade_all = false;
98            if let Some(package) = &args.package {
99                let project = workspace.select_member_mut(package)?;
100                project
101                    .upgrade(
102                        LuaDependencyType::Test(packages.iter().collect()),
103                        &db,
104                        &config,
105                    )
106                    .await?;
107            } else {
108                for project in workspace.members_mut().iter_mut() {
109                    project
110                        .upgrade(
111                            LuaDependencyType::Test(packages.iter().collect()),
112                            &db,
113                            &config,
114                        )
115                        .await?;
116                }
117            }
118        }
119        if upgrade_all {
120            if let Some(package) = &args.package {
121                let project = workspace.select_member_mut(package)?;
122                project.upgrade_all(&db, &config).await?;
123            } else {
124                for project in workspace.members_mut().iter_mut() {
125                    project.upgrade_all(&db, &config).await?;
126                }
127            }
128        }
129    }
130
131    let updated_packages = operations::Update::new(&config)
132        .packages(args.packages)
133        .build_dependencies(args.build)
134        .test_dependencies(args.test)
135        .validate_integrity(!args.no_integrity_check)
136        .update()
137        .await
138        .wrap_err("update failed.")?;
139
140    if updated_packages.is_empty() {
141        println!("Nothing to update.");
142        return Ok(());
143    }
144
145    Ok(())
146}
147
148fn to_package_names(packages: Option<&Vec<PackageReq>>) -> Result<Option<Vec<PackageName>>> {
149    if packages.is_some_and(|pkgs| !pkgs.iter().any(|pkg| pkg.version_req().is_any())) {
150        let names_str = if packages.is_some_and(|pkgs| pkgs.len() == 1) {
151            "package names"
152        } else {
153            "a package name"
154        };
155        return Err(miette!(
156            help = format!("specify {names_str} using the '--toml' flag"),
157            "cannot use version constraints to upgrade dependencies in lux.toml."
158        ));
159    }
160    Ok(packages
161        .as_ref()
162        .map(|pkgs| pkgs.iter().map(|pkg| pkg.name()).cloned().collect_vec()))
163}