Skip to main content

lux_cli/
update.rs

1use clap::Args;
2use eyre::{eyre, Context, OptionExt, Result};
3use itertools::Itertools;
4use lux_lib::package::{PackageName, PackageReq};
5use lux_lib::progress::{MultiProgress, ProgressBar};
6use lux_lib::project::Project;
7use lux_lib::remote_package_db::RemotePackageDB;
8use lux_lib::rockspec::lua_dependency;
9use lux_lib::{config::Config, operations};
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
37pub async fn update(args: Update, config: Config) -> Result<()> {
38    let progress = MultiProgress::new_arc(&config);
39    progress.map(|p| p.add(ProgressBar::from("🔎 Looking for updates...".to_string())));
40
41    if args.toml {
42        let mut project = Project::current()?.ok_or_eyre("No project found")?;
43
44        let progress = MultiProgress::new(&config);
45        let bar = progress.map(|progress| progress.new_bar());
46        let db = RemotePackageDB::from_config(&config, &bar).await?;
47        let package_names = to_package_names(args.packages.as_ref())?;
48        let mut upgrade_all = true;
49        if let Some(packages) = package_names {
50            upgrade_all = false;
51            project
52                .upgrade(lua_dependency::LuaDependencyType::Regular(packages), &db)
53                .await?;
54        }
55        let build_package_names = to_package_names(args.build.as_ref())?;
56        if let Some(packages) = build_package_names {
57            upgrade_all = false;
58            project
59                .upgrade(lua_dependency::LuaDependencyType::Build(packages), &db)
60                .await?;
61        }
62        let test_package_names = to_package_names(args.test.as_ref())?;
63        if let Some(packages) = test_package_names {
64            upgrade_all = false;
65            project
66                .upgrade(lua_dependency::LuaDependencyType::Test(packages), &db)
67                .await?;
68        }
69        if upgrade_all {
70            project.upgrade_all(&db).await?;
71        }
72    }
73
74    let updated_packages = operations::Update::new(&config)
75        .progress(progress)
76        .packages(args.packages)
77        .build_dependencies(args.build)
78        .test_dependencies(args.test)
79        .validate_integrity(!args.no_integrity_check)
80        .update()
81        .await
82        .wrap_err("update failed.")?;
83
84    if updated_packages.is_empty() {
85        println!("Nothing to update.");
86        return Ok(());
87    }
88
89    Ok(())
90}
91
92fn to_package_names(packages: Option<&Vec<PackageReq>>) -> Result<Option<Vec<PackageName>>> {
93    if packages.is_some_and(|pkgs| !pkgs.iter().any(|pkg| pkg.version_req().is_any())) {
94        return Err(eyre!(
95            "Cannot use version constraints to upgrade dependencies in lux.toml."
96        ));
97    }
98    Ok(packages
99        .as_ref()
100        .map(|pkgs| pkgs.iter().map(|pkg| pkg.name()).cloned().collect_vec()))
101}