<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate semver;
extern crate toml;

use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fmt;
use std::fs::{self, OpenOptions, File};
use std::io::{Read, Write, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::process;

type Dependency = (String, toml::Value);

static USAGE: &'static str = "
Usage:
    cargo add [options] <dep>...
    cargo add [options] <dep> (--version | --path | --git) <source>
    cargo add -h | --help

Options:
    --manifest-path PATH    Path to the manifest to add a dependency to.
    -h --help               Show this help page.

Add a dependency to the crate's Cargo.toml file. If no source is specified, the
source will be set to a wild-card version dependency from the source's default
crate registry.

If a version is specified, it will be validated as a valid semantic version
requirement. No other kind of source will be validated, and the registry will
not be polled to guarantee that a crate meeting that version requirement
actually exists.
";

#[derive(Debug, RustcDecodable)]
//Docopts input args.
struct Args {
    arg_dep: Vec<String>,
    arg_source: String,
    flag_manifest_path: Option<String>,
    flag_version: bool,
    flag_git: bool,
    flag_path: bool,
}

#[derive(Debug)]
// Catch-all error for misconfigured crates.
pub struct ManifestError;

impl Error for ManifestError {
    fn description(&self) -> &str {
        "Your Cargo.toml is either missing or incorrectly structured."
    }
}

impl fmt::Display for ManifestError {
    fn fmt(&self, format: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        format.write_str(self.description())
    }
}

// Parse command-line input into key/value data that can be added to the TOML.
fn parse_dependency(dep: &String, args: &Args) -> Result<Dependency, Box<Error>> {
    if args.flag_version { parse_semver(&args.arg_source) }
    else if args.flag_git { parse_git(&args.arg_source) }
    else if args.flag_path { parse_path(&args.arg_source) }
    else { Ok(toml::Value::String(String::from("*"))) }
    .map(|data| (dep.clone(), data))
}

// Parse (and validate) a version requirement to the correct TOML data.
fn parse_semver(version: &String) -> Result<toml::Value, Box<Error>> {
    try!(semver::VersionReq::parse(version));
    Ok(toml::Value::String(version.clone()))
}

// Parse a git source to the correct TOML data.
fn parse_git(repo: &String) -> Result<toml::Value, Box<Error>> {
    let mut dep = BTreeMap::new();
    dep.insert(String::from("git"), toml::Value::String(repo.clone()));
    Ok(toml::Value::Table(dep))
}

// Parse a path to the correct TOML data.
fn parse_path(path: &String) -> Result<toml::Value, Box<Error>> {
    let mut dep = BTreeMap::new();
    dep.insert(String::from("path"), toml::Value::String(path.clone()));
    Ok(toml::Value::Table(dep))
}

// If a manifest is specified, return that one, otherise perform a manifest search starting from
// the current directory.
fn find_manifest(specified: Option<&String>) -> Result<PathBuf, Box<Error>> {
    specified.map(PathBuf::from).ok_or(())
    .or_else(|_| env::current_dir().map_err(From::from)
                 .and_then(|ref dir| manifest_search(dir).map_err(From::from)))
}

// Search for Cargo.toml in this directory and recursively up the tree until one is found.
#[allow(unconditional_recursion)] //Incorrect lint; recursion is conditional.
fn manifest_search(dir: &Path) -> Result<PathBuf, ManifestError> {
    let manifest = dir.join("Cargo.toml");
    fs::metadata(&manifest).map(|_| manifest)
    .or(dir.parent().ok_or(ManifestError).and_then(manifest_search))
}

// Read all the contents of a file & parse as a TOML table.
fn read_as_toml(file: &mut File) -> Result<BTreeMap<String, toml::Value>, Box<Error>> {
    let mut data = String::new();
    try!(file.read_to_string(&mut data));
    let mut parser = toml::Parser::new(&data);
    parser.parse().ok_or(parser.errors.pop()).map_err(Option::unwrap).map_err(From::from)
}

// Overwrite a file with TOML data.
fn write_from_toml(file: &mut File, mut toml: BTreeMap<String, toml::Value>)
        -> Result<(), Box<Error>> {
    try!(file.seek(SeekFrom::Start(0)));
    let (proj_header, proj_data) =
        try!(toml.remove("package").map(|data| ("package", data))
             .or_else(|| toml.remove("project").map(|data| ("project", data)))
             .ok_or(ManifestError));
    write!(file, "[{}]\n{}{}", proj_header, proj_data,
           toml::Value::Table(toml)).map_err(From::from)
}

// Add a dependency to a Cargo.toml.
fn insert_dependency(manifest: &mut BTreeMap<String, toml::Value>, (name, data): Dependency)
        -> Result<(), ManifestError> {
    match manifest.entry(String::from("dependencies"))
    .or_insert(toml::Value::Table(BTreeMap::new())) {
        &mut toml::Value::Table(ref mut deps) => {
            deps.insert(name, data);
            Ok(())
        }
        _ => Err(ManifestError)
    }
}

fn main() {
    //1. Generate an Args struct from the docopts string.
    docopt::Docopt::new(USAGE).and_then(|d| d.decode::<Args>()).or_else(|err| err.exit())
    //2. Generate a list of dependencies & a manifest file handle from the Args.
    //[Args -> (File, Vec<Dependency>)]
    .and_then(|args| {
        args.arg_dep.iter()
        .map(|dep| parse_dependency(dep, &args))
        .collect::<Result<Vec<_>, _>>()
        .and_then(|deps| {
            find_manifest(args.flag_manifest_path.as_ref())
            .and_then(|path| OpenOptions::new().read(true).write(true)
                                               .open(path).map_err(From::from))
            .map(|manifest| (manifest, deps))
        })
    })
    //3. Add the dependencies to the manifest. [(File, Vec<Dependency>) -> ()]
    .and_then(|(mut manifest, deps)| {
        read_as_toml(&mut manifest)
        .and_then(|mut toml_data| deps.into_iter()
                                 .map(|dep| insert_dependency(&mut toml_data, dep))
                                 .collect::<Result<Vec<_>, _>>()
                                 .map_err(From::from)
                                 .map(|_| toml_data))
        .and_then(|toml_data| write_from_toml(&mut manifest, toml_data))
    })
    //4. Print error message and return error code on failure.
    .or_else(|err| -> Result<(), Box<Error>> {
        println!("Could not add dependency.\n\nERROR: {:?}", err);
        process::exit(1);
    }).ok();
}
<commit_msg>Replace error message Debug insert with a Display insert.<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate semver;
extern crate toml;

use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::fmt;
use std::fs::{self, OpenOptions, File};
use std::io::{Read, Write, Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::process;

type Dependency = (String, toml::Value);

static USAGE: &'static str = "
Usage:
    cargo add [options] <dep>...
    cargo add [options] <dep> (--version | --path | --git) <source>
    cargo add -h | --help

Options:
    --manifest-path PATH    Path to the manifest to add a dependency to.
    -h --help               Show this help page.

Add a dependency to the crate's Cargo.toml file. If no source is specified, the
source will be set to a wild-card version dependency from the source's default
crate registry.

If a version is specified, it will be validated as a valid semantic version
requirement. No other kind of source will be validated, and the registry will
not be polled to guarantee that a crate meeting that version requirement
actually exists.
";

#[derive(Debug, RustcDecodable)]
//Docopts input args.
struct Args {
    arg_dep: Vec<String>,
    arg_source: String,
    flag_manifest_path: Option<String>,
    flag_version: bool,
    flag_git: bool,
    flag_path: bool,
}

#[derive(Debug)]
// Catch-all error for misconfigured crates.
pub struct ManifestError;

impl Error for ManifestError {
    fn description(&self) -> &str {
        "Your Cargo.toml is either missing or incorrectly structured."
    }
}

impl fmt::Display for ManifestError {
    fn fmt(&self, format: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        format.write_str(self.description())
    }
}

// Parse command-line input into key/value data that can be added to the TOML.
fn parse_dependency(dep: &String, args: &Args) -> Result<Dependency, Box<Error>> {
    if args.flag_version { parse_semver(&args.arg_source) }
    else if args.flag_git { parse_git(&args.arg_source) }
    else if args.flag_path { parse_path(&args.arg_source) }
    else { Ok(toml::Value::String(String::from("*"))) }
    .map(|data| (dep.clone(), data))
}

// Parse (and validate) a version requirement to the correct TOML data.
fn parse_semver(version: &String) -> Result<toml::Value, Box<Error>> {
    try!(semver::VersionReq::parse(version));
    Ok(toml::Value::String(version.clone()))
}

// Parse a git source to the correct TOML data.
fn parse_git(repo: &String) -> Result<toml::Value, Box<Error>> {
    let mut dep = BTreeMap::new();
    dep.insert(String::from("git"), toml::Value::String(repo.clone()));
    Ok(toml::Value::Table(dep))
}

// Parse a path to the correct TOML data.
fn parse_path(path: &String) -> Result<toml::Value, Box<Error>> {
    let mut dep = BTreeMap::new();
    dep.insert(String::from("path"), toml::Value::String(path.clone()));
    Ok(toml::Value::Table(dep))
}

// If a manifest is specified, return that one, otherise perform a manifest search starting from
// the current directory.
fn find_manifest(specified: Option<&String>) -> Result<PathBuf, Box<Error>> {
    specified.map(PathBuf::from).ok_or(())
    .or_else(|_| env::current_dir().map_err(From::from)
                 .and_then(|ref dir| manifest_search(dir).map_err(From::from)))
}

// Search for Cargo.toml in this directory and recursively up the tree until one is found.
#[allow(unconditional_recursion)] //Incorrect lint; recursion is conditional.
fn manifest_search(dir: &Path) -> Result<PathBuf, ManifestError> {
    let manifest = dir.join("Cargo.toml");
    fs::metadata(&manifest).map(|_| manifest)
    .or(dir.parent().ok_or(ManifestError).and_then(manifest_search))
}

// Read all the contents of a file & parse as a TOML table.
fn read_as_toml(file: &mut File) -> Result<BTreeMap<String, toml::Value>, Box<Error>> {
    let mut data = String::new();
    try!(file.read_to_string(&mut data));
    let mut parser = toml::Parser::new(&data);
    parser.parse().ok_or(parser.errors.pop()).map_err(Option::unwrap).map_err(From::from)
}

// Overwrite a file with TOML data.
fn write_from_toml(file: &mut File, mut toml: BTreeMap<String, toml::Value>)
        -> Result<(), Box<Error>> {
    try!(file.seek(SeekFrom::Start(0)));
    let (proj_header, proj_data) =
        try!(toml.remove("package").map(|data| ("package", data))
             .or_else(|| toml.remove("project").map(|data| ("project", data)))
             .ok_or(ManifestError));
    write!(file, "[{}]\n{}{}", proj_header, proj_data,
           toml::Value::Table(toml)).map_err(From::from)
}

// Add a dependency to a Cargo.toml.
fn insert_dependency(manifest: &mut BTreeMap<String, toml::Value>, (name, data): Dependency)
        -> Result<(), ManifestError> {
    match manifest.entry(String::from("dependencies"))
    .or_insert(toml::Value::Table(BTreeMap::new())) {
        &mut toml::Value::Table(ref mut deps) => {
            deps.insert(name, data);
            Ok(())
        }
        _ => Err(ManifestError)
    }
}

fn main() {
    //1. Generate an Args struct from the docopts string.
    docopt::Docopt::new(USAGE).and_then(|d| d.decode::<Args>()).or_else(|err| err.exit())
    //2. Generate a list of dependencies & a manifest file handle from the Args.
    //[Args -> (File, Vec<Dependency>)]
    .and_then(|args| {
        args.arg_dep.iter()
        .map(|dep| parse_dependency(dep, &args))
        .collect::<Result<Vec<_>, _>>()
        .and_then(|deps| {
            find_manifest(args.flag_manifest_path.as_ref())
            .and_then(|path| OpenOptions::new().read(true).write(true)
                                               .open(path).map_err(From::from))
            .map(|manifest| (manifest, deps))
        })
    })
    //3. Add the dependencies to the manifest. [(File, Vec<Dependency>) -> ()]
    .and_then(|(mut manifest, deps)| {
        read_as_toml(&mut manifest)
        .and_then(|mut toml_data| deps.into_iter()
                                 .map(|dep| insert_dependency(&mut toml_data, dep))
                                 .collect::<Result<Vec<_>, _>>()
                                 .map_err(From::from)
                                 .map(|_| toml_data))
        .and_then(|toml_data| write_from_toml(&mut manifest, toml_data))
    })
    //4. Print error message and return error code on failure.
    .or_else(|err| -> Result<(), Box<Error>> {
        println!("Could not add dependency.\n\nERROR: {}", err);
        process::exit(1);
    }).ok();
}
<|endoftext|>


<commit_before>#![recursion_limit = "1024"]

extern crate serde;
extern crate serde_json;
#[macro_use] extern crate error_chain;
extern crate flate2;
extern crate tar;
extern crate rustc_perf_collector;
extern crate env_logger;
extern crate reqwest;

mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types
    error_chain! {
        foreign_links {
            Reqwest(::reqwest::Error);
            Serde(::serde_json::Error);
            Io(::std::io::Error);
        }
    }
}

use errors::*;

quick_main!(run);

use std::fs::{self, File, OpenOptions};
use std::env;
use std::str;
use std::path::{Path, PathBuf};
use std::io::{Read, Write, BufReader};
use std::process::Command;

use rustc_perf_collector::{Pass, Run, Patch};

use tar::Archive;
use flate2::bufread::GzDecoder;
use serde_json::Value;
use reqwest::header::Authorization;

const BASE_PATH: &'static str = "https://s3.amazonaws.com/rust-lang-ci/rustc-builds";
const GH_API_TOKEN: &'static str = env!("GH_API_TOKEN");

fn get_and_extract(url: &str, into: &str, is_std: bool) -> Result<()> {
    println!("requesting: {}", url);
    let resp = reqwest::get(url)?;
    println!("{}", resp.status());
    let mut resp = BufReader::new(resp);

    let decoder = GzDecoder::new(&mut resp)?;
    let mut archive = Archive::new(decoder);
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?.into_owned();
        let mut components = path.components();
        assert!(components.next().is_some(), "strip container directory");
        let path = components.as_path();
        let path = if is_std {
            if let Ok(path) = path.strip_prefix("rust-std-x86_64-unknown-linux-gnu/lib/rustlib") {
                Path::new("rustc/lib/rustlib").join(path)
            } else {
                continue;
            }
        } else {
            path.into()
        };
        let path = Path::new(into).join(path);
        fs::create_dir_all(&path.parent().unwrap())
            .chain_err(|| format!("could not create intermediate directories for {}",
                    path.display()))?;
        entry.unpack(path)?;
    }
    Ok(())
}

