Create the main binary #15

Merged
wojtek merged 4 commits from 7---create-the-main-binary into main 2023-04-10 00:13:18 +02:00
6 changed files with 279 additions and 26 deletions
Showing only changes of commit 5250b1b93a - Show all commits

184
Cargo.lock generated
View File

@ -2,6 +2,26 @@
# It is not intended for manual editing.
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]]
name = "bitflags"
version = "1.3.2"
@ -20,6 +40,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "errno"
version = "0.3.0"
@ -50,6 +85,24 @@ dependencies = [
"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]]
name = "hermit-abi"
version = "0.3.1"
@ -71,7 +124,7 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
dependencies = [
"hermit-abi",
"hermit-abi 0.3.1",
"libc",
"windows-sys",
]
@ -82,6 +135,12 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.140"
@ -101,6 +160,7 @@ dependencies = [
"once_cell",
"serde",
"serde_json",
"structopt",
"tempfile",
"uuid",
]
@ -111,6 +171,30 @@ version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "proc-macro2"
version = "1.0.54"
@ -175,7 +259,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.11",
]
[[package]]
@ -189,6 +273,47 @@ dependencies = [
"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]]
name = "syn"
version = "2.0.11"
@ -213,12 +338,33 @@ dependencies = [
"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]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "uuid"
version = "1.3.0"
@ -228,6 +374,40 @@ dependencies = [
"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]]
name = "windows-sys"
version = "0.45.0"

View File

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

View File

@ -4,7 +4,9 @@
use std::{
collections::{HashMap, HashSet},
fmt::Display,
process::Command, path::{PathBuf, Path},
path::{Path, PathBuf},
process::Command,
str,
};
use crate::{Album, AlbumId, Artist, ArtistId, Track};
@ -228,17 +230,22 @@ pub struct SystemExecutor {
}
impl SystemExecutor {
pub fn new(bin: &str, path: Option<&Path>) -> SystemExecutor {
pub fn new(bin: &str) -> Self {
SystemExecutor {
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 {
fn default() -> Self {
SystemExecutor::new("beet", None)
SystemExecutor::new("beet")
}
}
@ -250,7 +257,12 @@ impl BeetsExecutor for SystemExecutor {
cmd.arg(path);
}
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())
}
}

View File

@ -1,6 +1,6 @@
//! Module for interacting with the music library.
use std::{num::ParseIntError, str::Utf8Error};
use std::{num::ParseIntError, str::Utf8Error, fmt};
use crate::Artist;
@ -98,6 +98,8 @@ impl Query {
/// Error type for library calls.
#[derive(Debug)]
pub enum Error {
/// The underlying library failed to execute a command.
CmdExecError(String),
/// The underlying library returned invalid data.
InvalidData(String),
/// 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.
pub trait Library {
/// 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]
fn test_no_config_list() {
let executor = SystemExecutor::new("beet", None);
let executor = SystemExecutor::default();
let mut beets = Beets::new(Box::new(executor));
let output = beets.list(&Query::default()).unwrap();
@ -23,10 +23,9 @@ fn test_no_config_list() {
#[test]
fn test_full_list() {
let executor = SystemExecutor::new(
"beet",
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()),
);
let executor = SystemExecutor::default().config(Some(
&fs::canonicalize("./tests/files/library/config.yml").unwrap(),
));
let mut beets = Beets::new(Box::new(executor));
let output = beets.list(&Query::default()).unwrap();
@ -37,10 +36,9 @@ fn test_full_list() {
#[test]
fn test_album_artist_query() {
let executor = SystemExecutor::new(
"beet",
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()),
);
let executor = SystemExecutor::default().config(Some(
&fs::canonicalize("./tests/files/library/config.yml").unwrap(),
));
let mut beets = Beets::new(Box::new(executor));
let output = beets
@ -53,27 +51,24 @@ fn test_album_artist_query() {
#[test]
fn test_album_title_query() {
let executor = SystemExecutor::new(
"beet",
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()),
);
let executor = SystemExecutor::default().config(Some(
&fs::canonicalize("./tests/files/library/config.yml").unwrap(),
));
let mut beets = Beets::new(Box::new(executor));
let output = beets
.list(&Query::default().album_title(QueryOption::Include(String::from("Slovo"))))
.unwrap();
let expected: Vec<Artist> = COLLECTION[0..1].to_owned();
assert_eq!(output, expected);
}
#[test]
fn test_exclude_query() {
let executor = SystemExecutor::new(
"beet",
Some(&fs::canonicalize("./tests/files/library/config.yml").unwrap()),
);
let executor = SystemExecutor::default().config(Some(
&fs::canonicalize("./tests/files/library/config.yml").unwrap(),
));
let mut beets = Beets::new(Box::new(executor));
let output = beets