<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path =
        env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    let target = env::var("TARGET").unwrap();
    let arch = if target.contains("arm") {
        "arch-arm"
    } else if target.contains("aarch64") {
        "arch-arm64"
    } else if target.contains("x86") || target.contains("i686") {
        "arch-x86"
    } else if target.contains("mips") {
        "arch-mips"
    } else {
        panic!("Invalid target architecture {}", target);
    };

    let platform = if target.contains("aarch64") {
        "android-21"
    } else {
        "android-18"
    };

    // compiling android_native_app_glue.c
    let c_file = ndk_path
        .join("sources")
        .join("android")
        .join("native_app_glue")
        .join("android_native_app_glue.c");
    let sysroot = ndk_path.join("platforms").join(platform).join(arch);
    cc::Build::new()
        .file(c_file)
        .flag("--sysroot")
        .flag(sysroot.to_str().unwrap())
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir =
        env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");
}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<commit_msg>Remove unnecessary sysroot and platform configuration from build script.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate cc;
extern crate gl_generator;

use gl_generator::{Api, Fallbacks, Profile, Registry};
use std::env;
use std::fs::File;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target.contains("android") {
        android_main()
    }
    generate_gl_bindings(&target);
}

fn android_main() {
    // Get the NDK path from NDK_HOME env.
    let ndk_path =
        env::var_os("ANDROID_NDK").expect("Please set the ANDROID_NDK environment variable");
    let ndk_path = Path::new(&ndk_path);

    // compiling android_native_app_glue.c
    let c_file = ndk_path
        .join("sources")
        .join("android")
        .join("native_app_glue")
        .join("android_native_app_glue.c");
    cc::Build::new()
        .file(c_file)
        .warnings(false)
        .compile("android_native_app_glue");

    // Get the output directory.
    let out_dir =
        env::var("OUT_DIR").expect("Cargo should have set the OUT_DIR environment variable");

    println!("cargo:rustc-link-lib=static=android_native_app_glue");
    println!("cargo:rustc-link-search=native={}", out_dir);
    println!("cargo:rustc-link-lib=log");
    println!("cargo:rustc-link-lib=android");
}

fn generate_gl_bindings(target: &str) {
    // For now, we only support EGL, and only on Windows and Android.
    if target.contains("android") || target.contains("windows") {
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("egl_bindings.rs")).unwrap();
        if target.contains("android") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StaticStructGenerator, &mut file)
                .unwrap();
        }
        if target.contains("windows") {
            Registry::new(Api::Egl, (1, 5), Profile::Core, Fallbacks::All, [])
                .write_bindings(gl_generator::StructGenerator, &mut file)
                .unwrap();
        };
    }
}
<|endoftext|>


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

use crate::stats::Simple;
use logger::*;
use metrics::{Output, Percentile, Reading};
use std::net::SocketAddr;
use tiny_http::{Method, Response, Server};

pub struct Http {
    recorder: Simple,
    server: Server,
    snapshot: Vec<Reading>,
    refreshed: u64,
}

impl Http {
    pub fn new(address: SocketAddr, recorder: &Simple) -> Self {
        let server = tiny_http::Server::http(address);
        if server.is_err() {
            fatal!("Failed to open {} for HTTP Stats listener", address);
        }
        Self {
            recorder: recorder.clone(),
            server: server.unwrap(),
            snapshot: Vec::new(),
            refreshed: 0,
        }
    }

    pub fn run(&mut self) {
        let now = time::precise_time_ns();
        if now - self.refreshed > 500_000_000 {
            self.snapshot = self.recorder.readings();
            self.refreshed = time::precise_time_ns();
        }
        if let Ok(Some(request)) = self.server.try_recv() {
            match request.method() {
                Method::Get => match request.url() {
                    "/" => {
                        debug!("Serving GET on index");
                        let _ = request.respond(Response::from_string(format!(
                            "Welcome to rpc-perf\nVersion: {}",
                            crate::config::VERSION
                        )));
                    }
                    "/metrics.json" | "/vars.json" | "/admin/metrics.json" => {
                        debug!("Serving human readable stats on /vars");
                        let _ = request.respond(Response::from_string(self.json(false)));
                    }
                    "/vars" => {
                        debug!("Serving human readable stats on /vars");
                        let _ = request.respond(Response::from_string(self.human()));
                    }
                    url => {
                        debug!("GET on non-existent url: {}", url);
                        let _ = request.respond(Response::empty(404));
                    }
                },
                method => {
                    error!("unsupported request method: {}", method);
                    let _ = request.respond(Response::empty(404));
                }
            }
        }
        std::thread::sleep(std::time::Duration::from_millis(1));
    }

    pub fn human(&self) -> String {
        let mut data = Vec::new();
        for reading in &self.snapshot {
            let label = reading.label();
            let output = reading.output();
            let value = reading.value();
            match output {
                Output::Counter => {
                    data.push(format!("{}/count: {}", label, value));
                }
                Output::Percentile(percentile) => match percentile {
                    Percentile::Minimum => {
                        data.push(format!("{}/minimum/value: {}", label, value));
                    }
                    Percentile::Maximum => {
                        data.push(format!("{}/maximum/value: {}", label, value));
                    }
                    _ => {
                        data.push(format!("{}/histogram/{}: {}", label, percentile, value));
                    }
                },
                Output::MaxPointTime => {
                    // we have point's ns since X and current timespec and current ns sinc X
                    let point_ns = value;
                    let now_timespec = time::get_time();
                    let now_ns = time::precise_time_ns();

                    // find the number of NS in the past for point
                    let delta_ns = now_ns as usize - point_ns;
                    let point_timespec =
                        now_timespec - time::Duration::nanoseconds(delta_ns as i64);

                    // convert to UTC
                    let point_utc = time::at_utc(point_timespec);
                    // calculate offset from the top of the minute
                    let offset = point_utc.tm_sec as u64 * 1_000_000_000 + point_utc.tm_nsec as u64;
                    let offset_ms = (offset as f64 / 1_000_000.0).floor() as usize;
                    data.push(format!("{}/maximum/offset_ms: {}", label, offset_ms));
                }
                _ => {
                    continue;
                }
            }
        }
        data.sort();
        let mut content = data.join("\n");
        content += "\n";
        content
    }

    fn json(&self, pretty: bool) -> String {
        let mut head = "{".to_owned();
        if pretty {
            head += "\n  ";
        }
        let mut data = Vec::new();
        for reading in &self.snapshot {
            let label = reading.label();
            let output = reading.output();
            let value = reading.value();
            match output {
                Output::Counter => {
                    data.push(format!("\"{}/count\": {}", label, value));
                }
                Output::Percentile(percentile) => match percentile {
                    Percentile::Minimum => {
                        data.push(format!("\"{}/minimum/value\": {}", label, value));
                    }
                    Percentile::Maximum => {
                        data.push(format!("\"{}/maximum/value\": {}", label, value));
                    }
                    _ => {
                        data.push(format!("\"{}/histogram/{}\": {}", label, percentile, value));
                    }
                },
                Output::MaxPointTime => {
                    // we have point's ns since X and current timespec and current ns sinc X
                    let point_ns = value;
                    let now_timespec = time::get_time();
                    let now_ns = time::precise_time_ns();

                    // find the number of NS in the past for point
                    let delta_ns = now_ns as usize - point_ns;
                    let point_timespec =
                        now_timespec - time::Duration::nanoseconds(delta_ns as i64);

                    // convert to UTC
                    let point_utc = time::at_utc(point_timespec);
                    // calculate offset from the top of the minute
                    let offset = point_utc.tm_sec as u64 * 1_000_000_000 + point_utc.tm_nsec as u64;
                    let offset_ms = (offset as f64 / 1_000_000.0).floor() as usize;
                    data.push(format!("\"{}/maximum/offset_ms\": {}", label, offset_ms));
                }
                _ => {
                    continue;
                }
            }
        }
        data.sort();
        let body = if pretty {
            data.join(",\n  ")
        } else {
            data.join(",")
        };
        let mut content = head;
        content += &body;
        if pretty {
            content += "\n";
        }
        content += "}";
        content
    }
}
<commit_msg>rpc-perf: serve machine readable stats by default (#181)<commit_after>//  Copyright 2019 Twitter, Inc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

use crate::stats::Simple;
use logger::*;
use metrics::{Output, Percentile, Reading};
use std::net::SocketAddr;
use tiny_http::{Method, Response, Server};

pub struct Http {
    recorder: Simple,
    server: Server,
    snapshot: Vec<Reading>,
    refreshed: u64,
}

impl Http {
    pub fn new(address: SocketAddr, recorder: &Simple) -> Self {
        let server = tiny_http::Server::http(address);
        if server.is_err() {
            fatal!("Failed to open {} for HTTP Stats listener", address);
        }
        Self {
            recorder: recorder.clone(),
            server: server.unwrap(),
            snapshot: Vec::new(),
            refreshed: 0,
        }
    }

    pub fn run(&mut self) {
        let now = time::precise_time_ns();
        if now - self.refreshed > 500_000_000 {
            self.snapshot = self.recorder.readings();
            self.refreshed = time::precise_time_ns();
        }
        if let Ok(Some(request)) = self.server.try_recv() {
            match request.method() {
                Method::Get => match request.url() {
                    "/" => {
                        debug!("Serving GET on index");
                        let _ = request.respond(Response::from_string(format!(
                            "Welcome to rpc-perf\nVersion: {}",
                            crate::config::VERSION
                        )));
                    }
                    "/metrics.json" | "/vars.json" | "/admin/metrics.json" => {
                        debug!("Serving machine readable stats on /vars");
                        let _ = request.respond(Response::from_string(self.json(false)));
                    }
                    "/vars" => {
                        debug!("Serving human readable stats on /vars");
                        let _ = request.respond(Response::from_string(self.human()));
                    }
                    url => {
                        debug!("GET on non-existent url: {}", url);
                        debug!("Serving machine readable stats on /vars");
                        let _ = request.respond(Response::from_string(self.json(false)));
                    }
                },
                method => {
                    error!("unsupported request method: {}", method);
                    let _ = request.respond(Response::empty(404));
                }
            }
        }
        std::thread::sleep(std::time::Duration::from_millis(1));
    }

    pub fn human(&self) -> String {
        let mut data = Vec::new();
        for reading in &self.snapshot {
            let label = reading.label();
            let output = reading.output();
            let value = reading.value();
            match output {
                Output::Counter => {
                    data.push(format!("{}/count: {}", label, value));
                }
                Output::Percentile(percentile) => match percentile {
                    Percentile::Minimum => {
                        data.push(format!("{}/minimum/value: {}", label, value));
                    }
                    Percentile::Maximum => {
                        data.push(format!("{}/maximum/value: {}", label, value));
                    }
                    _ => {
                        data.push(format!("{}/histogram/{}: {}", label, percentile, value));
                    }
                },
                Output::MaxPointTime => {
                    // we have point's ns since X and current timespec and current ns sinc X
                    let point_ns = value;
                    let now_timespec = time::get_time();
                    let now_ns = time::precise_time_ns();

                    // find the number of NS in the past for point
                    let delta_ns = now_ns as usize - point_ns;
                    let point_timespec =
                        now_timespec - time::Duration::nanoseconds(delta_ns as i64);

                    // convert to UTC
                    let point_utc = time::at_utc(point_timespec);
                    // calculate offset from the top of the minute
                    let offset = point_utc.tm_sec as u64 * 1_000_000_000 + point_utc.tm_nsec as u64;
                    let offset_ms = (offset as f64 / 1_000_000.0).floor() as usize;
                    data.push(format!("{}/maximum/offset_ms: {}", label, offset_ms));
                }
                _ => {
                    continue;
                }
            }
        }
        data.sort();
        let mut content = data.join("\n");
        content += "\n";
        content
    }

    fn json(&self, pretty: bool) -> String {
        let mut head = "{".to_owned();
        if pretty {
            head += "\n  ";
        }
        let mut data = Vec::new();
        for reading in &self.snapshot {
            let label = reading.label();
            let output = reading.output();
            let value = reading.value();
            match output {
                Output::Counter => {
                    data.push(format!("\"{}/count\": {}", label, value));
                }
                Output::Percentile(percentile) => match percentile {
                    Percentile::Minimum => {
                        data.push(format!("\"{}/minimum/value\": {}", label, value));
                    }
                    Percentile::Maximum => {
                        data.push(format!("\"{}/maximum/value\": {}", label, value));
                    }
                    _ => {
                        data.push(format!("\"{}/histogram/{}\": {}", label, percentile, value));
                    }
                },
                Output::MaxPointTime => {
                    // we have point's ns since X and current timespec and current ns sinc X
                    let point_ns = value;
                    let now_timespec = time::get_time();
                    let now_ns = time::precise_time_ns();

                    // find the number of NS in the past for point
                    let delta_ns = now_ns as usize - point_ns;
                    let point_timespec =
                        now_timespec - time::Duration::nanoseconds(delta_ns as i64);

                    // convert to UTC
                    let point_utc = time::at_utc(point_timespec);
                    // calculate offset from the top of the minute
                    let offset = point_utc.tm_sec as u64 * 1_000_000_000 + point_utc.tm_nsec as u64;
                    let offset_ms = (offset as f64 / 1_000_000.0).floor() as usize;
                    data.push(format!("\"{}/maximum/offset_ms\": {}", label, offset_ms));
                }
                _ => {
                    continue;
                }
            }
        }
        data.sort();
        let body = if pretty {
            data.join(",\n  ")
        } else {
            data.join(",")
        };
        let mut content = head;
        content += &body;
        if pretty {
            content += "\n";
        }
        content += "}";
        content
    }
}
<|endoftext|>


<commit_before>use errors::*;
use multirust_dist::{utils, dist, InstallPrefix, InstallMethod};
use multirust_dist::dist::ToolchainDesc;
use multirust_dist::manifestation::{Manifestation, Changes};
use multirust_dist::manifest::Component;
use config::Cfg;
use env_var;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;

use hyper;
use multirust_dist;

#[derive(Debug)]
pub struct Toolchain<'a> {
    cfg: &'a Cfg,
    name: String,
    prefix: InstallPrefix,
}

impl<'a> Toolchain<'a> {
    pub fn from(cfg: &'a Cfg, name: &str) -> Self {
        Toolchain {
            cfg: cfg,
            name: name.to_owned(),
            prefix: InstallPrefix::from(cfg.toolchains_dir.join(name)),
        }
    }
    pub fn cfg(&self) -> &'a Cfg {
        self.cfg
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn prefix(&self) -> &InstallPrefix {
        &self.prefix
    }
    pub fn exists(&self) -> bool {
        utils::is_directory(self.prefix.path())
    }
    pub fn verify(&self) -> Result<()> {
        Ok(try!(utils::assert_is_directory(self.prefix.path())))
    }
    pub fn remove(&self) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UninstallingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::ToolchainNotInstalled(&self.name));
            return Ok(());
        }
        if let Some(update_hash) = try!(self.update_hash()) {
            try!(utils::remove_file("update hash", &update_hash));
        }
        let handler = self.cfg.notify_handler.as_ref();
        let result = self.prefix.uninstall(ntfy!(&handler));
        if !self.exists() {
            self.cfg.notify_handler.call(Notification::UninstalledToolchain(&self.name));
        }
        Ok(try!(result))
    }
    pub fn remove_if_exists(&self) -> Result<()> {
        if self.exists() {
            self.remove()
        } else {
            Ok(())
        }
    }
    pub fn install(&self, install_method: InstallMethod) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UpdatingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::InstallingToolchain(&self.name));
        }
        self.cfg
            .notify_handler
            .call(Notification::ToolchainDirectory(self.prefix.path(), &self.name));
        let handler = self.cfg.notify_handler.as_ref();
        Ok(try!(self.prefix.install(install_method, ntfy!(&handler))))
    }
    pub fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<()> {
        self.cfg.notify_handler.call(Notification::LookingForToolchain(&self.name));
        if !self.exists() {
            self.install(install_method)
        } else {
            self.cfg.notify_handler.call(Notification::UsingExistingToolchain(&self.name));
            Ok(())
        }
    }
    pub fn update_hash(&self) -> Result<Option<PathBuf>> {
        if self.is_custom() {
            Ok(None)
        } else {
            Ok(Some(try!(self.cfg.get_hash_file(&self.name, true))))
        }
    }

    fn download_cfg(&self) -> dist::DownloadCfg {
        dist::DownloadCfg {
            dist_root: &self.cfg.dist_root_url,
            temp_cfg: &self.cfg.temp_cfg,
            notify_handler: ntfy!(&self.cfg.notify_handler),
        }
    }

    pub fn install_from_dist(&self) -> Result<()> {
        let update_hash = try!(self.update_hash());
        self.install(InstallMethod::Dist(&self.name,
                                         update_hash.as_ref().map(|p| &**p),
                                         self.download_cfg()))
    }
    pub fn install_from_dist_if_not_installed(&self) -> Result<()> {
        let update_hash = try!(self.update_hash());
        self.install_if_not_installed(InstallMethod::Dist(&self.name,
                                                          update_hash.as_ref().map(|p| &**p),
                                                          self.download_cfg()))
    }
    pub fn is_custom(&self) -> bool {
        ToolchainDesc::from_str(&self.name).is_err()
    }
    pub fn is_tracking(&self) -> bool {
        ToolchainDesc::from_str(&self.name).ok().map(|d| d.is_tracking()) == Some(true)
    }

    pub fn ensure_custom(&self) -> Result<()> {
        if !self.is_custom() {
            Err(Error::Install(multirust_dist::Error::InvalidToolchainName(self.name.to_string())))
        } else {
            Ok(())
        }
    }

    pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
        try!(self.ensure_custom());

        try!(self.remove_if_exists());

        // FIXME: This should do all downloads first, then do
        // installs, and do it all in a single transaction.
        for installer in installers {
            let installer_str = installer.to_str().unwrap_or("bogus");
            match installer_str.rfind(".") {
                Some(i) => {
                    let extension = &installer_str[i+1..];
                    if extension != "gz" {
                        return Err(Error::BadInstallerType(extension.to_string()));
                    }
                }
                None => return Err(Error::BadInstallerType(String::from("(none)")))
            }

            // FIXME: Pretty hacky
            let is_url = installer_str.starts_with("file://")
                || installer_str.starts_with("http://")
                || installer_str.starts_with("https://");
            let url = hyper::Url::parse(installer_str).ok();
            let url = if is_url { url } else { None };
            if let Some(url) = url {

                // Download to a local file
                let local_installer = try!(self.cfg.temp_cfg.new_file_with_ext("", ".tar.gz"));
                try!(utils::download_file(url,
                                          &local_installer,
                                          None,
                                          ntfy!(&self.cfg.notify_handler)));
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            } else {
                // If installer is a filename

                // No need to download
                let local_installer = Path::new(installer);

                // Install from file
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            }
        }

        Ok(())
    }

    pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
        try!(self.ensure_custom());

        if link {
            self.install(InstallMethod::Link(&try!(utils::to_absolute(src))))
        } else {
            self.install(InstallMethod::Copy(src))
        }
    }

    fn set_env_inner(&self, cmd: &mut Command) {
        cmd.env("MULTIRUST_TOOLCHAIN", self.prefix.path());
        cmd.env("MULTIRUST_HOME", &self.cfg.multirust_dir);
    }

    pub fn set_env(&self, cmd: &mut Command) {
        self.set_prefix_env(cmd, &self.cfg.multirust_dir.join("cargo"));
        self.set_env_inner(cmd);
    }

    pub fn set_ldpath(&self, cmd: &mut Command) {
        let new_path = self.prefix.path().join("lib");

        env_var::set_path("LD_LIBRARY_PATH", &new_path, cmd);
        env_var::set_path("DYLD_LIBRARY_PATH", &new_path, cmd);
    }

    fn set_prefix_env(&self, cmd: &mut Command, cargo_home: &Path) {
        self.set_ldpath(cmd);
        env_var::set_path("PATH", &self.prefix.path().join("bin"), cmd);
        env_var::set_default("CARGO_HOME", cargo_home.as_ref(), cmd);
        env_var::inc("RUST_RECURSION_COUNT", cmd);
    }

    pub fn create_command<T: AsRef<OsStr>>(&self, binary: T) -> Result<Command> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let mut cmd = Command::new(binary);
        self.set_prefix_env(&mut cmd, &self.cfg.multirust_dir.join("cargo"));
        self.set_env_inner(&mut cmd);
        Ok(cmd)
    }

    pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
        try!(self.verify());
        Ok(try!(self.prefix.doc_path(relative)))
    }
    pub fn open_docs(&self, relative: &str) -> Result<()> {
        try!(self.verify());
        Ok(try!(self.prefix.open_docs(relative)))
    }

    pub fn make_default(&self) -> Result<()> {
        self.cfg.set_default(&self.name)
    }
    pub fn make_override(&self, path: &Path) -> Result<()> {
        Ok(try!(self.cfg.override_db.set(path,
                                         &self.name,
                                         &self.cfg.temp_cfg,
                                         self.cfg.notify_handler.as_ref())))
    }

    pub fn list_components(&self) -> Result<Vec<Component>> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        // FIXME: This toolchain handling is a mess. Just do it once
        // when the toolchain is created.
        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {
            // Return all optional components of the "rust" package for the
            // toolchain's target triple.
            let mut res = Vec::new();

            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            for extension in &targ_pkg.extensions {
                res.push(extension.clone())
            }

            Ok(res)
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn add_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::AddingRequiredComponent(self.name.to_string(), component));
            }

            if !targ_pkg.extensions.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![component],
                remove_extensions: vec![]
            };

            try!(manifestation.update(&self.name,
                                      &manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn remove_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::RemovingRequiredComponent(self.name.to_string(), component));
            }

            let dist_config = try!(manifestation.read_config()).unwrap();
            if !dist_config.components.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![],
                remove_extensions: vec![component]
            };

            try!(manifestation.update(&self.name,
                                      &manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }
}
<commit_msg>Simpify env-handling functions in toolchain<commit_after>use errors::*;
use multirust_dist::{utils, dist, InstallPrefix, InstallMethod};
use multirust_dist::dist::ToolchainDesc;
use multirust_dist::manifestation::{Manifestation, Changes};
use multirust_dist::manifest::Component;
use config::Cfg;
use env_var;

