<commit_before>mod edit;
mod error;
mod filter;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::Path;
use std::process::{self, Command, Stdio};

use atty::Stream::{Stderr, Stdout};
use prettyprint::{PagingMode, PrettyPrinter};
use quote::quote;
use structopt::StructOpt;

use crate::error::Result;
use crate::opts::{Args, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();

    if let Some(item) = &args.item {
        if args.ugly {
            eprintln!("ERROR: cannot expand single item ({}) in ugly mode.", item);
            return Ok(1);
        }
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "ERROR: rustc produced no expanded output"
        );
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    let which_rustfmt = match args.ugly {
        false => which("rustfmt"),
        true => None,
    };
    if let Some(fmt) = which_rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::remove_macro_rules(&mut syntax_tree);
            if let Some(filter) = args.item {
                filter::filter(&mut syntax_tree, filter);
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        // Ignore any errors.
        let _status = Command::new(fmt)
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .status();

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let do_color = match args.color.as_ref().map(String::as_str) {
        Some("always") => true,
        Some("never") => false,
        None | Some("auto") | Some(_) => atty::is(Stdout),
    };
    if do_color {
        if content.ends_with('\n') {
            // Pretty printer seems to print an extra trailing newline.
            content.truncate(content.len() - 1);
        }
        let printer = PrettyPrinter::default()
            .header(false)
            .grid(false)
            .line_numbers(false)
            .language("rust")
            .paging_mode(PagingMode::Never)
            .build()
            .unwrap();

        // Ignore any errors.
        let _ = printer.string(content);
    } else {
        let _ = write!(&mut io::stdout(), "{}", content);
    }

    Ok(0)
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, outfile: &Path) {
    cmd.arg("rustc");
    cmd.arg("--profile=check");

    if let Some(features) = &args.features {
        cmd.arg("--features");
        cmd.arg(features);
    }

    if args.all_features {
        cmd.arg("--all-features");
    }

    if args.no_default_features {
        cmd.arg("--no-default-features");
    }

    if args.lib {
        cmd.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        cmd.arg("--bin");
        cmd.arg(bin);
    }

    if let Some(example) = &args.example {
        cmd.arg("--example");
        cmd.arg(example);
    }

    if let Some(test) = &args.test {
        cmd.arg("--test");
        cmd.arg(test);
    }

    if let Some(bench) = &args.bench {
        cmd.arg("--bench");
        cmd.arg(bench);
    }

    if let Some(target) = &args.target {
        cmd.arg("--target");
        cmd.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        cmd.arg("--target-dir");
        cmd.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        cmd.arg("--manifest-path");
        cmd.arg(manifest_path);
    }

    if let Some(jobs) = args.jobs {
        cmd.arg("--jobs");
        cmd.arg(jobs.to_string());
    }

    cmd.arg("--color");
    if let Some(color) = &args.color {
        cmd.arg(color);
    } else {
        cmd.arg(if atty::is(Stderr) { "always" } else { "never" });
    }

    if args.frozen {
        cmd.arg("--frozen");
    }

    if args.locked {
        cmd.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        cmd.arg("-Z");
        cmd.arg(unstable_flag);
    }

    cmd.arg("--");
    cmd.arg("-o");
    cmd.arg(outfile);
    cmd.arg("-Zunstable-options");
    cmd.arg("--pretty=expanded");
}

fn which(cmd: &str) -> Option<OsString> {
    if env::args_os().any(|arg| arg == *"--help") {
        return None;
    }

    if let Some(which) = env::var_os(&cmd.to_uppercase()) {
        return if which.is_empty() { None } else { Some(which) };
    }

    let spawn = Command::new(cmd)
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd.into())
    } else {
        None
    }
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<commit_msg>Add error message for single item without rustfmt<commit_after>mod edit;
mod error;
mod filter;
mod opts;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, BufRead, Write};
use std::path::Path;
use std::process::{self, Command, Stdio};

use atty::Stream::{Stderr, Stdout};
use prettyprint::{PagingMode, PrettyPrinter};
use quote::quote;
use structopt::StructOpt;

use crate::error::Result;
use crate::opts::{Args, Opts};

fn main() {
    let result = cargo_expand_or_run_nightly();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

fn cargo_expand_or_run_nightly() -> Result<i32> {
    const NO_RUN_NIGHTLY: &str = "CARGO_EXPAND_NO_RUN_NIGHTLY";

    let maybe_nightly = !definitely_not_nightly();
    if maybe_nightly || env::var_os(NO_RUN_NIGHTLY).is_some() {
        return cargo_expand();
    }

    let mut nightly = Command::new("cargo");
    nightly.arg("+nightly");
    nightly.arg("expand");

    let mut args = env::args_os().peekable();
    args.next().unwrap(); // cargo
    if args.peek().map_or(false, |arg| arg == "expand") {
        args.next().unwrap(); // expand
    }
    nightly.args(args);

    // Hopefully prevent infinite re-run loop.
    nightly.env(NO_RUN_NIGHTLY, "");

    let status = nightly.status()?;

    Ok(match status.code() {
        Some(code) => code,
        None => {
            if status.success() {
                0
            } else {
                1
            }
        }
    })
}

fn definitely_not_nightly() -> bool {
    let mut cmd = Command::new(cargo_binary());
    cmd.arg("--version");

    let output = match cmd.output() {
        Ok(output) => output,
        Err(_) => return false,
    };

    let version = match String::from_utf8(output.stdout) {
        Ok(version) => version,
        Err(_) => return false,
    };

    version.starts_with("cargo 1") && !version.contains("nightly")
}

fn cargo_binary() -> OsString {
    env::var_os("CARGO").unwrap_or_else(|| "cargo".to_owned().into())
}

fn cargo_expand() -> Result<i32> {
    let Opts::Expand(args) = Opts::from_args();

    let which_rustfmt;
    match (&args.item, args.ugly) {
        (Some(item), true) => {
            eprintln!("ERROR: cannot expand single item ({}) in ugly mode.", item);
            return Ok(1);
        }
        (Some(item), false) => {
            which_rustfmt = which("rustfmt");
            if which_rustfmt.is_none() {
                eprintln!("ERROR: cannot expand single item ({}) without rustfmt.", item);
                eprintln!("Install rustfmt by running `rustup component add rustfmt`.");
                return Ok(1);
            }
        }
        (None, true) => which_rustfmt = None,
        (None, false) => which_rustfmt = which("rustfmt"),
    }

    let mut builder = tempfile::Builder::new();
    builder.prefix("cargo-expand");
    let outdir = builder.tempdir().expect("failed to create tmp file");
    let outfile_path = outdir.path().join("expanded");

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    apply_args(&mut cmd, &args, &outfile_path);
    let code = filter_err(&mut cmd, ignore_cargo_err)?;

    let mut content = fs::read_to_string(&outfile_path)?;
    if content.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "ERROR: rustc produced no expanded output"
        );
        return Ok(if code == 0 { 1 } else { code });
    }

    // Run rustfmt
    if let Some(fmt) = which_rustfmt {
        // Work around rustfmt not being able to parse paths containing $crate.
        // This placeholder should be the same width as $crate to preserve
        // alignments.
        const DOLLAR_CRATE_PLACEHOLDER: &str = "Ξcrate";
        content = content.replace("$crate", DOLLAR_CRATE_PLACEHOLDER);

        // Discard comments, which are misplaced by the compiler
        if let Ok(mut syntax_tree) = syn::parse_file(&content) {
            edit::remove_macro_rules(&mut syntax_tree);
            if let Some(filter) = args.item {
                filter::filter(&mut syntax_tree, filter);
            }
            content = quote!(#syntax_tree).to_string();
        }
        fs::write(&outfile_path, content)?;

        // Ignore any errors.
        let _status = Command::new(fmt)
            .arg(&outfile_path)
            .stderr(Stdio::null())
            .status();

        content = fs::read_to_string(&outfile_path)?;
        content = content.replace(DOLLAR_CRATE_PLACEHOLDER, "$crate");
    }

    // Run pretty printer
    let do_color = match args.color.as_ref().map(String::as_str) {
        Some("always") => true,
        Some("never") => false,
        None | Some("auto") | Some(_) => atty::is(Stdout),
    };
    if do_color {
        if content.ends_with('\n') {
            // Pretty printer seems to print an extra trailing newline.
            content.truncate(content.len() - 1);
        }
        let printer = PrettyPrinter::default()
            .header(false)
            .grid(false)
            .line_numbers(false)
            .language("rust")
            .paging_mode(PagingMode::Never)
            .build()
            .unwrap();

        // Ignore any errors.
        let _ = printer.string(content);
    } else {
        let _ = write!(&mut io::stdout(), "{}", content);
    }

    Ok(0)
}

