<commit_before>#![crate_name="magog"]
#![feature(unboxed_closures, plugin)]
#![feature(path_ext, exit_status)]
#![feature(custom_derive)]
#![plugin(rand_macros)]

#[no_link] extern crate rand_macros;
extern crate rand;
extern crate rustc_serialize;
extern crate num;
extern crate getopts;
extern crate image;
extern crate time;
extern crate toml;
#[macro_use]
extern crate calx;
extern crate mapgen;
extern crate world;

use std::env;
use std::process;
use std::path::{PathBuf};
use std::fs::{self, File};
use std::io::prelude::*;
use std::default::Default;
use calx::backend::{Canvas, CanvasBuilder, Event};
use gamestate::GameState;
use titlestate::TitleState;

pub static SCREEN_W: u32 = 640;
pub static SCREEN_H: u32 = 360;

pub mod drawable;
pub mod tilecache;
pub mod viewutil;
pub mod worldview;
mod config;
mod gamestate;
mod titlestate;
mod sprite;
mod msg_queue;
mod console;

pub trait State {
    fn process(&mut self, ctx: &mut Canvas, event: Event) -> Option<Transition>;
}

pub enum Transition {
    Game,
    Title,
    Exit,
}

pub fn version() -> String {
    let next_release = "0.1.0";
    let git_hash = include_str!("git_hash.inc");
    // Set is_release to true for one commit to make a release.
    let is_release = false;

    if is_release {
        format!("{}", next_release)
    } else {
        format!("{}-alpha+g{}", next_release, git_hash)
    }
}

/// Get the application data file path and ensure the path exists.
pub fn app_data_path() -> PathBuf {
    let ret = calx::app_data_path("magog");
    if !ret.exists() {
        // Create the config dir
        // TODO: Handle error
        fs::create_dir_all(&ret).unwrap();
    }
    ret
}

pub fn compiler_version() -> String {
    include_str!("../rustc_version.txt").trim().to_string()
}

pub fn screenshot(ctx: &mut Canvas) {
    use time;
    use std::path::{Path};
    use std::fs::{self, File, PathExt};
    use image;

    let shot = ctx.screenshot();

    let timestamp = time::precise_time_s() as u64;
    // Create screenshot filenames by concatenating the current timestamp in
    // seconds with a running number from 00 to 99. 100 shots per second
    // should be good enough.

    // Default if we fail to generate any of the 100 candidates for this
    // second, just overwrite with the "xx" prefix then.
    let mut filename = format!("magog-{}{}.png", timestamp, "xx");

    // Run through candidates for this second.
    for i in 0..100 {
        let test_filename = format!("magog-{}{:02}.png", timestamp, i);
        if !Path::new(&test_filename).exists() {
            // Thread-safe claiming: create_dir will fail if the dir
            // already exists (it'll exist if another thread is gunning
            // for the same filename and managed to get past us here).
            // At least assuming that create_dir is atomic...
            let squat_dir = format!(".tmp-{}{:02}", timestamp, i);
            if std::fs::create_dir(&squat_dir).is_ok() {
                File::create(&test_filename).unwrap();
                filename = test_filename;
                fs::remove_dir(&squat_dir).unwrap();
                break;
            } else {
                continue;
            }
        }
    }

    let _ = image::save_buffer(&Path::new(&filename), &shot, shot.width(), shot.height(), image::ColorType::RGB(8));
}

pub fn main() {
    // TODO: Use persistent config object.
    let mut config: config::Config = Default::default();

    // Init the config file
    let cfg_path = config.file_path();
    if cfg_path.exists() {
        config.load(cfg_path).unwrap();
    } else {
        // Write the default config.
        let mut file = File::create(cfg_path).unwrap();
        file.write_all(config.default_file().as_bytes()).unwrap()
    }

    // Read command line arguments, *after* reading the config file. Command
    // line overrules file.
    match config.parse_args(env::args()) {
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
        Ok(Some(msg)) => {
            println!("{}", msg);
            return;
        }
        _ => {}
    };

    let mut builder = CanvasBuilder::new()
        .set_size(SCREEN_W, SCREEN_H)
        .set_magnify(config.magnify_mode)
        .set_title("Magog")
        .set_fullscreen(config.fullscreen)
        .set_frame_interval(0.030f64);

    tilecache::init(&mut builder);
    let mut state: Box<State> = Box::new(TitleState::new());

    let mut canvas = builder.build();
    loop {
        let event = canvas.next_event();
        match state.process(&mut canvas, event) {
            Some(Transition::Title) => { state = Box::new(TitleState::new()); }
            Some(Transition::Game) => {
                state = Box::new(GameState::new(config)); }
            Some(Transition::Exit) => { break; }
            _ => ()
        }
    }
}
<commit_msg>Use a local PathExt replacement<commit_after>#![crate_name="magog"]
#![feature(unboxed_closures, plugin)]
#![feature(path_ext, exit_status)]
#![feature(custom_derive)]
#![plugin(rand_macros)]

#[no_link] extern crate rand_macros;
extern crate rand;
extern crate rustc_serialize;
extern crate num;
extern crate getopts;
extern crate image;
extern crate time;
extern crate toml;
#[macro_use]
extern crate calx;
extern crate mapgen;
extern crate world;

use std::env;
use std::process;
use std::path::{PathBuf};
use std::fs::{self, File};
use std::io::{Write};
use std::default::Default;
// TODO: Get a stable standard library PathExt to replace this.
use calx::{PathExt};
use calx::backend::{Canvas, CanvasBuilder, Event};
use gamestate::GameState;
use titlestate::TitleState;

pub static SCREEN_W: u32 = 640;
pub static SCREEN_H: u32 = 360;

pub mod drawable;
pub mod tilecache;
pub mod viewutil;
pub mod worldview;
mod config;
mod gamestate;
mod titlestate;
mod sprite;
mod msg_queue;
mod console;

pub trait State {
    fn process(&mut self, ctx: &mut Canvas, event: Event) -> Option<Transition>;
}

pub enum Transition {
    Game,
    Title,
    Exit,
}

pub fn version() -> String {
    let next_release = "0.1.0";
    let git_hash = include_str!("git_hash.inc");
    // Set is_release to true for one commit to make a release.
    let is_release = false;

    if is_release {
        format!("{}", next_release)
    } else {
        format!("{}-alpha+g{}", next_release, git_hash)
    }
}

/// Get the application data file path and ensure the path exists.
pub fn app_data_path() -> PathBuf {
    let ret = calx::app_data_path("magog");
    if !ret.exists() {
        // Create the config dir
        // TODO: Handle error
        fs::create_dir_all(&ret).unwrap();
    }
    ret
}

pub fn compiler_version() -> String {
    include_str!("../rustc_version.txt").trim().to_string()
}

pub fn screenshot(ctx: &mut Canvas) {
    use time;
    use std::path::{Path};
    use std::fs::{self, File};
    use image;

    let shot = ctx.screenshot();

    let timestamp = time::precise_time_s() as u64;
    // Create screenshot filenames by concatenating the current timestamp in
    // seconds with a running number from 00 to 99. 100 shots per second
    // should be good enough.

    // Default if we fail to generate any of the 100 candidates for this
    // second, just overwrite with the "xx" prefix then.
    let mut filename = format!("magog-{}{}.png", timestamp, "xx");

    // Run through candidates for this second.
    for i in 0..100 {
        let test_filename = format!("magog-{}{:02}.png", timestamp, i);
        if !Path::new(&test_filename).exists() {
            // Thread-safe claiming: create_dir will fail if the dir
            // already exists (it'll exist if another thread is gunning
            // for the same filename and managed to get past us here).
            // At least assuming that create_dir is atomic...
            let squat_dir = format!(".tmp-{}{:02}", timestamp, i);
            if std::fs::create_dir(&squat_dir).is_ok() {
                File::create(&test_filename).unwrap();
                filename = test_filename;
                fs::remove_dir(&squat_dir).unwrap();
                break;
            } else {
                continue;
            }
        }
    }

    let _ = image::save_buffer(&Path::new(&filename), &shot, shot.width(), shot.height(), image::ColorType::RGB(8));
}

