Skip to content

Instantly share code, notes, and snippets.

@globin
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save globin/fd6f8ba3f636520a5c93 to your computer and use it in GitHub Desktop.
Save globin/fd6f8ba3f636520a5c93 to your computer and use it in GitHub Desktop.
Cloneable Trait Object
extern crate http;
extern crate url;
extern crate semver;
extern crate serialize;
use std::os;
use std::str;
use std::cmp::max;
use std::io::File;
use std::sync::Future;
use std::collections::TreeMap;
use semver::{Version, VersionReq};
use http::client::RequestWriter;
use http::method::Get;
use serialize::json::{mod, Json};
use url::Url;
trait Dependency : Clone {
fn to_check(dependency_file_contents: &str, Option<Self>) -> Vec<Box<Dependency>>;
fn name(&self) -> &String;
fn version_req(&self) -> &VersionReq;
fn registry_version(&self) -> Option<Version>;
fn clone_dep(&self) -> Box<Dependency> {
box self.clone() as Box<Dependency>
}
}
#[deriving(Show, Clone)]
struct ComposerDependency {
name: String,
version_req: VersionReq
}
impl ComposerDependency {
fn packagist_version_from_json(&self, json: &Json) -> Option<Version> {
json.find_path(&[&"package".to_string(), &"versions".to_string()])
.and_then(|versions_json| versions_json.as_object())
.and_then(|versions_map| {
versions_map.keys().map(
|version_string| Version::parse(version_string.as_slice()).ok()
).fold(None, |a, b| {
match (a, b) {
(None, b@_) => b,
(a@Some(_), None) => a,
(Some(a), Some(b)) => Some(max(a, b))
}
})
})
}
fn packagist_url(&self) -> Url {
Url::parse(
format!("https://packagist.org/packages/{}.json", self.name).as_slice()
).unwrap()
}
}
impl Dependency for ComposerDependency {
fn to_check(composer_json_contents: &str, _: Option<ComposerDependency>) -> Vec<Box<Dependency>> {
let composer_json = json::from_str(composer_json_contents).unwrap();
let default_map = TreeMap::new();
let requires = composer_json.find(&"require".to_string()).map(
|r| r.as_object().unwrap()
).unwrap_or(&default_map);
let require_devs = composer_json.find(&"require-dev".to_string()).map(
|r| r.as_object().unwrap()
).unwrap_or(&default_map);
requires.iter().chain(require_devs.iter()).map(
|(k, v)| {
match v {
&json::String(ref version) => Some((k.clone(), version.clone())),
_ => None
}
}
).filter_map(|opt| match opt {
Some((ref name, ref version)) => {
match VersionReq::parse(version.as_slice()) {
Ok(vr) => Some(box ComposerDependency { name: name.clone(), version_req: vr } as Box<Dependency>),
Err(err) => {
println!("{} ignored (could not parse {}: {})", name, version, err);
None
}
}
},
_ => None
}).collect()
}
fn name(&self) -> &String {
&self.name
}
fn version_req(&self) -> &VersionReq {
&self.version_req
}
fn registry_version(&self) -> Option<Version> {
let request: RequestWriter = RequestWriter::new(Get, self.packagist_url()).unwrap();
let mut response = match request.read_response() {
Ok(response) => response,
Err((_request, error)) => fail!(":-( {}", error),
};
let response_string = response.read_to_string().unwrap();
match json::from_str(response_string.as_slice()) {
Ok(version_struct) => self.packagist_version_from_json(&version_struct),
Err(_) => None
}
}
}
fn main() {
let args = os::args();
let file_raw_bytes = match File::open(&Path::new(args[1].as_slice())).read_to_end() {
Ok(bytes) => bytes,
Err(err) => {
println!("{}", err);
return;
}
};
let dependency_file_contents = str::from_utf8(file_raw_bytes.as_slice()).unwrap();
let dependencies_to_check = Dependency::to_check(dependency_file_contents, None::<ComposerDependency>);
let mut version_ftrs: Vec<Future<(&String, Option<Version>)>> = dependencies_to_check.iter().map(|d| {
let dependency = d.clone_dep();
let name = d.name();
Future::spawn(proc() {;
(name, dependency.registry_version())
})
}).collect();
let versions: Vec<(&String, Version)> = version_ftrs.iter_mut().map(
|ftr| ftr.get()
).filter_map(
|tpl| match tpl {
(name, Some(version)) => Some((name, version)),
(_, None) => None
}
).collect();
for dependency in dependencies_to_check.iter() {
for &(name, ref version) in versions.iter() {
if dependency.name() == name {
if !dependency.version_req().matches(version) {
println!("{}: {} doesn't match {}", dependency.name(), version, dependency.version_req())
} else {
println!("{}: {} matches {}", dependency.name(), version, dependency.version_req())
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment