<commit_before>mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2_commit;
extern crate git2;
extern crate clog;

use docopt::Docopt;
use commit_analyzer::CommitType;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -n, --dry-run          Run without writing, committing, pushing or publishing anything.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_dry_run: bool,
    flag_version: bool,
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

use std::process;
use semver::Version;

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

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let repository_path = &args.flag_path;

    match git2::Repository::open(repository_path) {
        Ok(_) => { },
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    let version = match toml_file::read_from_file(repository_path) {
        Ok(toml) => toml,
        Err(e) => {
            logger::stderr(format!("Reading `Cargo.toml` failed: {:?}", e));
            process::exit(1);
        }
    };

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(repository_path);
    logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));

    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    logger::stdout(format!("New version: {}", new_version));
    match toml_file::write_new_version(repository_path, &new_version) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Writing `Cargo.toml` failed: {:?}", err));
            process::exit(1);
        }
    }

    logger::stdout(format!("Writing Changelog"));
    match changelog::write(repository_path, &version.to_string(), &new_version.to_string()) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Writing Changelog failed: {:?}", err));
            process::exit(1);
        }
    }

    match git::commit_files(repository_path, &new_version) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Committing `Cargo.toml` failed: {:?}", err));
            process::exit(1);
        }
    }

    logger::stdout("Creating annotated git tag");
    let tag_message = match changelog::generate(repository_path, &version.to_string(), &new_version) {
        Ok(msg) => msg,
        Err(err) => {
            logger::stderr(format!("Can't geneate changelog: {:?}", err));
            process::exit(1);
        }
    };

    let tag_name = format!("v{}", new_version);
    match git::tag(repository_path, &tag_name, &tag_message) {
        Ok(_) => { },
        Err(err) => {
            logger::stderr(format!("Failed to create git tag: {:?}", err));
            process::exit(1);
        }
    }
}
<commit_msg>refactor: Move uses up<commit_after>mod logger;
mod toml_file;
mod git;
mod changelog;
mod commit_analyzer;

extern crate rustc_serialize;
extern crate toml;
extern crate regex;
extern crate semver;
extern crate docopt;
extern crate git2_commit;
extern crate git2;
extern crate clog;

use docopt::Docopt;
use commit_analyzer::CommitType;
use std::process;
use semver::Version;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
semantic.rs 🚀

Usage:
  semantic-rs [options]
  semantic-rs --version

Options:
  -h --help              Show this screen.
  --version              Show version.
  -p PATH, --path=PATH   Specifies the repository path. [default: .]
  -n, --dry-run          Run without writing, committing, pushing or publishing anything.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_path: String,
    flag_dry_run: bool,
    flag_version: bool,
}

fn version_bump(version: &Version, bump: CommitType) -> Option<Version> {
    let mut version = version.clone();
    match bump {
        CommitType::Unknown => return None,
        CommitType::Patch => version.increment_patch(),
        CommitType::Minor => version.increment_minor(),
        CommitType::Major => version.increment_major(),
    }

    Some(version)
}

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

    if args.flag_version {
        println!("semantic.rs 🚀 -- v{}", VERSION);
        process::exit(0);
    }

    println!("semantic.rs 🚀");

    logger::stdout("Analyzing your repository");
    let repository_path = &args.flag_path;

    match git2::Repository::open(repository_path) {
        Ok(_) => { },
        Err(e) => {
            logger::stderr(format!("Could not open the git repository: {:?}", e));
            process::exit(1);
        }
    };

    let version = match toml_file::read_from_file(repository_path) {
        Ok(toml) => toml,
        Err(e) => {
            logger::stderr(format!("Reading `Cargo.toml` failed: {:?}", e));
            process::exit(1);
        }
    };

    let version = Version::parse(&version).expect("Not a valid version");
    logger::stdout(format!("Current version: {}", version.to_string()));

    logger::stdout("Analyzing commits");

    let bump = git::version_bump_since_latest(repository_path);
    logger::stdout(format!("Commits analyzed. Bump will be {:?}", bump));

    let new_version = match version_bump(&version, bump) {
        Some(new_version) => new_version.to_string(),
        None => {
            logger::stdout("No version bump. Nothing to do.");
            process::exit(0);
        }
    };

    logger::stdout(format!("New version: {}", new_version));
    match toml_file::write_new_version(repository_path, &new_version) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Writing `Cargo.toml` failed: {:?}", err));
            process::exit(1);
        }
    }

    logger::stdout(format!("Writing Changelog"));
    match changelog::write(repository_path, &version.to_string(), &new_version.to_string()) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Writing Changelog failed: {:?}", err));
            process::exit(1);
        }
    }

    match git::commit_files(repository_path, &new_version) {
        Ok(_)    => { },
        Err(err) => {
            logger::stderr(format!("Committing `Cargo.toml` failed: {:?}", err));
            process::exit(1);
        }
    }

    logger::stdout("Creating annotated git tag");
    let tag_message = match changelog::generate(repository_path, &version.to_string(), &new_version) {
        Ok(msg) => msg,
        Err(err) => {
            logger::stderr(format!("Can't geneate changelog: {:?}", err));
            process::exit(1);
        }
    };

    let tag_name = format!("v{}", new_version);
    match git::tag(repository_path, &tag_name, &tag_message) {
        Ok(_) => { },
        Err(err) => {
            logger::stderr(format!("Failed to create git tag: {:?}", err));
            process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>//! goto :: Flexible Working Directory Shortcuts
//!
//! Copyright (c) 2016 by William R. Fraser

extern crate docopt;
extern crate rustc_serialize;
extern crate toml;

use std::collections::btree_map::*;
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use docopt::Docopt;

const CONFIG_FILENAME: &'static str = ".goto.toml";

// 79 columns:
// ----------------------------------------------------------------------------
const USAGE: &'static str = r#"
Usage:
    goto [<name>]
    goto (--help | --version)

Configuration is stored in ~/.goto.toml, with the following format:

    name = "/some/path"             # 'goto name' takes you here
    othername = "~/some/other/path" # $HOME expansion will happen

    ["/somewhere/specific"]         # Only in effect when in this location:
    "*" = "default/under/specific"  # With no arguments, this is used.
    "name" = "somewhere/else"       # Overshadows the one above.

Relative paths under a context header are resolved relative to the path in that
header. In the above example, when your current directory is under
/somewhere/specific, running 'goto name' takes you to
/somewhere/specific/somewhere/else.

goto is meant to be used as the argument to your shell's 'eval' builtin, like:
    function goto() {
        eval $(/usr/local/bin/goto $*)  # or wherever the 'goto' binary is
    }
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_name: Option<String>,
}

fn read_config(config_path: &Path) -> io::Result<toml::Table> {
    let mut config_text = String::new();
    let mut file = try!(File::open(config_path));
    try!(file.read_to_string(&mut config_text));
    let mut parser = toml::Parser::new(&config_text);
    let config = match parser.parse() {
        Some(v) => v,
        None => {
            let mut msg = String::from("failed to parse TOML:");
            for err in &parser.errors {
                let linecol_lo = parser.to_linecol(err.lo);
                let linecol_hi = parser.to_linecol(err.hi);
                msg.push_str(&format!("\n\t{} at {}:{} to {}:{}",
                        err.desc,
                        linecol_lo.0 + 1,
                        linecol_lo.1 + 1,
                        linecol_hi.0 + 1,
                        linecol_hi.1 + 1));
            }
            return Err(io::Error::new(io::ErrorKind::Other, msg));
        }
    };

    Ok(config)
}

type PathMapping = BTreeMap<String, PathBuf>;

#[derive(Debug)]
struct Configuration {
    global: PathMapping,
    contexts: BTreeMap<PathBuf, PathMapping>,
}

fn parse_toml_as_path(t: &toml::Value, cwd: Option<&Path>) -> Result<PathBuf, String> {
    if let &toml::Value::String(ref s) = t {
        let path: PathBuf = if s.starts_with("~/") || s.starts_with("~\\") {
            env::home_dir().unwrap().join(&Path::new(&s[2..]))
        } else if cwd.is_some() {
            // note: this handles absolute paths correctly, i.e. by not using cwd at a all (except
            // for Windows, where the drive letter of cwd is considered.)
            cwd.unwrap().join(Path::new(&s))
        } else {
            return Err(format!("expected an absolute path"));
        };
        Ok(path)
    } else {
        Err(format!("type error: expected a string, not {}", t.type_str()))
    }
}

/// Process the parsed configuration TOML into goto's configuration struct.
/// if `cwd` is specified, all relative paths will be interpreted relative to that path.
fn process_config(config_toml: toml::Table, cwd: Option<&Path>) -> Result<Configuration, String> {
    let mut config = Configuration {
        global: PathMapping::new(),
        contexts: BTreeMap::new(),
    };

    for (k, v) in config_toml.into_iter() {
        if let toml::Value::Table(t) = v {
            // A path context.

            let context_path = match parse_toml_as_path(&toml::Value::String(k), cwd) {
                Ok(path) => path,
                Err(msg) => { return Err(format!("error: {}", msg)); }
            };

            let mut context_map = PathMapping::new();

            for (name, path) in t.into_iter() {
                let mapped_path: PathBuf = match parse_toml_as_path(&path, Some(&context_path)) {
                    Ok(path) => path,
                    Err(msg) => {
                        return Err(format!("error at {:?}.{}: {}", context_path, name, msg));
                    }
                };

                context_map.insert(name, mapped_path);
            }

            config.contexts.insert(context_path, context_map);
        } else {
            // A top-level entry. Attempt to parse as a path and insert into the global table.
            match parse_toml_as_path(&v, cwd) {
                Ok(path) => { config.global.insert(k, path); },
                Err(msg) => {
                    return Err(format!(
                        "error at {}: expected a table or a path string, not {} ({})",
                         k, v.type_str(), msg));
                },
            }
        }
    }

    Ok(config)
}

fn exit(msg: String, fatal: bool) -> ! {
    io::stderr().write_all(msg.as_bytes()).unwrap();
    if !msg.ends_with("\n") {
        io::stderr().write_all(b"\n").unwrap();
    }
    let exit_code = if fatal { 1 } else { 0 };
    ::std::process::exit(exit_code);
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| {
                                d.version(Some(format!("goto {}", env!("CARGO_PKG_VERSION"))))
                                 .decode()
                            })
                            .unwrap_or_else(|e| {
                                exit(format!("{}", e), e.fatal());
                            });

    let name = args.arg_name.unwrap_or("*".to_owned());

    let home = env::home_dir().unwrap_or_else(|| {
        exit(format!("unable to determine home directory"), true);
    });
    let config_path = home.join(Path::new(CONFIG_FILENAME));

    let cwd = PathBuf::from(env::current_dir().unwrap_or_else(|e| {
        exit(format!("unable to get current working directory: {}", e), true);
    }));

    let config_toml = read_config(&config_path).map_err(|e| {
        exit(format!("failed to read configuration {:?}: {}", config_path, e), true);
    }).unwrap();

    let config = process_config(config_toml, Some(&home)).map_err(|msg| {
        exit(format!("invalid configuration in {:?}: {}", config_path, msg), true);
    }).unwrap();

    let mut matched = false;
    let mut context_paths_by_len: Vec<&PathBuf> = config.contexts.keys().collect();
    context_paths_by_len.sort_by_key(|p| p.as_os_str().len());
    for context_path in context_paths_by_len.iter().rev() {
        if cwd.starts_with(context_path) {
            let map = config.contexts.get(*context_path).unwrap();
            if let Some(path) = map.get(&name) {
                println!("pushd {:?}", path);
                matched = true;
                break;
            }
        }
    }

    if !matched {
        if let Some(path) = config.global.get(&name) {
            println!("pushd {:?}", path);
            matched = true;
        }
    }

    if !matched {
        exit(format!("not sure where to go"), false);
    }
}
<commit_msg>don't let the shell interpolate variables or other special characters; also make the shell command be configurable<commit_after>//! goto :: Flexible Working Directory Shortcuts
//!
//! Copyright (c) 2016 by William R. Fraser

