Merge branch 'develop'
diff --git a/Cargo.toml b/Cargo.toml
index 45bc374..ced41a9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "tuf"
-version = "0.1.1"
+version = "0.1.2"
 authors = [ "heartsucker <heartsucker@autistici.org>" ]
 description = "Library for The Update Framework (TUF)"
 homepage = "https://github.com/heartsucker/rust-tuf"
diff --git a/Makefile b/Makefile
index 908aa8f..ad5a83a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-.PHONY: help travis
+.PHONY: clean help test travis
 .DEFAULT_GOAL := help
 
 clean: ## Remove junk
diff --git a/appveyor.yml b/appveyor.yml
index 012ff30..b98fc75 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -57,5 +57,4 @@
 # TODO on failure cat Cargo.lock
 
 cache:
-  - target
-  - C:\Users\appveyor\.cargo\
+  - C:\Users\appveyor\.cargo\bin
diff --git a/src/lib.rs b/src/lib.rs
index 2b2f218..5e1d3d7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,139 @@
+//! This crate provides an API for talking to repositories that implement The Update Framework
+//! (TUF). Currently only downloading and verification of metadata is possible, not creating new
+//! metadata or storing targets.
+//!
+//! If you are unfamiliar with TUF, you should read up on via the [official
+//! website](http://theupdateframework.github.io/). This crate aims to implement the entirety of
+//! the specification as defined at the [head of the `develop`
+//! branch](https://github.com/theupdateframework/tuf/blob/develop/docs/tuf-spec.txt) in the
+//! official TUF git repository.
+//!
+//! ## Examples
+//!
+//! ### A Standalone Example
+//!
+//! ```no_run
+//! extern crate tuf;
+//! extern crate url;
+//! use tuf::{Tuf, Config, RemoteRepo};
+//! use std::path::PathBuf;
+//! use url::Url;
+//!
+//! fn main() {
+//!     let config = Config::build()
+//!         .remote(RemoteRepo::Http(Url::parse("http://localhost:8080/").unwrap()))
+//!         .local_path(PathBuf::from("/var/lib/tuf"))
+//!         .finish()
+//!         .unwrap();
+//!     let mut tuf = Tuf::new(config).unwrap();
+//!     let path_to_crate = tuf.fetch_target("targets/some_crate/0.1.0/pkg.crate").unwrap();
+//!     println!("Crate available at {}", path_to_crate.to_string_lossy());
+//! }
+//!
+//! ```
+//!
+//! The `Tuf` struct is the central piece to using this crate. It handles downloading and verifying
+//! of metadata as well as the storage of metadata and targets.
+//!
+//! ### An Integrated Example
+//!
+//! TUF is designed to be a drop in solution to verifying metadata and targets within an existing
+//! update library.
+//!
+//! Consider the following sample application that
+//!
+//! ```no_run
+//! extern crate url;
+//! use std::path::PathBuf;
+//! use url::Url;
+//!
+//! struct MyUpdater<'a> {
+//!     remote_url: Url,
+//!     local_cache: PathBuf,
+//!     package_list: Vec<&'a str>,
+//! }
+//!
+//! impl<'a> MyUpdater<'a> {
+//!     fn new(remote_url: Url, local_cache: PathBuf) -> Self {
+//!         MyUpdater {
+//!             remote_url: remote_url,
+//!             local_cache: local_cache,
+//!             package_list: Vec::new(),
+//!         }
+//!     }
+//!
+//!     fn update_lists(&mut self) -> Result<(), String> {
+//!         unimplemented!() // idk like some http + fs io probably
+//!     }
+//!
+//!     fn fetch_package(&self, package: &str) -> Result<PathBuf, String> {
+//!         if self.package_list.contains(&package) {
+//!             unimplemented!() // moar http + fs io
+//!         } else {
+//!             return Err("Unknown package".to_string())
+//!         }
+//!     }
+//! }
+//!
+//! fn main() {
+//!     let url = Url::parse("http://crates.io/").unwrap();
+//!     let cache = PathBuf::from("/var/lib/my-updater/");
+//!     let mut updater = MyUpdater::new(url, cache);
+//!     updater.update_lists().unwrap();
+//!     let path_to_crate = updater.fetch_package("some_crate/0.1.0").unwrap();
+//!     println!("Crate available at {}", path_to_crate.to_string_lossy());
+//! }
+//!
+//! ```
+//!
+//! This simple updater (baring some migration shims), could be altered to use TUF as follows.
+//!
+//! ```no_run
+//! extern crate tuf;
+//! extern crate url;
+//! use std::path::PathBuf;
+//! use tuf::{Tuf, Config, RemoteRepo};
+//! use url::Url;
+//!
+//! struct MyUpdater {
+//!     tuf: Tuf,
+//! }
+//!
+//! impl MyUpdater {
+//!     fn new(remote_url: Url, local_cache: PathBuf) -> Result<Self, String> {
+//!         let config = Config::build()
+//!             .remote(RemoteRepo::Http(remote_url))
+//!             .local_path(local_cache)
+//!             .finish()
+//!             .map_err(|e| format!("{:?}", e))?;
+//!         let tuf = Tuf::new(config)
+//!             .map_err(|e| format!("{:?}", e))?;
+//!         Ok(MyUpdater {
+//!             tuf: tuf,
+//!         })
+//!     }
+//!
+//!     fn update_lists(&mut self) -> Result<(), String> {
+//!         self.tuf.update().map_err(|e| format!("{:?}", e))
+//!     }
+//!
+//!     fn fetch_package(&self, package: &str) -> Result<PathBuf, String> {
+//!         self.tuf.fetch_target(&format!("targets/{:?}/pkg.crate", package))
+//!             .map_err(|e| format!("{:?}", e))
+//!     }
+//! }
+//!
+//! fn main() {
+//!     let url = Url::parse("http://crates.io/").unwrap();
+//!     let cache = PathBuf::from("/var/lib/my-updater/");
+//!     let mut updater = MyUpdater::new(url, cache).unwrap();
+//!     updater.update_lists().unwrap();
+//!     let path_to_crate = updater.fetch_package("some_crate/0.1.0").unwrap();
+//!     println!("Crate available at {}", path_to_crate.to_string_lossy());
+//! }
+//!
+//! ```
+
 extern crate chrono;
 extern crate data_encoding;
 extern crate env_logger;
