<commit_before>use macroquad::prelude::*;

use colour::Colour;
use graph::{Graph, Position};
use grid::Grid;

mod colour;
mod graph;
mod grid;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: usize,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: usize) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, graph: &Graph) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn handle_click(&self, graph: &mut Graph) {
        if !is_mouse_button_pressed(MouseButton::Left) {
            return;
        }

        if let Some(position) = self.cell_position(mouse_position()) {
            let clicked_component = graph.find_component(&position);
            let colour = clicked_component.colour;

            println!("Detected click at cell ({}, {}) with colour {:#?}", position.column, position.row, colour);

            graph.change_colour_of_component_at(&Position{column: 0_usize, row: 0_usize}, colour);
        }
    }
}

enum GameState {
    Solving,
    Solved,
}

struct Game {
    state: GameState
}

impl Game {
    fn create() -> Self {
        Self {
            state: GameState::Solving,
        }
    }
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;
    let grid = Grid::generate(size);
    let mut graph = Graph::create(&grid);
    println!("{:#?}", graph);

    let mut ui = Ui::create(size);

    let mut game = Game::create();

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        ui.handle_click(&mut graph);

        ui.resize();
        ui.render(&graph);

        match game.state {
            GameState::Solving =>
            if graph.components.len() == 1 {
                game.state = GameState::Solved;
                println!("Done");
            }
            GameState::Solved => (),
        }

        next_frame().await
    }
}
<commit_msg>Move graph into Game<commit_after>use macroquad::prelude::*;

use colour::Colour;
use graph::{Graph, Position};
use grid::Grid;

mod colour;
mod graph;
mod grid;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: usize,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: usize) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, graph: &Graph) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn handle_click(&self, graph: &mut Graph) {
        if !is_mouse_button_pressed(MouseButton::Left) {
            return;
        }

        if let Some(position) = self.cell_position(mouse_position()) {
            let clicked_component = graph.find_component(&position);
            let colour = clicked_component.colour;

            println!("Detected click at cell ({}, {}) with colour {:#?}", position.column, position.row, colour);

            graph.change_colour_of_component_at(&Position{column: 0_usize, row: 0_usize}, colour);
        }
    }
}

enum GameState {
    Solving,
    Solved,
}

struct Game {
    state: GameState,
    graph: Graph,
}

impl Game {
    fn create(size: usize) -> Self {
        let grid = Grid::generate(size);
        let graph = Graph::create(&grid);
        Self {
            state: GameState::Solving,
            graph,
        }
    }
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;

    let mut game = Game::create(size);
    let mut ui = Ui::create(size);

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        ui.handle_click(&mut game.graph);

        ui.resize();
        ui.render(&game.graph);

        match game.state {
            GameState::Solving =>
            if game.graph.components.len() == 1 {
                game.state = GameState::Solved;
                println!("Done");
            }
            GameState::Solved => (),
        }