fn process_output(name: &str, output: Vec<u8>) -> Result<Vec<Pass>> {
    let output = String::from_utf8(output)
        .chain_err(|| format!("unable to convert output of {} to UTF-8", name))?;
    let mut passes = Vec::new();

    for line in output.lines() {
        if line.starts_with("time: ") {
            let time = &line["time: ".len()..line.find(";").unwrap()];
            let time: f64 = time.parse().chain_err(|| format!("parsed time: {:?}", time))?;

            let mem = &line[line.find("rss: ").unwrap() + 5..line.find("MB").unwrap()];
            let mem: u64 = mem.parse().chain_err(|| format!("parsed memory: {:?}", mem))?;

            let name = line[line.find("MB\t").unwrap() + 3..].to_string();
            passes.push(Pass {
                name: name,
                time: time,
                mem: mem,
            });
        } else if line.starts_with("  time: ") {
            // XXX: sub passes currently cause problems because their names are inconsistent in
            // incremental runs, especially codegen passes
            //let time = &line["  time: ".len()..line.find(";").unwrap()];
            //let time: f64 = time.parse().chain_err(|| format!("parsed time: {:?}", time))?;

            //let mem = &line[line.find("rss: ").unwrap() + 5..line.find("MB").unwrap()];
            //let mem: u64 = mem.parse().chain_err(|| format!("parsed memory: {:?}", mem))?;

            //let name = line[line.find("MB\t").unwrap() + 3..].to_string();
            //sub_passes.insert(name.clone(), Pass {
            //    name: name,
            //    time: time,
            //    mem: mem,
            //    sub_passes: HashMap::new(),
            //});
        } else {
            //println!("unhandled line: {}", line);
        }
    }

    Ok(passes)
}

