<commit_before>//#![feature(convert)]

#[macro_use]
extern crate nickel;
extern crate rustc_serialize;
extern crate hyper;
extern crate nickel_postgres;
extern crate postgres;
extern crate r2d2_postgres;
extern crate r2d2;
extern crate time;

use nickel::{Nickel, HttpRouter, QueryString};
use nickel::extensions::Redirect;
use nickel::status::StatusCode;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;
use hyper::status::StatusClass;
use hyper::client::response::Response;
use std::io::Read;
use std::env;
use r2d2::{NopErrorHandler, PooledConnection};
use r2d2_postgres::{TlsMode, PostgresConnectionManager};
use nickel_postgres::{PostgresMiddleware, PostgresRequestExtensions};
use time::now;

#[derive(RustcDecodable, Debug)]
struct Data {
    data: User,
}

#[derive(RustcDecodable, Debug)]
struct User {
    id: i32,
    email: String,
    created_at: String,
    updated_at: String,
    first_name: String,
    last_name: String,
    major: String,
    shirt_size: String,
    dietary_restrictions: String,
    special_needs: Option<String>,
    date_of_birth: String,
    gender: String,
    phone_number: String,
    school: School,
}

#[derive(RustcDecodable, Debug)]
struct School {
    id: i32,
    name: String,
}

#[derive(RustcDecodable, Debug)]
struct TokenResp {
    access_token: String,
    token_type: String,
    scope: String,
    created_at: u64,
}

#[derive(RustcEncodable, Debug)]
struct Payload {
    channel: String,
    username: String,
    text: String,
    icon_emoji: String,
}

#[derive(Debug)]
enum ApiError {
    ClientError,
    ServerError,
}

#[derive(Debug)]
enum RequestError {
    Hyper(hyper::error::Error),
    Io(std::io::Error),
    JsonEnc(rustc_serialize::json::EncoderError),
    JsonDec(rustc_serialize::json::DecoderError),
    Api(ApiError),
}

// `env_err!(var, message)` gets `var` from the environment, and panics with
// `message` if that fails
// `env_err!(var)` gets `var` from the environment and panics with `"Failed to
// get env var $var"` if that fails
macro_rules! env_err {
    ( $var:expr, $error:expr ) => {
        env::var($var).expect($error)
    };
    ( $var:expr ) => {
        env_err!($var, &format!("Failed to get env var {}", $var))
    }
}

// Error handling code.  Expands to impl-ing From for enum_t from from_t to to_t
// See https://doc.rust-lang.org/book/error-handling.html for a full description
macro_rules! impl_from {
    ( $from_t:path, $to_t:path, $enum_t:path ) => {
        impl From<$from_t> for $enum_t {
            fn from(err: $from_t) -> $enum_t {
                $to_t(err)
            }
        }
    }
}

// All the impls for RequestError
impl_from!(hyper::error::Error, RequestError::Hyper, RequestError);
impl_from!(std::io::Error, RequestError::Io, RequestError);
impl_from!(rustc_serialize::json::DecoderError,
           RequestError::JsonDec,
           RequestError);
impl_from!(rustc_serialize::json::EncoderError,
           RequestError::JsonEnc,
           RequestError);
impl_from!(ApiError, RequestError::Api, RequestError);

// Checks for 4xx or 5xx errors and returns the appropriate ApiError
fn check_http_error(res: &Response) -> Result<(), ApiError> {
    match res.status.class() {
        StatusClass::ClientError => Err(ApiError::ClientError),
        StatusClass::ServerError => Err(ApiError::ServerError),
        _ => Ok(()),
    }
}

// Do the OAUTH stuff for my.mlh.io
// TODO: Something better about the long api urls
fn do_request(code: &str) -> Result<Data, RequestError> {
    let id = env_err!("ID");
    let secret = env_err!("SECRET");
    let redirect = env_err!("REDIRECT");

    let url = format!("https://my.mlh.io/oauth/token?client_id={}&\
                      client_secret={}&code={}&redirect_uri={}&\
                      grant_type=authorization_code",
                      id,
                      secret,
                      code,
                      redirect);

    let client = Client::new();
    let mut res = try!(client.post(&url)
        .header(Connection::close())
        .send());

    try!(check_http_error(&res));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    let token: TokenResp = try!(json::decode(&body));
    let url2 = format!("https://my.mlh.io/api/v2/user?access_token={}",
                       token.access_token);

    res = try!(client.get(&url2)
        .header(Connection::close())
        .send());

    try!(check_http_error(&res));

    body = String::new();
    try!(res.read_to_string(&mut body));

    let person_data: Data = try!(json::decode(&body));

    Ok(person_data)
}

// Send a message to slack when a new user signs up
fn slack_send(user: User) -> Result<(), RequestError> {
    let url = env_err!("SLACKURL");
    let client = Client::new();
    let payload = Payload {
        channel: "#signups".to_string(),
        username: "Signup bot".to_string(),
        icon_emoji: ":hackcwru:".to_string(),
        text: format!("{}, a {} major from {}, has signed up!",
                      user.first_name,
                      user.major,
                      user.school.name),
    };
    let payload_str = try!(json::encode(&payload));
    let res = try!(client.post(&url)
        .body(&payload_str)
        .send());

    try!(check_http_error(&res));

    Ok(())
}

// Create the table if it doesn't exist.  Runs on each startup
fn create_table(conn: PooledConnection<PostgresConnectionManager>) {
    let _r =
        conn.execute("CREATE TABLE IF NOT EXISTS person (
                id SERIAL PRIMARY KEY,
                email VARCHAR NOT NULL,
                created_at VARCHAR NOT NULL,
                updated_at VARCHAR NOT NULL,
                first_name VARCHAR NOT NULL,
                last_name VARCHAR NOT NULL,
                graduation VARCHAR,
                major VARCHAR NOT NULL,
                shirt_size VARCHAR NOT NULL,
                dietary_restrictions VARCHAR NOT NULL,
                special_needs VARCHAR,
                date_of_birth VARCHAR NOT NULL,
                gender VARCHAR NOT NULL,
                phone_number VARCHAR NOT NULL,
                school_id integer,
                school_name VARCHAR
                )",
            &[]
        );
    let _r = conn.execute("ALTER TABLE person ADD COLUMN year integer \
                          NOT NULL DEFAULT 2016",
                          &[]);
    let _r = conn.execute("ALTER TABLE person ALTER COLUMN graduation \
                          DROP NOT NULL",
                          &[]);
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signup_time VARCHAR", &[]
        );
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signed_in
            BOOLEAN NOT NULL DEFAULT FALSE",
        &[]
        );
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signed_in_time VARCHAR", &[]
        );
}