extern crate docopt;
extern crate rustc_serialize;
extern crate toml;

use std::collections::btree_map::*;
use std::env;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use docopt::Docopt;

const CONFIG_FILENAME: &'static str = ".goto.toml";
const DEFAULT_SHELLCMD: &'static str = "pushd";

// 79 columns:
// ----------------------------------------------------------------------------
const USAGE: &'static str = r#"
Usage:
    goto [options] [<name>]
    goto (--help | --version)

Options:
    -c <command>, --cmd=<command>   # defaults to 'pushd'

Configuration is stored in ~/.goto.toml, with the following format:

    name = "/some/path"             # 'goto name' takes you here
    othername = "~/some/other/path" # $HOME expansion will happen

    ["/somewhere/specific"]         # Only in effect when in this location:
    "*" = "default/under/specific"  # With no arguments, this is used.
    "name" = "somewhere/else"       # Overshadows the one above.

Relative paths under a context header are resolved relative to the path in that
header. In the above example, when your current directory is under
/somewhere/specific, running 'goto name' takes you to
/somewhere/specific/somewhere/else.

goto is meant to be used as the argument to your shell's 'eval' builtin, like:
    function goto() {
        eval $(/usr/local/bin/goto $*)  # or wherever the 'goto' binary is
    }
"#;

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_name: Option<String>,
    flag_cmd: Option<String>,
}

fn read_config(config_path: &Path) -> io::Result<toml::Table> {
    let mut config_text = String::new();
    let mut file = try!(File::open(config_path));
    try!(file.read_to_string(&mut config_text));
    let mut parser = toml::Parser::new(&config_text);
    let config = match parser.parse() {
        Some(v) => v,
        None => {
            let mut msg = String::from("failed to parse TOML:");
            for err in &parser.errors {
                let linecol_lo = parser.to_linecol(err.lo);
                let linecol_hi = parser.to_linecol(err.hi);
                msg.push_str(&format!("\n\t{} at {}:{} to {}:{}",
                        err.desc,
                        linecol_lo.0 + 1,
                        linecol_lo.1 + 1,
                        linecol_hi.0 + 1,
                        linecol_hi.1 + 1));
            }
            return Err(io::Error::new(io::ErrorKind::Other, msg));
        }
    };

    Ok(config)
}

type PathMapping = BTreeMap<String, PathBuf>;

#[derive(Debug)]
struct Configuration {
    global: PathMapping,
    contexts: BTreeMap<PathBuf, PathMapping>,
}

fn parse_toml_as_path(t: &toml::Value, cwd: Option<&Path>) -> Result<PathBuf, String> {
    if let &toml::Value::String(ref s) = t {
        let path: PathBuf = if s.starts_with("~/") || s.starts_with("~\\") {
            env::home_dir().unwrap().join(&Path::new(&s[2..]))
        } else if cwd.is_some() {
            // note: this handles absolute paths correctly, i.e. by not using cwd at a all (except
            // for Windows, where the drive letter of cwd is considered.)
            cwd.unwrap().join(Path::new(&s))
        } else {
            return Err(format!("expected an absolute path"));
        };
        Ok(path)
    } else {
        Err(format!("type error: expected a string, not {}", t.type_str()))
    }
}

/// Process the parsed configuration TOML into goto's configuration struct.
/// if `cwd` is specified, all relative paths will be interpreted relative to that path.
fn process_config(config_toml: toml::Table, cwd: Option<&Path>) -> Result<Configuration, String> {
    let mut config = Configuration {
        global: PathMapping::new(),
        contexts: BTreeMap::new(),
    };

    for (k, v) in config_toml.into_iter() {
        if let toml::Value::Table(t) = v {
            // A path context.

            let context_path = match parse_toml_as_path(&toml::Value::String(k), cwd) {
                Ok(path) => path,
                Err(msg) => { return Err(format!("error: {}", msg)); }
            };

            let mut context_map = PathMapping::new();

            for (name, path) in t.into_iter() {
                let mapped_path: PathBuf = match parse_toml_as_path(&path, Some(&context_path)) {
                    Ok(path) => path,
                    Err(msg) => {
                        return Err(format!("error at {:?}.{}: {}", context_path, name, msg));
                    }
                };

                context_map.insert(name, mapped_path);
            }

            config.contexts.insert(context_path, context_map);
        } else {
            // A top-level entry. Attempt to parse as a path and insert into the global table.
            match parse_toml_as_path(&v, cwd) {
                Ok(path) => { config.global.insert(k, path); },
                Err(msg) => {
                    return Err(format!(
                        "error at {}: expected a table or a path string, not {} ({})",
                         k, v.type_str(), msg));
                },
            }
        }
    }

    Ok(config)
}

fn exit(msg: String, fatal: bool) -> ! {
    io::stderr().write_all(msg.as_bytes()).unwrap();
    if !msg.ends_with("\n") {
        io::stderr().write_all(b"\n").unwrap();
    }
    let exit_code = if fatal { 1 } else { 0 };
    ::std::process::exit(exit_code);
}