// if running with cargo run, we want to avoid things like CARGO_INCREMENTAL
// sneaking into the command's environment, but we do need the PATH to
// find linkers and other things that cargo and rust needs.
fn command<P: AsRef<Path>>(path: P, cargo: &Path, rustc: &Path) -> Command {
    let mut command = Command::new(path.as_ref().as_os_str());
    command
        .env_clear()
        .env("PATH", env::var("PATH").unwrap_or_default())
        .env("CARGO", &cargo)
        .env("RUSTC", &rustc);
    command
}

struct PassAverager {
    state: Vec<Pass>,
    runs: u64
}

impl PassAverager {
    fn new(state: Vec<Pass>) -> Self {
        Self {
            state: state,
            runs: 0,
        }
    }

    fn average_with(
        &mut self,
        b: Vec<Pass>,
    ) -> Result<()> {
        self.runs += 1;

        for a in &mut self.state {
            let b = match b.iter().find(|p| p.name == a.name) {
                Some(b) => b,
                None => bail!("expected name {} to exist in both a and b", a.name),
            };
            a.time = a.time + ((b.time - a.time) / (self.runs as f64));
            a.mem = a.mem + ((b.mem - b.mem) / self.runs);
        }

        Ok(())
    }
}

fn run_commit(commit: &str, benchmarks: &[PathBuf]) -> Result<()> {
    let unpack_into = format!("rust-{}", commit);
    let triple = "x86_64-unknown-linux-gnu";
    get_and_extract(
        &format!("{}/{}/rustc-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        false,
    )?;
    get_and_extract(
        &format!("{}/{}/rust-std-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        true,
    )?;
    get_and_extract(
        &format!("{}/{}/cargo-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        false,
    )?;
    let rustc = PathBuf::from(format!("rust-{}/rustc/bin/rustc", commit)).canonicalize()
        .chain_err(|| "failed to canonicalize rustc path")?;
    let cargo = PathBuf::from(format!("rust-{}/cargo/bin/cargo", commit)).canonicalize()
        .chain_err(|| "failed to canonicalize cargo path")?;

    let version = String::from_utf8(command(&rustc, &cargo, &rustc).arg("--version").output()
        .chain_err(|| format!("{} --version", rustc.display()))?.stdout).unwrap();

    println!("version: {}", version);

    for path in benchmarks {
        let name = path.display().to_string().replace("benchmarks/", "");
        println!("processing {}", name);
        let output = command("make", &cargo, &rustc).arg("patches").current_dir(&path).output()?;
        let mut patches = str::from_utf8(&output.stdout)
            .chain_err(|| format!("make patches in {} returned non UTF-8 output", path.display()))?
            .split_whitespace()
            .collect::<Vec<_>>();
        if patches.is_empty() {
            patches.push("");
        }

        let mut patch_runs: Vec<Patch> = Vec::new();
        for _ in 0..3 {
            for patch in &patches {
                println!("running `make all{}`", patch);
                let output = command("make", &cargo, &rustc).arg(&format!("all{}", patch))
                    .current_dir(&path)
                    .env("CARGO_OPTS", "")
                    .env("CARGO_RUSTC_OPTS", "-Z time-passes")
                    .output()?;

                if !output.status.success() {
                    bail!("stderr non empty: {}", String::from_utf8_lossy(&output.stderr));
                }

                let patch_index = if let Some(p) = patch_runs.iter().position(|p_run| p_run.patch == *patch) {
                    p
                } else {
                    patch_runs.push(Patch {
                        patch: patch.to_string(),
                        name: name.clone(),
                        runs: Vec::new(),
                    });
                    patch_runs.len() - 1
                };

                patch_runs[patch_index].runs.push(Run {
                    name: format!("{}{}", name, patch),
                    passes: process_output(&format!("{}{}", name, patch), output.stdout)?,
                });
            }
            if !command("make", &cargo, &rustc).arg("touch").current_dir(&path).status()?.success() {
                bail!("{}: make touch failed.", path.display());
            }
        }

        let mut single_runs = Vec::new();
        for patch_run in patch_runs {
            let name = patch_run.name + &patch_run.patch;
            let mut runs = patch_run.runs.into_iter();
            let mut pa = PassAverager::new(runs.next().unwrap().passes);
            for run in runs {
                pa.average_with(run.passes)?;
            }
            single_runs.push(Run {
                name: name,
                passes: pa.state,
            });
        }

        let filepath = format!("times/{}-{}-{}.json",
            &commit, triple, name);
        println!("creating file {}", filepath);
        let mut file = File::create(&filepath)?;
        serde_json::to_writer_pretty(&mut file, &single_runs)?;
        if !command("make", &cargo, &rustc).arg("clean").current_dir(&path).status()?.success() {
            bail!("{}: make touch failed.", path.display());
        }
    }

    fs::remove_dir_all(&unpack_into).unwrap_or_else(|err| {
        println!("failed to remove {}, please do so manually: {:?}", unpack_into, err);
    });

    Ok(())
}

const COMMIT_FILE: &'static str = "last-commit-sha";

fn get_new_commit_shas(client: &reqwest::Client) -> Result<Vec<String>> {
    let mut commit_file = File::open(COMMIT_FILE)
        .chain_err(|| format!("expected {} to exist, and contain the last tested commit sha", COMMIT_FILE))?;

    let mut last_commit = String::new();
    commit_file.read_to_string(&mut last_commit)?;

    if last_commit.is_empty() {
        bail!("{} was empty", COMMIT_FILE);
    }

    let last_commit = last_commit.trim();

    fn request(client: &reqwest::Client, url: &str, last_commit: &str) -> Result<Vec<String>> {
        fn convert_to_str_array(url: &str, value: Value) -> Result<Vec<String>> {
            let value = if let Value::Array(arr) = value {
                arr.into_iter().map(|value| {
                    if let Value::Object(mut map) = value {
                        if let Some(commit) = map.remove("sha") {
                            if let Value::String(commit) = commit {
                                return Ok(commit);
                            }
                        }
                    }
                    bail!("{} returned element without string sha key in array element", url)
                }).collect::<Result<Vec<String>>>()?
            } else {
                bail!("{} returned non-array response: {}", url, value);
            };

            Ok(value)
        }

        println!("Requesting: {}", url);

        let mut response = client.get(url)
            .header(Authorization(format!("token {}", GH_API_TOKEN)))
            .send().chain_err(|| format!("API request to {}", url))?;
        let value: Value = serde_json::from_reader(&mut response)
            .chain_err(|| format!("API request to {} deserialization", url))?;
        let mut commits = convert_to_str_array(url, value)?;

        if let Some(pos) = commits.iter().position(|commit| commit == last_commit) {
            commits.truncate(pos);
            return Ok(commits);
        }

        if let Some(headers) = response.headers().get_raw("Link") {
            if let Some(next) = headers.iter().map(|s| str::from_utf8(s).unwrap()).flat_map(|s| s.split(", ")).find(|s| s.contains(r#"rel="next"#)) {
                let url = &next[1..next.find(">").unwrap()];
                let next_value = request(client, url, last_commit)?;
                commits.extend(next_value);
                if let Some(_) = commits.iter().find(|commit| *commit == last_commit) {
                    return Ok(commits);
                }

            }
        }

        Ok(commits)
    }

    let commits = request(
        client,
        "https://api.github.com/repos/rust-lang/rust/commits?author=bors&per_page=100",
        &last_commit,
    )?;

    Ok(commits)
}

fn run() -> Result<()> {
    env_logger::init().expect("logger initialization successful");

    let mut benchmarks = Vec::new();
    for entry in fs::read_dir("benchmarks")? {
        let entry = entry?;
        let path = entry.path();
        if path.ends_with(".git") || path.ends_with("scripts") || !entry.file_type()?.is_dir() {
            continue;
        }

        benchmarks.push(path);
    }

    let client = reqwest::Client::new()?;
    let commits = get_new_commit_shas(&client)?;
    if !commits.is_empty() {
        println!("new commits: {:?}", commits);
        // We need to reverse the commits in order to have the first commit be the one directly
        // after the commit in the commit file
        for commit in commits.iter().rev() {
            run_commit(&commit, &benchmarks)?;

            // Since we successfully ran for this commit, we update the file to mark the latest
            // commit as this one
            let mut commit_file = File::create(COMMIT_FILE)?;
            commit_file.write_all(commit.as_bytes())?;
        }
    } else {
        println!("Nothing to do; no new commits.");
    }

    Ok(())
}
<commit_msg>Remove OpenOptions import<commit_after>#![recursion_limit = "1024"]

extern crate serde;
extern crate serde_json;
#[macro_use] extern crate error_chain;
extern crate flate2;
extern crate tar;
extern crate rustc_perf_collector;
extern crate env_logger;
extern crate reqwest;

mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types
    error_chain! {
        foreign_links {
            Reqwest(::reqwest::Error);
            Serde(::serde_json::Error);
            Io(::std::io::Error);
        }
    }
}

use errors::*;

quick_main!(run);

use std::fs::{self, File};
use std::env;
use std::str;
use std::path::{Path, PathBuf};
use std::io::{Read, Write, BufReader};
use std::process::Command;

use rustc_perf_collector::{Pass, Run, Patch};

use tar::Archive;
use flate2::bufread::GzDecoder;
use serde_json::Value;
use reqwest::header::Authorization;

const BASE_PATH: &'static str = "https://s3.amazonaws.com/rust-lang-ci/rustc-builds";
const GH_API_TOKEN: &'static str = env!("GH_API_TOKEN");

fn get_and_extract(url: &str, into: &str, is_std: bool) -> Result<()> {
    println!("requesting: {}", url);
    let resp = reqwest::get(url)?;
    println!("{}", resp.status());
    let mut resp = BufReader::new(resp);

    let decoder = GzDecoder::new(&mut resp)?;
    let mut archive = Archive::new(decoder);
    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?.into_owned();
        let mut components = path.components();
        assert!(components.next().is_some(), "strip container directory");
        let path = components.as_path();
        let path = if is_std {
            if let Ok(path) = path.strip_prefix("rust-std-x86_64-unknown-linux-gnu/lib/rustlib") {
                Path::new("rustc/lib/rustlib").join(path)
            } else {
                continue;
            }
        } else {
            path.into()
        };
        let path = Path::new(into).join(path);
        fs::create_dir_all(&path.parent().unwrap())
            .chain_err(|| format!("could not create intermediate directories for {}",
                    path.display()))?;
        entry.unpack(path)?;
    }
    Ok(())
}

fn process_output(name: &str, output: Vec<u8>) -> Result<Vec<Pass>> {
    let output = String::from_utf8(output)
        .chain_err(|| format!("unable to convert output of {} to UTF-8", name))?;
    let mut passes = Vec::new();

    for line in output.lines() {
        if line.starts_with("time: ") {
            let time = &line["time: ".len()..line.find(";").unwrap()];
            let time: f64 = time.parse().chain_err(|| format!("parsed time: {:?}", time))?;

            let mem = &line[line.find("rss: ").unwrap() + 5..line.find("MB").unwrap()];
            let mem: u64 = mem.parse().chain_err(|| format!("parsed memory: {:?}", mem))?;

            let name = line[line.find("MB\t").unwrap() + 3..].to_string();
            passes.push(Pass {
                name: name,
                time: time,
                mem: mem,
            });
        } else if line.starts_with("  time: ") {
            // XXX: sub passes currently cause problems because their names are inconsistent in
            // incremental runs, especially codegen passes
            //let time = &line["  time: ".len()..line.find(";").unwrap()];
            //let time: f64 = time.parse().chain_err(|| format!("parsed time: {:?}", time))?;

            //let mem = &line[line.find("rss: ").unwrap() + 5..line.find("MB").unwrap()];
            //let mem: u64 = mem.parse().chain_err(|| format!("parsed memory: {:?}", mem))?;

            //let name = line[line.find("MB\t").unwrap() + 3..].to_string();
            //sub_passes.insert(name.clone(), Pass {
            //    name: name,
            //    time: time,
            //    mem: mem,
            //    sub_passes: HashMap::new(),
            //});
        } else {
            //println!("unhandled line: {}", line);
        }
    }

    Ok(passes)
}

// if running with cargo run, we want to avoid things like CARGO_INCREMENTAL
// sneaking into the command's environment, but we do need the PATH to
// find linkers and other things that cargo and rust needs.
fn command<P: AsRef<Path>>(path: P, cargo: &Path, rustc: &Path) -> Command {
    let mut command = Command::new(path.as_ref().as_os_str());
    command
        .env_clear()
        .env("PATH", env::var("PATH").unwrap_or_default())
        .env("CARGO", &cargo)
        .env("RUSTC", &rustc);
    command
}

struct PassAverager {
    state: Vec<Pass>,
    runs: u64
}

impl PassAverager {
    fn new(state: Vec<Pass>) -> Self {
        Self {
            state: state,
            runs: 0,
        }
    }

    fn average_with(
        &mut self,
        b: Vec<Pass>,
    ) -> Result<()> {
        self.runs += 1;

        for a in &mut self.state {
            let b = match b.iter().find(|p| p.name == a.name) {
                Some(b) => b,
                None => bail!("expected name {} to exist in both a and b", a.name),
            };
            a.time = a.time + ((b.time - a.time) / (self.runs as f64));
            a.mem = a.mem + ((b.mem - b.mem) / self.runs);
        }

        Ok(())
    }
}

fn run_commit(commit: &str, benchmarks: &[PathBuf]) -> Result<()> {
    let unpack_into = format!("rust-{}", commit);
    let triple = "x86_64-unknown-linux-gnu";
    get_and_extract(
        &format!("{}/{}/rustc-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        false,
    )?;
    get_and_extract(
        &format!("{}/{}/rust-std-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        true,
    )?;
    get_and_extract(
        &format!("{}/{}/cargo-nightly-{}.tar.gz", BASE_PATH, commit, triple),
        &unpack_into,
        false,
    )?;
    let rustc = PathBuf::from(format!("rust-{}/rustc/bin/rustc", commit)).canonicalize()
        .chain_err(|| "failed to canonicalize rustc path")?;
    let cargo = PathBuf::from(format!("rust-{}/cargo/bin/cargo", commit)).canonicalize()
        .chain_err(|| "failed to canonicalize cargo path")?;

    let version = String::from_utf8(command(&rustc, &cargo, &rustc).arg("--version").output()
        .chain_err(|| format!("{} --version", rustc.display()))?.stdout).unwrap();

    println!("version: {}", version);

    for path in benchmarks {
        let name = path.display().to_string().replace("benchmarks/", "");
        println!("processing {}", name);
        let output = command("make", &cargo, &rustc).arg("patches").current_dir(&path).output()?;
        let mut patches = str::from_utf8(&output.stdout)
            .chain_err(|| format!("make patches in {} returned non UTF-8 output", path.display()))?
            .split_whitespace()
            .collect::<Vec<_>>();
        if patches.is_empty() {
            patches.push("");
        }

        let mut patch_runs: Vec<Patch> = Vec::new();
        for _ in 0..3 {
            for patch in &patches {
                println!("running `make all{}`", patch);
                let output = command("make", &cargo, &rustc).arg(&format!("all{}", patch))
                    .current_dir(&path)
                    .env("CARGO_OPTS", "")
                    .env("CARGO_RUSTC_OPTS", "-Z time-passes")
                    .output()?;

                if !output.status.success() {
                    bail!("stderr non empty: {}", String::from_utf8_lossy(&output.stderr));
                }

                let patch_index = if let Some(p) = patch_runs.iter().position(|p_run| p_run.patch == *patch) {
                    p
                } else {
                    patch_runs.push(Patch {
                        patch: patch.to_string(),
                        name: name.clone(),
                        runs: Vec::new(),
                    });
                    patch_runs.len() - 1
                };

                patch_runs[patch_index].runs.push(Run {
                    name: format!("{}{}", name, patch),
                    passes: process_output(&format!("{}{}", name, patch), output.stdout)?,
                });
            }
            if !command("make", &cargo, &rustc).arg("touch").current_dir(&path).status()?.success() {
                bail!("{}: make touch failed.", path.display());
            }
        }

        let mut single_runs = Vec::new();
        for patch_run in patch_runs {
            let name = patch_run.name + &patch_run.patch;
            let mut runs = patch_run.runs.into_iter();
            let mut pa = PassAverager::new(runs.next().unwrap().passes);
            for run in runs {
                pa.average_with(run.passes)?;
            }
            single_runs.push(Run {
                name: name,
                passes: pa.state,
            });
        }

        let filepath = format!("times/{}-{}-{}.json",
            &commit, triple, name);
        println!("creating file {}", filepath);
        let mut file = File::create(&filepath)?;
        serde_json::to_writer_pretty(&mut file, &single_runs)?;
        if !command("make", &cargo, &rustc).arg("clean").current_dir(&path).status()?.success() {
            bail!("{}: make touch failed.", path.display());
        }
    }

    fs::remove_dir_all(&unpack_into).unwrap_or_else(|err| {
        println!("failed to remove {}, please do so manually: {:?}", unpack_into, err);
    });

    Ok(())
}

const COMMIT_FILE: &'static str = "last-commit-sha";

fn get_new_commit_shas(client: &reqwest::Client) -> Result<Vec<String>> {
    let mut commit_file = File::open(COMMIT_FILE)
        .chain_err(|| format!("expected {} to exist, and contain the last tested commit sha", COMMIT_FILE))?;

    let mut last_commit = String::new();
    commit_file.read_to_string(&mut last_commit)?;

    if last_commit.is_empty() {
        bail!("{} was empty", COMMIT_FILE);
    }

    let last_commit = last_commit.trim();

    fn request(client: &reqwest::Client, url: &str, last_commit: &str) -> Result<Vec<String>> {
        fn convert_to_str_array(url: &str, value: Value) -> Result<Vec<String>> {
            let value = if let Value::Array(arr) = value {
                arr.into_iter().map(|value| {
                    if let Value::Object(mut map) = value {
                        if let Some(commit) = map.remove("sha") {
                            if let Value::String(commit) = commit {
                                return Ok(commit);
                            }
                        }
                    }
                    bail!("{} returned element without string sha key in array element", url)
                }).collect::<Result<Vec<String>>>()?
            } else {
                bail!("{} returned non-array response: {}", url, value);
            };

            Ok(value)
        }

        println!("Requesting: {}", url);

        let mut response = client.get(url)
            .header(Authorization(format!("token {}", GH_API_TOKEN)))
            .send().chain_err(|| format!("API request to {}", url))?;
        let value: Value = serde_json::from_reader(&mut response)
            .chain_err(|| format!("API request to {} deserialization", url))?;
        let mut commits = convert_to_str_array(url, value)?;

        if let Some(pos) = commits.iter().position(|commit| commit == last_commit) {
            commits.truncate(pos);
            return Ok(commits);
        }

        if let Some(headers) = response.headers().get_raw("Link") {
            if let Some(next) = headers.iter().map(|s| str::from_utf8(s).unwrap()).flat_map(|s| s.split(", ")).find(|s| s.contains(r#"rel="next"#)) {
                let url = &next[1..next.find(">").unwrap()];
                let next_value = request(client, url, last_commit)?;
                commits.extend(next_value);
                if let Some(_) = commits.iter().find(|commit| *commit == last_commit) {
                    return Ok(commits);
                }

            }
        }

        Ok(commits)
    }

    let commits = request(
        client,
        "https://api.github.com/repos/rust-lang/rust/commits?author=bors&per_page=100",
        &last_commit,
    )?;

    Ok(commits)
}

fn run() -> Result<()> {
    env_logger::init().expect("logger initialization successful");

    let mut benchmarks = Vec::new();
    for entry in fs::read_dir("benchmarks")? {
        let entry = entry?;
        let path = entry.path();
        if path.ends_with(".git") || path.ends_with("scripts") || !entry.file_type()?.is_dir() {
            continue;
        }

        benchmarks.push(path);
    }

    let client = reqwest::Client::new()?;
    let commits = get_new_commit_shas(&client)?;
    if !commits.is_empty() {
        println!("new commits: {:?}", commits);
        // We need to reverse the commits in order to have the first commit be the one directly
        // after the commit in the commit file
        for commit in commits.iter().rev() {
            run_commit(&commit, &benchmarks)?;

            // Since we successfully ran for this commit, we update the file to mark the latest
            // commit as this one
            let mut commit_file = File::create(COMMIT_FILE)?;
            commit_file.write_all(commit.as_bytes())?;
        }
    } else {
        println!("Nothing to do; no new commits.");
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![feature(io, path)]
use std::fs;
use std::io;
use std::io::{Read, ReadExt, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a + b);
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x + i);
            }
            &Mov(n) => {
                self.index += n
            }
            &In => {
                let mut c = vec![0u8];
                io::stdin().read(&mut c).unwrap();
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<commit_msg>chore: adapt to latest io and path changes<commit_after>#![feature(io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a + b);
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a + b);
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x + i);
            }
            &Mov(n) => {
                self.index += n
            }
            &In => {
                let mut c = vec![0u8];
                io::stdin().read(&mut c).unwrap();
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    self.run(ops.get());
                }
            }
        }
    }

    fn run(&mut self, ops: &[Op]) {
        for op in ops {
            self.step(op);
        }
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]

