Create the main binary

This commit is contained in:
Wojciech Kozlowski 2023-04-10 00:00:06 +02:00
parent 16045a6c85
commit 5250b1b93a
6 changed files with 279 additions and 26 deletions

184
Cargo.lock generated
View File

@ -2,6 +2,26 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -20,6 +40,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.0" version = "0.3.0"
@ -50,6 +85,24 @@ dependencies = [
"instant", "instant",
] ]
[[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]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.1" version = "0.3.1"
@ -71,7 +124,7 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.3.1",
"libc", "libc",
"windows-sys", "windows-sys",
] ]
@ -82,6 +135,12 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.140" version = "0.2.140"
@ -101,6 +160,7 @@ dependencies = [
"once_cell", "once_cell",
"serde", "serde",
"serde_json", "serde_json",
"structopt",
"tempfile", "tempfile",
"uuid", "uuid",
] ]
@ -111,6 +171,30 @@ version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[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 1.0.109",
"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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.54" version = "1.0.54"
@ -175,7 +259,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.11",
] ]
[[package]] [[package]]
@ -189,6 +273,47 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.11" version = "2.0.11"
@ -213,12 +338,33 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.8" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.3.0" version = "1.3.0"
@ -228,6 +374,40 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.45.0" version = "0.45.0"

View File

@ -8,6 +8,7 @@ edition = "2021"
[dependencies] [dependencies]
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
structopt = "0.3"
uuid = { version = "1.3", features = ["serde"] } uuid = { version = "1.3", features = ["serde"] }
[dev-dependencies] [dev-dependencies]

View File

@ -4,7 +4,9 @@
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt::Display, fmt::Display,
process::Command, path::{PathBuf, Path}, path::{Path, PathBuf},
process::Command,
str,
}; };
use crate::{Album, AlbumId, Artist, ArtistId, Track}; use crate::{Album, AlbumId, Artist, ArtistId, Track};
@ -228,17 +230,22 @@ pub struct SystemExecutor {
} }
impl SystemExecutor { impl SystemExecutor {
pub fn new(bin: &str, path: Option<&Path>) -> SystemExecutor { pub fn new(bin: &str) -> Self {
SystemExecutor { SystemExecutor {
bin: bin.to_string(), bin: bin.to_string(),
config: path.map(|p| p.to_path_buf()), config: None,
} }
} }
pub fn config(mut self, path: Option<&Path>) -> Self {
self.config = path.map(|p| p.to_path_buf());
self
}
} }
impl Default for SystemExecutor { impl Default for SystemExecutor {
fn default() -> Self { fn default() -> Self {
SystemExecutor::new("beet", None) SystemExecutor::new("beet")
} }
} }
@ -250,7 +257,12 @@ impl BeetsExecutor for SystemExecutor {
cmd.arg(path); cmd.arg(path);
} }
let output = cmd.args(arguments).output()?; let output = cmd.args(arguments).output()?;
let output = std::str::from_utf8(&output.stdout)?; if !output.status.success() {
return Err(Error::CmdExecError(
String::from_utf8_lossy(&output.stderr).to_string(),
));
}
let output = str::from_utf8(&output.stdout)?;
Ok(output.split('\n').map(|s| s.to_string()).collect()) Ok(output.split('\n').map(|s| s.to_string()).collect())
} }
} }

View File

