Skip to content

Commit

Permalink
Merge pull request #13 from ink0rr/dev
Browse files Browse the repository at this point in the history
rgl v0.4.0
  • Loading branch information
ink0rr authored Nov 23, 2023
2 parents a8c9e8c + 1f1a321 commit 4147f92
Show file tree
Hide file tree
Showing 19 changed files with 330 additions and 209 deletions.
15 changes: 14 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rgl"
version = "0.3.0"
version = "0.4.0"
edition = "2021"

[[bin]]
Expand All @@ -11,6 +11,7 @@ anyhow = "1.0.75"
clap = { version = "4.4.8", features = ["cargo"] }
dialoguer = "0.11.0"
dunce = "1.0.4"
enum_dispatch = "0.3.12"
indexmap = { version = "2.1.0", features = ["serde"] }
md5 = "0.7.0"
notify = "6.1.1"
Expand Down
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
# rgl

Not Regolith.
Fast and minimal implementation of Regolith.

## Benchmark

Benchmark result on a project with ~2300 files, no filters, and a total size of 9.2MB

```
$ hyperfine --warmup 2 --runs 10 --setup 'rgl clean' 'regolith run build' 'rgl run build' 'rgl run build --cached'
Benchmark 1: regolith run build
Time (mean ± σ): 511.7 ms ± 24.0 ms [User: 43.8 ms, System: 465.5 ms]
Range (min … max): 485.0 ms … 560.6 ms 10 runs
Benchmark 2: rgl run build
Time (mean ± σ): 186.9 ms ± 34.3 ms [User: 24.0 ms, System: 789.0 ms]
Range (min … max): 134.9 ms … 257.4 ms 10 runs
Benchmark 3: rgl run build --cached
Time (mean ± σ): 46.2 ms ± 1.1 ms [User: 26.2 ms, System: 245.2 ms]
Range (min … max): 43.5 ms … 47.6 ms 10 runs
Summary
rgl run build --cached ran
4.05 ± 0.75 times faster than rgl run build
11.08 ± 0.59 times faster than regolith run build
```

> Testen on a MacBook Pro M1 (2020)
### Install