pub fn main() {
    // TODO: Use persistent config object.
    let mut config: config::Config = Default::default();

    // Init the config file
    let cfg_path = config.file_path();
    if cfg_path.exists() {
        config.load(cfg_path).unwrap();
    } else {
        // Write the default config.
        let mut file = File::create(cfg_path).unwrap();
        file.write_all(config.default_file().as_bytes()).unwrap()
    }

    // Read command line arguments, *after* reading the config file. Command
    // line overrules file.
    match config.parse_args(env::args()) {
        Err(e) => {
            println!("{}", e);
            process::exit(1);
        }
        Ok(Some(msg)) => {
            println!("{}", msg);
            return;
        }
        _ => {}
    };

    let mut builder = CanvasBuilder::new()
        .set_size(SCREEN_W, SCREEN_H)
        .set_magnify(config.magnify_mode)
        .set_title("Magog")
        .set_fullscreen(config.fullscreen)
        .set_frame_interval(0.030f64);

    tilecache::init(&mut builder);
    let mut state: Box<State> = Box::new(TitleState::new());

    let mut canvas = builder.build();
    loop {
        let event = canvas.next_event();
        match state.process(&mut canvas, event) {
            Some(Transition::Title) => { state = Box::new(TitleState::new()); }
            Some(Transition::Game) => {
                state = Box::new(GameState::new(config)); }
            Some(Transition::Exit) => { break; }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate rusty_vault;

use docopt::Docopt;
use rusty_vault as vault;

const USAGE: &'static str = "
Rusty Vault.

Usage:
  rusty_vault <externalid> <datastring>
  rusty_vault --version

Options:
  -h --help     Show this screen.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_externalid: String,
    arg_datastring: Option<String>
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then( |d| d.decode() )
                            .unwrap_or_else( |e| e.exit() );

    let external_id = args.arg_externalid;
    let data_string = args.arg_datastring;

    match data_string {
        Some(value) => dump(external_id, value.into_bytes()),
        None => load(&external_id)
    }
}

fn dump(external_id: String, data: Vec<u8>) {
    let result = vault::dump(external_id, data);
    println!("Ciphertext: {:?}", result.ciphertext);
}

fn load(external_id: &String) {
    let result = vault::load(external_id);
    println!("Data: {:?}", result.data);
}
<commit_msg>Usage with one argument.<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate rusty_vault;

use docopt::Docopt;
use rusty_vault as vault;

const USAGE: &'static str = "
Rusty Vault.

Usage:
  rusty_vault <external-id> <data-string>
  rusty_vault <external-id>
  rusty_vault --version

Options:
  -h --help     Show this screen.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_external_id: String,
    arg_data_string: Option<String>
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then( |d| d.decode() )
                            .unwrap_or_else( |e| e.exit() );

    let external_id = args.arg_external_id;
    let data_string = args.arg_data_string;

    match data_string {
        Some(value) => dump(external_id, value.into_bytes()),
        None => load(&external_id)
    }
}

fn dump(external_id: String, data: Vec<u8>) {
    let result = vault::dump(external_id, data);
    println!("Ciphertext: {:?}", result.ciphertext);
}

fn load(external_id: &String) {
    let result = vault::load(external_id);
    println!("Data: {:?}", result.data);
}
<|endoftext|>


<commit_before>extern crate html5ever;
#[macro_use(qualname,ns,atom)]
extern crate string_cache;
#[macro_use(format_tendril)] extern crate tendril;

use html5ever::{ParseOpts, parse_document};
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom, Handle, Node};
use html5ever::rcdom::NodeEnum::Element;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::io;
use html5ever::tree_builder::TreeSink;
use html5ever::tree_builder::interface::NodeOrText;
use tendril::Tendril;

fn main() {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts { drop_doctype: true, ..Default::default() },
        ..Default::default()
    };

    let stdin = io::stdin();
    let mut dom = parse_document(RcDom::default(), opts)
                      .from_utf8()
                      .read_from(&mut stdin.lock())
                      .unwrap();

    let mut sections = vec![];
    walkx(&dom.document, &mut sections);

    for section in sections {
        let attr = html5ever::Attribute{name: qualname!("", "name"), value: format_tendril!("xxx")};
        let myElement = dom.create_element(qualname!(html, "a"), vec![attr]);
        dom.append(section, NodeOrText::AppendNode(myElement));
    }

    let mut bytes = vec![];
    serialize(&mut bytes, &dom.document, SerializeOpts::default()).unwrap();
    let result = String::from_utf8(bytes).unwrap();
    println!("{}", result);
}

fn walkx(h :&Handle, sections :&mut Vec<Handle>) {
    let document = h.borrow();
    let html = document.children[0].borrow();
    for e in html.children.iter() {
        if let Element(ref qualname, _, _) = e.borrow().node {
            sections.push(e.clone());
        }
    }
    ;
}
<commit_msg>Simple recursion into the html tree<commit_after>extern crate html5ever;
#[macro_use(qualname,ns,atom)]
extern crate string_cache;
#[macro_use(format_tendril)] extern crate tendril;

use html5ever::{ParseOpts, parse_document};
use html5ever::tree_builder::TreeBuilderOpts;
use html5ever::rcdom::{RcDom, Handle, Node};
use html5ever::rcdom::NodeEnum::Element;
use html5ever::serialize::{SerializeOpts, serialize};
use html5ever::tendril::TendrilSink;
use std::io;
use html5ever::tree_builder::TreeSink;
use html5ever::tree_builder::interface::NodeOrText;
use tendril::Tendril;

fn main() {
    let opts = ParseOpts {
        tree_builder: TreeBuilderOpts { drop_doctype: true, ..Default::default() },
        ..Default::default()
    };

    let stdin = io::stdin();
    let mut dom = parse_document(RcDom::default(), opts)
                      .from_utf8()
                      .read_from(&mut stdin.lock())
                      .unwrap();

    let mut sections = vec![];
    walkx(&dom.document, &mut sections);

    for section in sections {
        let attr = html5ever::Attribute{name: qualname!("", "name"), value: format_tendril!("xxx")};
        let myElement = dom.create_element(qualname!(html, "a"), vec![attr]);
        dom.append(section, NodeOrText::AppendNode(myElement));
    }

    let mut bytes = vec![];
    serialize(&mut bytes, &dom.document, SerializeOpts::default()).unwrap();
    let result = String::from_utf8(bytes).unwrap();
    println!("{}", result);
}

fn walkx(h :&Handle, sections :&mut Vec<Handle>) {
    let node = h.borrow();
    for e in node.children.iter() {
        walkx(e, sections);
        if let Element(ref qualname, _, _) = e.borrow().node {
            sections.push(e.clone());
        }
    }
    ;
}
<|endoftext|>


<commit_before>extern crate clap;

use clap::{ App, Arg, ArgMatches, SubCommand };

fn main() {
    let matches = parse_args();

    if let Some(ref matches) = matches.subcommand_matches("week") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("day command requires day of week");
                return;
            },
        };

        // todo: write stupid library, stupid...
        println!("{} of week", day);
    }

    if let Some(ref matches) = matches.subcommand_matches("month") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("month command requires day of week and ord");
                return;
            },
        };

        let ord = match matches.value_of("ord") {
            Some(ord) => ord,
            None => {
                println!("month command requires day of week and ord");
                return;
            },
        };

        // todo: do actual repeated date code here!
        println!("{} {}", day, ord);
    }

    if let Some(ref matches) = matches.subcommand_matches("year") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("year command requires day of year");
                return;
            },
        };

        // todo: actual repeated date code here! ... No, probably not...
        println!("{} day of year", day);
    }
}

