Ver código fonte

Make command line argument parsing more robust.

Simon Persson 9 anos atrás
pai
commit
ef1c86df18
4 arquivos alterados com 90 adições e 12 exclusões
  1. 42 0
      Cargo.lock
  2. 2 0
      Cargo.toml
  3. 4 5
      README.md
  4. 42 7
      src/main.rs

+ 42 - 0
Cargo.lock

@@ -3,6 +3,7 @@ name = "librespot"
 version = "0.1.0"
 dependencies = [
  "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)",
  "librespot-protocol 0.1.0",
  "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)",
  "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)",
+ "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-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
  "shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
@@ -41,6 +43,14 @@ name = "gcc"
 version = "0.3.8"
 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]]
 name = "kernel32-sys"
 version = "0.1.2"
@@ -68,6 +78,14 @@ dependencies = [
  "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]]
 name = "mod_path"
 version = "0.1.5"
@@ -139,6 +157,17 @@ name = "readall"
 version = "0.1.0"
 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]]
 name = "rust-crypto"
 version = "0.2.31"
@@ -193,6 +222,14 @@ dependencies = [
  "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]]
 name = "time"
 version = "0.1.30"
@@ -254,6 +291,11 @@ dependencies = [
  "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]]
 name = "winapi-build"
 version = "0.1.0"

+ 2 - 0
Cargo.toml

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

+ 4 - 5
README.md

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

+ 42 - 7
src/main.rs

@@ -1,27 +1,62 @@
 #![feature(scoped)]
+#![feature(result_expect)]
 #![allow(deprecated)]
 
+extern crate getopts;
 extern crate librespot;
+extern crate rpassword;
 
 use std::clone::Clone;
 use std::fs::File;
-use std::io::Read;
+use std::io::{stdout, Read, Write};
 use std::path::Path;
 use std::thread;
 use std::path::PathBuf;
 
+use getopts::Options;
+use rpassword::read_password;
+
 use librespot::session::{Config, Session};
 use librespot::util::version::version_string;
 use librespot::player::Player;
 use librespot::spirc::SpircManager;
 
+fn usage(program: &str, opts: &Options) -> String {
+    let brief = format!("Usage: {} [options]", program);
+    format!("{}", opts.usage(&brief))
+}
+
 fn main() {
-    let mut args = std::env::args().skip(1);
-    let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap();
-    let username = args.next().unwrap();
-    let password = args.next().unwrap();
-    let cache_location = args.next().unwrap();
-    let name = args.next().unwrap();
+    let args: Vec<String> = std::env::args().collect();
+    let program = args[0].clone();
+
+    let mut opts = Options::new();
+    opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
+    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();
     appkey_file.read_to_end(&mut appkey).unwrap();