use std::process::Command;
use std::path::{Path, PathBuf};
use std::ffi::OsStr;

use hyper;
use multirust_dist;

#[derive(Debug)]
pub struct Toolchain<'a> {
    cfg: &'a Cfg,
    name: String,
    prefix: InstallPrefix,
}

impl<'a> Toolchain<'a> {
    pub fn from(cfg: &'a Cfg, name: &str) -> Self {
        Toolchain {
            cfg: cfg,
            name: name.to_owned(),
            prefix: InstallPrefix::from(cfg.toolchains_dir.join(name)),
        }
    }
    pub fn cfg(&self) -> &'a Cfg {
        self.cfg
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn prefix(&self) -> &InstallPrefix {
        &self.prefix
    }
    pub fn exists(&self) -> bool {
        utils::is_directory(self.prefix.path())
    }
    pub fn verify(&self) -> Result<()> {
        Ok(try!(utils::assert_is_directory(self.prefix.path())))
    }
    pub fn remove(&self) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UninstallingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::ToolchainNotInstalled(&self.name));
            return Ok(());
        }
        if let Some(update_hash) = try!(self.update_hash()) {
            try!(utils::remove_file("update hash", &update_hash));
        }
        let handler = self.cfg.notify_handler.as_ref();
        let result = self.prefix.uninstall(ntfy!(&handler));
        if !self.exists() {
            self.cfg.notify_handler.call(Notification::UninstalledToolchain(&self.name));
        }
        Ok(try!(result))
    }
    pub fn remove_if_exists(&self) -> Result<()> {
        if self.exists() {
            self.remove()
        } else {
            Ok(())
        }
    }
    pub fn install(&self, install_method: InstallMethod) -> Result<()> {
        if self.exists() {
            self.cfg.notify_handler.call(Notification::UpdatingToolchain(&self.name));
        } else {
            self.cfg.notify_handler.call(Notification::InstallingToolchain(&self.name));
        }
        self.cfg
            .notify_handler
            .call(Notification::ToolchainDirectory(self.prefix.path(), &self.name));
        let handler = self.cfg.notify_handler.as_ref();
        Ok(try!(self.prefix.install(install_method, ntfy!(&handler))))
    }
    pub fn install_if_not_installed(&self, install_method: InstallMethod) -> Result<()> {
        self.cfg.notify_handler.call(Notification::LookingForToolchain(&self.name));
        if !self.exists() {
            self.install(install_method)
        } else {
            self.cfg.notify_handler.call(Notification::UsingExistingToolchain(&self.name));
            Ok(())
        }
    }
    pub fn update_hash(&self) -> Result<Option<PathBuf>> {
        if self.is_custom() {
            Ok(None)
        } else {
            Ok(Some(try!(self.cfg.get_hash_file(&self.name, true))))
        }
    }

    fn download_cfg(&self) -> dist::DownloadCfg {
        dist::DownloadCfg {
            dist_root: &self.cfg.dist_root_url,
            temp_cfg: &self.cfg.temp_cfg,
            notify_handler: ntfy!(&self.cfg.notify_handler),
        }
    }

    pub fn install_from_dist(&self) -> Result<()> {
        let update_hash = try!(self.update_hash());
        self.install(InstallMethod::Dist(&self.name,
                                         update_hash.as_ref().map(|p| &**p),
                                         self.download_cfg()))
    }
    pub fn install_from_dist_if_not_installed(&self) -> Result<()> {
        let update_hash = try!(self.update_hash());
        self.install_if_not_installed(InstallMethod::Dist(&self.name,
                                                          update_hash.as_ref().map(|p| &**p),
                                                          self.download_cfg()))
    }
    pub fn is_custom(&self) -> bool {
        ToolchainDesc::from_str(&self.name).is_err()
    }
    pub fn is_tracking(&self) -> bool {
        ToolchainDesc::from_str(&self.name).ok().map(|d| d.is_tracking()) == Some(true)
    }

    pub fn ensure_custom(&self) -> Result<()> {
        if !self.is_custom() {
            Err(Error::Install(multirust_dist::Error::InvalidToolchainName(self.name.to_string())))
        } else {
            Ok(())
        }
    }

    pub fn install_from_installers(&self, installers: &[&OsStr]) -> Result<()> {
        try!(self.ensure_custom());

        try!(self.remove_if_exists());

        // FIXME: This should do all downloads first, then do
        // installs, and do it all in a single transaction.
        for installer in installers {
            let installer_str = installer.to_str().unwrap_or("bogus");
            match installer_str.rfind(".") {
                Some(i) => {
                    let extension = &installer_str[i+1..];
                    if extension != "gz" {
                        return Err(Error::BadInstallerType(extension.to_string()));
                    }
                }
                None => return Err(Error::BadInstallerType(String::from("(none)")))
            }

            // FIXME: Pretty hacky
            let is_url = installer_str.starts_with("file://")
                || installer_str.starts_with("http://")
                || installer_str.starts_with("https://");
            let url = hyper::Url::parse(installer_str).ok();
            let url = if is_url { url } else { None };
            if let Some(url) = url {

                // Download to a local file
                let local_installer = try!(self.cfg.temp_cfg.new_file_with_ext("", ".tar.gz"));
                try!(utils::download_file(url,
                                          &local_installer,
                                          None,
                                          ntfy!(&self.cfg.notify_handler)));
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            } else {
                // If installer is a filename

                // No need to download
                let local_installer = Path::new(installer);

                // Install from file
                try!(self.install(InstallMethod::Installer(&local_installer, &self.cfg.temp_cfg)));
            }
        }

        Ok(())
    }

    pub fn install_from_dir(&self, src: &Path, link: bool) -> Result<()> {
        try!(self.ensure_custom());

        if link {
            self.install(InstallMethod::Link(&try!(utils::to_absolute(src))))
        } else {
            self.install(InstallMethod::Copy(src))
        }
    }

    pub fn create_command<T: AsRef<OsStr>>(&self, binary: T) -> Result<Command> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let mut cmd = Command::new(binary);
        self.set_env(&mut cmd);
        Ok(cmd)
    }

    fn set_env(&self, cmd: &mut Command) {
        let ref cargo_home = self.cfg.multirust_dir.join("cargo");
        let ref bin_path = self.prefix.path().join("bin");

        self.set_ldpath(cmd);

        env_var::set_path("PATH", bin_path, cmd);
        env_var::set_default("CARGO_HOME", cargo_home.as_ref(), cmd);
        env_var::inc("RUST_RECURSION_COUNT", cmd);

        // FIXME: This should not be a path, but a toolchain name.
        // Not sure what's going on here.
        cmd.env("MULTIRUST_TOOLCHAIN", self.prefix.path());
        cmd.env("MULTIRUST_HOME", &self.cfg.multirust_dir);
    }

    pub fn set_ldpath(&self, cmd: &mut Command) {
        let new_path = self.prefix.path().join("lib");

        env_var::set_path("LD_LIBRARY_PATH", &new_path, cmd);
        env_var::set_path("DYLD_LIBRARY_PATH", &new_path, cmd);
    }

    pub fn doc_path(&self, relative: &str) -> Result<PathBuf> {
        try!(self.verify());
        Ok(try!(self.prefix.doc_path(relative)))
    }
    pub fn open_docs(&self, relative: &str) -> Result<()> {
        try!(self.verify());
        Ok(try!(self.prefix.open_docs(relative)))
    }

    pub fn make_default(&self) -> Result<()> {
        self.cfg.set_default(&self.name)
    }
    pub fn make_override(&self, path: &Path) -> Result<()> {
        Ok(try!(self.cfg.override_db.set(path,
                                         &self.name,
                                         &self.cfg.temp_cfg,
                                         self.cfg.notify_handler.as_ref())))
    }

    pub fn list_components(&self) -> Result<Vec<Component>> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        // FIXME: This toolchain handling is a mess. Just do it once
        // when the toolchain is created.
        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {
            // Return all optional components of the "rust" package for the
            // toolchain's target triple.
            let mut res = Vec::new();

            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            for extension in &targ_pkg.extensions {
                res.push(extension.clone())
            }

            Ok(res)
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn add_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::AddingRequiredComponent(self.name.to_string(), component));
            }

            if !targ_pkg.extensions.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![component],
                remove_extensions: vec![]
            };

            try!(manifestation.update(&self.name,
                                      &manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }

    pub fn remove_component(&self, component: Component) -> Result<()> {
        if !self.exists() {
            return Err(Error::ToolchainNotInstalled(self.name.to_owned()));
        }

        let ref toolchain = self.name;
        let ref toolchain = try!(ToolchainDesc::from_str(toolchain));
        let trip = toolchain.target_triple();
        let manifestation = try!(Manifestation::open(self.prefix.clone(), &trip));

        if let Some(manifest) = try!(manifestation.load_manifest()) {

            // Validate the component name
            let rust_pkg = manifest.packages.get("rust")
                .expect("manifest should cantain a rust package");
            let targ_pkg = rust_pkg.targets.get(&trip)
                .expect("installed manifest should have a known target");

            if targ_pkg.components.contains(&component) {
                return Err(Error::RemovingRequiredComponent(self.name.to_string(), component));
            }

            let dist_config = try!(manifestation.read_config()).unwrap();
            if !dist_config.components.contains(&component) {
                return Err(Error::UnknownComponent(self.name.to_string(), component));
            }

            let changes = Changes {
                add_extensions: vec![],
                remove_extensions: vec![component]
            };

            try!(manifestation.update(&self.name,
                                      &manifest,
                                      changes,
                                      self.download_cfg().temp_cfg,
                                      self.download_cfg().notify_handler.clone()));

            Ok(())
        } else {
            Err(Error::ComponentsUnsupported(self.name.to_string()))
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::Display;

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
				human_readable: format!("Does not equal '{}'", value)
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
                human_readable: format!("Must be one of {}", list.to_string())
            })
        }
    })
}<commit_msg>Tests for eq & either (#3 #1)<commit_after>use std::fmt::Display;

/// Enforce that `T` must equal `value`.
pub fn eq<T: 'static>(value: T) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display
{
    Box::new(move |s: &T| {
        if *s == value {
            Ok(())
        } else {
            Err(::Invalid {
                msg: "Does not equal %1.".to_string(),
                args: vec![value.to_string()],
				human_readable: format!("Does not equal '{}'", value)
            })
        }
    })
}

/// Enforce that `T` equals any of the values in `values`.
pub fn either<T: 'static>(values: Vec<T>) -> Box<Fn(&T) -> ::ValidatorResult>
    where T: PartialEq + Display + Clone
{
    Box::new(move |s: &T| {
        let x = values.iter().find(|x| *x == s);
        let r = x.is_some();
        if r == true {
            Ok(())
        } else {
            let list = values.iter()
                .cloned()
                .fold(String::new(), |acc, v| format!("{}, {}", acc, v));
            Err(::Invalid {
                msg: "Must be one of %1.".to_string(),
                args: vec![list.to_string()],
                human_readable: format!("Must be one of {}", list.to_string())
            })
        }
    })
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fmt;

    #[derive(PartialEq, Clone)]
    enum TestEnum {
        Yes,No,Maybe,IDontKnow,RepeatTheQuestion
    }

    impl Display for TestEnum {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "Doesn't Matter")
        }
    }

    // eq
    #[test]
    pub fn eq_valid() {
        assert!(eq(1)(&1).is_ok());
        assert!(eq("yes")(&"yes").is_ok());
        assert!(eq(TestEnum::Yes)(&TestEnum::Yes).is_ok());
        assert!(eq(TestEnum::No)(&TestEnum::No).is_ok());
    }

    #[test]
    pub fn eq_invalid() {
        assert!(eq(1)(&2).is_err());
        assert!(eq("yes")(&"yesn't").is_err());
        assert!(eq(TestEnum::Yes)(&TestEnum::No).is_err());
        assert!(eq(TestEnum::No)(&TestEnum::Yes).is_err());

    }

    // either
    #[test]
    pub fn either_valid() {
        assert!(either(vec![1, 2, 3])(&1).is_ok());
        assert!(either(vec![1, 2, 3])(&2).is_ok());
        assert!(either(vec![1, 2, 3])(&3).is_ok());

        assert!(either(vec!["yes", "no"])(&"yes").is_ok());
        assert!(either(vec!["yes", "no"])(&"no").is_ok());

        assert!(either(vec![TestEnum::Maybe, TestEnum::IDontKnow])(&TestEnum::Maybe).is_ok());
        assert!(either(vec![TestEnum::Maybe, TestEnum::IDontKnow])(&TestEnum::IDontKnow).is_ok());
    }

    #[test]
    pub fn either_invalid() {
        assert!(either(vec![1, 2, 3])(&4).is_err());
        assert!(either(vec![1, 2, 3])(&5).is_err());
        assert!(either(vec![1, 2, 3])(&6).is_err());

        assert!(either(vec!["yes", "no"])(&"maybe").is_err());
        assert!(either(vec!["yes", "no"])(&"i don't know").is_err());

        assert!(either(vec![TestEnum::Maybe, TestEnum::IDontKnow])(&TestEnum::Yes).is_err());
        assert!(either(vec![TestEnum::Maybe, TestEnum::IDontKnow])(&TestEnum::No).is_err());
        assert!(either(vec![TestEnum::Maybe, TestEnum::IDontKnow])(&TestEnum::RepeatTheQuestion).is_err());
    }
}<|endoftext|>