#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation};
use rustc::session::{config, Session};
use rustc::session::config::{Input, ErrorOutputType};
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        ClippyCompilerCalls {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(state.session,
                                                                             state
                                                                                .krate
                                                                                .as_ref()
                                                                                .expect("at this compilation stage \
                                                                                the krate must be parsed")
                                                                                .span);
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args()
            .skip(2)
            .find(|val| val.starts_with("--manifest-path="));

        let mut metadata =
            if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
                metadata
            } else {
                let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
                process::exit(101);
            };

        let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..])));

        let current_dir = std::env::current_dir();

        let package_index = metadata
            .packages
            .iter()
            .position(|package| {
                let package_manifest_path = Path::new(&package.manifest_path);
                if let Some(ref manifest_path) = manifest_path {
                    package_manifest_path == manifest_path
                } else {
                    let current_dir = current_dir
                        .as_ref()
                        .expect("could not read current directory");
                    let package_manifest_directory = package_manifest_path
                        .parent()
                        .expect("could not find parent directory of package manifest");
                    package_manifest_directory == current_dir
                }
            })
            .expect("could not find matching package");
        let package = metadata.packages.remove(package_index);
        for target in package.targets {
            let args = std::env::args().skip(2);
            if let Some(first) = target.kind.get(0) {
                if target.kind.len() > 1 || first.ends_with("lib") {
                    if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                        std::process::exit(code);
                    }
                } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                    if let Err(code) = process(vec![format!("--{}", first), target.name]
                                                   .into_iter()
                                                   .chain(args)) {
                        std::process::exit(code);
                    }
                }
            } else {
                panic!("badly formatted cargo metadata: target::kind is an empty array");
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust")
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "-Zno-trans");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(err_count) = result {
                if err_count > 0 {
                    std::process::exit(1);
                }
            }
        })
                .expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
    where I: Iterator<Item = String>
{

    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("-Zno-trans".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<commit_msg>Use `--emit=metadata` instead of `-Zno-trans`<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]

#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, CompilerCalls, RustcDefaultCalls, Compilation};
use rustc::session::{config, Session};
use rustc::session::config::{Input, ErrorOutputType};
use std::path::PathBuf;
use std::process::{self, Command};
use syntax::ast;
use std::io::{self, Write};

extern crate cargo_metadata;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        ClippyCompilerCalls {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(state.session,
                                                                             state
                                                                                .krate
                                                                                .as_ref()
                                                                                .expect("at this compilation stage \
                                                                                the krate must be parsed")
                                                                                .span);
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

use std::path::Path;

const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    --features               Features to compile for the package
    -V, --version            Print version info and exit

Other options are the same as `cargo rustc`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

The feature `cargo-clippy` is automatically defined for convenience. You can use
it to allow or deny lints from the code, eg.:

    #[cfg_attr(feature = "cargo-clippy", allow(needless_lifetimes))]
"#;

#[allow(print_stdout)]
fn show_help() {
    println!("{}", CARGO_CLIPPY_HELP);
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").map(|_| true).unwrap_or(false) {
        panic!("yummy");
    }

    // Check for version and help flags even when invoked as 'cargo-clippy'
    if std::env::args().any(|a| a == "--help" || a == "-h") {
        show_help();
        return;
    }
    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    if let Some("clippy") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) {
        // this arm is executed on the initial call to `cargo clippy`

        let manifest_path_arg = std::env::args()
            .skip(2)
            .find(|val| val.starts_with("--manifest-path="));

        let mut metadata =
            if let Ok(metadata) = cargo_metadata::metadata(manifest_path_arg.as_ref().map(AsRef::as_ref)) {
                metadata
            } else {
                let _ = io::stderr().write_fmt(format_args!("error: Could not obtain cargo metadata.\n"));
                process::exit(101);
            };

        let manifest_path = manifest_path_arg.map(|arg| PathBuf::from(Path::new(&arg["--manifest-path=".len()..])));

        let current_dir = std::env::current_dir();

        let package_index = metadata
            .packages
            .iter()
            .position(|package| {
                let package_manifest_path = Path::new(&package.manifest_path);
                if let Some(ref manifest_path) = manifest_path {
                    package_manifest_path == manifest_path
                } else {
                    let current_dir = current_dir
                        .as_ref()
                        .expect("could not read current directory");
                    let package_manifest_directory = package_manifest_path
                        .parent()
                        .expect("could not find parent directory of package manifest");
                    package_manifest_directory == current_dir
                }
            })
            .expect("could not find matching package");
        let package = metadata.packages.remove(package_index);
        for target in package.targets {
            let args = std::env::args().skip(2);
            if let Some(first) = target.kind.get(0) {
                if target.kind.len() > 1 || first.ends_with("lib") {
                    if let Err(code) = process(std::iter::once("--lib".to_owned()).chain(args)) {
                        std::process::exit(code);
                    }
                } else if ["bin", "example", "test", "bench"].contains(&&**first) {
                    if let Err(code) = process(vec![format!("--{}", first), target.name]
                                                   .into_iter()
                                                   .chain(args)) {
                        std::process::exit(code);
                    }
                }
            } else {
                panic!("badly formatted cargo metadata: target::kind is an empty array");
            }
        }
    } else {
        // this arm is executed when cargo-clippy runs `cargo rustc` with the `RUSTC`
        // env var set to itself

        let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
        let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
        let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
            format!("{}/toolchains/{}", home, toolchain)
        } else {
            option_env!("SYSROOT")
                .map(|s| s.to_owned())
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| s.trim().to_owned())
                })
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust")
        };

        rustc_driver::in_rustc_thread(|| {
            // this conditional check for the --sysroot flag is there so users can call
            // `cargo-clippy` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if env::args().any(|s| s == "--sysroot") {
                env::args().collect()
            } else {
                env::args()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::args().any(|s| s == "--emit=metadata");

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
            }

            let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
            let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
            if let Err(err_count) = result {
                if err_count > 0 {
                    std::process::exit(1);
                }
            }
        })
                .expect("rustc_thread failed");
    }
}

