diff --git a/Cargo.lock b/Cargo.lock index f7831a8..668ccdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,12 @@ dependencies = [ "libc", ] +[[package]] +name = "anyhow" +version = "1.0.97" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" + [[package]] name = "apply" version = "0.3.0" @@ -844,6 +850,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "clipboard-win" version = "5.4.0" @@ -1070,6 +1082,7 @@ dependencies = [ name = "cosmic-player" version = "0.1.0" dependencies = [ + "clap_lex", "dirs", "env_logger", "fork", @@ -1084,13 +1097,13 @@ dependencies = [ "libcosmic", "log", "mpris-server", - "pico-args", "rust-embed", "serde", "smol_str", "tempfile", "tokio", "url", + "vergen", ] [[package]] @@ -1292,6 +1305,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "deranged" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058" +dependencies = [ + "powerfmt", +] + [[package]] name = "derivative" version = "2.2.0" @@ -3680,6 +3702,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -3752,6 +3780,15 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -4139,6 +4176,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -4561,6 +4604,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + [[package]] name = "rustybuzz" version = "0.12.1" @@ -4796,9 +4845,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smithay-client-toolkit" @@ -5138,6 +5187,39 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -5575,6 +5657,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vergen" +version = "8.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" +dependencies = [ + "anyhow", + "cfg-if", + "rustversion", + "time", +] + [[package]] name = "version-compare" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index a1c90a2..a01c9a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "cosmic-player" version = "0.1.0" edition = "2021" +[build-dependencies] +vergen = { version = "8", features = ["git", "gitcl"] } + [dependencies] dirs = "5" gstreamer-tag = "0.23" @@ -12,11 +15,15 @@ serde = { version = "1", features = ["serde_derive"] } tempfile = "3" tokio = "1" url = "2" -pico-args = "0.5" +# CLI arguments +clap_lex = "0.7" # Internationalization icu_collator = "1.5" icu_provider = { version = "1.5", features = ["sync"] } -i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] } +i18n-embed = { version = "0.14", features = [ + "fluent-system", + "desktop-requester", +] } i18n-embed-fl = "0.7" rust-embed = "8" # Logging @@ -61,4 +68,3 @@ debug = true # libcosmic = { path = "../libcosmic" } # cosmic-config = { path = "../libcosmic/cosmic-config" } # cosmic-theme = { path = "../libcosmic/cosmic-theme" } - diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..f2a7518 --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +use vergen::EmitBuilder; + +fn main() { + EmitBuilder::builder().git_sha(true).emit().unwrap(); +} + diff --git a/src/argparse.rs b/src/argparse.rs index 9adb05f..38e2af3 100644 --- a/src/argparse.rs +++ b/src/argparse.rs @@ -3,9 +3,57 @@ use std::{fs, io}; +use clap_lex::RawArgs; use log::warn; use url::Url; +pub fn parse() -> Arguments { + let raw_args = RawArgs::from_args(); + let mut cursor = raw_args.cursor(); + let mut arguments = Arguments::default(); + let mut urls = Vec::new(); + + // Parse the arguments + while let Some(arg) = raw_args.next(&mut cursor) { + if let Some(mut shorts) = arg.to_short() { + while let Some(short) = shorts.next_flag() { + match short { + Ok('h') => print_help(), + Ok('V') => print_version(), + Ok(c) => warn!("unexpected flag: -{c}"), + Err(os_str) => warn!("unexpected flag: -{}", os_str.to_string_lossy()), + } + } + } else if let Some((long, _opt_value)) = arg.to_long() { + match long { + Ok("help") => print_help(), + Ok("version") => print_version(), + _ => warn!("unexpected flag: {}", arg.display()), + } + } else { + // Freestanding arguments are treated as URLs + match arg.to_value().ok().map(Source::try_from) { + Some(Ok(source)) => urls.push(source.0), + Some(Err(why)) => { + warn!("{}: not a valid URL: {}", arg.display(), why) + } + None => { + warn!("{}: not a valid string", arg.display()) + } + } + } + } + + if urls.len() > 1 { + arguments.urls = Some(urls); + } else { + urls.truncate(1); + arguments.url_opt = urls.pop(); + } + + arguments +} + #[derive(Debug, Default)] pub struct Arguments { /// Files or directory URLs to play @@ -14,39 +62,6 @@ pub struct Arguments { pub url_opt: Option, } -impl Arguments { - pub fn from_args() -> Result { - let mut parser = pico_args::Arguments::from_env(); - - // Freestanding arguments are treated as URLs - let urls: Vec = std::iter::from_fn(|| { - parser - .opt_free_from_fn(|arg| Source::try_from(arg)) - .ok() - .flatten() - }) - .map(|source| source.0) - .collect(); - - let remainder = parser.finish(); - for arg in remainder { - warn!("Unused argument: {arg:?}"); - } - - if urls.len() > 1 { - Ok(Arguments { - urls: Some(urls), - ..Default::default() - }) - } else { - Ok(Arguments { - url_opt: urls.into_iter().next(), - ..Default::default() - }) - } - } -} - // #[derive(Debug)] // pub enum Source { // File(Url), @@ -81,3 +96,36 @@ impl TryFrom<&str> for Source { } } } + +#[cold] +pub fn print_help() -> ! { + let version = env!("CARGO_PKG_VERSION"); + let git_rev = env!("VERGEN_GIT_SHA"); + + println!( + r#"cosmic-player {version} (git commit {git_rev}) +System76 + +Designed for the COSMICâ„¢ desktop environment, cosmic-player is a +libcosmic-based multimedia player for music and videos. + +Project home page: https://github.com/pop-os/cosmic-player + +Options: + -h, --help Show this message + -V, --version Show the version of cosmic-player"# + ); + + std::process::exit(0); +} + +#[cold] +pub fn print_version() -> ! { + println!( + "cosmic-player {} (git commit {})", + env!("CARGO_PKG_VERSION"), + env!("VERGEN_GIT_SHA") + ); + + std::process::exit(0); +} diff --git a/src/main.rs b/src/main.rs index a657a55..6cf1a9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,8 @@ const GST_PLAY_FLAG_VIDEO: i32 = 1 << 0; const GST_PLAY_FLAG_AUDIO: i32 = 1 << 1; const GST_PLAY_FLAG_TEXT: i32 = 1 << 2; +use std::error::Error; + fn language_name(code: &str) -> Option { let code_c = CString::new(code).ok()?; let name_c = unsafe { @@ -68,7 +70,7 @@ fn language_name(code: &str) -> Option { /// Runs application with these settings #[rustfmt::skip] -fn main() -> Result<(), Box> { +fn main() -> Result<(), Box> { #[cfg(all(unix, not(target_os = "redox")))] match fork::daemon(true, true) { Ok(fork::Fork::Child) => (), @@ -78,17 +80,19 @@ fn main() -> Result<(), Box> { process::exit(1); } } - + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init(); localize::localize(); + let args = argparse::parse(); + let (config_handler, config) = match cosmic_config::Config::new(App::APP_ID, CONFIG_VERSION) { Ok(config_handler) => { let config = match Config::get_entry(&config_handler) { Ok(ok) => ok, Err((errs, config)) => { - log::info!("errors loading config: {:?}", errs); + log::error!("errors loading config: {:?}", errs); config } }; @@ -121,15 +125,13 @@ fn main() -> Result<(), Box> { settings = settings.theme(config.app_theme.theme()); settings = settings.size_limits(Limits::NONE.min_width(360.0).min_height(180.0)); - let argparse::Arguments { urls, url_opt } = argparse::Arguments::from_args().unwrap_or_default(); - let flags = Flags { config_handler, config, config_state_handler, config_state, - url_opt, - urls + url_opt: args.url_opt, + urls: args.urls, }; cosmic::app::run::(settings, flags)?;