<commit_before>extern crate ncurses;

use backend;
use event::{Event, Key};

use theme::{BaseColor, Color, ColorStyle, Effect};
use utf8;

pub struct Concrete;

impl backend::Backend for Concrete {
    fn init() -> Self {
        ::std::env::set_var("ESCDELAY", "25");
        ncurses::setlocale(ncurses::LcCategory::all, "");
        ncurses::initscr();
        ncurses::keypad(unsafe { ncurses::stdscr() }, true);
        ncurses::noecho();
        ncurses::cbreak();
        ncurses::start_color();
        ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
        ncurses::wbkgd(unsafe { ncurses::stdscr() },
                       ncurses::COLOR_PAIR(ColorStyle::Background.id()));

        Concrete
    }

    fn screen_size(&self) -> (usize, usize) {
        let mut x: i32 = 0;
        let mut y: i32 = 0;
        ncurses::getmaxyx(unsafe { ncurses::stdscr() }, &mut y, &mut x);
        (x as usize, y as usize)
    }

    fn has_colors(&self) -> bool {
        ncurses::has_colors()
    }

    fn finish(&mut self) {
        ncurses::endwin();
    }

    fn init_color_style(&mut self, style: ColorStyle, foreground: &Color,
                        background: &Color) {
        // TODO: build the color on the spot

        ncurses::init_pair(style.id(),
                           find_closest(foreground) as i16,
                           find_closest(background) as i16);
    }

    fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) {
        let mut current_style: ncurses::attr_t = 0;
        let mut current_color: i16 = 0;
        ncurses::attr_get(&mut current_style, &mut current_color);

        let style = ncurses::COLOR_PAIR(color.id());
        ncurses::attron(style);
        f();
        // ncurses::attroff(style);
        ncurses::attron(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
        let style = match effect {
            Effect::Reverse => ncurses::A_REVERSE(),
            Effect::Simple => ncurses::A_NORMAL(),
        };
        ncurses::attron(style);
        f();
        ncurses::attroff(style);
    }

    fn clear(&self) {
        ncurses::clear();
    }

    fn refresh(&mut self) {
        ncurses::refresh();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        ncurses::mvaddstr(y as i32, x as i32, text);
    }

    fn poll_event(&self) -> Event {
        let ch: i32 = ncurses::getch();

        // Is it a UTF-8 starting point?
        if 32 <= ch && ch <= 255 && ch != 127 {
            Event::Char(utf8::read_char(ch as u8, || ncurses::getch() as u8)
                .unwrap())
        } else {
            parse_ncurses_char(ch)
        }
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        if fps == 0 {
            ncurses::timeout(-1);
        } else {
            ncurses::timeout(1000 / fps as i32);
        }
    }
}

/// Returns the Key enum corresponding to the given ncurses event.
fn parse_ncurses_char(ch: i32) -> Event {
    match ch {
        // Value sent by ncurses when nothing happens
        -1 => Event::Refresh,

        // Values under 256 are chars and control values
        //
        // Tab is '\t'
        9 => Event::Key(Key::Tab),
        // Treat '\n' and the numpad Enter the same
        10 |
        ncurses::KEY_ENTER => Event::Key(Key::Enter),
        // This is the escape key when pressed by itself.
        // When used for control sequences, it should have been caught earlier.
        27 => Event::Key(Key::Esc),
        // `Backspace` sends 127, but Ctrl-H sends `Backspace`
        127 |
        ncurses::KEY_BACKSPACE => Event::Key(Key::Backspace),

        410 => Event::WindowResize,

        // Values 512 and above are probably extensions
        // Those keys don't seem to be documented...
        519 => Event::Alt(Key::Del),
        520 => Event::AltShift(Key::Del),
        521 => Event::Ctrl(Key::Del),
        522 => Event::CtrlShift(Key::Del),
        // 523: CtrlAltDel?
        //
        // 524?
        525 => Event::Alt(Key::Down),
        526 => Event::AltShift(Key::Down),
        527 => Event::Ctrl(Key::Down),
        528 => Event::CtrlShift(Key::Down),
        529 => Event::CtrlAlt(Key::Down),

        530 => Event::Alt(Key::End),
        531 => Event::AltShift(Key::End),
        532 => Event::Ctrl(Key::End),
        533 => Event::CtrlShift(Key::End),
        534 => Event::CtrlAlt(Key::End),

        535 => Event::Alt(Key::Home),
        536 => Event::AltShift(Key::Home),
        537 => Event::Ctrl(Key::Home),
        538 => Event::CtrlShift(Key::Home),
        539 => Event::CtrlAlt(Key::Home),

        540 => Event::Alt(Key::Ins),
        // 541: AltShiftIns?
        542 => Event::Ctrl(Key::Ins),
        // 543: CtrlShiftIns?
        544 => Event::CtrlAlt(Key::Ins),

        545 => Event::Alt(Key::Left),
        546 => Event::AltShift(Key::Left),
        547 => Event::Ctrl(Key::Left),
        548 => Event::CtrlShift(Key::Left),
        549 => Event::CtrlAlt(Key::Left),

        550 => Event::Alt(Key::PageDown),
        551 => Event::AltShift(Key::PageDown),
        552 => Event::Ctrl(Key::PageDown),
        553 => Event::CtrlShift(Key::PageDown),
        554 => Event::CtrlAlt(Key::PageDown),

        555 => Event::Alt(Key::PageUp),
        556 => Event::AltShift(Key::PageUp),
        557 => Event::Ctrl(Key::PageUp),
        558 => Event::CtrlShift(Key::PageUp),
        559 => Event::CtrlAlt(Key::PageUp),

        560 => Event::Alt(Key::Right),
        561 => Event::AltShift(Key::Right),
        562 => Event::Ctrl(Key::Right),
        563 => Event::CtrlShift(Key::Right),
        564 => Event::CtrlAlt(Key::Right),
        // 565?
        566 => Event::Alt(Key::Up),
        567 => Event::AltShift(Key::Up),
        568 => Event::Ctrl(Key::Up),
        569 => Event::CtrlShift(Key::Up),
        570 => Event::CtrlAlt(Key::Up),

        ncurses::KEY_B2 => Event::Key(Key::NumpadCenter),
        ncurses::KEY_DC => Event::Key(Key::Del),
        ncurses::KEY_IC => Event::Key(Key::Ins),
        ncurses::KEY_BTAB => Event::Shift(Key::Tab),
        ncurses::KEY_SLEFT => Event::Shift(Key::Left),
        ncurses::KEY_SRIGHT => Event::Shift(Key::Right),
        ncurses::KEY_LEFT => Event::Key(Key::Left),
        ncurses::KEY_RIGHT => Event::Key(Key::Right),
        ncurses::KEY_UP => Event::Key(Key::Up),
        ncurses::KEY_DOWN => Event::Key(Key::Down),
        ncurses::KEY_SR => Event::Shift(Key::Up),
        ncurses::KEY_SF => Event::Shift(Key::Down),
        ncurses::KEY_PPAGE => Event::Key(Key::PageUp),
        ncurses::KEY_NPAGE => Event::Key(Key::PageDown),
        ncurses::KEY_HOME => Event::Key(Key::Home),
        ncurses::KEY_END => Event::Key(Key::End),
        ncurses::KEY_SHOME => Event::Shift(Key::Home),
        ncurses::KEY_SEND => Event::Shift(Key::End),
        ncurses::KEY_SDC => Event::Shift(Key::Del),
        ncurses::KEY_SNEXT => Event::Shift(Key::PageDown),
        ncurses::KEY_SPREVIOUS => Event::Shift(Key::PageUp),
        // All Fn keys use the same enum with associated number
        f @ ncurses::KEY_F1...ncurses::KEY_F12 => {
            Event::Key(Key::from_f((f - ncurses::KEY_F0) as u8))
        }
        f @ 277...288 => Event::Shift(Key::from_f((f - 276) as u8)),
        f @ 289...300 => Event::Ctrl(Key::from_f((f - 288) as u8)),
        f @ 301...312 => Event::CtrlShift(Key::from_f((f - 300) as u8)),
        f @ 313...324 => Event::Alt(Key::from_f((f - 312) as u8)),
        // Values 8-10 (H,I,J) are used by other commands,
        // so we probably won't receive them. Meh~
        c @ 1...25 => Event::CtrlChar((b'a' + (c - 1) as u8) as char),
        _ => Event::Unknown(ch),
    }
}