fn process<I>(old_args: I) -> Result<(), i32>
    where I: Iterator<Item = String>
{

    let mut args = vec!["rustc".to_owned()];

    let mut found_dashes = false;
    for arg in old_args {
        found_dashes |= arg == "--";
        args.push(arg);
    }
    if !found_dashes {
        args.push("--".to_owned());
    }
    args.push("--emit=metadata".to_owned());
    args.push("--cfg".to_owned());
    args.push(r#"feature="cargo-clippy""#.to_owned());

    let path = std::env::current_exe().expect("current executable path invalid");
    let exit_status = std::process::Command::new("cargo")
        .args(&args)
        .env("RUSTC", path)
        .spawn()
        .expect("could not run cargo")
        .wait()
        .expect("failed to wait for cargo?");

    if exit_status.success() {
        Ok(())
    } else {
        Err(exit_status.code().unwrap_or(-1))
    }
}
<|endoftext|>


<commit_before>use macroquad::prelude::*;

use colour::Colour;
use graph::Position;
use game::{Game, GameState};

mod colour;
mod graph;
mod grid;
mod game;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: u32,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: u32) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, game: &Game) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        let graph = &game.graph;
        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn click_while_solving(&self, game: &mut Game, position: Position) {
        let clicked_component = game.graph.find_component(&position);
        let colour = clicked_component.colour;

        game.fill_component_of_top_left_cell_with(colour);

        if game.graph.components.len() == 1 {
            game.state = GameState::Solved;

            if game.number_of_clicks <= game.allowed_clicks {
                println!(
                    "You win! You used {} out of {} available moves.",
                    game.number_of_clicks,
                    game.allowed_clicks,
                );
            } else {
                println!(
                    "You lose. You took {} moves but should have \
                            finished in {}.",
                    game.number_of_clicks,
                    game.allowed_clicks,
                );
            }
        }
    }

    fn handle_click(&self, game: &mut Game, mouse_position: (f32, f32)) {
        match game.state {
            GameState::Solving =>
                if let Some(position) = self.cell_position(mouse_position) {
                    self.click_while_solving(game, position);
                }

            GameState::Solved => (),
        }
    }
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;
    let number_of_colours = 4;

    let mut game = Game::create(size, number_of_colours);
    let mut ui = Ui::create(size);

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        if is_mouse_button_pressed(MouseButton::Left) {
            ui.handle_click(&mut game, mouse_position());
        }

        ui.resize();
        ui.render(&game);

        next_frame().await
    }
}
<commit_msg>Create new game on click the last one is finished<commit_after>use macroquad::prelude::*;

