Skip to content

Commit

Permalink
Extract information
Browse files Browse the repository at this point in the history
Closes #5
  • Loading branch information
bvssvni committed Aug 16, 2015
1 parent 2f330d9 commit ecca896
Show file tree
Hide file tree
Showing 6 changed files with 390 additions and 45 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ path = "src/main.rs"
[dependencies]
piston_meta = "0.12.1"
hyper = "0.6.9"
range = "0.1.1"
3 changes: 2 additions & 1 deletion assets/cargo-toml/syntax.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
@"dependency_list_item""dependency"
})]
4 "dependencies" [l({@"dependency""dependency" @"dependency_list" ..."\n"?})]
5 "document" [w? @"package""package" w? @"dependencies""dependencies" ...""?]
5 "package_node" [@"package" w? @"dependencies"]
5 "document" [w? @"package_node""package" ...""?]
61 changes: 61 additions & 0 deletions assets/dependencies/test2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"pistoncore-input": {
"version": "0.5.0",
"dependencies": {
"rustc-serialize": {
"version": "0.3.15"
},
"bitflags": {
"version": "0.3.2"
},
"piston-viewport": {
"version": "0.1.0"
}
}
},
"pistoncore-window": {
"version": "0.9.0",
"dependencies": {
"pistoncore-input": {
"version": "0.5.0"
},
"libc": {
"version": "0.1"
},
"shader_version": {
"version": "0.2.0"
}
}
},
"pistoncore-event_loop": {
"version": "0.10.0",
"dependencies": {
"pistoncore-window": {
"version": "0.9.0"
},
"pistoncore-input": {
"version": "0.5.0"
},
"clock_ticks": {
"version": "0.0.6"
},
"piston-viewport": {
"version": "0.1.0"
}
}
},
"piston": {
"version": "0.10.0",
"dependencies": {
"pistoncore-input": {
"version": "0.5.0"
},
"pistoncore-window": {
"version": "0.9.0"
},
"pistoncore-event_loop": {
"version": "0.10.0"
}
}
}
}
2 changes: 1 addition & 1 deletion assets/extract/syntax.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
1 "library" [t!"package" w? ":" w? "{" w? s?([w? "," w?]){{
["\"url\"" w? ":" w? t!"url"]
["\"override-version\"" w? ":" w? t!"version"]
["\"override-version\"" w? ":" w? t!"override_version"]
}} w? "}"]
0 "document" [w? "{" w? s?([w? "," w?]){[@"library""library" w?]} "}" w?]
311 changes: 311 additions & 0 deletions src/extract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
//! Extract dependency information from extract info.

use piston_meta::MetaData;
use range::Range;
use std::rc::Rc;

/// Stores extract information.
pub struct Extract {
/// The package name.
pub package: Rc<String>,
/// The url of the Cargo.toml.
pub url: Rc<String>,
/// Whether to override the library version to simulate breaking change.
pub override_version: Option<Rc<String>>,
}

impl Extract {
/// Converts from meta data.
pub fn from_meta_data(
mut data: &[(Range, MetaData)],
mut offset: usize,
ignored: &mut Vec<Range>
) -> Result<(Range, Extract), ()> {
use piston_meta::bootstrap::*;

let start_offset = offset;
let node = "library";
let start_range = try!(start_node(node, data, offset));
update(start_range, &mut data, &mut offset);

let mut package: Option<Rc<String>> = None;
let mut url: Option<Rc<String>> = None;
let mut override_version: Option<Rc<String>> = None;
loop {
if let Ok(range) = end_node(node, data, offset) {
update(range, &mut data, &mut offset);
break;
} else if let Ok((range, val)) = meta_string("package", data, offset) {
update(range, &mut data, &mut offset);
package = Some(val);
} else if let Ok((range, val)) = meta_string("url", data, offset) {
update(range, &mut data, &mut offset);
url = Some(val);
} else if let Ok((range, val)) = meta_string("override_version", data, offset) {
update(range, &mut data, &mut offset);
override_version = Some(val);
} else {
let range = ignore(data, offset);
update(range, &mut data, &mut offset);
ignored.push(range);
}
}

let package = try!(package.ok_or(()));
let url = try!(url.ok_or(()));
Ok((Range::new(start_offset, offset - start_offset), Extract {
package: package,
url: url,
override_version: override_version,
}))
}
}