fn parse_args() -> ArgMatches {
    App::new("reldate")
        .version("0.0.1")
        .author("J/A <archer884@gmail.com")
        .about("Prints relative dates.")
        .subcommand(SubCommand::new("month")
            .about("Allows creation of month-relative date streams.")
            .arg(Arg::new("day")
                .short("d")
                .long("day")
                .help("day of week")
                .takes_value(true))
            .arg(Arg::new("ord")
                 .short("o")
                 .long("ord")
                 .help("ord value of repeated date")
                 .takes_value(true)))
        .subcommand(SubCommand::new("week")
            .about("Allows creation of week-relative date streams.")
            .arg(Arg::new("day")
                .short("d")
                .long("day")
                .help("day of week")
                .takes_value(true)))
        .subcommand(SubCommand::new("year")
            .about("Allows immortals to sort out their calendars.")
            .arg(Arg::new("day")
                 .short("d")
                 .long("day")
                 .help("day of year")
                 .takes_value(true)))
        .get_matches()
}
<commit_msg>Add todo.<commit_after>extern crate clap;

use clap::{ App, Arg, ArgMatches, SubCommand };

fn main() {
    let matches = parse_args();

    if let Some(ref matches) = matches.subcommand_matches("week") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("day command requires day of week");
                return;
            },
        };

        // todo: write stupid library, stupid...
        println!("{} of week", day);
    }

    if let Some(ref matches) = matches.subcommand_matches("month") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("month command requires day of week and ord");
                return;
            },
        };

        let ord = match matches.value_of("ord") {
            Some(ord) => ord,
            None => {
                println!("month command requires day of week and ord");
                return;
            },
        };

        // todo: do actual repeated date code here!
        println!("{} {}", day, ord);
    }

    if let Some(ref matches) = matches.subcommand_matches("year") {
        let day = match matches.value_of("day") {
            Some(day) => day,
            None => {
                println!("year command requires day of year");
                return;
            },
        };

        // todo: actual repeated date code here! ... No, probably not...
        println!("{} day of year", day);
    }
}

fn parse_args() -> ArgMatches {
    // todo: add range control; we have to know how many dates to print
    App::new("reldate")
        .version("0.0.1")
        .author("J/A <archer884@gmail.com")
        .about("Prints relative dates.")
        .subcommand(SubCommand::new("month")
            .about("Allows creation of month-relative date streams.")
            .arg(Arg::new("day")
                .short("d")
                .long("day")
                .help("day of week")
                .takes_value(true))
            .arg(Arg::new("ord")
                 .short("o")
                 .long("ord")
                 .help("ord value of repeated date")
                 .takes_value(true)))
        .subcommand(SubCommand::new("week")
            .about("Allows creation of week-relative date streams.")
            .arg(Arg::new("day")
                .short("d")
                .long("day")
                .help("day of week")
                .takes_value(true)))
        .subcommand(SubCommand::new("year")
            .about("Allows immortals to sort out their calendars.")
            .arg(Arg::new("day")
                 .short("d")
                 .long("day")
                 .help("day of year")
                 .takes_value(true)))
        .get_matches()
}
<|endoftext|>


<commit_before>extern crate chattium_oxide_lib;
extern crate yaml_file_handler;
extern crate hyper;
extern crate clap;
extern crate time;

mod io;
mod options;

use options::Options;
use io::read_unprompted;
use hyper::client::Client;
use hyper::method::Method;
use time::{now_utc, strftime};
use std::io::{stderr, Read, Write};
use chattium_oxide_lib::{ChatMessage, ChatUser};
use chattium_oxide_lib::json::{ToJsonnable, FromJsonnable};

fn main() {
	let client = Client::new();
	let options = Options::parse();

	let mut newest = now_utc();
	loop {
		use std::thread::sleep_ms;

		let just_before = now_utc();
		match newest.to_json_string() {
			Ok(json) => {
				match client.request(Method::Trace, &*&options.server).body(&*&json).send() {
					Ok(mut res) => {
						let mut resbody = String::new();
						match res.read_to_string(&mut resbody) {
							Ok(_) =>
								match Vec::<ChatMessage>::from_json_string(&resbody) {
									Ok(messages) =>
										for message in messages {
											println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
										},
									Err(error) =>
										{let _ = stderr().write_fmt(format_args!("Server at {} replied with unprocessable entity (invalid JSON): {}\n", options.server, error));},
								},
							Err(error) => {let _ = stderr().write_fmt(format_args!("Failed reading request from server at {}: {}\n", res.url, error));},
						}
					},
					Err(error) => {let _ = stderr().write_fmt(format_args!("GETing the message failed: {}\n", error));},
				}
			},
			Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
		}

		newest = just_before;
		sleep_ms(500);
	}
	while let Ok(Some(rmessage)) = read_unprompted() {
		match ChatMessage::new(ChatUser::me(options.name.clone()), rmessage).to_json_string() {
			Ok(json) =>
				match client.post(&*&options.server).body(&*&json).send() {
					Ok(response) => println!("Server responded with status {}", response.status),
					Err(error) => {let _ = stderr().write_fmt(format_args!("POSTing the message failed: {}\n", error));},
				},
			Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
		}
	}
}
<commit_msg>Formatting<commit_after>extern crate chattium_oxide_lib;
extern crate yaml_file_handler;
extern crate hyper;
extern crate clap;
extern crate time;

mod io;
mod options;

use options::Options;
use io::read_unprompted;
use hyper::client::Client;
use hyper::method::Method;
use std::thread::sleep_ms;
use time::{now_utc, strftime};
use std::io::{stderr, Read, Write};
use chattium_oxide_lib::{ChatMessage, ChatUser};
use chattium_oxide_lib::json::{ToJsonnable, FromJsonnable};

fn main() {
	let client = Client::new();
	let options = Options::parse();

	let mut newest = now_utc();
	loop {
		let just_before = now_utc();
		match newest.to_json_string() {
			Ok(json) =>
				match client.request(Method::Trace, &*&options.server).body(&*&json).send() {
					Ok(mut res) => {
						let mut resbody = String::new();
						match res.read_to_string(&mut resbody) {
							Ok(_) =>
								match Vec::<ChatMessage>::from_json_string(&resbody) {
									Ok(messages) =>
										for message in messages {
											println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
										},
									Err(error) =>
										{let _ = stderr().write_fmt(format_args!("Server at {} replied with unprocessable entity (invalid JSON): {}\n", options.server, error));},
								},
							Err(error) => {let _ = stderr().write_fmt(format_args!("Failed reading request from server at {}: {}\n", res.url, error));},
						}
					},
					Err(error) => {let _ = stderr().write_fmt(format_args!("GETing the message failed: {}\n", error));},
				},
			Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
		}

		newest = just_before;
		sleep_ms(500);
	}
	while let Ok(Some(rmessage)) = read_unprompted() {
		match ChatMessage::new(ChatUser::me(options.name.clone()), rmessage).to_json_string() {
			Ok(json) =>
				match client.post(&*&options.server).body(&*&json).send() {
					Ok(response) => println!("Server responded with status {}", response.status),
					Err(error) => {let _ = stderr().write_fmt(format_args!("POSTing the message failed: {}\n", error));},
				},
			Err(error) => {let _ = stderr().write_fmt(format_args!("Couldn't serialize message: {}\n", error));},
		}
	}
}
<|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 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(())
    }

}
<commit_msg>Remove redundant copies<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, 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, self.conf.org);
        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|>


<commit_before>extern crate byteorder;

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io;
use std::str;
use std::io::{Error, ErrorKind};
use byteorder::{LittleEndian, ReadBytesExt};

// FAT implementation based on:
//   http://wiki.osdev.org/FAT
//   https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

#[derive(Debug, Copy, Clone)]
enum FatType {
    Fat12, Fat16, Fat32, ExFat
}

#[derive(Debug)]
struct FatFileSystem {
    fat_type: FatType,
    root_cluster: u32,
    volume_id: u32,
    volume_label: String,
    first_data_sector: u32,
    first_fat_sector: u32,
}

impl FatFileSystem {
    fn fat_type_from_clusters(total_clusters: u32) -> FatType {
        if total_clusters < 4085 {
            FatType::Fat12
        } else if total_clusters < 65525 {
            FatType::Fat16
        } else if total_clusters < 268435445 {
            FatType::Fat32
        } else {
            FatType::ExFat
        }
    }

