<commit_before>extern crate rustless;
extern crate hyper;
extern crate iron;
extern crate valico;
extern crate crypto;
#[macro_use]
extern crate serde_json;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::coll::options::FindOptions;
use bson::
{
    Bson,
    Document
};

use std::fs;
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use std::thread;
use std::time::
{
    SystemTime,
    UNIX_EPOCH
};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use valico::json_dsl;
use rustless::server::status::StatusCode;
use rustless::
{
    Application,
    Api,
    Nesting,
    Versioning,
};
use hyper::header::
{
    ContentDisposition,
    DispositionType,
    DispositionParam,
    Charset
};

use serde_json::value::Value;

const GBS_DIR:&str = "/var/lib/gbs";

fn check(path:&str) -> Option<&str>
{
    let p = Path::new(path).file_name()?.to_str()?;
    if p == path
    {
        return Some(path);
    }
    else
    {
        return None;
    }
}

fn is_atom(repository:&str, category:&str, package:&str, version:&str) -> Option<()>
{

    let r = check(repository)?;
    let c = check(category)?;
    let p = check(package)?;
    let v = check(version)?;

    if Path::new(&format!("{}/repos/{}/{}/{}/{}-{}.ebuild", GBS_DIR, r, c, p, p, v)).is_file()
    {
        return Some(());
    }
    else
    {
        return None;
    }
}

fn is_build_request(repository:&str, category:&str, package:&str, version:&str, id:&str) -> Option<()>
{

    let r = check(repository)?;
    let c = check(category)?;
    let p = check(package)?;
    let v = check(version)?;
    let i = check(id)?;

    if Path::new(&format!("{}/packages/{}/{}/{}/{}/{}", GBS_DIR, r, c, p, v, i)).is_dir()
    {
        return Some(());
    }
    else
    {
        return None;
    }
}

fn build_id(repository:&str, category:&str, package:&str, version:&str, uses:&[(String, bool)]) -> String
{
    let mut hasher = Sha3::sha3_256();
    hasher.input_str(&format!("{}{}{}{}", repository, category, package, version));

    for &(ref key, ref value) in uses.iter()
    {
        hasher.input_str(&format!("{}{} ", match *value {true => "", false => "-"}, key));
    }
    return hasher.result_str();
}

#[test]
fn test_is_atom()
{
    assert_eq!(false, is_atom("test","test","test","test").is_some());
    assert_eq!(false, is_atom("test/.","test/../.","test","test").is_some());
    assert_eq!(false, is_atom("gentoo/.","app-editors","vim","8.0.1298").is_some());
    assert_eq!(false, is_atom("gentoo","app-editors","vim","8").is_some());
    assert_eq!(true, is_atom("gentoo","app-editors","vim","8.0.1298").is_some());
}

fn main()
{
    let client = Client::connect("localhost", 27017)
        .expect("Failed to initialize standalone client.");
    let coll = Arc::new(client.db("gbs").collection("builds"));

    let api = Api::build(|api|
    {
        api.prefix("api");
        api.version("1", Versioning::Path);
        api.namespace("atoms", |atoms_ns|
        {
            atoms_ns.get("", |endpoint|
            {
                let coll = coll.clone();
                endpoint.handle(move |client, params|
                {
                    let mut op = FindOptions::new();
                    op.limit = Some(50);
                    op.sort = Some(doc!{"date": -1});
                    let a = coll.find(None, Some(op)).unwrap();
                    let c: Vec<Value> = a.map(|x| Bson::Document(x.unwrap()).clone().into()).collect();

                    return client.text(Value::Array(c).to_string());
                })
            });
        });

        api.namespace("atoms/:repositories/:categories/:packages/:versions", |atoms_ns|
        {
            atoms_ns.params(|params|
            {
                params.req_typed("repositories", json_dsl::string());
                params.req_typed("categories", json_dsl::string());
                params.req_typed("packages", json_dsl::string());
                params.req_typed("versions", json_dsl::string());
            });
            atoms_ns.get("builds/:id/status", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                let coll = coll.clone();
                endpoint.handle(move |mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    let mut op = FindOptions::new();
                    op.projection = Some(doc!{"status" => 1, "_id" => 0});
                    let c = coll.find_one(Some(doc!{"repository" => &repository, "category" => &category, "package" => &package, "version" => &version, "id" => &id}), Some(op)).unwrap().unwrap();
                    return client.text(c.to_string());
                })
            });
            atoms_ns.get("builds/:id/log", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        let s = format!("{}/packages/{}/{}/{}/{}/{}/log", GBS_DIR, repository, category, package, version, id);
                        let path = Path::new(&s);
                        if path.is_file()
                        {
                            let f = File::open(&s).unwrap();
                            let mut reader = BufReader::new(f);
                            let mut buf = String::new();
                            let _ = reader.read_to_string(&mut buf);
                            return client.text(buf);
                        }
                    }
                    client.set_status(StatusCode::NotFound);
                    return client.empty();
                })
            });
            atoms_ns.get("builds/:id", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        let s = format!("{}/packages/{}/{}/{}/{}/{}/{3}-{4}.tbz2", GBS_DIR, repository, category, package, version, id);
                        let path = Path::new(&s);
                        if path.is_file()
                        {
                            client.set_header(ContentDisposition
                            {
                              disposition: DispositionType::Attachment,
                              parameters: vec![DispositionParam::Filename(
                                Charset::Us_Ascii,
                                None,
                                format!("{}-{}.tbz2", package, version).into_bytes()
                            )]});
                            return client.file(path);
                        }
                    }
                    client.set_status(StatusCode::NotFound);
                    return client.empty();
                })
            });
            atoms_ns.get("builds", |endpoint|
            {
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let use_flag = params.find("use").unwrap();

                    let mut uses = String::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uses.push_str(&format!("{}{} ", match value.as_bool().unwrap(){true => "", false => "-"}, key));
                    }

                    let mut uu :Vec<(String, bool)> = Vec::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uu.push((key.clone(), value.as_bool().unwrap()));
                    }

                    let id = build_id(&repository, &category, &package, &version, &uu);

                    println!("GET {}/{}/{}/{}", repository, category, package, version);
                    println!("USE=\"{}\"", uses);
                    println!("id:{}", id);

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        println!("Available!");
                        println!("");
                        let url = format!("{}/{}/{}/{}/builds/{}", repository, category, package, version, id);
                        return client.text(url);
                    }
                    else
                    {
                        println!("N/A");
                        println!("");
                        client.set_status(StatusCode::NotFound);
                        return client.empty();
                    }
                })
            });
            atoms_ns.post("builds", |endpoint|
            {
                let coll = coll.clone();
                endpoint.handle(move |mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let use_flag = params.find("use").unwrap();

                    let mut uses = String::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uses.push_str(&format!("{}{} ", match value.as_bool().unwrap(){true => "", false => "-"}, key));
                    }
                    let mut uu :Vec<(String, bool)> = Vec::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uu.push((key.clone(), value.as_bool().unwrap()));
                    }
                    let id = build_id(&repository, &category, &package, &version, &uu);
                    println!("POST {}/{}/{}/{}", repository, category, package, version);
                    println!("USE=\"{}\"", uses);
                    println!("id:{}", id);
                    println!("");

                    let url = format!("{}/{}/{}/{}/builds/{}", repository, category, package, version, id);

                    if is_atom(&repository, &category, &package, &version).is_some()
                    {
                        if !is_build_request(&repository, &category, &package, &version, &id).is_some()
                        {
                            {
                                let mut uses = Document::new();
                                for (key, value) in use_flag.as_object().unwrap().iter()
                                {
                                    uses.insert(key.clone(), Bson::Boolean(value.as_bool().unwrap().clone()));
                                }
                                let s = SystemTime::now();
                                let doc = doc!
                                {
                                    "date" => s.duration_since(UNIX_EPOCH).unwrap().as_secs(),
                                    "id" => id.clone(),
                                    "repository" => repository.clone(),
                                    "category" => category.clone(),
                                    "package" => package.clone(),
                                    "version" => version.clone(),
                                    "use" => uses,
                                    "status" => "accept"
                                };
                                coll.insert_one(doc.clone(), None).ok().expect("Failed to insert document.");
                            }
                            thread::spawn(move ||
                            {
                                fs::create_dir_all(format!("{}/packages/{}/{}/{}/{}/{}", GBS_DIR, repository, category, package, version, id)).unwrap();
                                let b = Command::new("docker")
                                .arg("run")
                                .arg("--rm")
                                .arg("-v")
                                .arg(format!("{}/distfiles:/usr/portage/distfiles", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/repos:/var/db/repos:ro", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/ccache:/mnt/ccache", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/packages/{}/{}/{}/{}/{}:/mnt/package", GBS_DIR, repository, category, package, version, id))
                                .arg("-v")
                                .arg(format!("{}/logs/{}/{}/{}/{}/{}:/mnt/log", GBS_DIR, repository, category, package, version, id))
                                .arg("--cap-add=SYS_PTRACE")
                                .arg("-idt")
                                .arg("--name")
                                .arg(format!("{}_{}_{}_{}_{}", repository, category, package, version, id))
                                .arg("gentoo:gbs")
                                .arg("/usr/bin/build_script.sh")
                                .arg(repository)
                                .arg(category)
                                .arg(package)
                                .arg(version)
                                .arg(id)
                                .arg(uses)
                                .output().unwrap();
                                println!("{}\n", String::from_utf8_lossy(&b.stdout));
                                println!("{}\n", String::from_utf8_lossy(&b.stderr));
                            });
                        }
                        return client.text(url);
                    }
                    else
                    {
                        client.set_status(StatusCode::NotFound);
                        return client.empty();
                    }
                })
            });
        });
    });

    let app = Application::new(api);

    iron::Iron::new(app).http("0.0.0.0:4000").unwrap();
}
<commit_msg>cosme<commit_after>extern crate rustless;
extern crate hyper;
extern crate iron;
extern crate valico;
extern crate crypto;
#[macro_use]
extern crate serde_json;