/// Stores package information.
pub struct Package {
/// The package name.
pub name: Rc<String>,
/// The version.
pub version: Rc<String>,
/// Dependencies.
pub dependencies: Vec<Dependency>,
}

impl Package {
/// Converts from meta data.
pub fn from_meta_data(
mut data: &[(Range, MetaData)],
mut offset: usize,
ignored: &mut Vec<Range>
) -> Result<(Range, Package), ()> {
use piston_meta::bootstrap::*;

let start_offset = offset;
let node = "package";
let start_range = try!(start_node(node, data, offset));
update(start_range, &mut data, &mut offset);

let mut name: Option<Rc<String>> = None;
let mut version: Option<Rc<String>> = None;
let mut dependencies = vec![];
loop {
if let Ok(range) = end_node(node, data, offset) {
update(range, &mut data, &mut offset);
break;
} else if let Ok((range, val)) = meta_string("name", data, offset) {
update(range, &mut data, &mut offset);
name = Some(val);
} else if let Ok((range, val)) = meta_string("version", data, offset) {
update(range, &mut data, &mut offset);
version = Some(val);
} else if let Ok((range, dependency)) = Dependency::from_meta_data(data, offset, ignored) {
update(range, &mut data, &mut offset);
dependencies.push(dependency);
} else {
let range = ignore(data, offset);
update(range, &mut data, &mut offset);
ignored.push(range);
}
}

let name = try!(name.ok_or(()));
let version = try!(version.ok_or(()));
Ok((Range::new(start_offset, offset - start_offset), Package {
name: name,
version: version,
dependencies: dependencies,
}))
}
}

/// Stores dependency information.
pub struct Dependency {
/// The package name.
pub name: Rc<String>,
/// The semver version of the library.
pub version: Rc<String>,
}

impl Dependency {
/// Converts from meta data.
pub fn from_meta_data(
mut data: &[(Range, MetaData)],
mut offset: usize,
ignored: &mut Vec<Range>
) -> Result<(Range, Dependency), ()> {
use piston_meta::bootstrap::*;

let start_offset = offset;
let node = "dependency";
let start_range = try!(start_node(node, data, offset));
update(start_range, &mut data, &mut offset);

let mut name: Option<Rc<String>> = None;
let mut version: Option<Rc<String>> = None;
loop {
if let Ok(range) = end_node(node, data, offset) {
update(range, &mut data, &mut offset);
break;
} else if let Ok((range, val)) = meta_string("name", data, offset) {
update(range, &mut data, &mut offset);
name = Some(val);
} else if let Ok((range, val)) = meta_string("version", data, offset) {
update(range, &mut data, &mut offset);
version = Some(val);
} else {
let range = ignore(data, offset);
update(range, &mut data, &mut offset);
ignored.push(range);
}
}

let name = try!(name.ok_or(()));
let version = try!(version.ok_or(()));
Ok((Range::new(start_offset, offset - start_offset), Dependency {
name: name,
version: version
}))
}
}

/// Loads a text file from url.
pub fn load_text_file_from_url(url: &str) -> Result<String, String> {
use hyper::client::Client;
use hyper::{Url};
use hyper::status::StatusCode;
use std::io::Read;

let url_address = try!(Url::parse(url)
.map_err(|e| format!("Error parsing url: {}", e)));
let client = Client::new();
let request = client.get(url_address);
let mut response = try!(request.send()
.map_err(|e| format!("Error fetching file over http {}: {}",
url, e.to_string())));
if response.status == StatusCode::Ok {
let mut data = String::new();
try!(response.read_to_string(&mut data)
.map_err(|e| format!("Error fetching file over http {}: {}",
url, e.to_string())));
Ok(data)
} else {
Err(format!("Error fetching file over http {}: {}",
url, response.status))
}
}