        next_frame().await
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;
extern crate guzuta;

fn main() {
    env_logger::init().unwrap();

    let app = clap::App::new("guzuta")
        .version("0.1.0")
        .about("Custom repository manager for ArchLinux pacman")
        .setting(clap::AppSettings::SubcommandRequired)
        .subcommand(clap::SubCommand::with_name("build")
            .about("Build package in systemd-nspawn environment")
            .arg(clap::Arg::with_name("chroot-dir")
                .long("chroot-dir")
                .takes_value(true)
                .required(true)
                .help("Path to chroot top"))
            .arg(clap::Arg::with_name("package-key")
                .long("package-key")
                .takes_value(true)
                .help("GPG key to sign packages"))
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("logdest")
                .long("logdest")
                .takes_value(true)
                .help("Path to the directory to store logs"))
            .arg(clap::Arg::with_name("repo-dir")
                .long("repo-dir")
                .takes_value(true)
                .required(true)
                .help("Path to the repository directory"))
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("arch")
                .long("arch")
                .takes_value(true)
                .required(true)
                .help("Architecture"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD")))
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME from DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-remove")
            .about("Remove PACKAGE_NAME from FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("abs-add")
            .about("Add source package to abs tarball")
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("abs-remove")
            .about("Remove source package from abs tarball")
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Package name to be removed"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("omakase")
            .about("Manage repository with S3")
            .subcommand(clap::SubCommand::with_name("build")
                .about("Build PACKAGE_NAME")
                .arg(clap::Arg::with_name("PACKAGE_NAME").required(true))));
    let matches = app.get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("build", Some(build_command)) => build(build_command),
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        ("files-remove", Some(files_remove_command)) => {
            files_remove(files_remove_command);
        }
        ("abs-add", Some(abs_add_command)) => {
            abs_add(abs_add_command);
        }
        ("abs-remove", Some(abs_remove_command)) => {
            abs_remove(abs_remove_command);
        }
        ("omakase", Some(omakase_command)) => {
            match omakase_command.subcommand() {
                ("build", Some(build_command)) => {
                    omakase_build(build_command);
                }
                _ => {
                    panic!("Unknown subcommand");
                }
            }
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn build(args: &clap::ArgMatches) {
    let arch = match args.value_of("arch").unwrap() {
        "i686" => guzuta::Arch::I686,
        "x86_64" => guzuta::Arch::X86_64,
        arch => panic!("Unknown architecture: {}", arch),
    };
    let chroot = guzuta::ChrootHelper::new(args.value_of("chroot-dir").unwrap(), arch);
    let package_signer = args.value_of("package-key").map(|key| guzuta::Signer::new(key));
    let srcdest = args.value_of("srcdest").unwrap_or(".");
    let builder = guzuta::Builder::new(package_signer.as_ref(),
                                       srcdest,
                                       args.value_of("logdest").unwrap_or("."));
    let repo_dir = std::path::Path::new(args.value_of("repo-dir").unwrap());
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();

    let repo_signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let mut db_path = repo_dir.join(repo_name).into_os_string();
    db_path.push(".db");
    let mut files_path = repo_dir.join(repo_name).into_os_string();
    files_path.push(".files");
    let mut db_repo = guzuta::Repository::new(std::path::PathBuf::from(db_path),
                                              repo_signer.as_ref());
    let mut files_repo = guzuta::Repository::new(std::path::PathBuf::from(files_path),
                                                 repo_signer.as_ref());
    db_repo.load().unwrap();
    files_repo.load().unwrap();
    let mut abs_path = repo_dir.join(repo_name).into_os_string();
    abs_path.push(".abs.tar.gz");
    let abs = guzuta::Abs::new(repo_name, abs_path);

    let package_paths = builder.build_package(package_dir, repo_dir, &chroot).unwrap();

    for path in package_paths {
        let package = guzuta::Package::load(&path).unwrap();
        db_repo.add(&package);
        files_repo.add(&package);
    }

    abs.add(package_dir, srcdest).unwrap();
    db_repo.save(false).unwrap();
    files_repo.save(true).unwrap();
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap()).unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load().unwrap();
    repository.add(&package);
    repository.save(false).unwrap();
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load().unwrap();
    repository.remove(&package_name);
    repository.save(false).unwrap();
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap()).unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load().unwrap();
    repository.add(&package);
    repository.save(true).unwrap();
}

fn files_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load().unwrap();
    repository.remove(&package_name);
    repository.save(true).unwrap();
}

fn abs_add(args: &clap::ArgMatches) {
    let srcdest = std::path::PathBuf::from(args.value_of("srcdest").unwrap_or("."));
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.add(package_dir, srcdest).unwrap();
}

fn abs_remove(args: &clap::ArgMatches) {
    let repo_name = args.value_of("repo-name").unwrap();
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.remove(package_name).unwrap();
}

fn omakase_build(args: &clap::ArgMatches) {
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let file = std::fs::File::open(".guzuta.yml").unwrap();
    let config = guzuta::omakase::Config::from_reader(file).unwrap();
    let package_signer = config.package_key.as_ref().map(|key| guzuta::Signer::new(key));
    let repo_signer = config.repo_key.as_ref().map(|key| guzuta::Signer::new(key));
    let builder = guzuta::Builder::new(package_signer.as_ref(), &config.srcdest, &config.logdest);
    let s3 = config.s3.as_ref().map(|s3_config| guzuta::omakase::S3::new(s3_config));

    for (arch, build_config) in &config.builds {
        let chroot = guzuta::ChrootHelper::new(&build_config.chroot, arch.clone());
        let repo_dir = config.repo_dir(arch);
        let db_path = config.db_path(arch);
        let files_path = config.files_path(arch);
        let abs_path = config.abs_path(arch);
        let package_dir = config.package_dir(package_name);

        if let Some(ref s3) = s3 {
            s3.download_repository(&config, &arch).unwrap();
        }

        let mut db_repo = guzuta::Repository::new(db_path, repo_signer.as_ref());
        let mut files_repo = guzuta::Repository::new(files_path, repo_signer.as_ref());
        let abs = guzuta::Abs::new(&config.name, abs_path);
        db_repo.load().unwrap();
        files_repo.load().unwrap();
        std::fs::create_dir_all(repo_dir.as_path()).unwrap();

        let package_paths = builder.build_package(package_dir.as_path(), repo_dir, &chroot)
            .unwrap();
        for path in &package_paths {
            let package = guzuta::Package::load(&path).unwrap();
            db_repo.add(&package);
            files_repo.add(&package);
        }

        abs.add(package_dir.as_path(), &config.srcdest).unwrap();
        db_repo.save(false).unwrap();
        files_repo.save(true).unwrap();

        if let Some(ref s3) = s3 {
            s3.upload_repository(&config, &arch, &package_paths).unwrap();
        }
    }
}
<commit_msg>Use crate_version!<commit_after>#[macro_use]
extern crate clap;
extern crate env_logger;
extern crate guzuta;

fn main() {
    env_logger::init().unwrap();

    let app = clap::App::new("guzuta")
        .version(crate_version!())
        .about("Custom repository manager for ArchLinux pacman")
        .setting(clap::AppSettings::SubcommandRequired)
        .subcommand(clap::SubCommand::with_name("build")
            .about("Build package in systemd-nspawn environment")
            .arg(clap::Arg::with_name("chroot-dir")
                .long("chroot-dir")
                .takes_value(true)
                .required(true)
                .help("Path to chroot top"))
            .arg(clap::Arg::with_name("package-key")
                .long("package-key")
                .takes_value(true)
                .help("GPG key to sign packages"))
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("logdest")
                .long("logdest")
                .takes_value(true)
                .help("Path to the directory to store logs"))
            .arg(clap::Arg::with_name("repo-dir")
                .long("repo-dir")
                .takes_value(true)
                .required(true)
                .help("Path to the repository directory"))
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("arch")
                .long("arch")
                .takes_value(true)
                .required(true)
                .help("Architecture"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD")))
        .subcommand(clap::SubCommand::with_name("repo-add")
            .about("Add PACKAGE_PATH to DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("repo-remove")
            .about("Remove PACKAGE_NAME from DB_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-add")
            .about("Add PACKAGE_PATH to FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_PATH")
                .required(true)
                .help("Path to package to be added"))
            .arg(clap::Arg::with_name("FILES_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("files-remove")
            .about("Remove PACKAGE_NAME from FILES_PATH")
            .arg(clap::Arg::with_name("repo-key")
                .long("repo-key")
                .takes_value(true)
                .help("GPG key to sign repository database"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Path to package to be removed"))
            .arg(clap::Arg::with_name("DB_PATH")
                .required(true)
                .help("Path to repository database")))
        .subcommand(clap::SubCommand::with_name("abs-add")
            .about("Add source package to abs tarball")
            .arg(clap::Arg::with_name("srcdest")
                .long("srcdest")
                .takes_value(true)
                .help("Path to the directory to store sources"))
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_DIR")
                .required(true)
                .help("Path to the directory containing PKGBUILD"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("abs-remove")
            .about("Remove source package from abs tarball")
            .arg(clap::Arg::with_name("repo-name")
                .long("repo-name")
                .takes_value(true)
                .required(true)
                .help("Repository name"))
            .arg(clap::Arg::with_name("PACKAGE_NAME")
                .required(true)
                .help("Package name to be removed"))
            .arg(clap::Arg::with_name("ABS_PATH")
                .required(true)
                .help("Path to abs tarball")))
        .subcommand(clap::SubCommand::with_name("omakase")
            .about("Manage repository with S3")
            .subcommand(clap::SubCommand::with_name("build")
                .about("Build PACKAGE_NAME")
                .arg(clap::Arg::with_name("PACKAGE_NAME").required(true))));
    let matches = app.get_matches();

    run_subcommand(matches.subcommand());
}

fn run_subcommand(subcommand: (&str, Option<&clap::ArgMatches>)) {
    match subcommand {
        ("build", Some(build_command)) => build(build_command),
        ("repo-add", Some(repo_add_command)) => {
            repo_add(repo_add_command);
        }
        ("repo-remove", Some(repo_remove_command)) => {
            repo_remove(repo_remove_command);
        }
        ("files-add", Some(files_add_command)) => {
            files_add(files_add_command);
        }
        ("files-remove", Some(files_remove_command)) => {
            files_remove(files_remove_command);
        }
        ("abs-add", Some(abs_add_command)) => {
            abs_add(abs_add_command);
        }
        ("abs-remove", Some(abs_remove_command)) => {
            abs_remove(abs_remove_command);
        }
        ("omakase", Some(omakase_command)) => {
            match omakase_command.subcommand() {
                ("build", Some(build_command)) => {
                    omakase_build(build_command);
                }
                _ => {
                    panic!("Unknown subcommand");
                }
            }
        }
        _ => {
            panic!("Unknown subcommand");
        }
    }
}

fn build(args: &clap::ArgMatches) {
    let arch = match args.value_of("arch").unwrap() {
        "i686" => guzuta::Arch::I686,
        "x86_64" => guzuta::Arch::X86_64,
        arch => panic!("Unknown architecture: {}", arch),
    };
    let chroot = guzuta::ChrootHelper::new(args.value_of("chroot-dir").unwrap(), arch);
    let package_signer = args.value_of("package-key").map(|key| guzuta::Signer::new(key));
    let srcdest = args.value_of("srcdest").unwrap_or(".");
    let builder = guzuta::Builder::new(package_signer.as_ref(),
                                       srcdest,
                                       args.value_of("logdest").unwrap_or("."));
    let repo_dir = std::path::Path::new(args.value_of("repo-dir").unwrap());
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();

    let repo_signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let mut db_path = repo_dir.join(repo_name).into_os_string();
    db_path.push(".db");
    let mut files_path = repo_dir.join(repo_name).into_os_string();
    files_path.push(".files");
    let mut db_repo = guzuta::Repository::new(std::path::PathBuf::from(db_path),
                                              repo_signer.as_ref());
    let mut files_repo = guzuta::Repository::new(std::path::PathBuf::from(files_path),
                                                 repo_signer.as_ref());
    db_repo.load().unwrap();
    files_repo.load().unwrap();
    let mut abs_path = repo_dir.join(repo_name).into_os_string();
    abs_path.push(".abs.tar.gz");
    let abs = guzuta::Abs::new(repo_name, abs_path);

    let package_paths = builder.build_package(package_dir, repo_dir, &chroot).unwrap();

    for path in package_paths {
        let package = guzuta::Package::load(&path).unwrap();
        db_repo.add(&package);
        files_repo.add(&package);
    }

    abs.add(package_dir, srcdest).unwrap();
    db_repo.save(false).unwrap();
    files_repo.save(true).unwrap();
}

fn repo_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap()).unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load().unwrap();
    repository.add(&package);
    repository.save(false).unwrap();
}

fn repo_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository = guzuta::Repository::new(std::path::PathBuf::from(args.value_of("DB_PATH")
                                                     .unwrap()),
                                                 signer.as_ref());

    repository.load().unwrap();
    repository.remove(&package_name);
    repository.save(false).unwrap();
}

fn files_add(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package = guzuta::Package::load(&args.value_of("PACKAGE_PATH").unwrap()).unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load().unwrap();
    repository.add(&package);
    repository.save(true).unwrap();
}

fn files_remove(args: &clap::ArgMatches) {
    let signer = args.value_of("repo-key").map(|key| guzuta::Signer::new(key));
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let mut repository =
        guzuta::Repository::new(std::path::PathBuf::from(args.value_of("FILES_PATH").unwrap()),
                                signer.as_ref());

    repository.load().unwrap();
    repository.remove(&package_name);
    repository.save(true).unwrap();
}

fn abs_add(args: &clap::ArgMatches) {
    let srcdest = std::path::PathBuf::from(args.value_of("srcdest").unwrap_or("."));
    let repo_name = args.value_of("repo-name").unwrap();
    let package_dir = args.value_of("PACKAGE_DIR").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.add(package_dir, srcdest).unwrap();
}

fn abs_remove(args: &clap::ArgMatches) {
    let repo_name = args.value_of("repo-name").unwrap();
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let abs_path = args.value_of("ABS_PATH").unwrap();

    let abs = guzuta::Abs::new(repo_name, abs_path);
    abs.remove(package_name).unwrap();
}

fn omakase_build(args: &clap::ArgMatches) {
    let package_name = args.value_of("PACKAGE_NAME").unwrap();
    let file = std::fs::File::open(".guzuta.yml").unwrap();
    let config = guzuta::omakase::Config::from_reader(file).unwrap();
    let package_signer = config.package_key.as_ref().map(|key| guzuta::Signer::new(key));
    let repo_signer = config.repo_key.as_ref().map(|key| guzuta::Signer::new(key));
    let builder = guzuta::Builder::new(package_signer.as_ref(), &config.srcdest, &config.logdest);
    let s3 = config.s3.as_ref().map(|s3_config| guzuta::omakase::S3::new(s3_config));

    for (arch, build_config) in &config.builds {
        let chroot = guzuta::ChrootHelper::new(&build_config.chroot, arch.clone());
        let repo_dir = config.repo_dir(arch);
        let db_path = config.db_path(arch);
        let files_path = config.files_path(arch);
        let abs_path = config.abs_path(arch);
        let package_dir = config.package_dir(package_name);

        if let Some(ref s3) = s3 {
            s3.download_repository(&config, &arch).unwrap();
        }

        let mut db_repo = guzuta::Repository::new(db_path, repo_signer.as_ref());
        let mut files_repo = guzuta::Repository::new(files_path, repo_signer.as_ref());
        let abs = guzuta::Abs::new(&config.name, abs_path);
        db_repo.load().unwrap();
        files_repo.load().unwrap();
        std::fs::create_dir_all(repo_dir.as_path()).unwrap();

        let package_paths = builder.build_package(package_dir.as_path(), repo_dir, &chroot)
            .unwrap();
        for path in &package_paths {
            let package = guzuta::Package::load(&path).unwrap();
            db_repo.add(&package);
            files_repo.add(&package);
        }

        abs.add(package_dir.as_path(), &config.srcdest).unwrap();
        db_repo.save(false).unwrap();
        files_repo.save(true).unwrap();

        if let Some(ref s3) = s3 {
            s3.upload_repository(&config, &arch, &package_paths).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate trivial_colours;
#[macro_use]
extern crate lazy_static;
extern crate mime_guess;
extern crate lazysort;
extern crate brotli2;
extern crate unicase;
extern crate base64;
extern crate flate2;
extern crate bzip2;
#[macro_use]
extern crate clap;
extern crate iron;
extern crate time;
extern crate url;
extern crate md6;

mod error;
mod options;

pub mod ops;
pub mod util;

pub use error::Error;
pub use options::Options;

use iron::Iron;
use std::io::stderr;
use std::process::exit;

fn main() {
    let result = actual_main();
    exit(result);
}

fn actual_main() -> i32 {
    if let Err(err) = result_main() {
        err.print_error(&mut stderr());
        err.exit_value()
    } else {
        0
    }
}

fn result_main() -> Result<(), Error> {
    {
        use std::path::Path;

        let mut pb = Path::new("asdf");
        pb.push("fdsa/capitalism");
        println!("{}", pb.display());

        return Ok(());
    }

    let opts = Options::parse();

    let responder = try!(if let Some(p) = opts.port {
        Iron::new(ops::HttpHandler::new(&opts))
            .http(("0.0.0.0", p))
            .map_err(|_| {
                Error::Io {
                    desc: "server",
                    op: "start",
                    more: Some("port taken"),
                }
            })
    } else {
        ops::try_ports(ops::HttpHandler::new(&opts), util::PORT_SCAN_LOWEST, util::PORT_SCAN_HIGHEST)
    });

    println!("{}Hosting \"{}\" on port {}...", trivial_colours::Reset, opts.hosted_directory.0, responder.socket.port());
    println!("Ctrl-C to stop.");
    println!();

    Ok(())
}
<commit_msg>I really should<commit_after>extern crate trivial_colours;
#[macro_use]
extern crate lazy_static;
extern crate mime_guess;
extern crate lazysort;
extern crate brotli2;
extern crate unicase;
extern crate base64;
extern crate flate2;
extern crate bzip2;
#[macro_use]
extern crate clap;
extern crate iron;
extern crate time;
extern crate url;
extern crate md6;

mod error;
mod options;

pub mod ops;
pub mod util;

pub use error::Error;
pub use options::Options;

use iron::Iron;
use std::io::stderr;
use std::process::exit;

fn main() {
    let result = actual_main();
    exit(result);
}

fn actual_main() -> i32 {
    if let Err(err) = result_main() {
        err.print_error(&mut stderr());
        err.exit_value()
    } else {
        0
    }
}

fn result_main() -> Result<(), Error> {
    let opts = Options::parse();

    let responder = try!(if let Some(p) = opts.port {
        Iron::new(ops::HttpHandler::new(&opts))
            .http(("0.0.0.0", p))
            .map_err(|_| {
                Error::Io {
                    desc: "server",
                    op: "start",
                    more: Some("port taken"),
                }
            })
    } else {
        ops::try_ports(ops::HttpHandler::new(&opts), util::PORT_SCAN_LOWEST, util::PORT_SCAN_HIGHEST)
    });

    println!("{}Hosting \"{}\" on port {}...", trivial_colours::Reset, opts.hosted_directory.0, responder.socket.port());
    println!("Ctrl-C to stop.");
    println!();

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2015 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate inprimitives;
extern crate rustc_serialize;
extern crate zmq;

mod config;

use config::agent::AgentConf;
use config::Config;
use inprimitives::{command, telemetry, trim_str};
use inprimitives::telemetry::TelemetryInit;
use rustc_serialize::json;
use std::error::Error;
use std::path::PathBuf;
use std::process::exit;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let mut ctx = zmq::Context::new();
    run(&mut ctx);
}

fn run(ctx: &mut zmq::Context) {
    // Load agent config
    let agent_conf: AgentConf;
    match load_agent_conf() {
        Ok(conf) => agent_conf = conf,
        Err(e) => {
            print_err(&e);
            exit(1);
        },
    }

    let mut listen_sock = ctx.socket(zmq::REP).unwrap();
    let dsn = format!("tcp://*:{}", agent_conf.listen_port);
    listen_sock.bind(&dsn).unwrap();

    loop {
        let endpoint_msg = listen_sock.recv_msg(0).unwrap();
        let endpoint = endpoint_msg.as_str().unwrap();

        match endpoint {
            "command::exec" => {
                let args;

                match recv_args(&mut listen_sock, 1, 1) {
                    Ok(r) => args = r,
                    Err(_) => continue,
                }

                match command::exec(&args[0]) {
                    Ok(output) => send_args(&mut listen_sock, vec![
                        "Ok",
                        &output.status.code().unwrap().to_string(),
                        trim_str(&String::from_utf8(output.stdout).unwrap()),
                        trim_str(&String::from_utf8(output.stderr).unwrap())
                    ]),
                    Err(e) => send_args(&mut listen_sock, vec!["Err", e.description()]),
                }
            },
            "telemetry" => {
                if recv_args(&mut listen_sock, 0, 0).is_err() {
                    continue;
                }

                match telemetry::Telemetry::init() {
                    Ok(telemetry) => {
                        let json = json::encode(&telemetry);
                        if json.is_err() {
                            send_args(&mut listen_sock, vec!["Err", json.unwrap_err().description() ])
                        } else {
                            send_args(&mut listen_sock, vec!["Ok", &json.unwrap() ]);
                        }
                    },
                    Err(e) => send_args(&mut listen_sock, vec!["Err", e.description() ]),
                }
            },
            _ => {
                listen_sock.send_str("Err", zmq::SNDMORE).unwrap();
                listen_sock.send_str(&format!("Invalid endpoint {}", endpoint), 0).unwrap();
                continue;
            }
        }
    }
}

/// Receive a variable number of args from sock. We expect the number
/// of args from `sock` to be between `min` and `max`.
/// If max = 0 then we allow a variable number of args.
fn recv_args(sock: &mut zmq::Socket, min: u8, max: u8) -> Result<Vec<String>, AgentError> {
    let mut args: Vec<String> = vec![];
    let mut counter = 0;

    // Always receive all args, otherwise our socket will be in the
    // wrong state to send messages.
    while sock.get_rcvmore().unwrap() == true {
        match sock.recv_string(0) {
            Ok(str) => {
                args.push(str.unwrap());
                counter += 1;
            },
            Err(e) => return Err(AgentError {
                message: "Could not receive from socket",
                root: RootError::ZmqError(e),
            }),
        }
    }

    if min > counter || (max < counter && max > 0) {
        sock.send_str("Err", zmq::SNDMORE).unwrap();
        sock.send_str("Missing argument", 0).unwrap();
        return Err(AgentError {
            message: "Received more args than expected",
            root: RootError::None(()),
        });
    }

    Ok(args)
}

fn send_args(sock: &mut zmq::Socket, args: Vec<&str>) {
    let iter = args.iter();
    let iter_len = iter.len();
    let mut x = 1;
    let mut flag;
    for msg in iter {
        if x < iter_len {
            flag = zmq::SNDMORE;
        } else {
            flag = 0;
        }

        sock.send_str(&msg, flag).unwrap();
        x += 1;
    }
}

fn load_agent_conf<'a>() -> Result<AgentConf, AgentError<'a>> {
    for p in ["/usr/local/etc", "/etc"].iter() {
        let mut path = PathBuf::from(p);
        path.push("intecture");
        path.push("agent.json");

        match AgentConf::load(&path) {
            Ok(conf) => return Ok(conf),
            Err(_) => continue,
        }
    }

    Err(AgentError {
        message: "Could not load agent.json",
        root: RootError::None(()),
    })
}

#[derive(Debug)]
pub struct AgentError<'a> {
    message: &'a str,
    root: RootError,
}

#[derive(Debug)]
pub enum RootError {
    None(()),
    ZmqError(zmq::Error),
}

fn print_err(e: &AgentError) {
    println!("{}", e.message);
    println!("{:?}", e.root);
}

#[cfg(test)]
mod tests {
    use zmq;

    /// Test providing 1 and only 1 arg
    #[test]
    fn test_recv_args_ok_eq() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 1).unwrap();
        assert_eq!(result, vec!["1"]);
    }

    /// Test providing 1 or more args
    #[test]
    fn test_recv_args_ok_range() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 2).unwrap();
        assert_eq!(result, vec!["1"]);
    }

    /// Test providing 1+ args
    #[test]
    fn test_recv_args_ok_variable() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", zmq::SNDMORE).unwrap();
        req_sock.send_str("2", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 0).unwrap();
        assert_eq!(result, vec!["1", "2"]);
    }

    /// Test failing less than 2 args
    #[test]
    fn test_recv_args_err_min() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 2, 2);
        assert!(result.is_err());
    }

    /// Test failing more than 1 arg
    #[test]
    fn test_recv_args_err_max() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", zmq::SNDMORE).unwrap();
        req_sock.send_str("2", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 0, 1);
        assert!(result.is_err());
    }

    /// Test sending args
    #[test]
    fn test_send_args() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        let req_vec = vec!["moo", "cow"];
        super::send_args(&mut req_sock, req_vec);

        assert_eq!(rep_sock.recv_string(0).unwrap().unwrap(), "moo");
        assert!(rep_sock.get_rcvmore().unwrap());
        assert_eq!(rep_sock.recv_string(0).unwrap().unwrap(), "cow");
    }
}<commit_msg>Removed dependence on trim_str<commit_after>// Copyright 2015 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

