Make command line argument parsing more robust.

This commit is contained in:
Simon Persson 2015-07-19 20:36:14 +00:00
parent 17fdca40dd
commit ef1c86df18
4 changed files with 90 additions and 12 deletions

42
Cargo.lock generated
View file

@ -3,6 +3,7 @@ name = "librespot"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"librespot-protocol 0.1.0", "librespot-protocol 0.1.0",
"mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -12,6 +13,7 @@ dependencies = [
"protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)", "protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)", "readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
"rpassword 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)", "rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
"shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)", "shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
@ -41,6 +43,14 @@ name = "gcc"
version = "0.3.8" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "kernel32-sys" name = "kernel32-sys"
version = "0.1.2" version = "0.1.2"
@ -68,6 +78,14 @@ dependencies = [
"protobuf 1.0.1 (git+https://github.com/plietar/rust-protobuf.git)", "protobuf 1.0.1 (git+https://github.com/plietar/rust-protobuf.git)",
] ]
[[package]]
name = "log"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "mod_path" name = "mod_path"
version = "0.1.5" version = "0.1.5"
@ -139,6 +157,17 @@ name = "readall"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/plietar/rust-readall.git#d2bcc1de325705230e79ba444cde2f39b469f891" source = "git+https://github.com/plietar/rust-readall.git#d2bcc1de325705230e79ba444cde2f39b469f891"
[[package]]
name = "rpassword"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rust-crypto" name = "rust-crypto"
version = "0.2.31" version = "0.2.31"
@ -193,6 +222,14 @@ dependencies = [
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "termios"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.30" version = "0.1.30"
@ -254,6 +291,11 @@ dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "winapi"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "winapi-build" name = "winapi-build"
version = "0.1.0" version = "0.1.0"

View file

@ -24,6 +24,8 @@ lazy_static = "0.1.*"
rust-crypto = "*" rust-crypto = "*"
time = "*" time = "*"
tempfile = "*" tempfile = "*"
rpassword = "*"
getopts = "0.2.4"
[dependencies.protobuf] [dependencies.protobuf]
git = "https://github.com/plietar/rust-protobuf.git" git = "https://github.com/plietar/rust-protobuf.git"

View file

@ -25,12 +25,11 @@ cargo build
A sample program implementing a headless Spotify Connect receiver is provided. A sample program implementing a headless Spotify Connect receiver is provided.
Once you've built *librespot*, run it using : Once you've built *librespot*, run it using :
```shell ```shell
target/debug/main APPKEY USERNAME PASSWORD CACHEDIR DEVICENAME target/debug/main -a APPKEY -u USERNAME -c CACHEDIR -d DEVICENAME
``` ```
where `APPKEY` is the path to a Spotify application key file, `USERNAME` and where `APPKEY` is the path to a Spotify application key file, `USERNAME` is your
`PASSWORD` are your Spotify credentials, `CACHEDIR` is the path to directory Spotify username, `CACHEDIR` is the path to directory where data will be cached,
where data will be cached, and `DEVICENAME` is the name that will appear in the and `DEVICENAME` is the name that will appear in the Spotify Connect menu.
Spotify Connect menu.
## Disclaimer ## Disclaimer
Using this code to connect to Spotify's API is probably forbidden by them, and Using this code to connect to Spotify's API is probably forbidden by them, and

View file

@ -1,27 +1,62 @@
#![feature(scoped)] #![feature(scoped)]
#![feature(result_expect)]
#![allow(deprecated)] #![allow(deprecated)]
extern crate getopts;
extern crate librespot; extern crate librespot;
extern crate rpassword;
use std::clone::Clone; use std::clone::Clone;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::{stdout, Read, Write};
use std::path::Path; use std::path::Path;
use std::thread; use std::thread;
use std::path::PathBuf; use std::path::PathBuf;
use getopts::Options;
use rpassword::read_password;
use librespot::session::{Config, Session}; use librespot::session::{Config, Session};
use librespot::util::version::version_string; use librespot::util::version::version_string;
use librespot::player::Player; use librespot::player::Player;
use librespot::spirc::SpircManager; use librespot::spirc::SpircManager;
fn usage(program: &str, opts: &Options) -> String {
let brief = format!("Usage: {} [options]", program);
format!("{}", opts.usage(&brief))
}
fn main() { fn main() {
let mut args = std::env::args().skip(1); let args: Vec<String> = std::env::args().collect();
let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap(); let program = args[0].clone();
let username = args.next().unwrap();
let password = args.next().unwrap(); let mut opts = Options::new();
let cache_location = args.next().unwrap(); opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
let name = args.next().unwrap(); opts.reqopt("u", "username", "Username to sign in with", "USERNAME");
opts.optopt("p", "password", "Password (optional)", "PASSWORD");
opts.reqopt("c", "cache", "Path to a directory where files will be cached.", "CACHE");
opts.reqopt("n", "name", "Device name", "NAME");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m },
Err(f) => {
print!("Error: {}\n{}", f.to_string(), usage(&*program, &opts));
return;
}
};
let mut appkey_file = File::open(
Path::new(&*matches.opt_str("a").unwrap())
).expect("Could not open app key.");
let username = matches.opt_str("u").unwrap();
let cache_location = matches.opt_str("c").unwrap();
let name = matches.opt_str("n").unwrap();
let password = matches.opt_str("p").unwrap_or_else(|| {
print!("Password: ");
stdout().flush().unwrap();
read_password().unwrap()
});
let mut appkey = Vec::new(); let mut appkey = Vec::new();
appkey_file.read_to_end(&mut appkey).unwrap(); appkey_file.read_to_end(&mut appkey).unwrap();