// Based on https://github.com/rsolomo/cargo-check
fn apply_args(cmd: &mut Command, args: &Args, outfile: &Path) {
    cmd.arg("rustc");
    cmd.arg("--profile=check");

    if let Some(features) = &args.features {
        cmd.arg("--features");
        cmd.arg(features);
    }

    if args.all_features {
        cmd.arg("--all-features");
    }

    if args.no_default_features {
        cmd.arg("--no-default-features");
    }

    if args.lib {
        cmd.arg("--lib");
    }

    if let Some(bin) = &args.bin {
        cmd.arg("--bin");
        cmd.arg(bin);
    }

    if let Some(example) = &args.example {
        cmd.arg("--example");
        cmd.arg(example);
    }

    if let Some(test) = &args.test {
        cmd.arg("--test");
        cmd.arg(test);
    }

    if let Some(bench) = &args.bench {
        cmd.arg("--bench");
        cmd.arg(bench);
    }

    if let Some(target) = &args.target {
        cmd.arg("--target");
        cmd.arg(target);
    }

    if let Some(target_dir) = &args.target_dir {
        cmd.arg("--target-dir");
        cmd.arg(target_dir);
    }

    if let Some(manifest_path) = &args.manifest_path {
        cmd.arg("--manifest-path");
        cmd.arg(manifest_path);
    }

    if let Some(jobs) = args.jobs {
        cmd.arg("--jobs");
        cmd.arg(jobs.to_string());
    }

    cmd.arg("--color");
    if let Some(color) = &args.color {
        cmd.arg(color);
    } else {
        cmd.arg(if atty::is(Stderr) { "always" } else { "never" });
    }

    if args.frozen {
        cmd.arg("--frozen");
    }

    if args.locked {
        cmd.arg("--locked");
    }

    for unstable_flag in &args.unstable_flags {
        cmd.arg("-Z");
        cmd.arg(unstable_flag);
    }

    cmd.arg("--");
    cmd.arg("-o");
    cmd.arg(outfile);
    cmd.arg("-Zunstable-options");
    cmd.arg("--pretty=expanded");
}

fn which(cmd: &str) -> Option<OsString> {
    if env::args_os().any(|arg| arg == *"--help") {
        return None;
    }

    if let Some(which) = env::var_os(&cmd.to_uppercase()) {
        return if which.is_empty() { None } else { Some(which) };
    }

    let spawn = Command::new(cmd)
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd.into())
    } else {
        None
    }
}

fn filter_err(cmd: &mut Command, ignore: fn(&str) -> bool) -> io::Result<i32> {
    let mut child = cmd.stderr(Stdio::piped()).spawn()?;
    let mut stderr = io::BufReader::new(child.stderr.take().unwrap());
    let mut line = String::new();
    while let Ok(n) = stderr.read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    let code = child.wait()?.code().unwrap_or(1);
    Ok(code)
}

fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag",
        "ignoring -C extra-filename flag due to -o flag",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<|endoftext|>


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

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "{ git = \"https://github.com/intecture/api\" }";
const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_v: bool,
    flag_verbose: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

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

    if let Err(e) = run(&args) {
        println!("{}", e);

        if args.flag_v || args.flag_verbose {
            println!("{:?}", e);
        }

        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        let status = try!(project.run(&args_deref));

        if !status.success() {
            exit(status.code().unwrap_or(1));
        }
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let mut auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }

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

extern crate czmq;
extern crate docopt;
extern crate inapi;
extern crate rustc_serialize;
#[cfg(test)]
extern crate tempdir;
extern crate time;
extern crate zdaemon;

mod auth;
mod cert;
mod error;
mod language;
mod payload;
mod project;

use auth::Auth;
use docopt::Docopt;
use error::Result;
use language::language_from_str;
use payload::Payload;
use project::Project;
use std::{env, io};
use std::path::Path;
use std::process::exit;

const API_VERSION: &'static str = "{ git = \"https://github.com/intecture/api\" }";
const VERSION: &'static str = "0.2.1";

static USAGE: &'static str = "
Intecture CLI.

Usage:
  incli run [<arg>...]
  incli project init <name> <lang>
  incli payload init <name> <lang>
  incli payload build [<names>...]
  incli host (add | delete | bootstrap) [(-s | --silent)] <hostname>
  incli host list
  incli user (add | delete) [(-s | --silent)] <username>
  incli user list
  incli (-h | --help)
  incli --version

Options:
  -h --help     Show this screen.
  -s --silent   Save private key instead of printing it.
  -v --verbose  Verbose output.
  --version     Show version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    cmd_add: bool,
    cmd_bootstrap: bool,
    cmd_build: bool,
    cmd_delete: bool,
    cmd_host: bool,
    cmd_init: bool,
    cmd_list: bool,
    cmd_payload: bool,
    cmd_project: bool,
    cmd_run: bool,
    cmd_user: bool,
    flag_h: bool,
    flag_help: bool,
    flag_s: bool,
    flag_silent: bool,
    flag_version: bool,
    arg_arg: Vec<String>,
    arg_hostname: String,
    arg_lang: String,
    arg_name: String,
    arg_names: Option<Vec<String>>,
    arg_username: String,
}

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

    if let Err(e) = run(&args) {
        println!("{}", e);
        println!("{:?}", e);
        exit(1);
    }
}

