Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
444bbb6
temp: extra tests
vhyrro Sep 22, 2026
af656ff
feat!: pipeline implementation
vhyrro Sep 22, 2026
9aed4c2
temp: more tests
vhyrro Sep 24, 2026
10459ac
refactor!: reimplement vendor logic
vhyrro Sep 24, 2026
32edf77
fix: collapse artifact types into single `Artifact`
vhyrro Oct 3, 2026
daca2c4
fix: `EmitLockfile` -> `LockfileHandle`
vhyrro Oct 3, 2026
a8358bd
refactor: simplify `InstallWorkspaceDependencies`
vhyrro Oct 3, 2026
ddb0d8b
fix(BuildProject): only read project dependencies not all workspace d…
vhyrro Oct 3, 2026
1fe913f
fix: remove `dyn` errors
vhyrro Oct 3, 2026
88cdb45
refactor!: break apart `LockedPackage::binaries()` into the lockfile
vhyrro Oct 3, 2026
50c3aaf
feat!: parallelize resolve and build
vhyrro Oct 3, 2026
69113bd
feat: paralellize build step
vhyrro Oct 4, 2026
f440da7
fix(vendor): deduplicate code in vendor logic
vhyrro Oct 4, 2026
3a2b7cf
feat(lockfile): use atomic writes to prevent corruption during multit…
vhyrro Oct 4, 2026
b1713d1
fix(sync): use `Sync` in `SyncWorkspace` instead of `InstallWorkspace…
vhyrro Oct 4, 2026
823c47d
feat!: unify search and resolution into RemotePackageDB
vhyrro Oct 4, 2026
4f60b76
feat!: unify install_rockspec logic with new pipeline
vhyrro Oct 4, 2026
a384735
refactor: make PackageSource take a PathBuf
vhyrro Oct 4, 2026
77c6fec
refactor!: join `Build` to pipeline
vhyrro Oct 4, 2026
34d664f
refactor!: route Project building through the same code as package bu…
vhyrro Oct 4, 2026
a75aa26
fix: multiple small fixes and refactors
vhyrro Oct 4, 2026
629966a
fix: more fixes, cleanup
vhyrro Oct 5, 2026
ddfc434
feat!: granularize BuildBehaviour
vhyrro Oct 5, 2026
cf3e0ab
fix: lux-lua compilation
vhyrro Oct 5, 2026
878fe9d
feat!(resolve): do not reinstall already existing packages, rebuild p…
vhyrro Oct 5, 2026
3b1866a
feat!: unify Sync operation across codebase
vhyrro Oct 5, 2026
74fc1fd
fix: don't include `.luarc.json` and others in project hashes
vhyrro Oct 6, 2026
035c961
fix: `lint` command reinstalling `luacheck` each time
vhyrro Oct 7, 2026
9cfdbd0
fix(outdated): don't resync the project
vhyrro Oct 7, 2026
e55f4ef
fix(build): force install unavailable packages
vhyrro Oct 7, 2026
3747485
fix(TargetSet): use constructors instead of explicit construction
vhyrro Oct 7, 2026
9683dc2
refactor: `reconcile` -> `sync::frozen`
vhyrro Oct 8, 2026
4504d0c
refactor!: `RemotePackageDB` -> `PackageDB`
vhyrro Oct 8, 2026
9d2714e
fix: resolve nitpicks and PR suggestions
vhyrro Oct 10, 2026
320a307
fix: make CI happy
vhyrro Oct 10, 2026
e4bee7f
fix: properly gate impure tests for CI
vhyrro Oct 11, 2026
8e5e048
feat(lockfile): auto-migrate lockfiles with default layout (#1998)
mrcjkb Oct 5, 2026
0c39628
fix(lux-lua): mark loader test as impure
vhyrro Oct 11, 2026
786cfa2
fix(ci): make CI happy
vhyrro Oct 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lux-cli/src/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use itertools::{Either, Itertools};
use lux_lib::{
config::Config,
package::PackageName,
remote_package_db::RemotePackageDB,
package_db::PackageDB,
rockspec::lua_dependency::{self},
workspace::Workspace,
};
Expand Down Expand Up @@ -45,7 +45,7 @@ pub struct Add {
pub async fn add(data: Add, config: Config) -> Result<()> {
let mut workspace = Workspace::current_or_err()?;
let project = workspace.single_member_or_select_mut(&data.package)?;
let db = RemotePackageDB::from_config(&config).await?;
let db = PackageDB::from_config(&config).await?;

let (dependencies, git_dependencies): (Vec<_>, Vec<_>) =
data.package_req.iter().partition_map(|req| match req {
Expand Down
30 changes: 22 additions & 8 deletions lux-cli/src/build.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use clap::Args;
use lux_lib::{
build::BuildBehaviour,
config::Config,
lockfile::LocalPackage,
operations::{self},
drivers::sync::{Sync, SyncMode, TargetSet},
lockfile::LockedPackage,
package::PackageName,
workspace::Workspace,
};
Expand All @@ -24,15 +25,28 @@ pub struct Build {
}

/// Returns `Some` if the `only_deps` arg is set to `false`.
pub async fn build(data: Build, config: Config) -> Result<Vec<LocalPackage>> {
pub async fn build(data: Build, config: Config) -> Result<Vec<LockedPackage>> {
build_with_behaviour(data, config, BuildBehaviour::Force).await
}

pub async fn build_with_behaviour(
data: Build,
config: Config,
behaviour: BuildBehaviour,
) -> Result<Vec<LockedPackage>> {
let workspace = Workspace::current_or_err()?;
let result = operations::BuildWorkspace::new(&workspace, &config)
.maybe_package(data.package)
.no_lock(data.no_lock)
let report = Sync::new(&workspace, &config)
.mode(SyncMode::Open)
.targets(match data.package {
Some(package) => TargetSet::member(package, false),
None => TargetSet::all(&workspace, false),
})
.behaviour(behaviour)
.only_deps(data.only_deps)
.build()
.no_lock(data.no_lock)
.sync()
.await?;
Ok(result)
Ok(report.added().to_vec())
}

#[cfg(test)]
Expand Down
23 changes: 14 additions & 9 deletions lux-cli/src/dist/flat_archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ use std::{

use clap::Args;
use lux_lib::{
build::{Build, BuildBehaviour},
build::BuildBehaviour,
config::{Config, ConfigBuilder},
lockfile::LocalPackage,
drivers::install_packages::InstallPackages,
lockfile::LockedPackage,
lua_installation::LuaInstallation,
lua_rockspec::RemoteLuaRockspec,
lua_version::LuaVersion,
operations::{Install, InstallProject, PackageInstallSpec},
operations::{InstallProject, PackageInstallSpec},
package::{PackageName, PackageReq},
package_db::PackageDB,
pipeline::build_local::Build,
tree::{self, FlatDistTree, InstallTree},
workspace::Workspace,
};
Expand Down Expand Up @@ -132,7 +135,7 @@ async fn install_project(
package: Option<&PackageName>,
staging_dir: &TempDir,
config: &Config,
) -> Result<(LocalPackage, PathBuf)> {
) -> Result<(LockedPackage, PathBuf)> {
let workspace = Workspace::current_or_err()?;
let project = match package {
Some(package) => workspace.select_member(package)?,
Expand All @@ -155,18 +158,19 @@ async fn install_package(
package: &PackageReq,
staging_dir: &TempDir,
config: &Config,
) -> Result<(LocalPackage, PathBuf)> {
) -> Result<(LockedPackage, PathBuf)> {
let lua_version = LuaVersion::from(config)?.clone();
let tree = FlatDistTree::new(staging_dir.path().to_path_buf(), lua_version, config)?;
let packages = Install::new(config)
let packages = InstallPackages::new(config, &tree)
.package(
PackageInstallSpec::new(package.clone(), tree::EntryType::Entrypoint)
.build_behaviour(BuildBehaviour::Force)
.build(),
)
.tree(tree.clone())
.package_db(PackageDB::from_config(config).await?)
.install()
.await?;
.await?
.0;
let package = packages
.into_iter()
.find(|pkg| pkg.name() == package.name())
Expand All @@ -178,7 +182,7 @@ async fn install_rockspec(
rockspec_path: &Path,
staging_dir: &TempDir,
config: &Config,
) -> Result<(LocalPackage, PathBuf)> {
) -> Result<(LockedPackage, PathBuf)> {
let content = tokio::fs::read_to_string(&rockspec_path)
.await
.into_diagnostic()?;
Expand All @@ -203,6 +207,7 @@ async fn install_rockspec(
.tree(&tree)
.entry_type(tree::EntryType::Entrypoint)
.config(config)
.behaviour(BuildBehaviour::Force)
.build()
.await?;
Ok((package, tree.root()))
Expand Down
12 changes: 6 additions & 6 deletions lux-cli/src/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use inquire::{Confirm, Select};
use itertools::Itertools;
use lux_lib::{
config::Config,
lockfile::LocalPackage,
lockfile::LockedPackage,
lua_rockspec::RemoteLuaRockspec,
lua_version::LuaVersion,
package::PackageReq,
Expand Down Expand Up @@ -50,7 +50,7 @@ pub async fn doc(args: Doc, config: Config) -> Result<()> {
}
}

async fn open_homepage(pkg: LocalPackage, tree: &Tree) -> Result<()> {
async fn open_homepage(pkg: LockedPackage, tree: &Tree) -> Result<()> {
let homepage = match get_homepage(&pkg, tree)? {
Some(homepage) => Ok(homepage),
None => Err(miette!(
Expand All @@ -62,9 +62,9 @@ async fn open_homepage(pkg: LocalPackage, tree: &Tree) -> Result<()> {
Ok(())
}

fn get_homepage(pkg: &LocalPackage, tree: &Tree) -> Result<Option<Url>> {
fn get_homepage(pkg: &LockedPackage, tree: &Tree) -> Result<Option<Url>> {
let rockspec_content =
std::fs::read_to_string(tree.layout_for(pkg).rockspec_path()).into_diagnostic()?;
std::fs::read_to_string(tree.layout_for(pkg.spec()).rockspec_path()).into_diagnostic()?;
let rockspec = RemoteLuaRockspec::new(&rockspec_content)?;
Ok(rockspec.description().homepage.clone())
}
Expand All @@ -88,8 +88,8 @@ fn open_doc_file(path: &Path) -> Result<()> {
Ok(())
}

async fn open_local_docs(pkg: LocalPackage, tree: &Tree, config: &Config) -> Result<()> {
let doc_dir = tree.layout_for(&pkg).doc;
async fn open_local_docs(pkg: LockedPackage, tree: &Tree, config: &Config) -> Result<()> {
let doc_dir = tree.layout_for(pkg.spec()).doc;
let files: Vec<String> = WalkDir::new(&doc_dir)
.into_iter()
.filter_map_ok(|file| {
Expand Down
7 changes: 5 additions & 2 deletions lux-cli/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use std::path::PathBuf;

use lux_lib::{
config::Config,
drivers::install_packages::InstallPackages,
lockfile::PinnedState,
lua_version::LuaVersion,
operations,
package::{PackageName, PackageReq},
package_db::PackageDB,
workspace::{Workspace, WorkspaceError},
};

Expand Down Expand Up @@ -62,6 +64,7 @@ async fn install_from_path(
.project(project)
.config(&config)
.tree(&tree)
.workspace(&workspace)
.build()
.await?;

Expand All @@ -77,9 +80,9 @@ async fn install_remote(data: Install, config: Config) -> Result<()> {
let packages = apply_build_behaviour(data.package_req, pin, data.force, &tree, &config)?;

// TODO(vhyrro): If the tree doesn't exist then error out.
operations::Install::new(&config)
InstallPackages::new(&config, &tree)
.packages(packages)
.tree(tree)
.package_db(PackageDB::from_config(&config).await?)
.install()
.await?;

Expand Down
4 changes: 2 additions & 2 deletions lux-cli/src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use clap::Args;
use itertools::Itertools as _;
use lux_lib::{
config::Config,
lockfile::{LocalPackageId, PinnedState},
lockfile::{LockedPackageId, PinnedState},
lua_version::LuaVersion,
tree::InstallTree,
};
Expand Down Expand Up @@ -33,7 +33,7 @@ pub fn list_installed(list_data: ListCmd, config: Config) -> Result<()> {
let lockfile = tree.lockfile()?;
let mut available_rocks = tree.list()?;
if list_data.orphans {
let reachable: HashSet<LocalPackageId> = lockfile
let reachable: HashSet<LockedPackageId> = lockfile
.reachable_rocks()
.into_iter()
.map(|package| package.id())
Expand Down
32 changes: 19 additions & 13 deletions lux-cli/src/outdated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use std::collections::HashMap;
use clap::Args;
use itertools::Itertools;
use lux_lib::{
config::Config, lockfile::LocalPackage, lua_version::LuaVersion, package::PackageVersion,
remote_package_db::RemotePackageDB, workspace::Workspace,
config::Config, lockfile::LockedPackage, lua_version::LuaVersion, package::PackageVersion,
package_db::PackageDB, workspace::Workspace,
};

use miette::{IntoDiagnostic, Result};
use text_trees::{FormatCharacters, StringTreeNode, TreeFormatting};

use crate::{args::OutputFormat, workspace::sync_dependencies_if_locked};
use crate::args::OutputFormat;

#[derive(Args)]
pub struct Outdated {
Expand All @@ -22,19 +22,18 @@ pub struct Outdated {
/// If in a project, this lists rocks in the project tree
pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> {
let workspace = Workspace::current()?;
// NOTE: We deliberately do not sync the workspace before listing outdated
// rocks. `Sync` may install or remove packages as a side effect, which would
// make this otherwise read-only command mutate the install tree.
let tree = match &workspace {
Some(project) => {
// Make sure dependencies are synced if in a project
sync_dependencies_if_locked(project, &config).await?;
project.tree(&config)?
}
Some(project) => project.tree(&config)?,
Comment thread
vhyrro marked this conversation as resolved.
None => {
let lua_version = LuaVersion::from(&config)?.clone();
config.user_tree(lua_version)?
}
};

let package_db = RemotePackageDB::from_config(&config).await?;
let package_db = PackageDB::from_config(&config).await?;

// NOTE: This will display all installed versions and each possible upgrade.
// However, this should also take into account dependency constraints made by other rocks.
Expand All @@ -43,19 +42,22 @@ pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> {
let rock_list = tree.as_rock_list()?;
let rock_list = rock_list
.iter()
.map(|rock| {
.filter_map(|rock| {
rock.to_package()
.has_update(&package_db)
.map(|mb_version| mb_version.map(|version| (rock, version)))
.ok()
.flatten()
.map(|version| (rock, version))
})
.filter_map_ok(|mb_tuple| mb_tuple)
.try_collect::<_, Vec<(&LocalPackage, PackageVersion)>, _>()?;
.collect::<Vec<(&LockedPackage, PackageVersion)>>();

let rock_list = rock_list
.iter()
.sorted_by_key(|(rock, _)| rock.name().to_owned())
.into_group_map_by(|(rock, _)| rock.name().to_owned());

let has_outdated = !rock_list.is_empty();

match outdated_data.output_format {
OutputFormat::Json => {
let jsonified_rock_list = rock_list
Expand Down Expand Up @@ -94,5 +96,9 @@ pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> {
}
}

if has_outdated {
println!("\nRun `lx update` to update all outdated rocks.");
}

Ok(())
}
15 changes: 10 additions & 5 deletions lux-cli/src/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ use crate::{args::PackageOrRockspec, build, workspace::exists_matching_workspace
use clap::Args;
use itertools::Itertools;
use lux_lib::{
build::{Build, BuildBehaviour},
build::BuildBehaviour,
config::Config,
drivers::install_packages::InstallPackages,
lua_installation::LuaInstallation,
lua_rockspec::RemoteLuaRockspec,
lua_version::LuaVersion,
operations::{self, Install, PackageInstallSpec},
operations::{self, PackageInstallSpec},
package::PackageName,
package_db::PackageDB,
pipeline::build_local::Build,
rockspec::Rockspec as _,
tree::{self, InstallTree},
workspace::Workspace,
Expand Down Expand Up @@ -107,15 +110,16 @@ pub async fn pack(args: Pack, config: Config) -> Result<()> {
let temp_dir = tempdir().into_diagnostic()?;
let temp_config = config.with_tree(temp_dir.path().to_path_buf());
let tree = temp_config.user_tree(lua_version.clone())?;
let packages = Install::new(&temp_config)
let packages = InstallPackages::new(&temp_config, &tree)
.package(
PackageInstallSpec::new(package_req, tree::EntryType::Entrypoint)
.build_behaviour(BuildBehaviour::Force)
.build(),
)
.tree(tree.clone())
.package_db(PackageDB::from_config(&temp_config).await?)
.install()
.await?;
.await?
.0;
let package = packages
.first()
.ok_or_else(|| miette!("no packages installed"))?;
Expand Down Expand Up @@ -174,6 +178,7 @@ pub async fn pack(args: Pack, config: Config) -> Result<()> {
.tree(&tree)
.entry_type(tree::EntryType::Entrypoint)
.config(&config)
.behaviour(BuildBehaviour::Force)
.build()
.await?;
let rock_path = operations::Pack::new(dest_dir, tree, package)
Expand Down
6 changes: 4 additions & 2 deletions lux-cli/src/pin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use clap::Args;
use itertools::Itertools;
use lux_lib::config::Config;
use lux_lib::drivers::sync::{Sync, SyncMode, TargetSet};
use lux_lib::lockfile::PinnedState;
use lux_lib::lua_version::LuaVersion;
use lux_lib::operations;
Expand Down Expand Up @@ -82,8 +83,9 @@ pub async fn set_pinned_state(data: ChangePin, config: Config, pin: PinnedState)
)
.await?;
}
operations::Sync::new(&workspace, &config)
.test(!test_packages.is_empty())
Sync::new(&workspace, &config)
.mode(SyncMode::Frozen)
.targets(TargetSet::all(&workspace, !test_packages.is_empty()))
.sync()
.await
.wrap_err("syncing dependencies with the workspace lockfile failed.")?;
Expand Down
4 changes: 2 additions & 2 deletions lux-cli/src/run.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;

use clap::Args;
use lux_lib::{config::Config, operations, workspace::Workspace};
use lux_lib::{build::BuildBehaviour, config::Config, operations, workspace::Workspace};
use miette::Result;

use crate::build::{self, Build};
Expand Down Expand Up @@ -31,7 +31,7 @@ pub async fn run(run_args: Run, config: Config) -> Result<()> {
let workspace = Workspace::current_or_err()?;

let package = run_args.build.package.clone();
build::build(run_args.build, config.clone()).await?;
build::build_with_behaviour(run_args.build, config.clone(), BuildBehaviour::Ignore).await?;

operations::Run::new()
.workspace(&workspace)
Expand Down
Loading
Loading