<commit_before>//! Utility functions for testing

use std::path::PathBuf;

// Expose dependency for use by other internal crates (e.g. so macros work)
pub use pretty_assertions;
pub use serde_json;

/// Get the path of the home directory of this repository
pub fn home() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../..")
        .canonicalize()
        .expect("Unable to get repository home directory")
}

/// Get the path of the `fixtures` directory
pub fn fixtures() -> PathBuf {
    home().join("fixtures")
}

/// Should slow tests be skipped?
///
/// Use at the start of slow tests to return early except on CI or when
/// the env var `RUN_SLOW_TESTS` is set.
///
/// Inspired by https://github.com/rust-analyzer/rust-analyzer/pull/2491
pub fn skip_slow_tests() -> bool {
    if std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err() {
        eprintln!("Skipping slow test");
        true
    } else {
        false
    }
}

/// Assert that two nodes are equal based on their JSON representation
///
/// This has the advantage over `pretty_assertions::assert_eq` of not requiring the
/// `==` operator to be defined for the types and hiding less usually irrelevant
/// details such as `Box` wrappers.
#[macro_export]
macro_rules! assert_json_eq {
    ($a:expr, $b:expr) => {
        test_utils::pretty_assertions::assert_eq!(
            test_utils::serde_json::to_value(&$a).unwrap(),
            test_utils::serde_json::to_value(&$b).unwrap()
        );
    };
}
<commit_msg>test(Rust): Fix path<commit_after>//! Utility functions for testing