/// Converts meta data into extract info.
pub fn convert_extract_info(
mut data: &[(Range, MetaData)],
ignored: &mut Vec<Range>
) -> Result<Vec<Extract>, ()> {
use piston_meta::bootstrap::*;

let mut list = vec![];
let mut offset = 0;
loop {
if let Ok((range, extract)) = Extract::from_meta_data(data, offset, ignored) {
update(range, &mut data, &mut offset);
list.push(extract);
} else if offset < data.len() {
return Err(());
} else {
break;
}
}
Ok(list)
}

/// Converts meta data into Cargo.toml information.
pub fn convert_cargo_toml(
data: &[(Range, MetaData)],
ignored: &mut Vec<Range>
) -> Result<Package, ()> {
let offset = 0;
let (_, package) = try!(Package::from_meta_data(data, offset, ignored));
Ok((package))
}

/// Extracts dependency info.
pub fn extract_dependency_info_from(extract_info: &str) -> Result<String, String> {
use piston_meta::*;
use std::io::Write;

let extract_meta_syntax = include_str!("../assets/extract/syntax.txt");
let extract_meta_rules = stderr_unwrap(extract_meta_syntax,
syntax(extract_meta_syntax));
let extract_data = stderr_unwrap(extract_info,
parse(&extract_meta_rules, extract_info));

let mut ignored = vec![];
let list = try!(convert_extract_info(&extract_data, &mut ignored)
.map_err(|_| String::from("Could not convert extract data")));

// Stores package and dependency information extracted from Cargo.toml.
let mut package_data = vec![];

// Extract information.
let cargo_toml_syntax = include_str!("../assets/cargo-toml/syntax.txt");
let cargo_toml_rules = stderr_unwrap(cargo_toml_syntax,
syntax(cargo_toml_syntax));
for extract in &list {
let config = try!(load_text_file_from_url(&extract.url));
let cargo_toml_data = stderr_unwrap(&config,
parse(&cargo_toml_rules, &config));

let mut ignored = vec![];
let package = try!(convert_cargo_toml(
&cargo_toml_data, &mut ignored)
.map_err(|_| format!("Could not convert Cargo.toml data for url `{}`", &extract.url)));
package_data.push(package);
}

let mut res: Vec<u8> = vec![];
writeln!(res, "{{").unwrap();
let n0 = package_data.len();
for (i0, package) in package_data.iter().enumerate() {
// Package name.
write!(res, " ").unwrap();
json::write_string(&mut res, &package.name).unwrap();
writeln!(res, ": {{").unwrap();

// Version.
write!(res, " \"version\": ").unwrap();
json::write_string(&mut res, &package.version).unwrap();
writeln!(res, ",").unwrap();

// Dependencies.
writeln!(res, " \"dependencies\": {{").unwrap();
let n1 = package.dependencies.len();
for (i1, dependency) in package.dependencies.iter().enumerate() {
write!(res, " ").unwrap();
json::write_string(&mut res, &dependency.name).unwrap();
writeln!(res, ": {{").unwrap();
// Version.
write!(res, " \"version\": ").unwrap();
json::write_string(&mut res, &dependency.version).unwrap();
writeln!(res, "").unwrap();
write!(res, " }}").unwrap();
if i1 + 1 != n1 {
writeln!(res, ",").unwrap();
} else {
writeln!(res, "").unwrap();
}
}
writeln!(res, " }}").unwrap();

// End package.
write!(res, " }}").unwrap();
if i0 + 1 != n0 {
writeln!(res, ",").unwrap();
} else {
writeln!(res, "").unwrap();
}
}
writeln!(res, "}}").unwrap();

let res = try!(String::from_utf8(res)
.map_err(|e| format!("UTF8 error: {}", e)));

Ok(res)
}
Loading

0 comments on commit ecca896

Please sign in to comment.