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");