fn main() {
    let mut app = Nickel::new();

    let postgres_url = env_err!("DATABASE");
    let dbpool =
        PostgresMiddleware::new(&*postgres_url, TlsMode::None, 5, Box::new(NopErrorHandler))
            .expect("Failed to start PostgresMiddleware");

    create_table(dbpool.pool.clone().get().unwrap());
    app.utilize(dbpool);

    app.get("/callback", middleware! { |request, mut response|
        let conn = request.db_conn();
        let redirect_success = env_err!("FINALREDIRECT");
        let redirect_failure = env_err!("REDIRECTERR");
        let year = env_err!("YEAR").parse::<i32>().unwrap();
        let code = match request.query().get("code") {
            Some(s) => s,
            None => {
                println!("No code, quitting");
                return response.error(StatusCode::BadRequest, "Failed");
            }
        };
        let user_data = match do_request(code) {
            Ok(s) => s,
            Err(e) => {
                println!("Get user data failed with error: {:?}", e);
                return response
                    .error(StatusCode::InternalServerError, "Failed");
            }
        }.data;

        let now = now();
        let now_s = format!("{}", now.rfc3339());
        // TODO: make this a function
        let r = conn.execute(
                "INSERT INTO person (id, email, created_at, updated_at,
                first_name, last_name, major, shirt_size,
                dietary_restrictions, special_needs, date_of_birth, gender,
                phone_number, school_id, school_name, year, signup_time) VALUES
                ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14,
                $15, $16, $17)",
                &[&user_data.id, &user_data.email, &user_data.created_at,
                  &user_data.updated_at, &user_data.first_name,
                  &user_data.last_name, &user_data.major,
                  &user_data.shirt_size, &user_data.dietary_restrictions,
                  &user_data.special_needs, &user_data.date_of_birth,
                  &user_data.gender, &user_data.phone_number,
                  &user_data.school.id, &user_data.school.name, &year, &now_s]
            );
        let redirect = match r {
            Ok(v) => {
                println!("Add to database succeeded with status {:?}", v);
                match slack_send(user_data) {
                    Ok(_) => println!("Slack send worked"),
                    Err(e) => println!("Slack send failed with error: {:?}", e)
                }
                redirect_success
            },
            Err(e) => {
                println!("Add to database failed: {:?}", e);
                redirect_failure
            }
        };

        return response.redirect(&redirect[..]);
    });

    app.get("/start", middleware! { |_req, response|
        let id = env_err!("ID");
        let redirect = env_err!("REDIRECT");
        return response.redirect(
            format!(
                    "http://my.mlh.io/oauth/authorize?client_id={}&\
                    redirect_uri={}&response_type=code",
                    id, redirect
                )
            );
    });

    let bind = match env::var("BIND") {
        Ok(v) => v,
        Err(_) => "127.0.0.1:8080".to_string(),
    };

    let _ = app.listen(&bind[..]);
}
<commit_msg>Primary key id, year<commit_after>//#![feature(convert)]

#[macro_use]
extern crate nickel;
extern crate rustc_serialize;
extern crate hyper;
extern crate nickel_postgres;
extern crate postgres;
extern crate r2d2_postgres;
extern crate r2d2;
extern crate time;

use nickel::{Nickel, HttpRouter, QueryString};
use nickel::extensions::Redirect;
use nickel::status::StatusCode;
use rustc_serialize::json;
use hyper::Client;
use hyper::header::Connection;
use hyper::status::StatusClass;
use hyper::client::response::Response;
use std::io::Read;
use std::env;
use r2d2::{NopErrorHandler, PooledConnection};
use r2d2_postgres::{TlsMode, PostgresConnectionManager};
use nickel_postgres::{PostgresMiddleware, PostgresRequestExtensions};
use time::now;

#[derive(RustcDecodable, Debug)]
struct Data {
    data: User,
}

#[derive(RustcDecodable, Debug)]
struct User {
    id: i32,
    email: String,
    created_at: String,
    updated_at: String,
    first_name: String,
    last_name: String,
    major: String,
    shirt_size: String,
    dietary_restrictions: String,
    special_needs: Option<String>,
    date_of_birth: String,
    gender: String,
    phone_number: String,
    school: School,
}

#[derive(RustcDecodable, Debug)]
struct School {
    id: i32,
    name: String,
}

#[derive(RustcDecodable, Debug)]
struct TokenResp {
    access_token: String,
    token_type: String,
    scope: String,
    created_at: u64,
}

#[derive(RustcEncodable, Debug)]
struct Payload {
    channel: String,
    username: String,
    text: String,
    icon_emoji: String,
}

#[derive(Debug)]
enum ApiError {
    ClientError,
    ServerError,
}

#[derive(Debug)]
enum RequestError {
    Hyper(hyper::error::Error),
    Io(std::io::Error),
    JsonEnc(rustc_serialize::json::EncoderError),
    JsonDec(rustc_serialize::json::DecoderError),
    Api(ApiError),
}

// `env_err!(var, message)` gets `var` from the environment, and panics with
// `message` if that fails
// `env_err!(var)` gets `var` from the environment and panics with `"Failed to
// get env var $var"` if that fails
macro_rules! env_err {
    ( $var:expr, $error:expr ) => {
        env::var($var).expect($error)
    };
    ( $var:expr ) => {
        env_err!($var, &format!("Failed to get env var {}", $var))
    }
}

// Error handling code.  Expands to impl-ing From for enum_t from from_t to to_t
// See https://doc.rust-lang.org/book/error-handling.html for a full description
macro_rules! impl_from {
    ( $from_t:path, $to_t:path, $enum_t:path ) => {
        impl From<$from_t> for $enum_t {
            fn from(err: $from_t) -> $enum_t {
                $to_t(err)
            }
        }
    }
}

// All the impls for RequestError
impl_from!(hyper::error::Error, RequestError::Hyper, RequestError);
impl_from!(std::io::Error, RequestError::Io, RequestError);
impl_from!(rustc_serialize::json::DecoderError,
           RequestError::JsonDec,
           RequestError);
impl_from!(rustc_serialize::json::EncoderError,
           RequestError::JsonEnc,
           RequestError);
impl_from!(ApiError, RequestError::Api, RequestError);

// Checks for 4xx or 5xx errors and returns the appropriate ApiError
fn check_http_error(res: &Response) -> Result<(), ApiError> {
    match res.status.class() {
        StatusClass::ClientError => Err(ApiError::ClientError),
        StatusClass::ServerError => Err(ApiError::ServerError),
        _ => Ok(()),
    }
}

// Do the OAUTH stuff for my.mlh.io
// TODO: Something better about the long api urls
fn do_request(code: &str) -> Result<Data, RequestError> {
    let id = env_err!("ID");
    let secret = env_err!("SECRET");
    let redirect = env_err!("REDIRECT");

    let url = format!("https://my.mlh.io/oauth/token?client_id={}&\
                      client_secret={}&code={}&redirect_uri={}&\
                      grant_type=authorization_code",
                      id,
                      secret,
                      code,
                      redirect);

    let client = Client::new();
    let mut res = try!(client.post(&url)
        .header(Connection::close())
        .send());

    try!(check_http_error(&res));

    let mut body = String::new();
    try!(res.read_to_string(&mut body));

    let token: TokenResp = try!(json::decode(&body));
    let url2 = format!("https://my.mlh.io/api/v2/user?access_token={}",
                       token.access_token);

    res = try!(client.get(&url2)
        .header(Connection::close())
        .send());

    try!(check_http_error(&res));

    body = String::new();
    try!(res.read_to_string(&mut body));

    let person_data: Data = try!(json::decode(&body));

    Ok(person_data)
}

// Send a message to slack when a new user signs up
fn slack_send(user: User) -> Result<(), RequestError> {
    let url = env_err!("SLACKURL");
    let client = Client::new();
    let payload = Payload {
        channel: "#signups".to_string(),
        username: "Signup bot".to_string(),
        icon_emoji: ":hackcwru:".to_string(),
        text: format!("{}, a {} major from {}, has signed up!",
                      user.first_name,
                      user.major,
                      user.school.name),
    };
    let payload_str = try!(json::encode(&payload));
    let res = try!(client.post(&url)
        .body(&payload_str)
        .send());

    try!(check_http_error(&res));

    Ok(())
}

// Create the table if it doesn't exist.  Runs on each startup
fn create_table(conn: PooledConnection<PostgresConnectionManager>) {
    let _r =
        conn.execute("CREATE TABLE IF NOT EXISTS person (
                id SERIAL PRIMARY KEY,
                email VARCHAR NOT NULL,
                created_at VARCHAR NOT NULL,
                updated_at VARCHAR NOT NULL,
                first_name VARCHAR NOT NULL,
                last_name VARCHAR NOT NULL,
                graduation VARCHAR,
                major VARCHAR NOT NULL,
                shirt_size VARCHAR NOT NULL,
                dietary_restrictions VARCHAR NOT NULL,
                special_needs VARCHAR,
                date_of_birth VARCHAR NOT NULL,
                gender VARCHAR NOT NULL,
                phone_number VARCHAR NOT NULL,
                school_id integer,
                school_name VARCHAR
                )",
            &[]
        );
    let _r = conn.execute("ALTER TABLE person ADD COLUMN year integer \
                          NOT NULL DEFAULT 2016",
                          &[]);
    let _r = conn.execute("ALTER TABLE person ALTER COLUMN graduation \
                          DROP NOT NULL",
                          &[]);
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signup_time VARCHAR", &[]
        );
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signed_in
            BOOLEAN NOT NULL DEFAULT FALSE",
        &[]
        );
    let _r = conn.execute(
            "ALTER TABLE person ADD COLUMN signed_in_time VARCHAR", &[]
        );

    let _r = conn.execute(
            "ALTER TABLE person DROP CONSTRAINT person_pkey", &[]
        );

    let _r = conn.execute(
            "ALTER TABLE person ADD PRIMARY KEY (id, year)", &[]
        );
}