fn find_closest(color: &Color) -> u8 {
    match *color {
        Color::Dark(BaseColor::Black) => 0,
        Color::Dark(BaseColor::Red) => 1,
        Color::Dark(BaseColor::Green) => 2,
        Color::Dark(BaseColor::Yellow) => 3,
        Color::Dark(BaseColor::Blue) => 4,
        Color::Dark(BaseColor::Magenta) => 5,
        Color::Dark(BaseColor::Cyan) => 6,
        Color::Dark(BaseColor::White) => 7,
        Color::Light(BaseColor::Black) => 8,
        Color::Light(BaseColor::Red) => 9,
        Color::Light(BaseColor::Green) => 10,
        Color::Light(BaseColor::Yellow) => 11,
        Color::Light(BaseColor::Blue) => 12,
        Color::Light(BaseColor::Magenta) => 13,
        Color::Light(BaseColor::Cyan) => 14,
        Color::Light(BaseColor::White) => 15,
        Color::Rgb(r, g, b) => {
            let r = 6 * r as u16 / 256;
            let g = 6 * g as u16 / 256;
            let b = 6 * b as u16 / 256;
            (16 + 36 * r + 6 * g + b) as u8
        }
        Color::RgbLowRes(r, g, b) => (16 + 36 * r + 6 * g + b) as u8,
    }
}
<commit_msg>Fix clippy warnings<commit_after>extern crate ncurses;

use backend;
use event::{Event, Key};

use self::super::find_closest;
use theme::{Color, ColorStyle, Effect};
use utf8;

pub struct Concrete;

impl backend::Backend for Concrete {
    fn init() -> Self {
        ::std::env::set_var("ESCDELAY", "25");
        ncurses::setlocale(ncurses::LcCategory::all, "");
        ncurses::initscr();
        ncurses::keypad(ncurses::stdscr(), true);
        ncurses::noecho();
        ncurses::cbreak();
        ncurses::start_color();
        ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
        ncurses::wbkgd(ncurses::stdscr(),
                       ncurses::COLOR_PAIR(ColorStyle::Background.id()));

        Concrete
    }

    fn screen_size(&self) -> (usize, usize) {
        let mut x: i32 = 0;
        let mut y: i32 = 0;
        ncurses::getmaxyx(ncurses::stdscr(), &mut y, &mut x);
        (x as usize, y as usize)
    }

    fn has_colors(&self) -> bool {
        ncurses::has_colors()
    }

    fn finish(&mut self) {
        ncurses::endwin();
    }

    fn init_color_style(&mut self, style: ColorStyle, foreground: &Color,
                        background: &Color) {
        // TODO: build the color on the spot

        ncurses::init_pair(style.id(),
                           find_closest(foreground) as i16,
                           find_closest(background) as i16);
    }

    fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) {
        let mut current_style: ncurses::attr_t = 0;
        let mut current_color: i16 = 0;
        ncurses::attr_get(&mut current_style, &mut current_color);

        let style = ncurses::COLOR_PAIR(color.id());
        ncurses::attron(style);
        f();
        // ncurses::attroff(style);
        ncurses::attron(current_style);
    }

    fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
        let style = match effect {
            Effect::Reverse => ncurses::A_REVERSE(),
            Effect::Simple => ncurses::A_NORMAL(),
        };
        ncurses::attron(style);
        f();
        ncurses::attroff(style);
    }

    fn clear(&self) {
        ncurses::clear();
    }

    fn refresh(&mut self) {
        ncurses::refresh();
    }

    fn print_at(&self, (x, y): (usize, usize), text: &str) {
        ncurses::mvaddstr(y as i32, x as i32, text);
    }

    fn poll_event(&self) -> Event {
        let ch: i32 = ncurses::getch();

        // Is it a UTF-8 starting point?
        if 32 <= ch && ch <= 255 && ch != 127 {
            Event::Char(utf8::read_char(ch as u8, || ncurses::getch() as u8)
                .unwrap())
        } else {
            parse_ncurses_char(ch)
        }
    }

    fn set_refresh_rate(&mut self, fps: u32) {
        if fps == 0 {
            ncurses::timeout(-1);
        } else {
            ncurses::timeout(1000 / fps as i32);
        }
    }
}

/// Returns the Key enum corresponding to the given ncurses event.
fn parse_ncurses_char(ch: i32) -> Event {
    match ch {
        // Value sent by ncurses when nothing happens
        -1 => Event::Refresh,

        // Values under 256 are chars and control values
        //
        // Tab is '\t'
        9 => Event::Key(Key::Tab),
        // Treat '\n' and the numpad Enter the same
        10 |
        ncurses::KEY_ENTER => Event::Key(Key::Enter),
        // This is the escape key when pressed by itself.
        // When used for control sequences, it should have been caught earlier.
        27 => Event::Key(Key::Esc),
        // `Backspace` sends 127, but Ctrl-H sends `Backspace`
        127 |
        ncurses::KEY_BACKSPACE => Event::Key(Key::Backspace),

        410 => Event::WindowResize,

        // Values 512 and above are probably extensions
        // Those keys don't seem to be documented...
        519 => Event::Alt(Key::Del),
        520 => Event::AltShift(Key::Del),
        521 => Event::Ctrl(Key::Del),
        522 => Event::CtrlShift(Key::Del),
        // 523: CtrlAltDel?
        //
        // 524?
        525 => Event::Alt(Key::Down),
        526 => Event::AltShift(Key::Down),
        527 => Event::Ctrl(Key::Down),
        528 => Event::CtrlShift(Key::Down),
        529 => Event::CtrlAlt(Key::Down),

        530 => Event::Alt(Key::End),
        531 => Event::AltShift(Key::End),
        532 => Event::Ctrl(Key::End),
        533 => Event::CtrlShift(Key::End),
        534 => Event::CtrlAlt(Key::End),

        535 => Event::Alt(Key::Home),
        536 => Event::AltShift(Key::Home),
        537 => Event::Ctrl(Key::Home),
        538 => Event::CtrlShift(Key::Home),
        539 => Event::CtrlAlt(Key::Home),

        540 => Event::Alt(Key::Ins),
        // 541: AltShiftIns?
        542 => Event::Ctrl(Key::Ins),
        // 543: CtrlShiftIns?
        544 => Event::CtrlAlt(Key::Ins),

        545 => Event::Alt(Key::Left),
        546 => Event::AltShift(Key::Left),
        547 => Event::Ctrl(Key::Left),
        548 => Event::CtrlShift(Key::Left),
        549 => Event::CtrlAlt(Key::Left),

        550 => Event::Alt(Key::PageDown),
        551 => Event::AltShift(Key::PageDown),
        552 => Event::Ctrl(Key::PageDown),
        553 => Event::CtrlShift(Key::PageDown),
        554 => Event::CtrlAlt(Key::PageDown),

        555 => Event::Alt(Key::PageUp),
        556 => Event::AltShift(Key::PageUp),
        557 => Event::Ctrl(Key::PageUp),
        558 => Event::CtrlShift(Key::PageUp),
        559 => Event::CtrlAlt(Key::PageUp),

        560 => Event::Alt(Key::Right),
        561 => Event::AltShift(Key::Right),
        562 => Event::Ctrl(Key::Right),
        563 => Event::CtrlShift(Key::Right),
        564 => Event::CtrlAlt(Key::Right),
        // 565?
        566 => Event::Alt(Key::Up),
        567 => Event::AltShift(Key::Up),
        568 => Event::Ctrl(Key::Up),
        569 => Event::CtrlShift(Key::Up),
        570 => Event::CtrlAlt(Key::Up),

        ncurses::KEY_B2 => Event::Key(Key::NumpadCenter),
        ncurses::KEY_DC => Event::Key(Key::Del),
        ncurses::KEY_IC => Event::Key(Key::Ins),
        ncurses::KEY_BTAB => Event::Shift(Key::Tab),
        ncurses::KEY_SLEFT => Event::Shift(Key::Left),
        ncurses::KEY_SRIGHT => Event::Shift(Key::Right),
        ncurses::KEY_LEFT => Event::Key(Key::Left),
        ncurses::KEY_RIGHT => Event::Key(Key::Right),
        ncurses::KEY_UP => Event::Key(Key::Up),
        ncurses::KEY_DOWN => Event::Key(Key::Down),
        ncurses::KEY_SR => Event::Shift(Key::Up),
        ncurses::KEY_SF => Event::Shift(Key::Down),
        ncurses::KEY_PPAGE => Event::Key(Key::PageUp),
        ncurses::KEY_NPAGE => Event::Key(Key::PageDown),
        ncurses::KEY_HOME => Event::Key(Key::Home),
        ncurses::KEY_END => Event::Key(Key::End),
        ncurses::KEY_SHOME => Event::Shift(Key::Home),
        ncurses::KEY_SEND => Event::Shift(Key::End),
        ncurses::KEY_SDC => Event::Shift(Key::Del),
        ncurses::KEY_SNEXT => Event::Shift(Key::PageDown),
        ncurses::KEY_SPREVIOUS => Event::Shift(Key::PageUp),
        // All Fn keys use the same enum with associated number
        f @ ncurses::KEY_F1...ncurses::KEY_F12 => {
            Event::Key(Key::from_f((f - ncurses::KEY_F0) as u8))
        }
        f @ 277...288 => Event::Shift(Key::from_f((f - 276) as u8)),
        f @ 289...300 => Event::Ctrl(Key::from_f((f - 288) as u8)),
        f @ 301...312 => Event::CtrlShift(Key::from_f((f - 300) as u8)),
        f @ 313...324 => Event::Alt(Key::from_f((f - 312) as u8)),
        // Values 8-10 (H,I,J) are used by other commands,
        // so we probably won't receive them. Meh~
        c @ 1...25 => Event::CtrlChar((b'a' + (c - 1) as u8) as char),
        _ => Event::Unknown(ch),
    }
}
<|endoftext|>