fn run(args: &Args) -> Result<()> {
    if args.flag_version {
        println!("{}", VERSION);
    }
    else if args.cmd_run {
        let project = try!(Project::load(&mut env::current_dir().unwrap()));
        let args_deref: Vec<&str> = args.arg_arg.iter().map(AsRef::as_ref).collect();
        let status = try!(project.run(&args_deref));

        if !status.success() {
            exit(status.code().unwrap_or(1));
        }
    }
    else if args.cmd_project && args.cmd_init {
        try!(Project::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
    }
    else if args.cmd_payload {
        if args.cmd_init {
            try!(Payload::create(&Path::new(&args.arg_name), try!(language_from_str(&args.arg_lang))));
        }
        else if args.cmd_build {
            let payloads = if let Some(ref names) = args.arg_names {
                let n: Vec<&str> = names.iter().map(|n| &**n).collect();
                try!(Payload::find(".", Some(&*n)))
            } else {
                try!(Payload::find(".", None))
            };
            for payload in payloads {
                try!(payload.build());
            }
        }
    }
    else if args.cmd_host || args.cmd_user {
        let cert_type = if args.cmd_host { "host" } else { "user" };
        let name = if args.cmd_host { &args.arg_hostname } else { &args.arg_username };

        let mut auth = try!(Auth::new(&env::current_dir().unwrap()));

        if args.cmd_add {
            let cert = try!(auth.add(cert_type, name));
            if args.flag_s || args.flag_silent {
                try!(cert.save_secret(&format!("{}.crt", name)));
            } else {
                println!("Please distribute this certificate securely.

------------------------COPY BELOW THIS LINE-------------------------
{}
------------------------COPY ABOVE THIS LINE-------------------------", cert.secret());
            }
        }
        else if args.cmd_delete {
            if args.flag_s || args.flag_silent {
                try!(auth.delete(name));
            } else {
                println!("Are you sure you want to delete this certificate?");
                loop {
                    println!("Please enter [y/n]: ");
                    let mut input = String::new();
                    match io::stdin().read_line(&mut input) {
                        Ok(_) => match { input.as_ref() as &str }.trim() {
                            "y" => {
                                try!(auth.delete(name));
                                break;
                            },
                            "n" => break,
                            _ => (),
                        },
                        Err(e) => {
                            println!("Stdin error: {}", e);
                            exit(1);
                        },
                    }
                }
            }
        }
        else if args.cmd_list {
            let names = try!(auth.list(cert_type));

            for name in names {
                println!("{}", name);
            }
        }
        else if args.cmd_bootstrap && args.cmd_host {
            unimplemented!();
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate diesel;

#[macro_use]
extern crate lazy_static;

mod db;
mod homectl_core;
mod integrations;
mod utils;

// use db::{actions::find_floorplans, establish_connection};
use anyhow::{Context, Result};
use async_std::{prelude::*, task};
use homectl_core::{
    devices::Devices,
    events::*,
    groups::Groups,
    integration::IntegrationActionDescriptor,
    integrations::Integrations,
    rules::Rules,
    scene::{CycleScenesDescriptor, SceneDescriptor},
    scenes::Scenes,
};
use std::error::Error;

#[derive(Clone)]
struct State {
    integrations: Integrations,
    groups: Groups,
    scenes: Scenes,
    devices: Devices,
    rules: Rules,
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let (config, opaque_integrations_configs) = homectl_core::config::read_config()?;

    // println!("Using config:");
    // println!("{:#?}", config);

    let (sender, mut receiver) = mk_channel();

    let mut integrations = Integrations::new(sender.clone());
    let groups = Groups::new(config.groups);
    let scenes = Scenes::new(config.scenes, groups);
    let devices = Devices::new(sender.clone(), scenes);
    let rules = Rules::new(config.routines, sender.clone());

    for (id, integration_config) in &config.integrations {
        let opaque_integration_config: &config::Value = opaque_integrations_configs
            .get(id)
            .with_context(|| format!("Expected to find config for integration with id {}", id))?;

        integrations
            .load_integration(&integration_config.plugin, id, opaque_integration_config)
            .await?;
    }

    let _: Result<()> = {
        integrations.run_register_pass().await?;
        integrations.run_start_pass().await?;

        Ok(())
    };

    // let state = State {
    //     integrations: Arc::new(Mutex::new(integrations)),
    //     groups,
    //     scenes,
    //     devices: Arc::new(Mutex::new(devices)),
    //     rules: Arc::new(Mutex::new(rules)),
    // };

    loop {
        let msg = receiver
            .next()
            .await
            .expect("Expected sender end of channel to never be dropped");

        // println!("got msg: {:#?}", msg);

        // TODO: Need to figure out a way of not locking such large chunks of
        // state across .await points

        // let state = state.clone();

        // Maybe instead of cloning all these structs we should pass state
        // around in an Arc<Mutex<>> and only lock it when necessary
        let mut devices = devices.clone();
        let rules = rules.clone();
        let mut integrations = integrations.clone();

        task::spawn(async move {
            let result: Result<()> = match &msg {
                Message::IntegrationDeviceRefresh { device } => {
                    devices.handle_integration_device_refresh(device).await;
                    Ok(())
                }
                Message::DeviceUpdate {
                    old_state,
                    new_state,
                    old,
                    new,
                } => {
                    rules
                        .handle_device_update(old_state, new_state, old, new)
                        .await;

                    Ok(())
                }
                Message::SetDeviceState { device, set_scene } => {
                    devices.set_device_state(&device, *set_scene).await;

                    Ok(())
                }
                Message::SetIntegrationDeviceState { device } => {
                    integrations.set_integration_device_state(&device).await
                }
                Message::ActivateScene(SceneDescriptor { scene_id }) => {
                    devices.activate_scene(&scene_id).await;

                    Ok(())
                }
                Message::CycleScenes(CycleScenesDescriptor { scenes }) => {
                    devices.cycle_scenes(&scenes).await;

                    Ok(())
                }
                Message::RunIntegrationAction(IntegrationActionDescriptor {
                    integration_id,
                    payload,
                }) => {
                    integrations
                        .run_integration_action(integration_id, payload)
                        .await
                }
            };

            if let Err(err) = result {
                println!("Error while handling message:");
                println!("Msg: {:#?}", msg);
                println!("Error: {:#?}", err);
            }
        });
    }
}
<commit_msg>Clone only structs necessary for handling msg<commit_after>#[macro_use]
extern crate diesel;

#[macro_use]
extern crate lazy_static;

mod db;
mod homectl_core;
mod integrations;
mod utils;

// use db::{actions::find_floorplans, establish_connection};
use anyhow::{Context, Result};
use async_std::{prelude::*, task};
use homectl_core::{
    devices::Devices,
    events::*,
    groups::Groups,
    integration::IntegrationActionDescriptor,
    integrations::Integrations,
    rules::Rules,
    scene::{CycleScenesDescriptor, SceneDescriptor},
    scenes::Scenes,
};
use std::{error::Error, sync::Arc};

#[derive(Clone)]
struct State {
    integrations: Integrations,
    groups: Groups,
    scenes: Scenes,
    devices: Devices,
    rules: Rules,
}

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let (config, opaque_integrations_configs) = homectl_core::config::read_config()?;

    // println!("Using config:");
    // println!("{:#?}", config);

    let (sender, mut receiver) = mk_channel();

    let mut integrations = Integrations::new(sender.clone());
    let groups = Groups::new(config.groups);
    let scenes = Scenes::new(config.scenes, groups.clone());
    let devices = Devices::new(sender.clone(), scenes.clone());
    let rules = Rules::new(config.routines, sender.clone());

    for (id, integration_config) in &config.integrations {
        let opaque_integration_config: &config::Value = opaque_integrations_configs
            .get(id)
            .with_context(|| format!("Expected to find config for integration with id {}", id))?;

        integrations
            .load_integration(&integration_config.plugin, id, opaque_integration_config)
            .await?;
    }

    let _: Result<()> = {
        integrations.run_register_pass().await?;
        integrations.run_start_pass().await?;

        Ok(())
    };

    let state = State {
        integrations,
        groups,
        scenes,
        devices,
        rules,
    };

    let state = Arc::new(state);

    loop {
        let msg = receiver
            .next()
            .await
            .expect("Expected sender end of channel to never be dropped");

        // println!("got msg: {:#?}", msg);

        // TODO: Need to figure out a way of not locking such large chunks of
        // state across .await points

        // let state = state.clone();

        // Maybe instead of cloning all these structs we should pass state
        // around to functions in an Arc<Mutex<>> and only lock it when
        // necessary
        let state = Arc::clone(&state);

        task::spawn(async move {
            let result: Result<()> = match &msg {
                Message::IntegrationDeviceRefresh { device } => {
                    let mut devices = state.devices.clone();
                    devices.handle_integration_device_refresh(device).await;
                    Ok(())
                }
                Message::DeviceUpdate {
                    old_state,
                    new_state,
                    old,
                    new,
                } => {
                    state.rules
                        .handle_device_update(old_state, new_state, old, new)
                        .await;

                    Ok(())
                }
                Message::SetDeviceState { device, set_scene } => {
                    let mut devices = state.devices.clone();
                    devices.set_device_state(&device, *set_scene).await;

                    Ok(())
                }
                Message::SetIntegrationDeviceState { device } => {
                    let mut integrations = state.integrations.clone();
                    integrations.set_integration_device_state(&device).await
                }
                Message::ActivateScene(SceneDescriptor { scene_id }) => {
                    let mut devices = state.devices.clone();
                    devices.activate_scene(&scene_id).await;

                    Ok(())
                }
                Message::CycleScenes(CycleScenesDescriptor { scenes }) => {
                    let mut devices = state.devices.clone();
                    devices.cycle_scenes(&scenes).await;

                    Ok(())
                }
                Message::RunIntegrationAction(IntegrationActionDescriptor {
                    integration_id,
                    payload,
                }) => {
                    let mut integrations = state.integrations.clone();
                    integrations
                        .run_integration_action(integration_id, payload)
                        .await
                }
            };

            if let Err(err) = result {
                println!("Error while handling message:");
                println!("Msg: {:#?}", msg);
                println!("Error: {:#?}", err);
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate rand;
extern crate stopwatch;
use piston_window::*;
use piston_window::types::Color;
use std::f64::consts::PI;
use std::f64;
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use rand::{thread_rng, Rng};
use stopwatch::Stopwatch;
enum Speed {
    Go { scala: f64 },
    None,
}
enum Side {
    None,
    Center,
    Up,
    Down,
    Right,
    Left,
}
struct Arrow {
    theta: f64,
    sin: f64,
    cos: f64,
}
impl Arrow {
    fn new(theta: f64) -> Self {
        Arrow {
            theta: theta,
            sin: (PI * theta).sin(),
            cos: (PI * theta).cos(),
        }
    }
}
pub struct Object {
    background: (u32, u32),
    current_speed: Speed,
    current_state: (f64, f64),
    size: (f64, f64),
    spawn: Side,
    arrow: Arrow,
    color: Color,
}
impl Object {
    pub fn new(width: f64, height: f64) -> Self {
        Object {
            background: (0, 0),
            current_state: (0.0, 0.0),
            current_speed: Speed::None,
            size: (width, height),
            spawn: Side::None,
            arrow: Arrow::new(0.0),
            color: [0.0, 0.0, 0.0, 0.0],
        }
    }
    fn set_place(&mut self, r: &RenderArgs) {
        self.background = (r.width, r.height);
    }
    pub fn set_speed(&mut self, scala: f64) {
        self.current_speed = Speed::Go { scala: scala };
    }
    fn set_pos(&mut self, r: &RenderArgs, pos: Side) {
        let position_x = thread_rng().gen_range(0.0, r.width as f64 - self.size.0);
        let position_y = thread_rng().gen_range(0.0, r.height as f64 - self.size.1);
        self.current_state = match pos {
            Side::Up => (position_x, 0.0),
            Side::Right => (r.width as f64 - self.size.0, position_y),
            Side::Down => (position_x, r.height as f64 - self.size.1),
            Side::Left => (0.0, position_y),
            Side::Center => (r.width as f64 / 2.0, r.height as f64 / 2.0),
            _ => panic!("system error"),
        };
        self.spawn = pos;
    }
    pub fn set_color(&mut self, color: Color) {
        self.color = color;
    }
    fn inner_set_pos(&mut self, pos: (f64, f64)) {
        self.current_state = pos;
    }
    pub fn arrow_set(&mut self, theta: f64) {
        self.arrow = Arrow::new(theta);
    }
    fn random_arrow_set(&mut self) {
        let theta = match self.spawn {
            Side::Up => thread_rng().gen_range(0.0, 1.0),
            Side::Right => thread_rng().gen_range(0.5, 1.5),
            Side::Down => thread_rng().gen_range(1.0, 2.0),
            Side::Left => thread_rng().gen_range(-0.5, 0.5),
            Side::Center => thread_rng().gen_range(0.0, 2.0),
            _ => panic!("system error"),
        };
        self.arrow = Arrow::new(theta);
    }
    fn update(&mut self, args: &UpdateArgs) {
        let before_pos = self.current_state;
        match self.current_speed {
            Speed::Go { scala } => {
                self.current_state.0 += scala * self.arrow.cos * args.dt;
                self.current_state.1 += scala * self.arrow.sin * args.dt;
            }
            Speed::None => {}
        };
        if !self.is_wall() {
            self.collide();
            self.inner_set_pos(before_pos);
        }
    }
    fn move_it(&mut self, control: &Button) {
        let theta = match *control {
            Button::Keyboard(key) => {
                match key {
                    Key::Right => 0.0,
                    Key::Left => 1.0,
                    Key::Up => 1.5,
                    Key::Down => 0.5,
                    _ => self.arrow.theta,
                }
            }
            _ => self.arrow.theta,
        };
        self.arrow = Arrow::new(theta);
    }
    fn is_wall(&mut self) -> bool {
        let available_x = self.background.0 as f64 - self.size.0;
        let available_y = self.background.1 as f64 - self.size.1;
        between(0.0, available_x, self.current_state.0) &&
        between(0.0, available_y, self.current_state.1)
    }
    fn collide(&mut self) {
        let available_x = self.background.0 as f64 - self.size.0;
        let available_y = self.background.1 as f64 - self.size.1;
        let before_theta = self.arrow.theta;
        let plane_vec = match (between(0.0, available_x, self.current_state.0),
                               between(0.0, available_y, self.current_state.1)) {
            (false, true) => 1.0,
            (true, false) => 2.0,
            (false, false) => 2.0 * before_theta,
            (true, true) => {
                panic!("system error");
            }
        };
        let mut result = plane_vec - before_theta;
        loop {
            if result <= 0.0 {
                result += 2.0;
                continue;
            } else if result >= 2.0 {
                result -= 2.0;
                continue;
            } else {
                break;
            }
        }
        self.arrow = Arrow::new(result);
    }
    fn is_hit(&self, other: &Object) -> bool {
        let (result_x, result_y) = (self.current_state.0 - other.current_state.0,
                                    self.current_state.1 - other.current_state.1);
        match (result_x < 0.0, result_y < 0.0) {
            (false, false) => result_x <= other.size.0 && result_y <= other.size.1,
            (true, false) => result_x.abs() <= self.size.0 && result_y <= other.size.1,
            (false, true) => result_x <= other.size.0 && result_y.abs() <= self.size.1,
            (true, true) => result_x.abs() <= self.size.0 && result_y.abs() <= self.size.1,
        }
    }
}
fn between(x: f64, y: f64, target: f64) -> bool {
    x <= target && target <= y
}
const MAXINUM: u32 = 150;
const TIME_LIMIT: u64 = 2000;
fn main() {
    let opengls = OpenGL::V4_5;
    let mut window: PistonWindow = WindowSettings::new("machine_dodge", [800, 800])
        .opengl(opengls)
        .exit_on_esc(true)
        .build()
        .unwrap();
    let (tx, rx) = mpsc::channel();
    let mut start: bool = true;
    let mut game_end: bool = false;
    let mut count = 0;
    let mut machine = Object::new(20.0, 20.0);
    let mut obstacles: Vec<Object> = Vec::new();
    let time_limit = Duration::from_millis(TIME_LIMIT);
    let mut sw = Stopwatch::start_new();
    while let Some(e) = window.next() {
        if let Some(r) = e.render_args() {
            if start {
                machine.set_pos(&r, Side::Center);
                machine.set_speed(50.0);
                machine.set_color([0.0, 1.0, 0.0, 1.0]);
                start = false;
            }
            if game_end {
                start = true;
                game_end = false;
                count = 0;
                obstacles.clear();
                let result = sw.elapsed_ms();
                let (t_x, b_x) = (result / 1000, result % 1000);
                println!("THE END \ntime:{}.{}", t_x, b_x);
                sw.restart();
                continue;
            }
            if count < MAXINUM {
                let rng = thread_rng().gen_range(1, 4);
                count += rng;
                for _ in 0..rng {
                    let tx = tx.clone();
                    thread::spawn(move || {
                        let mut obstacle = Object::new(10.0, 10.0);
                        let position = match thread_rng().gen_range(0, 4) {
                            0 => Side::Up,
                            1 => Side::Right,
                            2 => Side::Down,
                            3 => Side::Left,
                            _ => {
                                panic!("system error");
                            }
                        };
                        obstacle.set_pos(&r, position);
                        obstacle.set_speed(30.0);
                        obstacle.set_color([0.0, 0.0, 1.0, 1.0]);
                        obstacle.random_arrow_set();
                        tx.send(obstacle).unwrap();
                    });
                    let temp = match rx.recv_timeout(time_limit) {
                        Ok(result) => result,
                        Err(_) => {
                            panic!("send fail");
                        }
                    };
                    obstacles.push(temp);
                }
            }
            window.draw_2d(&e, |c, g| {
                let transform = c.transform.trans(machine.current_state.0, machine.current_state.1);
                machine.set_place(&r);
                clear([0.0, 0.0, 0.0, 1.0], g);
                Rectangle::new(machine.color).draw([0.0, 0.0, machine.size.0, machine.size.1],
                                                   &c.draw_state,
                                                   transform,
                                                   g);
                for obstacle in obstacles.iter_mut() {
                    let transform = c.transform
                        .trans(obstacle.current_state.0, obstacle.current_state.1);
                    obstacle.set_place(&r);
                    Rectangle::new(obstacle.color)
                        .draw([0.0, 0.0, obstacle.size.0, obstacle.size.1],
                              &c.draw_state,
                              transform,
                              g);
                }
            });
        }
        if let Some(b) = e.press_args() {
            machine.move_it(&b);
        }
        if let Some(u) = e.update_args() {
            machine.update(&u);
            for obstacle in obstacles.iter_mut() {
                {
                    game_end = machine.is_hit(&obstacle);
                    if game_end {
                        break;
                    }
                }
                obstacle.update(&u);
            }
        }
    }
}
<commit_msg>comment the main,rs<commit_after>extern crate piston_window;
extern crate rand;
extern crate stopwatch;
use piston_window::*;
use piston_window::types::Color;
use std::f64::consts::PI;
use std::f64;
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
use rand::{thread_rng, Rng};
use stopwatch::Stopwatch;
// speed of object
enum Speed {
    Go { scala: f64 },
    None,
}
// object spawn side
enum Side {
    None,
    Center,
    Up,
    Down,
    Right,
    Left,
}
// direction of the object
struct Arrow {
    theta: f64,
    sin: f64,
    cos: f64,
}
impl Arrow {
    fn new(theta: f64) -> Self {
        // caculate the sin,cos of the angle
        Arrow {
            theta: theta,
            sin: (PI * theta).sin(),
            cos: (PI * theta).cos(),
        }
    }
}
// object info
pub struct Object {
    // evironment sixe
    background: (u32, u32),
    current_speed: Speed,
    // object's position
    current_state: (f64, f64),
    size: (f64, f64),
    spawn: Side,
    arrow: Arrow,
    color: Color,
}
impl Object {
    pub fn new(width: f64, height: f64) -> Self {
        Object {
            background: (0, 0),
            current_state: (0.0, 0.0),
            current_speed: Speed::None,
            size: (width, height),
            spawn: Side::None,
            arrow: Arrow::new(0.0),
            color: [0.0, 0.0, 0.0, 0.0],
        }
    }
    // set the environment size
    fn set_place(&mut self, r: &RenderArgs) {
        self.background = (r.width, r.height);
    }
    // set object speed
    pub fn set_speed(&mut self, scala: f64) {
        self.current_speed = Speed::Go { scala: scala };
    }
    // this is for setting the spawn postion
    fn set_pos(&mut self, r: &RenderArgs, pos: Side) {
        let position_x = thread_rng().gen_range(0.0, r.width as f64 - self.size.0);
        let position_y = thread_rng().gen_range(0.0, r.height as f64 - self.size.1);
        self.current_state = match pos {
            Side::Up => (position_x, 0.0),
            Side::Right => (r.width as f64 - self.size.0, position_y),
            Side::Down => (position_x, r.height as f64 - self.size.1),
            Side::Left => (0.0, position_y),
            Side::Center => (r.width as f64 / 2.0, r.height as f64 / 2.0),
            _ => panic!("system error"),
        };
        self.spawn = pos;
    }
    // set the object color
    pub fn set_color(&mut self, color: Color) {
        self.color = color;
    }
    // set position for some other function
    fn inner_set_pos(&mut self, pos: (f64, f64)) {
        self.current_state = pos;
    }//set the direction according to angle (theta: 0.0~2.0)
    pub fn arrow_set(&mut self, theta: f64) {
        self.arrow = Arrow::new(theta);
    }
    // set direction for ramdome
    fn random_arrow_set(&mut self) {
        let theta = match self.spawn {
            Side::Up => thread_rng().gen_range(0.0, 1.0),
            Side::Right => thread_rng().gen_range(0.5, 1.5),
            Side::Down => thread_rng().gen_range(1.0, 2.0),
            Side::Left => thread_rng().gen_range(-0.5, 0.5),
            Side::Center => thread_rng().gen_range(0.0, 2.0),
            _ => panic!("system error"),
        };
        self.arrow = Arrow::new(theta);
    }
    // update the current state
    fn update(&mut self, args: &UpdateArgs) {
        let before_pos = self.current_state;
        match self.current_speed {
            Speed::Go { scala } => {
                self.current_state.0 += scala * self.arrow.cos * args.dt;
                self.current_state.1 += scala * self.arrow.sin * args.dt;
            }
            Speed::None => {}
        };
        // if object hit the wall then reflect
        if !self.is_wall() {
            // this is the reflect function
            self.collide();
            // and set the before position
            self.inner_set_pos(before_pos);
        }
    }
    // manage the key control
    fn move_it(&mut self, control: &Button) {
        let theta = match *control {
            Button::Keyboard(key) => {
                match key {
                    Key::Right => 0.0,
                    Key::Left => 1.0,
                    Key::Up => 1.5,
                    Key::Down => 0.5,
                    _ => self.arrow.theta,
                }
            }
            _ => self.arrow.theta,
        };
        self.arrow = Arrow::new(theta);
    }
    // if object goes outside the window then it turns the false
    fn is_wall(&mut self) -> bool {
        let available_x = self.background.0 as f64 - self.size.0;
        let available_y = self.background.1 as f64 - self.size.1;
        between(0.0, available_x, self.current_state.0) &&
        between(0.0, available_y, self.current_state.1)
    }
    // set the new direction according to current position
    fn collide(&mut self) {
        let available_x = self.background.0 as f64 - self.size.0;
        let available_y = self.background.1 as f64 - self.size.1;
        let before_theta = self.arrow.theta;
        let plane_vec = match (between(0.0, available_x, self.current_state.0),
                               between(0.0, available_y, self.current_state.1)) {
            (false, true) => 1.0,
            (true, false) => 2.0,
            (false, false) => 2.0 * before_theta,
            (true, true) => {
                panic!("system error");
            }
        };
        let mut result = plane_vec - before_theta;
        // set theta range in 0.0~2.0
        loop {
            if result <= 0.0 {
                result += 2.0;
                continue;
            } else if result >= 2.0 {
                result -= 2.0;
                continue;
            } else {
                break;
            }
        }
        self.arrow = Arrow::new(result);
    }
    // if object hit with other object then return true
    fn is_hit(&self, other: &Object) -> bool {
        let (result_x, result_y) = (self.current_state.0 - other.current_state.0,
                                    self.current_state.1 - other.current_state.1);
        match (result_x < 0.0, result_y < 0.0) {
            (false, false) => result_x <= other.size.0 && result_y <= other.size.1,
            (true, false) => result_x.abs() <= self.size.0 && result_y <= other.size.1,
            (false, true) => result_x <= other.size.0 && result_y.abs() <= self.size.1,
            (true, true) => result_x.abs() <= self.size.0 && result_y.abs() <= self.size.1,
        }
    }
}
// return treu if target is in the range
fn between(x: f64, y: f64, target: f64) -> bool {
    x <= target && target <= y
}
// MAXINUM number of other particles
const MAXINUM: u32 = 150;
// time limit of channel
const TIME_LIMIT: u64 = 2000;
fn main() {
    let opengls = OpenGL::V4_5;
    // set piston window
    let mut window: PistonWindow = WindowSettings::new("machine_dodge", [800, 800])
        .opengl(opengls)
        .exit_on_esc(true)
        .build()
        .unwrap();
    let (tx, rx) = mpsc::channel();
    let mut start: bool = true;
    let mut game_end: bool = false;
    let mut count = 0;
    // create main object
    let mut machine = Object::new(20.0, 20.0);
    // create other objects
    let mut obstacles: Vec<Object> = Vec::new();
    let time_limit = Duration::from_millis(TIME_LIMIT);
    // start stopwatch
    let mut sw = Stopwatch::start_new();
    // make the eventloop of window
    while let Some(e) = window.next() {
        // rnader the window
        if let Some(r) = e.render_args() {
            if start {
                // setting the main object
                machine.set_pos(&r, Side::Center);
                machine.set_speed(50.0);
                machine.set_color([0.0, 1.0, 0.0, 1.0]);
                start = false;
            }
            // if game is over then run this code and restart
            if game_end {
                start = true;
                game_end = false;
                count = 0;
                obstacles.clear();
                let result = sw.elapsed_ms();
                let (t_x, b_x) = (result / 1000, result % 1000);
                // print the surviving time
                println!("THE END \ntime:{}.{}", t_x, b_x);
                sw.restart();
                continue;
            }
            if count < MAXINUM {
                let rng = thread_rng().gen_range(1, 4);
                count += rng;
                // spawn randome number of obstacles
                for _ in 0..rng {
                    let tx = tx.clone();
                    thread::spawn(move || {
                        let mut obstacle = Object::new(10.0, 10.0);
                        let position = match thread_rng().gen_range(0, 4) {
                            0 => Side::Up,
                            1 => Side::Right,
                            2 => Side::Down,
                            3 => Side::Left,
                            _ => {
                                panic!("system error");
                            }
                        };
                        obstacle.set_pos(&r, position);
                        obstacle.set_speed(30.0);
                        obstacle.set_color([0.0, 0.0, 1.0, 1.0]);
                        obstacle.random_arrow_set();
                        tx.send(obstacle).unwrap();
                    });
                    let temp = match rx.recv_timeout(time_limit) {
                        Ok(result) => result,
                        Err(_) => {
                            panic!("send fail");
                        }
                    };
                    obstacles.push(temp);
                }
            }
            // draw the object
            window.draw_2d(&e, |c, g| {
                // set postion of main object
                let transform = c.transform.trans(machine.current_state.0, machine.current_state.1);
                machine.set_place(&r);
                // clear the background
                clear([0.0, 0.0, 0.0, 1.0], g);
                // draw the rectangle
                Rectangle::new(machine.color).draw([0.0, 0.0, machine.size.0, machine.size.1],
                                                   &c.draw_state,
                                                   transform,
                                                   g);
                for obstacle in obstacles.iter_mut() {
                    // set postion of obstacles
                    let transform = c.transform
                        .trans(obstacle.current_state.0, obstacle.current_state.1);
                    obstacle.set_place(&r);
                    // draw the rectangle
                    Rectangle::new(obstacle.color)
                        .draw([0.0, 0.0, obstacle.size.0, obstacle.size.1],
                              &c.draw_state,
                              transform,
                              g);
                }
            });
        }
        // if there is the press event then run this code
        if let Some(b) = e.press_args() {
            machine.move_it(&b);
        }
        // if there is the update event then run this code
        if let Some(u) = e.update_args() {
            machine.update(&u);
            for obstacle in obstacles.iter_mut() {
                {
                    // compare withe main and obstacles
                    game_end = machine.is_hit(&obstacle);
                    if game_end {
                        break;
                    }
                }
                obstacle.update(&u);
            }
        }
    }
}
<|endoftext|>


<commit_before>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};

extern crate toml;
extern crate rustc_serialize;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::format::Format;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
use std::ascii::AsciiExt;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    let config_content = try!(config::read_config(config_file));
    let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
    debug!("Using config: {:?}!", config);

    let server_config = config.server.unwrap_or_else(ServerConfig::default);
    let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
        Ok(host) => host,
        Err(_) => server_config.host.unwrap_or_else(config::default_host),
    };
    let port_number = match value_t!(matches, "port_number", u16) {
        Ok(port_number) => port_number,
        Err(_) => server_config.port.unwrap_or_else(config::default_port),
    };

    // Initialize Iron's router and pass it to config processing function to define routes
    let mut router = Router::new();
    let mut mount = Mount::new();
    match config.requests {
        Some(requests) => {
            try!(process_config_requests(&requests, &mut mount, &mut router));
        }
        None => return Err(HaxoniteError::NoRequestDefined),
    }
    mount.mount("/", router);

    // Insert logger middlewares before and after router
    let mut chain = Chain::new(mount);
    let format = Format::new(FORMAT);
    let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
    chain.link_before(logger_before);
    chain.link_after(logger_after);

    // Initialize Iron to process requests
    Iron::new(chain).http((host.as_ref(), port_number)).unwrap();
    info!("Haxonite running on port: {}!", port_number);

    Ok(())
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.\n",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.\n",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let content_type = response_config.content_type.unwrap_or_else(config::default_content_type);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, content_type.clone(), response.clone()))
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .value_name("HOST")
            .help("Run Haxonite on the host. Default: localhost.")
            .takes_value(true))
        .arg(Arg::with_name("port_number")
            .short("p")
            .long("port")
            .value_name("PORT")
            .help("Run Haxonite on the specified port. Default: 4000.")
            .takes_value(true))
        .arg(Arg::with_name("config_file")
            .short("c")
            .long("config")
            .value_name("FILE")
            .help("Sets a custom config file. Default: config.toml.")
            .takes_value(true))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<commit_msg>Start Iron in a non-blocking way<commit_after>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, App, SubCommand};

extern crate toml;
extern crate rustc_serialize;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::format::Format;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
use std::ascii::AsciiExt;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    let config_content = try!(config::read_config(config_file));
    let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
    debug!("Using config: {:?}!", config);

    let server_config = config.server.unwrap_or_else(ServerConfig::default);
    let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
        Ok(host) => host,
        Err(_) => server_config.host.unwrap_or_else(config::default_host),
    };
    let port_number = match value_t!(matches, "port_number", u16) {
        Ok(port_number) => port_number,
        Err(_) => server_config.port.unwrap_or_else(config::default_port),
    };

    // Initialize Iron's router and pass it to config processing function to define routes
    let mut router = Router::new();
    let mut mount = Mount::new();
    match config.requests {
        Some(requests) => {
            try!(process_config_requests(&requests, &mut mount, &mut router));
        }
        None => return Err(HaxoniteError::NoRequestDefined),
    }
    mount.mount("/", router);

    // Insert logger middlewares before and after router
    let mut chain = Chain::new(mount);
    let format = Format::new(FORMAT);
    let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
    chain.link_before(logger_before);
    chain.link_after(logger_after);

    // Initialize Iron to process requests
    let _iron = Iron::new(chain).http((host.as_ref(), port_number)).unwrap();
    info!("Haxonite running on port: {}!", port_number);

    Ok(())
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.\n",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.\n",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let content_type = response_config.content_type.unwrap_or_else(config::default_content_type);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, content_type.clone(), response.clone()))
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .value_name("HOST")
            .help("Run Haxonite on the host. Default: localhost.")
            .takes_value(true))
        .arg(Arg::with_name("port_number")
            .short("p")
            .long("port")
            .value_name("PORT")
            .help("Run Haxonite on the specified port. Default: 4000.")
            .takes_value(true))
        .arg(Arg::with_name("config_file")
            .short("c")
            .long("config")
            .value_name("FILE")
            .help("Sets a custom config file. Default: config.toml.")
            .takes_value(true))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<|endoftext|>