use colour::Colour;
use graph::Position;
use game::{Game, GameState};

mod colour;
mod graph;
mod grid;
mod game;

fn macroquad_colour(colour: Colour) -> Color {
    match colour {
        Colour::Red => color_u8!(255, 0, 0, 255),
        Colour::Yellow => color_u8!(255, 255, 0, 255),
        Colour::Green => color_u8!(0, 176, 0, 255),
        Colour::LightBrown => color_u8!(255, 204, 102, 255),
        Colour::Purple => color_u8!(128, 0, 128, 255),
        Colour::Cyan => color_u8!(0, 255, 255, 255),
        Colour::Blue => color_u8!(0, 0, 255, 255),
        Colour::Fuchsia => color_u8!(255, 0, 255, 255),
    }
}

fn draw_cell(grid_x: f32, grid_y: f32, cell_size: f32, position: &Position, colour: Colour) {
    let color = macroquad_colour(colour);
    draw_rectangle(
        grid_x + cell_size * position.column as f32,
        grid_y + cell_size * position.row as f32,
        cell_size,
        cell_size,
        color,
    );
}

struct Ui {
    /// Size of the grid in cells.
    size: u32,

    /// Size of the grid in pixels.  Assumes the grid is always square.
    grid_size: f32,

    /// Offset of the grid relative to the whole window along the horizontal axis.
    grid_x: f32,

