<commit_before>extern crate aqueren;
extern crate hyper;
extern crate rustc_serialize;

use aqueren::types::{Board, COLS, Game, Player, PlayerShares, Slot, Tile};
use hyper::client::Client;
use hyper::client::response::Response;
use rustc_serialize::json;
use rustc_serialize::json::DecoderError;
use std::io::Read;
use std::io::Error;
use std::io::ErrorKind;

fn get_state() -> Result<Game, String> {
    let client = Client::new();
    let url = "http://localhost:3001/state";
    let result: Result<Response, hyper::error::Error> = client.get(url).send();
    result
        .map_err(|_| "Could not parse response".to_string())
        .and_then(parse_body)
        .and_then(parse_state)
}

fn parse_body(mut response: Response) -> Result<String, String> {
    let mut buf = String::new();
    match response.read_to_string(&mut buf) {
        Ok(_) => Ok(buf),
        Err(_) => Err("Could not parse body".to_string())
    }
}

fn parse_state(mut state_json: String) -> Result<Game, String> {
    json::decode(&state_json).map_err(|_| "Could not parse state".to_string())
}

fn print_game(game: &Game) -> String {
    let mut string = String::new();
    string.push_str("Game status\n");
    string.push_str("---------------------\n");
    string.push_str(&format!("Turn: Player {:?} ({:?})\n", game.turn, game.turn_state));
    string.push_str("\n");
    string.push_str(&print_players(&game.players));
    string.push_str("\n");
    string.push_str(&print_board(&game.board));
    string
}

fn row_to_char<'a>(row: u8) -> &'a str {
    let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
    mapping[row as usize]
}

fn print_board(board: &Board) -> String {
    let mut string = String::new();
    string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
    for row in board.slots.chunks(COLS as usize) {
        let row_char = row_to_char(row[0].row);
        string.push_str(&format!("{}  ", row_char));
        for slot in row {
            string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
        }
        string.push_str(&format!("{}\n", row_char));
    }
    string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
    string
}

fn print_players(players: &Vec<Player>) -> String {
    let players_str: Vec<String> = players.iter().map(print_player).collect();
    players_str.as_slice().join("\n")
}

fn print_player(player: &Player) -> String {
    let mut string = String::new();
    string.push_str(&format!("Player {:?}: \n", player.id));
    string.push_str(&format!("  Money: {:?}\n", player.money));
    string.push_str(&format!("  Shares: {}\n", print_shares(&player.shares)));
    string.push_str(&format!("  Tiles: {}\n", print_tiles(&player.tiles)));
    string
}

fn print_shares(shares: &PlayerShares) -> String {
    format!("LUX: {}, TOW: {}, AMER: {}, FEST: {}, WW: {}, CONT: {}, IMP: {}", shares.luxor, shares.tower, shares.american, shares.festival, shares.worldwide, shares.continental, shares.imperial)
}

fn print_tiles(tiles: &Vec<Tile>) -> String {
    let mut tiles_str: Vec<String> = tiles.iter().map(print_tile).collect();
    let mut slice = tiles_str.as_mut_slice();
    slice.sort();
    slice.join(", ")

}

fn print_tile(slot: &Tile) -> String {
    format!("{}{}", row_to_char(slot.row), slot.col + 1)
}

fn main() {
    println!("Starting client");
    match get_state() {
        Ok(game) => println!("{}", print_game(&game)),
        Err(_) => println!("Couldn't get start state")
    }
}

<commit_msg>Debug client: pass in server URL as parameter<commit_after>extern crate aqueren;
extern crate hyper;
extern crate rustc_serialize;

use aqueren::types::{Board, COLS, Game, Player, PlayerShares, Slot, Tile};
use hyper::client::Client;
use hyper::client::response::Response;
use rustc_serialize::json;
use rustc_serialize::json::DecoderError;
use std::env;
use std::io::Read;
use std::io::Error;
use std::io::ErrorKind;

fn get_state(server_url: &str) -> Result<Game, String> {
    let url = format!("{}/state", server_url);
    let client = Client::new();
    let result: Result<Response, hyper::error::Error> = client.get(&url).send();
    result
        .map_err(|_| "Could not get state, do you have the correct server URL?".to_string())
        .and_then(parse_body)
        .and_then(parse_state)
}

fn parse_body(mut response: Response) -> Result<String, String> {
    let mut buf = String::new();
    match response.read_to_string(&mut buf) {
        Ok(_) => Ok(buf),
        Err(_) => Err("Could not parse body".to_string())
    }
}

fn parse_state(mut state_json: String) -> Result<Game, String> {
    json::decode(&state_json).map_err(|_| "Could not parse state".to_string())
}

fn print_game(game: &Game) -> String {
    let mut string = String::new();
    string.push_str("Game status\n");
    string.push_str("---------------------\n");
    string.push_str(&format!("Turn: Player {:?} ({:?})\n", game.turn, game.turn_state));
    string.push_str("\n");
    string.push_str(&print_players(&game.players));
    string.push_str("\n");
    string.push_str(&print_board(&game.board));
    string
}

fn row_to_char<'a>(row: u8) -> &'a str {
    let mapping = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
    mapping[row as usize]
}

fn print_board(board: &Board) -> String {
    let mut string = String::new();
    string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12\n");
    for row in board.slots.chunks(COLS as usize) {
        let row_char = row_to_char(row[0].row);
        string.push_str(&format!("{}  ", row_char));
        for slot in row {
            string.push_str(&format!("{:<2} ", if slot.has_tile { '\u{25FC}' } else { '\u{25FB}' }));
        }
        string.push_str(&format!("{}\n", row_char));
    }
    string.push_str("   1  2  3  4  5  6  7  8  9  10 11 12");
    string
}

fn print_players(players: &Vec<Player>) -> String {
    let players_str: Vec<String> = players.iter().map(print_player).collect();
    players_str.as_slice().join("\n")
}

fn print_player(player: &Player) -> String {
    let mut string = String::new();
    string.push_str(&format!("Player {:?}: \n", player.id));
    string.push_str(&format!("  Money: {:?}\n", player.money));
    string.push_str(&format!("  Shares: {}\n", print_shares(&player.shares)));
    string.push_str(&format!("  Tiles: {}\n", print_tiles(&player.tiles)));
    string
}

fn print_shares(shares: &PlayerShares) -> String {
    format!("LUX: {}, TOW: {}, AMER: {}, FEST: {}, WW: {}, CONT: {}, IMP: {}", shares.luxor, shares.tower, shares.american, shares.festival, shares.worldwide, shares.continental, shares.imperial)
}

fn print_tiles(tiles: &Vec<Tile>) -> String {
    let mut tiles_str: Vec<String> = tiles.iter().map(print_tile).collect();
    let mut slice = tiles_str.as_mut_slice();
    slice.sort();
    slice.join(", ")

}

fn print_tile(slot: &Tile) -> String {
    format!("{}{}", row_to_char(slot.row), slot.col + 1)
}

fn main() {
    let server_url = env::args().nth(1).unwrap_or("http://localhost:3001".to_string());
    println!("Starting client, connecting to {}", server_url);
    match get_state(&server_url) {
        Ok(game) => println!("\n{}", print_game(&game)),
        Err(e) => println!("{}", e)
    }
}

<|endoftext|>


<commit_before>use std::fs::{self, File};
use std::io::SeekFrom;
use std::io::prelude::*;
use std::path::{self, Path};
use std::sync::Arc;

use flate2::read::GzDecoder;
use flate2::{GzBuilder, Compression};
use git2;
use tar::{Archive, Builder, Header, EntryType};

use core::{Package, Workspace, Source, SourceId};
use sources::PathSource;
use util::{self, internal, Config, FileLock};
use util::errors::{CargoResult, CargoResultExt};
use ops::{self, DefaultExecutor};

pub struct PackageOpts<'cfg> {
    pub config: &'cfg Config,
    pub list: bool,
    pub check_metadata: bool,
    pub allow_dirty: bool,
    pub verify: bool,
    pub jobs: Option<u32>,
    pub target: Option<&'cfg str>,
    pub registry: Option<String>,
}

pub fn package(ws: &Workspace,
               opts: &PackageOpts) -> CargoResult<Option<FileLock>> {
    let pkg = ws.current()?;
    let config = ws.config();

    // Allow packaging if a registry has been provided, or if there are no nightly
    // features enabled.
    if opts.registry.is_none() && !pkg.manifest().features().activated().is_empty() {
        bail!("cannot package or publish crates which activate nightly-only \
               cargo features")
    }
    let mut src = PathSource::new(pkg.root(),
                                  pkg.package_id().source_id(),
                                  config);
    src.update()?;

    if opts.check_metadata {
        check_metadata(pkg, config)?;
    }

    verify_dependencies(pkg)?;

    if opts.list {
        let root = pkg.root();
        let mut list: Vec<_> = src.list_files(pkg)?.iter().map(|file| {
            util::without_prefix(file, root).unwrap().to_path_buf()
        }).collect();
        list.sort();
        for file in list.iter() {
            println!("{}", file.display());
        }
        return Ok(None)
    }

    if !opts.allow_dirty {
        check_not_dirty(pkg, &src)?;
    }

    let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
    let dir = ws.target_dir().join("package");
    let mut dst = {
        let tmp = format!(".{}", filename);
        dir.open_rw(&tmp, config, "package scratch space")?
    };

    // Package up and test a temporary tarball and only move it to the final
    // location if it actually passes all our tests. Any previously existing
    // tarball can be assumed as corrupt or invalid, so we just blow it away if
    // it exists.
    config.shell().status("Packaging", pkg.package_id().to_string())?;
    dst.file().set_len(0)?;
    tar(ws, &src, dst.file(), &filename).chain_err(|| {
        format_err!("failed to prepare local package for uploading")
    })?;
    if opts.verify {
        dst.seek(SeekFrom::Start(0))?;
        run_verify(ws, dst.file(), opts).chain_err(|| {
            "failed to verify package tarball"
        })?
    }
    dst.seek(SeekFrom::Start(0))?;
    {
        let src_path = dst.path();
        let dst_path = dst.parent().join(&filename);
        fs::rename(&src_path, &dst_path).chain_err(|| {
            "failed to move temporary tarball into final location"
        })?;
    }
    Ok(Some(dst))
}