fn print_path(path: &Path, shellcmd: &str) {
    if !shellcmd.is_empty() {
        print!("{} ", shellcmd);
    }

    // Because the path is potentially combined with the current working directory, which is
    // untrusted data, and the path is going to be evaluated by the shell, the path needs to be
    // single-quote escaped to prevent any expansion, for security.
    // (Otherwise a folder named '$(:(){:|:&};:)' would make for a bad day.)
    println!("'{}'", path.to_str().unwrap().replace("'", "'\\''"));
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| {
            d.version(Some(format!("goto {}", env!("CARGO_PKG_VERSION"))))
             .decode()
        })
        .unwrap_or_else(|e| {
            exit(format!("{}", e), e.fatal());
        });

    let shellcmd = args.flag_cmd.unwrap_or(DEFAULT_SHELLCMD.to_owned());
    let name = args.arg_name.unwrap_or("*".to_owned());

    let home = env::home_dir().unwrap_or_else(|| {
        exit(format!("unable to determine home directory"), true);
    });
    let config_path = home.join(Path::new(CONFIG_FILENAME));

    let cwd = PathBuf::from(env::current_dir().unwrap_or_else(|e| {
        exit(format!("unable to get current working directory: {}", e), true);
    }));

    let config_toml = read_config(&config_path).map_err(|e| {
        exit(format!("failed to read configuration {:?}: {}", config_path, e), true);
    }).unwrap();

    let config = process_config(config_toml, Some(&home)).map_err(|msg| {
        exit(format!("invalid configuration in {:?}: {}", config_path, msg), true);
    }).unwrap();

    let mut matched = false;
    let mut context_paths_by_len: Vec<&PathBuf> = config.contexts.keys().collect();
    context_paths_by_len.sort_by_key(|p| p.as_os_str().len());
    for context_path in context_paths_by_len.iter().rev() {
        if cwd.starts_with(context_path) {
            let map = config.contexts.get(*context_path).unwrap();
            if let Some(path) = map.get(&name) {
                print_path(path, &shellcmd);
                matched = true;
                break;
            }
        }
    }

    if !matched {
        if let Some(path) = config.global.get(&name) {
            print_path(path, &shellcmd);
            matched = true;
        }
    }

    if !matched {
        exit(format!("not sure where to go"), false);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;

extern crate afterparty;
extern crate clap;
extern crate lettre;
extern crate git2;
extern crate hyper;
extern crate regex;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::path::Path;
use std::sync::Mutex;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taste -w /path/to/workdir -s my_secret
  taste -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

pub fn main() {
    use clap::{Arg, App};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes Soup commits.")
        .arg(Arg::with_name("listen_addr")
            .short("l")
            .long("listen_addr")
            .takes_value(true)
            .value_name("IP:PORT")
            .default_value("0.0.0.0:4567")
            .help("Listen address and port for webhook delivery"))
        .arg(Arg::with_name("github_repo")
            .short("r")
            .long("github_repo")
            .takes_value(true)
            .required(true)
            .value_name("GH_REPO")
            .default_value("https://github.com/ms705/taster")
            .help("GitHub repository to taste"))
        .arg(Arg::with_name("email_addr")
            .long("email_addr")
            .takes_value(true)
            .required(false)
            .help("Email address to send notifications to"))
        .arg(Arg::with_name("secret")
            .short("s")
            .long("secret")
            .takes_value(true)
            .required(false)
            .help("GitHub webhook secret"))
        .arg(Arg::with_name("slack_hook_url")
            .long("slack_hook_url")
            .takes_value(true)
            .required(false)
            .help("Slack webhook URL to push notifications to"))
        .arg(Arg::with_name("slack_channel")
            .long("slack_channel")
            .takes_value(true)
            .required(false)
            .default_value("#soup-test")
            .help("Slack channel for notifications"))
        .arg(Arg::with_name("taste_commit")
            .long("taste_commit")
            .short("t")
            .takes_value(true)
            .required(false)
            .help("Do a one-off taste of a specific commit"))
        .arg(Arg::with_name("taste_head_only")
            .long("taste_head_only")
            .required(false)
            .help("When multiple commits are pushed, taste the head commit only"))
        .arg(Arg::with_name("workdir")
            .short("w")
            .long("workdir")
            .takes_value(true)
            .required(true)
            .value_name("REPO_DIR")
            .help("Directory holding the workspace repo"))
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());

    let wsl = Mutex::new(repo::Workspace::new(repo, workdir));
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(url, slack_channel.unwrap(), repo))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            let ws = wsl.lock().unwrap();
            // yuck
            let cid = ws.repo.head().unwrap().target().unwrap().clone();
            format!("{}", cid)
        } else {
            String::from(taste_commit.unwrap())
        };
        let res = taste::taste_commit(&wsl, "", &cid, &cid, "");
        match res {
            Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
            Ok(tr) => {
                // email notification
                if en.is_some() {
                    en.as_ref().unwrap().notify(&tr).unwrap();
                }
                // slack notification
                if sn.is_some() {
                    sn.as_ref().unwrap().notify(&tr).unwrap();
                }
                return;
            }
        }
    }

    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push { ref _ref, ref commits, ref head_commit, ref pusher, .. } => {
                let notify = |res: &taste::TastingResult| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(&res).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(&res).unwrap();
                    }
                };
                println!("Handling {} commits pushed by {}",
                         commits.len(),
                         pusher.name);
                {
                    let ws = wsl.lock().unwrap();
                    ws.fetch().unwrap();
                }
                // First state the head commit
                let head_res = taste::taste_commit(&wsl,
                                                   &_ref,
                                                   &head_commit.id,
                                                   &head_commit.message,
                                                   &head_commit.url);
                match head_res {
                    Err(e) => {
                        println!("ERROR: failed to taste HEAD commit {}: {}",
                                 head_commit.id,
                                 e)
                    }
                    Ok(tr) => {
                        notify(&tr);
                        // Taste others if needed
                        if !taste_head_only || !tr.build || !tr.bench {
                            for c in commits.iter() {
                                if c.id == head_commit.id {
                                    // skip HEAD as we've already tested it
                                    continue;
                                }
                                // taste
                                let res =
                                    taste::taste_commit(&wsl, &_ref, &c.id, &c.message, &c.url);
                                match res {
                                    Err(e) => {
                                        println!("ERROR: failed to taste commit {}: {}", c.id, e)
                                    }
                                    Ok(tr) => notify(&tr),
                                }
                            }
                        } else if !commits.is_empty() {
                            println!("Skipping {} remaining commits in push!", commits.len() - 1);
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..])
        .unwrap()
        .handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<commit_msg>Fix help line<commit_after>#[macro_use]
extern crate log;
extern crate env_logger;

extern crate afterparty;
extern crate clap;
extern crate lettre;
extern crate git2;
extern crate hyper;
extern crate regex;
extern crate slack_hook;
extern crate toml;

mod auth;
mod config;
mod email;
mod repo;
mod slack;
mod taste;

use afterparty::{Delivery, Event, Hub};
use hyper::Server;
use std::path::Path;
use std::sync::Mutex;

#[cfg_attr(rustfmt, rustfmt_skip)]
const TASTER_USAGE: &'static str = "\
EXAMPLES:
  taste -w /path/to/workdir -s my_secret
  taste -l 0.0.0.0:1234 -w /path/to/workdir -s my_secret";

pub fn main() {
    use clap::{Arg, App};

    env_logger::init().unwrap();

    let args = App::new("taster")
        .version("0.0.1")
        .about("Tastes GitHub commits.")
        .arg(Arg::with_name("listen_addr")
            .short("l")
            .long("listen_addr")
            .takes_value(true)
            .value_name("IP:PORT")
            .default_value("0.0.0.0:4567")
            .help("Listen address and port for webhook delivery"))
        .arg(Arg::with_name("github_repo")
            .short("r")
            .long("github_repo")
            .takes_value(true)
            .required(true)
            .value_name("GH_REPO")
            .default_value("https://github.com/ms705/taster")
            .help("GitHub repository to taste"))
        .arg(Arg::with_name("email_addr")
            .long("email_addr")
            .takes_value(true)
            .required(false)
            .help("Email address to send notifications to"))
        .arg(Arg::with_name("secret")
            .short("s")
            .long("secret")
            .takes_value(true)
            .required(false)
            .help("GitHub webhook secret"))
        .arg(Arg::with_name("slack_hook_url")
            .long("slack_hook_url")
            .takes_value(true)
            .required(false)
            .help("Slack webhook URL to push notifications to"))
        .arg(Arg::with_name("slack_channel")
            .long("slack_channel")
            .takes_value(true)
            .required(false)
            .default_value("#soup-test")
            .help("Slack channel for notifications"))
        .arg(Arg::with_name("taste_commit")
            .long("taste_commit")
            .short("t")
            .takes_value(true)
            .required(false)
            .help("Do a one-off taste of a specific commit"))
        .arg(Arg::with_name("taste_head_only")
            .long("taste_head_only")
            .required(false)
            .help("When multiple commits are pushed, taste the head commit only"))
        .arg(Arg::with_name("workdir")
            .short("w")
            .long("workdir")
            .takes_value(true)
            .required(true)
            .value_name("REPO_DIR")
            .help("Directory holding the workspace repo"))
        .after_help(TASTER_USAGE)
        .get_matches();

    let addr = args.value_of("listen_addr").unwrap();
    let email_notification_addr = args.value_of("email_addr");
    let repo = args.value_of("github_repo").unwrap();
    let secret = args.value_of("secret");
    let slack_hook_url = args.value_of("slack_hook_url");
    let slack_channel = args.value_of("slack_channel");
    let taste_commit = args.value_of("taste_commit");
    let taste_head_only = args.is_present("taste_head_only");
    let workdir = Path::new(args.value_of("workdir").unwrap());

    let wsl = Mutex::new(repo::Workspace::new(repo, workdir));
    let en = if let Some(addr) = email_notification_addr {
        Some(email::EmailNotifier::new(addr, repo))
    } else {
        None
    };
    let sn = if let Some(url) = slack_hook_url {
        Some(slack::SlackNotifier::new(url, slack_channel.unwrap(), repo))
    } else {
        None
    };

    if taste_commit.is_some() {
        let cid = if let Some("HEAD") = taste_commit {
            let ws = wsl.lock().unwrap();
            // yuck
            let cid = ws.repo.head().unwrap().target().unwrap().clone();
            format!("{}", cid)
        } else {
            String::from(taste_commit.unwrap())
        };
        let res = taste::taste_commit(&wsl, "", &cid, &cid, "");
        match res {
            Err(e) => println!("ERROR: failed to taste{}: {}", cid, e),
            Ok(tr) => {
                // email notification
                if en.is_some() {
                    en.as_ref().unwrap().notify(&tr).unwrap();
                }
                // slack notification
                if sn.is_some() {
                    sn.as_ref().unwrap().notify(&tr).unwrap();
                }
                return;
            }
        }
    }

    if let None = secret {
        panic!("--secret must be set when in continuous webhook handler mode");
    }

    let mut hub = Hub::new();
    hub.handle_authenticated("push", secret.unwrap(), move |delivery: &Delivery| {
        match delivery.payload {
            Event::Push { ref _ref, ref commits, ref head_commit, ref pusher, .. } => {
                let notify = |res: &taste::TastingResult| {
                    // email notification
                    if en.is_some() {
                        en.as_ref().unwrap().notify(&res).unwrap();
                    }
                    // slack notification
                    if sn.is_some() {
                        sn.as_ref().unwrap().notify(&res).unwrap();
                    }
                };
                println!("Handling {} commits pushed by {}",
                         commits.len(),
                         pusher.name);
                {
                    let ws = wsl.lock().unwrap();
                    ws.fetch().unwrap();
                }
                // First state the head commit
                let head_res = taste::taste_commit(&wsl,
                                                   &_ref,
                                                   &head_commit.id,
                                                   &head_commit.message,
                                                   &head_commit.url);
                match head_res {
                    Err(e) => {
                        println!("ERROR: failed to taste HEAD commit {}: {}",
                                 head_commit.id,
                                 e)
                    }
                    Ok(tr) => {
                        notify(&tr);
                        // Taste others if needed
                        if !taste_head_only || !tr.build || !tr.bench {
                            for c in commits.iter() {
                                if c.id == head_commit.id {
                                    // skip HEAD as we've already tested it
                                    continue;
                                }
                                // taste
                                let res =
                                    taste::taste_commit(&wsl, &_ref, &c.id, &c.message, &c.url);
                                match res {
                                    Err(e) => {
                                        println!("ERROR: failed to taste commit {}: {}", c.id, e)
                                    }
                                    Ok(tr) => notify(&tr),
                                }
                            }
                        } else if !commits.is_empty() {
                            println!("Skipping {} remaining commits in push!", commits.len() - 1);
                        }
                    }
                }
            }
            _ => (),
        }
    });

    let srvc = Server::http(&addr[..])
        .unwrap()
        .handle(hub);

    println!("Taster listening on {}", addr);
    srvc.unwrap();
}
<|endoftext|>


<commit_before>fn main() {
    const N: u64 = 400;

    let mut first: u64 = 0;
    let mut second: u64 = 1;

    for _ in 1..N {
        let temp: u64 = second;
        second = first + second;
        first = temp;
    }

    println!("Result is {}", second);
}
<commit_msg>references<commit_after>fn main() {
    let mut s = String::from("this is a string");
    takes_a_reference(&mut s);

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

fn takes_a_reference(s: &mut String) {
    s.push_str(" this is a pushed string");
}
<|endoftext|>


<commit_before>#[macro_use]
mod lib;

mod command;
mod constant;
mod error;

use error::CliError;
use lib::io::*;
use std::process;

fn main() {
    if let Err(why) = command::execute() {
        let error_code = match why {
            CliError::Essential(_) | CliError::RunningPlace(_) => {
                print_with_tag(Tag::Warning, why);
                if let Err(e) = command::clean_up_cron() {
                    print_with_tag(Tag::Error, e);
                }
                1
            },
            CliError::Usage(u) => {
                echo(u);
                1
            },
            _ => {
                print_with_tag(Tag::Error, why);
                1
            },
        };
        process::exit(error_code);
    };
}
<commit_msg>[Refactoring] Remove useless attribute "macro_use"<commit_after>mod command;
mod constant;
mod error;
mod lib;

use error::CliError;
use lib::io::*;
use std::process;

fn main() {
    if let Err(why) = command::execute() {
        let error_code = match why {
            CliError::Essential(_) | CliError::RunningPlace(_) => {
                print_with_tag(Tag::Warning, why);
                if let Err(e) = command::clean_up_cron() {
                    print_with_tag(Tag::Error, e);
                }
                1
            },
            CliError::Usage(u) => {
                echo(u);
                1
            },
            _ => {
                print_with_tag(Tag::Error, why);
                1
            },
        };
        process::exit(error_code);
    };
}
<|endoftext|>


<commit_before>use std::env;
use std::io::prelude::*;
use std::io;
use std::fs::File;

extern crate ansi_term;
use ansi_term::Style;
use ansi_term::Colour::Red;

extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;

// include output of rust-peg given grammar.rustpeg
mod parser {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

mod ast;
mod interpreter;
mod value;
mod operations;

#[derive(Debug)]
enum ProcessingError {
    ParseError(parser::ParseError),
    IoError(io::Error)
}

impl From<io::Error> for ProcessingError {
    fn from(from: io::Error) -> Self {
        ProcessingError::IoError(from)
    }
}

impl From<parser::ParseError> for ProcessingError {
    fn from(from: parser::ParseError) -> Self {
        ProcessingError::ParseError(from)
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    if args.len() == 1 {
        repl();
        return;
    }

    if args.len() < 3 || (args[1] != "run" && args[1] != "parse") {
        println!("usage: balloon run|parse FILE");
        return;
    }
    let file_name = &args[2];
    let result = parse_file(file_name).and_then(|ast| {
        if args[1] == "parse" {
            println!("{:#?}", ast);
            Ok(())
        } else {
            interpreter::interpret_program(&ast);
            Ok(())
        }
    });
    if let Err(err) = result {
        match err {
            ProcessingError::ParseError(parse_error) => {
                println!("{:?}", parse_error);
                let (mut line_number, mut column_number) = (parse_error.line, parse_error.column);

                let mut buf_reader = io::BufReader::new(File::open(file_name).unwrap());
                let mut line = buf_reader.by_ref().lines().nth(line_number - 1);

                let line_content;

                // error was in last line which was empty
                if let None = line {
                    line_number -= 1;
                    buf_reader.seek(io::SeekFrom::Start(0)).unwrap();
                    // more helpful to point to end of previous line
                    line = buf_reader.lines().nth(line_number - 1);
                    line_content = line.unwrap().unwrap();
                    column_number = line_content.len() + 1;
                } else {
                    line_content = line.unwrap().unwrap();
                }

                println!("{}: {}: line {}, col {}: expected one of {:?}",
                    Style::new().bold().paint(file_name.clone()),
                    Red.bold().paint("parse error"),
                    line_number,
                    column_number,
                    parse_error.expected
                );
                println!("{}", line_content);
                let mut pointer_string = String::from_utf8(vec![b' '; column_number - 1]).unwrap();
                pointer_string.push('^');
                println!("{}", Style::new().bold().paint(pointer_string));
            },
            ProcessingError::IoError(io_error) => {
                match io_error.kind() {
                    io::ErrorKind::NotFound => println!("{}", io_error),
                    e => println!("An error occurred.\n{:?}", e),
                };
            },
        };
    }
}

fn parse_file(name: &String) -> Result<Vec<ast::Statement>, ProcessingError> {
    let mut input_file = File::open(name)?;
    let mut input = String::new();
    input_file.read_to_string(&mut input)?;
    if !input.ends_with("\n") {
        input.push('\n');
    }
    let x = parser::program(&input);
    Ok(x?)
}

fn repl() {
    println!("Balloon REPL");
    let mut rl = Editor::<()>::new();
    let mut repl = interpreter::Repl::new();
    repl.start();
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                let orig_input = String::from(line.trim());
                let mut input = orig_input.clone();
                if !input.ends_with(";") {
                    input.push(';');
                }
                match parser::program(&input) {
                    Err(parse_error) => {
                        let (line_number, column_number) = (parse_error.line, parse_error.column);
                        println!("{}: {}: line {}, col {}: expected one of {:?}",
                            Style::new().bold().paint("repl"),
                            Red.bold().paint("parse error"),
                            line_number,
                            column_number,
                            parse_error.expected
                        );
                        println!("{}", orig_input);
                        let mut pointer_string = String::from_utf8(vec![b' '; column_number - 1]).unwrap();
                        pointer_string.push('^');
                        println!("{}", Style::new().bold().paint(pointer_string));
                    },
                    Ok(ast) => repl.execute(&ast),
                }
            },
            Err(ReadlineError::Interrupted) => {
                repl.end();
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                repl.end();
                println!("CTRL-D");
                break
            },
            Err(err) => {
                repl.end();
                println!("Error: {:?}", err);
                break
            }
        }
    }
}
<commit_msg>Move parse error printing to separate function<commit_after>use std::env;
use std::io::prelude::*;
use std::io;
use std::fs::File;

extern crate ansi_term;
use ansi_term::Style;
use ansi_term::Colour::Red;

extern crate rustyline;
use rustyline::error::ReadlineError;
use rustyline::Editor;

// include output of rust-peg given grammar.rustpeg
mod parser {
    include!(concat!(env!("OUT_DIR"), "/grammar.rs"));
}

mod ast;
mod interpreter;
mod value;
mod operations;

#[derive(Debug)]
enum ProcessingError {
    ParseError(parser::ParseError),
    IoError(io::Error)
}

impl From<io::Error> for ProcessingError {
    fn from(from: io::Error) -> Self {
        ProcessingError::IoError(from)
    }
}

impl From<parser::ParseError> for ProcessingError {
    fn from(from: parser::ParseError) -> Self {
        ProcessingError::ParseError(from)
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();

    if args.len() == 1 {
        repl();
        return;
    }

    if args.len() < 3 || (args[1] != "run" && args[1] != "parse") {
        println!("usage: balloon run|parse FILE");
        return;
    }
    let file_name = &args[2];
    let result = parse_file(file_name).and_then(|ast| {
        if args[1] == "parse" {
            println!("{:#?}", ast);
            Ok(())
        } else {
            interpreter::interpret_program(&ast);
            Ok(())
        }
    });
    if let Err(err) = result {
        match err {
            ProcessingError::ParseError(parse_error) => {
                let mut parse_error = parse_error;

                let mut buf_reader = io::BufReader::new(File::open(file_name).unwrap());
                let mut line = buf_reader.by_ref().lines().nth(parse_error.line - 1);

                let line_content;

                // error was in last line which was empty
                if let None = line {
                    parse_error.line -= 1;
                    buf_reader.seek(io::SeekFrom::Start(0)).unwrap();
                    // more helpful to point to end of previous line
                    line = buf_reader.lines().nth(parse_error.line - 1);
                    line_content = line.unwrap().unwrap();
                    parse_error.column = line_content.len() + 1;
                } else {
                    line_content = line.unwrap().unwrap();
                }
                print_parse_error(file_name.to_string(), line_content, parse_error);
            },
            ProcessingError::IoError(io_error) => {
                match io_error.kind() {
                    io::ErrorKind::NotFound => println!("{}", io_error),
                    e => println!("An error occurred.\n{:?}", e),
                };
            },
        };
    }
}

fn parse_file(name: &String) -> Result<Vec<ast::Statement>, ProcessingError> {
    let mut input_file = File::open(name)?;
    let mut input = String::new();
    input_file.read_to_string(&mut input)?;
    if !input.ends_with("\n") {
        input.push('\n');
    }
    let x = parser::program(&input);
    Ok(x?)
}

fn print_parse_error(file_name: String, line_content: String, parse_error: parser::ParseError) {
    println!("{}: {}: line {}, col {}: expected one of {:?}",
        Style::new().bold().paint(file_name.clone()),
        Red.bold().paint("parse error"),
        parse_error.line,
        parse_error.column,
        parse_error.expected
    );
    println!("{}", line_content);
    let mut pointer_string = String::from_utf8(vec![b' '; parse_error.column - 1]).unwrap();
    pointer_string.push('^');
    println!("{}", Style::new().bold().paint(pointer_string));
}

fn repl() {
    println!("Balloon REPL");
    let mut rl = Editor::<()>::new();
    let mut repl = interpreter::Repl::new();
    repl.start();
    loop {
        let readline = rl.readline("> ");
        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                let orig_input = String::from(line.trim());
                let mut input = orig_input.clone();
                if !input.ends_with(";") {
                    input.push(';');
                }
                match parser::program(&input) {
                    Err(parse_error) => {
                        print_parse_error("repl".to_string(), orig_input, parse_error);
                    },
                    Ok(ast) => repl.execute(&ast),
                }
            },
            Err(ReadlineError::Interrupted) => {
                repl.end();
                println!("CTRL-C");
                break
            },
            Err(ReadlineError::Eof) => {
                repl.end();
                println!("CTRL-D");
                break
            },
            Err(err) => {
                repl.end();
                println!("Error: {:?}", err);
                break
            }
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

fn main() {
}
<commit_msg>Added proper main<commit_after>#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn _start() -> ! {
    loop {}
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate kafka;

use clap::{Arg, App};
use kafka::client::{KafkaClient, ProduceMessage, RequiredAcks};
use std::time::Duration;
use std::io;
use std::io::prelude::*;

fn main() {
    let matches = App::new("ktee")
                      .version("0.1.0")
                      .author("Xavier Stevens <xavier@mystobreak.com>")
                      .about("tee for Kafka")
                      .arg(Arg::with_name("broker")
                               .short("b")
                               .long("broker")
                               .value_name("BROKER")
                               .help("Kafka broker")
                               .takes_value(true)
                               .required(true))
                      .arg(Arg::with_name("topic")
                               .short("t")
                               .long("topic")
                               .value_name("TOPIC")
                               .help("Kafka topic")
                               .takes_value(true)
                               .required(true))
                      .get_matches();

    let broker = matches.value_of("broker").unwrap();
    let topic = matches.value_of("topic").unwrap();

    let mut client = KafkaClient::new(vec![broker.to_owned()]);
    let meta_res = client.load_metadata_all();
    if let Some(err) = meta_res.err() {
        println!("Error fetching metadata: {}", err);
        return;
    }

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        if line.is_ok() {
            let b = line.unwrap().into_bytes();
            let req = vec![ProduceMessage::new(topic, 0, None, Some(&b))];
            let res = client.produce_messages(RequiredAcks::One, Duration::from_millis(0), req);
            if let Some(err) = res.err() {
                println!("Error sending message: {}", err);
            }
        }
    }
}
<commit_msg>Added writing of input to stdout<commit_after>extern crate clap;
extern crate kafka;

use clap::{Arg, App};
use kafka::client::{KafkaClient, ProduceMessage, RequiredAcks};
use std::time::Duration;
use std::io;
use std::io::prelude::*;

fn main() {
    let matches = App::new("ktee")
                      .version("0.1.0")
                      .about("tee for kafka")
                      .arg(Arg::with_name("broker")
                               .short("b")
                               .long("broker")
                               .value_name("BROKER")
                               .help("Kafka broker")
                               .takes_value(true)
                               .required(true))
                      .arg(Arg::with_name("topic")
                               .short("t")
                               .long("topic")
                               .value_name("TOPIC")
                               .help("Kafka topic")
                               .takes_value(true)
                               .required(true))
                      .get_matches();

    let broker = matches.value_of("broker").unwrap();
    let topic = matches.value_of("topic").unwrap();

    let mut client = KafkaClient::new(vec![broker.to_owned()]);
    let meta_res = client.load_metadata_all();
    if let Some(err) = meta_res.err() {
        println!("Error fetching metadata: {}", err);
        return;
    }

    let stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut stderr = io::stderr();
    for line in stdin.lock().lines() {
        if line.is_ok() {
            let l = line.unwrap();
            let req = vec![ProduceMessage::new(topic, 0, None, Some(&l.as_bytes()))];
            let res = client.produce_messages(RequiredAcks::One, Duration::from_millis(0), req);
            if let Some(err) = res.err() {
                writeln!(&mut stderr, "Error sending message: {}", err).unwrap();
            }

            let write_res = write!(&mut stdout, "{}\n", &l);
            if let Some(err) = write_res.err() {
                writeln!(&mut stderr, "Error writing to stdout: {}", err).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate env_logger;
extern crate libc;
extern crate x11;

use std::rc::Rc;

mod debug;
mod groups;
mod keys;
mod layout;
mod window;
mod x;

use layout::{Layout, TiledLayout};
use keys::{KeyCombo, KeyHandlers, ModKey};
use x::{Connection, Event, WindowId};
use window::Window;
use groups::{Group, GroupWindow};

struct Config {
    layout: Box<Layout>,
    keys: KeyHandlers,
}

pub struct RustWindowManager {
    connection: Rc<Connection>,

    config: Config,

    group: Group,
}

impl RustWindowManager {
    fn new(config: Config) -> Result<Self, String> {
        let connection = Connection::connect()?;
        connection.install_as_wm()?;
        let connection = Rc::new(connection);

        Ok(RustWindowManager {
               connection: connection.clone(),

               config: config,

               group: Group::new(connection.clone()),
           })
    }

    fn layout(&mut self) {
        let root_window_id = self.connection.root_window_id();
        let (width, height) = self.connection.get_window_geometry(&root_window_id);

        self.config.layout.layout(width, height, self.group.iter_mut());
    }

    fn get_focused(&mut self) -> Option<GroupWindow> {
        self.group.get_focused()
    }

    fn focus_next(&mut self) {
        self.group.focus_next();
    }

    fn focus_previous(&mut self) {
        self.group.focus_previous();
    }

    fn run_event_loop(&mut self) {
        let event_loop_connection = self.connection.clone();
        let event_loop = event_loop_connection.get_event_loop();
        for event in event_loop {
            match event {
                Event::MapRequest(window_id) => self.on_map_request(window_id),
                Event::DestroyNotify(window_id) => self.on_destroy_notify(window_id),
                Event::KeyPress(key) => self.on_key_press(key),
                Event::EnterNotify(window_id) => self.on_enter_notify(window_id),
            }
        }
        info!("Event loop exiting");
    }

    fn on_map_request(&mut self, window_id: WindowId) {
        self.connection.register_window_events(&window_id, &self.config.keys);
        self.connection.map_window(&window_id);

        self.group.add_window(window_id);
        self.layout();
    }

    fn on_destroy_notify(&mut self, window_id: WindowId) {
        self.group.find_window_by_id(&window_id).map(|w| w.remove_from_group());
        self.layout();
    }

    fn on_key_press(&mut self, key: KeyCombo) {
        self.config
            .keys
            .get(&key)
            .map(move |handler| (handler)(self));
    }

    fn on_enter_notify(&mut self, window_id: WindowId) {
        self.group.find_window_by_id(&window_id).map(|mut w| w.focus());
    }
}

fn close_window(wm: &mut RustWindowManager) {
    wm.get_focused().map(|w| w.close());
}

fn focus_next(wm: &mut RustWindowManager) {
    wm.focus_next();
}

fn focus_previous(wm: &mut RustWindowManager) {
    wm.focus_previous();
}

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

    let keys = KeyHandlers::new(vec![(KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_t),
                                      Rc::new(close_window)),
                                     (KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_y),
                                      Rc::new(focus_next)),
                                     (KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_u),
                                      Rc::new(focus_previous))]);

    let layout = Box::new(TiledLayout {});
    let config = Config {
        keys: keys,
        layout: layout,
    };

    let mut wm = RustWindowManager::new(config).unwrap();
    wm.run_event_loop();
}
<commit_msg>Deny warnings.<commit_after>#![deny(warnings)]

#[macro_use]
extern crate log;
extern crate env_logger;
extern crate libc;
extern crate x11;

use std::rc::Rc;

mod debug;
mod groups;
mod keys;
mod layout;
mod window;
mod x;

use layout::{Layout, TiledLayout};
use keys::{KeyCombo, KeyHandlers, ModKey};
use x::{Connection, Event, WindowId};
use window::Window;
use groups::{Group, GroupWindow};

struct Config {
    layout: Box<Layout>,
    keys: KeyHandlers,
}

pub struct RustWindowManager {
    connection: Rc<Connection>,

    config: Config,

    group: Group,
}

impl RustWindowManager {
    fn new(config: Config) -> Result<Self, String> {
        let connection = Connection::connect()?;
        connection.install_as_wm()?;
        let connection = Rc::new(connection);

        Ok(RustWindowManager {
               connection: connection.clone(),

               config: config,

               group: Group::new(connection.clone()),
           })
    }

    fn layout(&mut self) {
        let root_window_id = self.connection.root_window_id();
        let (width, height) = self.connection.get_window_geometry(&root_window_id);

        self.config.layout.layout(width, height, self.group.iter_mut());
    }

    fn get_focused(&mut self) -> Option<GroupWindow> {
        self.group.get_focused()
    }

    fn focus_next(&mut self) {
        self.group.focus_next();
    }

    fn focus_previous(&mut self) {
        self.group.focus_previous();
    }

    fn run_event_loop(&mut self) {
        let event_loop_connection = self.connection.clone();
        let event_loop = event_loop_connection.get_event_loop();
        for event in event_loop {
            match event {
                Event::MapRequest(window_id) => self.on_map_request(window_id),
                Event::DestroyNotify(window_id) => self.on_destroy_notify(window_id),
                Event::KeyPress(key) => self.on_key_press(key),
                Event::EnterNotify(window_id) => self.on_enter_notify(window_id),
            }
        }
        info!("Event loop exiting");
    }

    fn on_map_request(&mut self, window_id: WindowId) {
        self.connection.register_window_events(&window_id, &self.config.keys);
        self.connection.map_window(&window_id);

        self.group.add_window(window_id);
        self.layout();
    }

    fn on_destroy_notify(&mut self, window_id: WindowId) {
        self.group.find_window_by_id(&window_id).map(|w| w.remove_from_group());
        self.layout();
    }

    fn on_key_press(&mut self, key: KeyCombo) {
        self.config
            .keys
            .get(&key)
            .map(move |handler| (handler)(self));
    }

    fn on_enter_notify(&mut self, window_id: WindowId) {
        self.group.find_window_by_id(&window_id).map(|mut w| w.focus());
    }
}

fn close_window(wm: &mut RustWindowManager) {
    wm.get_focused().map(|w| w.close());
}

fn focus_next(wm: &mut RustWindowManager) {
    wm.focus_next();
}

fn focus_previous(wm: &mut RustWindowManager) {
    wm.focus_previous();
}

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

    let keys = KeyHandlers::new(vec![(KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_t),
                                      Rc::new(close_window)),
                                     (KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_y),
                                      Rc::new(focus_next)),
                                     (KeyCombo::new(vec![ModKey::Mod4], x11::keysym::XK_u),
                                      Rc::new(focus_previous))]);

    let layout = Box::new(TiledLayout {});
    let config = Config {
        keys: keys,
        layout: layout,
    };

    let mut wm = RustWindowManager::new(config).unwrap();
    wm.run_event_loop();
}
<|endoftext|>