extern crate inprimitives;
extern crate rustc_serialize;
extern crate zmq;

mod config;

use config::agent::AgentConf;
use config::Config;
use inprimitives::{command, telemetry};
use inprimitives::telemetry::TelemetryInit;
use rustc_serialize::json;
use std::error::Error;
use std::path::PathBuf;
use std::process::exit;
use std::str;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let mut ctx = zmq::Context::new();
    run(&mut ctx);
}

fn run(ctx: &mut zmq::Context) {
    // Load agent config
    let agent_conf: AgentConf;
    match load_agent_conf() {
        Ok(conf) => agent_conf = conf,
        Err(e) => {
            print_err(&e);
            exit(1);
        },
    }

    let mut listen_sock = ctx.socket(zmq::REP).unwrap();
    let dsn = format!("tcp://*:{}", agent_conf.listen_port);
    listen_sock.bind(&dsn).unwrap();

    loop {
        let endpoint_msg = listen_sock.recv_msg(0).unwrap();
        let endpoint = endpoint_msg.as_str().unwrap();

        match endpoint {
            "command::exec" => {
                let args;

                match recv_args(&mut listen_sock, 1, 1) {
                    Ok(r) => args = r,
                    Err(_) => continue,
                }

                match command::exec(&args[0]) {
                    Ok(output) => send_args(&mut listen_sock, vec![
                        "Ok",
                        &output.status.code().unwrap().to_string(),
                        str::from_utf8(&output.stdout).unwrap().trim(),
                        str::from_utf8(&output.stderr).unwrap().trim()
                    ]),
                    Err(e) => send_args(&mut listen_sock, vec!["Err", e.description()]),
                }
            },
            "telemetry" => {
                if recv_args(&mut listen_sock, 0, 0).is_err() {
                    continue;
                }

                match telemetry::Telemetry::init() {
                    Ok(telemetry) => {
                        let json = json::encode(&telemetry);
                        if json.is_err() {
                            send_args(&mut listen_sock, vec!["Err", json.unwrap_err().description() ])
                        } else {
                            send_args(&mut listen_sock, vec!["Ok", &json.unwrap() ]);
                        }
                    },
                    Err(e) => send_args(&mut listen_sock, vec!["Err", e.description() ]),
                }
            },
            _ => {
                listen_sock.send_str("Err", zmq::SNDMORE).unwrap();
                listen_sock.send_str(&format!("Invalid endpoint {}", endpoint), 0).unwrap();
                continue;
            }
        }
    }
}