<commit_before>#![feature(fs_walk)]
#![feature(path_ext)]

extern crate cronparse;
extern crate libc;
extern crate md5;
extern crate users;

#[macro_use]
extern crate log;
extern crate kernlog;

use std::thread::spawn;
use std::env;
use std::fs::{File, PathExt, create_dir_all};
use std::os::unix::fs::symlink;
use std::io::Write;
use std::path::Path;

use cronparse::crontab::{UserCrontabEntry, SystemCrontabEntry, AnacrontabEntry};

mod generate;
mod process;

include!(concat!(env!("OUT_DIR"), "/config.rs"));
static SYSTEM_CRONTAB_DIR: &'static str = "/etc/cron.d";  // SystemCrontabEntry
static SYSTEM_CRONTAB_FILE: &'static str = "/etc/crontab";
static ANACRONTAB_FILE: &'static str = "/etc/anacrontab";  // AnacrontabEntry
static REBOOT_FILE: &'static str = "/run/crond.reboot";

macro_rules! try_ {
    ($exp:expr) => {
        match $exp {
            Ok(value) => value,
            Err(err) => { error!("{}", err); return; }
        }
    }
}

fn main() {
    log::set_logger(|filter| kernlog::KernelLog::init_level(log::LogLevelFilter::Error, filter)).unwrap();

    let dest_dir = match env::args().nth(1) {
        None => {
            println!("Usage: systemd-crontab-generator <destination-directory>");
            return;
        },
        Some(path) => path
    };

    let s = dest_dir.clone();
    let user_thread = spawn(move || {
        if Path::new(USERS_CRONTAB_DIR).is_dir() {
            process::process_crontab_dir::<UserCrontabEntry, _>(USERS_CRONTAB_DIR, s);
            if let Err(err) = File::create(REBOOT_FILE) {
                warn!("error creating lock file {}: {}", REBOOT_FILE, err);
            }
        } else {
            let cron_after_var_unit_path = Path::new(&*s).join("cron-after-var.service");
            {
                let mut cron_after_var_unit_file = try_!(File::create(&cron_after_var_unit_path));
                try_!(writeln!(cron_after_var_unit_file, r###"[Unit]
Description=Rerun systemd-crontab-generator because /var is a separate mount
Documentation=man:systemd.cron(7)
After=cron.target
ConditionDirectoryNotEmpty={statedir}

[Service]
Type=oneshot
ExecStart=/bin/sh -c "{bindir}/systemctl daemon-reload ; {bindir}/systemctl try-restart cron.target""###,
                    statedir = USERS_CRONTAB_DIR,
                    bindir = BIN_DIR));
            }

            let multiuser_wants_path = Path::new(&*s).join("multi-user.target.wants");
            try_!(create_dir_all(&multiuser_wants_path));
            try_!(symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service")));
        }
    });

    let s = dest_dir.clone();
    let system_thread = spawn(move || {
        process::process_crontab_dir::<SystemCrontabEntry, _>(SYSTEM_CRONTAB_DIR, &s);
        process::process_crontab_file::<SystemCrontabEntry, _, _>(SYSTEM_CRONTAB_FILE, &s);
    });

    let s = dest_dir.clone();
    let anacron_thread = spawn(move || process::process_crontab_file::<AnacrontabEntry, _, _>(ANACRONTAB_FILE, &s));

    let _ = user_thread.join();
    let _ = system_thread.join();
    let _ = anacron_thread.join();
}
<commit_msg>small refactoring<commit_after>#![feature(fs_walk)]
#![feature(path_ext)]

extern crate cronparse;
extern crate libc;
extern crate md5;
extern crate users;

#[macro_use]
extern crate log;
extern crate kernlog;

use std::thread::spawn;
use std::env;
use std::fs::{File, PathExt, create_dir_all};
use std::os::unix::fs::symlink;
use std::io::Write;
use std::path::Path;

use cronparse::crontab::{UserCrontabEntry, SystemCrontabEntry, AnacrontabEntry};

mod generate;
mod process;

include!(concat!(env!("OUT_DIR"), "/config.rs"));
static SYSTEM_CRONTAB_DIR: &'static str = "/etc/cron.d";  // SystemCrontabEntry
static SYSTEM_CRONTAB_FILE: &'static str = "/etc/crontab";
static ANACRONTAB_FILE: &'static str = "/etc/anacrontab";  // AnacrontabEntry
static REBOOT_FILE: &'static str = "/run/crond.reboot";

macro_rules! try_ {
    ($exp:expr) => {
        match $exp {
            Ok(value) => value,
            Err(err) => { error!("{}", err); return; }
        }
    }
}

fn main() {
    log::set_logger(|filter| kernlog::KernelLog::init_level(log::LogLevelFilter::Error, filter)).unwrap();

    let dest_dir = match env::args().nth(1) {
        None => {
            println!("Usage: systemd-crontab-generator <destination-directory>");
            return;
        },
        Some(path) => path
    };

    let s = dest_dir.clone();
    let user_thread = spawn(move || {
        if !Path::new(USERS_CRONTAB_DIR).is_dir() {
            return generate_after_var_unit(&*s);
        }

        process::process_crontab_dir::<UserCrontabEntry, _>(USERS_CRONTAB_DIR, s);
        create_reboot_lock_file();
    });

    let s = dest_dir.clone();
    let system_thread = spawn(move || {
        process::process_crontab_file::<SystemCrontabEntry, _, _>(SYSTEM_CRONTAB_FILE, &s);
        process::process_crontab_dir::<SystemCrontabEntry, _>(SYSTEM_CRONTAB_DIR, &s);
    });

    let s = dest_dir.clone();
    let anacron_thread = spawn(move || {
        process::process_crontab_file::<AnacrontabEntry, _, _>(ANACRONTAB_FILE, &s);
    });

    let _ = user_thread.join();
    let _ = system_thread.join();
    let _ = anacron_thread.join();
}

fn generate_after_var_unit(dest_dir: &str) {
    let cron_after_var_unit_path = Path::new(dest_dir).join("cron-after-var.service");
    let mut cron_after_var_unit_file = try_!(File::create(&cron_after_var_unit_path));
    try_!(writeln!(cron_after_var_unit_file, r###"[Unit]
Description=Rerun systemd-crontab-generator because /var is a separate mount
Documentation=man:systemd.cron(7)
After=cron.target
ConditionDirectoryNotEmpty={statedir}

[Service]
Type=oneshot
ExecStart=/bin/sh -c "{bindir}/systemctl daemon-reload ; {bindir}/systemctl try-restart cron.target""###,
statedir = USERS_CRONTAB_DIR,
bindir = BIN_DIR));

    let multiuser_wants_path = Path::new(dest_dir).join("multi-user.target.wants");
    try_!(create_dir_all(&multiuser_wants_path));
    try_!(symlink(cron_after_var_unit_path, multiuser_wants_path.join("cron-after-var.service")));
}

fn create_reboot_lock_file() {
    if let Err(err) = File::create(REBOOT_FILE) {
        warn!("error creating lock file {}: {}", REBOOT_FILE, err);
    }
}
<|endoftext|>