Skip to content

Commit

Permalink
feat: rocks sync command
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcjkb committed Feb 4, 2025
1 parent 3c9e9e1 commit cdff4c7
Show file tree
Hide file tree
Showing 24 changed files with 1,293 additions and 380 deletions.
92 changes: 92 additions & 0 deletions
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use eyre::{Context, OptionExt};
use itertools::Itertools;
use std::sync::Arc;

use clap::Args;
use eyre::Result;
use rocks_lib::{
build::{self, BuildBehaviour},
config::Config,
lockfile::PinnedState,
operations::{Install, Sync},
package::PackageName,
progress::MultiProgress,
project::Project,
rockspec::Rockspec,
};

#[derive(Args, Default)]
pub struct Build {
/// Whether to pin the dependencies.
#[arg(long)]
pin: bool,

/// Ignore the project's existing lockfile.
#[arg(long)]
ignore_lockfile: bool,
}

pub async fn build(data: Build, config: Config) -> Result<()> {
let project = Project::current()?.ok_or_eyre("Not in a project!")?;
let pin = PinnedState::from(data.pin);
let progress_arc = MultiProgress::new_arc();
let progress = Arc::clone(&progress_arc);

let tree = project.tree(&config)?;
let rocks = project.new_local_rockspec()?;

let lockfile = match project.try_lockfile()? {
None => None,
Some(_) if data.ignore_lockfile => None,
Some(lockfile) => Some(lockfile),
};

let dependencies = rocks
.dependencies()
.current_platform()
.iter()
.filter(|package| !package.name().eq(&PackageName::new("lua".into())))
.cloned()
.collect_vec();

match lockfile {
Some(mut project_lockfile) => {
Sync::new(&tree, &mut project_lockfile, &config)
.progress(progress.clone())
.packages(dependencies)
.sync()
.await
.wrap_err(
"
syncing with the project lockfile failed.
Use --ignore-lockfile to force a new build.
",
)?;
}
None => {
let dependencies_to_install = dependencies
.into_iter()
.filter(|req| {
tree.match_rocks(req)
.is_ok_and(|rock_match| !rock_match.is_found())
})
.map(|dep| (BuildBehaviour::NoForce, dep));

Install::new(&tree, &config)
.packages(dependencies_to_install)
.project(&project)
.pin(pin)
.progress(progress.clone())
.install()
.await?;
}
}

build::Build::new(&rocks, &tree, &config, &progress.map(|p| p.new_bar()))
.pin(pin)
.behaviour(BuildBehaviour::Force)
.build()
.await?;

Ok(())
}
71 changes: 38 additions & 33 deletions rocks-bin/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ use rocks_lib::{
build::{self, BuildBehaviour},
config::Config,
lockfile::PinnedState,
operations::Install,
operations::{Install, Sync},
package::PackageName,
progress::MultiProgress,
project::Project,
remote_package_db::RemotePackageDB,
rockspec::Rockspec,
};

Expand All @@ -25,10 +24,6 @@ pub struct Build {
/// Ignore the project's existing lockfile.
#[arg(long)]
ignore_lockfile: bool,

/// Do not create a lockfile.
#[arg(long)]
no_lock: bool,
}

