From 076a947b0809295818ce5bdaf9ba6af3039d2545 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Tue, 4 Feb 2020 22:56:15 -0800 Subject: [PATCH] structopt-ify, move list ablum to subcommand add filtering by regex. --- Cargo.lock | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 + src/main.rs | 74 +++++++++++++++++++++---- 3 files changed, 224 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a21a04..d588b14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,12 +6,41 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +[[package]] +name = "aho-corasick" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "anyhow" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + [[package]] name = "autocfg" version = "0.1.7" @@ -108,6 +137,21 @@ dependencies = [ "time", ] +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -781,9 +825,37 @@ version = "0.1.0" dependencies = [ "google-photoslibrary1", "google_api_auth", + "regex", + "structopt", "yup-oauth2", ] +[[package]] +name = "proc-macro-error" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875077759af22fa20b610ad4471d8155b321c89c3f2785526c9839b099be4e0a" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5717d9fa2664351a01ed73ba5ef6df09c01a521cb42cb65a061432a826f3c7a" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn", + "syn-mid", +] + [[package]] name = "proc-macro2" version = "1.0.8" @@ -942,7 +1014,10 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", + "thread_local", ] [[package]] @@ -1030,6 +1105,17 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustversion" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bba175698996010c4f6dce5e7f173b6eb781fce25d2cfc45e27091ce0b79f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ryu" version = "1.0.2" @@ -1163,6 +1249,36 @@ dependencies = [ "bytes", ] +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1bcbed7d48956fcbb5d80c6b95aedb553513de0a1b451ea92679d999c010e98" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "095064aa1f5b94d14e635d0a5684cf140c43ae40a0fd990708d38f5d669e5f64" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.14" @@ -1174,6 +1290,17 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "synstructure" version = "0.12.3" @@ -1200,6 +1327,24 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] + [[package]] name = "time" version = "0.1.42" @@ -1466,6 +1611,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1509,6 +1660,12 @@ dependencies = [ "rand", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + [[package]] name = "version_check" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 5f9b64f..f4c29a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,7 @@ edition = "2018" [dependencies] yup-oauth2 = "^3.1" google_api_auth = { git = "https://github.com/google-apis-rs/generator", features = ["with-yup-oauth2"] } +# TODO, use https://git.z.xinu.tv/wathiede/google-api-photoslibrary and figure out auth story. google-photoslibrary1 = { path = "../google-api-photoslibrary" } +structopt = "0.3.9" +regex = "1.3.4" diff --git a/src/main.rs b/src/main.rs index 2d0f044..1c570bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,44 @@ -use std::path::Path; +use std::error::Error; +use std::path::PathBuf; use google_api_auth; use google_photoslibrary1; -use yup_oauth2::GetToken; +use regex::Regex; +use structopt::StructOpt; use yup_oauth2::{Authenticator, InstalledFlow}; -fn main() -> Result<(), Box> { - // Read application secret from a file. Sometimes it's easier to compile it directly into - // the binary. The clientsecret file contains JSON like `{"installed":{"client_id": ... }}` - let credentials = "/home/wathiede/src/xinu.tv/photosync/auth/oob-credentials.json"; - let secret = yup_oauth2::read_application_secret(Path::new(credentials)).expect(credentials); +#[derive(Debug, StructOpt)] +enum Command { + /// List albums for the user of the given credentials. Optionally title filter. + ListAlbums { title_filter: Option }, +} + +#[derive(Debug, StructOpt)] +#[structopt( + name = "photosync", + about = "Utility for interacting with Google Photos API." +)] +struct Opt { + /// Activate debug mode + #[structopt(short, parse(from_occurrences))] + verbose: u32, + + /// Path to json file containing Google client ID and secrets for out of band auth flow. + #[structopt(long)] + credentials: PathBuf, + /// Path to json file where photosync will store auth tokens refreshed from Google. + #[structopt(long)] + token_cache: PathBuf, + + #[structopt(subcommand)] + cmd: Command, +} + +fn new_client( + credentials: &PathBuf, + token_cache: &PathBuf, +) -> Result> { + let secret = yup_oauth2::read_application_secret(credentials)?; // Create an authenticator that uses an InstalledFlow to authenticate. The // authentication tokens are persisted to a file named tokencache.json. The @@ -19,7 +48,7 @@ fn main() -> Result<(), Box> { secret, yup_oauth2::InstalledFlowReturnMethod::Interactive, )) - .persist_tokens_to_disk("/tmp/tokencache.json") + .persist_tokens_to_disk(token_cache) .build() .unwrap(); @@ -27,18 +56,43 @@ fn main() -> Result<(), Box> { let auth = google_api_auth::yup_oauth2::from_authenticator(auth, scopes); - let client = google_photoslibrary1::Client::new(auth); + Ok(google_photoslibrary1::Client::new(auth)) +} + +fn list_albums( + client: google_photoslibrary1::Client, + title_filter: Option, +) -> Result<(), Box> { for album in client .shared_albums() .list() .iter_shared_albums_with_all_fields() { let a = album?; + if let Some(title_filter) = &title_filter { + match &a.title { + Some(title) => { + if !title_filter.is_match(&title) { + continue; + } + } + None => continue, + } + } println!( "album: {} {}", a.id.unwrap_or("NO ID".to_string()), - a.title.unwrap_or("NO TITLE".to_string()) + a.title.unwrap_or("NO TITLE".to_string()).to_string() ); } Ok(()) } + +fn main() -> Result<(), Box> { + let opt = Opt::from_args(); + println!("opt: {:?}", opt); + let client = new_client(&opt.credentials, &opt.token_cache)?; + match opt.cmd { + Command::ListAlbums { title_filter } => list_albums(client, title_filter), + } +}