@ -1,6 +1,6 @@
//! Module for interacting with the music library. //! Module for interacting with the music library.
use std::{num::ParseIntError, str::Utf8Error}; use std::{num::ParseIntError, str::Utf8Error, fmt};
use crate::Artist; use crate::Artist;
@ -98,6 +98,8 @@ impl Query {
/// Error type for library calls. /// Error type for library calls.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// The underlying library failed to execute a command.
CmdExecError(String),
/// The underlying library returned invalid data. /// The underlying library returned invalid data.
InvalidData(String), InvalidData(String),
/// The underlying library experienced an I/O error. /// The underlying library experienced an I/O error.
@ -126,6 +128,12 @@ impl From<Utf8Error> for Error {
} }
} }
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:#?}", self)
}
}
/// Trait for interacting with the music library. /// Trait for interacting with the music library.
pub trait Library { pub trait Library {
/// List lirbary items that match the a specific query. /// List lirbary items that match the a specific query.

57
src/main.rs Normal file
View File

@ -0,0 +1,57 @@
use std::{path::PathBuf, process::exit};
use structopt::StructOpt;
use musichoard::{
database::{
json::{DatabaseJson, DatabaseJsonFile},
DatabaseWrite,
},
library::{
beets::{Beets, SystemExecutor},
Library, Query,
},
};
#[derive(StructOpt)]
struct Opt {
#[structopt(
short = "b",
long = "beets-config",
name = "beets config file path",
parse(from_os_str)
)]
beets_config_file_path: Option<PathBuf>,
#[structopt(
short = "d",
long = "database",
name = "database file path",
default_value = "database.json",
parse(from_os_str)
)]
database_file_path: PathBuf,
}
fn main() {
let opt = Opt::from_args();
let mut beets = Beets::new(Box::new(
SystemExecutor::default().config(opt.beets_config_file_path.as_deref()),
));
let collection = match beets.list(&Query::new()) {
Ok(collection) => collection,
Err(e) => {
println!("{e}");
exit(1)
}
};
let mut database = DatabaseJson::new(Box::new(DatabaseJsonFile::new(&opt.database_file_path)));
if let Err(e) = database.write(&collection) {
println!("{e}");
exit(1)
}
}

View File

@ -12,7 +12,7 @@ use crate::COLLECTION;
#[test] #[test]
fn test_no_config_list() { fn test_no_config_list() {
let executor = SystemExecutor::new("beet", None); let executor = SystemExecutor::default();
let mut beets = Beets::new(Box::new(executor)); let mut beets = Beets::new(Box::new(executor));
let output = beets.list(&Query::default()).unwrap(); let output = beets.list(&Query::default()).unwrap();
@ -23,10 +23,9 @@ fn test_no_config_list() {
#[test] #[test]
fn test_full_list() { fn test_full_list() {
let executor = SystemExecutor::new( let executor = SystemExecutor::default().config(Some(
"beet", &fs::canonicalize("./tests/files/library/config.yml").unwrap(),
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), ));
);
let mut beets = Beets::new(Box::new(executor)); let mut beets = Beets::new(Box::new(executor));
let output = beets.list(&Query::default()).unwrap(); let output = beets.list(&Query::default()).unwrap();
@ -37,10 +36,9 @@ fn test_full_list() {
#[test] #[test]
fn test_album_artist_query() { fn test_album_artist_query() {
let executor = SystemExecutor::new( let executor = SystemExecutor::default().config(Some(
"beet", &fs::canonicalize("./tests/files/library/config.yml").unwrap(),
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), ));
);
let mut beets = Beets::new(Box::new(executor)); let mut beets = Beets::new(Box::new(executor));
let output = beets let output = beets
@ -53,27 +51,24 @@ fn test_album_artist_query() {
#[test] #[test]
fn test_album_title_query() { fn test_album_title_query() {
let executor = SystemExecutor::new( let executor = SystemExecutor::default().config(Some(
"beet", &fs::canonicalize("./tests/files/library/config.yml").unwrap(),
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), ));
);
let mut beets = Beets::new(Box::new(executor)); let mut beets = Beets::new(Box::new(executor));
let output = beets let output = beets
.list(&Query::default().album_title(QueryOption::Include(String::from("Slovo")))) .list(&Query::default().album_title(QueryOption::Include(String::from("Slovo"))))
.unwrap(); .unwrap();
let expected: Vec<Artist> = COLLECTION[0..1].to_owned(); let expected: Vec<Artist> = COLLECTION[0..1].to_owned();
assert_eq!(output, expected); assert_eq!(output, expected);
} }
#[test] #[test]
fn test_exclude_query() { fn test_exclude_query() {
let executor = SystemExecutor::new( let executor = SystemExecutor::default().config(Some(
"beet", &fs::canonicalize("./tests/files/library/config.yml").unwrap(),
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()), ));
);
let mut beets = Beets::new(Box::new(executor)); let mut beets = Beets::new(Box::new(executor));
let output = beets let output = beets