/// Receive a variable number of args from sock. We expect the number
/// of args from `sock` to be between `min` and `max`.
/// If max = 0 then we allow a variable number of args.
fn recv_args(sock: &mut zmq::Socket, min: u8, max: u8) -> Result<Vec<String>, AgentError> {
    let mut args: Vec<String> = vec![];
    let mut counter = 0;

    // Always receive all args, otherwise our socket will be in the
    // wrong state to send messages.
    while sock.get_rcvmore().unwrap() == true {
        match sock.recv_string(0) {
            Ok(str) => {
                args.push(str.unwrap());
                counter += 1;
            },
            Err(e) => return Err(AgentError {
                message: "Could not receive from socket",
                root: RootError::ZmqError(e),
            }),
        }
    }

    if min > counter || (max < counter && max > 0) {
        sock.send_str("Err", zmq::SNDMORE).unwrap();
        sock.send_str("Missing argument", 0).unwrap();
        return Err(AgentError {
            message: "Received more args than expected",
            root: RootError::None(()),
        });
    }

    Ok(args)
}

fn send_args(sock: &mut zmq::Socket, args: Vec<&str>) {
    let iter = args.iter();
    let iter_len = iter.len();
    let mut x = 1;
    let mut flag;
    for msg in iter {
        if x < iter_len {
            flag = zmq::SNDMORE;
        } else {
            flag = 0;
        }

        sock.send_str(&msg, flag).unwrap();
        x += 1;
    }
}