#[macro_use(bson, doc)]
extern crate bson;
extern crate mongodb;

use mongodb::{Client, ThreadedClient};
use mongodb::db::ThreadedDatabase;
use mongodb::coll::options::FindOptions;
use bson::
{
    Bson,
    Document
};

use std::fs;
use std::fs::File;
use std::io::BufReader;
use std::io::Read;
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use std::thread;
use std::time::
{
    SystemTime,
    UNIX_EPOCH
};
use crypto::digest::Digest;
use crypto::sha3::Sha3;
use valico::json_dsl;
use rustless::server::status::StatusCode;
use rustless::
{
    Application,
    Api,
    Nesting,
    Versioning,
};
use hyper::header::
{
    ContentDisposition,
    DispositionType,
    DispositionParam,
    Charset
};

use serde_json::value::Value;

const GBS_DIR:&str = "/var/lib/gbs";

fn check(path:&str) -> Option<&str>
{
    let p = Path::new(path).file_name()?.to_str()?;
    if p == path
    {
        return Some(path);
    }
    else
    {
        return None;
    }
}

fn is_atom(repository:&str, category:&str, package:&str, version:&str) -> Option<()>
{
    let r = check(repository)?;
    let c = check(category)?;
    let p = check(package)?;
    let v = check(version)?;

    if Path::new(&format!("{}/repos/{}/{}/{}/{}-{}.ebuild", GBS_DIR, r, c, p, p, v)).is_file()
    {
        return Some(());
    }
    else
    {
        return None;
    }
}

fn is_build_request(repository:&str, category:&str, package:&str, version:&str, id:&str) -> Option<()>
{
    let r = check(repository)?;
    let c = check(category)?;
    let p = check(package)?;
    let v = check(version)?;
    let i = check(id)?;

    if Path::new(&format!("{}/packages/{}/{}/{}/{}/{}", GBS_DIR, r, c, p, v, i)).is_dir()
    {
        return Some(());
    }
    else
    {
        return None;
    }
}

fn build_id(repository:&str, category:&str, package:&str, version:&str, uses:&[(String, bool)]) -> String
{
    let mut hasher = Sha3::sha3_256();
    hasher.input_str(&format!("{}{}{}{}", repository, category, package, version));

    for &(ref key, ref value) in uses.iter()
    {
        hasher.input_str(&format!("{}{} ", match *value {true => "", false => "-"}, key));
    }
    return hasher.result_str();
}

#[test]
fn test_is_atom()
{
    assert_eq!(false, is_atom("test","test","test","test").is_some());
    assert_eq!(false, is_atom("test/.","test/../.","test","test").is_some());
    assert_eq!(false, is_atom("gentoo/.","app-editors","vim","8.0.1298").is_some());
    assert_eq!(false, is_atom("gentoo","app-editors","vim","8").is_some());
    assert_eq!(true, is_atom("gentoo","app-editors","vim","8.0.1298").is_some());
}