fn main() {
    let mut app = Nickel::new();

    let postgres_url = env_err!("DATABASE");
    let dbpool =
        PostgresMiddleware::new(&*postgres_url, TlsMode::None, 5, Box::new(NopErrorHandler))
            .expect("Failed to start PostgresMiddleware");

    create_table(dbpool.pool.clone().get().unwrap());
    app.utilize(dbpool);

    app.get("/callback", middleware! { |request, mut response|
        let conn = request.db_conn();
        let redirect_success = env_err!("FINALREDIRECT");
        let redirect_failure = env_err!("REDIRECTERR");
        let year = env_err!("YEAR").parse::<i32>().unwrap();
        let code = match request.query().get("code") {
            Some(s) => s,
            None => {
                println!("No code, quitting");
                return response.error(StatusCode::BadRequest, "Failed");
            }
        };
        let user_data = match do_request(code) {
            Ok(s) => s,
            Err(e) => {
                println!("Get user data failed with error: {:?}", e);
                return response
                    .error(StatusCode::InternalServerError, "Failed");
            }
        }.data;

        let now = now();
        let now_s = format!("{}", now.rfc3339());
        // TODO: make this a function
        let r = conn.execute(
                "INSERT INTO person (id, email, created_at, updated_at,
                first_name, last_name, major, shirt_size,
                dietary_restrictions, special_needs, date_of_birth, gender,
                phone_number, school_id, school_name, year, signup_time) VALUES
                ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14,
                $15, $16, $17)",
                &[&user_data.id, &user_data.email, &user_data.created_at,
                  &user_data.updated_at, &user_data.first_name,
                  &user_data.last_name, &user_data.major,
                  &user_data.shirt_size, &user_data.dietary_restrictions,
                  &user_data.special_needs, &user_data.date_of_birth,
                  &user_data.gender, &user_data.phone_number,
                  &user_data.school.id, &user_data.school.name, &year, &now_s]
            );
        let redirect = match r {
            Ok(v) => {
                println!("Add to database succeeded with status {:?}", v);
                match slack_send(user_data) {
                    Ok(_) => println!("Slack send worked"),
                    Err(e) => println!("Slack send failed with error: {:?}", e)
                }
                redirect_success
            },
            Err(e) => {
                println!("Add to database failed: {:?}", e);
                redirect_failure
            }
        };

        return response.redirect(&redirect[..]);
    });

    app.get("/start", middleware! { |_req, response|
        let id = env_err!("ID");
        let redirect = env_err!("REDIRECT");
        return response.redirect(
            format!(
                    "http://my.mlh.io/oauth/authorize?client_id={}&\
                    redirect_uri={}&response_type=code",
                    id, redirect
                )
            );
    });

    let bind = match env::var("BIND") {
        Ok(v) => v,
        Err(_) => "127.0.0.1:8080".to_string(),
    };

    let _ = app.listen(&bind[..]);
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::path::Path;
use std::fs::File;
use std::clone::Clone;
use std::str::Lines;
use std::io::prelude::*;
use std::io::BufReader;

// Device Tree stucture
/*
struct DeviceTree<'a> {
	version: u32,
	boot_cpuid: u32,
	reserved_mem: Vec<(u64, u64)>,
	root: Node<'a, 'a>,
}

struct DeviceNode<'a, 'b> {
	name: String,
	props: Vec<(String, Property<'a>)>,
	children: Vec<DeviceNode<'b, 'b>>,
}

enum Property<'a> {
	Empty,
	Cells(Vec<u32>),
	String(String),
	ByteString(Vec<u8>),
	Combo(Vec<&'a Property<'a>>),
}
*/

// File tracking
#[derive(Debug)]
struct ParsedFile<'a> {
	path: &'a Path,
	file: File,
	method: IncludeMethod<'a>,
	included_files: Vec<ParsedFile<'a>>,
}

#[derive(Debug)]
enum IncludeMethod<'a> {
	DTS,
	CPP(&'a File, Vec<(FileSlice, FileSlice)>),
}

#[derive(Debug)]
struct FileSlice {
	start: usize,
	len: usize,
}

// Change tracking
/*
struct Change<'a> {
	file: File,
	line: usize,
	// maybe point to node?
	name: String,
	value: Property<'a>,
}
*/

impl<'a> ParsedFile<'a> {
	fn new(path: &'a Path, method: IncludeMethod<'a>) -> ParsedFile<'a> {
		ParsedFile {
			path: path,
			file: File::open(path).unwrap(),
			method: method,
			included_files: vec![],
		}
	}
/*
	fn print(&self, depth: usize) -> String {

	}
*/
}
/*
impl<'a> fmt::Display for ParsedFile<'a> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{:?}: {}", self.file, self.method)
		//Name: method
		//|- Next one
	}
}
*/

fn main() {
	// let file_name = "am335x-boneblack.dts";
	let file_name = match env::args().nth(1) {
		None => {
			println!("You forgot the dts file, you dummy");
			return;
		},
		Some(x) => x,
	};

	// arm-linux-gnueabi-gcc -H -E -nostdinc -Iarch/arm/boot/dts -Iarch/arm/boot/dts/include -undef -D__DTS__ -x assembler-with-cpp -o /dev/null arch/arm/boot/dts/versatile-ab.dts
	let arch = "arm";
	let dts_folder = format!("arch/{}/boot/dts/", arch);
	let file_path = format!("{}{}", dts_folder, file_name);

	let include_output = Command::new("arm-linux-gnueabi-gcc")
								.args(&["-H", "-E", "-nostdinc"])
								.arg(format!("-I{}", dts_folder))
								.arg(format!("-I{}include/", dts_folder))
								.args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
								.args(&["-o", "dts_viewer_tmp.dts"])
								.arg(&file_path)
								.output()
								.expect("failed to execute process"); //TODO: properly handle errors

	let global_file = File::open("dts_viewer_tmp.dts").unwrap();

	let cpp_output = String::from_utf8_lossy(&include_output.stderr);
	println!("{}", cpp_output);

	let mut main_file = ParsedFile::new(
			&Path::new(&file_path),
			IncludeMethod::CPP(&global_file, vec![])
	);

	parse_cpp_output(&mut cpp_output.lines(), &mut main_file, &global_file, 0);

	let global_buffer = BufReader::new(File::open("dts_viewer_tmp.dts").unwrap());
	let mut line_num = 0;
	for line in global_buffer.lines() {
		if let Ok(line) = line {
			line_num += 1;
			if !line.starts_with('#') {
				continue;
			}

			//parse this shit
			let tokens: Vec<&str> = line.split('"').map(|s| s.trim_matches('#').trim()).collect();
/*
			if !main_file.contains(tokens[1]) {
				println!("Not found: {:?}", tokens);
				continue;
			}
*/
			println!("{:?}", tokens);
		} else {
			//set last end as final line num count
		}
	}
}

fn count_begining_chars(s: &str, c: char) -> usize {
	let mut count: usize = 0;
	for sc in s.chars() {
		if sc == c {
			count += 1;
		} else {
			break;
		}
	}

	count
}

fn parse_cpp_output<'a>(lines: &mut Lines<'a>, parrent_file: &mut ParsedFile<'a>, global_file: &'a File, depth: usize) {
	while let Some(line) = lines.clone().next() {
		let count = count_begining_chars(line, '.');

		if count == 0 {
			return;
		} else if count < depth {
			return;
		} else if count == depth {
			return;
		} else if count > depth && (count - depth) == 1 {
			parrent_file.included_files.push(
				ParsedFile::new(
					&Path::new(lines.next().unwrap().trim_left_matches('.').trim_left()),
					IncludeMethod::CPP(&global_file, vec![])
				)
			);
			parse_cpp_output(lines, parrent_file.included_files.last_mut().unwrap(), global_file, depth + 1);
		} else {
			panic!("Match that should not have been reached.");
		}
	}
}
/*
fn find_included_lines_end(lines: &mut Lines, start_tokens: &[&str], start_line: usize) -> (FileSlice, FileSlice) {

}
*/<commit_msg>Taught program how to parse CPP linemarkers<commit_after>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::clone::Clone;
use std::str::Lines;
use std::io::prelude::*;
use std::io::BufReader;