// check that the package has some piece of metadata that a human can
// use to tell what the package is about.
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
    let md = pkg.manifest().metadata();

    let mut missing = vec![];

    macro_rules! lacking {
        ($( $($field: ident)||* ),*) => {{
            $(
                if $(md.$field.as_ref().map_or(true, |s| s.is_empty()))&&* {
                    $(missing.push(stringify!($field).replace("_", "-"));)*
                }
            )*
        }}
    }
    lacking!(description, license || license_file, documentation || homepage || repository);

    if !missing.is_empty() {
        let mut things = missing[..missing.len() - 1].join(", ");
        // things will be empty if and only if length == 1 (i.e. the only case
        // to have no `or`).
        if !things.is_empty() {
            things.push_str(" or ");
        }
        things.push_str(missing.last().unwrap());

        config.shell().warn(
            &format!("manifest has no {things}.\n\
                    See http://doc.crates.io/manifest.html#package-metadata for more info.",
                    things = things))?
    }
    Ok(())
}

// check that the package dependencies are safe to deploy.
fn verify_dependencies(pkg: &Package) -> CargoResult<()> {
    for dep in pkg.dependencies() {
        if dep.source_id().is_path() && !dep.specified_req() {
            bail!("all path dependencies must have a version specified \
                    when packaging.\ndependency `{}` does not specify \
                    a version.", dep.name())
        }
    }
    Ok(())
}

fn check_not_dirty(p: &Package, src: &PathSource) -> CargoResult<()> {
    if let Ok(repo) = git2::Repository::discover(p.root()) {
        if let Some(workdir) = repo.workdir() {
            debug!("found a git repo at {:?}, checking if index present",
                   workdir);
            let path = p.manifest_path();
            let path = path.strip_prefix(workdir).unwrap_or(path);
            if let Ok(status) = repo.status_file(path) {
                if (status & git2::STATUS_IGNORED).is_empty() {
                    debug!("Cargo.toml found in repo, checking if dirty");
                    return git(p, src, &repo)
                }
            }
        }
    }

    // No VCS recognized, we don't know if the directory is dirty or not, so we
    // have to assume that it's clean.
    return Ok(());

    fn git(p: &Package,
           src: &PathSource,
           repo: &git2::Repository) -> CargoResult<()> {
        let workdir = repo.workdir().unwrap();
        let dirty = src.list_files(p)?.iter().filter(|file| {
            let relative = file.strip_prefix(workdir).unwrap();
            if let Ok(status) = repo.status_file(relative) {
                status != git2::STATUS_CURRENT
            } else {
                false
            }
        }).map(|path| {
            path.strip_prefix(p.root()).unwrap_or(path).display().to_string()
        }).collect::<Vec<_>>();
        if dirty.is_empty() {
            Ok(())
        } else {
            bail!("{} files in the working directory contain changes that were \
                   not yet committed into git:\n\n{}\n\n\
                   to proceed despite this, pass the `--allow-dirty` flag",
                  dirty.len(), dirty.join("\n"))
        }
    }
}

fn tar(ws: &Workspace,
       src: &PathSource,
       dst: &File,
       filename: &str) -> CargoResult<()> {
    // Prepare the encoder and its header
    let filename = Path::new(filename);
    let encoder = GzBuilder::new().filename(util::path2bytes(filename)?)
                                  .write(dst, Compression::Best);

    // Put all package files into a compressed archive
    let mut ar = Builder::new(encoder);
    let pkg = ws.current()?;
    let config = ws.config();
    let root = pkg.root();
    for file in src.list_files(pkg)?.iter() {
        let relative = util::without_prefix(file, root).unwrap();
        check_filename(relative)?;
        let relative = relative.to_str().ok_or_else(|| {
            format_err!("non-utf8 path in source directory: {}",
                        relative.display())
        })?;
        config.shell().verbose(|shell| {
            shell.status("Archiving", &relative)
        })?;
        let path = format!("{}-{}{}{}", pkg.name(), pkg.version(),
                           path::MAIN_SEPARATOR, relative);

        // The tar::Builder type by default will build GNU archives, but
        // unfortunately we force it here to use UStar archives instead. The
        // UStar format has more limitations on the length of path name that it
        // can encode, so it's not quite as nice to use.
        //
        // Older cargos, however, had a bug where GNU archives were interpreted
        // as UStar archives. This bug means that if we publish a GNU archive
        // which has fully filled out metadata it'll be corrupt when unpacked by
        // older cargos.
        //
        // Hopefully in the future after enough cargos have been running around
        // with the bugfixed tar-rs library we'll be able to switch this over to
        // GNU archives, but for now we'll just say that you can't encode paths
        // in archives that are *too* long.
        //
        // For an instance of this in the wild, use the tar-rs 0.3.3 library to
        // unpack the selectors 0.4.0 crate on crates.io. Either that or take a
        // look at rust-lang/cargo#2326
        let mut header = Header::new_ustar();
        header.set_path(&path).chain_err(|| {
            format!("failed to add to archive: `{}`", relative)
        })?;
        let mut file = File::open(file).chain_err(|| {
            format!("failed to open for archiving: `{}`", file.display())
        })?;
        let metadata = file.metadata().chain_err(|| {
            format!("could not learn metadata for: `{}`", relative)
        })?;
        header.set_metadata(&metadata);

        if relative == "Cargo.toml" {
            let orig = Path::new(&path).with_file_name("Cargo.toml.orig");
            header.set_path(&orig)?;
            header.set_cksum();
            ar.append(&header, &mut file).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;

            let mut header = Header::new_ustar();
            let toml = pkg.to_registry_toml()?;
            header.set_path(&path)?;
            header.set_entry_type(EntryType::file());
            header.set_mode(0o644);
            header.set_size(toml.len() as u64);
            header.set_cksum();
            ar.append(&header, toml.as_bytes()).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;
        } else {
            header.set_cksum();
            ar.append(&header, &mut file).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;
        }
    }
    let encoder = ar.into_inner()?;
    encoder.finish()?;
    Ok(())
}

fn run_verify(ws: &Workspace, tar: &File, opts: &PackageOpts) -> CargoResult<()> {
    let config = ws.config();
    let pkg = ws.current()?;

    config.shell().status("Verifying", pkg)?;

    let f = GzDecoder::new(tar)?;
    let dst = pkg.root().join(&format!("target/package/{}-{}",
                                       pkg.name(), pkg.version()));
    if fs::metadata(&dst).is_ok() {
        fs::remove_dir_all(&dst)?;
    }
    let mut archive = Archive::new(f);
    archive.unpack(dst.parent().unwrap())?;

    // Manufacture an ephemeral workspace to ensure that even if the top-level
    // package has a workspace we can still build our new crate.
    let id = SourceId::for_path(&dst)?;
    let mut src = PathSource::new(&dst, &id, ws.config());
    let new_pkg = src.root_package()?;
    let ws = Workspace::ephemeral(new_pkg, config, None, true)?;

    ops::compile_ws(&ws, None, &ops::CompileOptions {
        config: config,
        jobs: opts.jobs,
        target: opts.target,
        features: &[],
        no_default_features: false,
        all_features: false,
        spec: ops::Packages::Packages(&[]),
        filter: ops::CompileFilter::Default { required_features_filterable: true },
        release: false,
        message_format: ops::MessageFormat::Human,
        mode: ops::CompileMode::Build,
        target_rustdoc_args: None,
        target_rustc_args: None,
    }, Arc::new(DefaultExecutor))?;

    Ok(())
}

// It can often be the case that files of a particular name on one platform
// can't actually be created on another platform. For example files with colons
// in the name are allowed on Unix but not on Windows.
//
// To help out in situations like this, issue about weird filenames when
// packaging as a "heads up" that something may not work on other platforms.
fn check_filename(file: &Path) -> CargoResult<()> {
    let name = match file.file_name() {
        Some(name) => name,
        None => return Ok(()),
    };
    let name = match name.to_str() {
        Some(name) => name,
        None => {
            bail!("path does not have a unicode filename which may not unpack \
                   on all platforms: {}", file.display())
        }
    };
    let bad_chars = ['/', '\\', '<', '>', ':', '"', '|', '?', '*'];
    if let Some(c) = bad_chars.iter().find(|c| name.contains(**c)) {
        bail!("cannot package a filename with a special character `{}`: {}",
              c, file.display())
    }
    Ok(())
}
<commit_msg>Untar into the right dir when verifying<commit_after>use std::fs::{self, File};
use std::io::SeekFrom;
use std::io::prelude::*;
use std::path::{self, Path};
use std::sync::Arc;

use flate2::read::GzDecoder;
use flate2::{GzBuilder, Compression};
use git2;
use tar::{Archive, Builder, Header, EntryType};