<commit_before>use clap;
use cobalt;

use args;
use error::*;

pub fn debug_command_args() -> clap::App<'static, 'static> {
    clap::SubCommand::with_name("debug")
        .about("Print site debug information")
        .subcommand(clap::SubCommand::with_name("config").about("Prints post-processed config"))
        .subcommand(clap::SubCommand::with_name("highlight")
                        .about("Print syntax-highlight information")
                        .subcommand(clap::SubCommand::with_name("themes"))
                        .subcommand(clap::SubCommand::with_name("syntaxes")))
        .subcommand(clap::SubCommand::with_name("files")
                        .about("Print files associated with a collection")
                        .args(&args::get_config_args())
                        .arg(clap::Arg::with_name("COLLECTION")
                                 .help("Collection name")
                                 .index(1)))
}

pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
    match matches.subcommand() {
        ("config", _) => {
            let config = args::get_config(matches)?;
            let config = config.build()?;
            println!("{}", config);
        }
        ("highlight", Some(matches)) => {
            match matches.subcommand() {
                ("themes", _) => {
                    for name in cobalt::list_syntax_themes() {
                        println!("{}", name);
                    }
                }
                ("syntaxes", _) => {
                    for name in cobalt::list_syntaxes() {
                        println!("{}", name);
                    }
                }
                _ => bail!(matches.usage()),
            }
        }
        ("files", Some(matches)) => {
            let config = args::get_config(matches)?;
            let config = config.build()?;
            let collection = matches.value_of("COLLECTION");
            match collection {
                Some("assets") => {
                    let assets = config.assets.build()?;
                    for file_path in assets.files() {
                        println!("{:?}", file_path);
                    }
                }
                None => {
                    bail!("Must specify collection");
                }
                _ => {
                    bail!("Collection is not yet supported");
                }
            }
        }
        _ => bail!(matches.usage()),
    }

    Ok(())
}
<commit_msg>feat(debug): Print pages and posts files<commit_after>use clap;
use cobalt;

use args;
use error::*;

pub fn debug_command_args() -> clap::App<'static, 'static> {
    clap::SubCommand::with_name("debug")
        .about("Print site debug information")
        .subcommand(clap::SubCommand::with_name("config").about("Prints post-processed config"))
        .subcommand(clap::SubCommand::with_name("highlight")
                        .about("Print syntax-highlight information")
                        .subcommand(clap::SubCommand::with_name("themes"))
                        .subcommand(clap::SubCommand::with_name("syntaxes")))
        .subcommand(clap::SubCommand::with_name("files")
                        .about("Print files associated with a collection")
                        .args(&args::get_config_args())
                        .arg(clap::Arg::with_name("COLLECTION")
                                 .help("Collection name")
                                 .index(1)))
}

