From 57878e74c68fb79be097488ad337096a8074bed5 Mon Sep 17 00:00:00 2001 From: Krusty/Benediction Date: Sat, 17 Aug 2024 13:10:24 +0200 Subject: [PATCH] [cpclib-runner] Several bndbuild refactoring to add cpclib-runner that will ease some additional refactorings to include emucontrol within bndbuild --- Cargo.lock | 23 ++- Cargo.toml | 19 +- cpclib-basm/pgo.sh | 0 cpclib-bdasm/tries.sh | 0 cpclib-bndbuild/Cargo.toml | 10 +- cpclib-bndbuild/src/executor.rs | 18 +- cpclib-bndbuild/src/lib.rs | 1 - cpclib-bndbuild/src/runners/assembler.rs | 74 +------- cpclib-bndbuild/src/runners/mod.rs | 46 +---- cpclib-bndbuild/src/task.rs | 25 ++- cpclib-common/src/clap_extra.rs | 1 - cpclib-common/src/lib.rs | 174 +----------------- cpclib-emucontrol/Cargo.toml | 2 +- cpclib-emucontrol/src/lib.rs | 6 +- cpclib-emucontrol/src/main.rs | 2 +- cpclib-emucontrol/tests/test_enigo.rs | 0 cpclib-runner/Cargo.toml | 24 +++ .../src/delegated.rs | 8 +- cpclib-runner/src/lib.rs | 4 + cpclib-runner/src/runner/arguments.rs | 27 +++ cpclib-runner/src/runner/assembler.rs | 89 +++++++++ .../src/runner}/emulator.rs | 17 +- .../src/runner}/impdisc.rs | 5 +- .../src/runner}/martine.rs | 5 +- cpclib-runner/src/runner/mod.rs | 9 + .../src/runner/runner.rs | 19 +- 26 files changed, 259 insertions(+), 349 deletions(-) mode change 100644 => 100755 cpclib-basm/pgo.sh mode change 100644 => 100755 cpclib-bdasm/tries.sh mode change 100644 => 100755 cpclib-emucontrol/tests/test_enigo.rs create mode 100644 cpclib-runner/Cargo.toml rename {cpclib-bndbuild => cpclib-runner}/src/delegated.rs (95%) create mode 100644 cpclib-runner/src/lib.rs create mode 100644 cpclib-runner/src/runner/arguments.rs create mode 100644 cpclib-runner/src/runner/assembler.rs rename {cpclib-bndbuild/src/runners => cpclib-runner/src/runner}/emulator.rs (95%) rename {cpclib-bndbuild/src/runners => cpclib-runner/src/runner}/impdisc.rs (96%) rename {cpclib-bndbuild/src/runners => cpclib-runner/src/runner}/martine.rs (96%) create mode 100644 cpclib-runner/src/runner/mod.rs rename cpclib-bndbuild/src/runners/extern.rs => cpclib-runner/src/runner/runner.rs (72%) diff --git a/Cargo.lock b/Cargo.lock index d122d56f..c903dd93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1603,11 +1603,9 @@ dependencies = [ "cpclib-common", "cpclib-disc", "cpclib-imgconverter", + "cpclib-runner", "cpclib-xfertool", - "directories", "dot-writer", - "flate2", - "glob", "globmatch", "lazy-regex", "minijinja", @@ -1616,12 +1614,9 @@ dependencies = [ "serde_yaml", "serial_test", "shlex", - "tar", "test-generator", "thiserror", "topologic", - "ureq", - "zip-extract", ] [[package]] @@ -1703,8 +1698,8 @@ dependencies = [ "bon", "camino-tempfile", "clap 4.5.15", - "cpclib-bndbuild", "cpclib-common", + "cpclib-runner", "enigo", "fs_extra", "glob", @@ -1750,6 +1745,20 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "cpclib-runner" +version = "0.1.0" +dependencies = [ + "cpclib-common", + "directories", + "flate2", + "glob", + "shlex", + "tar", + "ureq", + "zip-extract", +] + [[package]] name = "cpclib-sna" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 529e333e..f7ee00ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,26 +2,29 @@ members = [ "cpclib-asm", "cpclib-basic", + "cpclib-basm", + "cpclib-bdasm", "cpclib-bndbuild", "cpclib-common", "cpclib-cpr", + "cpclib-cprcli", "cpclib-crunchers", "cpclib-disc", + "cpclib-emucontrol", "cpclib-image", + "cpclib-imgconverter", "cpclib-macros", + "cpclib-runner", "cpclib-sna", "cpclib-tokens", + "cpclib-visual-basm", + "cpclib-visual-bndbuild", + "cpclib-wasm", "cpclib-xfer", "cpclib-xfertool", - # "cpclib-xferfs", "cpclib-z80emu", "cpclib", - "cpclib-basm", - "cpclib-bdasm", - "cpclib-imgconverter", - "cpclib-visual-basm", - "cpclib-visual-bndbuild", - "cpclib-wasm", "cpclib-cprcli", "cpclib-emucontrol", + # "cpclib-xferfs", ] resolver = "2" @@ -48,6 +51,7 @@ cpclib-disc = { version = "0.8.0", path = "cpclib-disc", default-features = fals cpclib-image = { version = "0.8.0", path = "cpclib-image", default-features = false } cpclib-imgconverter = { version = "0.8.0", path = "cpclib-imgconverter", default-features = false } cpclib-macros = { version = "0.8.0", path = "cpclib-macros", default-features = false } +cpclib-runner = { version = "0.1.0", path = "cpclib-runner", default-features = false } cpclib-sna = { version = "0.8.0", path = "cpclib-sna", default-features = false } cpclib-tokens = { version = "0.8.0", path = "cpclib-tokens", default-features = false } cpclib-visual-bndbuild = { version = "0.4.0", path = "cpclib-visual-bndbuild", default-features = false } @@ -144,6 +148,7 @@ self_cell = "1.0.4" semver = "1.0.23" serde = { version = "1.0.204", features = ["derive"] } serial_test = "3.1.1" +shlex = "1.3.0" similar-asserts = "1.5.0" simple_logger = { version = "4.3.3" } smallvec = "1.13.2" diff --git a/cpclib-basm/pgo.sh b/cpclib-basm/pgo.sh old mode 100644 new mode 100755 diff --git a/cpclib-bdasm/tries.sh b/cpclib-bdasm/tries.sh old mode 100644 new mode 100755 diff --git a/cpclib-bndbuild/Cargo.toml b/cpclib-bndbuild/Cargo.toml index 7b432cfa..3c547d61 100644 --- a/cpclib-bndbuild/Cargo.toml +++ b/cpclib-bndbuild/Cargo.toml @@ -17,7 +17,7 @@ exclude = ["examples", "tests/dummy", "*.gif"] [dependencies] - +cpclib-runner.workspace = true cpclib-common = {workspace=true, features=["cmdline"]} cpclib-basm = { workspace=true, default-features=false, features=["xferlib"] } cpclib-asm.workspace = true @@ -26,22 +26,16 @@ cpclib-imgconverter = { workspace=true, features=["xferlib"]} cpclib-xfertool.workspace = true anyhow = "1.0.86" -directories = "5.0.1" dot-writer = "0.1.3" -flate2 = "1.0.31" -glob = "0.3.1" globmatch = "0.3" lazy-regex = "3.2.0" minijinja = {version="2.1.1", features=["loader"]} self_cell = "1.0.4" serde_yaml = "0.9.34" serde.workspace = true -shlex = "1.3.0" -tar = "0.4.41" +shlex.workspace = true thiserror = "1.0" topologic = "1.1.0" -ureq.workspace = true -zip-extract = "=0.1.3" [build-dependencies] built.workspace = true diff --git a/cpclib-bndbuild/src/executor.rs b/cpclib-bndbuild/src/executor.rs index fb042539..19f33f6f 100644 --- a/cpclib-bndbuild/src/executor.rs +++ b/cpclib-bndbuild/src/executor.rs @@ -1,18 +1,18 @@ use std::sync::LazyLock; -use crate::delegated::DelegatedRunner; -use crate::runners::assembler::BasmRunner; +use cpclib_runner::delegated::DelegatedRunner; +use cpclib_runner::runner::impdisc::ImpDskVersion; +use cpclib_runner::runner::martine::MartineVersion; +use cpclib_runner::runner::{ExternRunner, Runner}; + +use crate::runners::assembler::{Assembler, BasmRunner}; use crate::runners::bndbuild::BndBuildRunner; use crate::runners::cp::CpRunner; use crate::runners::disc::DiscManagerRunner; use crate::runners::echo::EchoRunner; use crate::runners::imgconverter::ImgConverterRunner; -use crate::runners::impdisc::ImpDskVersion; -use crate::runners::martine::MartineVersion; -use crate::runners::r#extern::ExternRunner; use crate::runners::rm::RmRunner; use crate::runners::xfer::XferRunner; -use crate::runners::Runner; use crate::task::Task; pub static BASM_RUNNER: LazyLock = LazyLock::new(BasmRunner::default); @@ -37,10 +37,10 @@ pub fn execute(task: &Task) -> Result<(), String> { }, Task::Assembler(a, _) => { match a { - crate::runners::assembler::Assembler::Basm => BASM_RUNNER.run(task.args()), - crate::runners::assembler::Assembler::Rasm(v) => { + Assembler::Basm => BASM_RUNNER.run(task.args()), + Assembler::Extern(e) => { DelegatedRunner { - app: v.configuration(), + app: e.configuration(), cmd: a.get_command().to_owned() } .run(task.args()) diff --git a/cpclib-bndbuild/src/lib.rs b/cpclib-bndbuild/src/lib.rs index b133e097..c0834722 100644 --- a/cpclib-bndbuild/src/lib.rs +++ b/cpclib-bndbuild/src/lib.rs @@ -15,7 +15,6 @@ pub use crate::BndBuilder; pub mod builder; pub mod constraints; -pub mod delegated; pub mod executor; pub mod rules; pub mod runners; diff --git a/cpclib-bndbuild/src/runners/assembler.rs b/cpclib-bndbuild/src/runners/assembler.rs index cf86fa1b..805bb0f4 100644 --- a/cpclib-bndbuild/src/runners/assembler.rs +++ b/cpclib-bndbuild/src/runners/assembler.rs @@ -1,92 +1,26 @@ -use cpclib_common::camino::Utf8Path; use cpclib_common::clap::{self, Arg, ArgAction, Command}; use cpclib_common::itertools::Itertools; +use cpclib_runner::runner::assembler::ExternAssembler; -use super::r#extern::ExternRunner; use super::{Runner, RunnerWithClap}; use crate::built_info; -use crate::delegated::{ArchiveFormat, DelegateApplicationDescription}; -use crate::task::{BASM_CMDS, RASM_CMDS}; +use crate::task::BASM_CMDS; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Assembler { Basm, - Rasm(RasmVersion) + Extern(ExternAssembler) } impl Assembler { pub fn get_command(&self) -> &str { match self { Assembler::Basm => &BASM_CMDS[0], - Assembler::Rasm(_) => &RASM_CMDS[0] + Assembler::Extern(a) => a.get_command() } } } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum RasmVersion { - Consolidation2024 // V2_2_5 -} - -impl Default for RasmVersion { - fn default() -> Self { - Self::Consolidation2024 - } -} - -cfg_match! { - cfg(target_os = "linux") => - { - impl RasmVersion { - pub fn configuration(&self) -> DelegateApplicationDescription { - match self { - RasmVersion::Consolidation2024 => - DelegateApplicationDescription { - download_url: "https://github.com/EdouardBERGE/rasm/archive/refs/tags/v2.2.5.zip", // we assume a modern CPU - folder : "rasm_consolidation", - archive_format: ArchiveFormat::Zip, - exec_fname: "rasm", - compile: Some(Box::new(|path: &Utf8Path| -> Result<(), String>{ - let command = vec!["make"]; - ExternRunner::default().inner_run(&command)?; - - let command = vec!["mv", "rasm.exe", "rasm"]; - ExternRunner::default().inner_run(&command)?; - - Ok(()) - })) - } - } - } - } - - } - cfg(target_os = "windows") => - { - impl RasmVersion { - pub fn configuration(&self) -> DelegateApplicationDescription { - match self { - RasmVersion::Consolidation2024 => - DelegateApplicationDescription { - download_url: "https://github.com/EdouardBERGE/rasm/releases/download/v2.2.5/rasm_win64.exe", // we assume a modern CPU - folder : "rasm_consolidation", - archive_format: ArchiveFormat::Raw, - exec_fname: "rasm.exe", - compile: None - } - } - } - } - - } - cfg(target_os = "macos") => - { - - } - _ => { - } -} - pub struct BasmRunner { command: clap::Command } diff --git a/cpclib-bndbuild/src/runners/mod.rs b/cpclib-bndbuild/src/runners/mod.rs index 567dbc18..871bd7a6 100644 --- a/cpclib-bndbuild/src/runners/mod.rs +++ b/cpclib-bndbuild/src/runners/mod.rs @@ -1,59 +1,15 @@ use cpclib_common::clap::{ArgMatches, Command}; -use glob::glob; -use shlex::split; +use cpclib_runner::runner::Runner; pub mod assembler; pub mod bndbuild; pub mod cp; pub mod disc; pub mod echo; -pub mod emulator; -pub mod r#extern; pub mod imgconverter; -pub mod impdisc; -pub mod martine; pub mod rm; pub mod xfer; -/// Get all args (split string as done in shell and apply glob matching) -fn get_all_args(arguments: &str) -> Vec { - let init_args = split(arguments).unwrap_or_default(); - let mut res = Vec::new(); - for p in init_args { - match glob(&p) { - Ok(entries) => { - let mut added = 0; - for entry in entries { - match entry { - Ok(p) => res.push(p.display().to_string()), - Err(e) => res.push(e.path().display().to_string()) - } - added += 1; - } - if added == 0 { - res.push(p); - } - }, - Err(_) => res.push(p) - } - } - res -} - -pub trait Runner { - /// Run the task and return true if successfull - fn run(&self, arguments: &str) -> Result<(), String> { - println!("\t$ {} {}", self.get_command(), arguments); - let args = get_all_args(&arguments.replace(r"\", r"\\").replace("\"", "\\\"")); - self.inner_run(&args) - } - - /// Implement the command specific action - fn inner_run>(&self, itr: &[S]) -> Result<(), String>; - - fn get_command(&self) -> &str; -} - pub trait RunnerWithClap: Runner { fn get_clap_command(&self) -> &Command; diff --git a/cpclib-bndbuild/src/task.rs b/cpclib-bndbuild/src/task.rs index 90f07cf5..55798442 100644 --- a/cpclib-bndbuild/src/task.rs +++ b/cpclib-bndbuild/src/task.rs @@ -1,11 +1,16 @@ use std::fmt::Display; use cpclib_common::itertools::Itertools; +use cpclib_runner::runner::assembler::{RasmVersion, RASM_CMD}; +use cpclib_runner::runner::emulator::{ + AceVersion, CpcecVersion, Emulator, WinapeVersion, ACE_CMD, CPCEC_CMD, WINAPE_CMD +}; +use cpclib_runner::runner::impdisc::IMPDISC_CMD; +use cpclib_runner::runner::martine::MARTINE_CMD; use serde::de::{Error, Visitor}; use serde::{Deserialize, Deserializer}; -use crate::runners::assembler::{Assembler, RasmVersion}; -use crate::runners::emulator::{AceVersion, CpcecVersion, Emulator, WinapeVersion}; +use crate::runners::assembler::Assembler; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Task { @@ -23,20 +28,20 @@ pub enum Task { Xfer(StandardTask) } -pub const ACE_CMDS: &[&str] = &["ace", "acedl"]; -pub const WINAPE_CMDS: &[&str] = &["winape"]; -pub const CPCEC_CMDS: &[&str] = &["cpcec"]; +pub const ACE_CMDS: &[&str] = &[ACE_CMD, "acedl"]; +pub const WINAPE_CMDS: &[&str] = &[WINAPE_CMD]; +pub const CPCEC_CMDS: &[&str] = &[CPCEC_CMD]; pub const BASM_CMDS: &[&str] = &["basm", "assemble"]; pub const BNDBUILD_CMDS: &[&str] = &["bndbuild", "build"]; pub const CP_CMDS: &[&str] = &["cp", "copy"]; pub const DISC_CMDS: &[&str] = &["dsk", "disc"]; -pub const IMPDISC_CMDS: &[&str] = &["impdsk", "impdisc"]; +pub const IMPDISC_CMDS: &[&str] = &[IMPDISC_CMD, "impdisc"]; pub const ECHO_CMDS: &[&str] = &["echo", "print"]; pub const EXTERN_CMDS: &[&str] = &["extern"]; pub const IMG2CPC_CMDS: &[&str] = &["img2cpc", "imgconverter"]; -pub const MARTINE_CMDS: &[&str] = &["martine"]; -pub const RASM_CMDS: &[&str] = &["rasm"]; +pub const MARTINE_CMDS: &[&str] = &[MARTINE_CMD]; +pub const RASM_CMDS: &[&str] = &[RASM_CMD]; pub const RM_CMDS: &[&str] = &["rm", "del"]; pub const XFER_CMDS: &[&str] = &["xfer", "cpcwifi", "m4"]; @@ -108,7 +113,9 @@ impl<'de> Deserialize<'de> for Task { } else if RASM_CMDS.iter().contains(&code) { Ok(Task::Assembler( - Assembler::Rasm(RasmVersion::default()), + Assembler::Extern(cpclib_runner::runner::assembler::ExternAssembler::Rasm( + RasmVersion::default() + )), std )) } diff --git a/cpclib-common/src/clap_extra.rs b/cpclib-common/src/clap_extra.rs index 2fe5c798..618c8871 100644 --- a/cpclib-common/src/clap_extra.rs +++ b/cpclib-common/src/clap_extra.rs @@ -1,4 +1,3 @@ - use std::str::FromStr; use camino::Utf8PathBuf; diff --git a/cpclib-common/src/lib.rs b/cpclib-common/src/lib.rs index 8bb85d0d..8f240d8d 100644 --- a/cpclib-common/src/lib.rs +++ b/cpclib-common/src/lib.rs @@ -1,191 +1,29 @@ #![feature(slice_take)] +pub mod clap_extra; +pub mod parse; pub mod riff; -use std::str::FromStr; - -use camino::Utf8PathBuf; #[cfg(feature = "cmdline")] -pub use clap; +pub use ::clap; +pub use clap_extra::*; +pub use parse::*; #[cfg(all(not(target_arch = "wasm32"), feature = "rayon"))] pub use rayon; #[cfg(feature = "cmdline")] pub use semver; #[cfg(feature = "cmdline")] pub use time; -use winnow::ascii::{alphanumeric1, space0}; -use winnow::combinator::{alt, not, opt, terminated}; -use winnow::error::{AddContext, ParserError, StrContext}; -use winnow::stream::{AsBytes, AsChar, Compare, Stream, StreamIsPartial}; -use winnow::token::take_while; -use winnow::{PResult, Parser}; pub use { bitfield, bitflags, bitvec, camino, itertools, num, resolve_path, smallvec, smol_str, strsim, winnow }; -pub fn utf8pathbuf_value_parser(must_exist: bool) -> impl Fn(&str) -> Result { - move |p: &str| { - match Utf8PathBuf::from_str(p) { - Ok(p) => { - if !must_exist || p.exists() { - Ok(p) - } - else { - Err(format!("{} does not exists", p)) - } - }, - Err(_) => Err(format!("{} is not a valid filename.", p)) - } - } -} - -#[inline] -/// (prefix) space number suffix -pub fn parse_value>(input: &mut I) -> PResult -where - I: Stream + StreamIsPartial + for<'a> Compare<&'a str>, - ::Slice: AsBytes, - ::Token: AsChar, - ::Token: Clone, - I: for<'a> Compare<&'a [u8; 2]>, - I: for<'a> Compare<&'a [u8; 1]>, - I: winnow::stream::Compare, - Error: AddContext -{ - #[derive(Clone, PartialEq, Debug)] - #[repr(u32)] - enum EncodingKind { - Hex = 16, - Bin = 2, - Dec = 10, - - AmbiguousBinHex = 200, - Unk = 255 - } - - let before_encoding: ::Checkpoint = input.checkpoint(); - - // numbers have an optional prefix with an eventual space - let encoding = opt(terminated( - alt(( - alt((b"0x", b"0X", b"#", b"$", b"&")).value(EncodingKind::Hex), // hexadecimal number - alt((b"0b", b"0B")).value(EncodingKind::AmbiguousBinHex), - b"%".value(EncodingKind::Bin) // binary number - )), - space0 - ) - .context(StrContext::Label("Number prefix detection"))) - .parse_next(input)? - .unwrap_or(EncodingKind::Unk); - - let hex_digits_and_sep = || { - take_while(1.., (('0'..='9'), ('a'..='f'), ('A'..='F'), '_')) - .context(StrContext::Label("Read hexadecimal digits")) - }; - let mut dec_digits_and_sep = - take_while(1.., (('0'..='9'), '_')).context(StrContext::Label("Read decimal digits")); - let mut bin_digits_and_sep = - take_while(1.., (('0'..='1'), '_')).context(StrContext::Label("Read binary digits")); - - let (encoding, digits) = match encoding { - EncodingKind::Hex => (EncodingKind::Hex, hex_digits_and_sep().parse_next(input)?), - EncodingKind::Bin => (EncodingKind::Bin, bin_digits_and_sep.parse_next(input)?), - EncodingKind::Dec => unreachable!("No prefix exist for decimal kind"), - EncodingKind::AmbiguousBinHex => { - // we parse for hexdecimal then guess the encoding - let digits = opt(hex_digits_and_sep()).parse_next(input)?; - let suffix = opt(alt((b'h', b'H'))) - .verify(|s| { - if digits.is_none() { - s.is_some() - } - else { - true - } - }) - .parse_next(input)?; - - if suffix.is_some() { - // this is an hexadecimal number and part of the encoding place was - // TODO find a more efficient way to not redo that - input.reset(&before_encoding); - b'0'.parse_next(input)?; // eat 0 - let digits = hex_digits_and_sep().parse_next(input)?; - let _suffix = alt((b'h', b'H')).parse_next(input)?; - - (EncodingKind::Hex, digits) - } - else { - // this is a decimal number - (EncodingKind::Bin, digits.unwrap()) - } - }, - EncodingKind::Unk => { - // we parse for hexdecimal then guess the encoding - let backup = input.checkpoint(); - let digits = hex_digits_and_sep().parse_next(input)?; - let suffix = opt(alt((b'h', b'H'))).parse_next(input)?; - - if suffix.is_some() { - // we know if is hex - (EncodingKind::Hex, digits) - } - else { - // we need to choose between bin and dec so we reparse a second time :() - input.reset(&backup); - let digits: &[u8] = digits.as_bytes(); - let last_digit = digits[digits.len() - 1]; - if last_digit == b'b' || last_digit == b'B' { - // we need to check this is really a binary - let digits = bin_digits_and_sep.parse_next(input)?; - alt((b'b', b'B')).parse_next(input)?; - (EncodingKind::Bin, digits) - } - else { - (EncodingKind::Dec, dec_digits_and_sep.parse_next(input)?) - } - } - } - }; - - // ensure there are no more numbers - if encoding == EncodingKind::Hex { - not(alphanumeric1) - .context(StrContext::Label("This is not an hexadecimal number")) - .parse_next(input)?; - } - - // right here encoding anddigits are compatible - debug_assert!(encoding != EncodingKind::Unk); - debug_assert!(encoding != EncodingKind::AmbiguousBinHex); - let digits: &[u8] = digits.as_bytes(); - - let base = encoding as u32; - let mut number = 0; - for digit in digits.iter().filter(|&&digit| digit != b'_') { - let digit = *digit; - let digit = if digit.is_ascii_digit() { - digit - b'0' - } - else if (b'a'..=b'f').contains(&digit) { - digit - b'a' + 10 - } - else { - digit - b'A' + 10 - } as u32; - - number = base * number + digit; - } - - Ok(number) -} - #[cfg(test)] mod tests { use winnow::error::ContextError; use winnow::stream::AsBStr; - use winnow::BStr; + use winnow::{BStr, Parser}; use super::*; diff --git a/cpclib-emucontrol/Cargo.toml b/cpclib-emucontrol/Cargo.toml index 46302d8b..02cd90fe 100644 --- a/cpclib-emucontrol/Cargo.toml +++ b/cpclib-emucontrol/Cargo.toml @@ -8,7 +8,7 @@ repository.workspace = true homepage.workspace = true [dependencies] -cpclib-bndbuild.workspace = true +cpclib-runner.workspace = true cpclib-common.workspace = true camino-tempfile.workspace = true clap = {version="4.5.15", features=["derive"]} diff --git a/cpclib-emucontrol/src/lib.rs b/cpclib-emucontrol/src/lib.rs index 77ab1b62..069c11ce 100644 --- a/cpclib-emucontrol/src/lib.rs +++ b/cpclib-emucontrol/src/lib.rs @@ -4,10 +4,10 @@ use std::path::absolute; use std::time::Duration; use bon::builder; -use cpclib_bndbuild::delegated::DelegatedRunner; -use cpclib_bndbuild::runners::emulator::Emulator; -use cpclib_bndbuild::runners::Runner; use cpclib_common::itertools::Itertools; +use cpclib_runner::delegated::DelegatedRunner; +use cpclib_runner::runner::emulator::Emulator; +use cpclib_runner::runner::Runner; use enigo::{Direction, Enigo, Key, Keyboard}; use xcap::image::{open, GenericImageView, ImageBuffer, Rgba}; use xcap::Window; diff --git a/cpclib-emucontrol/src/main.rs b/cpclib-emucontrol/src/main.rs index 0dd107c4..9ab45e54 100644 --- a/cpclib-emucontrol/src/main.rs +++ b/cpclib-emucontrol/src/main.rs @@ -2,8 +2,8 @@ use std::process::exit; use std::time::Duration; use clap::{ArgAction, Parser, Subcommand, ValueEnum}; -use cpclib_bndbuild::runners::emulator::{AceVersion, CpcecVersion, Emulator, WinapeVersion}; use cpclib_emucontrol::{get_emulator_window, start_emulator, EmulatorConf, Robot}; +use cpclib_runner::runner::emulator::{AceVersion, CpcecVersion, Emulator, WinapeVersion}; use enigo::{Enigo, Settings}; #[derive(Parser, Debug)] diff --git a/cpclib-emucontrol/tests/test_enigo.rs b/cpclib-emucontrol/tests/test_enigo.rs old mode 100644 new mode 100755 diff --git a/cpclib-runner/Cargo.toml b/cpclib-runner/Cargo.toml new file mode 100644 index 00000000..523c4b8c --- /dev/null +++ b/cpclib-runner/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "cpclib-runner" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true + +resolver = "2" +description = "Dependency for various cpclib crates to help running external applications (mostly assemblers or emulators)" + +[dependencies] +cpclib-common.workspace=true +ureq.workspace = true + +zip-extract = "=0.1.3" +directories = "5.0.1" +tar = "0.4.41" +flate2 = "1.0.31" +glob = "0.3.1" +shlex.workspace = true + + diff --git a/cpclib-bndbuild/src/delegated.rs b/cpclib-runner/src/delegated.rs similarity index 95% rename from cpclib-bndbuild/src/delegated.rs rename to cpclib-runner/src/delegated.rs index e39e3207..2c9d4dd4 100644 --- a/cpclib-bndbuild/src/delegated.rs +++ b/cpclib-runner/src/delegated.rs @@ -1,14 +1,12 @@ use std::io::{Cursor, Read}; use cpclib_common::camino::{Utf8Path, Utf8PathBuf}; -use cpclib_common::itertools::Itertools; use directories::ProjectDirs; use flate2::read::GzDecoder; use tar::Archive; use ureq::Response; -use crate::runners::r#extern::ExternRunner; -use crate::runners::Runner; +use crate::runner::runner::{ExternRunner, Runner}; pub enum ArchiveFormat { Raw, @@ -98,8 +96,8 @@ impl DelegateApplicationDescription { } pub struct DelegatedRunner { - pub(crate) app: DelegateApplicationDescription, - pub(crate) cmd: String + pub app: DelegateApplicationDescription, + pub cmd: String } impl DelegatedRunner { diff --git a/cpclib-runner/src/lib.rs b/cpclib-runner/src/lib.rs new file mode 100644 index 00000000..025a7474 --- /dev/null +++ b/cpclib-runner/src/lib.rs @@ -0,0 +1,4 @@ +#![feature(cfg_match)] + +pub mod delegated; +pub mod runner; diff --git a/cpclib-runner/src/runner/arguments.rs b/cpclib-runner/src/runner/arguments.rs new file mode 100644 index 00000000..6c2770fd --- /dev/null +++ b/cpclib-runner/src/runner/arguments.rs @@ -0,0 +1,27 @@ +use glob::glob; +use shlex::split; + +/// Get all args (split string as done in shell and apply glob matching) +pub fn get_all_args(arguments: &str) -> Vec { + let init_args = split(arguments).unwrap_or_default(); + let mut res = Vec::new(); + for p in init_args { + match glob(&p) { + Ok(entries) => { + let mut added = 0; + for entry in entries { + match entry { + Ok(p) => res.push(p.display().to_string()), + Err(e) => res.push(e.path().display().to_string()) + } + added += 1; + } + if added == 0 { + res.push(p); + } + }, + Err(_) => res.push(p) + } + } + res +} diff --git a/cpclib-runner/src/runner/assembler.rs b/cpclib-runner/src/runner/assembler.rs new file mode 100644 index 00000000..11b3da48 --- /dev/null +++ b/cpclib-runner/src/runner/assembler.rs @@ -0,0 +1,89 @@ +use cpclib_common::camino::Utf8Path; + +use super::{ExternRunner, Runner}; +use crate::delegated::{ArchiveFormat, DelegateApplicationDescription}; + +pub const RASM_CMD: &str = "rasm"; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ExternAssembler { + Rasm(RasmVersion) +} + +impl ExternAssembler { + pub fn get_command(&self) -> &str { + match self { + ExternAssembler::Rasm(_) => RASM_CMD + } + } + + pub fn configuration(&self) -> DelegateApplicationDescription { + match self { + ExternAssembler::Rasm(r) => r.configuration() + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum RasmVersion { + Consolidation2024 // V2_2_5 +} + +impl Default for RasmVersion { + fn default() -> Self { + Self::Consolidation2024 + } +} + +cfg_match! { + cfg(target_os = "linux") => + { + impl RasmVersion { + pub fn configuration(&self) -> DelegateApplicationDescription { + match self { + RasmVersion::Consolidation2024 => + DelegateApplicationDescription { + download_url: "https://github.com/EdouardBERGE/rasm/archive/refs/tags/v2.2.5.zip", // we assume a modern CPU + folder : "rasm_consolidation", + archive_format: ArchiveFormat::Zip, + exec_fname: "rasm", + compile: Some(Box::new(|path: &Utf8Path| -> Result<(), String>{ + let command = vec!["make"]; + ExternRunner::default().inner_run(&command)?; + + let command = vec!["mv", "rasm.exe", "rasm"]; + ExternRunner::default().inner_run(&command)?; + + Ok(()) + })) + } + } + } + } + + } + cfg(target_os = "windows") => + { + impl RasmVersion { + pub fn configuration(&self) -> DelegateApplicationDescription { + match self { + RasmVersion::Consolidation2024 => + DelegateApplicationDescription { + download_url: "https://github.com/EdouardBERGE/rasm/releases/download/v2.2.5/rasm_win64.exe", // we assume a modern CPU + folder : "rasm_consolidation", + archive_format: ArchiveFormat::Raw, + exec_fname: "rasm.exe", + compile: None + } + } + } + } + + } + cfg(target_os = "macos") => + { + + } + _ => { + } +} diff --git a/cpclib-bndbuild/src/runners/emulator.rs b/cpclib-runner/src/runner/emulator.rs similarity index 95% rename from cpclib-bndbuild/src/runners/emulator.rs rename to cpclib-runner/src/runner/emulator.rs index b024d2ff..5bf9d859 100644 --- a/cpclib-bndbuild/src/runners/emulator.rs +++ b/cpclib-runner/src/runner/emulator.rs @@ -1,7 +1,10 @@ use cpclib_common::camino::Utf8PathBuf; use crate::delegated::{ArchiveFormat, DelegateApplicationDescription}; -use crate::task::{ACE_CMDS, CPCEC_CMDS, WINAPE_CMDS}; + +pub const ACE_CMD: &str = "ace"; +pub const WINAPE_CMD: &str = "winape"; +pub const CPCEC_CMD: &str = "cpcec"; #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum Emulator { @@ -19,9 +22,9 @@ impl Default for Emulator { impl Emulator { pub fn get_command(&self) -> &str { match self { - Emulator::Ace(_) => ACE_CMDS[0], - Emulator::Cpcec(_) => CPCEC_CMDS[0], - Emulator::Winape(_) => WINAPE_CMDS[0] + Emulator::Ace(_) => ACE_CMD, + Emulator::Cpcec(_) => CPCEC_CMD, + Emulator::Winape(_) => WINAPE_CMD } } @@ -74,7 +77,7 @@ pub enum CpcecVersion { #[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] pub enum WinapeVersion { #[default] - v2_0b2 + V2_0b2 } impl Emulator { @@ -160,7 +163,7 @@ cfg_match! { impl WinapeVersion { pub fn configuration(&self) -> DelegateApplicationDescription { match self { - WinapeVersion::v2_0b2 => { + WinapeVersion::V2_0b2 => { DelegateApplicationDescription { download_url: "http://www.winape.net/download/WinAPE20B2.zip", folder: "winape_2_0b2", @@ -208,7 +211,7 @@ cfg_match! { impl WinapeVersion { pub fn configuration(&self) -> DelegateApplicationDescription { match self { - WinapeVersion::v2_0b2 => { + WinapeVersion::V2_0b2 => { DelegateApplicationDescription { download_url: "http://www.winape.net/download/WinAPE20B2.zip", folder: "winape_2_0b2", diff --git a/cpclib-bndbuild/src/runners/impdisc.rs b/cpclib-runner/src/runner/impdisc.rs similarity index 96% rename from cpclib-bndbuild/src/runners/impdisc.rs rename to cpclib-runner/src/runner/impdisc.rs index 6d3cfa84..ab9ad28c 100644 --- a/cpclib-bndbuild/src/runners/impdisc.rs +++ b/cpclib-runner/src/runner/impdisc.rs @@ -1,5 +1,6 @@ use crate::delegated::{ArchiveFormat, DelegateApplicationDescription}; -use crate::task::IMPDISC_CMDS; + +pub const IMPDISC_CMD: &str = "impdsk"; pub enum ImpDskVersion { V0_24 @@ -13,7 +14,7 @@ impl Default for ImpDskVersion { impl ImpDskVersion { pub fn get_command(&self) -> &str { - IMPDISC_CMDS[0] + IMPDISC_CMD } } diff --git a/cpclib-bndbuild/src/runners/martine.rs b/cpclib-runner/src/runner/martine.rs similarity index 96% rename from cpclib-bndbuild/src/runners/martine.rs rename to cpclib-runner/src/runner/martine.rs index efd59355..04134779 100644 --- a/cpclib-bndbuild/src/runners/martine.rs +++ b/cpclib-runner/src/runner/martine.rs @@ -1,5 +1,6 @@ use crate::delegated::{ArchiveFormat, DelegateApplicationDescription}; -use crate::task::MARTINE_CMDS; + +pub const MARTINE_CMD: &str = "martine"; pub enum MartineVersion { V0_39 @@ -13,7 +14,7 @@ impl Default for MartineVersion { impl MartineVersion { pub fn get_command(&self) -> &str { - MARTINE_CMDS[0] + MARTINE_CMD } } diff --git a/cpclib-runner/src/runner/mod.rs b/cpclib-runner/src/runner/mod.rs new file mode 100644 index 00000000..5e63adf8 --- /dev/null +++ b/cpclib-runner/src/runner/mod.rs @@ -0,0 +1,9 @@ +pub mod arguments; +pub mod runner; + +pub mod assembler; +pub mod emulator; +pub mod impdisc; +pub mod martine; + +pub use runner::{ExternRunner, Runner}; diff --git a/cpclib-bndbuild/src/runners/extern.rs b/cpclib-runner/src/runner/runner.rs similarity index 72% rename from cpclib-bndbuild/src/runners/extern.rs rename to cpclib-runner/src/runner/runner.rs index f2f17282..352f717d 100644 --- a/cpclib-bndbuild/src/runners/extern.rs +++ b/cpclib-runner/src/runner/runner.rs @@ -1,7 +1,20 @@ use cpclib_common::itertools::Itertools; -use super::Runner; -use crate::task::EXTERN_CMDS; +use crate::runner::arguments::get_all_args; + +pub trait Runner { + /// Run the task and return true if successfull + fn run(&self, arguments: &str) -> Result<(), String> { + println!("\t$ {} {}", self.get_command(), arguments); + let args = get_all_args(&arguments.replace(r"\", r"\\").replace("\"", "\\\"")); + self.inner_run(&args) + } + + /// Implement the command specific action + fn inner_run>(&self, itr: &[S]) -> Result<(), String>; + + fn get_command(&self) -> &str; +} #[derive(Default)] pub struct ExternRunner {} @@ -42,6 +55,6 @@ impl Runner for ExternRunner { } fn get_command(&self) -> &str { - EXTERN_CMDS[0] + "external" } }