use core::{Package, Workspace, Source, SourceId};
use sources::PathSource;
use util::{self, internal, Config, FileLock};
use util::errors::{CargoResult, CargoResultExt};
use ops::{self, DefaultExecutor};

pub struct PackageOpts<'cfg> {
    pub config: &'cfg Config,
    pub list: bool,
    pub check_metadata: bool,
    pub allow_dirty: bool,
    pub verify: bool,
    pub jobs: Option<u32>,
    pub target: Option<&'cfg str>,
    pub registry: Option<String>,
}

pub fn package(ws: &Workspace,
               opts: &PackageOpts) -> CargoResult<Option<FileLock>> {
    let pkg = ws.current()?;
    let config = ws.config();

    // Allow packaging if a registry has been provided, or if there are no nightly
    // features enabled.
    if opts.registry.is_none() && !pkg.manifest().features().activated().is_empty() {
        bail!("cannot package or publish crates which activate nightly-only \
               cargo features")
    }
    let mut src = PathSource::new(pkg.root(),
                                  pkg.package_id().source_id(),
                                  config);
    src.update()?;

    if opts.check_metadata {
        check_metadata(pkg, config)?;
    }

    verify_dependencies(pkg)?;

    if opts.list {
        let root = pkg.root();
        let mut list: Vec<_> = src.list_files(pkg)?.iter().map(|file| {
            util::without_prefix(file, root).unwrap().to_path_buf()
        }).collect();
        list.sort();
        for file in list.iter() {
            println!("{}", file.display());
        }
        return Ok(None)
    }

    if !opts.allow_dirty {
        check_not_dirty(pkg, &src)?;
    }

    let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
    let dir = ws.target_dir().join("package");
    let mut dst = {
        let tmp = format!(".{}", filename);
        dir.open_rw(&tmp, config, "package scratch space")?
    };

    // Package up and test a temporary tarball and only move it to the final
    // location if it actually passes all our tests. Any previously existing
    // tarball can be assumed as corrupt or invalid, so we just blow it away if
    // it exists.
    config.shell().status("Packaging", pkg.package_id().to_string())?;
    dst.file().set_len(0)?;
    tar(ws, &src, dst.file(), &filename).chain_err(|| {
        format_err!("failed to prepare local package for uploading")
    })?;
    if opts.verify {
        dst.seek(SeekFrom::Start(0))?;
        run_verify(ws, &dst, opts).chain_err(|| {
            "failed to verify package tarball"
        })?
    }
    dst.seek(SeekFrom::Start(0))?;
    {
        let src_path = dst.path();
        let dst_path = dst.parent().join(&filename);
        fs::rename(&src_path, &dst_path).chain_err(|| {
            "failed to move temporary tarball into final location"
        })?;
    }
    Ok(Some(dst))
}

// check that the package has some piece of metadata that a human can
// use to tell what the package is about.
fn check_metadata(pkg: &Package, config: &Config) -> CargoResult<()> {
    let md = pkg.manifest().metadata();

    let mut missing = vec![];

    macro_rules! lacking {
        ($( $($field: ident)||* ),*) => {{
            $(
                if $(md.$field.as_ref().map_or(true, |s| s.is_empty()))&&* {
                    $(missing.push(stringify!($field).replace("_", "-"));)*
                }
            )*
        }}
    }
    lacking!(description, license || license_file, documentation || homepage || repository);

    if !missing.is_empty() {
        let mut things = missing[..missing.len() - 1].join(", ");
        // things will be empty if and only if length == 1 (i.e. the only case
        // to have no `or`).
        if !things.is_empty() {
            things.push_str(" or ");
        }
        things.push_str(missing.last().unwrap());

        config.shell().warn(
            &format!("manifest has no {things}.\n\
                    See http://doc.crates.io/manifest.html#package-metadata for more info.",
                    things = things))?
    }
    Ok(())
}

// check that the package dependencies are safe to deploy.
fn verify_dependencies(pkg: &Package) -> CargoResult<()> {
    for dep in pkg.dependencies() {
        if dep.source_id().is_path() && !dep.specified_req() {
            bail!("all path dependencies must have a version specified \
                    when packaging.\ndependency `{}` does not specify \
                    a version.", dep.name())
        }
    }
    Ok(())
}

fn check_not_dirty(p: &Package, src: &PathSource) -> CargoResult<()> {
    if let Ok(repo) = git2::Repository::discover(p.root()) {
        if let Some(workdir) = repo.workdir() {
            debug!("found a git repo at {:?}, checking if index present",
                   workdir);
            let path = p.manifest_path();
            let path = path.strip_prefix(workdir).unwrap_or(path);
            if let Ok(status) = repo.status_file(path) {
                if (status & git2::STATUS_IGNORED).is_empty() {
                    debug!("Cargo.toml found in repo, checking if dirty");
                    return git(p, src, &repo)
                }
            }
        }
    }

    // No VCS recognized, we don't know if the directory is dirty or not, so we
    // have to assume that it's clean.
    return Ok(());

    fn git(p: &Package,
           src: &PathSource,
           repo: &git2::Repository) -> CargoResult<()> {
        let workdir = repo.workdir().unwrap();
        let dirty = src.list_files(p)?.iter().filter(|file| {
            let relative = file.strip_prefix(workdir).unwrap();
            if let Ok(status) = repo.status_file(relative) {
                status != git2::STATUS_CURRENT
            } else {
                false
            }
        }).map(|path| {
            path.strip_prefix(p.root()).unwrap_or(path).display().to_string()
        }).collect::<Vec<_>>();
        if dirty.is_empty() {
            Ok(())
        } else {
            bail!("{} files in the working directory contain changes that were \
                   not yet committed into git:\n\n{}\n\n\
                   to proceed despite this, pass the `--allow-dirty` flag",
                  dirty.len(), dirty.join("\n"))
        }
    }
}

fn tar(ws: &Workspace,
       src: &PathSource,
       dst: &File,
       filename: &str) -> CargoResult<()> {
    // Prepare the encoder and its header
    let filename = Path::new(filename);
    let encoder = GzBuilder::new().filename(util::path2bytes(filename)?)
                                  .write(dst, Compression::Best);

    // Put all package files into a compressed archive
    let mut ar = Builder::new(encoder);
    let pkg = ws.current()?;
    let config = ws.config();
    let root = pkg.root();
    for file in src.list_files(pkg)?.iter() {
        let relative = util::without_prefix(file, root).unwrap();
        check_filename(relative)?;
        let relative = relative.to_str().ok_or_else(|| {
            format_err!("non-utf8 path in source directory: {}",
                        relative.display())
        })?;
        config.shell().verbose(|shell| {
            shell.status("Archiving", &relative)
        })?;
        let path = format!("{}-{}{}{}", pkg.name(), pkg.version(),
                           path::MAIN_SEPARATOR, relative);

        // The tar::Builder type by default will build GNU archives, but
        // unfortunately we force it here to use UStar archives instead. The
        // UStar format has more limitations on the length of path name that it
        // can encode, so it's not quite as nice to use.
        //
        // Older cargos, however, had a bug where GNU archives were interpreted
        // as UStar archives. This bug means that if we publish a GNU archive
        // which has fully filled out metadata it'll be corrupt when unpacked by
        // older cargos.
        //
        // Hopefully in the future after enough cargos have been running around
        // with the bugfixed tar-rs library we'll be able to switch this over to
        // GNU archives, but for now we'll just say that you can't encode paths
        // in archives that are *too* long.
        //
        // For an instance of this in the wild, use the tar-rs 0.3.3 library to
        // unpack the selectors 0.4.0 crate on crates.io. Either that or take a
        // look at rust-lang/cargo#2326
        let mut header = Header::new_ustar();
        header.set_path(&path).chain_err(|| {
            format!("failed to add to archive: `{}`", relative)
        })?;
        let mut file = File::open(file).chain_err(|| {
            format!("failed to open for archiving: `{}`", file.display())
        })?;
        let metadata = file.metadata().chain_err(|| {
            format!("could not learn metadata for: `{}`", relative)
        })?;
        header.set_metadata(&metadata);

        if relative == "Cargo.toml" {
            let orig = Path::new(&path).with_file_name("Cargo.toml.orig");
            header.set_path(&orig)?;
            header.set_cksum();
            ar.append(&header, &mut file).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;

            let mut header = Header::new_ustar();
            let toml = pkg.to_registry_toml()?;
            header.set_path(&path)?;
            header.set_entry_type(EntryType::file());
            header.set_mode(0o644);
            header.set_size(toml.len() as u64);
            header.set_cksum();
            ar.append(&header, toml.as_bytes()).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;
        } else {
            header.set_cksum();
            ar.append(&header, &mut file).chain_err(|| {
                internal(format!("could not archive source file `{}`", relative))
            })?;
        }
    }
    let encoder = ar.into_inner()?;
    encoder.finish()?;
    Ok(())
}

fn run_verify(ws: &Workspace, tar: &FileLock, opts: &PackageOpts) -> CargoResult<()> {
    let config = ws.config();
    let pkg = ws.current()?;

    config.shell().status("Verifying", pkg)?;

    let f = GzDecoder::new(tar.file())?;
    let dst = tar.parent().join(&format!("{}-{}", pkg.name(), pkg.version()));
    if fs::metadata(&dst).is_ok() {
        fs::remove_dir_all(&dst)?;
    }
    let mut archive = Archive::new(f);
    archive.unpack(dst.parent().unwrap())?;

    // Manufacture an ephemeral workspace to ensure that even if the top-level
    // package has a workspace we can still build our new crate.
    let id = SourceId::for_path(&dst)?;
    let mut src = PathSource::new(&dst, &id, ws.config());
    let new_pkg = src.root_package()?;
    let ws = Workspace::ephemeral(new_pkg, config, None, true)?;

    ops::compile_ws(&ws, None, &ops::CompileOptions {
        config: config,
        jobs: opts.jobs,
        target: opts.target,
        features: &[],
        no_default_features: false,
        all_features: false,
        spec: ops::Packages::Packages(&[]),
        filter: ops::CompileFilter::Default { required_features_filterable: true },
        release: false,
        message_format: ops::MessageFormat::Human,
        mode: ops::CompileMode::Build,
        target_rustdoc_args: None,
        target_rustc_args: None,
    }, Arc::new(DefaultExecutor))?;

    Ok(())
}