fn main()
{
    let client = Client::connect("localhost", 27017)
        .expect("Failed to initialize standalone client.");
    let coll = Arc::new(client.db("gbs").collection("builds"));

    let api = Api::build(|api|
    {
        api.prefix("api");
        api.version("1", Versioning::Path);
        api.namespace("atoms", |atoms_ns|
        {
            atoms_ns.get("", |endpoint|
            {
                let coll = coll.clone();
                endpoint.handle(move |client, params|
                {
                    let mut op = FindOptions::new();
                    op.limit = Some(50);
                    op.sort = Some(doc!{"date": -1});
                    let a = coll.find(None, Some(op)).unwrap();
                    let c: Vec<Value> = a.map(|x| Bson::Document(x.unwrap()).clone().into()).collect();

                    return client.text(Value::Array(c).to_string());
                })
            });
        });

        api.namespace("atoms/:repositories/:categories/:packages/:versions", |atoms_ns|
        {
            atoms_ns.params(|params|
            {
                params.req_typed("repositories", json_dsl::string());
                params.req_typed("categories", json_dsl::string());
                params.req_typed("packages", json_dsl::string());
                params.req_typed("versions", json_dsl::string());
            });
            atoms_ns.get("builds/:id/status", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                let coll = coll.clone();
                endpoint.handle(move |mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    let mut op = FindOptions::new();
                    op.projection = Some(doc!{"status" => 1, "_id" => 0});
                    let c = coll.find_one(Some(doc!{"repository" => &repository, "category" => &category, "package" => &package, "version" => &version, "id" => &id}), Some(op)).unwrap().unwrap();
                    return client.text(c.to_string());
                })
            });
            atoms_ns.get("builds/:id/log", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        let s = format!("{}/packages/{}/{}/{}/{}/{}/log", GBS_DIR, repository, category, package, version, id);
                        let path = Path::new(&s);
                        if path.is_file()
                        {
                            let f = File::open(&s).unwrap();
                            let mut reader = BufReader::new(f);
                            let mut buf = String::new();
                            let _ = reader.read_to_string(&mut buf);
                            return client.text(buf);
                        }
                    }
                    client.set_status(StatusCode::NotFound);
                    return client.empty();
                })
            });
            atoms_ns.get("builds/:id", |endpoint|
            {
                endpoint.params(|params|
                {
                    params.req_typed("id", json_dsl::string());
                });
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let id = params.find("id").unwrap().to_string().trim_matches('"').to_string();

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        let s = format!("{}/packages/{}/{}/{}/{}/{}/{3}-{4}.tbz2", GBS_DIR, repository, category, package, version, id);
                        let path = Path::new(&s);
                        if path.is_file()
                        {
                            client.set_header(ContentDisposition
                            {
                              disposition: DispositionType::Attachment,
                              parameters: vec![DispositionParam::Filename(
                                Charset::Us_Ascii,
                                None,
                                format!("{}-{}.tbz2", package, version).into_bytes()
                            )]});
                            return client.file(path);
                        }
                    }
                    client.set_status(StatusCode::NotFound);
                    return client.empty();
                })
            });
            atoms_ns.get("builds", |endpoint|
            {
                endpoint.handle(|mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let use_flag = params.find("use").unwrap();

                    let mut uses = String::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uses.push_str(&format!("{}{} ", match value.as_bool().unwrap(){true => "", false => "-"}, key));
                    }

                    let mut uu :Vec<(String, bool)> = Vec::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uu.push((key.clone(), value.as_bool().unwrap()));
                    }

                    let id = build_id(&repository, &category, &package, &version, &uu);

                    println!("GET {}/{}/{}/{}", repository, category, package, version);
                    println!("USE=\"{}\"", uses);
                    println!("id:{}", id);

                    if is_build_request(&repository, &category, &package, &version, &id).is_some()
                    {
                        println!("Available!");
                        println!("");
                        let url = format!("{}/{}/{}/{}/builds/{}", repository, category, package, version, id);
                        return client.text(url);
                    }
                    else
                    {
                        println!("N/A");
                        println!("");
                        client.set_status(StatusCode::NotFound);
                        return client.empty();
                    }
                })
            });
            atoms_ns.post("builds", |endpoint|
            {
                let coll = coll.clone();
                endpoint.handle(move |mut client, params|
                {
                    let repository = params.find("repositories").unwrap().to_string().trim_matches('"').to_string();
                    let category = params.find("categories").unwrap().to_string().trim_matches('"').to_string();
                    let package = params.find("packages").unwrap().to_string().trim_matches('"').to_string();
                    let version = params.find("versions").unwrap().to_string().trim_matches('"').to_string();
                    let use_flag = params.find("use").unwrap();

                    let mut uses = String::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uses.push_str(&format!("{}{} ", match value.as_bool().unwrap(){true => "", false => "-"}, key));
                    }
                    let mut uu :Vec<(String, bool)> = Vec::new();
                    for (key, value) in use_flag.as_object().unwrap().iter()
                    {
                        uu.push((key.clone(), value.as_bool().unwrap()));
                    }
                    let id = build_id(&repository, &category, &package, &version, &uu);
                    println!("POST {}/{}/{}/{}", repository, category, package, version);
                    println!("USE=\"{}\"", uses);
                    println!("id:{}", id);
                    println!("");

                    let url = format!("{}/{}/{}/{}/builds/{}", repository, category, package, version, id);

                    if is_atom(&repository, &category, &package, &version).is_some()
                    {
                        if !is_build_request(&repository, &category, &package, &version, &id).is_some()
                        {
                            {
                                let mut uses = Document::new();
                                for (key, value) in use_flag.as_object().unwrap().iter()
                                {
                                    uses.insert(key.clone(), Bson::Boolean(value.as_bool().unwrap().clone()));
                                }
                                let s = SystemTime::now();
                                let doc = doc!
                                {
                                    "date" => s.duration_since(UNIX_EPOCH).unwrap().as_secs(),
                                    "id" => id.clone(),
                                    "repository" => repository.clone(),
                                    "category" => category.clone(),
                                    "package" => package.clone(),
                                    "version" => version.clone(),
                                    "use" => uses,
                                    "status" => "accept"
                                };
                                coll.insert_one(doc.clone(), None).ok().expect("Failed to insert document.");
                            }
                            thread::spawn(move ||
                            {
                                fs::create_dir_all(format!("{}/packages/{}/{}/{}/{}/{}", GBS_DIR, repository, category, package, version, id)).unwrap();
                                let b = Command::new("docker")
                                .arg("run")
                                .arg("--rm")
                                .arg("-v")
                                .arg(format!("{}/distfiles:/usr/portage/distfiles", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/repos:/var/db/repos:ro", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/ccache:/mnt/ccache", GBS_DIR))
                                .arg("-v")
                                .arg(format!("{}/packages/{}/{}/{}/{}/{}:/mnt/package", GBS_DIR, repository, category, package, version, id))
                                .arg("-v")
                                .arg(format!("{}/logs/{}/{}/{}/{}/{}:/mnt/log", GBS_DIR, repository, category, package, version, id))
                                .arg("--cap-add=SYS_PTRACE")
                                .arg("-idt")
                                .arg("--name")
                                .arg(format!("{}_{}_{}_{}_{}", repository, category, package, version, id))
                                .arg("gentoo:gbs")
                                .arg("/usr/bin/build_script.sh")
                                .arg(repository)
                                .arg(category)
                                .arg(package)
                                .arg(version)
                                .arg(id)
                                .arg(uses)
                                .output().unwrap();
                                println!("{}\n", String::from_utf8_lossy(&b.stdout));
                                println!("{}\n", String::from_utf8_lossy(&b.stderr));
                            });
                        }
                        return client.text(url);
                    }
                    else
                    {
                        client.set_status(StatusCode::NotFound);
                        return client.empty();
                    }
                })
            });
        });
    });

    let app = Application::new(api);

    iron::Iron::new(app).http("0.0.0.0:4000").unwrap();
}
<|endoftext|>


<commit_before>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use cgmath::vector::{Vector3};
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct Vertex<T> {
  position: Vector3<T>,
}

impl<T: Clone> Clone for Vertex<T> {
  fn clone(&self) -> Vertex<T> {
    Vertex {
      position: self.position.clone(),
    }
  }
}

impl<T: Clone> Vertex<T> {
  fn new(v: &Vector3<T>) -> Vertex<T> {
    Vertex {
      position: v.clone(),
    }
  }
}

pub struct Triangle<T> {
  vertices: [Vertex<T>, ..3],
}

impl<T: Clone> Clone for Triangle<T> {
  fn clone(&self) -> Triangle<T> {
    Triangle {
      vertices: [self.vertices[0].clone(), self.vertices[1].clone(), self.vertices[2].clone()],
    }
  }
}

pub struct App {
  vao: u32,
  vbo: u32,
  vertex_data: Vec<Triangle<GLfloat>>,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl<T: Clone> Triangle<T> {
  fn new(
      v1: &Vertex<T>,
      v2: &Vertex<T>,
      v3: &Vertex<T>)
      -> Triangle<T> {
    Triangle {
      vertices: [v1.clone(), v2.clone(), v3.clone()],
    }
  }
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      let raw_data = mem::transmute(&self.vertex_data.slice(0, self.vertex_data.len())[0]);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (self.vertex_data.len() * mem::size_of::<Triangle<GLfloat>>()) as GLsizeiptr,
                      raw_data,
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);