// Device Tree stucture
/*
struct DeviceTree<'a> {
	version: u32,
	boot_cpuid: u32,
	reserved_mem: Vec<(u64, u64)>,
	root: Node<'a, 'a>,
}

struct DeviceNode<'a, 'b> {
	name: String,
	props: Vec<(String, Property<'a>)>,
	children: Vec<DeviceNode<'b, 'b>>,
}

enum Property<'a> {
	Empty,
	Cells(Vec<u32>),
	String(String),
	ByteString(Vec<u8>),
	Combo(Vec<&'a Property<'a>>),
}
*/

// File tracking
#[derive(Debug)]
struct ParsedFile<'a> {
	path: &'a Path,
	file: File,
	method: IncludeMethod<'a>,
	included_files: Vec<ParsedFile<'a>>,
}

#[derive(Debug)]
enum IncludeMethod<'a> {
	DTS,
	CPP(&'a File, Vec<FileMapping>),
}

#[derive(Debug)]
struct FileMapping {
	parent_start: usize,
	child_start: usize,
	len: usize,
}

#[derive(Debug)]
enum LinemarkerFlag {
	Start,
	Return,
	System,
	Extern,
}

// Change tracking
/*
struct Change<'a> {
	file: File,
	line: usize,
	// maybe point to node?
	name: String,
	value: Property<'a>,
}
*/

impl<'a> ParsedFile<'a> {
	fn new(path: &'a Path, method: IncludeMethod<'a>) -> ParsedFile<'a> {
		ParsedFile {
			path: path,
			file: File::open(path).unwrap(),
			method: method,
			included_files: vec![],
		}
	}
}
/*
impl<'a> fmt::Display for ParsedFile<'a> {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{:?}: {}", self.file, self.method)
		//Name: method
		//|- Next one
	}
}
*/

const CPP_OUTPUT_NAME: &'static str = "dts_viewer_tmp.dts";

fn main() {
	// let file_name = "am335x-boneblack.dts";
	let file_name = match env::args().nth(1) {
		None => {
			println!("You forgot the dts file, you dummy");
			return;
		}
		Some(x) => x,
	};

	let arch = "arm";
	let dts_folder = format!("arch/{}/boot/dts/", arch);
	let file_path = format!("{}{}", dts_folder, file_name);

	let include_output = Command::new("arm-linux-gnueabi-gcc")
		.args(&["-H", "-E", "-nostdinc"])
		.arg(format!("-I{}", dts_folder))
		.arg(format!("-I{}include/", dts_folder))
		.args(&["-undef", "-D__DTS__", "-x", "assembler-with-cpp"])
		.args(&["-o", CPP_OUTPUT_NAME])
		.arg(&file_path)
		.output()
		.expect("failed to execute process"); //TODO: properly handle errors

	let global_file = File::open(CPP_OUTPUT_NAME).unwrap();

	let cpp_output = String::from_utf8_lossy(&include_output.stderr);
	println!("{}", cpp_output);

	let mut main_file = ParsedFile::new(&Path::new(&file_path),
										IncludeMethod::CPP(&global_file, vec![]));

	parse_cpp_output(&mut cpp_output.lines(), &mut main_file, &global_file, 0);

	let global_buffer = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap());
	let mut parsed_lines = global_buffer.lines()
		.enumerate()
		.filter(|&(_, ref line)| match *line {
			Ok(ref l) => l.starts_with('#'),
			Err(_) => false,
		})
		.map(|(line_num, line)| {
			let line = line.unwrap();
			let tokens: Vec<&str> = line.split('"').map(|s| s.trim_matches('#').trim()).collect();
			let child_num: usize = tokens[0].parse().unwrap();
			let flag = match tokens[2].parse().unwrap_or(0) { //TODO: make conversion function
				1 => Some(LinemarkerFlag::Start),
				2 => Some(LinemarkerFlag::Return),
				3 => Some(LinemarkerFlag::System),
				4 => Some(LinemarkerFlag::Extern),
				_ => None,
			};
			(line_num + 1, child_num, tokens[1].to_string(), flag)
		})
		.peekable();

	while let Some((path, mapping)) =
		parse_cpp_linemarkers(&parsed_lines.next(), &parsed_lines.peek()) {
		if mapping.len > 1 {
			println!("{:?} {:?}", path, mapping);
			// find file in ParsedFile tree
			// add mapping to vec
		}
	}
}

fn count_begining_chars(s: &str, c: char) -> usize {
	let mut count: usize = 0;
	for sc in s.chars() {
		if sc == c {
			count += 1;
		} else {
			break;
		}
	}

	count
}

fn parse_cpp_output<'a>(lines: &mut Lines<'a>,
						parrent_file: &mut ParsedFile<'a>,
						global_file: &'a File,
						depth: usize) {
	while let Some(line) = lines.clone().next() { //TODO: try to use Peekable again. Had problems with recursion before
		let count = count_begining_chars(line, '.');

		if count == 0 {
			return;
		} else if count < depth {
			return;
		} else if count == depth {
			return;
		} else if count > depth && (count - depth) == 1 {
			parrent_file.included_files.push(
					ParsedFile::new(
							&Path::new(lines.next()
								.unwrap()
								.trim_left_matches('.')
								.trim_left()),
							IncludeMethod::CPP(&global_file, vec![])
			));
			parse_cpp_output(lines,
							 parrent_file.included_files.last_mut().unwrap(),
							 global_file,
							 depth + 1);
		} else {
			panic!("Match that should not have been reached.");
		}
	}
}

fn parse_cpp_linemarkers(current: &Option<(usize, usize, String, Option<LinemarkerFlag>)>,
						next: &Option<&(usize, usize, String, Option<LinemarkerFlag>)>)
						-> Option<(PathBuf, FileMapping)> {
	if let Some((c_line_num, c_child_num, ref c_path, _)) = *current {
		if let Some(&(n_line_num, _, _, _)) = *next {
			Some((PathBuf::from(c_path),
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: n_line_num - c_line_num,
			}))
		} else {
			let last_line = BufReader::new(File::open(CPP_OUTPUT_NAME).unwrap())
				.lines()
				.count(); //TODO: don't use lines() as that allocates new Strings on the heap
			Some((PathBuf::from(c_path),
				FileMapping {
					parent_start: c_line_num + 1,
					child_start: c_child_num,
					len: last_line - c_line_num, // TODO: find length of file
			}))
		}
	} else {
		None
	}
}
<|endoftext|>


<commit_before>mod cmd;
mod config;
mod edit;
mod error;
mod fmt;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use atty::Stream::{Stderr, Stdout};
use prettyprint::{PagingMode, PrettyPrinter};
use quote::quote;
use structopt::StructOpt;
use termcolor::{Color::Green, ColorChoice, ColorSpec, StandardStream, WriteColor};