fn load_agent_conf<'a>() -> Result<AgentConf, AgentError<'a>> {
    for p in ["/usr/local/etc", "/etc"].iter() {
        let mut path = PathBuf::from(p);
        path.push("intecture");
        path.push("agent.json");

        match AgentConf::load(&path) {
            Ok(conf) => return Ok(conf),
            Err(_) => continue,
        }
    }

    Err(AgentError {
        message: "Could not load agent.json",
        root: RootError::None(()),
    })
}

#[derive(Debug)]
pub struct AgentError<'a> {
    message: &'a str,
    root: RootError,
}

#[derive(Debug)]
pub enum RootError {
    None(()),
    ZmqError(zmq::Error),
}

fn print_err(e: &AgentError) {
    println!("{}", e.message);
    println!("{:?}", e.root);
}

#[cfg(test)]
mod tests {
    use zmq;

    /// Test providing 1 and only 1 arg
    #[test]
    fn test_recv_args_ok_eq() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 1).unwrap();
        assert_eq!(result, vec!["1"]);
    }

    /// Test providing 1 or more args
    #[test]
    fn test_recv_args_ok_range() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 2).unwrap();
        assert_eq!(result, vec!["1"]);
    }

    /// Test providing 1+ args
    #[test]
    fn test_recv_args_ok_variable() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", zmq::SNDMORE).unwrap();
        req_sock.send_str("2", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 1, 0).unwrap();
        assert_eq!(result, vec!["1", "2"]);
    }

    /// Test failing less than 2 args
    #[test]
    fn test_recv_args_err_min() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 2, 2);
        assert!(result.is_err());
    }

    /// Test failing more than 1 arg
    #[test]
    fn test_recv_args_err_max() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        req_sock.send_str("0", zmq::SNDMORE).unwrap();
        req_sock.send_str("1", zmq::SNDMORE).unwrap();
        req_sock.send_str("2", 0).unwrap();

        // Eliminate race condition where REP socket prematurely
        // gives up receiving and tries to send err while in
        // incorrect state. This only happens in the test because we
        // call `recv_args()` out of context.
        let _ = rep_sock.recv_string(0).unwrap();

        let result = super::recv_args(&mut rep_sock, 0, 1);
        assert!(result.is_err());
    }

    /// Test sending args
    #[test]
    fn test_send_args() {
        let mut ctx = zmq::Context::new();

        let mut rep_sock = ctx.socket(zmq::REP).unwrap();
        rep_sock.bind("inproc://test_recv_args").unwrap();

        let mut req_sock = ctx.socket(zmq::REQ).unwrap();
        req_sock.connect("inproc://test_recv_args").unwrap();

        let req_vec = vec!["moo", "cow"];
        super::send_args(&mut req_sock, req_vec);

        assert_eq!(rep_sock.recv_string(0).unwrap().unwrap(), "moo");
        assert!(rep_sock.get_rcvmore().unwrap());
        assert_eq!(rep_sock.recv_string(0).unwrap().unwrap(), "cow");
    }
}<|endoftext|>


<commit_before>extern crate regex;
extern crate clap;
extern crate walkdir;
extern crate ansi_term;

use std::io::Write;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

use clap::{Arg, App, AppSettings};
use regex::Regex;
use walkdir::WalkDir;
use ansi_term::Colour::Blue;

use std::env;
use std::path::PathBuf;