// It can often be the case that files of a particular name on one platform
// can't actually be created on another platform. For example files with colons
// in the name are allowed on Unix but not on Windows.
//
// To help out in situations like this, issue about weird filenames when
// packaging as a "heads up" that something may not work on other platforms.
fn check_filename(file: &Path) -> CargoResult<()> {
    let name = match file.file_name() {
        Some(name) => name,
        None => return Ok(()),
    };
    let name = match name.to_str() {
        Some(name) => name,
        None => {
            bail!("path does not have a unicode filename which may not unpack \
                   on all platforms: {}", file.display())
        }
    };
    let bad_chars = ['/', '\\', '<', '>', ':', '"', '|', '?', '*'];
    if let Some(c) = bad_chars.iter().find(|c| name.contains(**c)) {
        bail!("cannot package a filename with a special character `{}`: {}",
              c, file.display())
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::Read;
use std::path::PathBuf;

#[cfg(unix)]
use std::os::unix::fs::MetadataExt;

use reqwest::{Client, Proxy};
use flate2::read::GzDecoder;
use log::debug;
use app_dirs::{get_app_root, AppDataType};
use std::time::{Duration, SystemTime};
use tar::Archive;
use walkdir::{DirEntry, WalkDir};

use crate::error::TealdeerError::{self, CacheError, UpdateError};
use crate::types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {
    pub fn new<S>(url: S, os: OsType) -> Self
    where
        S: Into<String>,
    {
        Self {
            url: url.into(),
            os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TealdeerError> {
        // Allow overriding the cache directory by setting the
        // $TEALDEER_CACHE_DIR env variable.
        if let Ok(value) = env::var("TEALDEER_CACHE_DIR") {
            let path = PathBuf::from(value);

            if path.exists() && path.is_dir() {
                return Ok(path);
            } else {
                return Err(CacheError(
                    "Path specified by $TEALDEER_CACHE_DIR \
                     does not exist or is not a directory."
                        .into(),
                ));
            }
        };

        // Otherwise, fall back to user cache directory.
        match get_app_root(AppDataType::UserCache, &crate::APP_INFO) {
            Ok(dirs) => Ok(dirs),
            Err(_) => Err(CacheError("Could not determine user cache directory.".into())),
        }
    }

    /// Download the archive
    fn download(&self) -> Result<Vec<u8>, TealdeerError> {
        let mut builder = Client::builder();
        if let Ok(ref host) = env::var("HTTP_PROXY") {
            if let Ok(proxy) = Proxy::http(host) {
                builder = builder.proxy(proxy);
            }
        }
        if let Ok(ref host) = env::var("HTTPS_PROXY") {
            if let Ok(proxy) = Proxy::https(host) {
                builder = builder.proxy(proxy);
            }
        }
        let client = builder.build().unwrap_or_else(|_| Client::new());
        let mut resp = client.get(&self.url).send()?;
        let mut buf: Vec<u8> = vec![];
        let bytes_downloaded = resp.copy_to(&mut buf)?;
        debug!("{} bytes downloaded", bytes_downloaded);
        Ok(buf)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
        Archive::new(GzDecoder::new(reader))
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TealdeerError> {
        // First, download the compressed data
        let bytes: Vec<u8> = self.download()?;

        // Decompress the response body into an `Archive`
        let mut archive = self.decompress(&bytes[..]);

        // Determine paths
        let cache_dir = self.get_cache_dir()?;

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        fs::create_dir_all(&cache_dir)
            .map_err(|e| UpdateError(format!("Could not create cache directory: {}", e)))?;

        // Clear cache directory
        // Note: This is not the best solution. Ideally we would download the
        // archive to a temporary directory and then swap the two directories.
        // But renaming a directory doesn't work across filesystems and Rust
        // does not yet offer a recursive directory copying function. So for
        // now, we'll use this approach.
        self.clear()?;

        // Extract archive
        archive
            .unpack(&cache_dir)
            .map_err(|e| UpdateError(format!("Could not unpack compressed data: {}", e)))?;

        Ok(())
    }

    /// Return the duration since the cache directory was last modified.
    pub fn last_update(&self) -> Option<Duration> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir.join("tldr-master")) {
                if let Ok(mtime) = metadata.modified() {
                    let now = SystemTime::now();
                    return now.duration_since(mtime).ok();
                };
            };
        };
        None
    }

    /// Return the platform directory.
    #[allow(clippy::match_same_arms)]
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Windows => Some("windows"),
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let platforms_dir = match self.get_cache_dir() {
            Ok(cache_dir) => cache_dir.join("tldr-master").join("pages"),
            _ => return None,
        };

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Return the available pages.
    pub fn list_pages(&self) -> Result<Vec<String>, TealdeerError> {
        // Determine platforms directory and platform
        let cache_dir = self.get_cache_dir()?;
        let platforms_dir = cache_dir.join("tldr-master").join("pages");
        let platform_dir = self.get_platform_dir();

        // Closure that allows the WalkDir instance to traverse platform
        // specific and common page directories, but not others.
        let should_walk = |entry: &DirEntry| -> bool {
            let file_type = entry.file_type();
            let file_name = match entry.file_name().to_str() {
                Some(name) => name,
                None => return false,
            };
            if file_type.is_dir() {
                if file_name == "common" {
                    return true;
                }
                if let Some(platform) = platform_dir {
                    return file_name == platform;
                }
            } else if file_type.is_file() {
                return true;
            }
            false
        };

        // Recursively walk through common and (if applicable) platform specific directory
        let mut pages = WalkDir::new(platforms_dir)
            .min_depth(1) // Skip root directory
            .into_iter()
            .filter_entry(|e| should_walk(e)) // Filter out pages for other architectures
            .filter_map(|e| e.ok()) // Convert results to options, filter out errors
            .filter_map(|e| {
                let path = e.path();
                let extension = &path.extension().and_then(|s| s.to_str()).unwrap_or("");
                if e.file_type().is_file() && extension == &"md" {
                    path.file_stem()
                        .and_then(|stem| stem.to_str().map(|s| s.into()))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>();
        pages.sort();
        pages.dedup();
        Ok(pages)
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TealdeerError> {
        let path = self.get_cache_dir()?;
        if path.exists() && path.is_dir() {
            fs::remove_dir_all(&path).map_err(|_| CacheError(format!(
                "Could not remove cache directory ({}).",
                path.display()
            )))?;
        } else if path.exists() {
            return Err(CacheError(format!(
                "Cache path ({}) is not a directory.",
                path.display()
            )));
        } else {
            return Err(CacheError(format!(
                "Cache path ({}) does not exist.",
                path.display()
            )));
        };
        Ok(())
    }
}
<commit_msg>Remove unused import<commit_after>use std::env;
use std::fs;
use std::io::Read;
use std::path::PathBuf;

use reqwest::{Client, Proxy};
use flate2::read::GzDecoder;
use log::debug;
use app_dirs::{get_app_root, AppDataType};
use std::time::{Duration, SystemTime};
use tar::Archive;
use walkdir::{DirEntry, WalkDir};

use crate::error::TealdeerError::{self, CacheError, UpdateError};
use crate::types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {
    pub fn new<S>(url: S, os: OsType) -> Self
    where
        S: Into<String>,
    {
        Self {
            url: url.into(),
            os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TealdeerError> {
        // Allow overriding the cache directory by setting the
        // $TEALDEER_CACHE_DIR env variable.
        if let Ok(value) = env::var("TEALDEER_CACHE_DIR") {
            let path = PathBuf::from(value);

            if path.exists() && path.is_dir() {
                return Ok(path);
            } else {
                return Err(CacheError(
                    "Path specified by $TEALDEER_CACHE_DIR \
                     does not exist or is not a directory."
                        .into(),
                ));
            }
        };

        // Otherwise, fall back to user cache directory.
        match get_app_root(AppDataType::UserCache, &crate::APP_INFO) {
            Ok(dirs) => Ok(dirs),
            Err(_) => Err(CacheError("Could not determine user cache directory.".into())),
        }
    }

    /// Download the archive
    fn download(&self) -> Result<Vec<u8>, TealdeerError> {
        let mut builder = Client::builder();
        if let Ok(ref host) = env::var("HTTP_PROXY") {
            if let Ok(proxy) = Proxy::http(host) {
                builder = builder.proxy(proxy);
            }
        }
        if let Ok(ref host) = env::var("HTTPS_PROXY") {
            if let Ok(proxy) = Proxy::https(host) {
                builder = builder.proxy(proxy);
            }
        }
        let client = builder.build().unwrap_or_else(|_| Client::new());
        let mut resp = client.get(&self.url).send()?;
        let mut buf: Vec<u8> = vec![];
        let bytes_downloaded = resp.copy_to(&mut buf)?;
        debug!("{} bytes downloaded", bytes_downloaded);
        Ok(buf)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Archive<GzDecoder<R>> {
        Archive::new(GzDecoder::new(reader))
    }

    /// Update the pages cache.
    pub fn update(&self) -> Result<(), TealdeerError> {
        // First, download the compressed data
        let bytes: Vec<u8> = self.download()?;

        // Decompress the response body into an `Archive`
        let mut archive = self.decompress(&bytes[..]);

        // Determine paths
        let cache_dir = self.get_cache_dir()?;

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        fs::create_dir_all(&cache_dir)
            .map_err(|e| UpdateError(format!("Could not create cache directory: {}", e)))?;

        // Clear cache directory
        // Note: This is not the best solution. Ideally we would download the
        // archive to a temporary directory and then swap the two directories.
        // But renaming a directory doesn't work across filesystems and Rust
        // does not yet offer a recursive directory copying function. So for
        // now, we'll use this approach.
        self.clear()?;

        // Extract archive
        archive
            .unpack(&cache_dir)
            .map_err(|e| UpdateError(format!("Could not unpack compressed data: {}", e)))?;

        Ok(())
    }

    /// Return the duration since the cache directory was last modified.
    pub fn last_update(&self) -> Option<Duration> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir.join("tldr-master")) {
                if let Ok(mtime) = metadata.modified() {
                    let now = SystemTime::now();
                    return now.duration_since(mtime).ok();
                };
            };
        };
        None
    }

    /// Return the platform directory.
    #[allow(clippy::match_same_arms)]
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Windows => Some("windows"),
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let platforms_dir = match self.get_cache_dir() {
            Ok(cache_dir) => cache_dir.join("tldr-master").join("pages"),
            _ => return None,
        };

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Return the available pages.
    pub fn list_pages(&self) -> Result<Vec<String>, TealdeerError> {
        // Determine platforms directory and platform
        let cache_dir = self.get_cache_dir()?;
        let platforms_dir = cache_dir.join("tldr-master").join("pages");
        let platform_dir = self.get_platform_dir();

        // Closure that allows the WalkDir instance to traverse platform
        // specific and common page directories, but not others.
        let should_walk = |entry: &DirEntry| -> bool {
            let file_type = entry.file_type();
            let file_name = match entry.file_name().to_str() {
                Some(name) => name,
                None => return false,
            };
            if file_type.is_dir() {
                if file_name == "common" {
                    return true;
                }
                if let Some(platform) = platform_dir {
                    return file_name == platform;
                }
            } else if file_type.is_file() {
                return true;
            }
            false
        };

        // Recursively walk through common and (if applicable) platform specific directory
        let mut pages = WalkDir::new(platforms_dir)
            .min_depth(1) // Skip root directory
            .into_iter()
            .filter_entry(|e| should_walk(e)) // Filter out pages for other architectures
            .filter_map(|e| e.ok()) // Convert results to options, filter out errors
            .filter_map(|e| {
                let path = e.path();
                let extension = &path.extension().and_then(|s| s.to_str()).unwrap_or("");
                if e.file_type().is_file() && extension == &"md" {
                    path.file_stem()
                        .and_then(|stem| stem.to_str().map(|s| s.into()))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>();
        pages.sort();
        pages.dedup();
        Ok(pages)
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TealdeerError> {
        let path = self.get_cache_dir()?;
        if path.exists() && path.is_dir() {
            fs::remove_dir_all(&path).map_err(|_| CacheError(format!(
                "Could not remove cache directory ({}).",
                path.display()
            )))?;
        } else if path.exists() {
            return Err(CacheError(format!(
                "Cache path ({}) is not a directory.",
                path.display()
            )));
        } else {
            return Err(CacheError(format!(
                "Cache path ({}) does not exist.",
                path.display()
            )));
        };
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::vec::Vec;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::exit;

use zwreec::config;

mod logger;

// found in:
// http://stackoverflow.com/a/27590832
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

/// Returns the primary options for zwreec. It is e.g. used to generate the
/// usage information.
fn short_options() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optflagmulti("v", "verbose", "be more verbose. Can be used multiple times.");
    opts.optflag("q", "quiet", "be quiet");
    opts.optflagopt("l", "logfile", "specify log file (default zwreec.log)", "LOGFILE");
    opts.optopt("o", "", "name of the output file", "FILE");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "display version");

    opts
}

/// Prints usage information
/// The verbose flag signals if all options should be shown.
/// NOTE: This is similar to librustc_driver's usage function.
fn usage(verbose: bool) {
    let options = if verbose {
        short_options()
    } else {
        config::zwreec_options(short_options())
    };

    let brief = format!("Usage: zwreec [-hV] [-vq] [-l [LOGFILE]] [-o OUTPUT] INPUT");

    println!("{}\n
Additional help:
    --help -v           Print the full set of options zwreec accepts",
        options.usage(&brief));
}

/// Parse command line arguments
///
/// Parses command line arguments to set up the logger and extract input and
/// output parameters. Will display the usage and exit depending on arguments.
///
/// Returns `getopts::Matches` and a `std::fs::File` for the input and output
/// file. The `getopts::Matches` can be used to
///
/// # Examples
///
/// ```
/// let mut opts = getopts::Options::new();
/// opts.optflag("h", "help", "display this help and exit");
///
/// let (matches, mut input, mut output) = parse_arguments(
///     env::args().collect(),
///     opts
/// );
/// ```
///
/// # Failures
///
/// Depending on encountered arguments or parsing errors this function will
/// print the usage and/or call `exit(1)`.
///
/// NOTE: This is similar to librustc_driver's handle_options function.
fn parse_arguments(args: Vec<String>, opts: getopts::Options) -> (getopts::Matches, config::Config) {
    let mut loggers: Vec<Box<logger::SharedLogger>> = vec![];

    if args.is_empty() {
        // No options provided, print usage and exit
        usage(false);
        exit(1);
    }

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(f) => {
            // parsing error
            // display usage and return
            print_stderr!("{}\n", f.to_string());
            exit(1);
        }
    };

    if matches.opt_present("help") {
        usage(matches.opt_present("verbose"));
        exit(1);
    }

    if matches.opt_present("version") {
        println!("zwreec {}", match option_env!("CFG_VERSION") {
            Some(s) => s.to_string(),
            None => format!("{}.{}.{}{}",
                            env!("CARGO_PKG_VERSION_MAJOR"),
                            env!("CARGO_PKG_VERSION_MINOR"),
                            env!("CARGO_PKG_VERSION_PATCH"),
                            option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
        });
        exit(0);
    }

    if matches.opt_present("verbose") {
        // set log level to verbose
        loggers.push(logger::TermLogger::new(
                match matches.opt_count("v") {
                    1 => logger::LogLevelFilter::Info,
                    2 => logger::LogLevelFilter::Debug,
                    _ => logger::LogLevelFilter::Trace,
                }));
    } else if matches.opt_present("quiet") {
        // set log level to error
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Error));
    } else {
        // set log level to warn
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Warn));
    }

    if matches.opt_present("logfile") {
        // sets a logger to output to logfile
        let name = if let Some(n) = matches.opt_str("logfile") {
            n
        } else {
            "zwreec.log".to_string()
        };
        loggers.push(logger::FileLogger::new(
                        logger::LogLevelFilter::Trace,
                        File::create(name).unwrap())
            );
    }

    // TODO: This might not belong in a function called parse_arguments
    // activate logger
    let _ = logger::CombinedLogger::init(loggers);

    let cfg = config::parse_matches(&matches);
    (matches, cfg)
}

fn parse_input(matches: &getopts::Matches) -> Option<File> {
    if matches.free.len() == 1 {
        let path = Path::new(&matches.free[0]);
        match File::open(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                    path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                info!("Opened input: {}", path.display());
                Some(file)
            }
        }
    } else {
        // TODO: check if STDOUT is a tty
        None
    }
}

fn parse_output(matches: &getopts::Matches) -> Option<File> {
    if let Some(file) = matches.opt_str("o") {
        // try to open FILE
        let path = Path::new(&file);
        match File::create(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                       path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                info!("Opened output: {}", path.display());
                Some(file)
            }
        }
    } else {
        let path = Path::new("a.z8");
        match File::create(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                       path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                debug!("No output file specified, assuming default");
                info!("Opened output: {}", path.display());
                Some(file)
            }
        }
    }
}

fn main() {
    // handle command line parameters
    let (matches, cfg) = parse_arguments(
        env::args().collect(),
        config::zwreec_options(short_options())
    );

    let mut input = parse_input(&matches);
    let mut output = parse_output(&matches);

    debug!("Parsed command line options");
    info!("Main started");

    // call library
    if cfg.testmode {
        zwreec::test_library(cfg, &mut input, &mut output);
    } else {
        // unwrap input and output
        let mut _input = match input {
            Some(i) => i,
            None => panic!("Missing input file! Compile aborted")
        };
        let mut _output = match output {
            Some(o) => o,
            None => panic!("Missing output file! Compile aborted")
        };
        zwreec::compile(cfg, &mut _input, &mut _output);
    }

    info!("Main finished");
}
<commit_msg>Fix verbose help display<commit_after>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::vec::Vec;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::exit;

use zwreec::config;

mod logger;

// found in:
// http://stackoverflow.com/a/27590832
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

/// Returns the primary options for zwreec. It is e.g. used to generate the
/// usage information.
fn short_options() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optflagmulti("v", "verbose", "be more verbose. Can be used multiple times.");
    opts.optflag("q", "quiet", "be quiet");
    opts.optflagopt("l", "logfile", "specify log file (default zwreec.log)", "LOGFILE");
    opts.optopt("o", "", "name of the output file", "FILE");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "display version");

    opts
}

/// Prints usage information
/// The verbose flag signals if all options should be shown.
/// NOTE: This is similar to librustc_driver's usage function.
fn usage(verbose: bool) {
    let options = if verbose {
        config::zwreec_options(short_options())
    } else {
        short_options()
    };

    let brief = format!("Usage: zwreec [-hV] [-vq] [-l [LOGFILE]] [-o OUTPUT] INPUT");

    println!("{}\n
Additional help:
    --help -v           Print the full set of options zwreec accepts",
        options.usage(&brief));
}

/// Parse command line arguments
///
/// Parses command line arguments to set up the logger and extract input and
/// output parameters. Will display the usage and exit depending on arguments.
///
/// Returns `getopts::Matches` and a `std::fs::File` for the input and output
/// file. The `getopts::Matches` can be used to
///
/// # Examples
///
/// ```
/// let mut opts = getopts::Options::new();
/// opts.optflag("h", "help", "display this help and exit");
///
/// let (matches, mut input, mut output) = parse_arguments(
///     env::args().collect(),
///     opts
/// );
/// ```
///
/// # Failures
///
/// Depending on encountered arguments or parsing errors this function will
/// print the usage and/or call `exit(1)`.
///
/// NOTE: This is similar to librustc_driver's handle_options function.
fn parse_arguments(args: Vec<String>, opts: getopts::Options) -> (getopts::Matches, config::Config) {
    let mut loggers: Vec<Box<logger::SharedLogger>> = vec![];

    if args.is_empty() {
        // No options provided, print usage and exit
        usage(false);
        exit(1);
    }

    let matches = match opts.parse(&args[1..]) {
        Ok(m)  => m,
        Err(f) => {
            // parsing error
            // display usage and return
            print_stderr!("{}\n", f.to_string());
            exit(1);
        }
    };

    if matches.opt_present("help") {
        usage(matches.opt_present("verbose"));
        exit(1);
    }

    if matches.opt_present("version") {
        println!("zwreec {}", match option_env!("CFG_VERSION") {
            Some(s) => s.to_string(),
            None => format!("{}.{}.{}{}",
                            env!("CARGO_PKG_VERSION_MAJOR"),
                            env!("CARGO_PKG_VERSION_MINOR"),
                            env!("CARGO_PKG_VERSION_PATCH"),
                            option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
        });
        exit(0);
    }

    if matches.opt_present("verbose") {
        // set log level to verbose
        loggers.push(logger::TermLogger::new(
                match matches.opt_count("v") {
                    1 => logger::LogLevelFilter::Info,
                    2 => logger::LogLevelFilter::Debug,
                    _ => logger::LogLevelFilter::Trace,
                }));
    } else if matches.opt_present("quiet") {
        // set log level to error
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Error));
    } else {
        // set log level to warn
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Warn));
    }

    if matches.opt_present("logfile") {
        // sets a logger to output to logfile
        let name = if let Some(n) = matches.opt_str("logfile") {
            n
        } else {
            "zwreec.log".to_string()
        };
        loggers.push(logger::FileLogger::new(
                        logger::LogLevelFilter::Trace,
                        File::create(name).unwrap())
            );
    }

    // TODO: This might not belong in a function called parse_arguments
    // activate logger
    let _ = logger::CombinedLogger::init(loggers);

    let cfg = config::parse_matches(&matches);
    (matches, cfg)
}

