Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 19 additions & 2 deletions Cargo.lock

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

5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ Where:

Simplex CLI provides the following commands:

- `simplex init` - Initializes a Simplex project.
- `simplex init` - Initializes a new Simplex project.
- `simplex config` - Prints the current config.
- `simplex build` - Generates simplicity artifacts.
- `simplex regtest` - Spins up local Electrs + Elements nodes.
- `simplex test` - Runs Simplex tests.
- `simplex clean` - Cleans up generated artifacts.

To view the available options, run the help command:

Expand All @@ -119,7 +120,7 @@ We are open to any mind-blowing ideas! Please take a look at our [contributing g

## Future work

- [ ] Complete `simplex init` and `simplex clean` tasks.
- [x] Complete `simplex init` and `simplex clean` tasks.
- [ ] SDK support for confidential assets, taproot signer, and custom witness signatures.
- [ ] Local regtest 10x speedup.
- [ ] Regtest cheat codes.
Expand Down
9 changes: 5 additions & 4 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ workspace = true
[dependencies]
smplx-regtest = { workspace = true }
smplx-test = { workspace = true }
smplx-build = { workspace = true}
smplx-build = { workspace = true }
smplx-sdk = { workspace = true }

simplicityhl = { workspace = true }
electrsd = { workspace = true }
thiserror = { workspace = true }
serde = { workspace = true }
toml = { workspace = true }
minreq = { workspace = true }

anyhow = "1"
dotenvy = "0.15"
clap = { version = "4", features = ["derive", "env"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
ctrlc = { version = "3.5.2", features = ["termination"] }
toml_edit = { version = "0.23.9" }
ctrlc = { version = "3.5.2", features = ["termination"] }
serde_json = { version = "1.0.149" }
19 changes: 12 additions & 7 deletions crates/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use clap::Parser;

use crate::commands::Command;
use crate::commands::build::Build;
use crate::commands::clean::Clean;
use crate::commands::init::Init;
use crate::commands::regtest::Regtest;
use crate::commands::test::Test;
use crate::config::{Config, INIT_CONFIG};
use crate::config::Config;
use crate::error::CliError;

#[derive(Debug, Parser)]
Expand All @@ -22,13 +24,10 @@ pub struct Cli {
impl Cli {
pub async fn run(&self) -> Result<(), CliError> {
match &self.command {
Command::Init => {
let config_path = Config::get_default_path()?;
std::fs::write(&config_path, INIT_CONFIG)?;

println!("Config written to: '{}'", config_path.display());
Command::Init { additional_flags } => {
let simplex_conf_path = Config::get_default_path()?;

Ok(())
Ok(Init::run(*additional_flags, simplex_conf_path)?)
}
Command::Config => {
let config_path = Config::get_default_path()?;
Expand Down Expand Up @@ -56,6 +55,12 @@ impl Cli {

Ok(Build::run(loaded_config.build)?)
}
Command::Clean { additional_flags } => {
let config_path = Config::get_default_path()?;
let loaded_config = Config::load(&config_path)?;

Ok(Clean::run(loaded_config.build, *additional_flags, config_path)?)
}
}
}
}
97 changes: 97 additions & 0 deletions crates/cli/src/commands/clean.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use std::{
fmt::Display,
fs,
path::{Path, PathBuf},
};

use smplx_build::{ArtifactsResolver, BuildConfig};

use crate::commands::error::CommandError;
use crate::commands::{CleanFlags, error::CleanError};

pub struct Clean;

pub struct DeletedItems(Vec<PathBuf>);

impl Clean {
pub fn run(
config: BuildConfig,
additional_flags: CleanFlags,
config_path: impl AsRef<Path>,
) -> Result<(), CommandError> {
let deleted_files = Self::delete_files(config, additional_flags, config_path)?;

println!("Deleted files: {deleted_files}");

Ok(())
}

fn delete_files(
config: BuildConfig,
additional_flags: CleanFlags,
smplx_toml_path: impl AsRef<Path>,
) -> Result<DeletedItems, CleanError> {
let mut deleted_items = Vec::with_capacity(2);
let generated_artifacts = Self::remove_artifacts(config)?;

if let Some(artifacts_dir) = generated_artifacts {
deleted_items.push(artifacts_dir);
}

if additional_flags.all {
let simplex_toml_path = Self::remove_config(smplx_toml_path)?;

if let Some(simplex_toml) = simplex_toml_path {
deleted_items.push(simplex_toml);
}
}

Ok(DeletedItems(deleted_items))
}

fn remove_artifacts(config: BuildConfig) -> Result<Option<PathBuf>, CleanError> {
let output_dir = ArtifactsResolver::resolve_local_dir(&config.out_dir)
.map_err(|e| CleanError::ResolveOutDir(e.to_string()))?;

let res = if output_dir.exists() {
fs::remove_dir_all(&output_dir).map_err(|e| CleanError::RemoveOutDir(e, output_dir.to_path_buf()))?;
Some(output_dir)
} else {
None
};

Ok(res)
}

fn remove_config(config_path: impl AsRef<Path>) -> Result<Option<PathBuf>, CleanError> {
let config_path = config_path.as_ref().to_path_buf();

if config_path.exists() && config_path.is_file() {
fs::remove_file(&config_path).map_err(|e| CleanError::RemoveFile(e, config_path.to_path_buf()))?;

Ok(Some(config_path))
} else {
Ok(None)
}
}
}

impl Display for DeletedItems {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let paths_len = self.0.len();
let mut result = String::from("[");

for (index, path) in self.0.iter().enumerate() {
result.push_str(&format!("\n\t{}", path.display()));

if index < paths_len - 1 {
result.push(',');
}
result.push('\n');
}

result.push(']');

write!(f, "{}", result)
}
}
30 changes: 26 additions & 4 deletions crates/cli/src/commands/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@ use clap::{Args, Subcommand};

#[derive(Debug, Subcommand)]
pub enum Command {
/// Initializes the Simplex project (TODO)
Init,
/// Prints the current Simplex config in use
/// Initializes Simplex project
Init {
#[command(flatten)]
additional_flags: InitFlags,
},
/// Prints current Simplex config in use
Config,
/// Spins up the local Electrs + Elements regtest
Regtest,
/// Runs the Simplex tests
/// Runs Simplex tests
Test {
#[command(subcommand)]
command: TestCommand,
},
/// Generates the simplicity contracts artifacts
Build,
/// Clean Simplex artifacts in the current directory
Clean {
#[command(flatten)]
additional_flags: CleanFlags,
},
}

#[derive(Debug, Subcommand)]
Expand Down Expand Up @@ -46,3 +54,17 @@ pub struct TestFlags {
#[arg(long)]
pub ignored: bool,
}

#[derive(Debug, Args, Copy, Clone)]
pub struct InitFlags {
/// Generate a draft Rust library instead of just `Simplex.toml`
#[arg(long)]
pub lib: bool,
}

#[derive(Debug, Args, Copy, Clone)]
pub struct CleanFlags {
/// Remove `Simplex.toml` as well
#[arg(long)]
pub all: bool,
}
47 changes: 47 additions & 0 deletions crates/cli/src/commands/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::path::PathBuf;

#[derive(thiserror::Error, Debug)]
pub enum CommandError {
#[error(transparent)]
Expand All @@ -12,6 +14,51 @@ pub enum CommandError {
#[error(transparent)]
Build(#[from] smplx_build::error::BuildError),

#[error(transparent)]
Init(#[from] InitError),

#[error(transparent)]
Clean(#[from] CleanError),

#[error("IO error: {0}")]
Io(#[from] std::io::Error),
}

#[derive(thiserror::Error, Debug)]
pub enum InitError {
#[error("Failed to open file '{1}': {0}")]
OpenFile(std::io::Error, PathBuf),

#[error("Failed to write to file '{1}': {0}")]
WriteToFile(std::io::Error, PathBuf),

#[error("Failed to format file with rustfmt: {0}")]
FmtError(std::io::Error),

#[error("Failed to resolve parent directory for: {0}")]
ResolveParent(PathBuf),

#[error("Failed to create directories at '{1}': {0}")]
CreateDirs(std::io::Error, PathBuf),

#[error("Failed to fetch crate info from crates.io: {0}")]
CratesIoFetch(String),

#[error("Cannot auto-detect package name from path: {0}")]
PackageName(PathBuf),

#[error("Cannot create package with a non-unicode name: '{0}'")]
NonUnicodeName(String),
}

#[derive(thiserror::Error, Debug)]
pub enum CleanError {
#[error("Failed to resolve out_dir from config, err: '{0}'")]
ResolveOutDir(String),

#[error("Failed to remove output directory '{1}': {0}")]
RemoveOutDir(std::io::Error, PathBuf),

#[error("Failed to remove file '{1}': {0}")]
RemoveFile(std::io::Error, PathBuf),
}
Loading