Expand Down
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main() {
fn cli() -> Command {
Command::new("rgl")
.bin_name("rgl")
.about("Not Regolith")
.about("Fast and minimal implementation of Regolith.")
.author("ink0rr")
.version(crate_version!())
.arg(
Expand All @@ -31,6 +31,7 @@ fn cli() -> Command {
)
.arg_required_else_help(true)
.subcommand_required(true)
.subcommand(Command::new("clean").about("Cleans Regolith cache and build files"))
.subcommand(
Command::new("init")
.about("Initializes a new Regolith project in the current directory")
Expand Down Expand Up @@ -95,6 +96,9 @@ fn run_command(matches: ArgMatches) -> Result<()> {
_ => None,
};
match matches.subcommand() {
Some(("clean", _)) => {
rgl::clean().context("Error cleaning files")?;
}
Some(("init", matches)) => {
let force = matches.get_flag("force");
rgl::init(force).context("Error initializing project")?;
Expand Down
14 changes: 14 additions & 0 deletions src/rgl/clean.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use super::{rimraf, Config};
use crate::info;
use anyhow::{Context, Result};

pub fn clean() -> Result<()> {
// Make sure it's a regolith project
let _ = Config::load().context("Not a Regolith project")?;
info!("Cleaning .regolith folder...");
rimraf(".regolith")?;
info!("Cleaning build files...");
rimraf("build")?;
info!("Completed!");
Ok(())
}
7 changes: 4 additions & 3 deletions src/rgl/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::{read_json, write_json, Export, FilterDefinition, FilterRunner, Profile};
use super::{read_json, write_json, Export, FilterRunner, Profile};
use anyhow::Result;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;

#[derive(Serialize, Deserialize)]
Expand All @@ -25,7 +26,7 @@ pub struct Packs {
#[serde(rename_all = "camelCase")]
pub struct Regolith {
pub data_path: String,
pub filter_definitions: BTreeMap<String, FilterDefinition>,
pub filter_definitions: BTreeMap<String, Value>,
pub profiles: IndexMap<String, Profile>,
}

Expand Down Expand Up @@ -62,7 +63,7 @@ impl Config {
},
regolith: Regolith {
data_path: "./data".to_owned(),
filter_definitions: BTreeMap::<String, FilterDefinition>::new(),
filter_definitions: BTreeMap::<String, Value>::new(),
profiles,
},
}
Expand Down
25 changes: 18 additions & 7 deletions src/rgl/context.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{Config, FileWatcher, FilterDefinition, Profile};
use anyhow::{Context, Result};
use anyhow::{anyhow, Context, Result};
use indexmap::IndexMap;
use std::collections::BTreeMap;

Expand All @@ -14,16 +14,27 @@ pub struct RunContext {
}

impl RunContext {
pub fn new(config: Config, profile: &str) -> Self {
Self {
pub fn new(config: Config, profile: &str) -> Result<Self> {
let mut filter_definitions = BTreeMap::<String, FilterDefinition>::new();
for (name, value) in config.regolith.filter_definitions {
let filter = FilterDefinition::from_value(value).map_err(|e| {
anyhow!(
"Invalid filter definition for <b>{name}</>\n\
<yellow> >></> {e}"
)
})?;
filter_definitions.insert(name, filter);
}
let context = Self {
name: config.name,
behavior_pack: config.packs.behavior_pack,
resource_pack: config.packs.resource_pack,
data_path: config.regolith.data_path,
filter_definitions: config.regolith.filter_definitions,
filter_definitions,
profiles: config.regolith.profiles,
root_profile: profile.to_string(),
}
};
Ok(context)
}

pub fn get_profile(&self, profile_name: &str) -> Result<&Profile> {
Expand All @@ -32,9 +43,9 @@ impl RunContext {
.context(format!("Profile <b>{profile_name}</> not found"))
}

pub fn get_filter_def(&self, filter_name: &str) -> Result<&FilterDefinition> {
pub fn get_filter(&self, filter_name: &str) -> Result<&FilterDefinition> {
self.filter_definitions.get(filter_name).context(format!(
"Filter <b>{filter_name}</> not defined in filter_definitions"
"Filter <b>{filter_name}</> is not defined in filter_definitions"
))
}

Expand Down
2 changes: 1 addition & 1 deletion src/rgl/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub fn run_or_watch(profile_name: &str, watch: bool, cached: bool) -> Result<()>
let start_time = time::Instant::now();
let config = Config::load()?;

let context = RunContext::new(config, profile_name);
let context = RunContext::new(config, profile_name)?;
let profile = context.get_profile(profile_name)?;
let temp = profile.get_temp_dir()?;
let temp_bp = temp.join("BP");
Expand Down
140 changes: 68 additions & 72 deletions src/rgl/filter.rs
Original file line number Diff line number Diff line change
@@ -1,93 +1,89 @@
use super::{FilterDeno, FilterGo, FilterNode, FilterPython, FilterRemote};
use anyhow::{bail, Context, Result};
use super::{FilterDeno, FilterExe, FilterGo, FilterNode, FilterPython, RemoteFilter};
use anyhow::{anyhow, Result};
use dunce::canonicalize;
use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};

pub trait Filter {
fn run(&self, temp: &Path, run_args: &[String]) -> Result<()>;
fn install_dependencies(&self) -> Result<()> {
Ok(())
}
}
use serde_json::Value;
use std::{
env,
path::{Path, PathBuf},
};

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
#[enum_dispatch]
pub enum FilterDefinition {
Local(LocalFilterDefinition),
Remote(RemoteFilterDefinition),
Local(LocalFilter),
Remote(RemoteFilter),
}

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalFilterDefinition {
pub run_with: String,
pub script: String,
impl FilterDefinition {
pub fn from_value(value: Value) -> Result<Self> {
let filter = match value["runWith"] {
Value::String(_) => {
let filter = serde_json::from_value::<LocalFilter>(value)?;
FilterDefinition::Local(filter)
}
_ => {
let filter = serde_json::from_value::<RemoteFilter>(value)?;
FilterDefinition::Remote(filter)
}
};
Ok(filter)
}

pub fn is_remote(&self) -> bool {
matches!(self, FilterDefinition::Remote(_))
}
}

#[derive(Serialize, Deserialize)]
pub struct RemoteFilterDefinition {
pub url: String,
pub version: String,
#[serde(rename_all = "camelCase", tag = "runWith")]
#[enum_dispatch]
pub enum LocalFilter {
Deno(FilterDeno),
Exe(FilterExe),
Go(FilterGo),
Nodejs(FilterNode),
Python(FilterPython),
}

pub struct FilterArgs {
pub struct FilterContext {
pub name: String,
pub script: PathBuf,
pub filter_dir: PathBuf,
pub dir: PathBuf,
pub is_remote: bool,
}

impl FilterDefinition {
pub fn to_filter(&self, name: &str, filter_dir: Option<PathBuf>) -> Result<Box<dyn Filter>> {
let inner = || {
let filter: Box<dyn Filter> = match self {
FilterDefinition::Local(def) => {
let args = FilterArgs::new(name, filter_dir, def)?;
match def.run_with.as_str() {
"deno" => Box::new(FilterDeno(args)),
"go" => Box::new(FilterGo(args)),
"nodejs" => Box::new(FilterNode(args)),
"python" => Box::new(FilterPython(args)),
filter_type => bail!("Filter type <b>{filter_type}</> not supported"),
}
}
FilterDefinition::Remote(def) => {
let filter_remote = FilterRemote::new(name)?;
let is_latest = matches!(def.version.as_str(), "HEAD" | "latest");
if !is_latest && def.version != filter_remote.version {
bail!(
"Filter version mismatch\n\
<yellow> >></> Filter: {}\n\
<yellow> >></> Installed version: {}\n\
<yellow> >></> Required version: {}",
name,
filter_remote.version,
def.version
);
}
Box::new(filter_remote)
}
};
Ok(filter)
};
inner().context(format!("Invalid filter definition for <b>{name}</>"))
}
}

impl FilterArgs {
fn new(name: &str, filter_dir: Option<PathBuf>, def: &LocalFilterDefinition) -> Result<Self> {
let script =
canonicalize(&def.script).context(format!("Failed to resolve path {}", def.script))?;
let filter_dir = filter_dir.unwrap_or_else(|| {
script
.parent()
.map(|path| path.to_path_buf())
.unwrap_or_else(|| PathBuf::from("."))
});
impl FilterContext {
pub fn new(name: &str, is_remote: bool) -> Result<Self> {
Ok(Self {
name: name.to_owned(),
script,
filter_dir,
dir: match is_remote {
true => canonicalize(RemoteFilter::cache_dir(name)).map_err(|_| {
anyhow!("Filter <b>{name}</> not installed, run \"rgl install\" to install it")
})?,
false => env::current_dir()?,
},
is_remote,
})
}

pub fn filter_dir(&self, path: &str) -> Result<PathBuf> {
if self.is_remote {
Ok(self.dir.to_owned())
} else {
let mut dir = PathBuf::from(path);
dir.pop();
Ok(dir)
}
}
}

#[enum_dispatch(FilterDefinition, LocalFilter)]
pub trait Filter {
fn run(&self, context: &FilterContext, temp: &Path, run_args: &[String]) -> Result<()>;
#[allow(unused_variables)]
fn install_dependencies(&self, context: &FilterContext) -> Result<()> {
Ok(())
}
}
Loading

0 comments on commit 4147f92

Please sign in to comment.