      gl::VertexAttribPointer(
          pos_attr as GLuint,
          (mem::size_of::<Vector3<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null(),
      );
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      vertex_data: Vec::from_slice([
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0)),
          &Vertex::new(&Vector3::new( 0.5, -0.5, 0.0)),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0)),
        ),
      ]),
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn destroy(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
out vec4 out_color;\n\
void main() {\n\
out_color = vec4(1.0, 1.0, 1.0, 1.0);\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<commit_msg>add color data to each point<commit_after>#![feature(globs)] // Allow global imports

extern crate cgmath;
extern crate gl;
extern crate graphics;
extern crate native;
extern crate piston;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;

use cgmath::array::*;
use cgmath::vector::{Vector3, Vector4};
use piston::*;
use gl::types::*;
use std::mem;
use std::ptr;
use std::str;

pub struct Color4<T> { inner: Vector4<T>, }

impl<T: Clone> Clone for Color4<T> {
  fn clone(&self) -> Color4<T> {
    Color4 { inner: self.inner.clone(), }
  }
}

impl<T: Clone> Color4<T> {
  fn new(v: &Vector4<T>) -> Color4<T> {
    Color4 { inner: v.clone(), }
  }
}

pub struct Vertex<T> {
  position: Vector3<T>,
  color: Color4<T>,
}

impl<T: Clone> Clone for Vertex<T> {
  fn clone(&self) -> Vertex<T> {
    Vertex {
      position: self.position.clone(),
      color: self.color.clone(),
    }
  }
}

impl<T: Clone> Vertex<T> {
  fn new(v: &Vector3<T>, c: &Color4<T>) -> Vertex<T> {
    Vertex {
      position: v.clone(),
      color: c.clone(),
    }
  }
}

pub struct Triangle<T> {
  vertices: [Vertex<T>, ..3],
}

impl<T: Clone> Clone for Triangle<T> {
  fn clone(&self) -> Triangle<T> {
    Triangle {
      vertices: [self.vertices[0].clone(), self.vertices[1].clone(), self.vertices[2].clone()],
    }
  }
}

pub struct App {
  vao: u32,
  vbo: u32,
  vertex_data: Vec<Triangle<GLfloat>>,
  projection_matrix: cgmath::matrix::Matrix4<GLfloat>,
  shader_program: u32,
}

pub fn translate(t: &Vector3<GLfloat>) -> cgmath::matrix::Matrix4<GLfloat> {
  cgmath::matrix::Matrix4::new(
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    t.x, t.y, t.z, 1.0,
  )
}

impl<T: Clone> Triangle<T> {
  fn new(
      v1: &Vertex<T>,
      v2: &Vertex<T>,
      v3: &Vertex<T>)
      -> Triangle<T> {
    Triangle {
      vertices: [v1.clone(), v2.clone(), v3.clone()],
    }
  }
}

impl Game for App {
  fn key_press(&mut self, _args: &KeyPressArgs) {
    match _args.key {
      piston::keyboard::A => {
        self.transform_projection(&translate(&Vector3::new(0.1, 0.0, 0.0)));
      },
      piston::keyboard::D => {
        self.transform_projection(&translate(&Vector3::new(-0.1, 0.0, 0.0)));
      },
      piston::keyboard::LShift => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.1, 0.0)));
      },
      piston::keyboard::Space => {
        self.transform_projection(&translate(&Vector3::new(0.0, -0.1, 0.0)));
      },
      piston::keyboard::W => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, 0.1)));
      },
      piston::keyboard::S => {
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
      },
      _ => {},
    }
  }

  fn load(&mut self) {
    let vs = compile_shader(VS_SRC, gl::VERTEX_SHADER);
    let fs = compile_shader(FS_SRC, gl::FRAGMENT_SHADER);

    self.shader_program = link_program(vs, fs);

    unsafe {
      // Create Vertex Array Object
      gl::GenVertexArrays(1, &mut self.vao);
      gl::BindVertexArray(self.vao);

      let raw_data = mem::transmute(&self.vertex_data.slice(0, self.vertex_data.len())[0]);

      // Create a Vertex Buffer Object and copy the vertex data to it
      gl::GenBuffers(1, &mut self.vbo);
      gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
      gl::BufferData(gl::ARRAY_BUFFER,
                      (self.vertex_data.len() * mem::size_of::<Triangle<GLfloat>>()) as GLsizeiptr,
                      raw_data,
                      gl::STATIC_DRAW);

      gl::UseProgram(self.shader_program);
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = cgmath::projection::frustum::<GLfloat>(-1.0, 1.0, -1.0, 1.0, 0.1, 2.0);
        self.transform_projection(&translate(&Vector3::new(0.0, 0.0, -0.1)));
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
      "out_color".with_c_str(|ptr| gl::BindFragDataLocation(self.shader_program, 0, ptr));

      // Specify the layout of the vertex data
      let pos_attr = "position".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(pos_attr as GLuint);
      let color_attr = "in_color".with_c_str(|ptr| gl::GetAttribLocation(self.shader_program, ptr));
      gl::EnableVertexAttribArray(color_attr as GLuint);

      gl::VertexAttribPointer(
          pos_attr as GLuint,
          (mem::size_of::<Vector3<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null(),
      );
      gl::VertexAttribPointer(
          color_attr as GLuint,
          (mem::size_of::<Color4<GLfloat>>() / mem::size_of::<GLfloat>()) as i32,
          gl::FLOAT,
          gl::FALSE as GLboolean,
          mem::size_of::<Vertex<GLfloat>>() as i32,
          ptr::null().offset(mem::size_of::<Vector3<GLfloat>>() as int),
      );
    }

    gl::ClearColor(0.0, 0.0, 0.0, 1.0);
  }

  fn render(&mut self, _:&RenderArgs) {
    gl::Clear(gl::COLOR_BUFFER_BIT);

    // Draw a triangle from the 3 vertices
    gl::DrawArrays(gl::TRIANGLES, 0, 3);
  }
}

impl App {
  pub fn new() -> App {
    App {
      vao: 0,
      vbo: 0,
      vertex_data: Vec::from_slice([
        Triangle::new(
          &Vertex::new(&Vector3::new( 0.0,  0.5, 0.0), &Color4::new(&Vector4::new(1.0, 0.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new( 0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 1.0, 0.0, 1.0))),
          &Vertex::new(&Vector3::new(-0.5, -0.5, 0.0), &Color4::new(&Vector4::new(0.0, 0.0, 1.0, 1.0))),
        ),
      ]),
      shader_program: -1 as u32,
      projection_matrix: cgmath::matrix::Matrix4::from_value(0.0),
    }
  }

  pub fn transform_projection(&mut self, t: &cgmath::matrix::Matrix4<GLfloat>) {
    unsafe {
      let loc = gl::GetUniformLocation(self.shader_program, "proj_matrix".to_c_str().unwrap());
      if loc == -1 {
        println!("couldn't read matrix");
      } else {
        self.projection_matrix = self.projection_matrix * *t;
        gl::UniformMatrix4fv(loc, 1, 0, mem::transmute(self.projection_matrix.ptr()));
      }
    }
  }

  pub fn destroy(&mut self) {
    unsafe {
      gl::DeleteBuffers(1, &self.vbo);
      gl::DeleteVertexArrays(1, &self.vao);
    }
  }
}

// Shader sources
static VS_SRC: &'static str =
   "#version 150\n\
uniform mat4 proj_matrix;\n\
in vec3 position;\n\
in vec4 in_color;\n\
varying vec4 color;\n\
void main() {\n\
gl_Position = proj_matrix * vec4(position, 1.0);\n\
color = in_color;\n\
}";

static FS_SRC: &'static str =
   "#version 150\n\
varying vec4 color;\n\
out vec4 out_color;\n\
void main() {\n\
out_color = color;\n\
}";

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader = gl::CreateShader(ty);
    unsafe {
        // Attempt to compile the shader
        src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    let program = gl::CreateProgram();

    gl::AttachShader(program, vs);
    gl::AttachShader(program, fs);
    gl::LinkProgram(program);

    unsafe {
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::from_elem(len as uint - 1, 0u8); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
            fail!("{}", str::from_utf8(buf.as_slice()).expect("ProgramInfoLog not valid utf8"));
        }
    }