    pub fn new(rdr: &mut BufRead) -> io::Result<FatFileSystem> {
        let mut bootjmp = [0; 3];
        rdr.read(&mut bootjmp)?;
        let mut oem_name: [u8; 8] = [0; 8];
        rdr.read(&mut oem_name)?;
        let bytes_per_sector = rdr.read_u16::<LittleEndian>()? as u32;
        let sectors_per_cluster = rdr.read_u8()? as u32;
        let reserved_sector_count = rdr.read_u16::<LittleEndian>()? as u32;
        let table_count = rdr.read_u8()? as u32;
        let root_entry_count = rdr.read_u16::<LittleEndian>()? as u32;
        let total_sectors_16 = rdr.read_u16::<LittleEndian>()? as u32;
        rdr.read_u8()?; // media_type
        let table_size_16 = rdr.read_u16::<LittleEndian>()? as u32;
        rdr.read_u16::<LittleEndian>()?; // sectors_per_track
        rdr.read_u16::<LittleEndian>()?; // head_side_count
        rdr.read_u32::<LittleEndian>()?; // hidden_sector_count
        let total_sectors_32 = rdr.read_u32::<LittleEndian>()? as u32;

        let (fat_size, fat_info, root_cluster, volume_id);
        let mut volume_label = [0; 11];
        let mut fat_type_label = [0; 8];

        if table_size_16 == 0 {
            let table_size_32 = rdr.read_u32::<LittleEndian>()? as u32;
            rdr.read_u16::<LittleEndian>()?; // extended_flags
            rdr.read_u16::<LittleEndian>()?; // fat_version
            root_cluster = rdr.read_u32::<LittleEndian>()?;
            fat_info = rdr.read_u16::<LittleEndian>()? as u32;
            rdr.read_u16::<LittleEndian>()?; // backup_bs_sector
            let mut reserved_0 = [0; 12];
            rdr.read(&mut reserved_0)?;
            rdr.read_u8()?; // drive_num
            rdr.read_u8()?; // reserved_1
            rdr.read_u8()?; // ext_sig (0x29)
            volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut volume_label)?;
            rdr.read(&mut fat_type_label)?;
            let mut boot_code = [0; 420];
            rdr.read(&mut boot_code)?;

            fat_size = table_size_32;
        } else {
            rdr.read_u8()?; // drive_num
            rdr.read_u8()?; // reserved1
            rdr.read_u8()?; // ext_sig (0x29)
            volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut volume_label)?;
            rdr.read(&mut fat_type_label)?;
            let mut boot_code = [0; 448];
            rdr.read(&mut boot_code)?;

            fat_size = table_size_16;
            fat_info = 0;
            root_cluster = 0;
        }
        let mut boot_sig = [0; 2];
        rdr.read(&mut boot_sig)?;
        if boot_sig != [0x55, 0xAA] {
            return Err(Error::new(ErrorKind::Other, "invalid signature"));
        }

        let total_sectors = if total_sectors_16 == 0 { total_sectors_32 } else { total_sectors_16 };
        let root_dir_sectors = ((root_entry_count * 32) + (bytes_per_sector - 1)) / (bytes_per_sector);
        let first_data_sector = reserved_sector_count + (table_count * fat_size) + root_dir_sectors;
        let first_fat_sector = reserved_sector_count;
        let data_sectors = total_sectors - (reserved_sector_count + (table_count * fat_size) + root_dir_sectors);
        let total_clusters = data_sectors / sectors_per_cluster;
        let fat_type = FatFileSystem::fat_type_from_clusters(total_clusters);

        let fs = FatFileSystem {
            fat_type: fat_type,
            root_cluster: root_cluster,
            volume_id: volume_id,
            volume_label: str::from_utf8(&volume_label).unwrap().to_string(),
            first_data_sector: first_data_sector,
            first_fat_sector: first_fat_sector,
        };

        println!("fat_type {:?}", fat_type);
        println!("fat_info {}", fat_info);
        println!("root_cluster {}", root_cluster);
        println!("volume_id {}", volume_id);
        println!("oem_name {}", str::from_utf8(&oem_name).unwrap());
        println!("volume_label {}", str::from_utf8(&volume_label).unwrap());
        println!("fat_type_label {}", str::from_utf8(&fat_type_label).unwrap());
        Ok(fs)
    }
}

fn fat_test() -> io::Result<()> {
    let file = File::open("resources/floppy.img")?;
    let mut buf_rdr = BufReader::new(file);
    FatFileSystem::new(&mut buf_rdr)?;
    Ok(())
}

fn main() {
    println!("Hello, world!");
    fat_test().unwrap();
}
<commit_msg>Add functionality of reading directory.<commit_after>extern crate byteorder;

use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io;
use std::str;
use std::io::{Error, ErrorKind, SeekFrom};
use byteorder::{LittleEndian, ReadBytesExt};

// FAT implementation based on:
//   http://wiki.osdev.org/FAT
//   https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

#[derive(Debug, Copy, Clone, PartialEq)]
enum FatType {
    Fat12, Fat16, Fat32, ExFat
}

struct FatFileSystem<T: Read+Seek> {
    rdr: T,
    fat_type: FatType,
    boot: FatBootRecord,
    first_fat_sector: u32,
    first_data_sector: u32,
    root_dir_sectors: u32,
}

#[derive(Debug, PartialEq)]
#[allow(dead_code)]
enum FatFileAttribute {
    READ_ONLY = 0x01,
    HIDDEN    = 0x02,
    SYSTEM    = 0x04,
    VOLUME_ID = 0x08,
    DIRECTORY = 0x10,
    ARCHIVE   = 0x20,
    LFN       = 0x0F,
}

#[allow(dead_code)]
#[derive(Default, Debug)]
struct FatBiosParameterBlock {
    bytes_per_sector: u16,
    sectors_per_cluster: u8,
    reserved_sector_count: u16,
    table_count: u8,
    root_entry_count: u16,
    total_sectors_16: u16,
    media_type: u8,
    table_size_16: u16,
    sectors_per_track: u16,
    head_side_count: u16,
    hidden_sector_count: u32,
    total_sectors_32: u32,

    // Extended BIOS Parameter Block
    table_size_32: u32,
    extended_flags: u16,
    fat_version: u16,
    root_cluster: u32,
    fat_info: u16,
    backup_bs_sector: u16,
    reserved_0: [u8; 12],
    drive_num: u8,
    reserved_1: u8,
    ext_sig: u8,
    volume_id: u32,
    volume_label: [u8; 11],
    fat_type_label: [u8; 8],
}

#[allow(dead_code)]
struct FatBootRecord {
    bootjmp: [u8; 3],
    oem_name: [u8; 8],
    bpb: FatBiosParameterBlock,
    boot_code: [u8; 448],
    boot_sig: [u8; 2],
}

impl Default for FatBootRecord {
    fn default() -> FatBootRecord {
        FatBootRecord {
            bootjmp: Default::default(),
            oem_name: Default::default(),
            bpb: Default::default(),
            boot_code: [0; 448],
            boot_sig: Default::default(),
        }
    }
}

#[allow(dead_code)]
struct FatDirEntry {
    name: [u8; 11],
    attrs: u8,
    reserved_0: u8,
    creation_time_0: u8,
    creation_time_1: u16,
    creation_date: u16,
    access_date: u16,
    first_cluster_hi: u16,
    mod_time: u16,
    mod_date: u16,
    first_cluster_lo: u16,
    size: u32,
}

impl<T: Read+Seek> FatFileSystem<T> {
    fn fat_type_from_clusters(total_clusters: u32) -> FatType {
        if total_clusters < 4085 {
            FatType::Fat12
        } else if total_clusters < 65525 {
            FatType::Fat16
        } else if total_clusters < 268435445 {
            FatType::Fat32
        } else {
            FatType::ExFat
        }
    }