fn find(rgx: Regex, dirs: Vec<PathBuf>, paint: bool) {
    let painter;
    let replacement = if paint {
        painter = Blue.paint("$search");
        format!("{}", painter)
    } else {
        "$search".to_string()
    };

    for d in dirs.iter() {
        let wkd = WalkDir::new(d);

        for f in wkd.into_iter() {
            let entry;
            match f {
                Ok(e) => entry = e,
                Err(err) => {
                    println_stderr!("{}", err);
                    continue;
                }
            }

            // paths are ascii so should always be valid unicode
            // the edge case is super rare so just ignore it
            let s = &entry.path().to_string_lossy();

            if rgx.is_match(s) {
                let display = if paint {
                    rgx.replace_all(s, replacement.as_str()).to_owned()
                } else {
                    s.to_owned()
                };

                println!("{}", display);
            }
        }
    }
}

fn main() {
    let matches = App::new("fnd, a simpler way to find files")
        .version("0.2.0")
        .author("Mathew Robinson <mrobinson@praelatus.io>")
        .about("Finds files")
        .setting(AppSettings::TrailingVarArg)
        .arg(Arg::with_name("color")
             .long("color")
             .short("c")
             .help("When specified will highlight matches with ansi \
                    term color codes. Note that for large regexes or \
                    regexes which match a large portion of text this \
                    can negatively affect performance."))
        .arg(Arg::with_name("REGEX")
             .required(true)
             .index(1)
             .help("The REGEX to search for, defaults to fuzzy finding"))
        .arg(Arg::with_name("DIRS")
            .multiple(true)
            .help("Where to search for SEARCH")
            .default_value("."))
        .get_matches();

    let search = matches.value_of("REGEX").unwrap();
    let dirs: Vec<&str> = matches.values_of("DIRS").unwrap().collect();

    let d: Vec<PathBuf> = dirs.iter()
        .map(|x| {
            if *x == "." {
                return env::current_dir().unwrap().to_path_buf();
            }

            PathBuf::from(x)
        })
        .collect();

    let re = format!("(?P<search>{})", search);
    let rgx = Regex::new(&re).unwrap();

    find(rgx, d, matches.is_present("color"));
}
<commit_msg>update help output<commit_after>extern crate regex;
extern crate clap;
extern crate walkdir;
extern crate ansi_term;

use std::io::Write;

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

use clap::{Arg, App, AppSettings};
use regex::Regex;
use walkdir::WalkDir;
use ansi_term::Colour::Blue;

use std::env;
use std::path::PathBuf;

fn find(rgx: Regex, dirs: Vec<PathBuf>, paint: bool) {
    let painter;
    let replacement = if paint {
        painter = Blue.paint("$search");
        format!("{}", painter)
    } else {
        "$search".to_string()
    };

    for d in dirs.iter() {
        let wkd = WalkDir::new(d);

        for f in wkd.into_iter() {
            let entry;
            match f {
                Ok(e) => entry = e,
                Err(err) => {
                    println_stderr!("{}", err);
                    continue;
                }
            }

            // paths are ascii so should always be valid unicode
            // the edge case is super rare so just ignore it
            let s = &entry.path().to_string_lossy();

            if rgx.is_match(s) {
                let display = if paint {
                    rgx.replace_all(s, replacement.as_str()).to_owned()
                } else {
                    s.to_owned()
                };

                println!("{}", display);
            }
        }
    }
}

fn main() {
    let matches = App::new("fnd")
        .version("0.3.0")
        .author("Mathew Robinson <mrobinson@praelatus.io>")
        .about("
Find files by regex.

Copyright (C) 2016 Mathew Robinson <mrobinson@praelatus.io>

This program is free software: you can redistribute it and/or modify
it under the terms of the Apache Version 2.0 License

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

You should have recieved a copy of the license with this software if
not you can view it here: https://www.apache.org/licenses/LICENSE-2.0")
        .setting(AppSettings::TrailingVarArg)
        .arg(Arg::with_name("color")
             .long("color")
             .short("c")
             .help("When specified will highlight matches with ansi \
                    term color codes. Note that for large regexes or \
                    regexes which match a large portion of text this \
                    can negatively affect performance."))
        .arg(Arg::with_name("REGEX")
             .required(true)
             .index(1)
             .help("The REGEX to search for, defaults to fuzzy finding"))
        .arg(Arg::with_name("DIRS")
            .multiple(true)
            .help("Where to search for SEARCH")
            .default_value("."))
        .get_matches();

    let search = matches.value_of("REGEX").unwrap();
    let dirs: Vec<&str> = matches.values_of("DIRS").unwrap().collect();

    let d: Vec<PathBuf> = dirs.iter()
        .map(|x| {
            if *x == "." {
                return env::current_dir().unwrap().to_path_buf();
            }

            PathBuf::from(x)
        })
        .collect();

    let re = format!("(?P<search>{})", search);
    let rgx = Regex::new(&re).unwrap();

    find(rgx, d, matches.is_present("color"));
}
<|endoftext|>


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

extern crate yaml;

use std::io::BufReader;
use std::fs::File;

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

#[derive(Debug)]
struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }
}

#[derive(Debug)]
struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: Result,
    kind: Kind,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id: id,
                deck: String::new(),
                opponent: String::new(),
                result: Result::Win,
                kind: Kind::Casual }
    }
}

#[derive(Debug)]
enum Result {
    Win,
    Loss,
}

#[derive(Debug)]
enum Kind {
    Ranked,
    Casual,
    Friendly,
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref content))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {

                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content).unwrap()),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
        }
    }

    Ok(seasons)
}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Match, &'static str> {
    let mut m = Match::new(id);

    for m in map.as_slice() {
        match map {
            &(YamlString(ref key), YamlString(ref value)) =>

                match key.as_str() {
                    "deck"     => m.deck = value.to_string(),
                    "opponent" => m.opponent = value.to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = Result::Win,
                            "Loss" => m.result = Result::Loss,
                            _      => Err("Unknown result"),
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = Kind::Ranked,
                            "Casual"   => m.kind = Kind::Casual,
                            "Friendly" => m.kind = Kind::Friendly,
                            _          => Err("Unknown match type"),
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    Ok(m)
}

fn parse(doc: Vec<YamlStandardData>) -> Vec<Season> {

    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => parse_seasons(map),

            _ => panic!("Error"),
        }
    }
}

fn main() {
    let path = "/Users/Gabriele/Dropbox/hearthstone.yaml";

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let mut seasons: Vec<Season> = Vec::new();

    match data.first().unwrap() {

        &YamlMapping(ref content) =>

            match content.as_slice() {
                [(YamlString(ref name), YamlMapping(ref content))] => {
                    let mut matches: Vec<Match>  = Vec::new();

                    for e in content.as_slice() {

                        match e {
                            &(YamlInteger(ref id), YamlMapping(ref content)) => {
                                let mut m = Match::new(*id);

                                for e in content.as_slice() {

                                    match e {
                                        &(YamlString(ref key), YamlString(ref value)) =>
                                            match key.as_str() {
                                                "deck"     => m.deck = value.to_string(),
                                                "opponent" => m.opponent = value.to_string(),
                                                "result"   =>
                                                    match value.as_str() {
                                                        "Win"  => m.result = Result::Win,
                                                        "Loss" => m.result = Result::Loss,
                                                        _      => continue,
                                                    },
                                                "type"     =>
                                                    match value.as_str() {
                                                        "Ranked"   => m.kind = Kind::Ranked,
                                                        "Casual"   => m.kind = Kind::Casual,
                                                        "Friendly" => m.kind = Kind::Friendly,
                                                        _          => continue,
                                                    },
                                                _ => continue,
                                            },

                                        _ => continue
                                    }
                                }

                                matches.push(m);
                            },

                            _ => continue,
                        }

                    }

                    let s_name = name.to_string();
                    let temp: Vec<&str> = s_name.split(' ').collect();
                    let season_num = temp[1].to_string().parse::<isize>().unwrap();

                    seasons.push(Season::new(season_num, matches));
                },

                _ => panic!("Error"),
            },

        _ => panic!("Error"),
    }

    println!("{:?}", seasons);

}
<commit_msg>using functions<commit_after>#![feature(slice_patterns)]
#![feature(convert)]