    /// Offset of the grid relative to the whole window along the vertical axis.
    grid_y: f32,
}

impl Ui {
    fn create(size: u32) -> Ui {
        let mut ui = Ui {
            size,
            grid_size: 0.0,
            grid_x: 0.0,
            grid_y: 0.0,
        };

        ui.resize();

        ui
    }

    fn resize(&mut self) {
        let screen_height = screen_height();
        let screen_width = screen_width();

        let grid_size = screen_height.min(screen_width);
        self.grid_size = grid_size;
        self.grid_x = (screen_width - grid_size) / 2.0;
        self.grid_y = (screen_height - grid_size) / 2.0;
    }

    fn render(&self, game: &Game) {
        clear_background(BLACK);

        let grid_x = self.grid_x;
        let grid_y = self.grid_y;
        let cell_size = self.cell_size();

        let graph = &game.graph;
        for component in graph.neighbours.keys() {
            for position in &graph.components[component].cells {
                draw_cell(grid_x, grid_y, cell_size, position, graph.components[component].colour);
            }
        }
    }

    fn cell_size(&self) -> f32 {
        self.grid_size / self.size as f32
    }

    fn cell_position(&self, raw_position: (f32, f32)) -> Option<Position> {
        let (raw_x, raw_y) = raw_position;

        let cell_size = self.cell_size();
        let x = (raw_x - self.grid_x) / cell_size;
        let y = (raw_y - self.grid_y) / cell_size;

        let size = self.size as f32;
        if x < 0.0 || y < 0.0 || x > size || y > size {
            // Out of bounds, nothing to do
            None
        } else {
            Some(Position{column: x.floor() as usize, row: y.floor() as usize})
        }
    }

    fn click_while_solving(&self, game: &mut Game, position: Position) {
        let clicked_component = game.graph.find_component(&position);
        let colour = clicked_component.colour;

        game.fill_component_of_top_left_cell_with(colour);

        if game.graph.components.len() == 1 {
            game.state = GameState::Solved;

            if game.number_of_clicks <= game.allowed_clicks {
                println!(
                    "You win! You used {} out of {} available moves.",
                    game.number_of_clicks,
                    game.allowed_clicks,
                );
            } else {
                println!(
                    "You lose. You took {} moves but should have \
                            finished in {}.",
                    game.number_of_clicks,
                    game.allowed_clicks,
                );
            }
        }
    }

    fn handle_click(&self, game: &mut Game, mouse_position: (f32, f32)) {
        match game.state {
            GameState::Solving =>
                if let Some(position) = self.cell_position(mouse_position) {
                    self.click_while_solving(game, position);
                }

            GameState::Solved =>
                *game = Game::create(8, 4),
        }
    }
}

#[macroquad::main("Flood-It")]
async fn main() {
    let size = 8;
    let number_of_colours = 4;

    let mut game = Game::create(size, number_of_colours);
    let mut ui = Ui::create(size);

    loop {
        if let Some(KeyCode::Q) = get_last_key_pressed() {
            break;
        }

        if is_mouse_button_pressed(MouseButton::Left) {
            ui.handle_click(&mut game, mouse_position());
        }

        ui.resize();
        ui.render(&game);

        next_frame().await
    }
}
<|endoftext|>