    pub fn new(rdr: &mut T) -> io::Result<FatFileSystem<&mut T>> {
        let boot = FatFileSystem::<T>::read_boot_record(rdr)?;
        if boot.boot_sig != [0x55, 0xAA] {
            return Err(Error::new(ErrorKind::Other, "invalid signature"));
        }

        let total_sectors = if boot.bpb.total_sectors_16 == 0 { boot.bpb.total_sectors_32 } else { boot.bpb.total_sectors_16 as u32 };
        let table_size = if boot.bpb.table_size_16 == 0 { boot.bpb.table_size_32 } else { boot.bpb.table_size_16 as u32 };
        let root_dir_sectors = ((boot.bpb.root_entry_count * 32) + (boot.bpb.bytes_per_sector - 1)) / (boot.bpb.bytes_per_sector);
        let first_data_sector = boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32;
        let first_fat_sector = boot.bpb.reserved_sector_count as u32;
        let data_sectors = total_sectors - (boot.bpb.reserved_sector_count as u32 + (boot.bpb.table_count as u32 * table_size) + root_dir_sectors as u32);
        let total_clusters = data_sectors / boot.bpb.sectors_per_cluster as u32;
        let fat_type = FatFileSystem::<T>::fat_type_from_clusters(total_clusters);

        {
            let oem_name_str = str::from_utf8(&boot.oem_name).unwrap().trim_right();
            let volume_label_str = str::from_utf8(&boot.bpb.volume_label).unwrap().trim_right();
            let fat_type_label_str = str::from_utf8(&boot.bpb.fat_type_label).unwrap().trim_right();

            println!("fat_type {:?}", fat_type);
            println!("volume_id {}", boot.bpb.volume_id);
            println!("oem_name {}", oem_name_str);
            println!("volume_label {}", volume_label_str);
            println!("fat_type_label {}", fat_type_label_str);
        }

        let fs = FatFileSystem {
            rdr: rdr,
            fat_type: fat_type,
            boot: boot,
            first_data_sector: first_data_sector,
            first_fat_sector: first_fat_sector,
            root_dir_sectors: root_dir_sectors as u32,
        };

        Ok(fs)
    }

    fn read_bpb(rdr: &mut Read) -> io::Result<FatBiosParameterBlock> {
        let mut bpb: FatBiosParameterBlock = Default::default();
        bpb.bytes_per_sector = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_cluster = rdr.read_u8()?;
        bpb.reserved_sector_count = rdr.read_u16::<LittleEndian>()?;
        bpb.table_count = rdr.read_u8()?;
        bpb.root_entry_count = rdr.read_u16::<LittleEndian>()? ;
        bpb.total_sectors_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.media_type = rdr.read_u8()?;
        bpb.table_size_16 = rdr.read_u16::<LittleEndian>()?;
        bpb.sectors_per_track = rdr.read_u16::<LittleEndian>()?;
        bpb.head_side_count = rdr.read_u16::<LittleEndian>()?;
        bpb.hidden_sector_count = rdr.read_u32::<LittleEndian>()?; // hidden_sector_count
        bpb.total_sectors_32 = rdr.read_u32::<LittleEndian>()?;

        if bpb.table_size_16 == 0 {
            bpb.table_size_32 = rdr.read_u32::<LittleEndian>()?;
            bpb.extended_flags = rdr.read_u16::<LittleEndian>()?;
            bpb.fat_version = rdr.read_u16::<LittleEndian>()?;
            bpb.root_cluster = rdr.read_u32::<LittleEndian>()?;
            bpb.fat_info = rdr.read_u16::<LittleEndian>()?;
            bpb.backup_bs_sector = rdr.read_u16::<LittleEndian>()?;
            rdr.read(&mut bpb.reserved_0)?;
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fat_type_label)?;
            //bpb.boot_code = Vec::with_capacity(420);
            //rdr.read_exact(bpb.boot_code.as_mut_slice())?;
        } else {
            bpb.drive_num = rdr.read_u8()?;
            bpb.reserved_1 = rdr.read_u8()?;
            bpb.ext_sig = rdr.read_u8()?; // 0x29
            bpb.volume_id = rdr.read_u32::<LittleEndian>()?;
            rdr.read(&mut bpb.volume_label)?;
            rdr.read(&mut bpb.fat_type_label)?;
            //bpb.boot_code = Vec::with_capacity(448);
            //rdr.read_exact(bpb.boot_code.as_mut_slice())?;
        }
        Ok(bpb)
    }

    fn read_boot_record(rdr: &mut Read) -> io::Result<FatBootRecord> {
        let mut boot: FatBootRecord = Default::default();
        rdr.read(&mut boot.bootjmp)?;
        rdr.read(&mut boot.oem_name)?;
        boot.bpb = FatFileSystem::<T>::read_bpb(rdr)?;

        if boot.bpb.table_size_16 == 0 {
            rdr.read_exact(&mut boot.boot_code[0..420])?;
        } else {
            rdr.read_exact(&mut boot.boot_code[0..448])?;
        }
        rdr.read(&mut boot.boot_sig)?;
        Ok(boot)
    }

    fn seek_to_sector(&mut self, sector: u64) -> io::Result<()> {
        self.rdr.seek(SeekFrom::Start(sector*512))?;
        Ok(())
    }

    fn sector_from_cluster(&self, cluster: u32) -> u32 {
        ((cluster - 2) * self.boot.bpb.sectors_per_cluster as u32) + self.first_data_sector
    }

    fn read_dir_entry(&mut self) -> io::Result<FatDirEntry> {
        let mut name = [0; 11];
        self.rdr.read(&mut name)?;
        Ok(FatDirEntry {
            name:             name,
            attrs:            self.rdr.read_u8()?,
            reserved_0:       self.rdr.read_u8()?,
            creation_time_0:  self.rdr.read_u8()?,
            creation_time_1:  self.rdr.read_u16::<LittleEndian>()?,
            creation_date:    self.rdr.read_u16::<LittleEndian>()?,
            access_date:      self.rdr.read_u16::<LittleEndian>()?,
            first_cluster_hi: self.rdr.read_u16::<LittleEndian>()?,
            mod_time:         self.rdr.read_u16::<LittleEndian>()?,
            mod_date:         self.rdr.read_u16::<LittleEndian>()?,
            first_cluster_lo: self.rdr.read_u16::<LittleEndian>()?,
            size:             self.rdr.read_u32::<LittleEndian>()?,
        })
    }

    fn read_dir(&mut self) -> io::Result<()> {
        let pos = self.rdr.seek(SeekFrom::Current(0))?;
        println!("Reading dir at {}", pos);
        loop {
            let entry = self.read_dir_entry()?;
            if entry.name[0] == 0 {
                break; // end of dir
            }
            if entry.name[0] == 0xE5 {
                continue; // deleted
            }
            let name_str = str::from_utf8(&entry.name).unwrap().trim_right();
            println!("name {} size {} cluster {}", name_str, entry.size, entry.first_cluster_lo);
        }
        Ok(())
    }

    pub fn read_root_dir(&mut self) -> io::Result<()> {
        let first_root_dir_sector = match self.fat_type {
            FatType::Fat12 | FatType::Fat16 => self.first_data_sector - self.root_dir_sectors,
            _ => self.sector_from_cluster(self.boot.bpb.root_cluster)
        };
        self.seek_to_sector(first_root_dir_sector as u64)?;
        self.read_dir()?;
        Ok(())
    }
}

fn fat_test() -> io::Result<()> {
    let file = File::open("resources/floppy.img")?;
    let mut buf_rdr = BufReader::new(file);
    let mut fs = FatFileSystem::new(&mut buf_rdr)?;
    fs.read_root_dir()?;
    Ok(())
}