pub fn debug_command(matches: &clap::ArgMatches) -> Result<()> {
    match matches.subcommand() {
        ("config", _) => {
            let config = args::get_config(matches)?;
            let config = config.build()?;
            println!("{}", config);
        }
        ("highlight", Some(matches)) => {
            match matches.subcommand() {
                ("themes", _) => {
                    for name in cobalt::list_syntax_themes() {
                        println!("{}", name);
                    }
                }
                ("syntaxes", _) => {
                    for name in cobalt::list_syntaxes() {
                        println!("{}", name);
                    }
                }
                _ => bail!(matches.usage()),
            }
        }
        ("files", Some(matches)) => {
            let config = args::get_config(matches)?;
            let config = config.build()?;
            let collection = matches.value_of("COLLECTION");
            match collection {
                Some("assets") => {
                    let assets = config.assets.build()?;
                    for file_path in assets.files() {
                        println!("{:?}", file_path);
                    }
                }
                Some("pages") => {
                    let pages = config.pages.build()?;
                    for file_path in pages.pages.files() {
                        println!("{:?}", file_path);
                    }
                    if let Some(ref drafts) = pages.drafts {
                        for file_path in drafts.files() {
                            println!("{:?}", file_path);
                        }
                    }
                }
                Some("posts") => {
                    let posts = config.posts.build()?;
                    for file_path in posts.pages.files() {
                        println!("{:?}", file_path);
                    }
                    if let Some(ref drafts) = posts.drafts {
                        for file_path in drafts.files() {
                            println!("{:?}", file_path);
                        }
                    }
                }
                None => {
                    bail!("Must specify collection");
                }
                _ => {
                    bail!("Collection is not yet supported");
                }
            }
        }
        _ => bail!(matches.usage()),
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = &self.path;
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(path) {
                let target = path.join(&cmd);
                let mut cmd_exe = cmd.clone();
                cmd_exe.push(".exe");

                if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists() // some/path/git/git.exe
                {
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .filter_map(|host| build.config.target_config.get(host))
        .any(|config| config.llvm_config.is_none());
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_default();

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                    .or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<commit_msg>Rollup merge of #61890 - golddranks:fix_sanity_check_llvm, r=Dylan-DPC<commit_after>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = &self.path;
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(path) {
                let target = path.join(&cmd);
                let mut cmd_exe = cmd.clone();
                cmd_exe.push(".exe");

                if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists() // some/path/git/git.exe
                {
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .map(|host| build.config.target_config
            .get(host)
            .map(|config| config.llvm_config.is_none())
            .unwrap_or(true))
        .any(|build_llvm_ourselves| build_llvm_ourselves);
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }

        if build.config.lldb_enabled {
            cmd_finder.must_have("swig");
            let out = output(Command::new("swig").arg("-version"));
            if !out.contains("SWIG Version 3") && !out.contains("SWIG Version 4") {
                panic!("Ensure that Swig 3.x.x or 4.x.x is installed.");
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_default();

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                    .or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::vec::Vec;

use futures::Future;
use futures_cpupool::CpuPool;
#[cfg(not(target_os="linux"))]
use nix::c_int;
#[cfg(not(target_os="linux"))]
use nix::sys::signal::{SaFlags, SigAction, SigHandler, sigaction};
use nix::sys::signal::{SigSet, Signal};
use nix::sys::wait::{WaitStatus, waitpid};
use nix::unistd::{ForkResult, fork};
use time::PreciseTime;
use tokio_timer::Timer;

use errors::*;

pub trait Supervisable {
    fn init(&self) -> Result<()>;
    fn finalize(&self) -> Result<()>;
}

pub enum Strategy {
    OneForOne,
    OneForAll,
    RestForOne,
    SimpleOneForOne,
}

#[derive(Clone)]
pub enum ChildLifetime {
    Permanent,
    Temporary,
    Transient,
}

#[derive(Clone)]
pub enum ProcessType {
    Worker,
    Supervisor,
}

#[derive(Clone)]
pub enum ShutdownType {
    BrutalKill,
    Infinity,
    Timeout(u64),
}

pub struct SupervisorFlags {
    strategy: Strategy,
    intensity: u64,
    period: u64,
}

impl SupervisorFlags {
    pub fn new(strategy: Strategy, intensity: u64, period: u64) -> Option<SupervisorFlags> {
        if period > 0 {
            Some(SupervisorFlags {
                strategy: strategy,
                intensity: intensity,
                period: period,
            })
        } else {
            None
        }
    }
}

#[derive(Clone)]
pub struct ChildSpecs {
    id: String,
    child: Rc<Supervisable>,
    restart: ChildLifetime,
    shutdown: ShutdownType,
    process_type: ProcessType,
}

impl ChildSpecs {
    pub fn new(id: &str,
               child: Rc<Supervisable>,
               restart: ChildLifetime,
               shutdown: ShutdownType,
               process_type: ProcessType)
               -> ChildSpecs {
        ChildSpecs {
            id: id.to_owned(),
            child: child,
            restart: restart,
            shutdown: shutdown,
            process_type: process_type,
        }
    }
}

#[derive(Clone)]
struct ChildRecord {
    spec_index: usize,
    time_started: PreciseTime,
}

pub struct Supervisor {
    flags: SupervisorFlags,
    child_specs: Vec<ChildSpecs>,
    child_records: HashMap<i32, ChildRecord>,
}

impl Supervisor {
    pub fn new(flags: SupervisorFlags, specs: &[ChildSpecs]) -> Supervisor {
        Supervisor {
            flags: flags,
            child_specs: specs.to_vec(),
            child_records: HashMap::new(),
        }
    }

    /// Runs the supervisor for the given child tasks
    pub fn run(&mut self) -> Result<()> {
        info!("Supervisor start.");
        self.init().chain_err(|| ErrorKind::SupervisorInitError)?;
        for idx in 0..self.child_specs.len() {
            info!("Supervisor spawning child: {}.", self.child_specs[idx].id);
            match fork().chain_err(|| "Could not fork process.")? {
                ForkResult::Child => {
                    self.child_specs[idx].child.init()?;
                    return Ok(());
                }
                ForkResult::Parent { child } => {
                    self.child_records
                        .insert(child,
                                ChildRecord {
                                    spec_index: idx,
                                    time_started: PreciseTime::now(),
                                });
                }
            }
        }
        self.supervise()?;
        Ok(())
    }

    fn supervise(&mut self) -> Result<()> {
        thread::spawn(|| {
            let mut sigs = SigSet::empty();
            sigs.add(Signal::SIGCHLD);
            sigs.add(Signal::SIGINT);
            if let Ok(sig) = sigs.wait() {
                match sig {
                    Signal::SIGINT => {
                        warn!("SIGINT!!!!!");
                        // Here, send child processes an exit message
                    }
                    _ => {}
                }
            }
        });

        let pool = CpuPool::new_num_cpus();
        let timer = Timer::default();
        let num_kids = self.child_records.len();
        info!("Supervisor waiting for child processes. {} remaining.",
              num_kids);
        let (tx, rx) = mpsc::channel();
        let records = self.child_records.clone();
        let names = self.child_specs.iter().map(|s| s.id.clone()).collect::<Vec<String>>();
        thread::spawn(move || for idx in 0..num_kids {
            let pid = get_pid_for_idx(&records, idx);
            let birth = records[&pid].time_started;
            let child_name = names[records[&pid].spec_index].clone();
            let txc = tx.clone();
            let wait_future = pool.spawn_fn(move || {
                info!("Waiting for {}", pid);
                match waitpid(pid, None) {
                    Ok(WaitStatus::Exited(_, ret)) => {
                        let life = birth.to(PreciseTime::now())
                            .num_seconds();
                        info!("Status: {} exited after {}s with exit code {}.",
                              child_name,
                              life,
                              ret);
                    }
                    _ => {
                        warn!("Unknown action");
                    }
                };
                let res: Result<i32> = Ok(pid);
                res
            });
            let timeout = pool.spawn(timer.sleep(Duration::from_secs(5))
                .then(|_| {
                    info!("Timeout reached!");
                    Ok(-1)
                }));
            let _ = txc.send(timeout.select(wait_future).map(|(res, _)| res));
        });
        for v in rx {
            if let Ok(pid) = v.wait() {
                info!("{} Exited", pid);
                self.child_records.remove(&pid);
            }
        }
        Ok(())
    }

    fn init(&self) -> Result<()> {
        #[cfg(not(target_os="linux"))]
        {
            let mask = SigSet::empty();
            let flags = SaFlags::empty();
            let handler = SigHandler::Handler(null_handler);
            let action = SigAction::new(handler, flags, mask);
            unsafe {
                sigaction(Signal::SIGCHLD, &action)?;
            }
        }

        SigSet::all().thread_set_mask()?;
        Ok(())
    }
}

fn get_pid_for_idx(records: &HashMap<i32, ChildRecord>, idx: usize) -> i32 {
    let pids = records.iter()
        .filter(|&(_, v)| v.spec_index == idx)
        .map(|(k, _)| *k)
        .collect::<Vec<i32>>();
    pids[0]
}

#[cfg(not(target_os="linux"))]
extern "C" fn null_handler(_: c_int) -> () {}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Use future::join_all to ensure that all child processes have finished<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::vec::Vec;

use futures::{Future,future};
use futures_cpupool::CpuPool;
#[cfg(not(target_os="linux"))]
use nix::c_int;
#[cfg(not(target_os="linux"))]
use nix::sys::signal::{SaFlags, SigAction, SigHandler, sigaction};
use nix::sys::signal::{SigSet, Signal};
use nix::sys::wait::{WaitStatus, waitpid};
use nix::unistd::{ForkResult, fork};
use time::PreciseTime;
use tokio_timer::Timer;

use errors::*;

pub trait Supervisable {
    fn init(&self) -> Result<()>;
    fn finalize(&self) -> Result<()>;
}

pub enum Strategy {
    OneForOne,
    OneForAll,
    RestForOne,
    SimpleOneForOne,
}

#[derive(Clone)]
pub enum ChildLifetime {
    Permanent,
    Temporary,
    Transient,
}

#[derive(Clone)]
pub enum ProcessType {
    Worker,
    Supervisor,
}

#[derive(Clone)]
pub enum ShutdownType {
    BrutalKill,
    Infinity,
    Timeout(u64),
}

pub struct SupervisorFlags {
    strategy: Strategy,
    intensity: u64,
    period: u64,
}

impl SupervisorFlags {
    pub fn new(strategy: Strategy, intensity: u64, period: u64) -> Option<SupervisorFlags> {
        if period > 0 {
            Some(SupervisorFlags {
                strategy: strategy,
                intensity: intensity,
                period: period,
            })
        } else {
            None
        }
    }
}

#[derive(Clone)]
pub struct ChildSpecs {
    id: String,
    child: Rc<Supervisable>,
    restart: ChildLifetime,
    shutdown: ShutdownType,
    process_type: ProcessType,
}

impl ChildSpecs {
    pub fn new(id: &str,
               child: Rc<Supervisable>,
               restart: ChildLifetime,
               shutdown: ShutdownType,
               process_type: ProcessType)
               -> ChildSpecs {
        ChildSpecs {
            id: id.to_owned(),
            child: child,
            restart: restart,
            shutdown: shutdown,
            process_type: process_type,
        }
    }
}

#[derive(Clone)]
struct ChildRecord {
    spec_index: usize,
    time_started: PreciseTime,
}

pub struct Supervisor {
    flags: SupervisorFlags,
    child_specs: Vec<ChildSpecs>,
    child_records: HashMap<i32, ChildRecord>,
}

impl Supervisor {
    pub fn new(flags: SupervisorFlags, specs: &[ChildSpecs]) -> Supervisor {
        Supervisor {
            flags: flags,
            child_specs: specs.to_vec(),
            child_records: HashMap::new(),
        }
    }

    /// Runs the supervisor for the given child tasks
    pub fn run(&mut self) -> Result<()> {
        info!("Supervisor start.");
        self.init().chain_err(|| ErrorKind::SupervisorInitError)?;
        for idx in 0..self.child_specs.len() {
            info!("Supervisor spawning child: {}.", self.child_specs[idx].id);
            match fork().chain_err(|| "Could not fork process.")? {
                ForkResult::Child => {
                    self.child_specs[idx].child.init()?;
                    return Ok(());
                }
                ForkResult::Parent { child } => {
                    self.child_records
                        .insert(child,
                                ChildRecord {
                                    spec_index: idx,
                                    time_started: PreciseTime::now(),
                                });
                }
            }
        }
        self.supervise()?;
        Ok(())
    }

    fn supervise(&mut self) -> Result<()> {
        thread::spawn(|| {
            let mut sigs = SigSet::empty();
            sigs.add(Signal::SIGCHLD);
            sigs.add(Signal::SIGINT);
            if let Ok(sig) = sigs.wait() {
                match sig {
                    Signal::SIGINT => {
                        warn!("SIGINT!!!!!");
                        // Here, send child processes an exit message
                    }
                    _ => {}
                }
            }
        });

        let pool = CpuPool::new_num_cpus();
        let timer = Timer::default();
        let num_kids = self.child_records.len();
        info!("Supervisor waiting for child processes. {} remaining.",
              num_kids);
        let mut results = Vec::new();
        let records = self.child_records.clone();
        let names = self.child_specs.iter().map(|s| s.id.clone()).collect::<Vec<String>>();
        for idx in 0..num_kids {
            let pid = get_pid_for_idx(&records, idx);
            let birth = records[&pid].time_started;
            let child_name = names[records[&pid].spec_index].clone();
            let wait_future = pool.spawn_fn(move || {
                info!("Waiting for {}", pid);
                match waitpid(pid, None) {
                    Ok(WaitStatus::Exited(_, ret)) => {
                        let life = birth.to(PreciseTime::now())
                            .num_seconds();
                        info!("Status: {} exited after {}s with exit code {}.",
                              child_name,
                              life,
                              ret);
                    }
                    _ => {
                        warn!("Unknown action");
                    }
                };
                let res: Result<i32> = Ok(pid);
                res
            });
            let timeout = pool.spawn(timer.sleep(Duration::from_secs(5))
                .then(|_| {
                    info!("Timeout reached!");
                    Ok(-1)
                }));
            results.push(timeout.select(wait_future).map(|(res, _)| res));
        };
        if let Ok(results) = future::join_all(results).wait() {
            for pid in results {
                info!("{} Exited", pid);
                self.child_records.remove(&pid);
            }
        }
        Ok(())
    }

    fn init(&self) -> Result<()> {
        #[cfg(not(target_os="linux"))]
        {
            let mask = SigSet::empty();
            let flags = SaFlags::empty();
            let handler = SigHandler::Handler(null_handler);
            let action = SigAction::new(handler, flags, mask);
            unsafe {
                sigaction(Signal::SIGCHLD, &action)?;
            }
        }

        SigSet::all().thread_set_mask()?;
        Ok(())
    }
}

fn get_pid_for_idx(records: &HashMap<i32, ChildRecord>, idx: usize) -> i32 {
    let pids = records.iter()
        .filter(|&(_, v)| v.spec_index == idx)
        .map(|(k, _)| *k)
        .collect::<Vec<i32>>();
    pids[0]
}

#[cfg(not(target_os="linux"))]
extern "C" fn null_handler(_: c_int) -> () {}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use par_exec::{Executor, ExecutorJobError, JobExecuteError};

use super::PopulationFit;
use super::super::individual::{Individual, IndividualManager};
use super::super::super::set::{Set, SetManager};
use super::super::super::set::union;

pub trait Policy {
    type LocalContext ; //: IndividualManagerMut<IM = Self::IndivM> + SetManagerMut<SM = Self::PopSM> + SetManagerMut<SM = Self::FitsSM>;
    type Exec: Executor<LC = Self::LocalContext>;

    type Indiv: Individual;
    type Fit;
    type IndivME: Send + 'static;
    type IndivM: IndividualManager<I = Self::Indiv, FI = Self::Fit, E = Self::IndivME>;

    type PopE: Send + 'static;
    type Pop: Set<T = Self::Indiv, E = Self::PopE>;
    type PopSME: Send + 'static;
    type PopSM: SetManager<S = Self::Pop, E = Self::PopSME>;

    type FitsE: Send + 'static;
    type Fits: Set<T = (Self::Fit, usize), E = Self::FitsE> + Send + 'static;
    type FitsSME: Send + 'static;
    type FitsSM: SetManager<S = Self::Fits, E = Self::FitsSME>;
}
<commit_msg>futher work on policy<commit_after>use std::marker::PhantomData;
use par_exec::{Executor, ExecutorJobError, JobExecuteError};

use super::PopulationFit;
use super::super::individual::{Individual, IndividualManager};
use super::super::super::set::{Set, SetManager};
use super::super::super::set::union;

pub trait RetrieveFitsManager {
    type FitsM;

    fn retrieve(&mut self) -> &mut Self::FitsM;
}

pub trait RetrieveIndividualManager {
    type IM;

    fn retrieve(&mut self) -> &mut Self::IM;
}

pub trait Policy {
    type LocalContext: RetrieveFitsManager<FitsM = Self::FitsM> + RetrieveIndividualManager<IM = Self::IndivM>;
    type Exec: Executor<LC = Self::LocalContext>;

    type Indiv: Individual;
    type Fit;
    type IndivME: Send + 'static;
    type IndivM: IndividualManager<I = Self::Indiv, FI = Self::Fit, E = Self::IndivME>;

    type PopE: Send + 'static;
    type Pop: Set<T = Self::Indiv, E = Self::PopE>;

    type FitsE: Send + 'static;
    type Fits: Set<T = (Self::Fit, usize), E = Self::FitsE> + Send + 'static;
    type FitsME: Send + 'static;
    type FitsM: SetManager<S = Self::Fits, E = Self::FitsME>;
}
<|endoftext|>


<commit_before>use core::prelude::*;
use core::intrinsics;
use hil;

#[repr(C, packed)]
struct Register {
    val: u32,
    set: u32,
    clear: u32,
    toggle: u32
}

#[repr(C, packed)]
struct RegisterRO {
    val: u32,
    reserved: [u32; 3]
}

#[repr(C, packed)]
struct RegisterRC {
    val: u32,
    reserved0: u32,
    clear: u32,
    reserved1: u32
}

#[repr(C, packed)]
struct GPIOPortRegisters {
    gper: Register,
    pmr0: Register,
    pmr1: Register,
    pmr2: Register,
    oder: Register,
    ovr: Register,
    pvr: RegisterRO,
    puer: Register,
    pder: Register,
    ier: Register,
    imr0: Register,
    imr1: Register,
    gfer: Register,
    ifr: RegisterRC,
    reserved0: [u32; 8],
    ocdr0: Register,
    ocdr1: Register,
    reserved1: [u32; 4],
    osrr0: Register,
    reserved2: [u32; 8],
    ster: Register,
    reserved3: [u32; 4],
    ever: Register,
    reserved4: [u32; 26],
    parameter: u32,
    version: u32,
}

#[derive(Copy,Clone)]
pub enum PeripheralFunction {
    A, B, C, D, E, F, G, H
}

const BASE_ADDRESS: usize = 0x400E1000;
const SIZE: usize = 0x200;

#[derive(Copy,Clone)]
pub enum Pin {
    PA00, PA01, PA02, PA03, PA04, PA05, PA06, PA07,
    PA08, PA09, PA10, PA11, PA12, PA13, PA14, PA15,
    PA16, PA17, PA18, PA19, PA20, PA21, PA22, PA23,
    PA24, PA25, PA26, PA27, PA28, PA29, PA30, PA31,

    PB00, PB01, PB02, PB03, PB04, PB05, PB06, PB07,
    PB08, PB09, PB10, PB11, PB12, PB13, PB14, PB15,
    PB16, PB17, PB18, PB19, PB20, PB21, PB22, PB23,
    PB24, PB25, PB26, PB27, PB28, PB29, PB30, PB31,

    PC00, PC01, PC02, PC03, PC04, PC05, PC06, PC07,
    PC08, PC09, PC10, PC11, PC12, PC13, PC14, PC15,
    PC16, PC17, PC18, PC19, PC20, PC21, PC22, PC23,
    PC24, PC25, PC26, PC27, PC28, PC29, PC30, PC31,
}

pub struct GPIOPin {
    port: &'static mut GPIOPortRegisters,
    pin_mask: u32
}

impl GPIOPin {
    pub fn new(pin: Pin) -> GPIOPin {
        let address = BASE_ADDRESS + ((pin as usize) / 32) * SIZE;
        let pin_number = ((pin as usize) % 32) as u8;

        GPIOPin {
            port: unsafe { intrinsics::transmute(address) },
            pin_mask: 1 << (pin_number as u32)
        }
    }

    pub fn select_peripheral(&mut self, function: PeripheralFunction) {
        let f = function as u32;
        let (bit0, bit1, bit2) = (f & 0b1, (f & 0b10) >> 1, (f & 0b100) >> 2);

        // clear GPIO enable for pin
        volatile!(self.port.gper.clear = self.pin_mask);

        // Set PMR0-2 according to passed in peripheral

        // bradjc: This code doesn't look great, but actually works.
        if bit0 == 0 {
            volatile!(self.port.pmr0.clear = self.pin_mask);
        } else {
            volatile!(self.port.pmr0.set = 1 << self.pin_mask);
        }
        if bit1 == 0 {
            volatile!(self.port.pmr1.clear = 1 << self.pin_mask);
        } else {
            volatile!(self.port.pmr1.set = 1 << self.pin_mask);
        }
        if bit2 == 0 {
            volatile!(self.port.pmr2.clear = 1 << self.pin_mask);
        } else {
            volatile!(self.port.pmr2.set = 1 << self.pin_mask);
        }
        // bradjc: These register assigns erase previous settings and don't
        //         work.
        // volatile!(self.port.pmr0.val = bit0 << self.pin_mask);
        // volatile!(self.port.pmr1.val = bit1 << self.pin_mask);
        // volatile!(self.port.pmr2.val = bit2 << self.pin_mask);
    }

    pub fn set_ster(&mut self) {
        volatile!(self.port.ster.set = self.pin_mask);
    }
}

impl hil::Controller for GPIOPin {
    type Config = Option<PeripheralFunction>;

    fn configure(&mut self, config: Option<PeripheralFunction>) {
        config.map(|c| {
            self.select_peripheral(c);
        });
    }
}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&mut self) {
        volatile!(self.port.gper.set = self.pin_mask);
        volatile!(self.port.oder.set = self.pin_mask);
        volatile!(self.port.ster.clear = self.pin_mask);
    }

    fn read(&self) -> bool {
        (volatile!(self.port.pvr.val) & self.pin_mask) > 0
    }

    fn toggle(&mut self) {
        volatile!(self.port.ovr.toggle = self.pin_mask);
    }

    fn set(&mut self) {
        volatile!(self.port.ovr.set = self.pin_mask);
    }

    fn clear(&mut self) {
        volatile!(self.port.ovr.clear = self.pin_mask);
    }
}
<commit_msg>fix silent but huge bug in gpio select_peripheral<commit_after>use core::prelude::*;
use core::intrinsics;
use hil;

#[repr(C, packed)]
struct Register {
    val: u32,
    set: u32,
    clear: u32,
    toggle: u32
}

#[repr(C, packed)]
struct RegisterRO {
    val: u32,
    reserved: [u32; 3]
}

#[repr(C, packed)]
struct RegisterRC {
    val: u32,
    reserved0: u32,
    clear: u32,
    reserved1: u32
}

#[repr(C, packed)]
struct GPIOPortRegisters {
    gper: Register,
    pmr0: Register,
    pmr1: Register,
    pmr2: Register,
    oder: Register,
    ovr: Register,
    pvr: RegisterRO,
    puer: Register,
    pder: Register,
    ier: Register,
    imr0: Register,
    imr1: Register,
    gfer: Register,
    ifr: RegisterRC,
    reserved0: [u32; 8],
    ocdr0: Register,
    ocdr1: Register,
    reserved1: [u32; 4],
    osrr0: Register,
    reserved2: [u32; 8],
    ster: Register,
    reserved3: [u32; 4],
    ever: Register,
    reserved4: [u32; 26],
    parameter: u32,
    version: u32,
}

#[derive(Copy,Clone)]
pub enum PeripheralFunction {
    A, B, C, D, E, F, G, H
}

const BASE_ADDRESS: usize = 0x400E1000;
const SIZE: usize = 0x200;

#[derive(Copy,Clone)]
pub enum Pin {
    PA00, PA01, PA02, PA03, PA04, PA05, PA06, PA07,
    PA08, PA09, PA10, PA11, PA12, PA13, PA14, PA15,
    PA16, PA17, PA18, PA19, PA20, PA21, PA22, PA23,
    PA24, PA25, PA26, PA27, PA28, PA29, PA30, PA31,

    PB00, PB01, PB02, PB03, PB04, PB05, PB06, PB07,
    PB08, PB09, PB10, PB11, PB12, PB13, PB14, PB15,
    PB16, PB17, PB18, PB19, PB20, PB21, PB22, PB23,
    PB24, PB25, PB26, PB27, PB28, PB29, PB30, PB31,

    PC00, PC01, PC02, PC03, PC04, PC05, PC06, PC07,
    PC08, PC09, PC10, PC11, PC12, PC13, PC14, PC15,
    PC16, PC17, PC18, PC19, PC20, PC21, PC22, PC23,
    PC24, PC25, PC26, PC27, PC28, PC29, PC30, PC31,
}

pub struct GPIOPin {
    port: &'static mut GPIOPortRegisters,
    pin_mask: u32
}

impl GPIOPin {
    pub fn new(pin: Pin) -> GPIOPin {
        let address = BASE_ADDRESS + ((pin as usize) / 32) * SIZE;
        let pin_number = ((pin as usize) % 32) as u8;

        GPIOPin {
            port: unsafe { intrinsics::transmute(address) },
            pin_mask: 1 << (pin_number as u32)
        }
    }

    pub fn select_peripheral(&mut self, function: PeripheralFunction) {
        let f = function as u32;
        let (bit0, bit1, bit2) = (f & 0b1, (f & 0b10) >> 1, (f & 0b100) >> 2);

        // clear GPIO enable for pin
        volatile!(self.port.gper.clear = self.pin_mask);

        // Set PMR0-2 according to passed in peripheral

        // bradjc: This code doesn't look great, but actually works.
        if bit0 == 0 {
            volatile!(self.port.pmr0.clear = self.pin_mask);
        } else {
            volatile!(self.port.pmr0.set = self.pin_mask);
        }
        if bit1 == 0 {
            volatile!(self.port.pmr1.clear = self.pin_mask);
        } else {
            volatile!(self.port.pmr1.set = self.pin_mask);
        }
        if bit2 == 0 {
            volatile!(self.port.pmr2.clear = self.pin_mask);
        } else {
            volatile!(self.port.pmr2.set = self.pin_mask);
        }
        // bradjc: These register assigns erase previous settings and don't
        //         work.
        // volatile!(self.port.pmr0.val = bit0 << self.pin_mask);
        // volatile!(self.port.pmr1.val = bit1 << self.pin_mask);
        // volatile!(self.port.pmr2.val = bit2 << self.pin_mask);
    }

    pub fn set_ster(&mut self) {
        volatile!(self.port.ster.set = self.pin_mask);
    }
}

impl hil::Controller for GPIOPin {
    type Config = Option<PeripheralFunction>;

    fn configure(&mut self, config: Option<PeripheralFunction>) {
        config.map(|c| {
            self.select_peripheral(c);
        });
    }
}

impl hil::gpio::GPIOPin for GPIOPin {
    fn enable_output(&mut self) {
        volatile!(self.port.gper.set = self.pin_mask);
        volatile!(self.port.oder.set = self.pin_mask);
        volatile!(self.port.ster.clear = self.pin_mask);
    }

    fn read(&self) -> bool {
        (volatile!(self.port.pvr.val) & self.pin_mask) > 0
    }

    fn toggle(&mut self) {
        volatile!(self.port.ovr.toggle = self.pin_mask);
    }

    fn set(&mut self) {
        volatile!(self.port.ovr.set = self.pin_mask);
    }

    fn clear(&mut self) {
        volatile!(self.port.ovr.clear = self.pin_mask);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ::cache::disk::DiskCache;
use ::client::{
    connect_to_server,
};
use ::commands::{
    do_compile,
    request_shutdown,
    request_stats,
};
use env_logger;
use futures::sync::oneshot::{self, Sender};
use futures_cpupool::CpuPool;
use jobserver::Client;
use ::mock_command::*;
use ::server::{
    ServerMessage,
    SccacheServer,
};
use std::fs::File;
use std::io::{
    Cursor,
    Write,
};
use std::net::TcpListener;
use std::path::Path;
use std::process::Command;
use std::sync::{Arc,Mutex,mpsc};
use std::thread;
use std::time::Duration;
use std::u64;
use test::utils::*;
use tokio_core::reactor::Core;

/// Options for running the server in tests.
#[derive(Default)]
struct ServerOptions {
    /// The server's idle shutdown timeout.
    idle_timeout: Option<u64>,
    /// The maximum size of the disk cache.
    cache_size: Option<u64>,
}

/// Run a server on a background thread, and return a tuple of useful things.
///
/// * The port on which the server is listening.
/// * A `Sender` which can be used to send messages to the server.
///   (Most usefully, ServerMessage::Shutdown.)
/// * An `Arc`-and-`Mutex`-wrapped `MockCommandCreator` which the server will
///   use for all process creation.
/// * The `JoinHandle` for the server thread.
fn run_server_thread<T>(cache_dir: &Path, options: T)
                        -> (u16, Sender<ServerMessage>, Arc<Mutex<MockCommandCreator>>, thread::JoinHandle<()>)
    where T: Into<Option<ServerOptions>> + Send + 'static
{
    let options = options.into();
    let cache_dir = cache_dir.to_path_buf();

    let cache_size = options.as_ref()
                            .and_then(|o| o.cache_size.as_ref())
                            .map(|s| *s)
                            .unwrap_or(u64::MAX);
    let pool = CpuPool::new(1);
    let storage = Arc::new(DiskCache::new(&cache_dir, cache_size, &pool));

    // Create a server on a background thread, get some useful bits from it.
    let (tx, rx) = mpsc::channel();
    let (shutdown_tx, shutdown_rx) = oneshot::channel();
    let handle = thread::spawn(move || {
        let core = Core::new().unwrap();
        let client = unsafe { Client::new() };
        let srv = SccacheServer::new(0, pool, core, client, storage).unwrap();
        let mut srv: SccacheServer<Arc<Mutex<MockCommandCreator>>> = srv;
        assert!(srv.port() > 0);
        if let Some(options) = options {
            if let Some(timeout) = options.idle_timeout {
                 srv.set_idle_timeout(Duration::from_millis(timeout));
            }
        }
        let port = srv.port();
        let creator = srv.command_creator().clone();
        tx.send((port, creator)).unwrap();
        srv.run(shutdown_rx).unwrap();
    });
    let (port, creator) = rx.recv().unwrap();
    (port, shutdown_tx, creator, handle)
}

#[test]
fn test_server_shutdown() {
    let f = TestFixture::new();
    let (port, _sender, _storage, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    // Ask it to shut down
    request_shutdown(conn).unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

/// The server will shutdown when requested when the idle timeout is disabled.
#[test]
fn test_server_shutdown_no_idle() {
    let f = TestFixture::new();
    // Set a ridiculously low idle timeout.
    let (port, _sender, _storage, child) = run_server_thread(
        &f.tempdir.path(),
        ServerOptions {
            idle_timeout: Some(0),
            ..Default::default()
        },
    );

    let conn = connect_to_server(port).unwrap();
    request_shutdown(conn).unwrap();
    child.join().unwrap();
}

#[test]
fn test_server_idle_timeout() {
    let f = TestFixture::new();
    // Set a ridiculously low idle timeout.
    let (_port, _sender, _storage, child) = run_server_thread(&f.tempdir.path(), ServerOptions { idle_timeout: Some(1), .. Default::default() });
    // Don't connect to it.
    // Ensure that it shuts down.
    // It would be nice to have an explicit timeout here so we don't hang
    // if something breaks...
    child.join().unwrap();
}

#[test]
fn test_server_stats() {
    let f = TestFixture::new();
    let (port, sender, _storage, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    // Ask it for stats.
    let info = request_stats(conn).unwrap();
    assert_eq!(0, info.stats.compile_requests);
    // Now signal it to shut down.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
fn test_server_unsupported_compiler() {
    let f = TestFixture::new();
    let (port, sender, server_creator, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    {
        let mut c = server_creator.lock().unwrap();
        // The server will check the compiler, so pretend to be an unsupported
        // compiler.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), "hello", "error")));
    }
    // Ask the server to compile something.
    //TODO: MockCommand should validate these!
    let exe = &f.bins[0];
    let cmdline = vec!["-c".into(), "file.c".into(), "-o".into(), "file.o".into()];
    let cwd = f.tempdir.path();
    let client_creator = new_creator();
    const COMPILER_STDOUT: &'static [u8] = b"some stdout";
    const COMPILER_STDERR: &'static [u8] = b"some stderr";
    {
        let mut c = client_creator.lock().unwrap();
        // Actual client output.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), COMPILER_STDOUT, COMPILER_STDERR)));
    }
    let mut stdout = Cursor::new(Vec::new());
    let mut stderr = Cursor::new(Vec::new());
    let path = Some(f.paths);
    let mut core = Core::new().unwrap();
    assert_eq!(0, do_compile(client_creator.clone(), &mut core, conn, exe, cmdline, cwd, path, vec![], &mut stdout, &mut stderr).unwrap());
    // Make sure we ran the mock processes.
    assert_eq!(0, server_creator.lock().unwrap().children.len());
    assert_eq!(0, client_creator.lock().unwrap().children.len());
    assert_eq!(COMPILER_STDOUT, &stdout.into_inner()[..]);
    assert_eq!(COMPILER_STDERR, &stderr.into_inner()[..]);
    // Shut down the server.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
fn test_server_compile() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let f = TestFixture::new();
    let (port, sender, server_creator, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    const PREPROCESSOR_STDOUT : &'static [u8] = b"preprocessor stdout";
    const PREPROCESSOR_STDERR : &'static [u8] = b"preprocessor stderr";
    const STDOUT : &'static [u8] = b"some stdout";
    const STDERR : &'static [u8] = b"some stderr";
    let conn = connect_to_server(port).unwrap();
    {
        let mut c = server_creator.lock().unwrap();
        // The server will check the compiler. Pretend it's GCC.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), "gcc", "")));
        // Preprocessor invocation.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), PREPROCESSOR_STDOUT, PREPROCESSOR_STDERR)));
        // Compiler invocation.
        //TODO: wire up a way to get data written to stdin.
        let obj = f.tempdir.path().join("file.o");
        c.next_command_calls(move |_| {
            // Pretend to compile something.
            let mut f = File::create(&obj)?;
            f.write_all(b"file contents")?;
            Ok(MockChild::new(exit_status(0), STDOUT, STDERR))
        });
    }
    // Ask the server to compile something.
    //TODO: MockCommand should validate these!
    let exe = &f.bins[0];
    let cmdline = vec!["-c".into(), "file.c".into(), "-o".into(), "file.o".into()];
    let cwd = f.tempdir.path();
    // This creator shouldn't create any processes. It will assert if
    // it tries to.
    let client_creator = new_creator();
    let mut stdout = Cursor::new(Vec::new());
    let mut stderr = Cursor::new(Vec::new());
    let path = Some(f.paths);
    let mut core = Core::new().unwrap();
    assert_eq!(0, do_compile(client_creator.clone(), &mut core, conn, exe, cmdline, cwd, path, vec![], &mut stdout, &mut stderr).unwrap());
    // Make sure we ran the mock processes.
    assert_eq!(0, server_creator.lock().unwrap().children.len());
    assert_eq!(STDOUT, stdout.into_inner().as_slice());
    assert_eq!(STDERR, stderr.into_inner().as_slice());
    // Shut down the server.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
fn test_server_port_in_use() {
    // Bind an arbitrary free port.
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let sccache = find_sccache_binary();
    let output = Command::new(&sccache)
        .arg("--start-server")
        .env("SCCACHE_SERVER_PORT", listener.local_addr().unwrap().port().to_string())
        .output()
        .unwrap();
    assert!(!output.status.success());
    let s = String::from_utf8_lossy(&output.stderr);
    assert!(s.contains("Server startup failed:"),
            "Output did not contain 'Failed to start server:':\n========\n{}\n========",
            s);
}
<commit_msg>Disable test_server_port_in_use on macOS for now because it fails intermittently<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use ::cache::disk::DiskCache;
use ::client::{
    connect_to_server,
};
use ::commands::{
    do_compile,
    request_shutdown,
    request_stats,
};
use env_logger;
use futures::sync::oneshot::{self, Sender};
use futures_cpupool::CpuPool;
use jobserver::Client;
use ::mock_command::*;
use ::server::{
    ServerMessage,
    SccacheServer,
};
use std::fs::File;
use std::io::{
    Cursor,
    Write,
};
use std::net::TcpListener;
use std::path::Path;
use std::process::Command;
use std::sync::{Arc,Mutex,mpsc};
use std::thread;
use std::time::Duration;
use std::u64;
use test::utils::*;
use tokio_core::reactor::Core;

/// Options for running the server in tests.
#[derive(Default)]
struct ServerOptions {
    /// The server's idle shutdown timeout.
    idle_timeout: Option<u64>,
    /// The maximum size of the disk cache.
    cache_size: Option<u64>,
}

/// Run a server on a background thread, and return a tuple of useful things.
///
/// * The port on which the server is listening.
/// * A `Sender` which can be used to send messages to the server.
///   (Most usefully, ServerMessage::Shutdown.)
/// * An `Arc`-and-`Mutex`-wrapped `MockCommandCreator` which the server will
///   use for all process creation.
/// * The `JoinHandle` for the server thread.
fn run_server_thread<T>(cache_dir: &Path, options: T)
                        -> (u16, Sender<ServerMessage>, Arc<Mutex<MockCommandCreator>>, thread::JoinHandle<()>)
    where T: Into<Option<ServerOptions>> + Send + 'static
{
    let options = options.into();
    let cache_dir = cache_dir.to_path_buf();

    let cache_size = options.as_ref()
                            .and_then(|o| o.cache_size.as_ref())
                            .map(|s| *s)
                            .unwrap_or(u64::MAX);
    let pool = CpuPool::new(1);
    let storage = Arc::new(DiskCache::new(&cache_dir, cache_size, &pool));

    // Create a server on a background thread, get some useful bits from it.
    let (tx, rx) = mpsc::channel();
    let (shutdown_tx, shutdown_rx) = oneshot::channel();
    let handle = thread::spawn(move || {
        let core = Core::new().unwrap();
        let client = unsafe { Client::new() };
        let srv = SccacheServer::new(0, pool, core, client, storage).unwrap();
        let mut srv: SccacheServer<Arc<Mutex<MockCommandCreator>>> = srv;
        assert!(srv.port() > 0);
        if let Some(options) = options {
            if let Some(timeout) = options.idle_timeout {
                 srv.set_idle_timeout(Duration::from_millis(timeout));
            }
        }
        let port = srv.port();
        let creator = srv.command_creator().clone();
        tx.send((port, creator)).unwrap();
        srv.run(shutdown_rx).unwrap();
    });
    let (port, creator) = rx.recv().unwrap();
    (port, shutdown_tx, creator, handle)
}

#[test]
fn test_server_shutdown() {
    let f = TestFixture::new();
    let (port, _sender, _storage, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    // Ask it to shut down
    request_shutdown(conn).unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

/// The server will shutdown when requested when the idle timeout is disabled.
#[test]
fn test_server_shutdown_no_idle() {
    let f = TestFixture::new();
    // Set a ridiculously low idle timeout.
    let (port, _sender, _storage, child) = run_server_thread(
        &f.tempdir.path(),
        ServerOptions {
            idle_timeout: Some(0),
            ..Default::default()
        },
    );

    let conn = connect_to_server(port).unwrap();
    request_shutdown(conn).unwrap();
    child.join().unwrap();
}

#[test]
fn test_server_idle_timeout() {
    let f = TestFixture::new();
    // Set a ridiculously low idle timeout.
    let (_port, _sender, _storage, child) = run_server_thread(&f.tempdir.path(), ServerOptions { idle_timeout: Some(1), .. Default::default() });
    // Don't connect to it.
    // Ensure that it shuts down.
    // It would be nice to have an explicit timeout here so we don't hang
    // if something breaks...
    child.join().unwrap();
}

#[test]
fn test_server_stats() {
    let f = TestFixture::new();
    let (port, sender, _storage, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    // Ask it for stats.
    let info = request_stats(conn).unwrap();
    assert_eq!(0, info.stats.compile_requests);
    // Now signal it to shut down.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
fn test_server_unsupported_compiler() {
    let f = TestFixture::new();
    let (port, sender, server_creator, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    let conn = connect_to_server(port).unwrap();
    {
        let mut c = server_creator.lock().unwrap();
        // The server will check the compiler, so pretend to be an unsupported
        // compiler.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), "hello", "error")));
    }
    // Ask the server to compile something.
    //TODO: MockCommand should validate these!
    let exe = &f.bins[0];
    let cmdline = vec!["-c".into(), "file.c".into(), "-o".into(), "file.o".into()];
    let cwd = f.tempdir.path();
    let client_creator = new_creator();
    const COMPILER_STDOUT: &'static [u8] = b"some stdout";
    const COMPILER_STDERR: &'static [u8] = b"some stderr";
    {
        let mut c = client_creator.lock().unwrap();
        // Actual client output.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), COMPILER_STDOUT, COMPILER_STDERR)));
    }
    let mut stdout = Cursor::new(Vec::new());
    let mut stderr = Cursor::new(Vec::new());
    let path = Some(f.paths);
    let mut core = Core::new().unwrap();
    assert_eq!(0, do_compile(client_creator.clone(), &mut core, conn, exe, cmdline, cwd, path, vec![], &mut stdout, &mut stderr).unwrap());
    // Make sure we ran the mock processes.
    assert_eq!(0, server_creator.lock().unwrap().children.len());
    assert_eq!(0, client_creator.lock().unwrap().children.len());
    assert_eq!(COMPILER_STDOUT, &stdout.into_inner()[..]);
    assert_eq!(COMPILER_STDERR, &stderr.into_inner()[..]);
    // Shut down the server.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
fn test_server_compile() {
    match env_logger::init() {
        Ok(_) => {},
        Err(_) => {},
    }
    let f = TestFixture::new();
    let (port, sender, server_creator, child) = run_server_thread(&f.tempdir.path(), None);
    // Connect to the server.
    const PREPROCESSOR_STDOUT : &'static [u8] = b"preprocessor stdout";
    const PREPROCESSOR_STDERR : &'static [u8] = b"preprocessor stderr";
    const STDOUT : &'static [u8] = b"some stdout";
    const STDERR : &'static [u8] = b"some stderr";
    let conn = connect_to_server(port).unwrap();
    {
        let mut c = server_creator.lock().unwrap();
        // The server will check the compiler. Pretend it's GCC.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), "gcc", "")));
        // Preprocessor invocation.
        c.next_command_spawns(Ok(MockChild::new(exit_status(0), PREPROCESSOR_STDOUT, PREPROCESSOR_STDERR)));
        // Compiler invocation.
        //TODO: wire up a way to get data written to stdin.
        let obj = f.tempdir.path().join("file.o");
        c.next_command_calls(move |_| {
            // Pretend to compile something.
            let mut f = File::create(&obj)?;
            f.write_all(b"file contents")?;
            Ok(MockChild::new(exit_status(0), STDOUT, STDERR))
        });
    }
    // Ask the server to compile something.
    //TODO: MockCommand should validate these!
    let exe = &f.bins[0];
    let cmdline = vec!["-c".into(), "file.c".into(), "-o".into(), "file.o".into()];
    let cwd = f.tempdir.path();
    // This creator shouldn't create any processes. It will assert if
    // it tries to.
    let client_creator = new_creator();
    let mut stdout = Cursor::new(Vec::new());
    let mut stderr = Cursor::new(Vec::new());
    let path = Some(f.paths);
    let mut core = Core::new().unwrap();
    assert_eq!(0, do_compile(client_creator.clone(), &mut core, conn, exe, cmdline, cwd, path, vec![], &mut stdout, &mut stderr).unwrap());
    // Make sure we ran the mock processes.
    assert_eq!(0, server_creator.lock().unwrap().children.len());
    assert_eq!(STDOUT, stdout.into_inner().as_slice());
    assert_eq!(STDERR, stderr.into_inner().as_slice());
    // Shut down the server.
    sender.send(ServerMessage::Shutdown).ok().unwrap();
    // Ensure that it shuts down.
    child.join().unwrap();
}

#[test]
// test fails intermittently on macos:
// https://github.com/mozilla/sccache/issues/234
#[cfg(not(target_os="macos"))]
fn test_server_port_in_use() {
    // Bind an arbitrary free port.
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let sccache = find_sccache_binary();
    let output = Command::new(&sccache)
        .arg("--start-server")
        .env("SCCACHE_SERVER_PORT", listener.local_addr().unwrap().port().to_string())
        .output()
        .unwrap();
    assert!(!output.status.success());
    let s = String::from_utf8_lossy(&output.stderr);
    assert!(s.contains("Server startup failed:"),
            "Output did not contain 'Failed to start server:':\n========\n{}\n========",
            s);
}
<|endoftext|>


<commit_before>pub use self::close::close;
pub use self::data::data;
pub use self::init::init;
pub use self::status::StatusCode;

use std::collections::HashMap;
use std::sync::Mutex;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}

mod close;
mod data;
mod init;
mod status;<commit_msg>adjust statment order<commit_after>pub use self::close::close;
pub use self::data::data;
pub use self::init::init;
pub use self::status::StatusCode;

use std::collections::HashMap;
use std::sync::Mutex;

mod close;
mod data;
mod init;
mod status;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}<|endoftext|>


<commit_before>
// FIXME: There is so many PathBuf's in this module
//        Conver them to Path

use std::path::{Path, PathBuf};
use std::fs;
use error::Result;

use regex::Regex;

/// Copies documentation from a crate's target directory to destination.
///
/// Target directory must have doc directory.
///
/// This function is designed to avoid file duplications.
pub fn copy_doc_dir<P: AsRef<Path>>(source: P, destination: P) -> Result<()> {
    let destination = destination.as_ref().to_path_buf();

    // Make sure destination directory exists
    if !destination.exists() {
        fs::create_dir_all(&destination)?;
    }

    // Avoid copying common files
    let dup_regex = Regex::new(
        r"(\.lock|\.txt|\.woff|\.svg|\.css|main-.*\.css|main-.*\.js|normalize-.*\.js|rustdoc-.*\.css|storage-.*\.js|theme-.*\.js)$")
        .unwrap();

    for file in source.as_ref().read_dir()? {

        let file = file?;
        let mut destination_full_path = PathBuf::from(&destination);
        destination_full_path.push(file.file_name());

        let metadata = file.metadata()?;

        if metadata.is_dir() {
            fs::create_dir_all(&destination_full_path)?;
            copy_doc_dir(file.path(), destination_full_path)?
        } else if dup_regex.is_match(&file.file_name().into_string().unwrap()[..]) {
            continue;
        } else {
            fs::copy(&file.path(), &destination_full_path)?;
        }

    }
    Ok(())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::fs;
    use super::*;

    #[test]
    fn test_copy_doc_dir() {
        let source = tempdir::TempDir::new("cratesfyi-src").unwrap();
        let destination = tempdir::TempDir::new("cratesfyi-dst").unwrap();
        let doc = source.path().join("doc");
        fs::create_dir(&doc).unwrap();

        fs::write(doc.join("index.html"), "spooky").unwrap();
        fs::write(doc.join("index.txt"), "spooky").unwrap();

        // lets try to copy a src directory to tempdir
        copy_doc_dir(source.path(), destination.path()).unwrap();
        assert!(destination.path().join("index.html").exists());
        assert!(!destination.path().join("index.txt").exists());
    }
}
<commit_msg>refactor copy_doc_dir to use less allocation<commit_after>
use std::path::Path;
use std::fs;
use error::Result;

use regex::Regex;

/// Copies documentation from a crate's target directory to destination.
///
/// Target directory must have doc directory.
///
/// This function is designed to avoid file duplications.
pub fn copy_doc_dir<P: AsRef<Path>, Q: AsRef<Path>>(source: P, destination: Q) -> Result<()> {
    let destination = destination.as_ref();

    // Make sure destination directory exists
    if !destination.exists() {
        fs::create_dir_all(destination)?;
    }

    // Avoid copying common files
    let dup_regex = Regex::new(
        r"(\.lock|\.txt|\.woff|\.svg|\.css|main-.*\.css|main-.*\.js|normalize-.*\.js|rustdoc-.*\.css|storage-.*\.js|theme-.*\.js)$")
        .unwrap();

    for file in source.as_ref().read_dir()? {

        let file = file?;
        let destination_full_path = destination.join(file.file_name());

        let metadata = file.metadata()?;

        if metadata.is_dir() {
            fs::create_dir_all(&destination_full_path)?;
            copy_doc_dir(file.path(), destination_full_path)?
        } else if dup_regex.is_match(&file.file_name().into_string().unwrap()[..]) {
            continue;
        } else {
            fs::copy(&file.path(), &destination_full_path)?;
        }

    }
    Ok(())
}

#[cfg(test)]
mod test {
    extern crate env_logger;
    use std::fs;
    use super::*;

    #[test]
    fn test_copy_doc_dir() {
        let source = tempdir::TempDir::new("cratesfyi-src").unwrap();
        let destination = tempdir::TempDir::new("cratesfyi-dst").unwrap();
        let doc = source.path().join("doc");
        fs::create_dir(&doc).unwrap();
        fs::create_dir(doc.join("inner")).unwrap();

        fs::write(doc.join("index.html"), "spooky").unwrap();
        fs::write(doc.join("index.txt"), "spooky").unwrap();
        fs::write(doc.join("inner").join("index.html"), "spooky").unwrap();
        fs::write(doc.join("inner").join("index.txt"), "spooky").unwrap();

        // lets try to copy a src directory to tempdir
        copy_doc_dir(source.path().join("doc"), destination.path()).unwrap();
        assert!(destination.path().join("index.html").exists());
        assert!(!destination.path().join("index.txt").exists());
        assert!(destination.path().join("inner").join("index.html").exists());
        assert!(!destination.path().join("inner").join("index.txt").exists());
    }
}
<|endoftext|>