<commit_before>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate spaceapi;
extern crate spaceapi_server;

use std::sync::{Mutex,Arc};

use std::net::Ipv4Addr;
use spaceapi::{Status, Location, Contact, Optional};
use spaceapi_server::SpaceapiServer;
use spaceapi_server::datastore::DataStore;
use spaceapi_server::redis_store::RedisStore;

fn main() {
    let host = Ipv4Addr::new(127, 0, 0, 1);

    // TODO: Create variables for all params
    let status = Status::new(
        "coredump".to_string(),
        "https://www.coredump.ch/logo.png".to_string(),
        "https://www.coredump.ch/".to_string(),
        Location {
            address: Optional::Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        Contact {
            irc: Optional::Value("irc://freenode.net/#coredump".to_string()),
            twitter: Optional::Value("@coredump_ch".to_string()),
            foursquare: Optional::Value("525c20e5498e875d8231b1e5".to_string()),
            email: Optional::Value("danilo@coredump.ch".to_string()),
        },
        vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
    );

    let datastore = Arc::new(Mutex::new( Box::new( RedisStore::new().unwrap()) as Box<DataStore> ));
    let server = SpaceapiServer::new(host, status, datastore);
    server.serve();
}
<commit_msg>dont warn about main not being used in tests<commit_after>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate spaceapi;
extern crate spaceapi_server;

use std::sync::{Mutex,Arc};

use std::net::Ipv4Addr;
use spaceapi::{Status, Location, Contact, Optional};
use spaceapi_server::SpaceapiServer;
use spaceapi_server::datastore::DataStore;
use spaceapi_server::redis_store::RedisStore;

#[cfg_attr(test, allow(dead_code))]
fn main() {
    let host = Ipv4Addr::new(127, 0, 0, 1);

    // TODO: Create variables for all params
    let status = Status::new(
        "coredump".to_string(),
        "https://www.coredump.ch/logo.png".to_string(),
        "https://www.coredump.ch/".to_string(),
        Location {
            address: Optional::Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        Contact {
            irc: Optional::Value("irc://freenode.net/#coredump".to_string()),
            twitter: Optional::Value("@coredump_ch".to_string()),
            foursquare: Optional::Value("525c20e5498e875d8231b1e5".to_string()),
            email: Optional::Value("danilo@coredump.ch".to_string()),
        },
        vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
    );

    let datastore = Arc::new(Mutex::new( Box::new( RedisStore::new().unwrap()) as Box<DataStore> ));
    let server = SpaceapiServer::new(host, status, datastore);
    server.serve();
}
<|endoftext|>


<commit_before>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() {
    let config = Config::default().expect("cargo config");
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config).expect("cargo workspace");
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws).expect("resolve workspace");

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id).expect("get package ids");
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package);
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses").expect("write");
        for (name, version, licenses, _) in packages.clone() {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses).expect("write");
        }
        tw.flush().expect("tw.flush"); // TabWriter flush() makes the actual write to stdout.
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        for file in license_files {
            let mut fs = std::fs::File::open(file).expect("File::open");
            fs.read_to_end(&mut buf).expect("read_to_end");
            out.write_all(&buf).expect("write_all");
            buf.clear();
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(|s| s.trim())
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

fn package_license_files(package: &Package) -> Vec<path::PathBuf> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir().expect("read_dir call failed") {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    if name.starts_with("LICENSE") {
                        result.push(entry.path())
                    }
                }
            }
        }
    }

    result
}
<commit_msg>Add horizontal line<commit_after>use cargo::core::{Package, Workspace};
use cargo::ops;
use cargo::util::Config;

use std::collections::BTreeSet;
use std::fmt;
use std::io;
use std::io::prelude::*;
use std::path;

#[derive(Debug)]
enum Licenses<'a> {
    Licenses(BTreeSet<&'a str>),
    File(&'a str),
    Missing,
}

impl<'a> fmt::Display for Licenses<'a> {
    fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        match *self {
            Licenses::File(_) => write!(f, "Specified in license file"),
            Licenses::Missing => write!(f, "Missing"),
            Licenses::Licenses(ref lic_names) => {
                let lics: Vec<String> = lic_names.iter().map(|s| String::from(*s)).collect();
                write!(f, "{}", lics.join(", "))
            }
        }
    }
}

fn main() {
    let config = Config::default().expect("cargo config");
    let manifest = config.cwd().join("Cargo.toml");
    let ws = Workspace::new(&manifest, &config).expect("cargo workspace");
    let members: Vec<&Package> = ws.members().collect();
    let (package_ids, resolve) = ops::resolve_ws(&ws).expect("resolve workspace");

    let mut packages = Vec::new();
    for package_id in resolve.iter() {
        let package = package_ids.get_one(package_id).expect("get package ids");
        if members.contains(&package) {
            // Skip listing our own packages in our workspace
            continue;
        }
        let name = package.name().to_owned();
        let version = format!("{}", package.version());
        let licenses = format!("{}", package_licenses(package));
        let license_files = package_license_files(package);
        packages.push((name, version, licenses, license_files));
    }

    packages.sort();

    let stdout = io::stdout();
    let mut out = stdout.lock();

    {
        let mut tw = tabwriter::TabWriter::new(&mut out);
        writeln!(tw, "Name\t| Version\t| Licenses").expect("write");
        writeln!(tw, "----\t| -------\t| --------").expect("write");
        for (name, version, licenses, _) in packages.clone() {
            writeln!(tw, "{}\t| {}\t| {}", &name, &version, &licenses).expect("write");
        }
        tw.flush().expect("tw.flush"); // TabWriter flush() makes the actual write to stdout.
    }

    println!();

    for (name, version, _, license_files) in packages {
        if license_files.is_empty() {
            continue;
        }

        println!("-----BEGIN {} {} LICENSES-----", name, version);

        let mut buf = Vec::new();
        for file in license_files {
            let mut fs = std::fs::File::open(file).expect("File::open");
            fs.read_to_end(&mut buf).expect("read_to_end");
            out.write_all(&buf).expect("write_all");
            buf.clear();
        }

        println!("-----END {} {} LICENSES-----", name, version);
        println!();
    }
}

fn package_licenses(package: &Package) -> Licenses<'_> {
    let metadata = package.manifest().metadata();

    if let Some(ref license_str) = metadata.license {
        let licenses: BTreeSet<&str> = license_str
            .split('/')
            .map(|s| s.trim())
            .collect();
        return Licenses::Licenses(licenses);
    }

    if let Some(ref license_file) = metadata.license_file {
        return Licenses::File(license_file);
    }

    Licenses::Missing
}

fn package_license_files(package: &Package) -> Vec<path::PathBuf> {
    let mut result = Vec::new();

    if let Some(path) = package.manifest_path().parent() {
        for entry in path.read_dir().expect("read_dir call failed") {
            if let Ok(entry) = entry {
                if let Ok(name) = entry.file_name().into_string() {
                    if name.starts_with("LICENSE") {
                        result.push(entry.path())
                    }
                }
            }
        }
    }

    result
}
<|endoftext|>