Skip to main content

lux_cli/
workspace.rs

1use std::{collections::HashSet, path::PathBuf};
2
3use std::{str::FromStr, sync::Arc};
4
5use eyre::{Context, Result};
6use itertools::Itertools;
7use lux_lib::{
8    config::Config,
9    git::shorthand::RemoteGitUrlShorthand,
10    lua_version::LuaVersion,
11    operations::Sync,
12    package::PackageReq,
13    progress::{MultiProgress, Progress},
14    tree::Tree,
15    workspace::Workspace,
16};
17use walkdir::WalkDir;
18
19pub fn top_level_ignored_files(project: &Workspace) -> Vec<PathBuf> {
20    let top_level_project_files = ignore::WalkBuilder::new(project.root())
21        .max_depth(Some(1))
22        .build()
23        .filter_map(Result::ok)
24        .filter_map(|entry| {
25            let file = entry.into_path();
26            if file.is_dir() || file.extension().is_some_and(|ext| ext == "lua") {
27                Some(file)
28            } else {
29                None
30            }
31        })
32        .collect::<HashSet<_>>();
33
34    let top_level_files = WalkDir::new(project.root())
35        .max_depth(1)
36        .into_iter()
37        .filter_map(Result::ok)
38        .filter_map(|entry| {
39            let file = entry.into_path();
40            if file.is_dir() || file.extension().is_some_and(|ext| ext == "lua") {
41                Some(file)
42            } else {
43                None
44            }
45        })
46        .collect::<HashSet<_>>();
47
48    top_level_files
49        .difference(&top_level_project_files)
50        .cloned()
51        .collect_vec()
52}
53
54/// Used for parsing alternatives between a git URL shorthand and a package requirement.
55// The `FromStr` instance tries to parse a git URL shorthand first (expecting a git host prefix),
56// and then a package requirement.
57#[derive(Debug, Clone)]
58pub enum PackageReqOrGitShorthand {
59    PackageReq(PackageReq),
60    GitShorthand(RemoteGitUrlShorthand),
61}
62
63impl FromStr for PackageReqOrGitShorthand {
64    type Err = eyre::Error;
65
66    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
67        match RemoteGitUrlShorthand::parse_with_prefix(s) {
68            Ok(shorthand) => Ok(Self::GitShorthand(shorthand)),
69            Err(_) => Ok(Self::PackageReq(PackageReq::parse(s)?)),
70        }
71    }
72}
73
74/// Get the current workspaces tree, or fall back to
75/// the user tree if not in a project
76pub fn current_workspace_or_user_tree(config: &Config) -> Result<Tree> {
77    let workspace = Workspace::current()?;
78    Ok(match &workspace {
79        Some(workspace) => workspace.tree(config)?,
80        None => {
81            let lua_version = LuaVersion::from(config)?.clone();
82            config.user_tree(lua_version)?
83        }
84    })
85}
86
87pub async fn sync_dependencies_if_locked(
88    workspace: &Workspace,
89    progress: Arc<Progress<MultiProgress>>,
90    config: &Config,
91) -> Result<()> {
92    // NOTE: We only update the lockfile if one exists.
93    // Otherwise, the next `lx build` will remove the packages.
94    Sync::new(workspace, config)
95        .progress(progress)
96        .sync_dependencies()
97        .await
98        .wrap_err("syncing dependencies with the project lockfile failed.")?;
99    Ok(())
100}
101
102pub async fn sync_build_dependencies_if_locked(
103    workspace: &Workspace,
104    progress: Arc<Progress<MultiProgress>>,
105    config: &Config,
106) -> Result<()> {
107    Sync::new(workspace, config)
108        .progress(progress.clone())
109        .sync_build_dependencies()
110        .await
111        .wrap_err("syncing build dependencies with the project lockfile failed.")?;
112    Ok(())
113}
114
115pub async fn sync_test_dependencies_if_locked(
116    workspace: &Workspace,
117    progress: Arc<Progress<MultiProgress>>,
118    config: &Config,
119) -> Result<()> {
120    Sync::new(workspace, config)
121        .progress(progress.clone())
122        .sync_test_dependencies()
123        .await
124        .wrap_err("syncing test dependencies with the project lockfile failed.")?;
125    Ok(())
126}