fn parse_input(matches: &getopts::Matches) -> Option<File> {
    if matches.free.len() == 1 {
        let path = Path::new(&matches.free[0]);
        match File::open(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                    path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                info!("Opened input: {}", path.display());
                Some(file)
            }
        }
    } else {
        // TODO: check if STDOUT is a tty
        None
    }
}

fn parse_output(matches: &getopts::Matches) -> Option<File> {
    if let Some(file) = matches.opt_str("o") {
        // try to open FILE
        let path = Path::new(&file);
        match File::create(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                       path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                info!("Opened output: {}", path.display());
                Some(file)
            }
        }
    } else {
        let path = Path::new("a.z8");
        match File::create(path) {
            Err(why) => {
                error!("Couldn't open {}: {}",
                       path.display(), Error::description(&why));
                None
            },
            Ok(file) => {
                debug!("No output file specified, assuming default");
                info!("Opened output: {}", path.display());
                Some(file)
            }
        }
    }
}

fn main() {
    // handle command line parameters
    let (matches, cfg) = parse_arguments(
        env::args().collect(),
        config::zwreec_options(short_options())
    );

    let mut input = parse_input(&matches);
    let mut output = parse_output(&matches);

    debug!("Parsed command line options");
    info!("Main started");

    // call library
    if cfg.testmode {
        zwreec::test_library(cfg, &mut input, &mut output);
    } else {
        // unwrap input and output
        let mut _input = match input {
            Some(i) => i,
            None => panic!("Missing input file! Compile aborted")
        };
        let mut _output = match output {
            Some(o) => o,
            None => panic!("Missing output file! Compile aborted")
        };
        zwreec::compile(cfg, &mut _input, &mut _output);
    }

    info!("Main finished");
}
<|endoftext|>