<commit_before>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);

    move_up(&origin.y); // borrowing the value
    move_up(&origin.y); // so that I can change it

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // Here I get the value and store it
    y_cord.set(new_val + 1); // Here I modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}
<commit_msg>getting ready to learn how to write some tests<commit_after>use std::cell::Cell;

struct Coordinates {
    x: Cell<i32>,
    y: Cell<i32>,
}

fn main() {
    let origin = Coordinates { x: Cell::new(0), y: Cell::new(0) };

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);

    move_up(&origin.y); // borrowing the value
    move_up(&origin.y); // so that I can change it

    println!("X is {:?} and Y is {:?}", origin.x, origin.y);
}

fn move_up(y_cord: &Cell<i32>) -> &Cell<i32> {
    let new_val = y_cord.get(); // Here I get the value and store it
    y_cord.set(new_val + 1); // Here I modify the stored value and set the incoming param
    y_cord // no semicolon here because it is the return value
}

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


<commit_before>extern crate ws;
extern crate nphysics = "nphysics3df32";
extern crate ncollide = "ncollide3df32";
extern crate nalgebra;

use std::rc::Rc;
use std::cell::RefCell;
use nalgebra::na::{Vec3, Translation};
use ncollide::geom::{Ball, Plane};
use nphysics::world::World;
use nphysics::object::RigidBody;