extern crate yaml;

use std::io::BufReader;
use std::fs::File;

use yaml::constructor::*;
use yaml::constructor::YamlStandardData::{YamlMapping, YamlString, YamlInteger};

#[derive(Debug)]
struct Season {
    num: isize,
    matches: Vec<Match>,
}

impl Season {
    fn new(num: isize, matches: Vec<Match>) -> Season {
        Season { num: num, matches: matches }
    }
}

#[derive(Debug)]
struct Match {
    id: isize,
    deck: String,
    opponent: String,
    result: MatchResult,
    kind: MatchType,
}

impl Match {
    fn new(id: isize) -> Match {
        Match { id: id,
                deck: String::new(),
                opponent: String::new(),
                result: MatchResult::Win,
                kind: MatchType::Casual }
    }
}

#[derive(Debug)]
enum MatchResult {
    Win,
    Loss,
}

#[derive(Debug)]
enum MatchType {
    Ranked,
    Casual,
    Friendly,
}

fn parse_seasons(map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Vec<Season>, &'static str> {
    let mut seasons: Vec<Season> = Vec::new();

    match map.as_slice() {
        [(YamlString(ref name), YamlMapping(ref map))] => {
            let mut matches: Vec<Match>  = Vec::new();

            for m in map.as_slice() {

                match m {
                    &(YamlInteger(ref id), YamlMapping(ref content)) =>
                        matches.push(parse_match(*id, content).unwrap()),

                    _ => continue,
                }
            }

            let s_name = name.to_string();
            let temp: Vec<&str> = s_name.split(' ').collect();
            let season_num = temp[1].to_string().parse::<isize>().unwrap();

            seasons.push(Season::new(season_num, matches));
            Ok(seasons)
        },

        _ => Err("Error"),
    }

}

fn parse_match(id: isize, map: &Vec<(YamlStandardData, YamlStandardData)>) -> Result<Match, &'static str> {
    let mut m = Match::new(id);

    for e in map.as_slice() {
        match e {
            &(YamlString(ref key), YamlString(ref value)) =>

                match key.as_str() {
                    "deck"     => m.deck = value.to_string(),
                    "opponent" => m.opponent = value.to_string(),
                    "result"   =>
                        match value.as_str() {
                            "Win"  => m.result = MatchResult::Win,
                            "Loss" => m.result = MatchResult::Loss,
                            _      => continue,
                        },
                    "type"     =>
                        match value.as_str() {
                            "Ranked"   => m.kind = MatchType::Ranked,
                            "Casual"   => m.kind = MatchType::Casual,
                            "Friendly" => m.kind = MatchType::Friendly,
                            _          => continue,
                        },
                    _ => continue,
                },

            _ => continue
        }
    }

    Ok(m)
}

fn parse(data: Vec<YamlStandardData>) -> Result<Vec<Season>, &'static str> {
    for doc in data.iter() {
        match doc {
            &YamlMapping(ref map) => return parse_seasons(map),

            _ => return Err("No docs"),
        }
    }

    Err("No docs")
}

fn main() {
    let path = "/Users/Gabriele/Dropbox/hearthstone.yaml";

    let mut reader = BufReader::new(File::open(path).unwrap());
    let data = yaml::parse_io_utf8(&mut reader).unwrap();

    let seasons = parse(data);

    println!("{:?}", seasons);

}
<|endoftext|>


<commit_before>
extern crate sdl;

use sdl::video::{SurfaceFlag, VideoFlag, Color};
use sdl::event::{Event, Key};

fn init(screen_width: isize, screen_height: isize) -> sdl::video::Surface {
    sdl::init(&[sdl::InitFlag::Video]);
    sdl::wm::set_caption("mines", "mines");

    let screen = match sdl::video::set_video_mode(screen_width, screen_height, 32,
                                                  &[SurfaceFlag::HWSurface],
                                                  &[VideoFlag::DoubleBuf]) {
        Ok(screen) => screen,
        Err(err) => panic!("failed to set video mode: {}", err)
    };
    screen
}

fn draw_square(x: i16, y: i16, w: u16, (r,g,b): (u8, u8, u8), screen: &sdl::video::Surface) {
    screen.fill_rect(Some(sdl::Rect {x: x, y: y, w: w, h: w}), Color::RGB(r, g, b));
}

fn draw_num(n: u8, x: i16, y: i16, size: u16, screen: &sdl::video::Surface) {
    let sub = (size-1) as i16/3;
    let pack = (size as i16-sub*3)as i16/2;
    let color = if n == 1 {
        (100,100,255)
    }else if n == 2 {
        (0,255,0)
    }else if n == 3 {
        (255,0,0)
    }else if n == 4 {
        (0,0,255)
    }else if n == 5 {
        (200,50,0)
    }else if n == 6 {
        (0,255,255)
    }else if n == 7 {
        (255,255,255)
    }else {
        (150,150,150)
    };

    loop {
        if n == 1{
            draw_square(sub+x+pack, sub+y+pack, sub as u16-1, color, screen);
        }else if n == 2{
            draw_square(x+pack, y+pack, sub as u16-1,  (255,0, 0), screen);
            draw_square(sub*2+x+pack, sub*2+y+pack, sub as u16-1, color, screen);
        }else if n == 3{
            draw_num(1, x, y, size, screen);
            draw_num(2, x, y, size, screen);
        }else if n == 4{
            draw_num(2, x, y, size, screen);
            draw_square(x+pack, sub*2+y+pack, sub as u16-1, color, screen);
            draw_square(sub*2+x+pack, y+pack, sub as u16-1, color, screen);
        }else if n == 5{
            draw_num(4, x, y, size, screen);
            draw_num(1, x, y, size, screen);
        }else if n == 6{
            draw_num(4, x, y, size, screen);
            draw_square(x+pack, sub+y+pack, sub as u16-1, color, screen);
            draw_square(sub*2+x+pack, sub+y+pack, sub as u16-1, color, screen);
        }else if n == 7{
            draw_num(1, x, y, size, screen);
            draw_num(6, x, y, size, screen);
        }else if n == 8{
            draw_num(6, x, y, size, screen);
            draw_square(sub+x+pack, y+pack, sub as u16-1, color, screen);
            draw_square(sub+x+pack, sub*2+y+pack, sub as u16-1, color, screen);
        }
        break;
    }
}