diff --git a/src/main.rs b/src/main.rs
index 695546e..af4ecc6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -35,7 +35,10 @@
         .local_path(PathBuf::from(matches.value_of("path").unwrap()))
         .finish()?;
 
-    if let Some(_) = matches.subcommand_matches("init") {
+    if let Some(matches) = matches.subcommand_matches("fetch") {
+        let tuf = Tuf::new(config)?;
+        cmd_fetch(&tuf, matches.value_of("target").unwrap())
+    } else if let Some(_) = matches.subcommand_matches("init") {
         let path = PathBuf::from(matches.value_of("path").unwrap());
         cmd_init(&path)
     } else if let Some(_) = matches.subcommand_matches("list") {
@@ -88,6 +91,11 @@
         .group(ArgGroup::with_name("remote_repo")
                .args(&["url", "file"])
                .required(true))
+        .subcommand(SubCommand::with_name("fetch").about("Fetch a target")
+            .arg(Arg::with_name("target")
+                .takes_value(true)
+                .required(true)
+                .help("The full (non-local) path of the target to verify")))
         .subcommand(SubCommand::with_name("init").about("Initializes a new TUF repo"))
         .subcommand(SubCommand::with_name("list").about("Lists available targets"))
         .subcommand(SubCommand::with_name("update").about("Updates metadata from remotes"))
@@ -99,6 +107,11 @@
                 .help("The full (non-local) path of the target to verify")))
 }
 
+fn cmd_fetch(tuf: &Tuf, target: &str) -> Result<(), Error> {
+    tuf.fetch_target(target)
+        .map(|_| ())
+}
+
 fn cmd_init(local_path: &PathBuf) -> Result<(), Error> {
     Tuf::initialize(local_path)
 }
@@ -191,6 +204,17 @@
                                         &path.to_string_lossy(),
                                         "--path",
                                         temp.path().to_str().expect("path not utf-8"),
+                                        "fetch",
+                                        "targets/file.txt"])
+            .expect("parse error");
+        assert_eq!(run_main(matches), Ok(()));
+
+        let matches = parser()
+            .get_matches_from_safe(vec!["tuf",
+                                        "--file",
+                                        &path.to_string_lossy(),
+                                        "--path",
+                                        temp.path().to_str().expect("path not utf-8"),
                                         "verify",
                                         "targets/file.txt"])
             .expect("parse error");