    program
}

fn main() {
  let mut window = GameWindowSDL2::new(
    GameWindowSettings {
      title: "playform".to_string(),
      size: [800, 600],
      fullscreen: false,
      exit_on_esc: false,
    }
  );

  App::new().run(&mut window, &GameIteratorSettings {
    updates_per_second: 30,
    max_frames_per_second: 30,
  });
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(plugin)]
#![plugin(regex_macros)]

extern crate regex;
extern crate term;
extern crate binunit;

use std::io::prelude::*;

fn main() {

    let binunit = binunit::BinUnit::new(&std::env::current_dir().unwrap());
    match binunit.run() {
        Ok(output) =>
            print(&output)
        ,
        Err(err) =>
            println!("{}\nbinunit failed", err)
    }

}

pub fn print(output: &Vec<String>) {

    let summary = output.iter()
        .inspect(|result| print_result_colorized(&result.trim().to_owned()))
        .fold((0, 0, 0), |a, b| increment_summary(a, b));

    print_summary(&summary);
}

fn print_result_colorized(output: &String) {

    let mut term = term::stdout().unwrap();
    for capture in regex!(r"(?m)(.*: )(failed|ok)(.*)|.*").captures_iter(output) {
        match capture.at(2).unwrap_or("") {
            "ok" => {
                write!(term, "{}", capture.at(1).unwrap()).unwrap();
                term.fg(term::color::BRIGHT_GREEN).unwrap();
                write!(term, "{}", capture.at(2).unwrap()).unwrap();
                term.reset().unwrap();
                writeln!(term, "{}", capture.at(3).unwrap()).unwrap();
            },
            "failed" => {
                write!(term, "{}", capture.at(1).unwrap()).unwrap();
                term.fg(term::color::BRIGHT_RED).unwrap();
                write!(term, "{}", capture.at(2).unwrap()).unwrap();
                term.reset().unwrap();
                writeln!(term, "{}", capture.at(3).unwrap()).unwrap();
            },
            _ => writeln!(term, "{}\n", capture.at(0).unwrap()).unwrap()
        }
    }
}

fn increment_summary((total, pass, fail): (i32, i32, i32), result: &String) -> (i32, i32, i32) {

    if result.contains(": ok") {
        (total+1, pass+1, fail)
    } else if result.contains(": failed") {
        (total+1, pass, fail+1)
    } else {
        (total, pass, fail)
    }
}

fn print_summary(&(_, pass, fail): &(i32, i32, i32)) {

    let mut term = term::stdout().unwrap();
    write!(term, "\n\nsummary: ").unwrap();
    match fail {
        0 => {
            term.fg(term::color::BRIGHT_GREEN).unwrap();
            write!(term, "ok").unwrap()
        },
        _ => {
            term.fg(term::color::BRIGHT_RED).unwrap();
            write!(term, "failed").unwrap();
        }
    }
    term.reset().unwrap();
    writeln!(term, " -- {} passed, {} failed\n\n", pass, fail).unwrap();
}
<commit_msg>print failed tests last<commit_after>#![deny(warnings)]
#![feature(plugin)]
#![plugin(regex_macros)]

extern crate regex;
extern crate term;
extern crate binunit;

use std::io::prelude::*;

fn main() {

    let binunit = binunit::BinUnit::new(&std::env::current_dir().unwrap());
    match binunit.run() {
        Ok(mut output) =>
            print(&mut output)
        ,
        Err(err) =>
            println!("{}\nbinunit failed", err)
    }

}

pub fn print(output: &mut Vec<String>) {

    let summary = output.iter()
        .fold((0, 0, 0), |a, b| increment_summary(a, b));

    output.sort();

    println!("");

    for item in output.iter().filter(|item| item.contains(": ok")) {
        print_result_colorized(&item.trim().to_owned());
    }

    println!("\n");

    for item in output.iter().filter(|item| item.contains(": failed")) {
        print_result_colorized(&item.trim().to_owned());
    }

    print_summary(&summary);
}

fn print_result_colorized(output: &String) {

    let mut term = term::stdout().unwrap();
    for capture in regex!(r"(?m)(.*: )(ok|failed)(.*)|.*").captures_iter(output) {
        match capture.at(2).unwrap_or("") {
            "ok" => {
                write!(term, "{}", capture.at(1).unwrap()).unwrap();
                term.fg(term::color::BRIGHT_GREEN).unwrap();
                write!(term, "{}", capture.at(2).unwrap()).unwrap();
                term.reset().unwrap();
                writeln!(term, "{}", capture.at(3).unwrap()).unwrap();
            },
            "failed" => {
                write!(term, "{}", capture.at(1).unwrap()).unwrap();
                term.fg(term::color::BRIGHT_RED).unwrap();
                write!(term, "{}", capture.at(2).unwrap()).unwrap();
                term.reset().unwrap();
                writeln!(term, "{}", capture.at(3).unwrap()).unwrap();
            },
            _ => writeln!(term, "{}\n", capture.at(0).unwrap()).unwrap()
        }
    }

}

fn increment_summary((total, pass, fail): (i32, i32, i32), result: &String) -> (i32, i32, i32) {

    if result.contains(": ok") {
        (total+1, pass+1, fail)
    } else if result.contains(": failed") {
        (total+1, pass, fail+1)
    } else {
        (total, pass, fail)
    }
}