<commit_before>//! Choice combinators

#[macro_use]
mod macros;

use crate::error::ErrorKind;
use crate::error::ParseError;
use crate::internal::{Err, IResult, Parser};

/// Helper trait for the [alt()] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Alt<I, O, E> {
  /// Tests each parser in the tuple and returns the result of the first one that succeeds
  fn choice(&mut self, input: I) -> IResult<I, O, E>;
}

/// Tests a list of parsers one by one until one succeeds.
///
/// It takes as argument a tuple of parsers.
///
/// ```rust
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::ErrorKind, Needed, IResult};
/// use nom::character::complete::{alpha1, digit1};
/// use nom::branch::alt;
/// # fn main() {
/// fn parser(input: &str) -> IResult<&str, &str> {
///   alt((alpha1, digit1))(input)
/// };
///
/// // the first parser, alpha1, recognizes the input
/// assert_eq!(parser("abc"), Ok(("", "abc")));
///
/// // the first parser returns an error, so alt tries the second one
/// assert_eq!(parser("123456"), Ok(("", "123456")));
///
/// // both parsers failed, and with the default error type, alt will return the last error
/// assert_eq!(parser(" "), Err(Err::Error(error_position!(" ", ErrorKind::Digit))));
/// # }
/// ```
///
/// With a custom error type, it is possible to have alt return the error of the parser
/// that went the farthest in the input data
pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.choice(i)
}

/// Helper trait for the [permutation()] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Permutation<I, O, E> {
  /// Tries to apply all parsers in the tuple in various orders until all of them succeed
  fn permutation(&mut self, input: I) -> IResult<I, O, E>;
}

/// Applies a list of parsers in any order.
///
/// Permutation will succeed if all of the child parsers succeeded.
/// It takes as argument a tuple of parsers, and returns a
/// tuple of the parser results.
///
/// ```rust
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::{Error, ErrorKind}, Needed, IResult};
/// use nom::character::complete::{alpha1, digit1};
/// use nom::branch::permutation;
/// # fn main() {
/// fn parser(input: &str) -> IResult<&str, (&str, &str)> {
///   permutation((alpha1, digit1))(input)
/// }
///
/// // permutation recognizes alphabetic characters then digit
/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
///
/// // but also in inverse order
/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123"))));
///
/// // it will fail if one of the parsers failed
/// assert_eq!(parser("abc;"), Err(Err::Error(Error::new(";", ErrorKind::Digit))));
/// # }
/// ```
///
/// The parsers are applied greedily: if there are multiple unapplied parsers
/// that could parse the next slice of input, the first one is used.
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, IResult};
/// use nom::branch::permutation;
/// use nom::character::complete::{anychar, char};
///
/// fn parser(input: &str) -> IResult<&str, (char, char)> {
///   permutation((anychar, char('a')))(input)
/// }
///
/// # fn main() {
/// // anychar parses 'b', then char('a') parses 'a'
/// assert_eq!(parser("ba"), Ok(("", ('b', 'a'))));
///
/// // anychar parses 'a', then char('a') fails on 'b',
/// // even though char('a') followed by anychar would succeed
/// assert_eq!(parser("ab"), Err(Err::Error(Error::new("b", ErrorKind::Char))));
/// # }
/// ```
///
pub fn permutation<I: Clone, O, E: ParseError<I>, List: Permutation<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.permutation(i)
}

macro_rules! alt_trait(
  ($first:ident $second:ident $($id: ident)+) => (
    alt_trait!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    alt_trait_impl!($($current)*);

    alt_trait!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    alt_trait_impl!($($current)*);
    alt_trait_impl!($($current)* $head);
  );
);

macro_rules! alt_trait_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Parser<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn choice(&mut self, input: Input) -> IResult<Input, Output, Error> {
        match self.0.parse(input.clone()) {
          Err(Err::Error(e)) => alt_trait_inner!(1, self, input, e, $($id)+),
          res => res,
        }
      }
    }
  );
);

macro_rules! alt_trait_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match $self.$it.parse($input.clone()) {
      Err(Err::Error(e)) => {
        let err = $err.or(e);
        succ!($it, alt_trait_inner!($self, $input, err, $($id)+))
      }
      res => res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    Err(Err::Error(Error::append($input, ErrorKind::Alt, $err)))
  );
);

alt_trait!(A B C D E F G H I J K L M N O P Q R S T U);