fn main() {
    println!("FAT test!");
    fat_test().unwrap();
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

mod git;

extern crate getopts;
extern crate hyper;
extern crate oauth2;
extern crate queryst;
extern crate rustc_serialize;
extern crate tempdir;
extern crate unicase;
extern crate url;
extern crate uuid;

use getopts::Options;
use hyper::header;
use hyper::net::Openssl;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use oauth2::Config;
use rustc_serialize::Encodable;
use rustc_serialize::json::{self, Json};
use queryst::parse;
use std::env;
use std::error::Error;
use std::io::Read;
use std::string::String;
use unicase::UniCase;
use url::parse_path;
use self::uuid::Uuid;

fn main() {
    let (listen_address, ssl, oauth_config, oauth_redirect_path) = parse_flags();

    let handler = Handler{ oauth_config: oauth_config, oauth_redirect_path: oauth_redirect_path, };

    println!("Listening on {}", listen_address);
    if ssl.is_some() {
        Server::https(&listen_address[..], ssl.unwrap()).unwrap().handle(handler).unwrap();
    } else {
        Server::http(&listen_address[..]).unwrap().handle(handler).unwrap();
    }
}

fn parse_flags() -> (String, Option<Openssl>, oauth2::Config, String) {
    let mut opts = Options::new();

    opts.optopt("p", "port", "Port on which to listen", "3000");
    opts.optopt("i", "interface", "Interface on which to listen", "0.0.0.0");

    opts.optflag("s", "ssl", "Whether to listen for HTTPS or just HTTP");
    opts.optopt("c", "certfile", "SSL certificate file", "/path/to/foo.crt");
    opts.optopt("k", "keyfile", "SSL key file", "/path/to/foo.key");

    opts.optopt("h", "host_and_port", "Hostname and port", "127.0.0.1:443");
    opts.optopt("", "oauth_client_id", "Github oauth client ID", "clientid");
    opts.optopt("", "oauth_client_secret", "Github oauth client secret", "clientsecret");
    opts.optopt("", "oauth_redirect_path", "Github oauth redirect URL", "/oauth/redirect");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();
    let interface = matches.opt_str("i").unwrap_or("0.0.0.0".to_owned());
    let port = matches.opt_str("p").unwrap_or("3000".to_owned());

    let ssl = match matches.opt_present("s") {
        true => Some(Openssl::with_cert_and_key(matches.opt_str("c").unwrap(), matches.opt_str("k").unwrap()).unwrap()),
        false => None,
    };

    let mut oauth_config = oauth2::Config::new(
        &matches.opt_str("oauth_client_id").unwrap(),
        &matches.opt_str("oauth_client_secret").unwrap(),
        "https://github.com/login/oauth/authorize",
        "https://github.com/login/oauth/access_token"
    );
    oauth_config.scopes.push("repo".to_owned());
    let oauth_redirect_path = matches.opt_str("oauth_redirect_path").unwrap();
    oauth_config.redirect_url = format!("https://{}{}", matches.opt_str("host_and_port").unwrap(), oauth_redirect_path);

    let host_and_port = format!("{}:{}", interface, port);
    return (host_and_port, ssl, oauth_config, oauth_redirect_path);
}

struct Handler {
    oauth_config: oauth2::Config,
    oauth_redirect_path: String,
}

impl hyper::server::Handler for Handler {
    fn handle(&self, req: Request, mut res: Response) {
        let (path, qs) = match req.uri {
            AbsolutePath(ref p) => match parse_path(p) {
                Ok((path, qs, _)) => (format!("/{}", path.join("/")), qs),
                Err(err) => { self.error(res, err.description()); return },
            },
            _ => { self.not_found(res); return },
        };

        res.headers_mut().set(header::AccessControlAllowOrigin::Any);
        res.headers_mut().set(header::AccessControlAllowHeaders(vec![UniCase("content-type".to_owned())]));

        if req.method == hyper::method::Method::Options {
            return
        }

        match &path[..] {
            "/squashmerge" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_squash_request) },
                _ => self.not_allowed(res)
            },
            "/rewritehistory" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_rewrite_history_request) },
                _ => self.not_allowed(res),
            },
            "/oauth/authorize" => match req.method {
                hyper::Get => self.handle_oauth_authorize_request(res),
                _ => self.not_allowed(res),
            },
            _ => {
                if path == &self.oauth_redirect_path[..] {
                    match req.method {
                        hyper::Get => match qs {
                            Some(q) => self.handle_oauth_exchange_request(&q, res),
                            None => self.bad_request(res),
                        },
                        _ => self.not_allowed(res),
                    }
                } else {
                    self.not_found(res);
                }
            },
        };
    }
}

impl Handler {
    fn handle_request<F>(&self, mut req: Request, res: Response, handler: F)
        where F : Fn(&str) -> Result<String, String> {

        let mut body_string = String::new();
        let err = req.read_to_string(&mut body_string);
        if err.is_err() {
            self.error(res, &err.err().unwrap().description());
            return;
        }

        match handler(&body_string) {
            Ok(sha) => self.send_json(res, &ShaResponse { sha: &sha, merged: true }),
            Err(err) => self.error(res, &err),
        };
    }

    fn handle_squash_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::squash_merge(
            get_json_string!(body, "base_repo"),
            get_json_string!(body, "base_branch"),
            get_json_string!(body, "head_repo"),
            get_json_string!(body, "head_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
        );
    }

    fn handle_rewrite_history_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::rewrite_history(
            get_json_string!(body, "repo"),
            get_json_string!(body, "branch"),
            get_json_string!(body, "baseline_repo"),
            get_json_string!(body, "baseline_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password")
        );
    }

    fn handle_oauth_authorize_request(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::Found;
        res.headers_mut().set(header::Location(self.oauth_config.authorize_url(Uuid::new_v4().to_hyphenated_string()).to_string()));
    }

    fn handle_oauth_exchange_request(&self, qs: &str, res: Response) {
        let obj = match parse(qs) {
            Ok(q) => q,
            Err(err) => { self.error(res, &format!("Error parsing querystring: {}", err.message)); return },
        };
        let code = match obj.find("code") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "code not a string"); return },
            },
            None => { self.error(res, "No code present"); return },
        };
        let token = self.oauth_config.exchange(code.to_owned());
        match token {
            Ok(tok) => self.send_json(res, &TokenResponse { access_token: &tok.access_token }),
            Err(tok) => self.error(res, &format!("Error exchanging token: {}", tok)),
        };
    }

    fn send_json<T: Encodable>(&self, mut res: Response, obj: &T) {
        match json::encode(obj) {
            Ok(o) => { let _ = res.send(o.as_bytes()); },
            Err(_) => {
                let _ = *res.status_mut() = StatusCode::InternalServerError;
                let _ = res.send("{\"message\": \"error serializing response\"}".as_bytes());
            },
        };
    }

    fn error(&self, mut res: Response, description: &str) {
        let _ = *res.status_mut() = StatusCode::InternalServerError;
        self.send_json(res, &ErrorResponse { message: description });
    }

    fn bad_request(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::BadRequest;
    }

    fn not_allowed(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::MethodNotAllowed;
    }

    fn not_found(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::NotFound;
    }
}

#[derive(RustcEncodable)]
struct ShaResponse<'a> {
    sha: &'a str,
    merged: bool,
}

#[derive(RustcEncodable)]
struct ErrorResponse<'a> {
    message: &'a str,
}

#[derive(RustcEncodable)]
struct TokenResponse<'a> {
    access_token: &'a str,
}
<commit_msg>Redirect oauth if redirect_uri is passed<commit_after>#[macro_use]
mod macros;

mod git;

extern crate getopts;
extern crate hyper;
extern crate oauth2;
extern crate queryst;
extern crate rustc_serialize;
extern crate tempdir;
extern crate unicase;
extern crate url;
extern crate uuid;

use getopts::Options;
use hyper::header;
use hyper::net::Openssl;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri::AbsolutePath;
use oauth2::Config;
use rustc_serialize::Encodable;
use rustc_serialize::json::{self, Json};
use queryst::parse;
use std::collections::HashMap;
use std::env;
use std::error::Error;
use std::io::Read;
use std::string::String;
use std::sync::{Arc, Mutex};
use unicase::UniCase;
use url::parse_path;
use self::uuid::Uuid;

fn main() {
    let (listen_address, ssl, oauth_config, oauth_redirect_path) = parse_flags();

    let handler = Handler{
        oauth_config: oauth_config,
        oauth_redirect_path: oauth_redirect_path,
        redirect_uris: Arc::new(Mutex::new(HashMap::new())),
    };

    println!("Listening on {}", listen_address);
    if ssl.is_some() {
        Server::https(&listen_address[..], ssl.unwrap()).unwrap().handle(handler).unwrap();
    } else {
        Server::http(&listen_address[..]).unwrap().handle(handler).unwrap();
    }
}