use crate::cmd::Line;
use crate::config::Config;
use crate::error::Result;
use crate::opts::Coloring::*;
use crate::opts::{Args, Coloring, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();
    let config = config::deserialize();

    if args.themes {
        for theme in PrettyPrinter::default()
            .build()
            .unwrap()
            .get_themes()
            .keys()
        {
            let _ = writeln!(io::stdout(), "{}", theme);
        }
        return Ok(0);
    }

    let rustfmt;
    match (&args.item, args.ugly) {
        (Some(item), true) => {
            let _ = writeln!(
                io::stderr(),
                "ERROR: cannot expand single item ({}) in ugly mode.",
                item,
            );
            return Ok(1);
        }
        (Some(item), false) => {
            rustfmt = which_rustfmt();
            if rustfmt.is_none() {
                let _ = writeln!(
                    io::stderr(),
                    "ERROR: cannot expand single item ({}) without rustfmt.",
                    item,
                );
                let _ = writeln!(
                    io::stderr(),
                    "Install rustfmt by running `rustup component add rustfmt --toolchain nightly`.",
                );
                return Ok(1);
            }
        }
        (None, true) => rustfmt = None,
        (None, false) => rustfmt = which_rustfmt(),
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");
    let color = get_color(&args, &config);

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &color, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    if !outfile_path.exists() {
        return Ok(1);
    }

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(io::stderr(), "ERROR: rustc produced no expanded output",);
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    if let Some(rustfmt) = rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::sanitize(&mut syntax_tree);
            if let Some(filter) = args.item {
                syntax_tree.shebang = None;
                syntax_tree.attrs.clear();
                syntax_tree.items = filter.apply_to(&syntax_tree);
                if syntax_tree.items.is_empty() {
                    let _ = writeln!(io::stderr(), "WARNING: no such item: {}", filter);
                    return Ok(1);
                }
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        fmt::write_rustfmt_config(&outdir)?;

        // Ignore any errors.
        let _status = Command::new(rustfmt)
            .arg("--edition=2018")
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .status();

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let theme = args.theme.or(config.theme);
    let none_theme = theme.as_ref().map(String::as_str) == Some("none");
    let do_color = match color {
        Always => true,
        Never => false,
        Auto => !none_theme && atty::is(Stdout),
    };
    let _ = writeln!(io::stderr());
    if do_color {
        if content.ends_with('\n') {
            // Pretty printer seems to print an extra trailing newline.
            content.truncate(content.len() - 1);
        }

        let mut builder = PrettyPrinter::default();
        builder.header(false);
        builder.grid(false);
        builder.line_numbers(false);
        builder.language("rust");
        builder.paging_mode(PagingMode::Never);

        if let Some(theme) = theme {
            builder.theme(theme);
        }

        let printer = builder.build().unwrap();

        // Ignore any errors.
        let _ = printer.string(content);
    } else {
        let _ = write!(io::stdout(), "{}", content);
    }

    Ok(0)
}

fn which_rustfmt() -> Option<PathBuf> {
    match env::var_os("RUSTFMT") {
        Some(which) => {
            if which.is_empty() {
                None
            } else {
                Some(PathBuf::from(which))
            }
        }
        None => toolchain_find::find_installed_component("rustfmt"),
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, color: &Coloring, outfile: &Path) {
    let mut line = Line::new("cargo");

    line.arg("rustc");

    if args.tests && args.test.is_none() {
        line.arg("--profile=test");
    } else {
        line.arg("--profile=check");
    }

    if let Some(features) = &args.features {
        line.arg("--features");
        line.arg(features);
    }

    if args.all_features {
        line.arg("--all-features");
    }

    if args.no_default_features {
        line.arg("--no-default-features");
    }

    if args.lib {
        line.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        line.arg("--bin");
        line.arg(bin);
    }

    if let Some(example) = &args.example {
        line.arg("--example");
        line.arg(example);
    }

    if let Some(test) = &args.test {
        line.arg("--test");
        line.arg(test);
    }

    if let Some(bench) = &args.bench {
        line.arg("--bench");
        line.arg(bench);
    }

    if let Some(target) = &args.target {
        line.arg("--target");
        line.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        line.arg("--target-dir");
        line.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        line.arg("--manifest-path");
        line.arg(manifest_path);
    }

    if let Some(package) = &args.package {
        line.arg("--package");
        line.arg(package);
    }

    if let Some(jobs) = args.jobs {
        line.arg("--jobs");
        line.arg(jobs.to_string());
    }

    if args.verbose {
        line.arg("--verbose");
    }

    line.arg("--color");
    match color {
        Coloring::Auto => line.arg(if atty::is(Stderr) { "always" } else { "never" }),
        color => line.arg(color.to_string()),
    }

    if args.frozen {
        line.arg("--frozen");
    }

    if args.locked {
        line.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        line.arg("-Z");
        line.arg(unstable_flag);
    }

    line.arg("--");

    line.arg("-o");
    line.arg(outfile);
    line.arg("-Zunstable-options");
    line.arg("--pretty=expanded");

    if args.verbose {
        let mut display = line.clone();
        display.insert(0, "+nightly");
        print_command(display, color);
    }

    cmd.args(line);
}

fn print_command(line: Line, color: &Coloring) {
    let color_choice = match color {
        Coloring::Auto => ColorChoice::Auto,
        Coloring::Always => ColorChoice::Always,
        Coloring::Never => ColorChoice::Never,
    };

    let mut stream = StandardStream::stderr(color_choice);
    let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Green)));
    let _ = write!(stream, "{:>12}", "Running");
    let _ = stream.reset();
    let _ = writeln!(stream, " `{}`", line);
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}

fn get_color(args: &Args, config: &Config) -> Coloring {
    if let Some(value) = args.color {
        return value;
    }

    if let Some(value) = config.color.as_ref() {
        match Coloring::from_str(value.as_str()) {
            Ok(color) => return color,
            Err(err) => {
                let _ = writeln!(
                    io::stderr(),
                    "WARNING: invalid color in cargo config: {}",
                    err
                );
            }
        }
    }

    Coloring::Auto // default
}
<commit_msg>Format with rustfmt 2020-03-11<commit_after>mod cmd;
mod config;
mod edit;
mod error;
mod fmt;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command, Stdio};
use std::str::FromStr;

use atty::Stream::{Stderr, Stdout};
use prettyprint::{PagingMode, PrettyPrinter};
use quote::quote;
use structopt::StructOpt;
use termcolor::{Color::Green, ColorChoice, ColorSpec, StandardStream, WriteColor};