fn print_summary(&(_, pass, fail): &(i32, i32, i32)) {

    let mut term = term::stdout().unwrap();
    write!(term, "\n\n\t").unwrap();
    match fail {
        0 => {
            term.fg(term::color::BRIGHT_GREEN).unwrap();
            write!(term, "ok").unwrap()
        },
        _ => {
            term.fg(term::color::BRIGHT_RED).unwrap();
            write!(term, "failed").unwrap();
        }
    }
    term.reset().unwrap();
    writeln!(term, " -- {} passed, {} failed\n", pass, fail).unwrap();
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate icecore;

use getopts::{optopt, optflag, getopts, usage};
use std::os;
use std::str::FromStr;

use icecore::data::FileStore;
use icecore::ic::Icecore;

fn insert(ic: &mut Icecore, data: String) {
    ic.insert(data);
}

fn get(ic: &mut Icecore, id: u64) {
    let data = ic.get(id, None);
    println!("{}", data);
}

fn demo(ic: &mut Icecore) {
    let id = ic.insert(String::from_str("foo"));
    println!("new document: id={}", id);
    println!("get({}, None) -> {}", id, ic.get(id, None));

    ic.update(id, String::from_str("bar"));
    println!("get({}, None) -> {}", id, ic.get(id, None));
    println!("get({}, 1) -> {}", id, ic.get(id, Some(1u64)));

    ic.dump();
}

fn main() {
    let args: Vec<String> = os::args();

    let store = box FileStore::new(String::from_str("_documents"));
    let mut ic = Icecore::new(
        Path::new("_documents"),
        store,
    );

    ic.load();

    match args[1].as_slice() {
        "insert" => {
            let opts = [
                optopt("d", "data", "Data to insert into the database", "DATA"),
                optflag("h", "help", "print this help message and exit"),
            ];

            let matches = match getopts(args.tail(), &opts) {
                Ok(m) => m,
                Err(_) => panic!("{}", usage("Insert data in the data store", &opts)),
            };

            if matches.opt_present("h") {
                println!("{}", usage("Insert data in the data store", &opts));
                return;
            }

            let data = matches.opt_str("d").unwrap();
            insert(&mut ic, data);
        },
        "get" => {
            let opts = [
                optopt("v", "version", "Requested document version", "VERSION"),
            ];
            let matches = match getopts(args.slice_from(2), &opts) {
                Ok(m) => m,
                Err(_) => panic!(usage("Get document by id", &opts)),
            };
            let id = from_str::<u64>(args[2].as_slice()).unwrap();
            let version: Option<u64> = match matches.opt_str("v") {
                Some(v) => Some(from_str::<u64>(v.as_slice()).unwrap()),
                None => None,
            };
            println!("getting document id={} version={}", id, version);
            let data = ic.get(id, version);
            println!("{}", data);
        },
        "demo" => {
            demo(&mut ic);
        },
        _ => {
            println!("Command not found.");
        }
    }

    ic.dump();
}
<commit_msg>Remove dead code<commit_after>extern crate getopts;
extern crate icecore;

use getopts::{optopt, optflag, getopts, usage};
use std::os;

use icecore::data::FileStore;
use icecore::ic::Icecore;

fn demo(ic: &mut Icecore) {
    let id = ic.insert(String::from_str("foo"));
    println!("new document: id={}", id);
    println!("get({}, None) -> {}", id, ic.get(id, None));

    ic.update(id, String::from_str("bar"));
    println!("get({}, None) -> {}", id, ic.get(id, None));
    println!("get({}, 1) -> {}", id, ic.get(id, Some(0u64)));

    ic.dump();
}

fn main() {
    let args: Vec<String> = os::args();

    let store = box FileStore::new(String::from_str("_documents"));
    let mut ic = Icecore::new(
        Path::new("_documents"),
        store,
    );

    ic.load();

    match args[1].as_slice() {
        "insert" => {
            let opts = [
                optopt("d", "data", "Data to insert into the database", "DATA"),
                optflag("h", "help", "print this help message and exit"),
            ];

            let matches = match getopts(args.tail(), &opts) {
                Ok(m) => m,
                Err(_) => panic!("{}", usage("Insert data in the data store", &opts)),
            };

            if matches.opt_present("h") {
                println!("{}", usage("Insert data in the data store", &opts));
                return;
            }

            let data = matches.opt_str("d").unwrap();
            ic.insert(data);
        },
        "get" => {
            let opts = [
                optopt("v", "version", "Requested document version", "VERSION"),
            ];
            let matches = match getopts(args.slice_from(2), &opts) {
                Ok(m) => m,
                Err(_) => panic!(usage("Get document by id", &opts)),
            };
            let id = from_str::<u64>(args[2].as_slice()).unwrap();
            let version: Option<u64> = match matches.opt_str("v") {
                Some(v) => Some(from_str::<u64>(v.as_slice()).unwrap()),
                None => None,
            };
            println!("getting document id={} version={}", id, version);
            let data = ic.get(id, version);
            println!("{}", data);
        },
        "demo" => {
            demo(&mut ic);
        },
        _ => {
            println!("Command not found.");
        }
    }

    ic.dump();
}
<|endoftext|>


<commit_before>use bindings::{
	jit_context_t,
	jit_context_create,
	jit_context_destroy,
	jit_context_build_start,
	jit_context_build_end,
	jit_function_t,
	jit_function_next
};
use function::Function;
use std::kinds::marker::ContravariantLifetime;
use util::NativeRef;
/// Holds all of the functions you have built and compiled. There can be multiple, but normally there is only one.
native_ref!(Context, _context, jit_context_t)
impl Context {
	/// Create a new JIT Context
	pub fn new() -> Context {
		unsafe {
			NativeRef::from_ptr(jit_context_create())
		}
	}
	/// Run a closure that can generate IR
	pub fn build<R>(&self, cb: || -> R) -> R {
		unsafe {
			jit_context_build_start(self.as_ptr());
		}
		let rv = cb();
		unsafe {
			jit_context_build_end(self.as_ptr());
		}
		rv
	}
	/// Iterate through all the functions in this context
	pub fn iter_funcs<'t>(&'t self) -> Functions<'t> {
		Functions::new(self)
	}
}
#[unsafe_destructor]
impl Drop for Context {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_context_destroy(self.as_ptr());
		}
	}
}
/// Any JIT object which is in a context
pub trait InContext {
	/// Get the context for this object
	fn get_context(&self) -> Context;
}

/// An iterator over a context's functions
pub struct Functions<'a> {
	ctx: jit_context_t,
	last: jit_function_t,
	marker: ContravariantLifetime<'a>
}
impl<'a> Functions<'a> {
	fn new(ctx:&'a Context) -> Functions<'a> {
		unsafe {
			Functions {
				ctx: ctx.as_ptr(),
				last: RawPtr::null(),
				marker: ContravariantLifetime::<'a>
			}
		}
	}
}
impl<'a> Iterator<Function<'a>> for Functions<'a> {
	fn next(&mut self) -> Option<Function> {
		unsafe {
			let native_next = jit_function_next(self.ctx, self.last);
			self.last = native_next;
			NativeRef::from_ptr_opt(native_next)
		}
	}
	fn size_hint(&self) -> (uint, Option<uint>) {
		unsafe {
			let mut size : uint = 0;
			let mut last = self.last;
			loop {
				last = jit_function_next(self.ctx, last);
				if last.is_null() {
					break;
				} else {
					size += 1;
				}
			}
			(size, Some(size))
		}
	}
}<commit_msg>Add lifetime to context<commit_after>use bindings::{
	jit_context_t,
	jit_context_create,
	jit_context_destroy,
	jit_context_build_start,
	jit_context_build_end,
	jit_function_t,
	jit_function_next
};
use function::Function;
use std::kinds::marker::ContravariantLifetime;
use util::NativeRef;
/// Holds all of the functions you have built and compiled. There can be multiple, but normally there is only one.
native_ref!(Context, _context, jit_context_t, ContravariantLifetime)
impl<'a> Context<'a> {
	/// Create a new JIT Context
	pub fn new() -> Context {
		unsafe {
			NativeRef::from_ptr(jit_context_create())
		}
	}
	/// Run a closure that can generate IR
	pub fn build<R>(&self, cb: || -> R) -> R {
		unsafe {
			jit_context_build_start(self.as_ptr());
		}
		let rv = cb();
		unsafe {
			jit_context_build_end(self.as_ptr());
		}
		rv
	}
	/// Iterate through all the functions in this context
	pub fn iter_funcs<'t>(&'t self) -> Functions<'t> {
		Functions::new(self)
	}
}
#[unsafe_destructor]
impl<'a> Drop for Context<'a> {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_context_destroy(self.as_ptr());
		}
	}
}
/// Any JIT object which is in a context
pub trait InContext {
	/// Get the context for this object
	fn get_context(&self) -> Context;
}

/// An iterator over a context's functions
pub struct Functions<'a> {
	ctx: jit_context_t,
	last: jit_function_t,
	marker: ContravariantLifetime<'a>
}
impl<'a> Functions<'a> {
	fn new(ctx:&Context<'a>) -> Functions<'a> {
		unsafe {
			Functions {
				ctx: ctx.as_ptr(),
				last: RawPtr::null(),
				marker: ContravariantLifetime::<'a>
			}
		}
	}
}
impl<'a> Iterator<Function<'a>> for Functions<'a> {
	fn next(&mut self) -> Option<Function> {
		unsafe {
			let native_next = jit_function_next(self.ctx, self.last);
			self.last = native_next;
			NativeRef::from_ptr_opt(native_next)
		}
	}
	fn size_hint(&self) -> (uint, Option<uint>) {
		unsafe {
			let mut size : uint = 0;
			let mut last = self.last;
			loop {
				last = jit_function_next(self.ctx, last);
				if last.is_null() {
					break;
				} else {
					size += 1;
				}
			}
			(size, Some(size))
		}
	}
}<|endoftext|>


