Skip to content
Open
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
14 changes: 12 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,23 @@ jobs:
cargo build --target $TARGET --profile $RUST_PROFILE --bins
mv $OUT_DIR/${{ env.RUST_PROFILE }}/simplex simplex

- name: Download nextest, elementsd and electrs
- name: Download nextest, simfmt, elementsd and electrs
env:
SIMFMT_VERSION: ${{ vars.SIFMMT_VERSION }}
SIMFMT_TARGET: ${{ matrix.target }}
NEXTEST_VERSION: "0.9.137"
ELEMENTSD_VERSION: "23.3.1"
ELEMENTSD_TARGET: ${{ matrix.elementsd_target }}
ELECTRS_TARGET: ${{ matrix.electrs_target }}
NEXTEST_TARGET: ${{ matrix.nextest_target }}
run: |
#!/usr/bin/env bash
set -eo pipefail

ELEMENTSD_FILENAME="elements-${ELEMENTSD_VERSION}-${ELEMENTSD_TARGET}.tar.gz"
ELECTRS_FILENAME="electrs_${ELECTRS_TARGET}_esplora_027e38d3ebc2f85b28ae76f8f3448438ee4fc7b1_liquid.zip"
NEXTEST_FILENAME="cargo-nextest-${NEXTEST_VERSION}-${NEXTEST_TARGET}.tar.gz"
SIMFMT_FILENAME="simfmt-v${SIMFMT_VERSION}-${SIMFMT_TARGET}.tar.gz"

curl -Ls "https://github.com/ElementsProject/elements/releases/download/elements-${ELEMENTSD_VERSION}/${ELEMENTSD_FILENAME}" -o ${ELEMENTSD_FILENAME}
tar -xzf ${ELEMENTSD_FILENAME} && rm ${ELEMENTSD_FILENAME}
Expand All @@ -90,6 +96,9 @@ jobs:
curl -Ls "https://github.com/nextest-rs/nextest/releases/download/cargo-nextest-${NEXTEST_VERSION}/${NEXTEST_FILENAME}" -o ${NEXTEST_FILENAME}
tar -xzf ${NEXTEST_FILENAME} && rm ${NEXTEST_FILENAME}
mv cargo-nextest smplx-nextest

curl -fLsS "https://github.com/BlockstreamResearch/simfmt/releases/download/v${SIMFMT_VERSION}/${SIMFMT_FILENAME}" -o "${SIMFMT_FILENAME}"
tar -xzf "${SIMFMT_FILENAME}" && rm "${SIMFMT_FILENAME}"

- name: Sign elementsd binary
run: |
Expand All @@ -106,6 +115,7 @@ jobs:
elementsd
electrs
smplx-nextest
simfmt

- name: Record attestation URL
env:
Expand All @@ -116,7 +126,7 @@ jobs:
- name: Archive binaries
env:
ARCHIVE: simplex-${{ github.event.inputs.tag || github.ref_name }}-${{ matrix.archive }}
run: tar czf ${ARCHIVE} simplex elementsd electrs smplx-nextest
run: tar czf ${ARCHIVE} simplex elementsd electrs smplx-nextest simfmt