use std::path::PathBuf;

// Expose dependency for use by other internal crates (e.g. so macros work)
pub use pretty_assertions;
pub use serde_json;

/// Get the path of the home directory of this repository
pub fn home() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../..")
        .canonicalize()
        .expect("Unable to get repository home directory")
}

/// Get the path of the `fixtures` directory
pub fn fixtures() -> PathBuf {
    home().join("fixtures")
}

/// Should slow tests be skipped?
///
/// Use at the start of slow tests to return early except on CI or when
/// the env var `RUN_SLOW_TESTS` is set.
///
/// Inspired by https://github.com/rust-analyzer/rust-analyzer/pull/2491
pub fn skip_slow_tests() -> bool {
    if std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err() {
        eprintln!("Skipping slow test");
        true
    } else {
        false
    }
}

/// Assert that two nodes are equal based on their JSON representation
///
/// This has the advantage over `pretty_assertions::assert_eq` of not requiring the
/// `==` operator to be defined for the types and hiding less usually irrelevant
/// details such as `Box` wrappers.
#[macro_export]
macro_rules! assert_json_eq {
    ($a:expr, $b:expr) => {
        test_utils::pretty_assertions::assert_eq!(
            test_utils::serde_json::to_value(&$a).unwrap(),
            test_utils::serde_json::to_value(&$b).unwrap()
        );
    };
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use ::chrono::prelude::*;
use ::chrono::Duration;
use ::chrono_english::*;
use ::structopt::clap::Shell;
use ::structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum SubCommand {
    /// Enqueue a task for execution.
    Add {
        /// The command that should be added.
        command: Vec<String>,

        /// Start the task immediately.
        #[structopt(name = "immediate", short, long, conflicts_with = "stash")]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution if the queue is empty.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Delays enqueueing the task until <delay> elapses. See enqueue for accepted formats.
        #[structopt(name = "delay", short, long, conflicts_with = "immediate", parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,

        /// Assign the task to a group. Groups kind of act as separate queues.
        /// I.e. all groups run in parallel and you can specify the amount of parallel tasks for each group.
        /// If no group is specified, the default group will be used.
        #[structopt(name = "group", short, long)]
        group: Option<String>,

        /// Start the task once all specified tasks have successfully finished.
        /// As soon as one of the dependencies fails, this task will fail as well.
        #[structopt(name = "after", short, long)]
        dependencies: Vec<usize>,
    },
    /// Remove tasks from the list.
    /// Running or paused tasks need to be killed first.
    Remove {
        /// The task ids to be removed.
        task_ids: Vec<usize>,
    },
    /// Switches the queue position of two commands. Only works on queued and stashed commands.
    Switch {
        /// The first task id.
        task_id_1: usize,
        /// The second task id.
        task_id_2: usize,
    },
    /// Stashed tasks won't be automatically started.
    /// Either `enqueue` them, to be normally handled or explicitly `start` them.
    Stash {
        /// The id(s) of the tasks you want to stash.
        task_ids: Vec<usize>,
    },
    /// Enqueue stashed tasks. They'll be handled normally afterwards.
    #[structopt(after_help = "DELAY FORMAT:

    The --delay argument must be either a number of seconds or a \"date expression\" similar to GNU \
    `date -d` with some extensions. It does not attempt to parse all natural language, but is \
    incredibly flexible. Here are some supported examples.

    2020-04-01T18:30:00   // RFC 3339 timestamp
    2020-4-1 18:2:30      // Optional leading zeros
    2020-4-1 5:30pm       // Informal am/pm time
    2020-4-1 5pm          // Optional minutes and seconds
    April 1 2020 18:30:00 // English months
    1 Apr 8:30pm          // Implies current year
    4/1                   // American form date
    wednesday 10:30pm     // The closest wednesday in the future at 22:30
    wednesday             // The closest wednesday in the future
    4 months              // 4 months from today at 00:00:00
    1 week                // 1 week at the current time
    1days                 // 1 day from today at the current time
    1d 03:00              // The closest 3:00 after 1 day (24 hours)
    3h                    // 3 hours from now
    3600s                 // 3600 seconds from now
")]
    Enqueue {
        /// The id(s) of the tasks you want to enqueue.
        task_ids: Vec<usize>,

        /// Delay enqueuing the tasks until <delay> elapses. See DELAY FORMAT below.
        #[structopt(name = "delay", short, long, parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,
    },

    /// Resume operation of specific tasks or groups of tasks.
    /// Without any parameters, resumes the default queue and all it's tasks.
    /// Can also be used force specific tasks to start.
    #[structopt(verbatim_doc_comment)]
    Start {
        /// Enforce starting these tasks. Paused tasks will be started again.
        /// This doesn't affect anything other than these tasks.
        task_ids: Vec<usize>,

        /// Start a specific group and all paused tasks in it.
        #[structopt(short, long, group("start"))]
        group: Option<String>,

        /// Start a everything (Default queue and all groups)!
        /// All groups will be set to `running` and all paused tasks will be resumed.
        #[structopt(short, long, group("start"))]
        all: bool,

        /// Also resume direct child processes of your paused tasks.
        /// By default only the main process will get a SIGSTART.
        #[structopt(short, long, group("start"))]
        children: bool,
    },

    /// Restart task(s).
    /// Identical tasks will be created and instantly queued (unless specified otherwise).
    Restart {
        /// The tasks you want to restart.
        task_ids: Vec<usize>,

        /// Immediately start the task(s).
        #[structopt(name = "immediate", short, long)]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,
    },

    /// Pause either running tasks or specific groups of tasks.
    /// Without any parameters, pauses the default queue and all it's tasks.
    /// A paused queue (group) won't start any new tasks.
    /// Everything can be resumed with `start`.
    #[structopt(verbatim_doc_comment)]
    Pause {
        /// Pause these specific tasks.
        /// Doesn't affect the default queue, groups or any other tasks.
        task_ids: Vec<usize>,

        /// Pause a specific group.
        #[structopt(short, long, group("pause"))]
        group: Option<String>,

        /// Pause everything (Default queue and all groups)!
        #[structopt(short, long, group("pause"))]
        all: bool,

        /// Don't pause already running tasks and let them finish by themselves,
        ///  when pausing with `default`, `all` or `group`.
        #[structopt(short, long, group("pause"))]
        wait: bool,

        /// Also pause direct child processes of a task's main process.
        /// By default only the main process will get a SIGSTOP.
        /// This is useful when calling bash scripts, which start other processes themselves.
        /// This operation is not recursive!
        #[structopt(short, long, group("pause"))]
        children: bool,
    },

    /// Kill specific running tasks or various groups of tasks.
    Kill {
        /// The tasks that should be killed.
        task_ids: Vec<usize>,

        /// Kill all running tasks in the default queue. Pause the default queue.
        #[structopt(short, long, group("kill"))]
        default: bool,

        /// Kill all running in a group. Pauses the group.
        #[structopt(short, long, group("kill"))]
        group: Option<String>,

        /// Kill ALL running tasks. This also pauses everything
        #[structopt(short, long, group("kill"))]
        all: bool,

        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long, group("kill"))]
        children: bool,
    },

    /// Send something to a task. Useful for sending confirmations ('y\n').
    Send {
        /// The id of the task.
        task_id: usize,

        /// The input that should be sent to the process.
        input: String,
    },

    /// Edit the command or path of a stashed or queued task.
    /// This edits the command of the task by default.
    #[structopt(verbatim_doc_comment)]
    Edit {
        /// The id of the task.
        task_id: usize,

        /// Edit the path of the task.
        #[structopt(short, long)]
        path: bool,
    },

    /// Manage groups.
    /// Without any flags, this will simply display all known groups.
    Group {
        /// Add a group
        #[structopt(short, long)]
        add: Option<String>,

        /// Remove a group.
        /// This will move all tasks in this group to the default group!
        #[structopt(short, long)]
        remove: Option<String>,
    },

    /// Display the current status of all tasks.
    Status {
        /// Print the current state as json to stdout.
        /// This doesn't include stdout/stderr of tasks.
        /// Use `log -j` if you want everything.
        #[structopt(short, long)]
        json: bool,

        #[structopt(short, long)]
        /// Only show tasks of a specific group
        group: Option<String>,
    },

    /// Display the log output of finished tasks.
    Log {
        /// Specify for which specific tasks you want to see the output.
        task_ids: Vec<usize>,
        /// Print the current state as json.
        /// Includes EVERYTHING.
        #[structopt(short, long)]
        json: bool,
    },

    /// Follow the output of a currently running task.
    /// This command works like `tail -f`.
    Follow {
        /// The id of the task.  If None, it will default to the running task if
        /// only one is running.  If no or multiple tasks are running, a message
        /// will be displayed.
        task_id: Option<usize>,

        /// Show stderr instead of stdout.
        #[structopt(short, long)]
        err: bool,
    },

    /// Remove all finished tasks from the list (also clears logs).
    Clean,

    /// Kill all running tasks, remove all tasks and reset max_task_id.
    Reset {
        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long)]
        children: bool,
    },

    /// Remotely shut down the daemon. Should only be used if the daemon isn't started by a service manager.
    Shutdown,

    /// Set the amount of allowed parallel tasks.
    Parallel {
        /// The amount of allowed parallel tasks.
        #[structopt(validator=min_one)]
        parallel_tasks: usize,

        /// Specify the amount of parallel tasks for a group.
        #[structopt(name = "group", short, long)]
        group: Option<String>,
    },

    /// Generates shell completion files.
    /// This can be ignored during normal operations.
    Completions {
        /// The target shell. Can be `bash`, `fish`, `powershell`, `elvish` and `zsh`.
        shell: Shell,
        /// The output directory to which the file should be written.
        output_directory: PathBuf,
    },
}

