Skip to main content

lux_cli/
workspace.rs

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