<commit_before>extern crate iron;

use iron::prelude::*;
use iron::status;

fn main() {

    Iron::new(|_: &mut Request| {
        Ok(Response::with((
            status::Ok,
            "Hello Iron"
        )))
    }).http("localhost:3000").unwrap();
}
<commit_msg>chore: 测试channel<commit_after>extern crate iron;

use std::thread;
use std::sync::mpsc;

use iron::prelude::*;
use iron::status;

fn main() {

    let (sender, receiver): (mpsc::Sender<i32>, mpsc::Receiver<i32>) = mpsc::channel();

    thread::spawn(move || {
        println!("before action");
        sender.send(123).unwrap();
        println!("after action");
    });

    // Iron::new(|_: &mut Request| {
    //     Ok(Response::with((
    //         status::Ok,
    //         "Hello Iron"
    //     )))
    // }).http("localhost:3000").unwrap();

    println!("prev");
    println!("recevie {}", receiver.recv().unwrap());
    println!("next");
}
<|endoftext|>


<commit_before>#[macro_use] extern crate lazy_static;
extern crate deploy;
extern crate dotenv;
extern crate pencil;

use deploy::*;
use dotenv::dotenv;
use pencil::{Pencil, Response, Request, PencilResult};
use std::env;
use std::path::Path;
use std::process::{Stdio, Command};
use std::thread;

lazy_static! {
  pub static ref SECRET: String = env::var("TENJAVA_DEPLOY_SECRET").expect("missing TENJAVA_DEPLOY_SECRET");
  pub static ref PROD_REPO: String = env::var("TENJAVA_WEBSITE_REPO").expect("missing TENJAVA_WEBSITE_PROD_REPO");
  pub static ref DEV_REPO: String = env::var("TENJAVA_WEBSITE_REPO").expect("missing TENJAVA_WEBSITE_DEV_REPO");
}

fn deploy_webhook(r: &mut Request) -> PencilResult {
  println!("receiving a deploy request");
  let (signature, event) = {
    let headers = r.headers();
    let signature: &XHubSignature = match headers.get() {
      Some(x) => x,
      None => {
        println!("  it was missing a signature header");
        println!("  done");
        let mut res = Response::new("missing a signature header");
        res.status_code = 401;
        return Ok(res);
      }
    };
    let event: &XGitHubEvent = match headers.get() {
      Some(x) => x,
      None => {
        println!("  it was missing an event header");
        println!("  done");
        let mut res = Response::new("missing an event header");
        res.status_code = 401;
        return Ok(res);
      }
    };
    (signature.clone(), event.clone())
  };
  if *event != "push" {
    println!("  it was not a push event");
    println!("  done");
    return Ok("not a push event, but thanks anyway".into());
  }
  let signature_check = match deploy::check_signature(r, &signature, &SECRET) {
    Ok(x) => x,
    Err(e) => {
      println!("  an error occurred while checking the signature: {}", e);
      println!("  done");
      let mut res = Response::new(format!("an error occurred while checking signature: {}", e));
      res.status_code = 500;
      return Ok(res);
    }
  };
  if !signature_check {
    println!("  it had an invalid signature");
    println!("  done");
    let mut res = Response::new("invalid signature");
    res.status_code = 401;
    return Ok(res);
  }
  println!("  everything checks out");
  println!("  checking branch");
  let branch = match deploy::get_branch(r) {
    Ok(b) => b,
    Err(e) => {
      println!("  an error occurred while checking branch: {}", e);
      println!("  done");
      let mut res = Response::new(format!("couldn't get branch: {}", e));
      res.status_code = 401;
      return Ok(res);
    }
  };
  println!("  spawning update thread");
  update_repo(&branch);
  println!("  thread spawned");
  println!("  done");
  println!("");
  Ok("deploy initiated".into())
}

fn update_repo(branch: &Branch) {
  let repo_path = match *branch {
    Branch::Master => &*PROD_REPO,
    Branch::Dev => &*DEV_REPO
  };
  thread::spawn(move || {
    let status = Command::new("git")
      .arg("pull")
      .stdout(Stdio::null())
      .current_dir(Path::new(repo_path))
      .status()
      .expect("could not start git");
    if !status.success() {
      match status.code() {
        Some(code) => {
          println!("git exited with code {}", code);
        },
        None => {
          println!("git exited with an unknown status code");
        }
      }
    } else {
      println!("git exited successfully")
    }
  });
}

fn inner() -> i32 {
  // load up env
  dotenv().ok();

  // check env
  if (&*SECRET).is_empty() {
    println!("oops, no TENJAVA_DEPLOY_SECRET was specified");
    return 1;
  }
  if (&*PROD_REPO).is_empty() {
    println!("oops, no TENJAVA_WEBSITE_PROD_REPO was specified");
    return 1;
  }
  if (&*DEV_REPO).is_empty() {
    println!("oops, no TENJAVA_WEBSITE_DEV_REPO was specified");
    return 1;
  }
  let mut app = Pencil::new("/static");
  app.post("/deploy", "deploy", deploy_webhook);
  app.run("0.0.0.0:32260");
  0
}

fn main() {
  let exit_code = inner();
  std::process::exit(exit_code);
}
<commit_msg>fix: use correct environment variable names<commit_after>#[macro_use] extern crate lazy_static;
extern crate deploy;
extern crate dotenv;
extern crate pencil;

use deploy::*;
use dotenv::dotenv;
use pencil::{Pencil, Response, Request, PencilResult};
use std::env;
use std::path::Path;
use std::process::{Stdio, Command};
use std::thread;

lazy_static! {
  pub static ref SECRET: String = env::var("TENJAVA_DEPLOY_SECRET").expect("missing TENJAVA_DEPLOY_SECRET");
  pub static ref PROD_REPO: String = env::var("TENJAVA_WEBSITE_PROD_REPO").expect("missing TENJAVA_WEBSITE_PROD_REPO");
  pub static ref DEV_REPO: String = env::var("TENJAVA_WEBSITE_DEV_REPO").expect("missing TENJAVA_WEBSITE_DEV_REPO");
}

fn deploy_webhook(r: &mut Request) -> PencilResult {
  println!("receiving a deploy request");
  let (signature, event) = {
    let headers = r.headers();
    let signature: &XHubSignature = match headers.get() {
      Some(x) => x,
      None => {
        println!("  it was missing a signature header");
        println!("  done");
        let mut res = Response::new("missing a signature header");
        res.status_code = 401;
        return Ok(res);
      }
    };
    let event: &XGitHubEvent = match headers.get() {
      Some(x) => x,
      None => {
        println!("  it was missing an event header");
        println!("  done");
        let mut res = Response::new("missing an event header");
        res.status_code = 401;
        return Ok(res);
      }
    };
    (signature.clone(), event.clone())
  };
  if *event != "push" {
    println!("  it was not a push event");
    println!("  done");
    return Ok("not a push event, but thanks anyway".into());
  }
  let signature_check = match deploy::check_signature(r, &signature, &SECRET) {
    Ok(x) => x,
    Err(e) => {
      println!("  an error occurred while checking the signature: {}", e);
      println!("  done");
      let mut res = Response::new(format!("an error occurred while checking signature: {}", e));
      res.status_code = 500;
      return Ok(res);
    }
  };
  if !signature_check {
    println!("  it had an invalid signature");
    println!("  done");
    let mut res = Response::new("invalid signature");
    res.status_code = 401;
    return Ok(res);
  }
  println!("  everything checks out");
  println!("  checking branch");
  let branch = match deploy::get_branch(r) {
    Ok(b) => b,
    Err(e) => {
      println!("  an error occurred while checking branch: {}", e);
      println!("  done");
      let mut res = Response::new(format!("couldn't get branch: {}", e));
      res.status_code = 401;
      return Ok(res);
    }
  };
  println!("  spawning update thread");
  update_repo(&branch);
  println!("  thread spawned");
  println!("  done");
  println!("");
  Ok("deploy initiated".into())
}