use std::io::timer;
use std::time::Duration;
use ws::message::{Message, Empty, PingOp};

fn main(){
    let x = Message { payload: Empty, opcode: PingOp };
    println!("{}", x);

    let mut world = World::new();
    world.set_gravity(Vec3::new(0.0f32, -9.81, 0.0));

    // planes
    let normals = [
        Vec3::new(-1.0f32, 1.0, -1.0 ),
        Vec3::new(1.0f32, 1.0, -1.0 ),
        Vec3::new(-1.0f32, 1.0, 1.0 ),
        Vec3::new(1.0f32, 1.0, 1.0 )
    ];
    for n in normals.iter() {
        let rb   = RigidBody::new_static(Plane::new(*n), 0.3, 0.6);
        let body = Rc::new(RefCell::new(rb));

        world.add_body(body.clone());
        //graphics.add(body); FIXME instead, our ws stuff needs a reference to it right, to send coordinates to the browser?
    }

    // ball
    let rad = 0.5;
    let mut rb = RigidBody::new_dynamic(Ball::new(rad), 1.0f32, 0.3, 0.6);
    rb.append_translation(&Vec3::new(15.0, 30.0, -15.0));
    let body = Rc::new(RefCell::new(rb));

    world.add_body(body.clone());
    //graphics.add(window, body);

    let fps = 30.0f32;
    loop {
        println!("{}", (*body).borrow().center_of_mass());
        world.step(1.0 / fps);
        let step_duration = Duration::milliseconds((1000.0 / fps) as i32);
        timer::sleep(step_duration); // FIXME take into account time spent calcuating step
    }
}
<commit_msg>get json messages with object location to browser over ws in soft-realtime<commit_after>extern crate ws;
extern crate http;
extern crate time;
extern crate nphysics = "nphysics3df32";
extern crate ncollide = "ncollide3df32";
extern crate nalgebra;
extern crate serialize;