#[derive(StructOpt, Debug)]
#[structopt(
    name = "Pueue client",
    about = "Interact with the Pueue daemon",
    author = "Arne Beer <contact@arne.beer>"
)]
pub struct Opt {
    // The number of occurrences of the `v/verbose` flag.
    /// Verbose mode (-v, -vv, -vvv)
    #[structopt(short, long, parse(from_occurrences))]
    pub verbose: u8,

    //    /// The url for the daemon. Overwrites the address in the config file
    //    #[structopt(short, long)]
    //    pub address: Option<String>,
    /// The port for the daemon. Overwrites the port in the config file.
    #[structopt(short, long)]
    pub port: Option<String>,

    #[structopt(subcommand)]
    pub cmd: SubCommand,
}

fn parse_delay_until(src: &str) -> Result<DateTime<Local>, String> {
    if let Ok(seconds) = src.parse::<i64>() {
        let delay_until = Local::now() + Duration::seconds(seconds);
        return Ok(delay_until);
    }

    if let Ok(date_time) = parse_date_string(src, Local::now(), Dialect::Us) {
        return Ok(date_time);
    }

    Err(String::from(
        "could not parse as seconds or date expression",
    ))
}

/// Validator function. The input string has to be parsable as int and bigger than 0
fn min_one(value: String) -> Result<(), String> {
    match value.parse::<usize>() {
        Ok(value) => {
            if value < 1 {
                return Err("You must provide a value that's bigger than 0".into());
            }
            Ok(())
        }
        Err(_) => Err("Failed to parse integer".into()),
    }
}
<commit_msg>Streamline subcommand help texts a little<commit_after>use std::path::PathBuf;

use ::chrono::prelude::*;
use ::chrono::Duration;
use ::chrono_english::*;
use ::structopt::clap::Shell;
use ::structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub enum SubCommand {
    /// Enqueue a task for execution.
    Add {
        /// The command that should be added.
        command: Vec<String>,

        /// Start the task immediately.
        #[structopt(name = "immediate", short, long, conflicts_with = "stash")]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution if the queue is empty.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,

        /// Delays enqueueing the task until <delay> elapses. See enqueue for accepted formats.
        #[structopt(name = "delay", short, long, conflicts_with = "immediate", parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,

        /// Assign the task to a group. Groups kind of act as separate queues.
        /// I.e. all groups run in parallel and you can specify the amount of parallel tasks for each group.
        /// If no group is specified, the default group will be used.
        #[structopt(name = "group", short, long)]
        group: Option<String>,

        /// Start the task once all specified tasks have successfully finished.
        /// As soon as one of the dependencies fails, this task will fail as well.
        #[structopt(name = "after", short, long)]
        dependencies: Vec<usize>,
    },
    /// Remove tasks from the list.
    /// Running or paused tasks need to be killed first.
    Remove {
        /// The task ids to be removed.
        task_ids: Vec<usize>,
    },
    /// Switches the queue position of two commands. Only works on queued and stashed commands.
    Switch {
        /// The first task id.
        task_id_1: usize,
        /// The second task id.
        task_id_2: usize,
    },
    /// Stashed tasks won't be automatically started.
    /// Either `enqueue` them, to be normally handled or explicitly `start` them.
    Stash {
        /// The id(s) of the tasks you want to stash.
        task_ids: Vec<usize>,
    },
    /// Enqueue stashed tasks. They'll be handled normally afterwards.
    #[structopt(after_help = "DELAY FORMAT:

    The --delay argument must be either a number of seconds or a \"date expression\" similar to GNU \
    `date -d` with some extensions. It does not attempt to parse all natural language, but is \
    incredibly flexible. Here are some supported examples.

    2020-04-01T18:30:00   // RFC 3339 timestamp
    2020-4-1 18:2:30      // Optional leading zeros
    2020-4-1 5:30pm       // Informal am/pm time
    2020-4-1 5pm          // Optional minutes and seconds
    April 1 2020 18:30:00 // English months
    1 Apr 8:30pm          // Implies current year
    4/1                   // American form date
    wednesday 10:30pm     // The closest wednesday in the future at 22:30
    wednesday             // The closest wednesday in the future
    4 months              // 4 months from today at 00:00:00
    1 week                // 1 week at the current time
    1days                 // 1 day from today at the current time
    1d 03:00              // The closest 3:00 after 1 day (24 hours)
    3h                    // 3 hours from now
    3600s                 // 3600 seconds from now
")]
    Enqueue {
        /// The id(s) of the tasks you want to enqueue.
        task_ids: Vec<usize>,

        /// Delay enqueuing the tasks until <delay> elapses. See DELAY FORMAT below.
        #[structopt(name = "delay", short, long, parse(try_from_str=parse_delay_until))]
        delay_until: Option<DateTime<Local>>,
    },

    /// Resume operation of specific tasks or groups of tasks.
    /// By default, this resumes the default queue and all it's tasks.
    /// Can also be used force specific tasks to start.
    #[structopt(verbatim_doc_comment)]
    Start {
        /// Enforce starting these tasks. Paused tasks will be started again.
        /// This doesn't affect anything other than these tasks.
        task_ids: Vec<usize>,

        /// Start a specific group and all paused tasks in it.
        #[structopt(short, long, group("start"))]
        group: Option<String>,

        /// Start a everything (Default queue and all groups)!
        /// All groups will be set to `running` and all paused tasks will be resumed.
        #[structopt(short, long, group("start"))]
        all: bool,

        /// Also resume direct child processes of your paused tasks.
        /// By default only the main process will get a SIGSTART.
        #[structopt(short, long, group("start"))]
        children: bool,
    },

    /// Restart task(s).
    /// Identical tasks will be created and by defualt enqueued.
    Restart {
        /// The tasks you want to restart.
        task_ids: Vec<usize>,

        /// Immediately start the task(s).
        #[structopt(name = "immediate", short, long)]
        start_immediately: bool,

        /// Create the task in stashed state.
        /// Useful to avoid immediate execution.
        #[structopt(name = "stashed", short, long, conflicts_with = "immediate")]
        stashed: bool,
    },

    /// Pause either running tasks or specific groups of tasks.
    /// By default, pauses the default queue and all it's tasks.
    /// A paused queue (group) won't start any new tasks.
    /// Everything can be resumed with `start`.
    #[structopt(verbatim_doc_comment)]
    Pause {
        /// Pause these specific tasks.
        /// Doesn't affect the default queue, groups or any other tasks.
        task_ids: Vec<usize>,

        /// Pause a specific group.
        #[structopt(short, long, group("pause"))]
        group: Option<String>,

        /// Pause everything (Default queue and all groups)!
        #[structopt(short, long, group("pause"))]
        all: bool,

        /// Don't pause already running tasks and let them finish by themselves,
        ///  when pausing with `default`, `all` or `group`.
        #[structopt(short, long, group("pause"))]
        wait: bool,

        /// Also pause direct child processes of a task's main process.
        /// By default only the main process will get a SIGSTOP.
        /// This is useful when calling bash scripts, which start other processes themselves.
        /// This operation is not recursive!
        #[structopt(short, long, group("pause"))]
        children: bool,
    },

    /// Kill specific running tasks or various groups of tasks.
    Kill {
        /// The tasks that should be killed.
        task_ids: Vec<usize>,

        /// Kill all running tasks in the default queue. Pause the default queue.
        #[structopt(short, long, group("kill"))]
        default: bool,

        /// Kill all running in a group. Pauses the group.
        #[structopt(short, long, group("kill"))]
        group: Option<String>,

        /// Kill ALL running tasks. This also pauses everything
        #[structopt(short, long, group("kill"))]
        all: bool,

        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long, group("kill"))]
        children: bool,
    },

    /// Send something to a task. Useful for sending confirmations such as 'y\n'.
    Send {
        /// The id of the task.
        task_id: usize,

        /// The input that should be sent to the process.
        input: String,
    },

    /// Edit the command or path of a stashed or queued task.
    /// This edits the command of the task by default.
    #[structopt(verbatim_doc_comment)]
    Edit {
        /// The id of the task.
        task_id: usize,

        /// Edit the path of the task.
        #[structopt(short, long)]
        path: bool,
    },

    /// Manage groups.
    /// By default, this will simply display all known groups.
    Group {
        /// Add a group
        #[structopt(short, long)]
        add: Option<String>,

        /// Remove a group.
        /// This will move all tasks in this group to the default group!
        #[structopt(short, long)]
        remove: Option<String>,
    },

    /// Display the current status of all tasks.
    Status {
        /// Print the current state as json to stdout.
        /// This doesn't include stdout/stderr of tasks.
        /// Use `log -j` if you want everything.
        #[structopt(short, long)]
        json: bool,

        #[structopt(short, long)]
        /// Only show tasks of a specific group
        group: Option<String>,
    },

    /// Display the log output of finished tasks.
    Log {
        /// Specify for which specific tasks you want to see the output.
        task_ids: Vec<usize>,
        /// Print the current state as json.
        /// Includes EVERYTHING.
        #[structopt(short, long)]
        json: bool,
    },

    /// Follow the output of a currently running task.
    /// This command works like `tail -f`.
    Follow {
        /// The id of the task.  If None, it will default to the running task if
        /// only one is running.  If no or multiple tasks are running, a message
        /// will be displayed.
        task_id: Option<usize>,

        /// Show stderr instead of stdout.
        #[structopt(short, long)]
        err: bool,
    },

    /// Remove all finished tasks from the list (also clears logs).
    Clean,

    /// Kill all running tasks, remove all tasks and reset max_task_id.
    Reset {
        /// Send the SIGTERM signal to all children as well.
        /// Useful when working with shell scripts.
        #[structopt(short, long)]
        children: bool,
    },

    /// Remotely shut down the daemon. Should only be used if the daemon isn't started by a service manager.
    Shutdown,

    /// Set the amount of allowed parallel tasks.
    Parallel {
        /// The amount of allowed parallel tasks.
        #[structopt(validator=min_one)]
        parallel_tasks: usize,

        /// Specify the amount of parallel tasks for a group.
        #[structopt(name = "group", short, long)]
        group: Option<String>,
    },

    /// Generates shell completion files.
    /// This can be ignored during normal operations.
    Completions {
        /// The target shell. Can be `bash`, `fish`, `powershell`, `elvish` and `zsh`.
        shell: Shell,
        /// The output directory to which the file should be written.
        output_directory: PathBuf,
    },
}