macro_rules! permutation_trait(
  (
    $name1:ident $ty1:ident $item1:ident
    $name2:ident $ty2:ident $item2:ident
    $($name3:ident $ty3:ident $item3:ident)*
  ) => (
    permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
  );
  (
    __impl $($name:ident $ty:ident $item:ident),+;
    $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
  ) => (
    permutation_trait_impl!($($name $ty $item),+);
    permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
  );
  (__impl $($name:ident $ty:ident $item:ident),+;) => (
    permutation_trait_impl!($($name $ty $item),+);
  );
);

macro_rules! permutation_trait_impl(
  ($($name:ident $ty:ident $item:ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Parser<Input, $ty, Error>),+
    > Permutation<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn permutation(&mut self, mut input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        let mut res = ($(Option::<$ty>::None),+);

        loop {
          let mut err: Option<Error> = None;
          permutation_trait_inner!(0, self, input, res, err, $($name)+);

          // If we reach here, every iterator has either been applied before,
          // or errored on the remaining input
          if let Some(err) = err {
            // There are remaining parsers, and all errored on the remaining input
            return Err(Err::Error(Error::append(input, ErrorKind::Permutation, err)));
          }

          // All parsers were applied
          match res {
            ($(Some($item)),+) => return Ok((input, ($($item),+))),
            _ => unreachable!(),
          }
        }
      }
    }
  );
);

macro_rules! permutation_trait_inner(
  ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
    if $res.$it.is_none() {
      match $self.$it.parse($input.clone()) {
        Ok((i, o)) => {
          $input = i;
          $res.$it = Some(o);
          continue;
        }
        Err(Err::Error(e)) => {
          $err = Some(match $err {
            Some(err) => err.or(e),
            None => e,
          });
        }
        Err(e) => return Err(e),
      };
    }
    succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($id)*));
  );
  ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => ();
);

permutation_trait!(
  FnA A a
  FnB B b
  FnC C c
  FnD D d
  FnE E e
  FnF F f
  FnG G g
  FnH H h
  FnI I i
  FnJ J j
  FnK K k
  FnL L l
  FnM M m
  FnN N n
  FnO O o
  FnP P p
  FnQ Q q
  FnR R r
  FnS S s
  FnT T t
  FnU U u
);
<commit_msg>mention the limit in number of parsers for alt<commit_after>//! Choice combinators

#[macro_use]
mod macros;

use crate::error::ErrorKind;
use crate::error::ParseError;
use crate::internal::{Err, IResult, Parser};

/// Helper trait for the [alt()] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Alt<I, O, E> {
  /// Tests each parser in the tuple and returns the result of the first one that succeeds
  fn choice(&mut self, input: I) -> IResult<I, O, E>;
}

/// Tests a list of parsers one by one until one succeeds.
///
/// It takes as argument a tuple of parsers. There is a maximum of 21
/// parsers. If you need more, it is possible to nest them in other `alt` calls,
/// like this: `alt(parser_a, alt(parser_b, parser_c))`
///
/// ```rust
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::ErrorKind, Needed, IResult};
/// use nom::character::complete::{alpha1, digit1};
/// use nom::branch::alt;
/// # fn main() {
/// fn parser(input: &str) -> IResult<&str, &str> {
///   alt((alpha1, digit1))(input)
/// };
///
/// // the first parser, alpha1, recognizes the input
/// assert_eq!(parser("abc"), Ok(("", "abc")));
///
/// // the first parser returns an error, so alt tries the second one
/// assert_eq!(parser("123456"), Ok(("", "123456")));
///
/// // both parsers failed, and with the default error type, alt will return the last error
/// assert_eq!(parser(" "), Err(Err::Error(error_position!(" ", ErrorKind::Digit))));
/// # }
/// ```
///
/// With a custom error type, it is possible to have alt return the error of the parser
/// that went the farthest in the input data
pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.choice(i)
}

/// Helper trait for the [permutation()] combinator.
///
/// This trait is implemented for tuples of up to 21 elements
pub trait Permutation<I, O, E> {
  /// Tries to apply all parsers in the tuple in various orders until all of them succeed
  fn permutation(&mut self, input: I) -> IResult<I, O, E>;
}

/// Applies a list of parsers in any order.
///
/// Permutation will succeed if all of the child parsers succeeded.
/// It takes as argument a tuple of parsers, and returns a
/// tuple of the parser results.
///
/// ```rust
/// # #[macro_use] extern crate nom;
/// # use nom::{Err,error::{Error, ErrorKind}, Needed, IResult};
/// use nom::character::complete::{alpha1, digit1};
/// use nom::branch::permutation;
/// # fn main() {
/// fn parser(input: &str) -> IResult<&str, (&str, &str)> {
///   permutation((alpha1, digit1))(input)
/// }
///
/// // permutation recognizes alphabetic characters then digit
/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
///
/// // but also in inverse order
/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123"))));
///
/// // it will fail if one of the parsers failed
/// assert_eq!(parser("abc;"), Err(Err::Error(Error::new(";", ErrorKind::Digit))));
/// # }
/// ```
///
/// The parsers are applied greedily: if there are multiple unapplied parsers
/// that could parse the next slice of input, the first one is used.
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, IResult};
/// use nom::branch::permutation;
/// use nom::character::complete::{anychar, char};
///
/// fn parser(input: &str) -> IResult<&str, (char, char)> {
///   permutation((anychar, char('a')))(input)
/// }
///
/// # fn main() {
/// // anychar parses 'b', then char('a') parses 'a'
/// assert_eq!(parser("ba"), Ok(("", ('b', 'a'))));
///
/// // anychar parses 'a', then char('a') fails on 'b',
/// // even though char('a') followed by anychar would succeed
/// assert_eq!(parser("ab"), Err(Err::Error(Error::new("b", ErrorKind::Char))));
/// # }
/// ```
///
pub fn permutation<I: Clone, O, E: ParseError<I>, List: Permutation<I, O, E>>(
  mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
  move |i: I| l.permutation(i)
}

macro_rules! alt_trait(
  ($first:ident $second:ident $($id: ident)+) => (
    alt_trait!(__impl $first $second; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident $($id: ident)+) => (
    alt_trait_impl!($($current)*);

    alt_trait!(__impl $($current)* $head; $($id)+);
  );
  (__impl $($current:ident)*; $head:ident) => (
    alt_trait_impl!($($current)*);
    alt_trait_impl!($($current)* $head);
  );
);

macro_rules! alt_trait_impl(
  ($($id:ident)+) => (
    impl<
      Input: Clone, Output, Error: ParseError<Input>,
      $($id: Parser<Input, Output, Error>),+
    > Alt<Input, Output, Error> for ( $($id),+ ) {

      fn choice(&mut self, input: Input) -> IResult<Input, Output, Error> {
        match self.0.parse(input.clone()) {
          Err(Err::Error(e)) => alt_trait_inner!(1, self, input, e, $($id)+),
          res => res,
        }
      }
    }
  );
);

macro_rules! alt_trait_inner(
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
    match $self.$it.parse($input.clone()) {
      Err(Err::Error(e)) => {
        let err = $err.or(e);
        succ!($it, alt_trait_inner!($self, $input, err, $($id)+))
      }
      res => res,
    }
  );
  ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
    Err(Err::Error(Error::append($input, ErrorKind::Alt, $err)))
  );
);

alt_trait!(A B C D E F G H I J K L M N O P Q R S T U);

macro_rules! permutation_trait(
  (
    $name1:ident $ty1:ident $item1:ident
    $name2:ident $ty2:ident $item2:ident
    $($name3:ident $ty3:ident $item3:ident)*
  ) => (
    permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
  );
  (
    __impl $($name:ident $ty:ident $item:ident),+;
    $name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
  ) => (
    permutation_trait_impl!($($name $ty $item),+);
    permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
  );
  (__impl $($name:ident $ty:ident $item:ident),+;) => (
    permutation_trait_impl!($($name $ty $item),+);
  );
);

macro_rules! permutation_trait_impl(
  ($($name:ident $ty:ident $item:ident),+) => (
    impl<
      Input: Clone, $($ty),+ , Error: ParseError<Input>,
      $($name: Parser<Input, $ty, Error>),+
    > Permutation<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {

      fn permutation(&mut self, mut input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
        let mut res = ($(Option::<$ty>::None),+);

        loop {
          let mut err: Option<Error> = None;
          permutation_trait_inner!(0, self, input, res, err, $($name)+);

          // If we reach here, every iterator has either been applied before,
          // or errored on the remaining input
          if let Some(err) = err {
            // There are remaining parsers, and all errored on the remaining input
            return Err(Err::Error(Error::append(input, ErrorKind::Permutation, err)));
          }

          // All parsers were applied
          match res {
            ($(Some($item)),+) => return Ok((input, ($($item),+))),
            _ => unreachable!(),
          }
        }
      }
    }
  );
);

macro_rules! permutation_trait_inner(
  ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
    if $res.$it.is_none() {
      match $self.$it.parse($input.clone()) {
        Ok((i, o)) => {
          $input = i;
          $res.$it = Some(o);
          continue;
        }
        Err(Err::Error(e)) => {
          $err = Some(match $err {
            Some(err) => err.or(e),
            None => e,
          });
        }
        Err(e) => return Err(e),
      };
    }
    succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($id)*));
  );
  ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => ();
);

permutation_trait!(
  FnA A a
  FnB B b
  FnC C c
  FnD D d
  FnE E e
  FnF F f
  FnG G g
  FnH H h
  FnI I i
  FnJ J j
  FnK K k
  FnL L l
  FnM M m
  FnN N n
  FnO O o
  FnP P p
  FnQ Q q
  FnR R r
  FnS S s
  FnT T t
  FnU U u
);
<|endoftext|>