use crate::cmd::Line;
use crate::config::Config;
use crate::error::Result;
use crate::opts::Coloring::*;
use crate::opts::{Args, Coloring, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();
    let config = config::deserialize();

    if args.themes {
        for theme in PrettyPrinter::default()
            .build()
            .unwrap()
            .get_themes()
            .keys()
        {
            let _ = writeln!(io::stdout(), "{}", theme);
        }
        return Ok(0);
    }

    let rustfmt;
    match (&args.item, args.ugly) {
        (Some(item), true) => {
            let _ = writeln!(
                io::stderr(),
                "ERROR: cannot expand single item ({}) in ugly mode.",
                item,
            );
            return Ok(1);
        }
        (Some(item), false) => {
            rustfmt = which_rustfmt();
            if rustfmt.is_none() {
                let _ = writeln!(
                    io::stderr(),
                    "ERROR: cannot expand single item ({}) without rustfmt.",
                    item,
                );
                let _ = writeln!(
                    io::stderr(),
                    "Install rustfmt by running `rustup component add rustfmt --toolchain nightly`.",
                );
                return Ok(1);
            }
        }
        (None, true) => rustfmt = None,
        (None, false) => rustfmt = which_rustfmt(),
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");
    let color = get_color(&args, &config);

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &color, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    if !outfile_path.exists() {
        return Ok(1);
    }

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(io::stderr(), "ERROR: rustc produced no expanded output");
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    if let Some(rustfmt) = rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::sanitize(&mut syntax_tree);
            if let Some(filter) = args.item {
                syntax_tree.shebang = None;
                syntax_tree.attrs.clear();
                syntax_tree.items = filter.apply_to(&syntax_tree);
                if syntax_tree.items.is_empty() {
                    let _ = writeln!(io::stderr(), "WARNING: no such item: {}", filter);
                    return Ok(1);
                }
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        fmt::write_rustfmt_config(&outdir)?;

        // Ignore any errors.
        let _status = Command::new(rustfmt)
            .arg("--edition=2018")
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .status();

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let theme = args.theme.or(config.theme);
    let none_theme = theme.as_ref().map(String::as_str) == Some("none");
    let do_color = match color {
        Always => true,
        Never => false,
        Auto => !none_theme && atty::is(Stdout),
    };
    let _ = writeln!(io::stderr());
    if do_color {
        if content.ends_with('\n') {
            // Pretty printer seems to print an extra trailing newline.
            content.truncate(content.len() - 1);
        }

        let mut builder = PrettyPrinter::default();
        builder.header(false);
        builder.grid(false);
        builder.line_numbers(false);
        builder.language("rust");
        builder.paging_mode(PagingMode::Never);

        if let Some(theme) = theme {
            builder.theme(theme);
        }

        let printer = builder.build().unwrap();

        // Ignore any errors.
        let _ = printer.string(content);
    } else {
        let _ = write!(io::stdout(), "{}", content);
    }

    Ok(0)
}

fn which_rustfmt() -> Option<PathBuf> {
    match env::var_os("RUSTFMT") {
        Some(which) => {
            if which.is_empty() {
                None
            } else {
                Some(PathBuf::from(which))
            }
        }
        None => toolchain_find::find_installed_component("rustfmt"),
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, color: &Coloring, outfile: &Path) {
    let mut line = Line::new("cargo");

    line.arg("rustc");

    if args.tests && args.test.is_none() {
        line.arg("--profile=test");
    } else {
        line.arg("--profile=check");
    }

    if let Some(features) = &args.features {
        line.arg("--features");
        line.arg(features);
    }

    if args.all_features {
        line.arg("--all-features");
    }

    if args.no_default_features {
        line.arg("--no-default-features");
    }

    if args.lib {
        line.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        line.arg("--bin");
        line.arg(bin);
    }

    if let Some(example) = &args.example {
        line.arg("--example");
        line.arg(example);
    }

    if let Some(test) = &args.test {
        line.arg("--test");
        line.arg(test);
    }

    if let Some(bench) = &args.bench {
        line.arg("--bench");
        line.arg(bench);
    }

    if let Some(target) = &args.target {
        line.arg("--target");
        line.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        line.arg("--target-dir");
        line.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        line.arg("--manifest-path");
        line.arg(manifest_path);
    }

    if let Some(package) = &args.package {
        line.arg("--package");
        line.arg(package);
    }

    if let Some(jobs) = args.jobs {
        line.arg("--jobs");
        line.arg(jobs.to_string());
    }

    if args.verbose {
        line.arg("--verbose");
    }

    line.arg("--color");
    match color {
        Coloring::Auto => line.arg(if atty::is(Stderr) { "always" } else { "never" }),
        color => line.arg(color.to_string()),
    }

    if args.frozen {
        line.arg("--frozen");
    }

    if args.locked {
        line.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        line.arg("-Z");
        line.arg(unstable_flag);
    }

    line.arg("--");

    line.arg("-o");
    line.arg(outfile);
    line.arg("-Zunstable-options");
    line.arg("--pretty=expanded");

    if args.verbose {
        let mut display = line.clone();
        display.insert(0, "+nightly");
        print_command(display, color);
    }

    cmd.args(line);
}

fn print_command(line: Line, color: &Coloring) {
    let color_choice = match color {
        Coloring::Auto => ColorChoice::Auto,
        Coloring::Always => ColorChoice::Always,
        Coloring::Never => ColorChoice::Never,
    };

    let mut stream = StandardStream::stderr(color_choice);
    let _ = stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Green)));
    let _ = write!(stream, "{:>12}", "Running");
    let _ = stream.reset();
    let _ = writeln!(stream, " `{}`", line);
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}

fn get_color(args: &Args, config: &Config) -> Coloring {
    if let Some(value) = args.color {
        return value;
    }

    if let Some(value) = config.color.as_ref() {
        match Coloring::from_str(value.as_str()) {
            Ok(color) => return color,
            Err(err) => {
                let _ = writeln!(
                    io::stderr(),
                    "WARNING: invalid color in cargo config: {}",
                    err
                );
            }
        }
    }

    Coloring::Auto // default
}
<|endoftext|>


<commit_before>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() {
    let config = Config::default().expect("cargo config");
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config).expect("cargo workspace");
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws).expect("resolve workspace");

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id).expect("get package ids");
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package);
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses").expect("write");
        writeln!(tw, "----\t| -------\t| --------").expect("write");
        for (name, version, licenses, _) in packages.clone() {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses).expect("write");
        }
        tw.flush().expect("tw.flush"); // TabWriter flush() makes the actual write to stdout.
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        for file in license_files {
            let mut fs = std::fs::File::open(file).expect("File::open");
            fs.read_to_end(&mut buf).expect("read_to_end");
            out.write_all(&buf).expect("write_all");
            buf.clear();
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(|s| s.trim())
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

fn package_license_files(package: &Package) -> Vec<path::PathBuf> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir().expect("read_dir call failed") {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    if name.starts_with("LICENSE") {
                        result.push(entry.path())
                    }
                }
            }
        }
    }

    result
}
<commit_msg>Fix Clippy nag<commit_after>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io::prelude::*;
use std::io;
use std::path;
use std::str;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() {
    let config = Config::default().expect("cargo config");
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config).expect("cargo workspace");
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws).expect("resolve workspace");

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id).expect("get package ids");
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package);
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses").expect("write");
        writeln!(tw, "----\t| -------\t| --------").expect("write");
        for (name, version, licenses, _) in packages.clone() {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses).expect("write");
        }
        tw.flush().expect("tw.flush"); // TabWriter flush() makes the actual write to stdout.
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        for file in license_files {
            let mut fs = std::fs::File::open(file).expect("File::open");
            fs.read_to_end(&mut buf).expect("read_to_end");
            out.write_all(&buf).expect("write_all");
            buf.clear();
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(str::trim)
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

fn package_license_files(package: &Package) -> Vec<path::PathBuf> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir().expect("read_dir call failed") {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    if name.starts_with("LICENSE") {
                        result.push(entry.path())
                    }
                }
            }
        }
    }

    result
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::collections::HashMap;

use std::ops::{Add, Sub, Mul, Div};

struct Evaluator(HashMap<String, f64>);

impl Evaluator {
  fn new() -> Evaluator { Evaluator(HashMap::new()) }

  fn get(&self, key: &str) -> f64 { self.0.get(key).cloned().unwrap() }

  fn set(&mut self, key: &str, val: f64) { *self.0.entry(key.to_owned()).or_insert(0.0) = val; }

  fn substitute(&mut self, expr: &Json) -> f64 {
    match *expr {
      Json::Array(ref arr) => self.eval(arr.as_slice()).as_f64().unwrap(),
      Json::F64(ref i) => *i,
      Json::I64(ref i) => *i as f64,
      Json::U64(ref i) => *i as f64,
      _ => panic!("cannot substitute: {:?} (env: {:?})", expr, self.0)
    }
  }

  fn eval(&mut self, input: &[Json]) -> Json {
    let token = input[0].as_string().unwrap();
    let args = &input[1..];

    match token {
      "step" => self.eval_step(args),
      "until" => self.eval_until(args),

      "get" => self.eval_get(args),
      "set" => self.eval_set(args),

      "==" => self.eval_cmp(args, |l, r| l == r),
      "!=" => self.eval_cmp(args, |l, r| l != r),
      ">" => self.eval_cmp(args, |l, r| l > r),
      ">=" => self.eval_cmp(args, |l, r| l >= r),
      "<" => self.eval_cmp(args, |l, r| l < r),
      "<=" => self.eval_cmp(args, |l, r| l <= r),

      "+" => self.eval_binop(args, Add::add),
      "-" => self.eval_binop(args, Sub::sub),
      "*" => self.eval_binop(args, Mul::mul),
      "/" => self.eval_binop(args, Div::div),

      _ => panic!("invalid token: {:?}", token)
    }
  }

  fn eval_step(&mut self, lines: &[Json]) -> Json {
    let ret = self.eval(lines[0].as_array().unwrap().as_slice());
    if lines.len() == 1 {
      ret
    } else {
      self.eval_step(&lines[1..])
    }
  }

  fn eval_until(&mut self, args: &[Json]) -> Json {
    loop {
      let c = self.eval(args[0].as_array().unwrap().as_slice());
      if c.is_boolean() && c.as_boolean().unwrap() {
        return Json::Null;
      }
      self.eval(args[1].as_array().unwrap().as_slice());
    }
  }