#[derive(StructOpt, Debug)]
#[structopt(
    name = "Pueue client",
    about = "Interact with the Pueue daemon",
    author = "Arne Beer <contact@arne.beer>"
)]
pub struct Opt {
    // The number of occurrences of the `v/verbose` flag.
    /// Verbose mode (-v, -vv, -vvv)
    #[structopt(short, long, parse(from_occurrences))]
    pub verbose: u8,

    //    /// The url for the daemon. Overwrites the address in the config file
    //    #[structopt(short, long)]
    //    pub address: Option<String>,
    /// The port for the daemon. Overwrites the port in the config file.
    #[structopt(short, long)]
    pub port: Option<String>,

    #[structopt(subcommand)]
    pub cmd: SubCommand,
}

fn parse_delay_until(src: &str) -> Result<DateTime<Local>, String> {
    if let Ok(seconds) = src.parse::<i64>() {
        let delay_until = Local::now() + Duration::seconds(seconds);
        return Ok(delay_until);
    }

    if let Ok(date_time) = parse_date_string(src, Local::now(), Dialect::Us) {
        return Ok(date_time);
    }

    Err(String::from(
        "could not parse as seconds or date expression",
    ))
}

/// Validator function. The input string has to be parsable as int and bigger than 0
fn min_one(value: String) -> Result<(), String> {
    match value.parse::<usize>() {
        Ok(value) => {
            if value < 1 {
                return Err("You must provide a value that's bigger than 0".into());
            }
            Ok(())
        }
        Err(_) => Err("Failed to parse integer".into()),
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbtk;
extern crate userutils;

use std::{env, str};
use std::fs::File;
use std::io::Read;
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::sync::{Arc, Mutex};

use orbtk::{Button, Label, Point, Rect, TextBox, Window};
use orbtk::traits::{Click, Enter, Place, Text};
use userutils::Passwd;

pub fn main() {
    let mut args = env::args().skip(1);

    let launcher_cmd = args.next().expect("orblogin: no window manager command");
    let launcher_args: Vec<String> = args.collect();

    //loop
    {
        let user_lock = Arc::new(Mutex::new(String::new()));
        let pass_lock = Arc::new(Mutex::new(String::new()));

        {
            let mut issue_string = String::new();
            if let Ok(mut issue_file) = File::open("/etc/issue") {
                let _ = issue_file.read_to_string(&mut issue_string);
            }

            let issue = issue_string.trim();

            let issue_height = issue.lines().count() as u32 * 16;
            let window_height = 140 + issue_height + if issue_height > 0 { 16 } else { 0 };

            let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
            let mut window = Window::new(Rect::new((width as i32 - 576)/2, (height as i32 - window_height as i32)/2, 576, window_height), "Orbital Login");

            let mut y = 8;

            if ! issue.is_empty() {
                let label = Label::new();
                label.text(issue)
                    .text_offset(4, 4)
                    .position(8, y)
                    .size(560, issue_height + 8);
                //TODO: Put inset color into theme
                label.bg.set(orbclient::Color { data: 0xFFEFF1F2 });
                label.border.set(true);
                label.border_radius.set(2);
                window.add(&label);

                y += issue_height as i32 + 16;
            }

            let label = Label::new();
            label.text("Username")
                .position(8, y)
                .size(560, 16);
            window.add(&label);
            y += 16;

            let user_text_box = TextBox::new();
            user_text_box.position(8, y)
                .size(560, 24)
                .text_offset(4, 4)
                .grab_focus(true);
            window.add(&user_text_box);
            y += 24;

            y += 8;

            let label = Label::new();
            label.text("Password")
                .position(8, y)
                .size(560, 16);
            window.add(&label);
            y += 16;

            let pass_text_box = TextBox::new();
            pass_text_box.position(8, y)
                .size(560, 24)
                .text_offset(4, 4)
                .mask_char(Some('*'));
            window.add(&pass_text_box);
            y += 24;

            // Pressing enter in user text box will transfer focus to password text box
            {
                let pass_text_box = pass_text_box.clone();
                user_text_box.on_enter(move |_| {
                    pass_text_box.grab_focus.set(true);
                });
            }

            // Pressing enter in password text box will try to login
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let user_text_box = user_text_box.clone();
                let window_login = &mut window as *mut Window;
                pass_text_box.on_enter(move |me: &TextBox| {
                    println!("Login {}", user_text_box.text.get());
                    *user_lock.lock().unwrap() = user_text_box.text.get();
                    *pass_lock.lock().unwrap() = me.text.get();
                    unsafe { (&mut *window_login).close(); }
                });
            }

            y += 8;

            // Add a login button
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let window_login = &mut window as *mut Window;
                let button = Button::new();
                button.position(8, y)
                    .size(560, 28)
                    .text("Login")
                    .text_offset(6, 6)
                    .on_click(move |_button: &Button, _point: Point| {
                        *user_lock.lock().unwrap() = user_text_box.text.get();
                        *pass_lock.lock().unwrap() = pass_text_box.text.get();
                        unsafe { (&mut *window_login).close(); }
                    });
                window.add(&button);
            }

            window.exec();
        }

        let user = user_lock.lock().unwrap().clone();
        let pass = pass_lock.lock().unwrap().clone();
        if ! user.is_empty() {
            let mut passwd_string = String::new();
            File::open("/etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap();

            let mut passwd_option = None;
            for line in passwd_string.lines() {
                if let Ok(passwd) = Passwd::parse(line) {
                    if user == passwd.user && "" == passwd.hash {
                        passwd_option = Some(passwd);
                        break;
                    }
                }
            }

            if passwd_option.is_none() {
                for line in passwd_string.lines() {
                    if let Ok(passwd) = Passwd::parse(line) {
                        if user == passwd.user && passwd.verify(&pass) {
                            passwd_option = Some(passwd);
                            break;
                        }
                    }
                }
            }

            if let Some(passwd) = passwd_option {
                let mut command = Command::new(&launcher_cmd);
                for arg in launcher_args.iter() {
                    command.arg(&arg);
                }

                command.uid(passwd.uid);
                command.gid(passwd.gid);

                command.current_dir(passwd.home);

                command.env("USER", &user);
                command.env("UID", format!("{}", passwd.uid));
                command.env("GROUPS", format!("{}", passwd.gid));
                command.env("HOME", passwd.home);
                command.env("SHELL", passwd.shell);

                match command.spawn() {
                    Ok(mut child) => match child.wait() {
                        Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()),
                        Err(err) => panic!("orblogin: failed to wait for '{}': {}", passwd.shell, err)
                    },
                    Err(err) => panic!("orblogin: failed to execute '{}': {}", passwd.shell, err)
                }
            }
        }
    }
}
<commit_msg>Normalize button, inset, and text box<commit_after>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbtk;
extern crate userutils;

use std::{env, str};
use std::fs::File;
use std::io::Read;
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::sync::{Arc, Mutex};

use orbtk::{Button, Label, Point, Rect, TextBox, Window};
use orbtk::traits::{Click, Enter, Place, Text};
use userutils::Passwd;