fn parse_flags() -> (String, Option<Openssl>, oauth2::Config, String) {
    let mut opts = Options::new();

    opts.optopt("p", "port", "Port on which to listen", "3000");
    opts.optopt("i", "interface", "Interface on which to listen", "0.0.0.0");

    opts.optflag("s", "ssl", "Whether to listen for HTTPS or just HTTP");
    opts.optopt("c", "certfile", "SSL certificate file", "/path/to/foo.crt");
    opts.optopt("k", "keyfile", "SSL key file", "/path/to/foo.key");

    opts.optopt("h", "host_and_port", "Hostname and port", "127.0.0.1:443");
    opts.optopt("", "oauth_client_id", "Github oauth client ID", "clientid");
    opts.optopt("", "oauth_client_secret", "Github oauth client secret", "clientsecret");
    opts.optopt("", "oauth_redirect_path", "Github oauth redirect URL", "/oauth/redirect");

    let args: Vec<String> = env::args().collect();
    let matches = opts.parse(&args[1..]).unwrap();
    let interface = matches.opt_str("i").unwrap_or("0.0.0.0".to_owned());
    let port = matches.opt_str("p").unwrap_or("3000".to_owned());

    let ssl = match matches.opt_present("s") {
        true => Some(Openssl::with_cert_and_key(matches.opt_str("c").unwrap(), matches.opt_str("k").unwrap()).unwrap()),
        false => None,
    };

    let mut oauth_config = oauth2::Config::new(
        &matches.opt_str("oauth_client_id").unwrap(),
        &matches.opt_str("oauth_client_secret").unwrap(),
        "https://github.com/login/oauth/authorize",
        "https://github.com/login/oauth/access_token"
    );
    oauth_config.scopes.push("repo".to_owned());
    let oauth_redirect_path = matches.opt_str("oauth_redirect_path").unwrap();
    oauth_config.redirect_url = format!("https://{}{}", matches.opt_str("host_and_port").unwrap(), oauth_redirect_path);

    let host_and_port = format!("{}:{}", interface, port);
    return (host_and_port, ssl, oauth_config, oauth_redirect_path);
}

struct Handler {
    oauth_config: oauth2::Config,
    oauth_redirect_path: String,
    redirect_uris: Arc<Mutex<HashMap<String, String>>>,
}

impl hyper::server::Handler for Handler {
    fn handle(&self, req: Request, mut res: Response) {
        let (path, qs) = match req.uri {
            AbsolutePath(ref p) => match parse_path(p) {
                Ok((path, qs, _)) => (format!("/{}", path.join("/")), qs),
                Err(err) => { self.error(res, err.description()); return },
            },
            _ => { self.not_found(res); return },
        };

        res.headers_mut().set(header::AccessControlAllowOrigin::Any);
        res.headers_mut().set(header::AccessControlAllowHeaders(vec![UniCase("content-type".to_owned())]));

        if req.method == hyper::method::Method::Options {
            return
        }

        match &path[..] {
            "/squashmerge" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_squash_request) },
                _ => self.not_allowed(res)
            },
            "/rewritehistory" => match req.method {
                hyper::Post => { self.handle_request(req, res, Handler::handle_rewrite_history_request) },
                _ => self.not_allowed(res),
            },
            "/oauth/authorize" => match req.method {
                hyper::Get => self.handle_oauth_authorize_request(qs, res),
                _ => self.not_allowed(res),
            },
            _ => {
                if path == &self.oauth_redirect_path[..] {
                    match req.method {
                        hyper::Get => match qs {
                            Some(q) => self.handle_oauth_exchange_request(&q, res),
                            None => self.bad_request(res),
                        },
                        _ => self.not_allowed(res),
                    }
                } else {
                    self.not_found(res);
                }
            },
        };
    }
}

impl Handler {
    fn handle_request<F>(&self, mut req: Request, res: Response, handler: F)
        where F : Fn(&str) -> Result<String, String> {

        let mut body_string = String::new();
        let err = req.read_to_string(&mut body_string);
        if err.is_err() {
            self.error(res, &err.err().unwrap().description());
            return;
        }

        match handler(&body_string) {
            Ok(sha) => self.send_json(res, &ShaResponse { sha: &sha, merged: true }),
            Err(err) => self.error(res, &err),
        };
    }

    fn handle_squash_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::squash_merge(
            get_json_string!(body, "base_repo"),
            get_json_string!(body, "base_branch"),
            get_json_string!(body, "head_repo"),
            get_json_string!(body, "head_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password"),
        );
    }

    fn handle_rewrite_history_request(body_string: &str) -> Result<String, String> {
        let body = try_or_string!(Json::from_str(body_string));

        return git::rewrite_history(
            get_json_string!(body, "repo"),
            get_json_string!(body, "branch"),
            get_json_string!(body, "baseline_repo"),
            get_json_string!(body, "baseline_branch"),
            get_json_string!(body, "commit_message"),
            get_json_string!(body, "username"),
            get_json_string!(body, "password")
        );
    }

    fn handle_oauth_authorize_request(&self, qs: Option<String>, mut res: Response) {
        let uuid = Uuid::new_v4().to_hyphenated_string();

        let redirect_uri = self.get_redirect_uri(qs);

        if redirect_uri.is_some() {
            let mut uris = self.redirect_uris.lock().unwrap();
            uris.insert(uuid.clone(), redirect_uri.unwrap().to_owned());
        }

        let _ = *res.status_mut() = StatusCode::Found;
        res.headers_mut().set(header::Location(self.oauth_config.authorize_url(uuid).to_string()));
    }

    fn handle_oauth_exchange_request(&self, qs: &str, res: Response) {
        let obj = match parse(qs) {
            Ok(q) => q,
            Err(err) => { self.error(res, &format!("Error parsing querystring: {}", err.message)); return },
        };
        let code = match obj.find("code") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "code not a string"); return },
            },
            None => { self.error(res, "No code present"); return },
        };
        let state = match obj.find("state") {
            Some(c) => match c.as_string() {
                Some(c) => c,
                None => { self.error(res, "state not a string"); return },
            },
            None => { self.error(res, "No state present"); return },
        };
        let token = self.oauth_config.exchange(code.to_owned());
        match token {
            Ok(tok) => self.respond_with_token(res, state, &tok.access_token),
            Err(tok) => self.error(res, &format!("Error exchanging token: {}", tok)),
        };
    }

    fn respond_with_token(&self, mut res: Response, uuid: &str, token: &str) {
        let mut uris = self.redirect_uris.lock().unwrap();
        match uris.remove(uuid) {
            Some(uri) => {
                let _ = *res.status_mut() = StatusCode::Found;
                // TODO: Form URI better
                res.headers_mut().set(header::Location(format!("{}?token={}", uri, token)));
            },
            None => { self.send_json(res, &TokenResponse { access_token: &token }); }
        };
    }

    fn send_json<T: Encodable>(&self, mut res: Response, obj: &T) {
        match json::encode(obj) {
            Ok(o) => { let _ = res.send(o.as_bytes()); },
            Err(_) => {
                let _ = *res.status_mut() = StatusCode::InternalServerError;
                let _ = res.send("{\"message\": \"error serializing response\"}".as_bytes());
            },
        };
    }

    fn get_redirect_uri(&self, qs: Option<String>) -> Option<String> {
        let kv = match qs {
            Some(q) => match parse(&q) {
                Ok(kv) => kv,
                Err(_) => return None,
            },
            None => return None,
        };
        return kv.find("redirect_uri")
            .and_then(|v| v.as_string())
            .and_then(|v| Some(v.to_owned().clone()));
    }

    fn error(&self, mut res: Response, description: &str) {
        let _ = *res.status_mut() = StatusCode::InternalServerError;
        self.send_json(res, &ErrorResponse { message: description });
    }

    fn bad_request(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::BadRequest;
    }

    fn not_allowed(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::MethodNotAllowed;
    }

    fn not_found(&self, mut res: Response) {
        let _ = *res.status_mut() = StatusCode::NotFound;
    }
}