fn update_repo(branch: &Branch) {
  let repo_path = match *branch {
    Branch::Master => &*PROD_REPO,
    Branch::Dev => &*DEV_REPO
  };
  thread::spawn(move || {
    let status = Command::new("git")
      .arg("pull")
      .stdout(Stdio::null())
      .current_dir(Path::new(repo_path))
      .status()
      .expect("could not start git");
    if !status.success() {
      match status.code() {
        Some(code) => {
          println!("git exited with code {}", code);
        },
        None => {
          println!("git exited with an unknown status code");
        }
      }
    } else {
      println!("git exited successfully")
    }
  });
}

fn inner() -> i32 {
  // load up env
  dotenv().ok();

  // check env
  if (&*SECRET).is_empty() {
    println!("oops, no TENJAVA_DEPLOY_SECRET was specified");
    return 1;
  }
  if (&*PROD_REPO).is_empty() {
    println!("oops, no TENJAVA_WEBSITE_PROD_REPO was specified");
    return 1;
  }
  if (&*DEV_REPO).is_empty() {
    println!("oops, no TENJAVA_WEBSITE_DEV_REPO was specified");
    return 1;
  }
  let mut app = Pencil::new("/static");
  app.post("/deploy", "deploy", deploy_webhook);
  app.run("0.0.0.0:32260");
  0
}

fn main() {
  let exit_code = inner();
  std::process::exit(exit_code);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

// extern crate hyper;
// extern crate hyper_rustls;
// use hyper::Client;
// use hyper::net::HttpsConnector;
// use hyper_rustls::TlsClient;
// use hyper::header::Authorization;
// use hyper::header::{Accept, qitem};
// use hyper::mime::{Mime, TopLevel, SubLevel};

extern crate reqwest;
use reqwest::header::Authorization;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

extern crate glob;
use glob::glob;

#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
    #[serde(default="default_cache_duration")]
    cache_duration: u64,
    #[serde(default="default_cert_path")]
    cert_path: String
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
    SystemTime(std::time::SystemTimeError),
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}
impl From<std::time::SystemTimeError> for CliError {fn from(err: std::time::SystemTimeError) -> CliError { CliError::SystemTime(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .arg(Arg::with_name("v")
                               .short("v")
                               .multiple(true)
                               .help("Sets the level of verbosity"))
                      .subcommand(SubCommand::with_name("key")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(true)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("pam")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let config = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let mut file = File::open(config).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();

    match std::env::var("SSL_CERT_FILE") {
        Ok(_) => (),
        Err(_) => std::env::set_var("SSL_CERT_FILE", config.cert_path.clone()),
    }

    // let client = Client::with_connector(HttpsConnector::new(TlsClient::new()));
    let client = reqwest::Client::new().unwrap();
    let client = GithubClient::new(client, config);

    if let Some(matches) = matches.subcommand_matches("key") {
        client.print_user_public_key(matches.value_of("USER").unwrap()).unwrap();
    } else if let Some(_) = matches.subcommand_matches("passwd") {
        client.get_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.get_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.get_group().unwrap();
    } else if let Some(_) = matches.subcommand_matches("refresh") {
        client.clear_all_caches().unwrap();
    } else if let Some(_) = matches.subcommand_matches("pam") {
        match std::env::var("PAM_USER") {
            Ok(user) => {
                if client.check_pam(&user).unwrap() { std::process::exit(0); }
                else { std::process::exit(1) }
            }
            Err(e) => println!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

struct GithubClient {
    // client: hyper::Client,
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let mut dirpath = path.clone(); dirpath.pop();
        std::fs::create_dir_all(dirpath)?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint.clone(),user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn get_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint.clone(), self.conf.org.clone());
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

    fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}
<commit_msg>Remove useless comments<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

extern crate reqwest;
use reqwest::header::Authorization;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

extern crate glob;
use glob::glob;

#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
    #[serde(default="default_cache_duration")]
    cache_duration: u64,
    #[serde(default="default_cert_path")]
    cert_path: String
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }
fn default_cache_duration() -> u64 { 3600 }
fn default_cert_path() -> String { String::from("/etc/ssl/certs/ca-certificates.crt") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error),
    SystemTime(std::time::SystemTimeError),
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}
impl From<std::time::SystemTimeError> for CliError {fn from(err: std::time::SystemTimeError) -> CliError { CliError::SystemTime(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .arg(Arg::with_name("v")
                               .short("v")
                               .multiple(true)
                               .help("Sets the level of verbosity"))
                      .subcommand(SubCommand::with_name("key")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(true)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("pam")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let config = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let mut file = File::open(config).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();

    match std::env::var("SSL_CERT_FILE") {
        Ok(_) => (),
        Err(_) => std::env::set_var("SSL_CERT_FILE", config.cert_path.clone()),
    }

    let client = reqwest::Client::new().unwrap();
    let client = GithubClient::new(client, config);

    if let Some(matches) = matches.subcommand_matches("key") {
        client.print_user_public_key(matches.value_of("USER").unwrap()).unwrap();
    } else if let Some(_) = matches.subcommand_matches("passwd") {
        client.get_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.get_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.get_group().unwrap();
    } else if let Some(_) = matches.subcommand_matches("refresh") {
        client.clear_all_caches().unwrap();
    } else if let Some(_) = matches.subcommand_matches("pam") {
        match std::env::var("PAM_USER") {
            Ok(user) => {
                if client.check_pam(&user).unwrap() { std::process::exit(0); }
                else { std::process::exit(1) }
            }
            Err(e) => println!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

struct GithubClient {
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn load_content_from_cache(&self, url:&String) -> Result<(std::fs::Metadata,String),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata,content))
    }

    fn store_content_to_cache(&self, url:&String, content:&String) -> Result<(),CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push(url.as_str());
        let mut dirpath = path.clone(); dirpath.pop();
        std::fs::create_dir_all(dirpath)?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url:&String) -> Result<String,CliError> {
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        self.store_content_to_cache(url,&content)?;
        Ok(content)
    }

    fn get_content(&self, url:&String) -> Result<String,CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata,cache_content)) => {
                match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                    Ok(caching_duration) => {
                        if caching_duration.as_secs() > self.conf.cache_duration {
                            match self.get_content_from_url(url) {
                                Ok(content_from_url) => Ok(content_from_url),
                                Err(_) => Ok(cache_content)
                            }
                        } else {
                            Ok(cache_content)
                        }
                    },
                    Err(_) => {
                        Ok(cache_content)
                    }
                }
            },
            Err(_) => self.get_content_from_url(url)
        }
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint.clone(),user);
        let content = self.get_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn get_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint.clone(), self.conf.org.clone());
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

    fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("ghteam-auth-cache");
        path.push("**");
        path.push("*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {if path.is_file() {std::fs::remove_file(path)?}},
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }

}
<|endoftext|>