- name: Upload build artifacts
uses: actions/upload-artifact@v6
Expand Down
3 changes: 3 additions & 0 deletions crates/build/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ pub enum BuildError {
#[error("Glob error: {0}")]
Glob(#[from] GlobError),

#[error("Failed to resolve globpaths, directory walk error: {0}")]
Walk(#[from] globwalk::WalkError),

#[error("Failed to deserialize config: '{0}'")]
ConfigDeserialize(#[from] toml::de::Error),

Expand Down
49 changes: 37 additions & 12 deletions crates/build/src/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::hash::{DefaultHasher, Hash as _, Hasher as _};
use std::path::{Path, PathBuf};
use std::{env, fs};
Expand All @@ -18,21 +19,16 @@ use super::error::BuildError;
pub struct ArtifactsResolver {}

impl ArtifactsResolver {
pub fn resolve_files_to_build(src_dir: &String, simfs: &[String]) -> Result<Vec<PathBuf>, BuildError> {
pub fn resolve_files_to_build(
src_dir: impl AsRef<str>,
simfs: &[impl AsRef<str>],
) -> Result<Vec<PathBuf>, BuildError> {
let cwd = env::current_dir()?;
let base = cwd.join(src_dir);

let files = Self::resolve_simf_files(&cwd, src_dir, simfs)?;
let mut paths = Vec::new();

let walker = globwalk::GlobWalkerBuilder::from_patterns(base, simfs)
.follow_links(true)
.file_type(FileType::FILE)
.build()?
.filter_map(Result::ok);

for img in walker {
let path = img.path().to_path_buf().canonicalize()?;
let content = std::fs::read_to_string(&path)?;
for path in files {
let content = fs::read_to_string(&path)?;

if Self::contains_main(&content) {
paths.push(path);
Expand All @@ -42,6 +38,35 @@ impl ArtifactsResolver {
Ok(paths)
}

/// Resolves every source file matched by `simfs` beneath `src_dir` relative
/// to `project_root`.
///
/// Returned paths are canonicalized, sorted, and deduplicated. Unlike
/// [`Self::resolve_files_to_build`], this does not require a source file to
/// contain a `main` function.
///
/// # Errors
/// Returns a [`BuildError`] if a glob cannot be constructed, the directory
/// walk fails, or a matching path cannot be canonicalized.
pub fn resolve_simf_files(
project_root: impl AsRef<Path>,
src_dir: impl AsRef<str>,
simfs: &[impl AsRef<str>],
) -> Result<BTreeSet<PathBuf>, BuildError> {
let base = project_root.as_ref().join(src_dir.as_ref());
let walker = globwalk::GlobWalkerBuilder::from_patterns(base, simfs)
.follow_links(true)
.file_type(FileType::FILE)
.build()?;
let mut paths = BTreeSet::new();

for entry in walker {
paths.insert(entry?.path().canonicalize()?);
}

Ok(paths)
}

pub fn resolve_local_dir(path: &impl AsRef<Path>) -> Result<PathBuf, BuildError> {
let mut path_outer = PathBuf::from(path.as_ref());

Expand Down
35 changes: 35 additions & 0 deletions crates/cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use smplx_build::DependencyConfig;
use crate::commands::Command;
use crate::commands::build::Build;
use crate::commands::clean::Clean;
use crate::commands::error::{CommandError, FmtError};
use crate::commands::fmt::Format;
use crate::commands::init::Init;
use crate::commands::install::Install;
use crate::commands::regtest::Regtest;
Expand Down Expand Up @@ -89,6 +91,39 @@ impl Cli {

Ok(Clean::run(&loaded_config.build.out_dir, flags)?)
}
Command::Fmt { opts } => {
use std::io::Write;

let exit_status = if Format::is_info_request(opts) {
Format::run_info(opts)?
} else {
let files = if opts.files.is_empty() {
let config_path = Format::manifest_path(opts).map_err(CommandError::from)?;
let project_root = config_path
.parent()
.ok_or_else(|| FmtError::InvalidManifestPath(config_path.clone()))
.map_err(CommandError::from)?;
let loaded_config = Config::load(&config_path)?;

Format::resolve_files(&loaded_config.build, project_root)?
.into_iter()
.collect::<Vec<_>>()
} else {
opts.files
.iter()
.map(|s| {
let p = PathBuf::from(s);
p.canonicalize().unwrap_or(p)
})
.collect::<Vec<_>>()
};

Format::run(opts, &files)?
};

std::io::stdout().flush()?;
std::process::exit(exit_status);
}
}
}
}
46 changes: 46 additions & 0 deletions crates/cli/src/commands/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ pub enum Command {
#[command(flatten)]
flags: CleanFlags,
},
/// Formats the configured Simplex source files using simfmt
Fmt {
#[command(flatten)]
opts: FormatOpts,
},
}

#[allow(clippy::struct_excessive_bools)]
Expand Down Expand Up @@ -80,3 +85,44 @@ pub struct CleanFlags {
#[arg(long = "all")]
pub remove_all: bool,
}

#[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Args)]
pub struct FormatOpts {
/// Path to the file.
#[arg(value_hint = clap::ValueHint::FilePath, value_name = "PATH", num_args(1..))]
pub files: Vec<std::path::PathBuf>,

/// No output printed to stdout
#[arg(short = 'q', long = "quiet")]
pub quiet: bool,

/// Use verbose output
#[arg(short = 'v', long = "verbose")]
pub verbose: bool,

/// Print simfmt version and exit
#[arg(long = "version")]
pub version: bool,

/// Specify path to Simplex.toml
#[arg(long = "manifest-path", value_name = "manifest-path")]
pub manifest_path: Option<String>,

#[arg(
short = 'f',
long = "message-format",
value_name = "message-format",
help = format!("Specify message-format: {}", crate::commands::fmt::MessageFormat::OPTIONS)
)]
pub message_format: Option<String>,

/// Options passed to simfmt
// `raw = true` makes the `--` separator explicit.
#[arg(id = "simfmt_options", raw = true)]
pub simfmt_options: Vec<String>,

/// Run simfmt in check mode
#[arg(long = "check")]
pub check: bool,
}
30 changes: 30 additions & 0 deletions crates/cli/src/commands/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,43 @@ pub enum CommandError {
#[error(transparent)]
Install(#[from] InstallError),

#[error(transparent)]
Fmt(#[from] FmtError),

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

#[error("Verbosity level should be either -v or -vv, got: -v x {0}")]
BadVersbosityMode(u8),
}

#[derive(thiserror::Error, Debug)]
pub enum FmtError {
#[error("Quiet mode and verbose mode are not compatible")]
ConflictingVerbosity,

#[error("Failed to find manifest in current and parent directories")]
FailedToFindManifest,

#[error("The manifest-path must be a path to a Simplex.toml file, got: '{}'", .0.display())]
InvalidManifestPath(PathBuf),

#[error("Invalid --message-format value: {0}. Allowed values are: short|human")]
InvalidMessageFormat(String),

#[error("no files matched the configured simf_files patterns under '{}'", .0.display())]
NoFiles(PathBuf),

#[error("Failed to determine the current directory: {0}")]
CurrentDir(std::io::Error),

#[error("Failed to determine the simplex executable path: {0}")]
CurrentExecutable(std::io::Error),

#[error("could not run simfmt at '{}': {source}", binary.display())]
RunSimfmt { binary: PathBuf, source: std::io::Error },
}

#[derive(thiserror::Error, Debug)]
pub enum InitError {
#[error("Failed to open file '{1}': {0}")]
Expand Down
Loading
Loading