#[derive(RustcEncodable)]
struct ShaResponse<'a> {
    sha: &'a str,
    merged: bool,
}

#[derive(RustcEncodable)]
struct ErrorResponse<'a> {
    message: &'a str,
}

#[derive(RustcEncodable)]
struct TokenResponse<'a> {
    access_token: &'a str,
}
<|endoftext|>


<commit_before>extern crate time;

use std::process::{Command, exit, ExitStatus};
use std::env;
use time::PreciseTime;

#[cfg(unix)]
use std::os::unix::process::ExitStatusExt ;

#[cfg(unix)]
fn signal(status: &ExitStatus) -> Option<i32> { status.signal() }
#[cfg(not(unix))]
fn signal(_: &ExitStatus) -> Option<i32> { None }

fn main() {
    let arguments: Vec<_> = env::args().collect();
    if arguments.len() < 2 {
        println!("Usage: totalrecall <cmd ...>");
        exit(-1);
    }

    loop {
        let start = PreciseTime::now();
        match Command::new(&arguments[1])
                .args(&arguments[2..])
                .status() {
            Err(err) => {
                println!("Error running {:?}: {}", &arguments, err);
                exit(-1);
            },
            Ok(status) if status.success() => exit(0),
            Ok(status) => {
                println!("totalrecall: After {}s", start.to(PreciseTime::now()).num_seconds());
                if let Some(signum) = signal(&status) {
                    println!("totalrecall: {} exited with signal({}), exiting",
                            arguments[1], signum);
                    exit(-1);
                }

                if let Some(code) = status.code() {
                    println!("totalrecall: {} exited with code({}), restarting",
                            arguments[1], code);
                } else {
                    println!("totalrecall: {} terminated", arguments[1]);
                    exit(-1);
                }
            }
        };
    }
}
<commit_msg>Add restart delay if program runtime < 2s<commit_after>extern crate time;

use std::process::{Command, exit, ExitStatus};
use std::env;
use time::PreciseTime;
use std::thread::sleep;
use std::time::Duration;

#[cfg(unix)]
use std::os::unix::process::ExitStatusExt ;

#[cfg(unix)]
fn signal(status: &ExitStatus) -> Option<i32> { status.signal() }
#[cfg(not(unix))]
fn signal(_: &ExitStatus) -> Option<i32> { None }

fn main() {
    let arguments: Vec<_> = env::args().collect();
    if arguments.len() < 2 {
        println!("Usage: totalrecall <cmd ...>");
        exit(-1);
    }

    loop {
        let start = PreciseTime::now();
        match Command::new(&arguments[1])
                .args(&arguments[2..])
                .status() {
            Err(err) => {
                println!("Error running {:?}: {}", &arguments, err);
                exit(-1);
            },
            Ok(status) if status.success() => exit(0),
            Ok(status) => {
                if let Some(signum) = signal(&status) {
                    println!("totalrecall: {} exited with signal({}), exiting",
                            arguments[1], signum);
                    exit(-1);
                }

                if let Some(code) = status.code() {
                    if let Ok(elapsed) = start.to(PreciseTime::now()).to_std() {
		        if elapsed.as_secs() < 2 {
                            sleep(Duration::from_secs(1))
		        }
                        println!("totalrecall: After {}s {} exited with code({}), restarting",
                                elapsed.as_secs(),
                                arguments[1], code);
                    } else {
                        println!("totalrecall: {} exited with code({}), restarting",
                                arguments[1], code);
                    }
                } else {
                    println!("totalrecall: {} terminated", arguments[1]);
                    exit(-1);
                }
            }
        };
    }
}
<|endoftext|>


<commit_before>extern crate calamine;
extern crate csv;

use std::env;
use std::path::PathBuf;
use calamine::{Excel, Range, DataType, Result};

fn read_as_excel(sce: PathBuf) {
    let mut xl = Excel::open(&sce).unwrap();

    let sheet_name = xl.sheet_names().unwrap()[0];

    let mut xl2 = Excel::open(&sce).unwrap();
    let range = xl2.worksheet_range(&sheet_name).unwrap();

    write_range(range).unwrap();
}

fn read_as_csv(sce: PathBuf) {
    let mut rdr = csv::Reader::from_file(&sce).unwrap();
    for row in rdr.records().map(|r| r.unwrap()) {
        let n = row.len() - 1;
        for (i, c) in row.iter().enumerate() {
            print!("{}", c);
            if i != n {
                let _ = print!(",");
            }

        }
        println!("");
    }
}

fn main() {
    // converts first argument into a csv (same name, silently overrides
    // if the file already exists

    let file = env::args()
        .skip(1)
        .next()
        .expect("Please provide an file to show, csv, excel");
    let sce = PathBuf::from(file);
    match sce.extension().and_then(|s| s.to_str()) {
        Some("xlsx") | Some("xlsm") | Some("xlsb") | Some("xls") => read_as_excel(sce),
        Some("csv") | Some("txt") => read_as_csv(sce),
        _ => panic!("Expecting an excel file"),
    }

}

fn write_range(range: Range) -> Result<()> {
    let n = range.get_size().1 - 1;
    for r in range.rows() {
        for (i, c) in r.iter().enumerate() {
            let _ = match *c {
                DataType::Empty => println!(""),
                DataType::String(ref s) => print!("{}", s),
                DataType::Float(ref f) => print!("{}", f),
                DataType::Int(ref i) => print!("{}", i),
                DataType::Error(ref e) => print!("{:?}", e),
                DataType::Bool(ref b) => print!("{}", b),
            };
            if i != n {
                let _ = print!(",");
            }
        }
        let _ = println!("");
    }
    Ok(())
}
<commit_msg>cleanup code<commit_after>extern crate calamine;
extern crate csv;

use std::env;
use std::path::PathBuf;
use calamine::{Excel, Range, DataType, Result};

fn read_as_excel(sce: PathBuf) {
    let mut xl = Excel::open(&sce).unwrap();

    let range_result = xl.sheet_names()
        .map(|elem| elem[0].to_string())
        .and_then(|name| xl.worksheet_range(&name));
    let range = range_result.unwrap();
    write_range(range).unwrap();
}

fn read_as_csv(sce: PathBuf) {
    let mut rdr = csv::Reader::from_file(&sce).unwrap();
    for row in rdr.records().map(|r| r.unwrap()) {
        let n = row.len() - 1;
        for (i, c) in row.iter().enumerate() {
            print!("{}", c);
            if i != n {
                let _ = print!(",");
            }

        }
        println!("");
    }
}

fn main() {
    // converts first argument into a csv (same name, silently overrides
    // if the file already exists

    let file = env::args()
        .skip(1)
        .next()
        .expect("Please provide an file to show, csv, excel");
    let sce = PathBuf::from(file);
    match sce.extension().and_then(|s| s.to_str()) {
        Some("xlsx") | Some("xlsm") | Some("xlsb") | Some("xls") => read_as_excel(sce),
        Some("csv") | Some("txt") => read_as_csv(sce),
        _ => panic!("Expecting an excel file"),
    }

}

fn write_range(range: Range) -> Result<()> {
    let n = range.get_size().1 - 1;
    for r in range.rows() {
        for (i, c) in r.iter().enumerate() {
            let _ = match *c {
                DataType::Empty => println!(""),
                DataType::String(ref s) => print!("{}", s),
                DataType::Float(ref f) => print!("{}", f),
                DataType::Int(ref i) => print!("{}", i),
                DataType::Error(ref e) => print!("{:?}", e),
                DataType::Bool(ref b) => print!("{}", b),
            };
            if i != n {
                let _ = print!(",");
            }
        }
        let _ = println!("");
    }
    Ok(())
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Add Iron skeleton<commit_after>extern crate iron;
extern crate router;

use iron::prelude::*;
use iron::status;
use router::Router;

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello, world!")))
}

fn main() {
    let mut router = Router::new();
    router.get("/", hello_world);
    Iron::new(router).http("0.0.0.0:18800").unwrap();
}
<|endoftext|>