1use std::{path::PathBuf, str::FromStr};
2
3use crate::build;
4use clap::Args;
5use eyre::{eyre, Result};
6use lux_lib::{
7 build::{Build, BuildBehaviour},
8 config::{Config, LuaVersion},
9 lua_rockspec::RemoteLuaRockspec,
10 operations::{self, Install, PackageInstallSpec},
11 package::PackageReq,
12 progress::MultiProgress,
13 project::Project,
14 rockspec::Rockspec as _,
15 tree,
16};
17use tempdir::TempDir;
18
19#[derive(Debug, Clone)]
20pub enum PackageOrRockspec {
21 Package(PackageReq),
22 RockSpec(PathBuf),
23}
24
25impl FromStr for PackageOrRockspec {
26 type Err = eyre::Error;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 let path = PathBuf::from(s);
30 if path.is_file() {
31 Ok(Self::RockSpec(path))
32 } else {
33 let pkg = PackageReq::from_str(s).map_err(|err| {
34 eyre!(
35 "No file {0} found and cannot parse package query: {1}",
36 s,
37 err
38 )
39 })?;
40 Ok(Self::Package(pkg))
41 }
42 }
43}
44
45#[derive(Args)]
46pub struct Pack {
47 #[clap(value_parser)]
62 package_or_rockspec: Option<PackageOrRockspec>,
63}
64
65pub async fn pack(args: Pack, config: Config) -> Result<()> {
66 let lua_version = LuaVersion::from(&config)?.clone();
67 let dest_dir = std::env::current_dir()?;
68 let progress = MultiProgress::new_arc();
69 let result: Result<PathBuf> = match args.package_or_rockspec {
70 Some(PackageOrRockspec::Package(package_req)) => {
71 let user_tree = config.user_tree(lua_version.clone())?;
72 match user_tree.match_rocks(&package_req)? {
73 lux_lib::tree::RockMatches::NotFound(_) => {
74 let temp_dir = TempDir::new("lux-pack")?.into_path();
75 let temp_config = config.with_tree(temp_dir);
76 let tree = temp_config.user_tree(lua_version.clone())?;
77 let packages = Install::new(&temp_config)
78 .package(
79 PackageInstallSpec::new(package_req, tree::EntryType::Entrypoint)
80 .build_behaviour(BuildBehaviour::Force)
81 .build(),
82 )
83 .tree(tree.clone())
84 .progress(progress)
85 .install()
86 .await?;
87 let package = packages.first().unwrap();
88 let rock_path = operations::Pack::new(dest_dir, tree, package.clone())
89 .pack()
90 .await?;
91 Ok(rock_path)
92 }
93 lux_lib::tree::RockMatches::Single(local_package_id) => {
94 let lockfile = user_tree.lockfile()?;
95 let package = lockfile.get(&local_package_id).unwrap();
96 let rock_path = operations::Pack::new(dest_dir, user_tree, package.clone())
97 .pack()
98 .await?;
99 Ok(rock_path)
100 }
101 lux_lib::tree::RockMatches::Many(vec) => {
102 let local_package_id = vec.first().unwrap();
103 let lockfile = user_tree.lockfile()?;
104 let package = lockfile.get(local_package_id).unwrap();
105 let rock_path = operations::Pack::new(dest_dir, user_tree, package.clone())
106 .pack()
107 .await?;
108 Ok(rock_path)
109 }
110 }
111 }
112 Some(PackageOrRockspec::RockSpec(rockspec_path)) => {
113 let content = std::fs::read_to_string(&rockspec_path)?;
114 let rockspec = match rockspec_path
115 .extension()
116 .map(|ext| ext.to_string_lossy().to_string())
117 .unwrap_or("".into())
118 .as_str()
119 {
120 ".rockspec" => Ok(RemoteLuaRockspec::new(&content)?),
121 _ => Err(eyre!(
122 "expected a path to a .rockspec or a package requirement."
123 )),
124 }?;
125 let temp_dir = TempDir::new("lux-pack")?.into_path();
126 let bar = progress.map(|p| p.new_bar());
127 let config = config.with_tree(temp_dir);
128 let tree = config.user_tree(lua_version)?;
129 let package = Build::new(&rockspec, &tree, tree::EntryType::Entrypoint, &config, &bar)
130 .build()
131 .await?;
132 let rock_path = operations::Pack::new(dest_dir, tree, package)
133 .pack()
134 .await?;
135 Ok(rock_path)
136 }
137 None => {
138 let project = Project::current_or_err()?;
139 project
142 .toml()
143 .into_remote()?
144 .to_lua_remote_rockspec_string()?;
145 let package = build::build(build::Build::default(), config.clone())
146 .await?
147 .expect("exptected a `LocalPackage`");
148 let tree = project.tree(&config)?;
149 let rock_path = operations::Pack::new(dest_dir, tree, package)
150 .pack()
151 .await?;
152 Ok(rock_path)
153 }
154 };
155 print!("packed rock created at {}", result?.display());
156 Ok(())
157}