  fn eval_get(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    Json::F64(self.get(key))
  }

  fn eval_set(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    let val = self.substitute(&args[1]);
    self.set(key, val);
    Json::Null
  }

  fn eval_cmp<C>(&mut self, args: &[Json], cmp: C) -> Json
    where C: Fn(f64, f64) -> bool
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::Boolean(cmp(lhs, rhs))
  }

  fn eval_binop<O>(&mut self, args: &[Json], op: O) -> Json
    where O: Fn(f64, f64) -> f64
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::F64(op(lhs, rhs))
  }
}

fn parse(source: &str) -> Vec<Json> { Json::from_str(source).unwrap().as_array().unwrap().to_owned() }

fn main() {
  let source = r#"
["step",
  ["set", "i", 10],
  ["set", "sum", 0],
  ["until", ["==", ["get", "i"], 0], [
    "step",
    ["set", "sum", ["+", ["get", "sum"], ["get", "i"]]],
    ["set", "i", ["+", ["get", "i"], -1]]
  ]],
  ["get", "sum"]
]
"#;
  let input = parse(source);

  let mut e = Evaluator::new();

  println!("{:?}", e.eval(input.as_slice()));
}
<commit_msg>remove redundant operators & method calls<commit_after>extern crate rustc_serialize;
use rustc_serialize::json::Json;
use std::collections::HashMap;

use std::ops::{Add, Sub, Mul, Div};

struct Evaluator(HashMap<String, f64>);

impl Evaluator {
  fn new() -> Evaluator { Evaluator(HashMap::new()) }

  fn get(&self, key: &str) -> f64 { *self.0.get(key).unwrap() }

  fn set(&mut self, key: &str, val: f64) { self.0.insert(key.to_owned(), val); }

  fn substitute(&mut self, expr: &Json) -> f64 {
    match *expr {
      Json::Array(ref arr) => self.eval(arr.as_slice()).as_f64().unwrap(),
      Json::F64(i) => i,
      Json::I64(i) => i as f64,
      Json::U64(i) => i as f64,
      _ => panic!("cannot substitute: {:?} (env: {:?})", expr, self.0)
    }
  }

  fn eval(&mut self, input: &[Json]) -> Json {
    let token = input[0].as_string().unwrap();
    let args = &input[1..];

    match token {
      "step" => self.eval_step(args),
      "until" => self.eval_until(args),

      "get" => self.eval_get(args),
      "set" => self.eval_set(args),

      "==" => self.eval_cmp(args, |l, r| l == r),
      "!=" => self.eval_cmp(args, |l, r| l != r),
      ">" => self.eval_cmp(args, |l, r| l > r),
      ">=" => self.eval_cmp(args, |l, r| l >= r),
      "<" => self.eval_cmp(args, |l, r| l < r),
      "<=" => self.eval_cmp(args, |l, r| l <= r),

      "+" => self.eval_binop(args, Add::add),
      "-" => self.eval_binop(args, Sub::sub),
      "*" => self.eval_binop(args, Mul::mul),
      "/" => self.eval_binop(args, Div::div),

      _ => panic!("invalid token: {:?}", token)
    }
  }

  fn eval_step(&mut self, lines: &[Json]) -> Json {
    let ret = self.eval(lines[0].as_array().unwrap().as_slice());
    if lines.len() == 1 {
      ret
    } else {
      self.eval_step(&lines[1..])
    }
  }

  fn eval_until(&mut self, args: &[Json]) -> Json {
    loop {
      let c = self.eval(args[0].as_array().unwrap().as_slice());
      if c.is_boolean() && c.as_boolean().unwrap() {
        return Json::Null;
      }
      self.eval(args[1].as_array().unwrap().as_slice());
    }
  }

  fn eval_get(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    Json::F64(self.get(key))
  }

  fn eval_set(&mut self, args: &[Json]) -> Json {
    let key = args[0].as_string().unwrap();
    let val = self.substitute(&args[1]);
    self.set(key, val);
    Json::Null
  }

  fn eval_cmp<C>(&mut self, args: &[Json], cmp: C) -> Json
    where C: Fn(f64, f64) -> bool
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::Boolean(cmp(lhs, rhs))
  }

  fn eval_binop<O>(&mut self, args: &[Json], op: O) -> Json
    where O: Fn(f64, f64) -> f64
  {
    let lhs = self.substitute(&args[0]);
    let rhs = self.substitute(&args[1]);
    Json::F64(op(lhs, rhs))
  }
}

fn parse(source: &str) -> Vec<Json> { Json::from_str(source).unwrap().as_array().unwrap().to_owned() }

fn main() {
  let source = r#"
["step",
  ["set", "i", 10],
  ["set", "sum", 0],
  ["until", ["==", ["get", "i"], 0], [
    "step",
    ["set", "sum", ["+", ["get", "sum"], ["get", "i"]]],
    ["set", "i", ["+", ["get", "i"], -1]]
  ]],
  ["get", "sum"]
]
"#;
  let input = parse(source);

  let mut e = Evaluator::new();

  println!("{:?}", e.eval(input.as_slice()));
}
<|endoftext|>


<commit_before>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod round_robin;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  let scenarios = {
    (0..2).map(|_| (0..10).map(|_| 16).collect::<Vec<usize>>()).collect::<Vec<Vec<usize>>>()
  };

  macro_rules! run_simulation {
    ($scheduler:ident) => (
      for (run, scenario) in scenarios.iter().enumerate() {
        let scheduler = $scheduler::new();
        let name = scheduler.name().clone();
        let avg = run_simulation(&mut tui, scheduler, scenario.clone());
        tui.add_result(format!("{}: #{:02}: Average waiting time: {:02.2}", name, run, avg));
      }
    )
  }

  run_simulation!(fcfs);
  run_simulation!(round_robin);

  tui.update();

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>) -> f64
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();
  let mut average_waiting_time = 0f64;
  let mut num_of_spawned_procs = 1;

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("{:05}: Starting simulation using {}", clock_tick, scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    // update the process view
    scheduler.list_processes(&mut tui);
    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    // simulate executing the current process
    tui.debug(format!("{:05}: Executing {}", clock_tick, scheduler.current_proc().unwrap().name));
    scheduler.current_proc_mut().unwrap().record_execution();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("{:05}: Spawning {}", clock_tick, new_proc.name));
        scheduler.add_process(new_proc);
        num_of_spawned_procs += 1;
      }
    }

    if scheduler.current_proc().unwrap().done_executing() {
      tui.debug(format!("{:05}: Killing process {}", clock_tick, scheduler.current_proc().unwrap().name));
      scheduler.kill_current_proc();
    }

    if scheduler.has_processes() {
      if clock_tick % SYSTEM_HZ == SYSTEM_HZ - 1 {
        let prev_proc_name = scheduler.current_proc().unwrap().name.clone();
        scheduler.schedule();
        tui.debug(format!("{:05}: Switching context: {} -> {}", clock_tick, prev_proc_name, scheduler.current_proc().unwrap().name));
        tui.debug(format!("{:05}: {} was waiting {} clock ticks", clock_tick, scheduler.current_proc().unwrap().name, scheduler.current_proc().unwrap().waiting_time));

        average_waiting_time -= average_waiting_time / num_of_spawned_procs as f64;
        average_waiting_time += scheduler.current_proc().unwrap().waiting_time as f64 / num_of_spawned_procs as f64;
      }

      // increase the waiting time for every process
      scheduler.increase_waiting_times();
    }

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }

  average_waiting_time
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<commit_msg>Calculate the overall average waiting time from all test runs<commit_after>//
// main.rs
// Copyright (C) 2017 Szymon Urbaś <szymon.urbas@aol.com>
// Distributed under terms of the BSD (2-clause) license.
//
// Created on: 13 Mar 2017 21:03:41 +0100 (CET)
//

extern crate rand;
extern crate cursive;

use std::thread;
use std::time;

mod process;
mod scheduler;
mod fcfs;
mod round_robin;
mod tui;

use scheduler::*;
use tui::*;