pub async fn build(data: Build, config: Config) -> Result<()> {
Expand All @@ -37,44 +32,54 @@ pub async fn build(data: Build, config: Config) -> Result<()> {
let progress_arc = MultiProgress::new_arc();
let progress = Arc::clone(&progress_arc);

let bar = progress.map(|p| p.new_bar());
let package_db = match project.try_lockfile()? {
None => RemotePackageDB::from_config(&config, &bar).await?,
Some(_) if data.ignore_lockfile => RemotePackageDB::from_config(&config, &bar).await?,
Some(lockfile) => lockfile.into(),
};

bar.map(|b| b.finish_and_clear());
let tree = project.tree(&config)?;
let rocks = project.new_local_rockspec()?;

// Ensure all dependencies are installed first
let lockfile = match project.try_lockfile()? {
None => None,
Some(_) if data.ignore_lockfile => None,
Some(lockfile) => Some(lockfile),
};

let dependencies = rocks
.dependencies()
.current_platform()
.iter()
.filter(|package| !package.name().eq(&PackageName::new("lua".into())))
.cloned()
.collect_vec();

let dependencies_to_install = dependencies
.into_iter()
.filter(|req| {
tree.match_rocks(req)
.is_ok_and(|rock_match| !rock_match.is_found())
})
.map(|dep| (BuildBehaviour::NoForce, dep.to_owned()));

Install::new(&tree, &config)
.packages(dependencies_to_install)
.pin(pin)
.package_db(package_db)
.progress(progress_arc)
.install()
.await?;
match lockfile {
Some(mut project_lockfile) => {
Sync::new(&tree, &mut project_lockfile, &config)
.progress(progress.clone())
.packages(dependencies)
.sync()
.await
.wrap_err(
"
syncing with the project lockfile failed.
Use --ignore-lockfile to force a new build.
",
)?;
}
None => {
let dependencies_to_install = dependencies
.into_iter()
.filter(|req| {
tree.match_rocks(req)
.is_ok_and(|rock_match| !rock_match.is_found())
})
.map(|dep| (BuildBehaviour::NoForce, dep));

if !data.no_lock {
std::fs::copy(tree.lockfile_path(), project.lockfile_path())
.wrap_err("error copying the project lockfile")?;
Install::new(&tree, &config)
.packages(dependencies_to_install)
.project(&project)
.pin(pin)
.progress(progress.clone())
.install()
.await?;
}
}

build::Build::new(&rocks, &tree, &config, &progress.map(|p| p.new_bar()))
Expand Down
4 changes: 4 additions & 0 deletions rocks-bin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use rocks_lib::config::LuaVersion;
use run::Run;
use run_lua::RunLua;
use search::Search;
use sync::Sync;
use test::Test;
use uninstall::Uninstall;
use update::Update;
Expand Down Expand Up @@ -52,6 +53,7 @@ pub mod remove;
pub mod run;
pub mod run_lua;
pub mod search;
pub mod sync;
pub mod test;
pub mod uninstall;
pub mod unpack;
Expand Down Expand Up @@ -179,6 +181,8 @@ pub enum Commands {
/// Query the Luarocks servers.
#[command(arg_required_else_help = true)]
Search(Search),
/// Synchronise a tree with a lockfile.
Sync(Sync),
/// Run the test suite in the current directory.
Test(Test),
/// Uninstall a rock from the system.
Expand Down
4 changes: 3 additions & 1 deletion rocks-bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use rocks::{
add, build, check, config,
debug::Debug,
doc, download, fetch, format, info, install, install_lua, install_rockspec, list, outdated,
pack, path, pin, project, purge, remove, run, run_lua, search, test, uninstall, unpack, update,
pack, path, pin, project, purge, remove, run, run_lua, search, sync, test, uninstall, unpack,
update,
upload::{self},
which, Cli, Commands,
};
Expand Down Expand Up @@ -39,6 +40,7 @@ async fn main() {

match cli.command {
Commands::Search(search_data) => search::search(search_data, config).await.unwrap(),
Commands::Sync(sync_args) => sync::sync(sync_args, config).await.unwrap(),
Commands::Download(download_data) => {
download::download(download_data, config).await.unwrap()
}
Expand Down
70 changes: 70 additions & 0 deletions rocks-bin/src/sync.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::path::PathBuf;

use clap::Args;
use eyre::{eyre, Context, Result};
use rocks_lib::{
config::{Config, LuaVersion},
lockfile::Lockfile,
operations,
package::PackageReq,
project::{rocks_toml::RocksToml, ROCKS_TOML},
rockspec::Rockspec,
};

#[derive(Args)]
pub struct Sync {
/// The path to the lockfile to synchronise from.
lockfile: PathBuf,

/// Path to a rocks.toml.
/// If set, 'rocks sync' will also synchronise the dependencies in the rocks.toml
/// with the lockfile.
/// This is useful if dependencies have been added or removed manually
/// and the lockfile is out of sync.
///
/// If not set, rocks will check the lockfile's parent directory for a
/// rocks.toml file and use that.
manifest_path: Option<PathBuf>,

/// Skip the integrity checks for installed rocks.
#[arg(long)]
no_integrity_ckeck: bool,
}

pub async fn sync(args: Sync, config: Config) -> Result<()> {
let tree = config.tree(LuaVersion::from(&config)?)?;

let mut lockfile = Lockfile::new(args.lockfile.clone())?;

let mut sync = operations::Sync::new(&tree, &mut lockfile, &config)
.validate_integrity(!args.no_integrity_ckeck);

let manifest_path = match args.manifest_path {
Some(path) => {
if !path.is_file() {
return Err(eyre!("File not found: {}", path.display()));
}
Some(path)
}
None => args.lockfile.parent().map(|parent| parent.join(ROCKS_TOML)),
};

if let Some(dependencies) = manifest_path
.map(|manifest_path| -> Result<Vec<PackageReq>> {
let content = std::fs::read_to_string(&manifest_path)?;
let rocks = RocksToml::new(&content)?;
Ok(rocks
.into_validated_rocks_toml()?
.dependencies()
.current_platform()
.clone())
})
.transpose()?
{
sync.add_packages(dependencies);
}

sync.sync().await.wrap_err("sync failed.")?;

Ok(())
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit cdff4c7

Please sign in to comment.