Isolate toml code and split up concerns

This commit is contained in:
Yehuda Katz + Carl Lerche 2014-06-10 15:46:07 -07:00 committed by Tim Carey-Smith
parent 9a6be788d9
commit bbbf2dead8
9 changed files with 198 additions and 27 deletions

@ -1 +1 @@
Subproject commit 2f9e556c4ec1aa492884c951745699552494264b
Subproject commit 3eaa0ee4c81aa49bdcc98cad448ef3a6386d62af

View File

@ -37,5 +37,5 @@ fn execute(options: Options) -> CLIResult<Option<()>> {
CLIError::new("Could not find Cargo.toml in this directory or any parent directory", Some(err), 102)))
};
ops::compile(root.as_str().unwrap().as_slice()).map(|_| None).to_cli(101)
ops::compile(&root).map(|_| None).to_cli(101)
}

View File

@ -21,6 +21,6 @@ fn main() {
}
fn execute(options: Options) -> CLIResult<Option<Package>> {
ops::read_manifest(options.manifest_path.as_slice()).map(|m| Some(m))
ops::read_package(&Path::new(options.manifest_path.as_slice())).map(|m| Some(m))
.map_err(|err| CLIError::new(err.get_desc(), Some(err.get_detail()), 1))
}

View File

@ -23,13 +23,12 @@ use sources::path::PathSource;
use ops;
use util::{other_error, CargoResult, Wrap};
// TODO: manifest_path should be Path
pub fn compile(manifest_path: &str) -> CargoResult<()> {
log!(4, "compile; manifest-path={}", manifest_path);
pub fn compile(manifest_path: &Path) -> CargoResult<()> {
log!(4, "compile; manifest-path={}", manifest_path.display());
let manifest = try!(ops::read_manifest(manifest_path));
let package = try!(ops::read_package(manifest_path));
debug!("loaded manifest; manifest={}", manifest);
debug!("loaded package; package={}", package);
let configs = try!(config::all_configs(os::getcwd()));
@ -46,7 +45,7 @@ pub fn compile(manifest_path: &str) -> CargoResult<()> {
let source = PathSource::new(paths);
let summaries = try!(source.list().wrap("unable to list packages from source"));
let resolved = try!(resolve(manifest.get_dependencies(), &summaries).wrap("unable to resolve dependencies"));
let resolved = try!(resolve(package.get_dependencies(), &summaries).wrap("unable to resolve dependencies"));
try!(source.download(resolved.as_slice()).wrap("unable to download packages"));
@ -54,7 +53,7 @@ pub fn compile(manifest_path: &str) -> CargoResult<()> {
let package_set = PackageSet::new(packages.as_slice());
try!(ops::compile_packages(&manifest, &package_set));
try!(ops::compile_packages(&package, &package_set));
Ok(())
}

View File

@ -1,16 +1,16 @@
use toml;
use core::Package;
use util::toml::toml_to_package;
use util::{CargoResult,human_error,toml_error};
use std::io::File;
use util;
use core::{Package,Manifest};
use util::{CargoResult,io_error};
pub fn read_manifest(path: &str) -> CargoResult<Package> {
let root = try!(parse_from_file(path));
toml_to_package(root, &Path::new(path))
pub fn read_manifest(contents: &[u8]) -> CargoResult<Manifest> {
util::toml::to_manifest(contents)
}
fn parse_from_file(path: &str) -> CargoResult<toml::Value> {
toml::parse_from_file(path.clone()).map_err(|err| {
let err = toml_error("Couldn't parse Toml", err);
human_error("Cargo.toml is not valid Toml".to_str(), format!("path={}", path), err)
})
pub fn read_package(path: &Path) -> CargoResult<Package> {
let mut file = try!(File::open(path).map_err(io_error));
let data = try!(file.read_to_end().map_err(io_error));
let manifest = try!(read_manifest(data.as_slice()));
Ok(Package::new(&manifest, &path.dir_path()))
}

View File

@ -1,5 +1,5 @@
pub use self::cargo_compile::compile;
pub use self::cargo_read_manifest::read_manifest;
pub use self::cargo_read_manifest::{read_manifest,read_package};
pub use self::cargo_rustc::compile_packages;
mod cargo_compile;

View File

@ -61,6 +61,6 @@ impl Source for GitSource {
}
fn read_manifest(path: &Path) -> CargoResult<Package> {
let joined = path.join("Cargo.toml");
ops::read_manifest(joined.as_str().unwrap())
let path = path.join("Cargo.toml");
ops::read_package(&path)
}

View File

@ -58,8 +58,8 @@ impl Source for PathSource {
}
fn read_manifest(path: &Path) -> CargoResult<Package> {
let joined = path.join("Cargo.toml");
ops::read_manifest(joined.as_str().unwrap())
let path = path.join("Cargo.toml");
ops::read_package(&path)
}
fn display(paths: &[Path]) -> Vec<String> {

172
src/cargo/util/toml.rs Normal file
View File

@ -0,0 +1,172 @@
use toml;
use std::collections::HashMap;
use serialize::Decodable;
use core::{Summary,Manifest,Target,Project,Dependency};
use util::{CargoResult,Require,simple_human,toml_error};
pub fn to_manifest(contents: &[u8]) -> CargoResult<Manifest> {
let root = try!(toml::parse_from_bytes(contents).map_err(|_|
simple_human("Cargo.toml is not valid Toml")));
let toml = try!(toml_to_manifest(root).map_err(|_|
simple_human("Cargo.toml is not a valid Cargo manifest")));
toml.to_manifest()
}
fn toml_to_manifest(root: toml::Value) -> CargoResult<TomlManifest> {
fn decode<T: Decodable<toml::Decoder,toml::Error>>(root: &toml::Value, path: &str) -> Result<T, toml::Error> {
let root = match root.lookup(path) {
Some(val) => val,
None => return Err(toml::ParseError)
};
toml::from_toml(root.clone())
}
let project = try!(decode(&root, "project").map_err(|e| toml_error("ZOMG", e)));
let lib = decode(&root, "lib").ok();
let bin = decode(&root, "bin").ok();
let deps = root.lookup("dependencies");
let deps = match deps {
Some(deps) => {
let table = try!(deps.get_table().require(simple_human("dependencies must be a table"))).clone();
let mut deps: HashMap<String, TomlDependency> = HashMap::new();
for (k, v) in table.iter() {
match v {
&toml::String(ref string) => { deps.insert(k.clone(), SimpleDep(string.clone())); },
&toml::Table(ref table) => {
let mut details = HashMap::<String, String>::new();
for (k, v) in table.iter() {
let v = try!(v.get_str()
.require(simple_human("dependency values must be string")));
details.insert(k.clone(), v.clone());
}
let version = try!(details.find_equiv(&"version")
.require(simple_human("dependencies must include a version"))).clone();
deps.insert(k.clone(), DetailedDep(DetailedTomlDependency {
version: version,
other: details
}));
},
_ => ()
}
}
Some(deps)
},
None => None
};
Ok(TomlManifest { project: box project, lib: lib, bin: bin, dependencies: deps })
}
type TomlLibTarget = TomlTarget;
type TomlBinTarget = TomlTarget;
/*
* TODO: Make all struct fields private
*/
#[deriving(Encodable,PartialEq,Clone,Show)]
pub enum TomlDependency {
SimpleDep(String),
DetailedDep(DetailedTomlDependency)
}
#[deriving(Encodable,PartialEq,Clone,Show)]
pub struct DetailedTomlDependency {
version: String,
other: HashMap<String, String>
}
#[deriving(Encodable,PartialEq,Clone)]
pub struct TomlManifest {
project: Box<Project>,
lib: Option<Vec<TomlLibTarget>>,
bin: Option<Vec<TomlBinTarget>>,
dependencies: Option<HashMap<String, TomlDependency>>,
}
impl TomlManifest {
pub fn to_manifest(&self) -> CargoResult<Manifest> {
// Get targets
let targets = normalize(self.lib.as_ref().map(|l| l.as_slice()), self.bin.as_ref().map(|b| b.as_slice()));
if targets.is_empty() {
debug!("manifest has no build targets; project={}", self.project);
}
let mut deps = Vec::new();
// Collect the deps
match self.dependencies {
Some(ref dependencies) => {
for (n, v) in dependencies.iter() {
let version = match *v {
SimpleDep(ref string) => string.clone(),
DetailedDep(ref details) => details.version.clone()
};
deps.push(try!(Dependency::parse(n.as_slice(), version.as_slice())))
}
}
None => ()
}
Ok(Manifest::new(
&Summary::new(&self.project.to_name_ver(), deps.as_slice()),
targets.as_slice(),
&Path::new("target")))
}
}
#[deriving(Decodable,Encodable,PartialEq,Clone,Show)]
struct TomlTarget {
name: String,
path: Option<String>
}
fn normalize(lib: Option<&[TomlLibTarget]>, bin: Option<&[TomlBinTarget]>) -> Vec<Target> {
log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);
fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget]) {
let l = &libs[0];
let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
dst.push(Target::lib_target(l.name.as_slice(), &Path::new(path)));
}
fn bin_targets(dst: &mut Vec<Target>, bins: &[TomlBinTarget], default: |&TomlBinTarget| -> String) {
for bin in bins.iter() {
let path = bin.path.clone().unwrap_or_else(|| default(bin));
dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path)));
}
}
let mut ret = Vec::new();
match (lib, bin) {
(Some(ref libs), Some(ref bins)) => {
lib_targets(&mut ret, libs.as_slice());
bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name));
},
(Some(ref libs), None) => {
lib_targets(&mut ret, libs.as_slice());
},
(None, Some(ref bins)) => {
bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/{}.rs", bin.name));
},
(None, None) => ()
}
ret
}