From 7d15f27465a916b98217900a320f0fbe56edbe9d Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Sun, 2 Jan 2022 20:20:09 -0500 Subject: [PATCH] Implement simple CLI for executing scripts --- Cargo.lock | 132 ++++++++++++++++++++++++++++++++++++- Cargo.toml | 7 +- mps-interpreter/Cargo.toml | 1 - mps-player/Cargo.toml | 1 - src/cli.rs | 16 +++++ src/main.rs | 74 +++++++++++++++++---- tests/test.mps | 2 + 7 files changed, 213 insertions(+), 20 deletions(-) create mode 100644 src/cli.rs create mode 100644 tests/test.mps diff --git a/Cargo.lock b/Cargo.lock index f60c404..63d8945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,6 +50,17 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -146,6 +157,36 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim 0.10.0", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "claxon" version = "0.4.3" @@ -232,7 +273,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.9.3", "syn", ] @@ -371,6 +412,24 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hound" version = "3.4.0" @@ -383,6 +442,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "instant" version = "0.1.12" @@ -567,6 +636,7 @@ dependencies = [ name = "mps" version = "0.1.0" dependencies = [ + "clap", "mps-interpreter", "mps-player", ] @@ -777,6 +847,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -833,6 +912,30 @@ dependencies = [ "toml", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.32" @@ -986,6 +1089,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "symphonia" version = "0.4.0" @@ -1143,6 +1252,21 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + [[package]] name = "thiserror" version = "1.0.30" @@ -1187,6 +1311,12 @@ dependencies = [ "serde", ] +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index ad3e09e..cdd9d4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" authors = ["NGnius (Graham) "] description = "Music Playlist Scripting language (MPS)" license = "LGPL-2.1-only OR GPL-2.0-or-later" -license-file = "LICENSE" readme = "README.md" [workspace] @@ -16,5 +15,7 @@ members = [ [dependencies] # local -mps-interpreter = { path = "./mps-interpreter" } -mps-player = { path = "./mps-player" } +mps-interpreter = { version = "0.1.0", path = "./mps-interpreter" } +mps-player = { version = "0.1.0", path = "./mps-player" } +# external +clap = { version = "3.0", features = ["derive"] } diff --git a/mps-interpreter/Cargo.toml b/mps-interpreter/Cargo.toml index 4423536..1723fb7 100644 --- a/mps-interpreter/Cargo.toml +++ b/mps-interpreter/Cargo.toml @@ -3,7 +3,6 @@ name = "mps-interpreter" version = "0.1.0" edition = "2021" license = "LGPL-2.1-only OR GPL-2.0-or-later" -license-file = "LICENSE" readme = "README.md" [dependencies] diff --git a/mps-player/Cargo.toml b/mps-player/Cargo.toml index d938e52..3ea2e47 100644 --- a/mps-player/Cargo.toml +++ b/mps-player/Cargo.toml @@ -3,7 +3,6 @@ name = "mps-player" version = "0.1.0" edition = "2021" license = "LGPL-2.1-only OR GPL-2.0-or-later" -license-file = "LICENSE" readme = "README.md" [dependencies] diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..5cfb084 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,16 @@ +use clap::{Parser}; + +#[derive(Parser)] +#[clap(author, version)] +#[clap(about = "Music playlist scripting language runtime")] +pub struct CliArgs { + /// Script to run + pub file: Option, + /// Generate m3u8 playlist + #[clap(short, long)] + pub playlist: Option, +} + +pub fn parse() -> CliArgs { + CliArgs::parse() +} diff --git a/src/main.rs b/src/main.rs index 5d056a0..4d00b0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,12 @@ //! //! Future home of a MPS REPL for playing music ergonomically through a CLI. //! + +mod cli; + use std::io; +use std::path::PathBuf; + use mps_interpreter::MpsRunner; use mps_player::{MpsPlayer, PlaybackError, MpsController}; @@ -16,19 +21,60 @@ fn play_cursor() -> Result<(), PlaybackError> { } fn main() { - //play_cursor().unwrap(); - let ctrl = MpsController::create(|| { - //let cursor = io::Cursor::<&'static str>::new("sql(`SELECT * FROM songs JOIN artists ON songs.artist = artists.artist_id WHERE artists.name like 'thundercat'`);"); - let cursor = io::Cursor::<&'static str>::new( - "sql(`SELECT * FROM songs JOIN artists ON songs.artist = artists.artist_id WHERE artists.name like 'thundercat'`); - artist(`gwen`);" - ); - let runner = MpsRunner::with_stream(cursor); - let player = MpsPlayer::new(runner).unwrap(); - player.set_volume(0.8); - player - }); + let args = cli::parse(); - ctrl.wait_for_done().unwrap(); - //ctrl.exit().unwrap(); // don't use both + if let Some(script_file) = &args.file { + // interpret script + // script file checks + if let Err(_) = file_checks(script_file) { + return; + } + // build playback controller + let script_file2 = script_file.clone(); + let player_builder = move || { + let script_reader = io::BufReader::new( + std::fs::File::open(&script_file2) + .expect(&format!("Abort: Cannot open file `{}`", &script_file2)) + ); + let runner = MpsRunner::with_stream(script_reader); + let player = MpsPlayer::new(runner).unwrap(); + player + }; + if let Some(playlist_file) = &args.playlist { + // generate playlist + let mut player = player_builder(); + let mut writer = io::BufWriter::new( + std::fs::File::create(playlist_file) + .expect(&format!("Abort: Cannot create writeable file `{}`", playlist_file)) + ); + match player.save_m3u8(&mut writer) { + Ok(_) => println!("Succes: Finished playlist `{}` from script `{}`", playlist_file, script_file), + Err(e) => eprintln!("{}", e), + } + } else { + // live playback + let ctrl = MpsController::create(player_builder); + match ctrl.wait_for_done() { + Ok(_) => println!("Succes: Finished playback from script `{}`", script_file), + Err(e) => eprintln!("{}", e), + } + } + } else { + // start REPL + // TODO + eprintln!("Abort: Cannot start REPL because it is not implemented yet :("); + } +} + +fn file_checks(path_str: &str) -> Result<(), ()> { + let path = PathBuf::from(path_str); + if !path.exists() { + eprintln!("Abort: File `{}` does not exist", path_str); + return Err(()); + } + if !path.is_file() { + eprintln!("Abort: Path `{}` is not a file", path_str); + return Err(()); + } + Ok(()) } diff --git a/tests/test.mps b/tests/test.mps new file mode 100644 index 0000000..c250472 --- /dev/null +++ b/tests/test.mps @@ -0,0 +1,2 @@ +sql_init(generate = false); +sql(`SELECT * FROM songs JOIN artists ON songs.artist = artists.artist_id WHERE artists.name like 'thundercat'`);