<commit_before>#![allow(missing_copy_implementations)]

#[cfg(test)]
mod tests;

use crate::fmt;
use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write};

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty()`]. Please see
/// the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty {
    _priv: (),
}

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
    Empty { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        Ok(&[])
    }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "empty_seek", since = "1.51.0")]
impl Seek for Empty {
    fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_len(&mut self) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_position(&mut self) -> io::Result<u64> {
        Ok(0)
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

impl SizeHint for Empty {
    fn upper_bound(&self) -> Option<usize> {
       Some(0)
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
/// see the documentation of [`repeat()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat {
    byte: u8,
}

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
    Repeat { byte }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let mut nwritten = 0;
        for buf in bufs {
            nwritten += self.read(buf)?;
        }
        Ok(nwritten)
    }

    #[inline]
    fn is_read_vectored(&self) -> bool {
        true
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink {
    _priv: (),
}

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
    Sink { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "write_mt", since = "1.48.0")]
impl Write for &Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}
<commit_msg>Add space for proper indentation<commit_after>#![allow(missing_copy_implementations)]

#[cfg(test)]
mod tests;

use crate::fmt;
use crate::io::{self, BufRead, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, SizeHint, Write};

/// A reader which is always at EOF.
///
/// This struct is generally created by calling [`empty()`]. Please see
/// the documentation of [`empty()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty {
    _priv: (),
}

/// Constructs a new handle to an empty reader.
///
/// All reads from the returned reader will return [`Ok`]`(0)`.
///
/// # Examples
///
/// A slightly sad example of not reading anything into a buffer:
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = String::new();
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
    Empty { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
    #[inline]
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Ok(0)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        Ok(&[])
    }
    #[inline]
    fn consume(&mut self, _n: usize) {}
}

#[stable(feature = "empty_seek", since = "1.51.0")]
impl Seek for Empty {
    fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_len(&mut self) -> io::Result<u64> {
        Ok(0)
    }

    fn stream_position(&mut self) -> io::Result<u64> {
        Ok(0)
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Empty {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Empty { .. }")
    }
}

impl SizeHint for Empty {
    fn upper_bound(&self) -> Option<usize> {
        Some(0)
    }
}

/// A reader which yields one byte over and over and over and over and over and...
///
/// This struct is generally created by calling [`repeat()`]. Please
/// see the documentation of [`repeat()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat {
    byte: u8,
}

/// Creates an instance of a reader that infinitely repeats one byte.
///
/// All reads from this reader will succeed by filling the specified buffer with
/// the given byte.
///
/// # Examples
///
/// ```
/// use std::io::{self, Read};
///
/// let mut buffer = [0; 3];
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
    Repeat { byte }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        for slot in &mut *buf {
            *slot = self.byte;
        }
        Ok(buf.len())
    }

    #[inline]
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let mut nwritten = 0;
        for buf in bufs {
            nwritten += self.read(buf)?;
        }
        Ok(nwritten)
    }

    #[inline]
    fn is_read_vectored(&self) -> bool {
        true
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Repeat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Repeat { .. }")
    }
}

/// A writer which will move data into the void.
///
/// This struct is generally created by calling [`sink`]. Please
/// see the documentation of [`sink()`] for more details.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Sink {
    _priv: (),
}

/// Creates an instance of a writer which will successfully consume all data.
///
/// All calls to [`write`] on the returned instance will return `Ok(buf.len())`
/// and the contents of the buffer will not be inspected.
///
/// [`write`]: Write::write
///
/// # Examples
///
/// ```rust
/// use std::io::{self, Write};
///
/// let buffer = vec![1, 2, 3, 5, 8];
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
    Sink { _priv: () }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "write_mt", since = "1.48.0")]
impl Write for &Sink {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Ok(buf.len())
    }

    #[inline]
    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let total_len = bufs.iter().map(|b| b.len()).sum();
        Ok(total_len)
    }

    #[inline]
    fn is_write_vectored(&self) -> bool {
        true
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Sink {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.pad("Sink { .. }")
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::io::{self, Write};
use std::path::Path;

use crate::rustfmt_diff::{DiffLine, Mismatch};

/// The checkstyle header - should be emitted before the output of Rustfmt.
///
/// Note that emitting checkstyle output is not stable and may removed in a
/// future version of Rustfmt.
pub(crate) fn header() -> String {
    let mut xml_heading = String::new();
    xml_heading.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
    xml_heading.push_str("\n");
    xml_heading.push_str("<checkstyle version=\"4.3\">");
    xml_heading
}

/// The checkstyle footer - should be emitted after the output of Rustfmt.
///
/// Note that emitting checkstyle output is not stable and may removed in a
/// future version of Rustfmt.
pub(crate) fn footer() -> String {
    "</checkstyle>\n".to_owned()
}

pub(crate) fn output_checkstyle_file<T>(
    mut writer: T,
    filename: &Path,
    diff: Vec<Mismatch>,
) -> Result<(), io::Error>
where
    T: Write,
{
    write!(writer, "<file name=\"{}\">", filename.display())?;
    for mismatch in diff {
        for line in mismatch.lines {
            // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
            if let DiffLine::Expected(message) = line {
                write!(
                    writer,
                    "<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \
                     />",
                    mismatch.line_number, XmlEscaped(&message)
                )?;
            }
        }
    }
    write!(writer, "</file>")?;
    Ok(())
}

/// Convert special characters into XML entities.
/// This is needed for checkstyle output.
struct XmlEscaped<'a>(&'a str);

impl<'a> Display for XmlEscaped<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        for char in self.0.chars() {
            match char {
                '<' => write!(formatter, "<"),
                '>' => write!(formatter, ">"),
                '"' => write!(formatter, """),
                '\'' => write!(formatter, "'"),
                '&' => write!(formatter, "&"),
                _ => write!(formatter, "{}", char),
            }?;
        }

        Ok(())
    }
}

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

    #[test]
    fn special_characters_are_escaped() {
        assert_eq!(
            "<>"'&",
            format!("{}", XmlEscaped(r#"<>"'&"#)),
        );
    }

    #[test]
    fn special_characters_are_escaped_in_string_with_other_characters() {
        assert_eq!(
            "The quick brown "🦊" jumps <over> the lazy 🐶",
            format!(
                "{}",
                XmlEscaped(r#"The quick brown "🦊" jumps <over> the lazy 🐶"#)
            ),
        );
    }

    #[test]
    fn other_characters_are_not_escaped() {
        let string = "The quick brown 🦊 jumps over the lazy 🐶";
        assert_eq!(string, format!("{}", XmlEscaped(string)),);
    }
}
<commit_msg>Use raw strings<commit_after>use std::fmt::{self, Display};
use std::io::{self, Write};
use std::path::Path;

use crate::rustfmt_diff::{DiffLine, Mismatch};

/// The checkstyle header - should be emitted before the output of Rustfmt.
///
/// Note that emitting checkstyle output is not stable and may removed in a
/// future version of Rustfmt.
pub(crate) fn header() -> String {
    let mut xml_heading = String::new();
    xml_heading.push_str(r#"<?xml version="1.0" encoding="utf-8"?>"#);
    xml_heading.push_str("\n");
    xml_heading.push_str(r#"<checkstyle version="4.3">"#);
    xml_heading
}

/// The checkstyle footer - should be emitted after the output of Rustfmt.
///
/// Note that emitting checkstyle output is not stable and may removed in a
/// future version of Rustfmt.
pub(crate) fn footer() -> String {
    "</checkstyle>\n".to_owned()
}

pub(crate) fn output_checkstyle_file<T>(
    mut writer: T,
    filename: &Path,
    diff: Vec<Mismatch>,
) -> Result<(), io::Error>
where
    T: Write,
{
    write!(writer, r#"<file name="{}">"#, filename.display())?;
    for mismatch in diff {
        for line in mismatch.lines {
            // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
            if let DiffLine::Expected(message) = line {
                write!(
                    writer,
                    r#"<error line="{}" severity="warning" message="Should be `{}`" />"#,
                    mismatch.line_number,
                    XmlEscaped(&message)
                )?;
            }
        }
    }
    write!(writer, "</file>")?;
    Ok(())
}

/// Convert special characters into XML entities.
/// This is needed for checkstyle output.
struct XmlEscaped<'a>(&'a str);

impl<'a> Display for XmlEscaped<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        for char in self.0.chars() {
            match char {
                '<' => write!(formatter, "<"),
                '>' => write!(formatter, ">"),
                '"' => write!(formatter, """),
                '\'' => write!(formatter, "'"),
                '&' => write!(formatter, "&"),
                _ => write!(formatter, "{}", char),
            }?;
        }

        Ok(())
    }
}

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

    #[test]
    fn special_characters_are_escaped() {
        assert_eq!(
            "<>"'&",
            format!("{}", XmlEscaped(r#"<>"'&"#)),
        );
    }

    #[test]
    fn special_characters_are_escaped_in_string_with_other_characters() {
        assert_eq!(
            "The quick brown "🦊" jumps <over> the lazy 🐶",
            format!(
                "{}",
                XmlEscaped(r#"The quick brown "🦊" jumps <over> the lazy 🐶"#)
            ),
        );
    }

    #[test]
    fn other_characters_are_not_escaped() {
        let string = "The quick brown 🦊 jumps over the lazy 🐶";
        assert_eq!(string, format!("{}", XmlEscaped(string)),);
    }
}
<|endoftext|>