fn draw_field(ref field: &Vec<Vec<bool>>, length: i16, screen: &sdl::video::Surface) {
    let mut n = 0;
    for ref i in field.iter() {
        let mut m = 0;
        for ref j in i.iter() {
            draw_square(m*length+1,
                      n*length+1,
                      (length-1) as u16,
                      if **j {(0, 0, 0)} else {(255, 255, 255)},
                      screen
            );
            if !**j{
                draw_num(
                    count_field(m as usize, n as usize, field),
                    m as i16*length as i16+1,
                    n as i16*length as i16+1,
                    (length-1) as u16,
                    screen);
            }
            m += 1;
        }
        n += 1;
    }
}

fn flip_field(ref mut field: &mut Vec<Vec<bool>>, x: i16, y: i16, size: i16) {
    let i = (x/size) as usize;
    let j = (y/size) as usize;
    field[i][j] = !(field[i][j]);
}

fn count_field(x: usize, y: usize, field: &Vec<Vec<bool>>) -> u8 {
    let w = field[0].len();
    let h = field.len();
    let mut n = 0;
    for i in 0..3 {
        if y+i == 0 || y+i == h+1 {continue;}
        for j in 0..3 {
            if i == 1 && j == 1 {continue;}
            if x+j == 0 || x+j == w+1 {continue;}
            if field[y+i-1][x+j-1] {n += 1}
        }
    }
    n
}

fn main() {
    const WIDTH: usize = 40;
    const HEIGHT: usize = 30;
    const SIZE: usize = 25;

    let field = &mut vec![vec![false; WIDTH]; HEIGHT];

    let screen = init((SIZE*WIDTH) as isize + 1, (SIZE*HEIGHT) as isize + 1);
    loop {
        match sdl::event::poll_event() {
            Event::Quit => break,
            Event::MouseButton(_, down, mx, my) => {
                if down {
                    flip_field(field, my as i16, mx as i16, SIZE as i16);
                    println!("{}", count_field((mx/SIZE as u16) as usize, (my/SIZE as u16) as usize, field));
                }
            },
            Event::Key(k, _, _, _)
                if k == Key::Escape
                    => break,
            _ => {}
        }
        draw_field(&field, SIZE as i16, &screen);
        screen.flip();
    }

    sdl::quit();
}
<commit_msg>number are single color<commit_after>
extern crate sdl;

use sdl::video::{SurfaceFlag, VideoFlag, Color};
use sdl::event::{Event, Key};

fn init(screen_width: isize, screen_height: isize) -> sdl::video::Surface {
    sdl::init(&[sdl::InitFlag::Video]);
    sdl::wm::set_caption("mines", "mines");

    let screen = match sdl::video::set_video_mode(screen_width, screen_height, 32,
                                                  &[SurfaceFlag::HWSurface],
                                                  &[VideoFlag::DoubleBuf]) {
        Ok(screen) => screen,
        Err(err) => panic!("failed to set video mode: {}", err)
    };
    screen
}

fn draw_square(x: i16, y: i16, w: u16, (r,g,b): (u8, u8, u8), screen: &sdl::video::Surface) {
    screen.fill_rect(Some(sdl::Rect {x: x, y: y, w: w, h: w}), Color::RGB(r, g, b));
}

fn draw_num(n: u8, x: i16, y: i16, size: u16, screen: &sdl::video::Surface) {
    let mut n = n;
    let sub = (size-1) as i16/3;
    let pack = (size as i16-sub*3)as i16/2;
    let color = if n == 1 {
        (100,100,255)
    }else if n == 2 {
        (0,255,0)
    }else if n == 3 {
        (255,0,0)
    }else if n == 4 {
        (0,0,255)
    }else if n == 5 {
        (200,50,0)
    }else if n == 6 {
        (0,255,255)
    }else if n == 7 {
        (0,0,0)
    }else {
        (150,150,150)
    };

    loop {
        if n == 0 {break;}
        else if n == 1{
            draw_square(sub+x+pack, sub+y+pack, sub as u16-1, color, screen);
            break;
        }else if n == 2{
            draw_square(x+pack, y+pack, sub as u16-1,  color, screen);
            draw_square(sub*2+x+pack, sub*2+y+pack, sub as u16-1, color, screen);
            break;
        }else if n == 3{
            draw_square(sub+x+pack, sub+y+pack, sub as u16-1, color, screen);
            n = 2;
        }else if n == 4{
            draw_square(x+pack, sub*2+y+pack, sub as u16-1, color, screen);
            draw_square(sub*2+x+pack, y+pack, sub as u16-1, color, screen);
            n = 2;
        }else if n == 5{
            draw_square(sub+x+pack, sub+y+pack, sub as u16-1, color, screen);
            n = 4;
        }else if n == 6{
            draw_square(x+pack, sub+y+pack, sub as u16-1, color, screen);
            draw_square(sub*2+x+pack, sub+y+pack, sub as u16-1, color, screen);
            n = 4;
        }else if n == 7{
            draw_square(sub+x+pack, sub+y+pack, sub as u16-1, color, screen);
            n = 6;
        }else if n == 8{
            draw_square(sub+x+pack, y+pack, sub as u16-1, color, screen);
            draw_square(sub+x+pack, sub*2+y+pack, sub as u16-1, color, screen);
            n = 6;
        }
    }
}

fn draw_field(ref field: &Vec<Vec<bool>>, length: i16, screen: &sdl::video::Surface) {
    let mut n = 0;
    for ref i in field.iter() {
        let mut m = 0;
        for ref j in i.iter() {
            draw_square(m*length+1,
                      n*length+1,
                      (length-1) as u16,
                      if **j {(0, 0, 0)} else {(255, 255, 255)},
                      screen
            );
            if !**j{
                draw_num(
                    count_field(m as usize, n as usize, field),
                    m as i16*length as i16+1,
                    n as i16*length as i16+1,
                    (length-1) as u16,
                    screen);
            }
            m += 1;
        }
        n += 1;
    }
}

fn flip_field(ref mut field: &mut Vec<Vec<bool>>, x: i16, y: i16, size: i16) {
    let i = (x/size) as usize;
    let j = (y/size) as usize;
    field[i][j] = !(field[i][j]);
}

fn count_field(x: usize, y: usize, field: &Vec<Vec<bool>>) -> u8 {
    let w = field[0].len();
    let h = field.len();
    let mut n = 0;
    for i in 0..3 {
        if y+i == 0 || y+i == h+1 {continue;}
        for j in 0..3 {
            if i == 1 && j == 1 {continue;}
            if x+j == 0 || x+j == w+1 {continue;}
            if field[y+i-1][x+j-1] {n += 1}
        }
    }
    n
}

fn main() {
    const WIDTH: usize = 30;
    const HEIGHT: usize = 20;
    const SIZE: usize = 35;

    let field = &mut vec![vec![false; WIDTH]; HEIGHT];

    let screen = init((SIZE*WIDTH) as isize + 1, (SIZE*HEIGHT) as isize + 1);
    loop {
        match sdl::event::poll_event() {
            Event::Quit => break,
            Event::MouseButton(_, down, mx, my) => {
                if down {
                    flip_field(field, my as i16, mx as i16, SIZE as i16);
                    println!("{}", count_field((mx/SIZE as u16) as usize, (my/SIZE as u16) as usize, field));
                }
            },
            Event::Key(k, _, _, _)
                if k == Key::Escape
                    => break,
            _ => {}
        }
        draw_field(&field, SIZE as i16, &screen);
        screen.flip();
    }

    sdl::quit();
}
<|endoftext|>