pub fn main() {
    let mut args = env::args().skip(1);

    let launcher_cmd = args.next().expect("orblogin: no window manager command");
    let launcher_args: Vec<String> = args.collect();

    loop {
        let user_lock = Arc::new(Mutex::new(String::new()));
        let pass_lock = Arc::new(Mutex::new(String::new()));

        {
            let mut issue_string = String::new();
            if let Ok(mut issue_file) = File::open("/etc/issue") {
                let _ = issue_file.read_to_string(&mut issue_string);
            }

            let issue = issue_string.trim();

            let issue_height = issue.lines().count() as u32 * 16;
            let window_height = 148 + issue_height + if issue_height > 0 { 20 } else { 0 };

            let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
            let mut window = Window::new(Rect::new((width as i32 - 576)/2, (height as i32 - window_height as i32)/2, 576, window_height), "Orbital Login");

            let mut y = 8;

            if ! issue.is_empty() {
                let label = Label::new();
                label.text(issue)
                    .text_offset(6, 6)
                    .position(8, y)
                    .size(560, issue_height + 12);
                //TODO: Put inset color into theme
                label.bg.set(orbclient::Color { data: 0xFFEFF1F2 });
                label.border.set(true);
                label.border_radius.set(2);
                window.add(&label);

                y += issue_height as i32 + 20;
            }

            let label = Label::new();
            label.text("Username")
                .position(8, y)
                .size(560, 16);
            window.add(&label);
            y += 16;

            let user_text_box = TextBox::new();
            user_text_box.position(8, y)
                .size(560, 28)
                .text_offset(6, 6)
                .grab_focus(true);
            user_text_box.border_radius.set(2);
            window.add(&user_text_box);
            y += 28;

            y += 8;

            let label = Label::new();
            label.text("Password")
                .position(8, y)
                .size(560, 16);
            window.add(&label);
            y += 16;

            let pass_text_box = TextBox::new();
            pass_text_box.position(8, y)
                .size(560, 28)
                .text_offset(6, 6)
                .mask_char(Some('*'));
            pass_text_box.border_radius.set(2);
            window.add(&pass_text_box);
            y += 28;

            // Pressing enter in user text box will transfer focus to password text box
            {
                let pass_text_box = pass_text_box.clone();
                user_text_box.on_enter(move |_| {
                    pass_text_box.grab_focus.set(true);
                });
            }

            // Pressing enter in password text box will try to login
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let user_text_box = user_text_box.clone();
                let window_login = &mut window as *mut Window;
                pass_text_box.on_enter(move |me: &TextBox| {
                    println!("Login {}", user_text_box.text.get());
                    *user_lock.lock().unwrap() = user_text_box.text.get();
                    *pass_lock.lock().unwrap() = me.text.get();
                    unsafe { (&mut *window_login).close(); }
                });
            }

            y += 8;

            // Add a login button
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let window_login = &mut window as *mut Window;
                let button = Button::new();
                button.position(8, y)
                    .size(560, 28)
                    .text("Login")
                    .text_offset(6, 6)
                    .on_click(move |_button: &Button, _point: Point| {
                        *user_lock.lock().unwrap() = user_text_box.text.get();
                        *pass_lock.lock().unwrap() = pass_text_box.text.get();
                        unsafe { (&mut *window_login).close(); }
                    });
                window.add(&button);
            }

            window.exec();
        }

        let user = user_lock.lock().unwrap().clone();
        let pass = pass_lock.lock().unwrap().clone();
        if ! user.is_empty() {
            let mut passwd_string = String::new();
            File::open("/etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap();

            let mut passwd_option = None;
            for line in passwd_string.lines() {
                if let Ok(passwd) = Passwd::parse(line) {
                    if user == passwd.user && "" == passwd.hash {
                        passwd_option = Some(passwd);
                        break;
                    }
                }
            }

            if passwd_option.is_none() {
                for line in passwd_string.lines() {
                    if let Ok(passwd) = Passwd::parse(line) {
                        if user == passwd.user && passwd.verify(&pass) {
                            passwd_option = Some(passwd);
                            break;
                        }
                    }
                }
            }

            if let Some(passwd) = passwd_option {
                let mut command = Command::new(&launcher_cmd);
                for arg in launcher_args.iter() {
                    command.arg(&arg);
                }

                command.uid(passwd.uid);
                command.gid(passwd.gid);

                command.current_dir(passwd.home);

                command.env("USER", &user);
                command.env("UID", format!("{}", passwd.uid));
                command.env("GROUPS", format!("{}", passwd.gid));
                command.env("HOME", passwd.home);
                command.env("SHELL", passwd.shell);

                match command.spawn() {
                    Ok(mut child) => match child.wait() {
                        Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()),
                        Err(err) => panic!("orblogin: failed to wait for '{}': {}", passwd.shell, err)
                    },
                    Err(err) => panic!("orblogin: failed to execute '{}': {}", passwd.shell, err)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate rustc_serialize;

use std::collections::HashMap;

fn init_db_reader(path: &str) -> Reader<File> {
    let rdr = csv::Reader::from_file(path).unwrap();
    rdr
}

fn load_db(path: &str) {
    let rdr = csv::Reader::from_file(path).has_headers(true).unwrap();
    let mut ratings: HashMap<u32, HashMap<String, u32>> = HashMap::new();

    // let mut i = 0;
    for record in rdr.decode() {
        // if i > 54000 {
        //     break;
        // }
        // i += 1;
        let rating: Rating = record.unwrap();

        match ratings.entry(rating.user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(rating.book_isbn, rating.rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(rating.book_isbn, rating.rating);
            }
        }
    }

}

fn main() {
    let db = load_db("./data/ratings.csv");
    println!("Hello, world!");
}

// #[derive(Debug)]
// struct Database {
//     headers: HashMap<String, u32>,
//     names: HashMap<String, u32>,
//     records: Vec<f32>,
// }

// impl Database {
//     fn new(path: &str) {
//         let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(true);
//         let mut i = 0;
//         for record in rdr.decode() {
//             i+=1;
//         }
//         println!("{}", i);
//     }
// }<commit_msg>Finished load DB<commit_after>extern crate csv;
extern crate rustc_serialize;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

struct MovieDB(HashMap<u32, HashMap<u32, f32>>, HashMap<u32, HashMap<u32, f32>>);

fn item_based_prediction(name: u32, feature: u32) -> f32 {

}

fn load_db(path: &str) -> MovieDB {
    let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(true);
    let mut ratings: HashMap<u32, HashMap<u32, f32>> = HashMap::new();
    let mut features: HashMap<u32, HashMap<u32, f32>> = HashMap::new();

    for record in rdr.decode() {
        let (user_id, movie_id, rating): (u32, u32, f32) = record.unwrap();

        match ratings.entry(user_id) {
            Vacant(entry) => {
                let mut user_ratings = HashMap::new();
                user_ratings.insert(movie_id, rating);
                entry.insert(user_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(movie_id, rating);
            }
        }

        match features.entry(movie_id) {
            Vacant(entry) => {
                let mut movie_ratings = HashMap::new();
                movie_ratings.insert(user_id, rating);
                entry.insert(movie_ratings);
            }
            Occupied(entry) => {
                entry.into_mut().insert(user_id, rating);
            }
        }
    }

    MovieDB(ratings, features)
}

fn main() {
    let db = load_db("./data/ratings.csv");

    println!("Hello, world!");
}

// #[derive(Debug)]
// struct Database {
//     headers: HashMap<String, u32>,
//     names: HashMap<String, u32>,
//     records: Vec<f32>,
// }

// impl Database {
//     fn new(path: &str) {
//         let mut rdr = csv::Reader::from_file(path).unwrap().has_headers(true);
//         let mut i = 0;
//         for record in rdr.decode() {
//             i+=1;
//         }
//         println!("{}", i);
//     }
// }<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject};

pub type JSJitPropertyOp = *const u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
}

//pub type JSJitInfo = JSJitInfo_struct;

pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::uintptr_t;

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *const JSClass,
                                          proto: *const JSObject, parent: *const JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;
    }
}
<commit_msg>Add JS_WrapPropertyDescriptor.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSContext, JSObject, JSPropertyDescriptor, JSBool};

pub type JSJitPropertyOp = *const u8;

pub struct JSJitInfo {
    pub op: JSJitPropertyOp,
    pub protoID: u32,
    pub depth: u32,
    pub isInfallible: bool,
    pub isConstant: bool
}

extern {
pub fn JS_ObjectToOuterObject(cx: *mut JSContext,
                              obj: *mut JSObject) -> *mut JSObject;
pub fn JS_WrapPropertyDescriptor(cx: *mut JSContext,
                                 desc: *mut JSPropertyDescriptor) -> JSBool;
}

//pub type JSJitInfo = JSJitInfo_struct;

pub mod bindgen {
    use jsapi::{JSContext, JSObject, JSClass, JSRuntime};
    use libc::uintptr_t;

    extern {
        pub fn JS_NewObjectWithUniqueType(cx: *mut JSContext, clasp: *const JSClass,
                                          proto: *const JSObject, parent: *const JSObject) -> *mut JSObject;
        pub fn JS_GetAddressableObject(rt: *mut JSRuntime, candidateObj: uintptr_t) -> *mut JSObject;
    }
}
<|endoftext|>