/// Length of a single system clock tick (frequency of actual, real time)
const CLOCK_HZ: u64 = 50;
/// Switch context every <value> clock ticks
const SYSTEM_HZ: usize = 8;

fn main() {
  let mut tui = tui::new();

  let scenarios = {
    (0..2).map(|_| (0..10).map(|_| 16).collect::<Vec<usize>>()).collect::<Vec<Vec<usize>>>()
  };

  macro_rules! run_simulation {
    ($scheduler:ident) => ({
      let mut average_waiting_time = 0f64;

      for (run, scenario) in scenarios.iter().enumerate() {
        let scheduler = $scheduler::new();
        let avg = run_simulation(&mut tui, scheduler, scenario.clone());
        tui.add_result(format!("{}: #{:02}: Average waiting time: {:02.2}", stringify!($scheduler), run, avg));

        average_waiting_time -= average_waiting_time / (run + 1) as f64;
        average_waiting_time += avg / (run + 1) as f64;
      }

      tui.add_result(format!("{}: Overall average: {:02.2}", stringify!($scheduler), average_waiting_time));
    })
  }

  run_simulation!(fcfs);
  run_simulation!(round_robin);

  tui.update();

  loop {}
}

fn run_simulation<S>(mut tui: &mut Tui, mut scheduler: S, mut process_list: Vec<usize>) -> f64
where S: Scheduler {
  let mut clock_tick = 0;
  let mut process_spawner = process::new_spawner();
  let mut average_waiting_time = 0f64;
  let mut num_of_spawned_procs = 1;

  tui.set_header(format!("Using algorithm: {}", scheduler.name()));
  tui.debug(format!("{:05}: Starting simulation using {}", clock_tick, scheduler.name()));

  // vectors only support the pop (from the back) operation so
  // reverse it (so we pop from the front)
  process_list.reverse();

  // Add the equivalent of the 'init' process
  scheduler.add_process(process_spawner.spawn(process_list.pop().unwrap()));

  loop {
    // update the process view
    scheduler.list_processes(&mut tui);
    // update all the views
    tui.update();

    if !scheduler.has_processes() {
      // if there's no more processes - end the simulation
      // if a process can only be created by another process - there's
      // nothing else to do
      break;
    }

    // simulate executing the current process
    tui.debug(format!("{:05}: Executing {}", clock_tick, scheduler.current_proc().unwrap().name));
    scheduler.current_proc_mut().unwrap().record_execution();

    // Simulate other processes creating new processes
    // Assume that you can't create new processes, if there's none already
    if clock_tick % SYSTEM_HZ == 0 {
      if let Some(burst_time) = process_list.pop() {
        let new_proc = process_spawner.spawn(burst_time);
        tui.debug(format!("{:05}: Spawning {}", clock_tick, new_proc.name));
        scheduler.add_process(new_proc);
        num_of_spawned_procs += 1;
      }
    }

    if scheduler.current_proc().unwrap().done_executing() {
      tui.debug(format!("{:05}: Killing process {}", clock_tick, scheduler.current_proc().unwrap().name));
      scheduler.kill_current_proc();
    }

    if scheduler.has_processes() {
      if clock_tick % SYSTEM_HZ == SYSTEM_HZ - 1 {
        let prev_proc_name = scheduler.current_proc().unwrap().name.clone();
        scheduler.schedule();
        tui.debug(format!("{:05}: Switching context: {} -> {}", clock_tick, prev_proc_name, scheduler.current_proc().unwrap().name));
        tui.debug(format!("{:05}: {} was waiting {} clock ticks", clock_tick, scheduler.current_proc().unwrap().name, scheduler.current_proc().unwrap().waiting_time));

        average_waiting_time -= average_waiting_time / num_of_spawned_procs as f64;
        average_waiting_time += scheduler.current_proc().unwrap().waiting_time as f64 / num_of_spawned_procs as f64;
      }

      // increase the waiting time for every process
      scheduler.increase_waiting_times();
    }

    thread::sleep(time::Duration::from_millis(1000 / CLOCK_HZ));

    clock_tick += 1;
  }

  average_waiting_time
}

/*
 * vi: ts=2 sw=2 expandtab
 */

<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate itertools;
extern crate walkdir;

use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use clap::{App, SubCommand, AppSettings};
use itertools::Itertools;
use walkdir::{DirEntry, WalkDirIterator};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn display_path(path: &PathBuf) {
    path.file_name()
        .and_then(|p| p.to_str())
        .map(|p| println!("{}:", p));
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    // I am still not sure what is more idiomatic - the 'if' above or the 'match' below
    //
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let matches = App::new(CARGO)
                      .bin_name(CARGO)
                      .version(crate_version!())
                      .about("Run cargo command on multiple crates")
                      .setting(AppSettings::SubcommandRequired)
                      .setting(AppSettings::ArgRequiredElseHelp)
                      .subcommand(SubCommand::with_name("multi")
                                      .version(crate_version!())
                                      .setting(AppSettings::ArgRequiredElseHelp)
                                      .setting(AppSettings::TrailingVarArg)
                                      .arg_from_usage("<cmd>... 'cargo command to run'"))
                      .get_matches();

    let mut cargo_cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    if let Some(arg_cmd) = matches.subcommand_matches("multi")
                                  .and_then(|m| m.values_of("cmd")) {
        for arg in arg_cmd {
            cargo_cmd.arg(arg);
            banner = banner + " " + arg;
        }
    }

    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let to_path_buf = |e: DirEntry| e.path().to_path_buf();
    let execute = move |p| cargo_cmd.current_dir(p).output().ok();

    if let Ok(cwd) = env::current_dir() {
        announce(&banner);
        walkdir::WalkDir::new(cwd)
            .min_depth(MIN_DEPTH)
            .max_depth(MAX_DEPTH)
            .into_iter()
            .filter_entry(is_crate)
            .filter_map(|e| e.ok())
            .map(to_path_buf)
            .inspect(display_path)
            .filter_map(execute)
            .foreach(report_output);
    }
}
<commit_msg>Simplify display_path()<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#[macro_use]
extern crate clap;
extern crate itertools;
extern crate walkdir;

use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use clap::{App, SubCommand, AppSettings};
use itertools::Itertools;
use walkdir::{DirEntry, WalkDirIterator};

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    // I am still not sure what is more idiomatic - the 'if' above or the 'match' below
    //
    // match output.status.success() {
    //     true => print_ident(output.stdout),
    //     false => print_ident(output.stderr),
    // }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {

    let matches = App::new(CARGO)
                      .bin_name(CARGO)
                      .version(crate_version!())
                      .about("Run cargo command on multiple crates")
                      .setting(AppSettings::SubcommandRequired)
                      .setting(AppSettings::ArgRequiredElseHelp)
                      .subcommand(SubCommand::with_name("multi")
                                      .version(crate_version!())
                                      .setting(AppSettings::ArgRequiredElseHelp)
                                      .setting(AppSettings::TrailingVarArg)
                                      .arg_from_usage("<cmd>... 'cargo command to run'"))
                      .get_matches();

    let mut cargo_cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;

    if let Some(arg_cmd) = matches.subcommand_matches("multi")
                                  .and_then(|m| m.values_of("cmd")) {
        for arg in arg_cmd {
            cargo_cmd.arg(arg);
            banner = banner + " " + arg;
        }
    }

    let is_crate = |e: &DirEntry| e.path().join("Cargo.toml").exists();
    let to_path_buf = |e: DirEntry| e.path().to_path_buf();
    let execute = move |p| cargo_cmd.current_dir(p).output().ok();
    let display_path = |path: &PathBuf| println!("{}:", path.display());

    if let Ok(cwd) = env::current_dir() {
        announce(&banner);
        walkdir::WalkDir::new(cwd)
            .min_depth(MIN_DEPTH)
            .max_depth(MAX_DEPTH)
            .into_iter()
            .filter_entry(is_crate)
            .filter_map(|e| e.ok())
            .map(to_path_buf)
            .inspect(display_path)
            .filter_map(execute)
            .foreach(report_output);
    }
}
<|endoftext|>