use serialize::json;

use std::sync::{Mutex, Arc};
use std::rc::Rc;
use std::cell::RefCell;
use nalgebra::na::{Vec3, Translation};
use ncollide::geom::{Ball, Plane};
use nphysics::world::World;
use nphysics::object::RigidBody;

use std::io::timer;
use std::time::Duration;

use http::server::{Config, Server, Request, ResponseWriter};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use http::headers::content_type::MediaType;

use ws::message::{Message, TextOp, Text, BinaryOp, Binary};
use ws::server::WebSocketServer;

#[deriving(Clone)]
struct GameServer {
    netman: Arc<Mutex<NetMan>>
}

#[deriving(Clone)]
struct NetMan {
    players: Vec<Sender<Box<Message>>>,
}

impl NetMan {
    pub fn broadcast(&self, message: Box<Message>) {
        for player in self.players.iter() {
            player.send(message.clone());
        }
    }
}

impl Server for GameServer {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 8001 } }
    }

    fn handle_request(&self, r: Request, w: &mut ResponseWriter) {
        w.headers.date = Some(time::now_utc());
        w.headers.content_type = Some(MediaType {
            type_: String::from_str("text"),
            subtype: String::from_str("html"),
            parameters: vec!((String::from_str("charset"), String::from_str("UTF-8"))),
        });
        w.headers.server = Some(String::from_str("GameServer"));

        w.write(b"
Game Server
").unwrap();
        w.write(b"").unwrap();
    }
}

