<commit_before>use deque::{BufferPool, Worker, Stealer, Stolen};
use job::Job;
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use num_cpus;
use rand;
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use util::leak;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
    terminate: AtomicBool,
}

struct RegistryState {
    threads_at_work: usize,
    injected_jobs: Vec<*mut Job<LockLatch>>,
}

unsafe impl Send for Registry { }
unsafe impl Sync for Registry { }

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened) and
/// returns the registry.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| {
        let registry = leak(Registry::new());
        unsafe { THE_REGISTRY = Some(registry); }
    });
    unsafe { THE_REGISTRY.unwrap() }
}

impl Registry {
    pub fn new() -> Arc<Registry> {
        let num_threads = num_cpus::get();
        let pool = BufferPool::new();
        let registry = Arc::new(Registry {
            thread_infos: (0..num_threads).map(|_| ThreadInfo::new(&pool))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
            terminate: AtomicBool::new(false),
        });

        for index in 0 .. num_threads {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(registry, index) });
        }

        registry
    }

    fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[*mut Job<LockLatch>]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Option<*mut Job<LockLatch>> {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Some(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        self.terminate.store(true, Ordering::SeqCst);
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: Vec::new(),
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    worker: Worker<JobRef>,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(pool: &BufferPool<JobRef>) -> ThreadInfo {
        let (worker, stealer) = pool.deque();
        ThreadInfo {
            primed: LockLatch::new(),
            worker: worker,
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    registry: Arc<Registry>,
    index: usize
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    fn thread_info(&self) -> &ThreadInfo {
        &self.registry.thread_infos[self.index]
    }

    #[inline]
    pub unsafe fn push(&self, job: *mut Job<SpinLatch>) {
        self.thread_info().worker.push(JobRef { ptr: job });
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> bool {
        self.thread_info().worker.pop().is_some()
    }

    pub unsafe fn steal_until(&self, latch: &Latch) {
        while !latch.probe() {
            if let Some(job) = steal_work(&self.registry, self.index) {
                (*job).execute();
            } else {
                thread::yield_now();
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(registry: Arc<Registry>, index: usize) {
    let worker_thread = WorkerThread {
        registry: registry.clone(),
        index: index,
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    let mut was_active = false;
    while !registry.terminate.load(Ordering::SeqCst) {
        if let Some(injected_job) = registry.wait_for_work(index, was_active) {
            (*injected_job).execute();
            was_active = true;
        } else if let Some(stolen_job) = steal_work(&registry, index) {
            log!(StoleWork { worker: index, job: stolen_job });
            registry.start_working(index);
            (*stolen_job).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}

unsafe fn steal_work(registry: &Registry, index: usize) -> Option<*mut Job<SpinLatch>> {
    let num_threads = registry.num_threads();
    let start = rand::random::<usize>() % num_threads;
    (start .. num_threads)
        .chain(0 .. start)
        .filter(|&i| i != index)
        .flat_map(|i| match registry.thread_infos[i].stealer.steal() {
            Stolen::Empty => None,
            Stolen::Abort => None, // loop?
            Stolen::Data(v) => Some(v.ptr),
        })
        .next()
}

///////////////////////////////////////////////////////////////////////////

pub struct JobRef {
    pub ptr: *mut Job<SpinLatch>
}

unsafe impl Send for JobRef { }
unsafe impl Sync for JobRef { }

<commit_msg>don't use a `Latch` object, use `SpinLatch`<commit_after>use deque::{BufferPool, Worker, Stealer, Stolen};
use job::Job;
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use num_cpus;
use rand;
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use util::leak;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
    terminate: AtomicBool,
}

struct RegistryState {
    threads_at_work: usize,
    injected_jobs: Vec<*mut Job<LockLatch>>,
}

unsafe impl Send for Registry { }
unsafe impl Sync for Registry { }

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened) and
/// returns the registry.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| {
        let registry = leak(Registry::new());
        unsafe { THE_REGISTRY = Some(registry); }
    });
    unsafe { THE_REGISTRY.unwrap() }
}

impl Registry {
    pub fn new() -> Arc<Registry> {
        let num_threads = num_cpus::get();
        let pool = BufferPool::new();
        let registry = Arc::new(Registry {
            thread_infos: (0..num_threads).map(|_| ThreadInfo::new(&pool))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
            terminate: AtomicBool::new(false),
        });

        for index in 0 .. num_threads {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(registry, index) });
        }

        registry
    }

    fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[*mut Job<LockLatch>]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Option<*mut Job<LockLatch>> {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Some(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        self.terminate.store(true, Ordering::SeqCst);
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: Vec::new(),
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    worker: Worker<JobRef>,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(pool: &BufferPool<JobRef>) -> ThreadInfo {
        let (worker, stealer) = pool.deque();
        ThreadInfo {
            primed: LockLatch::new(),
            worker: worker,
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    registry: Arc<Registry>,
    index: usize
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    fn thread_info(&self) -> &ThreadInfo {
        &self.registry.thread_infos[self.index]
    }

    #[inline]
    pub unsafe fn push(&self, job: *mut Job<SpinLatch>) {
        self.thread_info().worker.push(JobRef { ptr: job });
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> bool {
        self.thread_info().worker.pop().is_some()
    }

    pub unsafe fn steal_until(&self, latch: &SpinLatch) {
        while !latch.probe() {
            if let Some(job) = steal_work(&self.registry, self.index) {
                (*job).execute();
            } else {
                thread::yield_now();
            }
        }
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(registry: Arc<Registry>, index: usize) {
    let worker_thread = WorkerThread {
        registry: registry.clone(),
        index: index,
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    let mut was_active = false;
    while !registry.terminate.load(Ordering::SeqCst) {
        if let Some(injected_job) = registry.wait_for_work(index, was_active) {
            (*injected_job).execute();
            was_active = true;
        } else if let Some(stolen_job) = steal_work(&registry, index) {
            log!(StoleWork { worker: index, job: stolen_job });
            registry.start_working(index);
            (*stolen_job).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}

unsafe fn steal_work(registry: &Registry, index: usize) -> Option<*mut Job<SpinLatch>> {
    let num_threads = registry.num_threads();
    let start = rand::random::<usize>() % num_threads;
    (start .. num_threads)
        .chain(0 .. start)
        .filter(|&i| i != index)
        .flat_map(|i| match registry.thread_infos[i].stealer.steal() {
            Stolen::Empty => None,
            Stolen::Abort => None, // loop?
            Stolen::Data(v) => Some(v.ptr),
        })
        .next()
}

///////////////////////////////////////////////////////////////////////////

pub struct JobRef {
    pub ptr: *mut Job<SpinLatch>
}

unsafe impl Send for JobRef { }
unsafe impl Sync for JobRef { }

<|endoftext|>


<commit_before>#![crate_name = "touch"]
#![feature(collections, core, old_io, old_path, rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Nick Platt <platt.nicholas@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate getopts;
extern crate time;

use std::old_io::File;
use std::old_io::fs::PathExtensions;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "touch";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("a", "",               "change only the access time"),
        getopts::optflag("c", "no-create",      "do not create any files"),
        getopts::optopt( "d", "date",           "parse argument and use it instead of current time", "STRING"),
        getopts::optflag("h", "no-dereference", "affect each symbolic link instead of any referenced file \
                                                 (only for systems that can change the timestamps of a symlink)"),
        getopts::optflag("m", "",               "change only the modification time"),
        getopts::optopt( "r", "reference",      "use this file's times instead of the current time", "FILE"),
        getopts::optopt( "t", "",               "use [[CC]YY]MMDDhhmm[.ss] instead of the current time", "STAMP"),
        getopts::optopt( "",  "time",           "change only the specified time: \"access\", \"atime\", or \
                                                 \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                                                 equivalent to -m", "WORD"),
        getopts::optflag("h", "help",           "display this help and exit"),
        getopts::optflag("V", "version",        "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m)  => m,
        Err(e) => panic!("Invalid options\n{}", e)
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage: {} [OPTION]... FILE...", NAME);
        println!("");
        println!("{}", getopts::usage("Update the access and modification times of \
                                         each FILE to the current time.", &opts));
        if matches.free.is_empty() {
            return 1;
        }
        return 0;
    }

    if matches.opt_present("date") && matches.opts_present(&["reference".to_string(), "t".to_string()]) ||
       matches.opt_present("reference") && matches.opts_present(&["date".to_string(), "t".to_string()]) ||
       matches.opt_present("t") && matches.opts_present(&["date".to_string(), "reference".to_string()]) {
        panic!("Invalid options: cannot specify reference time from more than one source");
    }

    let (mut atime, mut mtime) =
        if matches.opt_present("reference") {
            let path = Path::new(matches.opt_str("reference").unwrap().to_string());
            let stat = stat(&path, !matches.opt_present("no-dereference"));
            (stat.accessed, stat.modified)
        } else if matches.opts_present(&["date".to_string(), "t".to_string()]) {
            let timestamp = if matches.opt_present("date") {
                parse_date(matches.opt_str("date").unwrap().as_slice())
            } else {
                parse_timestamp(matches.opt_str("t").unwrap().as_slice())
            };
            (timestamp, timestamp)
        } else {
            // FIXME: Should use Timespec. https://github.com/mozilla/rust/issues/10301
            let now = (time::get_time().sec * 1000) as u64;
            (now, now)
        };

    for filename in matches.free.iter() {
        let path = Path::new(filename.to_string());

        if !path.exists() {
            // no-dereference included here for compatibility
            if matches.opts_present(&["no-create".to_string(), "no-dereference".to_string()]) {
                continue;
            }

            match File::create(&path) {
                Ok(fd) => fd,
                Err(e) => panic!("Unable to create file: {}\n{}", filename, e.desc)
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.opts_present(&["date".to_string(), "reference".to_string(), "t".to_string()]) {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.opts_present(&["a".to_string(), "m".to_string(), "time".to_string()]) {
            let stat = stat(&path, !matches.opt_present("no-dereference"));
            let time = matches.opt_strs("time");

            if !(matches.opt_present("a") ||
                 time.contains(&"access".to_string()) ||
                 time.contains(&"atime".to_string()) ||
                 time.contains(&"use".to_string())) {
                atime = stat.accessed;
            }

            if !(matches.opt_present("m") ||
                 time.contains(&"modify".to_string()) ||
                 time.contains(&"mtime".to_string())) {
                mtime = stat.modified;
            }
        }

        match std::old_io::fs::change_file_times(&path, atime, mtime) {
            Ok(t) => t,
            Err(e) => panic!("Unable to modify times\n{}", e.desc)
        }
    }

    0
}

fn stat(path: &Path, follow: bool) -> std::old_io::FileStat {
    if follow {
        match std::old_io::fs::stat(path) {
            Ok(stat) => stat,
            Err(e)   => panic!("Unable to open file\n{}", e.desc)
        }
    } else {
        match std::old_io::fs::lstat(path) {
            Ok(stat) => stat,
            Err(e)   => panic!("Unable to open file\n{}", e.desc)
        }
    }
}

fn parse_date(str: &str) -> u64 {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => (tm.to_timespec().sec * 1000) as u64,
        Err(e) => panic!("Unable to parse date\n{}", e)
    }
}

fn parse_timestamp(str: &str) -> u64 {
    let format = match str.chars().count() {
        15 => "%Y%m%d%H%M.%S",
        12 => "%Y%m%d%H%M",
        13 => "%y%m%d%H%M.%S",
        10 => "%y%m%d%H%M",
        11 => "%m%d%H%M.%S",
         8 => "%m%d%H%M",
         _ => panic!("Unknown timestamp format")
    };

    match time::strptime(str, format) {
        Ok(tm) => (tm.to_timespec().sec * 1000) as u64,
        Err(e) => panic!("Unable to parse timestamp\n{}", e)
    }
}

<commit_msg>fix `touch`<commit_after>#![crate_name = "touch"]
#![feature(rustc_private, path_ext, fs_time)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Nick Platt <platt.nicholas@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;
extern crate getopts;
extern crate time;

use libc::types::os::arch::c95::c_char;
use libc::types::os::arch::posix01::stat as stat_t;
use libc::funcs::posix88::stat_::stat as c_stat;
use libc::funcs::posix01::stat_::lstat as c_lstat;

use std::fs::{set_file_times, File, PathExt};
use std::io::{Error, Write};
use std::mem::uninitialized;
use std::path::Path;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "touch";
static VERSION: &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("a", "",               "change only the access time"),
        getopts::optflag("c", "no-create",      "do not create any files"),
        getopts::optopt( "d", "date",           "parse argument and use it instead of current time", "STRING"),
        getopts::optflag("h", "no-dereference", "affect each symbolic link instead of any referenced file \
                                                 (only for systems that can change the timestamps of a symlink)"),
        getopts::optflag("m", "",               "change only the modification time"),
        getopts::optopt( "r", "reference",      "use this file's times instead of the current time", "FILE"),
        getopts::optopt( "t", "",               "use [[CC]YY]MMDDhhmm[.ss] instead of the current time", "STAMP"),
        getopts::optopt( "",  "time",           "change only the specified time: \"access\", \"atime\", or \
                                                 \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                                                 equivalent to -m", "WORD"),
        getopts::optflag("h", "help",           "display this help and exit"),
        getopts::optflag("V", "version",        "output version information and exit"),
    ];

    let matches = match getopts::getopts(&args[1..], &opts) {
        Ok(m)  => m,
        Err(e) => panic!("Invalid options\n{}", e)
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.is_empty() {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage: {} [OPTION]... FILE...", NAME);
        println!("");
        println!("{}", getopts::usage("Update the access and modification times of \
                                         each FILE to the current time.", &opts));
        if matches.free.is_empty() {
            return 1;
        }
        return 0;
    }

    if matches.opt_present("date") && matches.opts_present(&["reference".to_string(), "t".to_string()]) ||
       matches.opt_present("reference") && matches.opts_present(&["date".to_string(), "t".to_string()]) ||
       matches.opt_present("t") && matches.opts_present(&["date".to_string(), "reference".to_string()]) {
        panic!("Invalid options: cannot specify reference time from more than one source");
    }

    let (mut atime, mut mtime) =
        if matches.opt_present("reference") {
            stat(&matches.opt_str("reference").unwrap()[..], !matches.opt_present("no-dereference"))
        } else if matches.opts_present(&["date".to_string(), "t".to_string()]) {
            let timestamp = if matches.opt_present("date") {
                parse_date(matches.opt_str("date").unwrap().as_ref())
            } else {
                parse_timestamp(matches.opt_str("t").unwrap().as_ref())
            };
            (timestamp, timestamp)
        } else {
            // FIXME: Should use Timespec. https://github.com/mozilla/rust/issues/10301
            let now = (time::get_time().sec * 1000) as u64;
            (now, now)
        };

    for filename in matches.free.iter() {
        let path = &filename[..];

        if ! Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.opts_present(&["no-create".to_string(), "no-dereference".to_string()]) {
                continue;
            }

            match File::create(path) {
                Err(e) => {
                    show_warning!("cannot touch '{}': {}", path, e);
                    continue;
                },
                _ => (),
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.opts_present(&["date".to_string(), "reference".to_string(), "t".to_string()]) {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.opts_present(&["a".to_string(), "m".to_string(), "time".to_string()]) {
            let st = stat(path, !matches.opt_present("no-dereference"));
            let time = matches.opt_strs("time");

            if !(matches.opt_present("a") ||
                 time.contains(&"access".to_string()) ||
                 time.contains(&"atime".to_string()) ||
                 time.contains(&"use".to_string())) {
                atime = st.0;
            }

            if !(matches.opt_present("m") ||
                 time.contains(&"modify".to_string()) ||
                 time.contains(&"mtime".to_string())) {
                mtime = st.1;
            }
        }

        // this follows symlinks and thus does not work correctly for the -h flag
        // need to use lutimes() c function on supported platforms
        match set_file_times(path, atime, mtime) {
            Err(e) => show_warning!("cannot touch '{}': {}", path, e),
            _ => (),
        };
    }

    0
}

fn stat(path: &str, follow: bool) -> (u64, u64) {
    let stat_fn = if follow {
        c_stat
    } else {
        c_lstat
    };
    let mut st: stat_t = unsafe { uninitialized() };
    let result = unsafe { stat_fn(path.as_ptr() as *const c_char, &mut st as *mut stat_t) };

    if result < 0 {
        crash!(1, "failed to get attributes of '{}': {}", path, Error::last_os_error());
    }

    // set_file_times expects milliseconds
    let atime = if st.st_atime_nsec == 0 {
        st.st_atime * 1000
    } else {
        st.st_atime_nsec / 1000
    } as u64;

    // set_file_times expects milliseconds
    let mtime = if st.st_mtime_nsec == 0 {
        st.st_mtime * 1000
    } else {
        st.st_mtime_nsec / 1000
    } as u64;

    (atime, mtime)
}

fn parse_date(str: &str) -> u64 {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    match time::strptime(str, "%c") {
        Ok(tm) => (tm.to_timespec().sec * 1000) as u64,
        Err(e) => panic!("Unable to parse date\n{}", e)
    }
}

fn parse_timestamp(str: &str) -> u64 {
    let format = match str.chars().count() {
        15 => "%Y%m%d%H%M.%S",
        12 => "%Y%m%d%H%M",
        13 => "%y%m%d%H%M.%S",
        10 => "%y%m%d%H%M",
        11 => "%m%d%H%M.%S",
         8 => "%m%d%H%M",
         _ => panic!("Unknown timestamp format")
    };

    match time::strptime(str, format) {
        Ok(tm) => (tm.to_timespec().sec * 1000) as u64,
        Err(e) => panic!("Unable to parse timestamp\n{}", e)
    }
}

<|endoftext|>


<commit_before>use nix::Error;
use nix::errno::*;
use nix::unistd::*;
use nix::sys::ptrace;

use std::{mem, ptr};

#[test]
fn test_ptrace() {
    use nix::sys::ptrace::ptrace::*;
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    let err = ptrace::ptrace(PTRACE_ATTACH, getpid(), ptr::null_mut(), ptr::null_mut()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
fn test_ptrace_setoptions() {
    use nix::sys::ptrace::ptrace::*; // for PTRACE_O_TRACESYSGOOD
    let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
fn test_ptrace_getevent() {
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
fn test_ptrace_getsiginfo() {
    match ptrace::getsiginfo(getpid()) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
fn test_ptrace_setsiginfo() {
    let siginfo = unsafe { mem::uninitialized() };
    match ptrace::setsiginfo(getpid(), &siginfo) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}
<commit_msg>Get rid of the bulk imports<commit_after>use nix::Error;
use nix::errno::Errno;
use nix::unistd::getpid;
use nix::sys::ptrace;

use std::{mem, ptr};

#[test]
fn test_ptrace() {
    use nix::sys::ptrace::ptrace::PTRACE_ATTACH;
    // Just make sure ptrace can be called at all, for now.
    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
    let err = ptrace::ptrace(PTRACE_ATTACH, getpid(), ptr::null_mut(), ptr::null_mut()).unwrap_err();
    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::ENOSYS));
}

// Just make sure ptrace_setoptions can be called at all, for now.
#[test]
fn test_ptrace_setoptions() {
    use nix::sys::ptrace::ptrace::PTRACE_O_TRACESYSGOOD;
    let err = ptrace::setoptions(getpid(), PTRACE_O_TRACESYSGOOD).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getevent can be called at all, for now.
#[test]
fn test_ptrace_getevent() {
    let err = ptrace::getevent(getpid()).unwrap_err();
    assert!(err != Error::UnsupportedOperation);
}

// Just make sure ptrace_getsiginfo can be called at all, for now.
#[test]
fn test_ptrace_getsiginfo() {
    match ptrace::getsiginfo(getpid()) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}

// Just make sure ptrace_setsiginfo can be called at all, for now.
#[test]
fn test_ptrace_setsiginfo() {
    let siginfo = unsafe { mem::uninitialized() };
    match ptrace::setsiginfo(getpid(), &siginfo) {
        Err(Error::UnsupportedOperation) => panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!"),
        _ => (),
    }
}
<|endoftext|>


<commit_before>use rsh::State;
use std::path::PathBuf;
use std::collections::HashMap;
use std::slice::Iter;

pub type Builtin = fn(State) -> State;

pub fn load() -> HashMap<String, Builtin> {
    let mut h = HashMap::new();

    h.insert("cd".to_string(), cd as fn(State) -> State);

    // h.insert("ls".to_string(), ls as fn(State) -> State);

    h
}

fn cd(s: State) -> State {
    match s.argv.get(1) {
        Some(x) => {
            let mut newS = s.clone();

            newS.cwd = PathBuf::from(x);
            return newS;
        }
        None => s.clone(),
    }
}

pub fn echo(s: State) -> State {
    if s.argv[1] == "-n" {
        let strings = &s.argv[2..s.argv.len()].join(" ");
        print!("{}", strings);
    } else {
        let strings = &s.argv[1..s.argv.len()].join(" ");
        println!("{}", strings);
    }

    s
}

//  fn ls<'a>(s: State) -> State {
//      let dirs: Iter<String>;

//      if s.argv.len() == 0 {
//          let cwd = s.cwd.to_str().unwrap_or("").to_string();
//          let mut args: &'a Vec<String>;
//          args = Vec::new();
//          args.push(cwd);

//          dirs = args.iter();
//      } else {
//          let mut args = s.argv.clone().iter();
//          args.next();
//          dirs = args;
//      }

//      for d in dirs {
//          let mut p = PathBuf::from(d);

//          // Cheking if file so we don't do extra processing
//          if p.is_file() {
//              println!("{}", p.to_str().unwrap_or(""));
//              continue;
//          }

//          // Unwrapping because we know it's a dir, not a file
//          for entry in p.read_dir().unwrap() {
//              match entry {
//                  Ok(e) => {
//                      // TODO replace this unwrap to something safer
//                      println!("{}", e.file_name().into_string().unwrap());
//                  },
//                  Err(e) => println!("Error: {}", e),

//              }
//          }
//      }

//      s
// }
<commit_msg>Add echo Builtin to load<commit_after>use rsh::State;
use std::path::PathBuf;
use std::collections::HashMap;
use std::slice::Iter;

pub type Builtin = fn(State) -> State;

pub fn load() -> HashMap<String, Builtin> {
    let mut h = HashMap::new();

    h.insert("cd".to_string(), cd as fn(State) -> State);
    h.insert("echo".to_string(), echo as fn(State) -> State);
    // h.insert("ls".to_string(), ls as fn(State) -> State);

    h
}

fn cd(s: State) -> State {
    match s.argv.get(1) {
        Some(x) => {
            let mut newS = s.clone();

            newS.cwd = PathBuf::from(x);
            return newS;
        }
        None => s.clone(),
    }
}

pub fn echo(s: State) -> State {
    if s.argv[1] == "-n" {
        let strings = &s.argv[2..s.argv.len()].join(" ");
        print!("{}", strings);
    } else {
        let strings = &s.argv[1..s.argv.len()].join(" ");
        println!("{}", strings);
    }

    s
}

//  fn ls<'a>(s: State) -> State {
//      let dirs: Iter<String>;

//      if s.argv.len() == 0 {
//          let cwd = s.cwd.to_str().unwrap_or("").to_string();
//          let mut args: &'a Vec<String>;
//          args = Vec::new();
//          args.push(cwd);

//          dirs = args.iter();
//      } else {
//          let mut args = s.argv.clone().iter();
//          args.next();
//          dirs = args;
//      }

//      for d in dirs {
//          let mut p = PathBuf::from(d);

//          // Cheking if file so we don't do extra processing
//          if p.is_file() {
//              println!("{}", p.to_str().unwrap_or(""));
//              continue;
//          }

//          // Unwrapping because we know it's a dir, not a file
//          for entry in p.read_dir().unwrap() {
//              match entry {
//                  Ok(e) => {
//                      // TODO replace this unwrap to something safer
//                      println!("{}", e.file_name().into_string().unwrap());
//                  },
//                  Err(e) => println!("Error: {}", e),

//              }
//          }
//      }

//      s
// }
<|endoftext|>


<commit_before>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: GPL-2.0
//

use serde_ini;

use chrono::{DateTime, Duration, Utc};

use std::io;
use std::path::Path;
use std::path::PathBuf;

use serde_helpers::{de, ser};

#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimeSettings {
    pub polling: RuntimePolling,
    pub update: RuntimeUpdate,
    #[serde(skip)] path: PathBuf,
}

impl RuntimeSettings {
    pub fn new() -> Self {
        RuntimeSettings::default()
    }

    pub fn load(mut self, path: &str) -> Result<Self, RuntimeSettingsError> {
        use std::fs::File;
        use std::io::Read;

        let path = Path::new(path);

        if path.exists() {
            info!("Loading runtime settings from '{}'...",
                  path.to_string_lossy());

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;
            self = RuntimeSettings::parse(&content)?;
        } else {
            debug!("Runtime settings file {} does not exists.",
                   path.to_string_lossy());
            info!("Using default runtime settings...");
        }

        self.path = path.to_path_buf();
        Ok(self)
    }

    fn parse(content: &str) -> Result<Self, RuntimeSettingsError> {
        Ok(serde_ini::from_str::<RuntimeSettings>(content)?)
    }

    pub fn save(&self) -> Result<usize, RuntimeSettingsError> {
        use std::fs::File;
        use std::io::Write;

        debug!("Saving runtime settings from '{}'...",
               &self.path.to_string_lossy());

        Ok(File::create(&self.path)?.write(self.serialize()?.as_bytes())?)
    }

    fn serialize(&self) -> Result<String, RuntimeSettingsError> {
        Ok(serde_ini::to_string(&self)?)
    }
}

#[derive(Debug)]
pub enum RuntimeSettingsError {
    Io(io::Error),
    IniDeserialize(serde_ini::de::Error),
    IniSerialize(serde_ini::ser::Error),
}

impl From<io::Error> for RuntimeSettingsError {
    fn from(err: io::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::Io(err)
    }
}

impl From<serde_ini::de::Error> for RuntimeSettingsError {
    fn from(err: serde_ini::de::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::IniDeserialize(err)
    }
}

impl From<serde_ini::ser::Error> for RuntimeSettingsError {
    fn from(err: serde_ini::ser::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::IniSerialize(err)
    }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "LastPoll")]
    pub last: Option<DateTime<Utc>>,
    #[serde(rename = "FirstPoll")] pub first: DateTime<Utc>,
    #[serde(deserialize_with = "de::duration_from_int")]
    #[serde(serialize_with = "ser::duration_to_int")]
    pub extra_interval: Duration,
    pub retries: usize,
    #[serde(rename = "ProbeASAP")]
    #[serde(deserialize_with = "de::bool_from_str")]
    #[serde(serialize_with = "ser::bool_to_string")]
    pub now: bool,
}

impl Default for RuntimePolling {
    fn default() -> Self {
        RuntimePolling { last: None,
                         first: Utc::now(),
                         extra_interval: Duration::seconds(0),
                         retries: 0,
                         now: false, }
    }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimeUpdate {
    #[serde(rename = "UpgradeToInstallation")] pub upgrading_to: i8,
}

impl Default for RuntimeUpdate {
    fn default() -> Self {
        RuntimeUpdate { upgrading_to: -1 }
    }
}

#[test]
fn de() {
    let ini = r"
[Polling]
LastPoll=2017-01-01T00:00:00Z
FirstPoll=2017-02-02T00:00:00Z
ExtraInterval=4
Retries=5
ProbeASAP=false

[Update]
UpgradeToInstallation=1
";
    let expected =
        RuntimeSettings { polling: RuntimePolling { last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap()),
                                                    first: "2017-02-02T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap(),
                                                    extra_interval: Duration::seconds(4),
                                                    retries: 5,
                                                    now: false, },
                          update: RuntimeUpdate { upgrading_to: 1 },
                          ..Default::default() };

    assert!(serde_ini::from_str::<RuntimeSettings>(ini).map_err(|e| println!("{}", e))
                                                       .as_ref()
                                                       .ok() == Some(&expected));
    assert!(RuntimeSettings::parse(ini).as_ref().ok() == Some(&expected));
}

#[test]
fn default() {
    let settings = RuntimeSettings::new();
    let expected = RuntimeSettings { polling: RuntimePolling { last: settings.polling.last,
                                                               first: settings.polling.first,
                                                               extra_interval: Duration::seconds(0),
                                                               retries: 0,
                                                               now: false, },
                                     update: RuntimeUpdate { upgrading_to: -1 },
                                     path: PathBuf::new(), };

    assert!(Some(settings) == Some(expected));
}

#[test]
fn ser() {
    let settings =
        RuntimeSettings { polling: RuntimePolling { last: Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap()),
                                                    first: "2017-02-02T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap(),
                                                    extra_interval: Duration::seconds(4),
                                                    retries: 5,
                                                    now: false, },
                          update: RuntimeUpdate { upgrading_to: 1 },
                          ..Default::default() };

    assert!(serde_ini::from_str(&settings.serialize().ok().unwrap()).map_err(|e| println!("{}", e))
                                                                    .ok() == Some(settings));
}

#[test]
fn load_and_save() {
    use mktemp::Temp;

    let settings_file = Temp::new_file().unwrap().to_path_buf();

    let mut settings = RuntimeSettings::new().load(settings_file.to_str().unwrap())
                                             .unwrap();

    assert_eq!(settings.polling.now, false);
    settings.polling.now = true;

    assert_eq!(settings.polling.now, true);
    settings.save()
            .expect("Failed to save the runtime settings");

    let new_settings = RuntimeSettings::new().load(settings_file.to_str().unwrap())
                                             .unwrap();

    assert_eq!(settings.update, new_settings.update);
}
<commit_msg>runtime_settings: Drop first poll information<commit_after>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: GPL-2.0
//

use serde_ini;

use chrono::{DateTime, Duration, Utc};

use std::io;
use std::path::Path;
use std::path::PathBuf;

use serde_helpers::{de, ser};

#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimeSettings {
    pub polling: RuntimePolling,
    pub update: RuntimeUpdate,
    #[serde(skip)] path: PathBuf,
}

impl RuntimeSettings {
    pub fn new() -> Self {
        RuntimeSettings::default()
    }

    pub fn load(mut self, path: &str) -> Result<Self, RuntimeSettingsError> {
        use std::fs::File;
        use std::io::Read;

        let path = Path::new(path);

        if path.exists() {
            info!("Loading runtime settings from '{}'...",
                  path.to_string_lossy());

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;
            self = RuntimeSettings::parse(&content)?;
        } else {
            debug!("Runtime settings file {} does not exists.",
                   path.to_string_lossy());
            info!("Using default runtime settings...");
        }

        self.path = path.to_path_buf();
        Ok(self)
    }

    fn parse(content: &str) -> Result<Self, RuntimeSettingsError> {
        Ok(serde_ini::from_str::<RuntimeSettings>(content)?)
    }

    pub fn save(&self) -> Result<usize, RuntimeSettingsError> {
        use std::fs::File;
        use std::io::Write;

        debug!("Saving runtime settings from '{}'...",
               &self.path.to_string_lossy());

        Ok(File::create(&self.path)?.write(self.serialize()?.as_bytes())?)
    }

    fn serialize(&self) -> Result<String, RuntimeSettingsError> {
        Ok(serde_ini::to_string(&self)?)
    }
}

#[derive(Debug)]
pub enum RuntimeSettingsError {
    Io(io::Error),
    IniDeserialize(serde_ini::de::Error),
    IniSerialize(serde_ini::ser::Error),
}

impl From<io::Error> for RuntimeSettingsError {
    fn from(err: io::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::Io(err)
    }
}

impl From<serde_ini::de::Error> for RuntimeSettingsError {
    fn from(err: serde_ini::de::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::IniDeserialize(err)
    }
}

impl From<serde_ini::ser::Error> for RuntimeSettingsError {
    fn from(err: serde_ini::ser::Error) -> RuntimeSettingsError {
        RuntimeSettingsError::IniSerialize(err)
    }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimePolling {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "LastPoll")]
    pub last: Option<DateTime<Utc>>,
    #[serde(deserialize_with = "de::duration_from_int")]
    #[serde(serialize_with = "ser::duration_to_int")]
    pub extra_interval: Duration,
    pub retries: usize,
    #[serde(rename = "ProbeASAP")]
    #[serde(deserialize_with = "de::bool_from_str")]
    #[serde(serialize_with = "ser::bool_to_string")]
    pub now: bool,
}

impl Default for RuntimePolling {
    fn default() -> Self {
        RuntimePolling { last: None,
                         extra_interval: Duration::seconds(0),
                         retries: 0,
                         now: false, }
    }
}

#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct RuntimeUpdate {
    #[serde(rename = "UpgradeToInstallation")]
    pub upgrading_to: i8,
}

impl Default for RuntimeUpdate {
    fn default() -> Self {
        RuntimeUpdate { upgrading_to: -1 }
    }
}

#[test]
fn de() {
    let ini = r"
[Polling]
LastPoll=2017-01-01T00:00:00Z
ExtraInterval=4
Retries=5
ProbeASAP=false

[Update]
UpgradeToInstallation=1
";
    let expected = RuntimeSettings { polling: RuntimePolling { last:
                                                                   Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap()),
                                                               extra_interval: Duration::seconds(4),
                                                               retries: 5,
                                                               now: false, },
                                     update: RuntimeUpdate { upgrading_to: 1 },
                                     ..Default::default() };

    assert!(serde_ini::from_str::<RuntimeSettings>(ini).map_err(|e| println!("{}", e))
                                                       .as_ref()
                                                       .ok() == Some(&expected));
    assert!(RuntimeSettings::parse(ini).as_ref().ok() == Some(&expected));
}

#[test]
fn default() {
    let settings = RuntimeSettings::new();
    let expected = RuntimeSettings { polling: RuntimePolling { last: settings.polling.last,
                                                               extra_interval: Duration::seconds(0),
                                                               retries: 0,
                                                               now: false, },
                                     update: RuntimeUpdate { upgrading_to: -1 },
                                     path: PathBuf::new(), };

    assert!(Some(settings) == Some(expected));
}

#[test]
fn ser() {
    let settings = RuntimeSettings { polling: RuntimePolling { last:
                                                                   Some("2017-01-01T00:00:00Z".parse::<DateTime<Utc>>()
                                                                                .unwrap()),
                                                               extra_interval: Duration::seconds(4),
                                                               retries: 5,
                                                               now: false, },
                                     update: RuntimeUpdate { upgrading_to: 1 },
                                     ..Default::default() };

    assert!(serde_ini::from_str(&settings.serialize().ok().unwrap()).map_err(|e| println!("{}", e))
                                                                    .ok() == Some(settings));
}

#[test]
fn load_and_save() {
    use mktemp::Temp;

    let settings_file = Temp::new_file().unwrap().to_path_buf();

    let mut settings = RuntimeSettings::new().load(settings_file.to_str().unwrap())
                                             .unwrap();

    assert_eq!(settings.polling.now, false);
    settings.polling.now = true;

    assert_eq!(settings.polling.now, true);
    settings.save()
            .expect("Failed to save the runtime settings");

    let new_settings = RuntimeSettings::new().load(settings_file.to_str().unwrap())
                                             .unwrap();

    assert_eq!(settings.update, new_settings.update);
}
<|endoftext|>


<commit_before>use std::io;
use std::mem::size_of;
use std::net::{self, SocketAddr};
use std::time::Duration;
use std::os::windows::io::FromRawSocket;
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.

use winapi::ctypes::{c_char, c_int, c_ushort};
use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
use winapi::um::winsock2::{
    self, closesocket, linger, setsockopt, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
    SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
};

use crate::sys::windows::net::{init, new_socket, socket_addr};

pub(crate) type TcpSocket = SOCKET;

pub(crate) fn new_v4_socket() -> io::Result<TcpSocket> {
    init();
    new_socket(PF_INET, SOCK_STREAM)
}

pub(crate) fn new_v6_socket() -> io::Result<TcpSocket> {
    init();
    new_socket(PF_INET6, SOCK_STREAM)
}

pub(crate) fn bind(socket: TcpSocket, addr: SocketAddr) -> io::Result<()> {
    use winsock2::bind;

    let (raw_addr, raw_addr_length) = socket_addr(&addr);
    syscall!(
        bind(socket, raw_addr, raw_addr_length),
        PartialEq::eq,
        SOCKET_ERROR
    )?;
    Ok(())
}

pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result<net::TcpStream> {
    use winsock2::connect;

    let (raw_addr, raw_addr_length) = socket_addr(&addr);

    let res = syscall!(
        connect(socket, raw_addr, raw_addr_length),
        PartialEq::eq,
        SOCKET_ERROR
    );

    match res {
        Err(err) if err.kind() != io::ErrorKind::WouldBlock => {
            Err(err)
        }
        _ => {
            Ok(unsafe { net::TcpStream::from_raw_socket(socket as StdSocket) })
        }
    }
}

pub(crate) fn listen(socket: TcpSocket, backlog: u32) -> io::Result<net::TcpListener> {
    use winsock2::listen;
    use std::convert::TryInto;

    let backlog = backlog.try_into().unwrap_or(i32::max_value());
    syscall!(listen(socket, backlog), PartialEq::eq, SOCKET_ERROR)?;
    Ok(unsafe { net::TcpListener::from_raw_socket(socket as StdSocket) })
}

pub(crate) fn close(socket: TcpSocket) {
    let _ = unsafe { closesocket(socket) };
}

pub(crate) fn set_reuseaddr(socket: TcpSocket, reuseaddr: bool) -> io::Result<()> {
    let val: BOOL = if reuseaddr { TRUE } else { FALSE };

    match unsafe { setsockopt(
        socket,
        SOL_SOCKET,
        SO_REUSEADDR,
        &val as *const _ as *const c_char,
        size_of::<BOOL>() as c_int,
    ) } {
        0 => Ok(()),
        SOCKET_ERROR => Err(io::Error::last_os_error()),
        _ => panic!("unexpected return value"),
    }
}

pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
    let val: linger = linger {
        l_onoff: if dur.is_some() { 1 } else { 0 },
        l_linger: dur.map(|dur| dur.as_secs() as c_ushort).unwrap_or_default(),
    };

    match unsafe { setsockopt(
        socket,
        SOL_SOCKET,
        SO_LINGER,
        &val as *const _ as *const c_char,
        size_of::<linger>() as c_int,
    ) } {
        0 => Ok(()),
        SOCKET_ERROR => Err(io::Error::last_os_error()),
        _ => panic!("unexpected return value"),
    }
}

pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
    // The non-blocking state of `listener` is inherited. See
    // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept#remarks.
    listener.accept()
}
<commit_msg>TcpSocket: don't panic on windows<commit_after>use std::io;
use std::mem::size_of;
use std::net::{self, SocketAddr};
use std::time::Duration;
use std::os::windows::io::FromRawSocket;
use std::os::windows::raw::SOCKET as StdSocket; // winapi uses usize, stdlib uses u32/u64.

use winapi::ctypes::{c_char, c_int, c_ushort};
use winapi::shared::minwindef::{BOOL, TRUE, FALSE};
use winapi::um::winsock2::{
    self, closesocket, linger, setsockopt, PF_INET, PF_INET6, SOCKET, SOCKET_ERROR,
    SOCK_STREAM, SOL_SOCKET, SO_LINGER, SO_REUSEADDR,
};

use crate::sys::windows::net::{init, new_socket, socket_addr};

pub(crate) type TcpSocket = SOCKET;

pub(crate) fn new_v4_socket() -> io::Result<TcpSocket> {
    init();
    new_socket(PF_INET, SOCK_STREAM)
}

pub(crate) fn new_v6_socket() -> io::Result<TcpSocket> {
    init();
    new_socket(PF_INET6, SOCK_STREAM)
}

pub(crate) fn bind(socket: TcpSocket, addr: SocketAddr) -> io::Result<()> {
    use winsock2::bind;

    let (raw_addr, raw_addr_length) = socket_addr(&addr);
    syscall!(
        bind(socket, raw_addr, raw_addr_length),
        PartialEq::eq,
        SOCKET_ERROR
    )?;
    Ok(())
}

pub(crate) fn connect(socket: TcpSocket, addr: SocketAddr) -> io::Result<net::TcpStream> {
    use winsock2::connect;

    let (raw_addr, raw_addr_length) = socket_addr(&addr);

    let res = syscall!(
        connect(socket, raw_addr, raw_addr_length),
        PartialEq::eq,
        SOCKET_ERROR
    );

    match res {
        Err(err) if err.kind() != io::ErrorKind::WouldBlock => {
            Err(err)
        }
        _ => {
            Ok(unsafe { net::TcpStream::from_raw_socket(socket as StdSocket) })
        }
    }
}

pub(crate) fn listen(socket: TcpSocket, backlog: u32) -> io::Result<net::TcpListener> {
    use winsock2::listen;
    use std::convert::TryInto;

    let backlog = backlog.try_into().unwrap_or(i32::max_value());
    syscall!(listen(socket, backlog), PartialEq::eq, SOCKET_ERROR)?;
    Ok(unsafe { net::TcpListener::from_raw_socket(socket as StdSocket) })
}

pub(crate) fn close(socket: TcpSocket) {
    let _ = unsafe { closesocket(socket) };
}

pub(crate) fn set_reuseaddr(socket: TcpSocket, reuseaddr: bool) -> io::Result<()> {
    let val: BOOL = if reuseaddr { TRUE } else { FALSE };

    match unsafe { setsockopt(
        socket,
        SOL_SOCKET,
        SO_REUSEADDR,
        &val as *const _ as *const c_char,
        size_of::<BOOL>() as c_int,
    ) } {
        SOCKET_ERROR => Err(io::Error::last_os_error()),
        _ => Ok(()),
    }
}

pub(crate) fn set_linger(socket: TcpSocket, dur: Option<Duration>) -> io::Result<()> {
    let val: linger = linger {
        l_onoff: if dur.is_some() { 1 } else { 0 },
        l_linger: dur.map(|dur| dur.as_secs() as c_ushort).unwrap_or_default(),
    };

    match unsafe { setsockopt(
        socket,
        SOL_SOCKET,
        SO_LINGER,
        &val as *const _ as *const c_char,
        size_of::<linger>() as c_int,
    ) } {
        SOCKET_ERROR => Err(io::Error::last_os_error()),
        _ => Ok(()),
    }
}

pub(crate) fn accept(listener: &net::TcpListener) -> io::Result<(net::TcpStream, SocketAddr)> {
    // The non-blocking state of `listener` is inherited. See
    // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-accept#remarks.
    listener.accept()
}
<|endoftext|>


<commit_before>use std::process::{Command, Output};
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use platform;

#[derive(Clone)]
pub struct SystemServices;

pub enum OSType {
    Redhat,
    Unknown
}

pub trait SystemInterface {
    fn file_exists(&self, path: &String) -> bool;
    fn read_file(&self, path: &String) -> Option<String>;
    fn is_package_installed(&self, package_name: &String) -> bool;
    fn install_package(&self, package: &String) -> Output;
    fn get_hostname(&self) -> Option<String>;
    fn set_hostname(&self, new_hostname: &String) -> bool;
    fn os_type(&self) -> OSType;
}

impl SystemInterface for SystemServices {
     fn file_exists(&self, path: &String) -> bool {
        let metadata = fs::metadata(path);

        match metadata {
            Ok(md) => md.is_dir() || md.is_file(),
            Err(_) => false
        }
    }

     fn read_file(&self, path: &String) -> Option<String> {
        let file_handle = File::open(path);
        let mut s = String::new();
        match file_handle {
            Ok(mut handle) => {
                handle.read_to_string(&mut s);
                Some(s)
            },
            Err(_)   => None
        }
    }

     fn is_package_installed(&self, package_name: &String) -> bool {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let command_str = format!("{} {}", platform.package_installed_command, package_name);
        let cmd_list :Vec<&str> = command_str.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());

        match Command::new(cmd_name).args(&cmd_args[..]).output() {
            Ok(output) => output.status.success(),
            Err(_)   => false
        }
    }

     fn install_package(&self, package: &String) -> Output {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let cmd_list :Vec<&str> = platform.install_command.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());
        cmd_args.push(package.to_string());

        Command::new(cmd_name)
            .args(&cmd_args[..])
            .output()
            .unwrap()
    }

     fn get_hostname(&self) -> Option<String> {
        let output = Command::new("hostname").output().unwrap();
        if output.status.success() {
            let hostname_with_newline = String::from_utf8(output.stdout).unwrap();
            Some(hostname_with_newline.replace("\n", ""))
        } else {
            None
        }
    }

     fn set_hostname(&self, new_hostname: &String) -> bool {
        let output = Command::new("hostname")
            .arg(new_hostname)
            .output()
            .unwrap();
        output.status.success()
    }

    fn os_type(&self) -> OSType {
        if self.file_exists(&"/etc/redhat-release".to_string()) ||
            self.file_exists(&"/etc/centos-release".to_string()){
                OSType::Redhat
            } else {
                OSType::Unknown
            }
    }
}
<commit_msg>Check return value of read_to_string<commit_after>use std::process::{Command, Output};
use std::fs;
use std::io::prelude::*;
use std::fs::File;
use platform;

#[derive(Clone)]
pub struct SystemServices;

pub enum OSType {
    Redhat,
    Unknown
}

pub trait SystemInterface {
    fn file_exists(&self, path: &String) -> bool;
    fn read_file(&self, path: &String) -> Option<String>;
    fn is_package_installed(&self, package_name: &String) -> bool;
    fn install_package(&self, package: &String) -> Output;
    fn get_hostname(&self) -> Option<String>;
    fn set_hostname(&self, new_hostname: &String) -> bool;
    fn os_type(&self) -> OSType;
}

impl SystemInterface for SystemServices {
     fn file_exists(&self, path: &String) -> bool {
        let metadata = fs::metadata(path);

        match metadata {
            Ok(md) => md.is_dir() || md.is_file(),
            Err(_) => false
        }
    }

     fn read_file(&self, path: &String) -> Option<String> {
        let file_handle = File::open(path);
        let mut s = String::new();
        match file_handle {
            Ok(mut handle) => {
                if handle.read_to_string(&mut s).is_ok() {
                    Some(s)
                } else {
                    None
                }
            },
            Err(_)   => None
        }
    }

     fn is_package_installed(&self, package_name: &String) -> bool {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let command_str = format!("{} {}", platform.package_installed_command, package_name);
        let cmd_list :Vec<&str> = command_str.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());

        match Command::new(cmd_name).args(&cmd_args[..]).output() {
            Ok(output) => output.status.success(),
            Err(_)   => false
        }
    }

     fn install_package(&self, package: &String) -> Output {
        let platform = platform::for_os_type(self.os_type()).unwrap();
        let cmd_list :Vec<&str> = platform.install_command.split_whitespace().collect();
        let cmd_name :String = cmd_list.first().unwrap().to_string();
        let mut cmd_args = Vec::new();
        cmd_args.extend(cmd_list.iter().skip(1).map(|s| s.to_string()).collect::<Vec<_>>());
        cmd_args.push(package.to_string());

        Command::new(cmd_name)
            .args(&cmd_args[..])
            .output()
            .unwrap()
    }

     fn get_hostname(&self) -> Option<String> {
        let output = Command::new("hostname").output().unwrap();
        if output.status.success() {
            let hostname_with_newline = String::from_utf8(output.stdout).unwrap();
            Some(hostname_with_newline.replace("\n", ""))
        } else {
            None
        }
    }

     fn set_hostname(&self, new_hostname: &String) -> bool {
        let output = Command::new("hostname")
            .arg(new_hostname)
            .output()
            .unwrap();
        output.status.success()
    }

    fn os_type(&self) -> OSType {
        if self.file_exists(&"/etc/redhat-release".to_string()) ||
            self.file_exists(&"/etc/centos-release".to_string()){
                OSType::Redhat
            } else {
                OSType::Unknown
            }
    }
}
<|endoftext|>


<commit_before>extern crate cgmath;
extern crate clap;
extern crate collision;
extern crate fnv;
extern crate image;
extern crate point_viewer;
extern crate protobuf;
extern crate quadtree;
extern crate scoped_pool;
extern crate xray;

use cgmath::{Point2, Point3};
use collision::{Aabb, Aabb3};
use fnv::{FnvHashMap, FnvHashSet};
use image::GenericImage;
use octree::OnDiskOctree;
use point_viewer::{octree, InternalIterator};
use protobuf::Message;
use quadtree::{ChildIndex, Node, NodeId, Rect};
use scoped_pool::Pool;
use std::collections::hash_map::Entry;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use xray::{proto, CURRENT_VERSION};

fn parse_arguments() -> clap::ArgMatches<'static> {
    clap::App::new("build_xray_quadtree")
        .version("1.0")
        .author("Holger H. Rapp <hrapp@lyft.com>")
        .args(&[
            clap::Arg::with_name("output_directory")
                .help("Output directory to write the X-Ray quadtree into.")
                .long("output_directory")
                .required(true)
                .takes_value(true),
            clap::Arg::with_name("resolution")
                .help("Size of 1px in meters on the finest X-Ray level.")
                .long("resolution")
                .default_value("0.01"),
            clap::Arg::with_name("tile_size")
                .help("Size of finest X-Ray level tile in pixels. Must be a power of two.")
                .long("tile_size")
                .default_value("256"),
            clap::Arg::with_name("octree_directory")
                .help("Octree directory to turn into xrays.")
                .index(1)
                .required(true),
        ])
        .get_matches()
}

fn xray_from_points(
    octree: &octree::OnDiskOctree,
    bbox: &Aabb3<f32>,
    png_file: &Path,
    image_size: u32,
) -> bool {
    const NUM_Z_BUCKETS: f32 = 1024.;

    let mut aggregation: FnvHashMap<(u32, u32), FnvHashSet<u32>> = FnvHashMap::default();
    let mut seen_any_points = false;
    octree.points_in_box(&bbox).for_each(|p| {
        seen_any_points = true;
        let x = (((p.position.x - bbox.min().x) / bbox.dim().x) * image_size as f32) as u32;
        let y = (((p.position.y - bbox.min().y) / bbox.dim().y) * image_size as f32) as u32;
        let z = (((p.position.z - bbox.min().z) / bbox.dim().z) * NUM_Z_BUCKETS) as u32;
        match aggregation.entry((x, y)) {
            Entry::Occupied(mut e) => {
                e.get_mut().insert(z);
            }
            Entry::Vacant(v) => {
                let mut s = FnvHashSet::default();
                s.insert(z);
                v.insert(s);
            }
        }
    });

    if !seen_any_points {
        return false;
    }

    let max_saturation = NUM_Z_BUCKETS.ln();
    let mut image = image::RgbImage::new(image_size, image_size);
    for x in 0..image_size {
        for y in 0..image_size {
            if !aggregation.contains_key(&(x, y)) {
                image.put_pixel(
                    x,
                    y,
                    image::Rgb {
                        data: [255, 255, 255],
                    },
                );
                continue;
            }
            let saturation = (aggregation[&(x, y)].len() as f32).ln() / max_saturation;
            let value = ((1. - saturation) * 255.) as u8;
            image.put_pixel(
                x,
                y,
                image::Rgb {
                    data: [value, value, value],
                },
            );
        }
    }
    image.save(png_file).unwrap();
    true
}

fn find_quadtree_bounding_rect_and_levels(bbox: &Aabb3<f32>, tile_size_m: f32) -> (Rect, u8) {
    let mut levels = 0;
    let mut cur_size = tile_size_m;
    while cur_size < bbox.dim().x || cur_size < bbox.dim().y {
        cur_size *= 2.;
        levels += 1;
    }
    (
        Rect::new(Point2::new(bbox.min().x, bbox.min().y), cur_size),
        levels,
    )
}

pub fn get_image_path(directory: &Path, id: NodeId) -> PathBuf {
    let mut rv = directory.join(&id.to_string());
    rv.set_extension("png");
    rv
}

fn run(
    octree_directory: &Path,
    output_directory: &Path,
    resolution: f32,
    tile_size_px: u32,
) -> Result<(), Box<Error>> {
    let octree = &OnDiskOctree::new(octree_directory)?;

    // Ignore errors, maybe directory is already there.
    let _ = fs::create_dir(output_directory);

    let bounding_box = octree.bounding_box();

    let (bounding_rect, deepest_level) =
        find_quadtree_bounding_rect_and_levels(&bounding_box, tile_size_px as f32 * resolution);

    let pool = Pool::new(10);

    // Create the deepest level of the quadtree.
    let (parents_to_create_tx, mut parents_to_create_rx) = mpsc::channel();
    let (all_nodes_tx, all_nodes_rx) = mpsc::channel();
    println!("Building level {}.", deepest_level);
    pool.scoped(|scope| {
        let mut open = vec![Node::root_with_bounding_rect(bounding_rect.clone())];
        while !open.is_empty() {
            let node = open.pop().unwrap();
            if node.level() == deepest_level {
                let parents_to_create_tx_clone = parents_to_create_tx.clone();
                let all_nodes_tx_clone = all_nodes_tx.clone();
                scope.execute(move || {
                    let bbox = Aabb3::new(
                        Point3::new(
                            node.bounding_rect.min().x,
                            node.bounding_rect.min().y,
                            bounding_box.min().z,
                        ),
                        Point3::new(
                            node.bounding_rect.max().x,
                            node.bounding_rect.max().y,
                            bounding_box.max().z,
                        ),
                    );
                    if xray_from_points(
                        octree,
                        &bbox,
                        &get_image_path(output_directory, node.id),
                        tile_size_px,
                    ) {
                        all_nodes_tx_clone.send(node.id).unwrap();
                        node.id
                            .parent_id()
                            .map(|id| parents_to_create_tx_clone.send(id).unwrap());
                    }
                });
            } else {
                for i in 0..4 {
                    open.push(node.get_child(ChildIndex::from_u8(i)));
                }
            }
        }
    });
    drop(parents_to_create_tx);

    for current_level in (0..deepest_level).rev() {
        println!("Building level {}.", current_level);
        let nodes_to_create: FnvHashSet<NodeId> = parents_to_create_rx.into_iter().collect();
        let (parents_to_create_tx, new_rx) = mpsc::channel();
        parents_to_create_rx = new_rx;
        pool.scoped(|scope| {
            for node_id in nodes_to_create {
                all_nodes_tx.send(node_id).unwrap();
                let tx_clone = parents_to_create_tx.clone();
                scope.execute(move || {
                    let mut large_image = image::RgbImage::from_pixel(
                        tile_size_px * 2,
                        tile_size_px * 2,
                        image::Rgb {
                            data: [255, 255, 255],
                        },
                    );

                    for &(id, xoffs, yoffs) in &[
                        (0, 0, 0),
                        (1, 0, tile_size_px),
                        (2, tile_size_px, 0),
                        (3, tile_size_px, tile_size_px),
                    ] {
                        let png = get_image_path(
                            output_directory,
                            node_id.get_child_id(ChildIndex::from_u8(id)),
                        );
                        if !png.exists() {
                            continue;
                        }
                        let img = image::open(&png).unwrap().to_rgb();
                        large_image.copy_from(&img, xoffs, yoffs);
                    }
                    let image = image::DynamicImage::ImageRgb8(large_image).resize(
                        tile_size_px,
                        tile_size_px,
                        image::FilterType::Lanczos3,
                    );
                    image
                        .as_rgb8()
                        .unwrap()
                        .save(&get_image_path(output_directory, node_id))
                        .unwrap();
                    node_id.parent_id().map(|id| tx_clone.send(id).unwrap());
                });
            }
        });
        drop(parents_to_create_tx);
    }
    drop(all_nodes_tx);

    let meta = {
        let mut meta = proto::Meta::new();
        meta.mut_bounding_rect()
            .mut_min()
            .set_x(bounding_rect.min().x);
        meta.mut_bounding_rect()
            .mut_min()
            .set_y(bounding_rect.min().y);
        meta.mut_bounding_rect()
            .set_edge_length(bounding_rect.edge_length());
        meta.set_deepest_level(deepest_level as u32);
        meta.set_tile_size(tile_size_px);
        meta.set_version(CURRENT_VERSION);

        for node_id in all_nodes_rx {
            let mut proto = proto::NodeId::new();
            proto.set_index(node_id.index());
            proto.set_level(node_id.level() as u32);
            meta.mut_nodes().push(proto);
        }
        meta
    };

    let mut buf_writer = BufWriter::new(File::create(output_directory.join("meta.pb")).unwrap());
    meta.write_to_writer(&mut buf_writer).unwrap();

    Ok(())
}

pub fn main() {
    let args = parse_arguments();
    let resolution = args.value_of("resolution")
        .unwrap()
        .parse::<f32>()
        .expect("resolution could not be parsed.");
    let tile_size = args.value_of("tile_size")
        .unwrap()
        .parse::<u32>()
        .expect("tile_size could not be parsed.");
    if !tile_size.is_power_of_two() {
        panic!("tile_size is not a power of two.");
    }

    let octree_directory = Path::new(args.value_of("octree_directory").unwrap());
    let output_directory = Path::new(args.value_of("output_directory").unwrap());

    run(octree_directory, output_directory, resolution, tile_size).unwrap();
}
<commit_msg>Refactor to enable more than one way of creating tiles from points. (#128)<commit_after>extern crate cgmath;
extern crate clap;
extern crate collision;
extern crate fnv;
extern crate image;
extern crate point_viewer;
extern crate protobuf;
extern crate quadtree;
extern crate scoped_pool;
extern crate xray;

use cgmath::{Point2, Point3};
use collision::{Aabb, Aabb3};
use fnv::{FnvHashMap, FnvHashSet};
use image::GenericImage;
use octree::OnDiskOctree;
use point_viewer::{octree, InternalIterator, color::Color};
use protobuf::Message;
use quadtree::{ChildIndex, Node, NodeId, Rect};
use scoped_pool::Pool;
use std::collections::hash_map::Entry;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io::BufWriter;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use xray::{proto, CURRENT_VERSION};

// The number of Z-buckets we subdivide our bounding cube into along the z-direction. This affects
// the saturation of a point in x-rays: the more buckets contain a point, the darker the pixel
// becomes.
const NUM_Z_BUCKETS: f32 = 1024.;

fn parse_arguments() -> clap::ArgMatches<'static> {
    clap::App::new("build_xray_quadtree")
        .version("1.0")
        .author("Holger H. Rapp <hrapp@lyft.com>")
        .args(&[
            clap::Arg::with_name("output_directory")
                .help("Output directory to write the X-Ray quadtree into.")
                .long("output_directory")
                .required(true)
                .takes_value(true),
            clap::Arg::with_name("resolution")
                .help("Size of 1px in meters on the finest X-Ray level.")
                .long("resolution")
                .default_value("0.01"),
            clap::Arg::with_name("tile_size")
                .help("Size of finest X-Ray level tile in pixels. Must be a power of two.")
                .long("tile_size")
                .default_value("256"),
            clap::Arg::with_name("octree_directory")
                .help("Octree directory to turn into xrays.")
                .index(1)
                .required(true),
        ])
        .get_matches()
}

trait ColoringStrategy: Send {
    // Processes a point that has been discretized into the pixel (x, y) and the z column according
    // to NUM_Z_BUCKETS.
    fn process_discretized_point(&mut self, x: u32, y: u32, z: u32);

    // After all points are processed, this is used to query the color that should be assigned to
    // the pixel (x, y) in the final tile image.
    fn get_pixel_color(&self, x: u32, y: u32) -> Color<u8>;
}

struct XRayColoringStrategy {
    z_buckets: FnvHashMap<(u32, u32), FnvHashSet<u32>>,
    max_saturation: f32,
}

impl XRayColoringStrategy {
    fn new() -> Self {
        XRayColoringStrategy {
            z_buckets: FnvHashMap::default(),
            // TODO(sirver): Once 'const fn' lands, this constant can be calculated at compile time.
            max_saturation: NUM_Z_BUCKETS.ln(),
        }
    }
}

impl ColoringStrategy for XRayColoringStrategy {
    fn process_discretized_point(&mut self, x: u32, y: u32, z: u32) {
        match self.z_buckets.entry((x, y)) {
            Entry::Occupied(mut e) => {
                e.get_mut().insert(z);
            }
            Entry::Vacant(v) => {
                let mut s = FnvHashSet::default();
                s.insert(z);
                v.insert(s);
            }
        }
    }

    fn get_pixel_color(&self, x: u32, y: u32) -> Color<u8> {
        if !self.z_buckets.contains_key(&(x, y)) {
            return Color {
                red: 255,
                green: 255,
                blue: 255,
                alpha: 255,
            };
        }
        let saturation = (self.z_buckets[&(x, y)].len() as f32).ln() / self.max_saturation;
        let value = ((1. - saturation) * 255.) as u8;
        Color {
            red: value,
            green: value,
            blue: value,
            alpha: value,
        }
    }
}

fn xray_from_points(
    octree: &octree::OnDiskOctree,
    bbox: &Aabb3<f32>,
    png_file: &Path,
    image_size: u32,
    mut coloring_strategy: Box<ColoringStrategy>,
) -> bool {
    let mut seen_any_points = false;
    octree.points_in_box(&bbox).for_each(|p| {
        seen_any_points = true;
        let x = (((p.position.x - bbox.min().x) / bbox.dim().x) * image_size as f32) as u32;
        let y = (((p.position.y - bbox.min().y) / bbox.dim().y) * image_size as f32) as u32;
        let z = (((p.position.z - bbox.min().z) / bbox.dim().z) * NUM_Z_BUCKETS) as u32;
        coloring_strategy.process_discretized_point(x, y, z);
    });

    if !seen_any_points {
        return false;
    }

    let mut image = image::RgbImage::new(image_size, image_size);
    for x in 0..image_size {
        for y in 0..image_size {
            let color = coloring_strategy.get_pixel_color(x, y);
            image.put_pixel(
                x,
                y,
                image::Rgb {
                    data: [color.red, color.green, color.blue],
                },
            );
        }
    }
    image.save(png_file).unwrap();
    true
}

fn find_quadtree_bounding_rect_and_levels(bbox: &Aabb3<f32>, tile_size_m: f32) -> (Rect, u8) {
    let mut levels = 0;
    let mut cur_size = tile_size_m;
    while cur_size < bbox.dim().x || cur_size < bbox.dim().y {
        cur_size *= 2.;
        levels += 1;
    }
    (
        Rect::new(Point2::new(bbox.min().x, bbox.min().y), cur_size),
        levels,
    )
}

pub fn get_image_path(directory: &Path, id: NodeId) -> PathBuf {
    let mut rv = directory.join(&id.to_string());
    rv.set_extension("png");
    rv
}

fn run(
    octree_directory: &Path,
    output_directory: &Path,
    resolution: f32,
    tile_size_px: u32,
) -> Result<(), Box<Error>> {
    let octree = &OnDiskOctree::new(octree_directory)?;

    // Ignore errors, maybe directory is already there.
    let _ = fs::create_dir(output_directory);

    let bounding_box = octree.bounding_box();

    let (bounding_rect, deepest_level) =
        find_quadtree_bounding_rect_and_levels(&bounding_box, tile_size_px as f32 * resolution);

    let pool = Pool::new(10);

    // Create the deepest level of the quadtree.
    let (parents_to_create_tx, mut parents_to_create_rx) = mpsc::channel();
    let (all_nodes_tx, all_nodes_rx) = mpsc::channel();
    println!("Building level {}.", deepest_level);

    let strategy_constructor = &|| XRayColoringStrategy::new();
    pool.scoped(|scope| {
        let mut open = vec![Node::root_with_bounding_rect(bounding_rect.clone())];
        while !open.is_empty() {
            let node = open.pop().unwrap();
            if node.level() == deepest_level {
                let parents_to_create_tx_clone = parents_to_create_tx.clone();
                let all_nodes_tx_clone = all_nodes_tx.clone();
                scope.execute(move || {
                    let bbox = Aabb3::new(
                        Point3::new(
                            node.bounding_rect.min().x,
                            node.bounding_rect.min().y,
                            bounding_box.min().z,
                        ),
                        Point3::new(
                            node.bounding_rect.max().x,
                            node.bounding_rect.max().y,
                            bounding_box.max().z,
                        ),
                    );
                    if xray_from_points(
                        octree,
                        &bbox,
                        &get_image_path(output_directory, node.id),
                        tile_size_px,
                        Box::new(strategy_constructor()),
                    ) {
                        all_nodes_tx_clone.send(node.id).unwrap();
                        node.id
                            .parent_id()
                            .map(|id| parents_to_create_tx_clone.send(id).unwrap());
                    }
                });
            } else {
                for i in 0..4 {
                    open.push(node.get_child(ChildIndex::from_u8(i)));
                }
            }
        }
    });
    drop(parents_to_create_tx);

    for current_level in (0..deepest_level).rev() {
        println!("Building level {}.", current_level);
        let nodes_to_create: FnvHashSet<NodeId> = parents_to_create_rx.into_iter().collect();
        let (parents_to_create_tx, new_rx) = mpsc::channel();
        parents_to_create_rx = new_rx;
        pool.scoped(|scope| {
            for node_id in nodes_to_create {
                all_nodes_tx.send(node_id).unwrap();
                let tx_clone = parents_to_create_tx.clone();
                scope.execute(move || {
                    let mut large_image = image::RgbImage::from_pixel(
                        tile_size_px * 2,
                        tile_size_px * 2,
                        image::Rgb {
                            data: [255, 255, 255],
                        },
                    );

                    for &(id, xoffs, yoffs) in &[
                        (0, 0, 0),
                        (1, 0, tile_size_px),
                        (2, tile_size_px, 0),
                        (3, tile_size_px, tile_size_px),
                    ] {
                        let png = get_image_path(
                            output_directory,
                            node_id.get_child_id(ChildIndex::from_u8(id)),
                        );
                        if !png.exists() {
                            continue;
                        }
                        let img = image::open(&png).unwrap().to_rgb();
                        large_image.copy_from(&img, xoffs, yoffs);
                    }
                    let image = image::DynamicImage::ImageRgb8(large_image).resize(
                        tile_size_px,
                        tile_size_px,
                        image::FilterType::Lanczos3,
                    );
                    image
                        .as_rgb8()
                        .unwrap()
                        .save(&get_image_path(output_directory, node_id))
                        .unwrap();
                    node_id.parent_id().map(|id| tx_clone.send(id).unwrap());
                });
            }
        });
        drop(parents_to_create_tx);
    }
    drop(all_nodes_tx);

    let meta = {
        let mut meta = proto::Meta::new();
        meta.mut_bounding_rect()
            .mut_min()
            .set_x(bounding_rect.min().x);
        meta.mut_bounding_rect()
            .mut_min()
            .set_y(bounding_rect.min().y);
        meta.mut_bounding_rect()
            .set_edge_length(bounding_rect.edge_length());
        meta.set_deepest_level(deepest_level as u32);
        meta.set_tile_size(tile_size_px);
        meta.set_version(CURRENT_VERSION);

        for node_id in all_nodes_rx {
            let mut proto = proto::NodeId::new();
            proto.set_index(node_id.index());
            proto.set_level(node_id.level() as u32);
            meta.mut_nodes().push(proto);
        }
        meta
    };

    let mut buf_writer = BufWriter::new(File::create(output_directory.join("meta.pb")).unwrap());
    meta.write_to_writer(&mut buf_writer).unwrap();

    Ok(())
}

pub fn main() {
    let args = parse_arguments();
    let resolution = args.value_of("resolution")
        .unwrap()
        .parse::<f32>()
        .expect("resolution could not be parsed.");
    let tile_size = args.value_of("tile_size")
        .unwrap()
        .parse::<u32>()
        .expect("tile_size could not be parsed.");
    if !tile_size.is_power_of_two() {
        panic!("tile_size is not a power of two.");
    }

    let octree_directory = Path::new(args.value_of("octree_directory").unwrap());
    let output_directory = Path::new(args.value_of("output_directory").unwrap());

    run(octree_directory, output_directory, resolution, tile_size).unwrap();
}
<|endoftext|>


<commit_before>use chrono::prelude::*;
use core::option::Option;
use core::option::Option::{None, Some};
use core::time::Duration;
use itertools::Itertools;
use tui::style::Style;
use tui::symbols;
use tui::widgets::{Dataset, GraphType, Paragraph};

pub struct PlotData {
    pub display: String,
    pub data: Vec<(f64, f64)>,
    pub style: Style,
    buffer: chrono::Duration,
    simple_graphics: bool,
}

impl PlotData {
    pub fn new(display: String, buffer: u64, style: Style, simple_graphics: bool) -> PlotData {
        PlotData {
            display,
            data: Vec::with_capacity(150), // ringbuffer::FixedRingBuffer::new(capacity),
            style,
            buffer: chrono::Duration::seconds(buffer as i64),
            simple_graphics,
        }
    }
    pub fn update(&mut self, item: Option<Duration>) {
        let now = Local::now();
        let idx = now.timestamp_millis() as f64 / 1_000f64;
        match item {
            Some(dur) => self.data.push((idx, dur.as_micros() as f64)),
            None => (), // self.data.push((idx, f64::NAN)),
        }
        // Find the last index that we should remove.
        let earliest_timestamp = (now - self.buffer).timestamp_millis() as f64 / 1_000f64;
        let last_idx = self
            .data
            .iter()
            .enumerate()
            .filter(|(_, (timestamp, _))| *timestamp < earliest_timestamp)
            .map(|(idx, _)| idx)
            .last();
        if let Some(idx) = last_idx {
            self.data.drain(0..idx).for_each(drop)
        }
    }

    pub fn header_stats(&self) -> Vec<Paragraph> {
        let ping_header = Paragraph::new(self.display.clone()).style(self.style);
        let items: Vec<&f64> = self
            .data
            .iter()
            .filter(|(_, x)| !x.is_nan())
            .sorted_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
            .map(|(_, v)| v)
            .collect();
        if items.is_empty() {
            return vec![ping_header];
        }

        let min = **items.first().unwrap();
        let max = **items.last().unwrap();
        let avg = items.iter().fold(0f64, |sum, &item| sum + item) / items.len() as f64;
        let jtr = items.iter().enumerate().fold(0f64, |sum, (idx, &item)| sum
            + (*items.get(idx + 1).unwrap_or(&item) - item).abs())
            / (items.len() - 1) as f64;

        let percentile_position = 0.95 * items.len() as f32;
        let rounded_position = percentile_position.round() as usize;
        let p95 = items.get(rounded_position).map(|i| **i).unwrap_or(0f64);

        // count timeouts
        let to = self.data.iter().filter(|(_, x)| x.is_nan()).count();

        vec![
            ping_header,
            Paragraph::new(format!("min {:?}", Duration::from_micros(min as u64)))
                .style(self.style),
            Paragraph::new(format!("max {:?}", Duration::from_micros(max as u64)))
                .style(self.style),
            Paragraph::new(format!("avg {:?}", Duration::from_micros(avg as u64)))
                .style(self.style),
            Paragraph::new(format!("jtr {:?}", Duration::from_micros(jtr as u64)))
                .style(self.style),
            Paragraph::new(format!("p95 {:?}", Duration::from_micros(p95 as u64)))
                .style(self.style),
            Paragraph::new(format!("t/o {:?}", to)).style(self.style),
        ]
    }
}

impl<'a> Into<Dataset<'a>> for &'a PlotData {
    fn into(self) -> Dataset<'a> {
        let slice = self.data.as_slice();
        Dataset::default()
            .marker(if self.simple_graphics {
                symbols::Marker::Dot
            } else {
                symbols::Marker::Braille
            })
            .style(self.style)
            .graph_type(GraphType::Line)
            .data(slice)
        // .x_axis_bounds([self.window_min, self.window_max])
    }
}
<commit_msg>Restore showing timeout as NaN (#152)<commit_after>use chrono::prelude::*;
use core::option::Option;
use core::option::Option::{None, Some};
use core::time::Duration;
use itertools::Itertools;
use tui::style::Style;
use tui::symbols;
use tui::widgets::{Dataset, GraphType, Paragraph};

pub struct PlotData {
    pub display: String,
    pub data: Vec<(f64, f64)>,
    pub style: Style,
    buffer: chrono::Duration,
    simple_graphics: bool,
}

impl PlotData {
    pub fn new(display: String, buffer: u64, style: Style, simple_graphics: bool) -> PlotData {
        PlotData {
            display,
            data: Vec::with_capacity(150), // ringbuffer::FixedRingBuffer::new(capacity),
            style,
            buffer: chrono::Duration::seconds(buffer as i64),
            simple_graphics,
        }
    }
    pub fn update(&mut self, item: Option<Duration>) {
        let now = Local::now();
        let idx = now.timestamp_millis() as f64 / 1_000f64;
        match item {
            Some(dur) => self.data.push((idx, dur.as_micros() as f64)),
            None => self.data.push((idx, f64::NAN)),
        }
        // Find the last index that we should remove.
        let earliest_timestamp = (now - self.buffer).timestamp_millis() as f64 / 1_000f64;
        let last_idx = self
            .data
            .iter()
            .enumerate()
            .filter(|(_, (timestamp, _))| *timestamp < earliest_timestamp)
            .map(|(idx, _)| idx)
            .last();
        if let Some(idx) = last_idx {
            self.data.drain(0..idx).for_each(drop)
        }
    }

    pub fn header_stats(&self) -> Vec<Paragraph> {
        let ping_header = Paragraph::new(self.display.clone()).style(self.style);
        let items: Vec<&f64> = self
            .data
            .iter()
            .filter(|(_, x)| !x.is_nan())
            .sorted_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap())
            .map(|(_, v)| v)
            .collect();
        if items.is_empty() {
            return vec![ping_header];
        }

        let min = **items.first().unwrap();
        let max = **items.last().unwrap();
        let avg = items.iter().fold(0f64, |sum, &item| sum + item) / items.len() as f64;
        let jtr = items.iter().enumerate().fold(0f64, |sum, (idx, &item)| sum
            + (*items.get(idx + 1).unwrap_or(&item) - item).abs())
            / (items.len() - 1) as f64;

        let percentile_position = 0.95 * items.len() as f32;
        let rounded_position = percentile_position.round() as usize;
        let p95 = items.get(rounded_position).map(|i| **i).unwrap_or(0f64);

        // count timeouts
        let to = self.data.iter().filter(|(_, x)| x.is_nan()).count();

        vec![
            ping_header,
            Paragraph::new(format!("min {:?}", Duration::from_micros(min as u64)))
                .style(self.style),
            Paragraph::new(format!("max {:?}", Duration::from_micros(max as u64)))
                .style(self.style),
            Paragraph::new(format!("avg {:?}", Duration::from_micros(avg as u64)))
                .style(self.style),
            Paragraph::new(format!("jtr {:?}", Duration::from_micros(jtr as u64)))
                .style(self.style),
            Paragraph::new(format!("p95 {:?}", Duration::from_micros(p95 as u64)))
                .style(self.style),
            Paragraph::new(format!("t/o {:?}", to)).style(self.style),
        ]
    }
}

impl<'a> Into<Dataset<'a>> for &'a PlotData {
    fn into(self) -> Dataset<'a> {
        let slice = self.data.as_slice();
        Dataset::default()
            .marker(if self.simple_graphics {
                symbols::Marker::Dot
            } else {
                symbols::Marker::Braille
            })
            .style(self.style)
            .graph_type(GraphType::Line)
            .data(slice)
        // .x_axis_bounds([self.window_min, self.window_max])
    }
}
<|endoftext|>


<commit_before>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::analysis::table::Table;

    // Fix these tests, they are broken
    // #[test]
    // fn find_known_local_variable_without_parent<'a>() {
    //     let mut table = Table::new(None);

    //     table.insert(&"example".to_string(), Expression::Boolean(true));

    //     assert_eq!(Some(&Expression::Boolean(true)), table.get(&"example".to_string()));
    // }

    // #[test]
    // fn find_known_local_variable_with_parent() {
    //     let mut table = Table::new(Some(Box::new(&Table::new(None))));

    //     table.insert(&"example".to_string(), Expression::Boolean(true));

    //     assert_eq!(Some(&Expression::Boolean(true)), table.get(&"example".to_string()));
    // }

    // #[test]
    // fn find_unknown_local_variable_without_parent() {
    //     let table = Table::<Expression>::new(None);

    //     assert_eq!(None, table.get(&"Example".to_string()));
    // }

    // #[test]
    // fn find_unknown_local_variable_with_parent() {
    //     let parent = Box::new(Table::new(None));

    //     let table = Table::<Expression>::new(Some(parent));

    //     assert_eq!(None, table.get(&"example".to_string()));
    // }
}
<commit_msg>Fix table tests<commit_after>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::table::Table;
    use robin_core::ast::Expression;

    #[test]
    fn find_known_local_variable_without_parent() {
        let mut table = Table::new(None);

        table.insert("example".to_string(), Expression::Boolean(true));

        assert_eq!(Some(&Expression::Boolean(true)), table.get(&"example".to_string()));
    }

    #[test]
    fn find_known_local_variable_with_parent() {
        let parent = Table::new(None);

        let mut table = Table::new(Some(Box::new(&parent)));

        table.insert("example".to_string(), Expression::Boolean(true));

        assert_eq!(Some(&Expression::Boolean(true)), table.get(&"example".to_string()));
    }

    #[test]
    fn find_unknown_local_variable_without_parent() {
        let table = Table::<Expression>::new(None);

        assert_eq!(None, table.get(&"example".to_string()));
    }

    #[test]
    fn find_unknown_local_variable_with_parent() {
        let parent = Table::new(None);

        let table = Table::<Expression>::new(Some(Box::new(&parent)));

        assert_eq!(None, table.get(&"example".to_string()));
    }
}
<|endoftext|>


<commit_before><commit_msg>chore(Schemas): Linting<commit_after><|endoftext|>