1use clap::Args;
2use eyre::eyre;
3use eyre::Context;
4use eyre::Result;
5use itertools::Itertools;
6use lux_lib::config::Config;
7use lux_lib::lockfile::PinnedState;
8use lux_lib::lua_version::LuaVersion;
9use lux_lib::operations;
10use lux_lib::package::PackageName;
11use lux_lib::package::PackageReq;
12use lux_lib::progress::MultiProgress;
13use lux_lib::project::Project;
14use lux_lib::rockspec::lua_dependency;
15use lux_lib::tree::RockMatches;
16
17#[derive(Args)]
18pub struct ChangePin {
19 package: Vec<PackageReq>,
23
24 #[arg(short, long, alias = "dev", visible_short_aliases = ['d', 'b'])]
27 build: Option<Vec<PackageName>>,
28
29 #[arg(short, long)]
31 test: Option<Vec<PackageName>>,
32}
33
34pub async fn set_pinned_state(data: ChangePin, config: Config, pin: PinnedState) -> Result<()> {
35 match Project::current()? {
36 Some(mut project) => {
37 let progress = MultiProgress::new_arc(&config);
38 if data.package.iter().any(|pkg| !pkg.version_req().is_any()) {
39 return Err(eyre!(
40 "Cannot pin project dependencies using version constraints."
41 ));
42 }
43 let packages = data
44 .package
45 .iter()
46 .map(|pkg| pkg.name())
47 .cloned()
48 .collect_vec();
49 if !packages.is_empty() {
50 project
51 .set_pinned_state(lua_dependency::LuaDependencyType::Regular(packages), pin)
52 .await?;
53 operations::Sync::new(&project, &config)
54 .progress(progress.clone())
55 .sync_dependencies()
56 .await
57 .wrap_err("syncing dependencies with the project lockfile failed.")?;
58 }
59 let build_packages = data.build.unwrap_or_default();
60 if !build_packages.is_empty() {
61 project
62 .set_pinned_state(
63 lua_dependency::LuaDependencyType::Build(build_packages),
64 pin,
65 )
66 .await?;
67 operations::Sync::new(&project, &config)
68 .progress(progress.clone())
69 .sync_build_dependencies()
70 .await
71 .wrap_err("syncing build dependencies with the project lockfile failed.")?;
72 }
73 let test_packages = data.test.unwrap_or_default();
74 if !test_packages.is_empty() {
75 project
76 .set_pinned_state(lua_dependency::LuaDependencyType::Test(test_packages), pin)
77 .await?;
78 operations::Sync::new(&project, &config)
79 .progress(progress.clone())
80 .sync_test_dependencies()
81 .await
82 .wrap_err("syncing test dependencies with the project lockfile failed.")?;
83 }
84 }
85 None => {
86 let tree = config.user_tree(LuaVersion::from(&config)?.clone())?;
87
88 for package in &data.package {
89 match tree.match_rocks_and(package, |package| pin != package.pinned())? {
90 RockMatches::Single(rock) => {
91 operations::set_pinned_state(&rock, &tree, pin)?;
92 }
93 RockMatches::Many(_) => {
94 todo!("Add an error here about many conflicting types and to use `all:`")
95 }
96 RockMatches::NotFound(_) => return Err(eyre!("Rock {} not found!", package)),
97 }
98 }
99 }
100 }
101 Ok(())
102}