impl WebSocketServer for GameServer {
    fn handle_ws_connect(&self, receiver: Receiver<Box<Message>>, sender: Sender<Box<Message>>) {
        let mut netman = self.netman.lock();
        (*netman).players.push(sender);

        let netman = self.netman.clone();
        spawn(proc() {

            // first message received is nick
            let nick = match receiver.recv().payload {
                Text(p) => p,
                _       => fail!(),
            };

            loop {
                let message = receiver.recv();
                let (payload, opcode) = match message.payload {
                    Text(p) => (Text(box nick.clone().append(": ").append((*p).as_slice())), TextOp),
                    _       => fail!(),
                };
                let broadcast_message = box Message {
                    payload: payload,
                    opcode: opcode,
                };
                let mut netman = netman.lock();
                netman.broadcast(broadcast_message);
            }
        });
    }
}

fn main(){
    //let x = Message { payload: Empty, opcode: PingOp };
    //println!("{}", x);

    let mut world = World::new();
    world.set_gravity(Vec3::new(0.0f32, -9.81, 0.0));

    // planes
    let normals = [
        Vec3::new(-1.0f32, 1.0, -1.0 ),
        Vec3::new(1.0f32, 1.0, -1.0 ),
        Vec3::new(-1.0f32, 1.0, 1.0 ),
        Vec3::new(1.0f32, 1.0, 1.0 )
    ];
    for n in normals.iter() {
        let rb   = RigidBody::new_static(Plane::new(*n), 0.3, 0.6);
        let body = Rc::new(RefCell::new(rb));

        world.add_body(body.clone());
        //graphics.add(body); FIXME instead, our ws stuff needs a reference to it right, to send coordinates to the browser?
    }

    // ball
    let rad = 0.5;
    let mut rb = RigidBody::new_dynamic(Ball::new(rad), 1.0f32, 0.3, 0.6);
    rb.append_translation(&Vec3::new(15.0, 30.0, -15.0));
    let body = Rc::new(RefCell::new(rb.clone()));

    world.add_body(body.clone());
    //graphics.add(window, body);

    let netman = Arc::new(Mutex::new(NetMan { players: vec![] }));
    let cloned_netman = netman.clone();
    spawn(proc() {
        GameServer { netman: cloned_netman }.ws_serve_forever();
    });

    let fps = 30.0f32;

    // XXX ncollide uses Rc and RefCell, which I can't share between tasks :(
    // // broadcast loop
    // let broadcast_body = Arc::new(rb.clone());
    // spawn(proc() {
    //     loop {
    //         println!("here");
    //         let step_duration = Duration::milliseconds((1000.0 / fps) as i32);
    //         timer::sleep(step_duration); // FIXME take into account time spent calcuating step

    //         let broadcast_message = box Message {
    //             payload: Text(box json::encode(broadcast_body.center_of_mass())),
    //             opcode: TextOp,
    //         };
    //         let mut netman = netman.lock();
    //         netman.broadcast(broadcast_message);
    //     }
    // });

    loop {
        world.step(1.0 / fps);
        let step_duration = Duration::milliseconds((1000.0 / fps) as i32);
        timer::sleep(step_duration); // FIXME take into account time spent calcuating step

        println!("{}", (*body).borrow().center_of_mass());

        let broadcast_message = box Message {
            payload: Text(box json::encode((*body).borrow().center_of_mass())),
            opcode: TextOp,
        };
        let mut netman = netman.lock();
        netman.broadcast(broadcast_message);
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>add timesheet stub<commit_after>mod timesheet;

fn main() {
    let ts = timesheet::Session::new();
    println!("{:?}", ts);
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::{self, BufRead, Write};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};

extern crate isatty;
use isatty::{stderr_isatty, stdout_isatty};

extern crate tempfile;

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() -> io::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().and_then(|arg| arg.to_str()) == Some("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() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if !color_never(&args) && stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        let mut builder = tempfile::Builder::new();
        builder.prefix("cargo-expand");
        Some(builder.tempdir().expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));
    let code = filter_err(&mut cmd, ignore_cargo_err)?;
    if code != 0 {
        return Ok(code);
    }

    // Run rustfmt
    if let Some(fmt) = which_rustfmt {
        // Ignore any errors.
        let _status = Command::new(fmt)
            .arg(outfile.as_ref().unwrap())
            .stderr(Stdio::null())
            .status();
    }

    // Run pygmentize
    if let Some(pyg) = which_pygmentize {
        let _status = Command::new(pyg)
            .args(&["-l", "rust", "-O", "encoding=utf8"])
            .arg(outfile.as_ref().unwrap())
            .status();
    } else if let Some(outfile) = outfile {
        // Cat outfile if rustfmt was used.
        let mut reader = File::open(outfile)?;
        io::copy(&mut reader, &mut io::stdout())?;
    }
    Ok(0)
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
where
    I: IntoIterator<Item = OsString>,
{
    let mut args = vec!["rustc".into(), "--profile=check".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

fn color_never(args: &Vec<OsString>) -> bool {
    args.windows(2).any(|pair| pair[0] == *"--color" && pair[1] == *"never")
        || args.iter().any(|arg| *arg == *"--color=never")
}

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

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

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .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[0].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>Handle --version flag<commit_after>use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::{self, BufRead, Write};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};

extern crate isatty;
use isatty::{stderr_isatty, stdout_isatty};

extern crate tempfile;

fn main() {
    if env::args_os().any(|arg| arg == "--version") {
        println!(concat!("cargo-expand ", env!("CARGO_PKG_VERSION")));
        return;
    }

    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() -> io::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().and_then(|arg| arg.to_str()) == Some("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() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if !color_never(&args) && stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        let mut builder = tempfile::Builder::new();
        builder.prefix("cargo-expand");
        Some(builder.tempdir().expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Run cargo
    let mut cmd = Command::new(cargo_binary());
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));
    let code = filter_err(&mut cmd, ignore_cargo_err)?;
    if code != 0 {
        return Ok(code);
    }

    // Run rustfmt
    if let Some(fmt) = which_rustfmt {
        // Ignore any errors.
        let _status = Command::new(fmt)
            .arg(outfile.as_ref().unwrap())
            .stderr(Stdio::null())
            .status();
    }

    // Run pygmentize
    if let Some(pyg) = which_pygmentize {
        let _status = Command::new(pyg)
            .args(&["-l", "rust", "-O", "encoding=utf8"])
            .arg(outfile.as_ref().unwrap())
            .status();
    } else if let Some(outfile) = outfile {
        // Cat outfile if rustfmt was used.
        let mut reader = File::open(outfile)?;
        io::copy(&mut reader, &mut io::stdout())?;
    }
    Ok(0)
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
where
    I: IntoIterator<Item = OsString>,
{
    let mut args = vec!["rustc".into(), "--profile=check".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

fn color_never(args: &Vec<OsString>) -> bool {
    args.windows(2).any(|pair| pair[0] == *"--color" && pair[1] == *"never")
        || args.iter().any(|arg| *arg == *"--color=never")
}

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

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

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .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[0].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>//! A Takuzu (a.k.a. Binairo) solver.
//!
//! # Usage
//!
//! ```shell
//! tackle [FILE]...
//! tackle {--help | --version}
//! ```
//!
//! If no `FILE` is provided, or if `FILE` is '`-`', reads from standard input.

extern crate libc;
extern crate takuzu;

use std::fs::File;
use std::io::{stderr, stdin, Write};

use takuzu::{Grid, Source};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE_STRING: &'static str =
r#"Usage: tackle [FILE]...
       tackle {--help | --version}

If no FILE is provided, or if FILE is "-", read from standard input.

Options:
    --help       display this message and exit
    --version    display the version and exit
"#;

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    if args.contains(&"--help".to_owned()) {
        print!("{}", USAGE_STRING);
        return
    }
    if args.contains(&"--version".to_owned()) {
        println!("takle (takuzu) {}", VERSION);
        return
    }
    if args.len() == 0 { solve_from(&mut stdin()); }
    else {
        takle(&args[0], args.len() > 1);
        for filename in args.iter().skip(1) {
            print!("\n");
            takle(filename, true);
        }
    }
}

/// Opens a file (or stdin) and feeds
/// the source to the solving + printing function.
fn takle(filename: &String, print_filename: bool) {
    if filename == "-" {
        if print_filename { println!("-"); }
        solve_from(&mut stdin());
    }
    else {
        let mut file = match File::open(filename) {
            Ok(file) => file,
            Err(err) => {
                write!(stderr(), "\"{}\": {}\n", filename, err).unwrap();
                return
            }
        };
        if print_filename { println!("{}", filename); }
        solve_from(&mut file);
    }
}

/// Reads a grid from a source, triggers the solving algorithm
/// and prints the solutions.
pub fn solve_from(source: &mut Source) {
    let grid = match source.source() {
        Ok(grid) => grid,
        Err(err) => {
            write!(stderr(), "error: {}\n", err.0).unwrap();
            return
        },
    };
    let solutions = grid.solve_backtrack();
    print_solutions(&grid, &solutions);
}

/// Prints the solution(s) to a grid on `stdout`.
///
/// Prints the grids with colors if appropriate (if `stdout` is a terminal).
/// If there is more than one solution, the grids are separated by
/// an empty line and preceded by a numbered label.
fn print_solutions(grid: &Grid, solutions: &Vec<Grid>) {
    if solutions.len() == 0 { write!(stderr(), "no solution\n").unwrap(); }
    else if solutions.len() == 1 {
        if isatty_stdout() { print!("{}", solutions[0].to_string_diff(&grid)); }
        else { print!("{}", solutions[0]); }
    }
    else {
        if isatty_stdout() {
            println!("solution 1");
            print!("{}", solutions[0].to_string_diff(&grid));
            for (i, sol) in solutions.into_iter().enumerate().skip(1) {
                println!("\nsolution {}", i + 1);
                print!("{}", sol.to_string_diff(&grid));
            }
        }
        else {
            print!("{}", solutions[0]);
            for sol in solutions.into_iter().skip(1) { print!("\n{}", sol); }
        }
    }
}

/// Returns `true` if `stdout` is a terminal.
pub fn isatty_stdout() -> bool {
    match unsafe { libc::isatty(libc::STDOUT_FILENO) } {
        1 => true,
        _ => false,
    }
}
<commit_msg>monomorphize solve_from<commit_after>//! A Takuzu (a.k.a. Binairo) solver.
//!
//! # Usage
//!
//! ```shell
//! tackle [FILE]...
//! tackle {--help | --version}
//! ```
//!
//! If no `FILE` is provided, or if `FILE` is '`-`', reads from standard input.

extern crate libc;
extern crate takuzu;

use std::fs::File;
use std::io::{stderr, stdin, Write};

use takuzu::{Grid, Source};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE_STRING: &'static str =
r#"Usage: tackle [FILE]...
       tackle {--help | --version}

If no FILE is provided, or if FILE is "-", read from standard input.

Options:
    --help       display this message and exit
    --version    display the version and exit
"#;

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();
    if args.contains(&"--help".to_owned()) {
        print!("{}", USAGE_STRING);
        return
    }
    if args.contains(&"--version".to_owned()) {
        println!("takle (takuzu) {}", VERSION);
        return
    }
    if args.len() == 0 { solve_from(&mut stdin()); }
    else {
        takle(&args[0], args.len() > 1);
        for filename in args.iter().skip(1) {
            print!("\n");
            takle(filename, true);
        }
    }
}

/// Opens a file (or stdin) and feeds
/// the source to the solving + printing function.
fn takle(filename: &String, print_filename: bool) {
    if filename == "-" {
        if print_filename { println!("-"); }
        solve_from(&mut stdin());
    }
    else {
        let mut file = match File::open(filename) {
            Ok(file) => file,
            Err(err) => {
                write!(stderr(), "\"{}\": {}\n", filename, err).unwrap();
                return
            }
        };
        if print_filename { println!("{}", filename); }
        solve_from(&mut file);
    }
}

/// Reads a grid from a source, triggers the solving algorithm
/// and prints the solutions.
pub fn solve_from<T: Source>(source: &mut T) {
    let grid = match source.source() {
        Ok(grid) => grid,
        Err(err) => {
            write!(stderr(), "error: {}\n", err.0).unwrap();
            return
        },
    };
    let solutions = grid.solve_backtrack();
    print_solutions(&grid, &solutions);
}

/// Prints the solution(s) to a grid on `stdout`.
///
/// Prints the grids with colors if appropriate (if `stdout` is a terminal).
/// If there is more than one solution, the grids are separated by
/// an empty line and preceded by a numbered label.
fn print_solutions(grid: &Grid, solutions: &Vec<Grid>) {
    if solutions.len() == 0 { write!(stderr(), "no solution\n").unwrap(); }
    else if solutions.len() == 1 {
        if isatty_stdout() { print!("{}", solutions[0].to_string_diff(&grid)); }
        else { print!("{}", solutions[0]); }
    }
    else {
        if isatty_stdout() {
            println!("solution 1");
            print!("{}", solutions[0].to_string_diff(&grid));
            for (i, sol) in solutions.into_iter().enumerate().skip(1) {
                println!("\nsolution {}", i + 1);
                print!("{}", sol.to_string_diff(&grid));
            }
        }
        else {
            print!("{}", solutions[0]);
            for sol in solutions.into_iter().skip(1) { print!("\n{}", sol); }
        }
    }
}

/// Returns `true` if `stdout` is a terminal.
pub fn isatty_stdout() -> bool {
    match unsafe { libc::isatty(libc::STDOUT_FILENO) } {
        1 => true,
        _ => false,
    }
}
<|endoftext|>