<commit_before>//! `cargo upgrade`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::errors::*;
use cargo_edit::{
    find, get_latest_dependency, registry_url, update_registry_index, CrateName, Dependency,
    LocalManifest,
};
use failure::Fail;
use std::collections::{HashMap, HashSet};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use structopt::StructOpt;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
use url::Url;

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::failure::Compat<::cargo_metadata::Error>);
        }
    }
}

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
    #[structopt(name = "upgrade", author = "")]
    #[structopt(
        after_help = "This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.

If the '--to-lockfile' flag is supplied, all dependencies will be upgraded to the currently locked
version as recorded in the Cargo.lock file. This flags requires that the Cargo.lock file is
up-to-date. If the lock file is missing, or it needs to be updated, cargo-upgrade will exit with an
error. If the '--to-lockfile' flag is supplied then the network won't be accessed."
    )]
    Upgrade(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[structopt(long = "manifest-path", value_name = "path")]
    manifest_path: Option<PathBuf>,

    /// Upgrade all packages in the workspace.
    #[structopt(long = "all")]
    all: bool,

    /// Include prerelease versions when fetching from crates.io (e.g. 0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    allow_prerelease: bool,

    /// Print changes to be made without making them.
    #[structopt(long = "dry-run")]
    dry_run: bool,

    /// Run without accessing the network
    #[structopt(long = "offline")]
    pub offline: bool,

    /// Upgrade all packages to the version in the lockfile.
    #[structopt(long = "to-lockfile", conflicts_with = "dependency")]
    pub to_lockfile: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

/// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
    match dependency.source {
        // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
        // dependency has the 'registry' kind.
        Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
        _ => false,
    }
}

fn dry_run_message() -> Result<()> {
    let bufwtr = BufferWriter::stdout(ColorChoice::Always);
    let mut buffer = bufwtr.buffer();
    buffer
        .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
        .chain_err(|| "Failed to set output colour")?;
    write!(&mut buffer, "Starting dry run. ").chain_err(|| "Failed to write dry run message")?;
    buffer
        .set_color(&ColorSpec::new())
        .chain_err(|| "Failed to clear output colour")?;
    writeln!(&mut buffer, "Changes will not be saved.")
        .chain_err(|| "Failed to write dry run message")?;
    bufwtr
        .print(&buffer)
        .chain_err(|| "Failed to print dry run message")
}

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd.exec().map_err(|e| {
            Error::from(e.compat()).chain_err(|| "Failed to get workspace metadata")
        })?;
        result
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;
        let packages = result.packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path.to_string_lossy() == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| {
                "Found virtual manifest, but this command requires running against an \
                 actual package in this workspace. Try adding `--all`."
            })?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        // Map the names of user-specified dependencies to the (optionally) requested version.
        let selected_dependencies = only_update
            .into_iter()
            .map(|name| {
                if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                    Ok((
                        dependency.name.clone(),
                        dependency.version().map(String::from),
                    ))
                } else {
                    Ok((name, None))
                }
            })
            .collect::<Result<HashMap<_, _>>>()?;

        Ok(DesiredUpgrades(
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .filter_map(|dependency| {
                    if selected_dependencies.is_empty() {
                        // User hasn't asked for any specific dependencies to be upgraded,
                        // so upgrade all the dependencies.
                        let mut dep = Dependency::new(&dependency.name);
                        if let Some(rename) = dependency.rename {
                            dep = dep.set_rename(&rename);
                        }
                        Some((dep, (dependency.registry, None)))
                    } else {
                        // User has asked for specific dependencies. Check if this dependency
                        // was specified, populating the registry from the lockfile metadata.
                        match selected_dependencies.get(&dependency.name) {
                            Some(version) => Some((
                                Dependency::new(&dependency.name),
                                (dependency.registry, version.clone()),
                            )),
                            None => None,
                        }
                    }
                })
                .collect(),
        ))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            dry_run_message()?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            for (dep, version) in &upgraded_deps.0 {
                let mut new_dep = Dependency::new(&dep.name).set_version(version);
                if let Some(rename) = dep.rename() {
                    new_dep = new_dep.set_rename(&rename);
                }
                manifest.upgrade(&new_dep, dry_run)?;
            }
        }

        Ok(())
    }

    /// Update dependencies in Cargo.toml file(s) to match the corresponding
    /// version in Cargo.lock.
    fn sync_to_lockfile(self, dry_run: bool) -> Result<()> {
        // Get locked dependencies. For workspaces with multiple Cargo.toml
        // files, there is only a single lockfile, so it suffices to get
        // metadata for any one of Cargo.toml files.
        let (manifest, _package) =
            self.0.iter().next().ok_or_else(|| {
                ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
            })?;
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.manifest_path(manifest.path.clone());
        cmd.other_options(vec!["--locked".to_string()]);

        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;

        let locked = result
            .packages
            .into_iter()
            .filter(|p| p.source.is_some()) // Source is none for local packages
            .collect::<Vec<_>>();

        if dry_run {
            dry_run_message()?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            // Upgrade the manifests one at a time, as multiple manifests may
            // request the same dependency at differing versions.
            for (name, version) in package
                .dependencies
                .clone()
                .into_iter()
                .filter(is_version_dep)
                .filter_map(|d| {
                    for p in &locked {
                        // The requested dependency may be present in the lock file with different versions,
                        // but only one will be semver-compatible with the requested version.
                        if d.name == p.name && d.req.matches(&p.version) {
                            return Some((d.name, p.version.to_string()));
                        }
                    }
                    None
                })
            {
                manifest.upgrade(&Dependency::new(&name).set_version(&version), dry_run)?;
            }
        }
        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside the registries returned from cargo metadata, and
/// the desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<Dependency, (Option<String>, Option<String>)>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<Dependency, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool, manifest_path: &Path) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(dep, (registry, version))| {
                if let Some(v) = version {
                    Ok((dep, v))
                } else {
                    let registry_url = match registry {
                        Some(x) => Some(Url::parse(&x).map_err(|_| {
                            ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
                        })?),
                        None => None,
                    };
                    get_latest_dependency(&dep.name, allow_prerelease, manifest_path, &registry_url)
                        .map(|new_dep| {
                            (
                                dep,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        dependency,
        manifest_path,
        all,
        allow_prerelease,
        dry_run,
        to_lockfile,
        ..
    } = args;

    if !args.offline && !to_lockfile {
        let url = registry_url(&find(&manifest_path)?, None)?;
        update_registry_index(&url)?;
    }

    let manifests = if all {
        Manifests::get_all(&manifest_path)
    } else {
        Manifests::get_local_one(&manifest_path)
    }?;

    if to_lockfile {
        manifests.sync_to_lockfile(dry_run)
    } else {
        let existing_dependencies = manifests.get_dependencies(dependency)?;

        // Update indices for any alternative registries, unless
        // we're offline.
        if !args.offline {
            for registry_url in existing_dependencies
                .0
                .values()
                .filter_map(|(registry, _)| registry.as_ref())
                .collect::<HashSet<_>>()
            {
                update_registry_index(&Url::parse(registry_url).map_err(|_| {
                    ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
                })?)?;
            }
        }

        let upgraded_dependencies =
            existing_dependencies.get_upgraded(allow_prerelease, &find(&manifest_path)?)?;

        manifests.upgrade(&upgraded_dependencies, dry_run)
    }
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Upgrade(args) = args;

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>Fix typo in help text<commit_after>//! `cargo upgrade`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::errors::*;
use cargo_edit::{
    find, get_latest_dependency, registry_url, update_registry_index, CrateName, Dependency,
    LocalManifest,
};
use failure::Fail;
use std::collections::{HashMap, HashSet};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use structopt::StructOpt;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
use url::Url;

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::failure::Compat<::cargo_metadata::Error>);
        }
    }
}

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
    #[structopt(name = "upgrade", author = "")]
    #[structopt(
        after_help = "This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest.

If the '--to-lockfile' flag is supplied, all dependencies will be upgraded to the currently locked
version as recorded in the Cargo.lock file. This flag requires that the Cargo.lock file is
up-to-date. If the lock file is missing, or it needs to be updated, cargo-upgrade will exit with an
error. If the '--to-lockfile' flag is supplied then the network won't be accessed."
    )]
    Upgrade(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[structopt(long = "manifest-path", value_name = "path")]
    manifest_path: Option<PathBuf>,

    /// Upgrade all packages in the workspace.
    #[structopt(long = "all")]
    all: bool,

    /// Include prerelease versions when fetching from crates.io (e.g. 0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    allow_prerelease: bool,

    /// Print changes to be made without making them.
    #[structopt(long = "dry-run")]
    dry_run: bool,

    /// Run without accessing the network
    #[structopt(long = "offline")]
    pub offline: bool,

    /// Upgrade all packages to the version in the lockfile.
    #[structopt(long = "to-lockfile", conflicts_with = "dependency")]
    pub to_lockfile: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

/// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
    match dependency.source {
        // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
        // dependency has the 'registry' kind.
        Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
        _ => false,
    }
}

fn dry_run_message() -> Result<()> {
    let bufwtr = BufferWriter::stdout(ColorChoice::Always);
    let mut buffer = bufwtr.buffer();
    buffer
        .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
        .chain_err(|| "Failed to set output colour")?;
    write!(&mut buffer, "Starting dry run. ").chain_err(|| "Failed to write dry run message")?;
    buffer
        .set_color(&ColorSpec::new())
        .chain_err(|| "Failed to clear output colour")?;
    writeln!(&mut buffer, "Changes will not be saved.")
        .chain_err(|| "Failed to write dry run message")?;
    bufwtr
        .print(&buffer)
        .chain_err(|| "Failed to print dry run message")
}

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd.exec().map_err(|e| {
            Error::from(e.compat()).chain_err(|| "Failed to get workspace metadata")
        })?;
        result
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;
        let packages = result.packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path.to_string_lossy() == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| {
                "Found virtual manifest, but this command requires running against an \
                 actual package in this workspace. Try adding `--all`."
            })?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        // Map the names of user-specified dependencies to the (optionally) requested version.
        let selected_dependencies = only_update
            .into_iter()
            .map(|name| {
                if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                    Ok((
                        dependency.name.clone(),
                        dependency.version().map(String::from),
                    ))
                } else {
                    Ok((name, None))
                }
            })
            .collect::<Result<HashMap<_, _>>>()?;

        Ok(DesiredUpgrades(
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .filter_map(|dependency| {
                    if selected_dependencies.is_empty() {
                        // User hasn't asked for any specific dependencies to be upgraded,
                        // so upgrade all the dependencies.
                        let mut dep = Dependency::new(&dependency.name);
                        if let Some(rename) = dependency.rename {
                            dep = dep.set_rename(&rename);
                        }
                        Some((dep, (dependency.registry, None)))
                    } else {
                        // User has asked for specific dependencies. Check if this dependency
                        // was specified, populating the registry from the lockfile metadata.
                        match selected_dependencies.get(&dependency.name) {
                            Some(version) => Some((
                                Dependency::new(&dependency.name),
                                (dependency.registry, version.clone()),
                            )),
                            None => None,
                        }
                    }
                })
                .collect(),
        ))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            dry_run_message()?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            for (dep, version) in &upgraded_deps.0 {
                let mut new_dep = Dependency::new(&dep.name).set_version(version);
                if let Some(rename) = dep.rename() {
                    new_dep = new_dep.set_rename(&rename);
                }
                manifest.upgrade(&new_dep, dry_run)?;
            }
        }

        Ok(())
    }

    /// Update dependencies in Cargo.toml file(s) to match the corresponding
    /// version in Cargo.lock.
    fn sync_to_lockfile(self, dry_run: bool) -> Result<()> {
        // Get locked dependencies. For workspaces with multiple Cargo.toml
        // files, there is only a single lockfile, so it suffices to get
        // metadata for any one of Cargo.toml files.
        let (manifest, _package) =
            self.0.iter().next().ok_or_else(|| {
                ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
            })?;
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.manifest_path(manifest.path.clone());
        cmd.other_options(vec!["--locked".to_string()]);

        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;

        let locked = result
            .packages
            .into_iter()
            .filter(|p| p.source.is_some()) // Source is none for local packages
            .collect::<Vec<_>>();

        if dry_run {
            dry_run_message()?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            // Upgrade the manifests one at a time, as multiple manifests may
            // request the same dependency at differing versions.
            for (name, version) in package
                .dependencies
                .clone()
                .into_iter()
                .filter(is_version_dep)
                .filter_map(|d| {
                    for p in &locked {
                        // The requested dependency may be present in the lock file with different versions,
                        // but only one will be semver-compatible with the requested version.
                        if d.name == p.name && d.req.matches(&p.version) {
                            return Some((d.name, p.version.to_string()));
                        }
                    }
                    None
                })
            {
                manifest.upgrade(&Dependency::new(&name).set_version(&version), dry_run)?;
            }
        }
        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside the registries returned from cargo metadata, and
/// the desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<Dependency, (Option<String>, Option<String>)>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<Dependency, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool, manifest_path: &Path) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(dep, (registry, version))| {
                if let Some(v) = version {
                    Ok((dep, v))
                } else {
                    let registry_url = match registry {
                        Some(x) => Some(Url::parse(&x).map_err(|_| {
                            ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
                        })?),
                        None => None,
                    };
                    get_latest_dependency(&dep.name, allow_prerelease, manifest_path, &registry_url)
                        .map(|new_dep| {
                            (
                                dep,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        dependency,
        manifest_path,
        all,
        allow_prerelease,
        dry_run,
        to_lockfile,
        ..
    } = args;

    if !args.offline && !to_lockfile {
        let url = registry_url(&find(&manifest_path)?, None)?;
        update_registry_index(&url)?;
    }

    let manifests = if all {
        Manifests::get_all(&manifest_path)
    } else {
        Manifests::get_local_one(&manifest_path)
    }?;

    if to_lockfile {
        manifests.sync_to_lockfile(dry_run)
    } else {
        let existing_dependencies = manifests.get_dependencies(dependency)?;

        // Update indices for any alternative registries, unless
        // we're offline.
        if !args.offline {
            for registry_url in existing_dependencies
                .0
                .values()
                .filter_map(|(registry, _)| registry.as_ref())
                .collect::<HashSet<_>>()
            {
                update_registry_index(&Url::parse(registry_url).map_err(|_| {
                    ErrorKind::CargoEditLib(::cargo_edit::ErrorKind::InvalidCargoConfig)
                })?)?;
            }
        }

        let upgraded_dependencies =
            existing_dependencies.get_upgraded(allow_prerelease, &find(&manifest_path)?)?;

        manifests.upgrade(&upgraded_dependencies, dry_run)
    }
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Upgrade(args) = args;

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::iter::repeat;

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    let urls: Vec<Url> = try!(url_strings.into_iter().map(network::parse_url).collect());
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    Ok(files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>()
      .join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("==> {} <==\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<commit_msg>fix(engines): make Index detection stricter<commit_after>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::iter::repeat;

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    if url_strings.is_empty() {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let urls: Result<Vec<Url>> = url_strings.into_iter().map(network::parse_url).collect();
    let urls: Vec<Url> = try!(urls.chain_err(|| ErrorKind::InvalidIndexError));
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    Ok(files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>()
      .join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("==> {} <==\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<|endoftext|>


<commit_before>//! Definition of the `JoinAll` combinator, waiting for all of a list of futures
//! to finish.

use std::prelude::v1::*;

use std::fmt;
use std::mem;

use futures_core::{Future, IntoFuture, Poll, Async};
use futures_core::task;

#[derive(Debug)]
enum ElemState<F> where F: Future {
    Pending(F),
    Done(F::Item),
}

/// A future which takes a list of futures and resolves with a vector of the
/// completed values.
///
/// This future is created with the `join_all` method.
#[must_use = "futures do nothing unless polled"]
pub struct JoinAll<F>
    where F: Future,
{
    elems: Vec<ElemState<F>>,
}

impl<F> fmt::Debug for JoinAll<F>
    where F: Future + fmt::Debug,
          F::Item: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("JoinAll")
            .field("elems", &self.elems)
            .finish()
    }
}

/// Creates a future which represents a collection of the results of the futures
/// given.
///
/// The returned future will drive execution for all of its underlying futures,
/// collecting the results into a destination `Vec<T>` in the same order as they
/// were provided. If any future returns an error then all other futures will be
/// canceled and an error will be returned immediately. If all futures complete
/// successfully, however, then the returned future will succeed with a `Vec` of
/// all the successful results.
///
/// # Examples
///
/// ```
/// # extern crate futures;
/// use futures::prelude::*;
/// use futures::future::{join_all, ok, err};
///
/// # fn main() {
/// #
/// let f = join_all(vec![
///     ok::<u32, u32>(1),
///     ok::<u32, u32>(2),
///     ok::<u32, u32>(3),
/// ]);
/// let f = f.map(|x| {
///     assert_eq!(x, [1, 2, 3]);
/// });
///
/// let f = join_all(vec![
///     Box::new(ok::<u32, u32>(1)),
///     Box::new(err::<u32, u32>(2)),
///     Box::new(ok::<u32, u32>(3)),
/// ]);
/// let f = f.then(|x| {
///     assert_eq!(x, Err(2));
///     x
/// });
/// # }
/// ```
pub fn join_all<I>(i: I) -> JoinAll<<I::Item as IntoFuture>::Future>
    where I: IntoIterator,
          I::Item: IntoFuture,
{
    let elems = i.into_iter().map(|f| {
        ElemState::Pending(f.into_future())
    }).collect();
    JoinAll { elems }
}

impl<F> Future for JoinAll<F>
    where F: Future,
{
    type Item = Vec<F::Item>;
    type Error = F::Error;

    fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
        let mut all_done = true;

        for idx in 0 .. self.elems.len() {
            let done_val = match self.elems[idx] {
                ElemState::Pending(ref mut t) => {
                    match t.poll(cx) {
                        Ok(Async::Ready(v)) => Ok(v),
                        Ok(Async::Pending) => {
                            all_done = false;
                            continue
                        }
                        Err(e) => Err(e),
                    }
                }
                ElemState::Done(ref mut _v) => continue,
            };

            match done_val {
                Ok(v) => self.elems[idx] = ElemState::Done(v),
                Err(e) => {
                    // On completion drop all our associated resources
                    // ASAP.
                    self.elems = Vec::new();
                    return Err(e)
                }
            }
        }

        if all_done {
            let elems = mem::replace(&mut self.elems, Vec::new());
            let result = elems.into_iter().map(|e| {
                match e {
                    ElemState::Done(t) => t,
                    _ => unreachable!(),
                }
            }).collect();
            Ok(Async::Ready(result))
        } else {
            Ok(Async::Pending)
        }
    }
}
<commit_msg>Allow using collect to turn a vec of futures into a future of vec<commit_after>//! Definition of the `JoinAll` combinator, waiting for all of a list of futures
//! to finish.

use std::prelude::v1::*;

use std::fmt;
use std::mem;
use std::iter::FromIterator;

use futures_core::{Future, IntoFuture, Poll, Async};
use futures_core::task;

#[derive(Debug)]
enum ElemState<F> where F: Future {
    Pending(F),
    Done(F::Item),
}

/// A future which takes a list of futures and resolves with a vector of the
/// completed values.
///
/// This future is created with the `join_all` method.
#[must_use = "futures do nothing unless polled"]
pub struct JoinAll<F>
    where F: Future,
{
    elems: Vec<ElemState<F>>,
}

impl<F> fmt::Debug for JoinAll<F>
    where F: Future + fmt::Debug,
          F::Item: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("JoinAll")
            .field("elems", &self.elems)
            .finish()
    }
}

/// Creates a future which represents a collection of the results of the futures
/// given.
///
/// The returned future will drive execution for all of its underlying futures,
/// collecting the results into a destination `Vec<T>` in the same order as they
/// were provided. If any future returns an error then all other futures will be
/// canceled and an error will be returned immediately. If all futures complete
/// successfully, however, then the returned future will succeed with a `Vec` of
/// all the successful results.
///
/// # Examples
///
/// ```
/// # extern crate futures;
/// use futures::prelude::*;
/// use futures::future::{join_all, ok, err};
///
/// # fn main() {
/// #
/// let f = join_all(vec![
///     ok::<u32, u32>(1),
///     ok::<u32, u32>(2),
///     ok::<u32, u32>(3),
/// ]);
/// let f = f.map(|x| {
///     assert_eq!(x, [1, 2, 3]);
/// });
///
/// let f = join_all(vec![
///     Box::new(ok::<u32, u32>(1)),
///     Box::new(err::<u32, u32>(2)),
///     Box::new(ok::<u32, u32>(3)),
/// ]);
/// let f = f.then(|x| {
///     assert_eq!(x, Err(2));
///     x
/// });
/// # }
/// ```
pub fn join_all<I>(i: I) -> JoinAll<<I::Item as IntoFuture>::Future>
    where I: IntoIterator,
          I::Item: IntoFuture,
{
    let elems = i.into_iter().map(|f| {
        ElemState::Pending(f.into_future())
    }).collect();
    JoinAll { elems }
}

impl<F> Future for JoinAll<F>
    where F: Future,
{
    type Item = Vec<F::Item>;
    type Error = F::Error;

    fn poll(&mut self, cx: &mut task::Context) -> Poll<Self::Item, Self::Error> {
        let mut all_done = true;

        for idx in 0 .. self.elems.len() {
            let done_val = match self.elems[idx] {
                ElemState::Pending(ref mut t) => {
                    match t.poll(cx) {
                        Ok(Async::Ready(v)) => Ok(v),
                        Ok(Async::Pending) => {
                            all_done = false;
                            continue
                        }
                        Err(e) => Err(e),
                    }
                }
                ElemState::Done(ref mut _v) => continue,
            };

            match done_val {
                Ok(v) => self.elems[idx] = ElemState::Done(v),
                Err(e) => {
                    // On completion drop all our associated resources
                    // ASAP.
                    self.elems = Vec::new();
                    return Err(e)
                }
            }
        }

        if all_done {
            let elems = mem::replace(&mut self.elems, Vec::new());
            let result = elems.into_iter().map(|e| {
                match e {
                    ElemState::Done(t) => t,
                    _ => unreachable!(),
                }
            }).collect();
            Ok(Async::Ready(result))
        } else {
            Ok(Async::Pending)
        }
    }
}

impl<F: IntoFuture> FromIterator<F> for JoinAll<F::Future> {
    fn from_iter<T: IntoIterator<Item=F>>(iter: T) -> Self {
        join_all(iter)
    }
}

#[test]
fn join_all_from_iter() {
    let f_ok = |a| {
        let r: Result<i32, ()> = Ok(a);
        r.into_future()
    };

    pub fn assert_done<T, F>(_f: F, _result: Result<T::Item, T::Error>)
        where T: Future,
              T::Item: Eq + fmt::Debug,
              T::Error: Eq + fmt::Debug,
              F: FnOnce() -> T,
    {
        //FIXME: write a real test somehow somewhere
    }

    assert_done(|| vec![f_ok(1), f_ok(2)].into_iter().collect::<JoinAll<_>>(), Ok(vec![1, 2]))
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate rand;
extern crate time;
extern crate test;
extern crate getopts;
extern crate timely;
extern crate graph_map;
extern crate differential_dataflow;

use std::num;
use std::collections::HashMap;

use rand::{Rng, SeedableRng, StdRng};

use differential_dataflow::collection_trace::index::{Index, OrdIndex};

fn main() {
    for i in 25..28 {
        test_index(i);
    }
    // test_hash();
}

fn test_index(log_size: usize) {

    let mut index = OrdIndex::new();
    let mut hash = HashMap::new();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let mut tally = 0;

    let mut vec = vec![];
    let mut remaining = 1 << log_size;
    while remaining > 0 {
        for _ in 0.. (1 << (log_size - 2)) {
            vec.push(((rng.next_u64()),(rng.next_u64())));
        }
        vec.sort();
        remaining -= vec.len();
        let start = time::precise_time_ns();
        index.for_each(&mut vec, |k,v| { *v = *k });
        tally += time::precise_time_ns() - start;
        vec.clear();
    }

    println!("loaded index 2e{}:\t{:.2e} ns", log_size, tally as f64);

    let start = time::precise_time_ns();

    for i in 0..(1 << log_size) {
        hash.insert((i,i),(i,i));
    }

    println!("loaded hash 2e{}:\t{:.2e} ns", log_size, (time::precise_time_ns() - start) as f64);

    for query in 0..log_size {

        let mut index_tally = 0;
        let mut hash_tally = 0;

        for _ in 0..10 {
            for _ in 0..(1 << query) {
                vec.push(((rng.next_u64()),(rng.next_u64())));
            }
            vec.sort();
            let start = time::precise_time_ns();
            index.find_each(&mut vec, |k,v| { *v = *k });
            vec.clear();
            index_tally += time::precise_time_ns() - start;

            let start = time::precise_time_ns();
            for i in 0..(1 << query) {
                assert!(hash.get(&(i,i)).unwrap() == &(i,i));
            }
            hash_tally += time::precise_time_ns() - start;

        }

        println!("\t2e{}:\t{}\t{:2.3}x\t{} ns", query, (index_tally / 10) >> query, index_tally as f64 / hash_tally as f64, (index_tally as i64 - hash_tally as i64) / 10);
    }
}

fn _test_hash() {
    let start = time::precise_time_ns();
    // let mut index = OrdIndex::new();
    let mut hash = HashMap::new();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    for i in 0..10_000 {

        let mut key = (0u64, 0u64);

        for _ in 0..1_000 {

            key.0 += rng.gen_range(0, 1000);
            key.1 += rng.gen_range(0, 1000);
            // key.2 += rng.gen_range(0, 1000);

            hash.entry(key.clone()).or_insert(key.clone());
        }
    }

    println!("loaded in {}ns avg", (time::precise_time_ns() - start) / 10_000_000);
    let start = time::precise_time_ns();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let mut vec = vec![];
    for i in 0..100 {
        let mut key = (0u64, 0u64);
        for _ in 0..1000 {
            key.0 += rng.gen_range(0, 1000);
            key.1 += rng.gen_range(0, 1000);
            vec.push(key.clone());
        }
    }
    vec.sort();

    let start = time::precise_time_ns();
    for k in &vec { assert!(hash.get(k).unwrap() == k); }

    println!("read in {}ns avg", (time::precise_time_ns() - start) / 100_000);
}
<commit_msg>dataflog stuffs<commit_after>// #![feature(test)]

extern crate rand;
extern crate time;
extern crate test;
extern crate getopts;
extern crate timely;
extern crate graph_map;
extern crate differential_dataflow;

use std::num;
use std::collections::HashMap;

use rand::{Rng, SeedableRng, StdRng};

use differential_dataflow::collection_trace::index::{Index, OrdIndex};

fn main() {
    for i in 25..28 {
        test_index(i);
    }
    // test_hash();
}

fn test_index(log_size: usize) {

    let mut index = OrdIndex::new();
    let mut hash = HashMap::new();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let mut tally = 0;

    let mut vec = vec![];
    let mut remaining = 1 << log_size;
    while remaining > 0 {
        for _ in 0.. (1 << (log_size - 2)) {
            vec.push(((rng.next_u64()),(rng.next_u64())));
        }
        vec.sort();
        remaining -= vec.len();
        let start = time::precise_time_ns();
        index.for_each(&mut vec, |k,v| { *v = *k });
        tally += time::precise_time_ns() - start;
        vec.clear();
    }

    println!("loaded index 2e{}:\t{:.2e} ns", log_size, tally as f64);

    let start = time::precise_time_ns();

    for i in 0..(1 << log_size) {
        hash.insert((i,i),(i,i));
    }

    println!("loaded hash 2e{}:\t{:.2e} ns", log_size, (time::precise_time_ns() - start) as f64);

    for query in 0..log_size {

        let mut index_tally = 0;
        let mut hash_tally = 0;

        for _ in 0..10 {
            for _ in 0..(1 << query) {
                vec.push(((rng.next_u64()),(rng.next_u64())));
            }
            vec.sort();
            let start = time::precise_time_ns();
            index.find_each(&mut vec, |k,v| { *v = *k });
            vec.clear();
            index_tally += time::precise_time_ns() - start;

            let start = time::precise_time_ns();
            for i in 0..(1 << query) {
                assert!(hash.get(&(i,i)).unwrap() == &(i,i));
            }
            hash_tally += time::precise_time_ns() - start;

        }

        println!("\t2e{}:\t{}\t{:2.3}x\t{} ns", query, (index_tally / 10) >> query, index_tally as f64 / hash_tally as f64, (index_tally as i64 - hash_tally as i64) / 10);
    }
}

fn _test_hash() {
    let start = time::precise_time_ns();
    // let mut index = OrdIndex::new();
    let mut hash = HashMap::new();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    for i in 0..10_000 {

        let mut key = (0u64, 0u64);

        for _ in 0..1_000 {

            key.0 += rng.gen_range(0, 1000);
            key.1 += rng.gen_range(0, 1000);
            // key.2 += rng.gen_range(0, 1000);

            hash.entry(key.clone()).or_insert(key.clone());
        }
    }

    println!("loaded in {}ns avg", (time::precise_time_ns() - start) / 10_000_000);
    let start = time::precise_time_ns();

    let seed: &[_] = &[1, 2, 3, 4];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let mut vec = vec![];
    for i in 0..100 {
        let mut key = (0u64, 0u64);
        for _ in 0..1000 {
            key.0 += rng.gen_range(0, 1000);
            key.1 += rng.gen_range(0, 1000);
            vec.push(key.clone());
        }
    }
    vec.sort();

    let start = time::precise_time_ns();
    for k in &vec { assert!(hash.get(k).unwrap() == k); }

    println!("read in {}ns avg", (time::precise_time_ns() - start) / 100_000);
}
<|endoftext|>


<commit_before>//! A simple, thread-safe IRC server library.
<commit_msg>Document state of server module<commit_after>//! A simple, thread-safe IRC server library.
//! The server module is currently unimplimented. Visit
//! https://github.com/aatxe/irc/issues/22 to contribute!
<|endoftext|>


<commit_before>//! HTTP Server
//!
//! # Example
//!
//! ```no_run
//! use hyper::server::{Server, Request, Response};
//! use hyper::status::StatusCode;
//! use hyper::uri::RequestUri;
//!
//! let server = Server::http(|req: Request, mut res: Response| {
//!     *res.status_mut() = match (req.method, req.uri) {
//!         (hyper::Get, RequestUri::AbsolutePath(ref path)) if path == "/"  => {
//!             StatusCode::Ok
//!         },
//!         (hyper::Get, _) => StatusCode::NotFound,
//!         _ => StatusCode::MethodNotAllowed
//!     };
//!
//!     res.start().unwrap().end().unwrap();
//! }).listen("0.0.0.0:8080").unwrap();
use std::fmt;
use std::io::{ErrorKind, BufWriter, Write};
use std::marker::PhantomData;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::Path;
use std::thread::{self, JoinHandle};

use num_cpus;

pub use self::request::Request;
pub use self::response::Response;

pub use net::{Fresh, Streaming};

use HttpError::HttpIoError;
use {HttpResult};
use buffer::BufReader;
use header::{Headers, Connection, Expect};
use header::ConnectionOption::{Close, KeepAlive};
use method::Method;
use net::{NetworkListener, NetworkStream, HttpListener};
use status::StatusCode;
use uri::RequestUri;
use version::HttpVersion::{Http10, Http11};

use self::listener::ListenerPool;

pub mod request;
pub mod response;

mod listener;

/// A server can listen on a TCP socket.
///
/// Once listening, it will create a `Request`/`Response` pair for each
/// incoming connection, and hand them to the provided handler.
#[derive(Debug)]
pub struct Server<'a, H: Handler, L = HttpListener> {
    handler: H,
    ssl: Option<(&'a Path, &'a Path)>,
    _marker: PhantomData<L>
}

macro_rules! try_option(
    ($e:expr) => {{
        match $e {
            Some(v) => v,
            None => return None
        }
    }}
);

impl<'a, H: Handler, L: NetworkListener> Server<'a, H, L> {
    /// Creates a new server with the provided handler.
    pub fn new(handler: H) -> Server<'a, H, L> {
        Server {
            handler: handler,
            ssl: None,
            _marker: PhantomData
        }
    }
}

impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn http(handler: H) -> Server<'a, H, HttpListener> {
        Server::new(handler)
    }
    /// Creates a new server that will handler `HttpStreams`s using a TLS connection.
    pub fn https(handler: H, cert: &'a Path, key: &'a Path) -> Server<'a, H, HttpListener> {
        Server {
            handler: handler,
            ssl: Some((cert, key)),
            _marker: PhantomData
        }
    }
}

impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> {
    /// Binds to a socket, and starts handling connections using a task pool.
    pub fn listen_threads<T: ToSocketAddrs>(self, addr: T, threads: usize) -> HttpResult<Listening> {
        let listener = try!(match self.ssl {
            Some((cert, key)) => HttpListener::https(addr, cert, key),
            None => HttpListener::http(addr)
        });
        with_listener(self.handler, listener, threads)
    }

    /// Binds to a socket and starts handling connections.
    pub fn listen<T: ToSocketAddrs>(self, addr: T) -> HttpResult<Listening> {
        self.listen_threads(addr, num_cpus::get() * 5 / 4)
    }
}
impl<
'a,
H: Handler + 'static,
L: NetworkListener<Stream=S> + Send + 'static,
S: NetworkStream + Clone + Send> Server<'a, H, L> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn with_listener(self, listener: L, threads: usize) -> HttpResult<Listening> {
        with_listener(self.handler, listener, threads)
    }
}

fn with_listener<H, L>(handler: H, mut listener: L, threads: usize) -> HttpResult<Listening>
where H: Handler + 'static,
L: NetworkListener + Send + 'static {
    let socket = try!(listener.local_addr());

    debug!("threads = {:?}", threads);
    let pool = ListenerPool::new(listener.clone());
    let work = move |mut stream| handle_connection(&mut stream, &handler);

    let guard = thread::spawn(move || pool.accept(work, threads));

    Ok(Listening {
        _guard: Some(guard),
        socket: socket,
    })
}

fn handle_connection<'h, S, H>(mut stream: &mut S, handler: &'h H)
where S: NetworkStream + Clone, H: Handler {
    debug!("Incoming stream");
    let addr = match stream.peer_addr() {
        Ok(addr) => addr,
        Err(e) => {
            error!("Peer Name error: {:?}", e);
            return;
        }
    };

    // FIXME: Use Type ascription
    let stream_clone: &mut NetworkStream = &mut stream.clone();
    let mut rdr = BufReader::new(stream_clone);
    let mut wrt = BufWriter::new(stream);

    let mut keep_alive = true;
    while keep_alive {
        let req = match Request::new(&mut rdr, addr) {
            Ok(req) => req,
            Err(HttpIoError(ref e)) if e.kind() == ErrorKind::ConnectionAborted => {
                trace!("tcp closed, cancelling keep-alive loop");
                break;
            }
            Err(HttpIoError(e)) => {
                debug!("ioerror in keepalive loop = {:?}", e);
                break;
            }
            Err(e) => {
                //TODO: send a 400 response
                error!("request error = {:?}", e);
                break;
            }
        };

        if req.version == Http11 && req.headers.get() == Some(&Expect::Continue) {
            let status = handler.check_continue((&req.method, &req.uri, &req.headers));
            match write!(&mut wrt, "{} {}\r\n\r\n", Http11, status) {
                Ok(..) => (),
                Err(e) => {
                    error!("error writing 100-continue: {:?}", e);
                    break;
                }
            }

            if status != StatusCode::Continue {
                debug!("non-100 status ({}) for Expect 100 request", status);
                break;
            }
        }

        keep_alive = match (req.version, req.headers.get::<Connection>()) {
            (Http10, Some(conn)) if !conn.contains(&KeepAlive) => false,
            (Http11, Some(conn)) if conn.contains(&Close)  => false,
            _ => true
        };
        let mut res = Response::new(&mut wrt);
        res.version = req.version;
        handler.handle(req, res);
        debug!("keep_alive = {:?}", keep_alive);
    }
}

/// A listening server, which can later be closed.
pub struct Listening {
    _guard: Option<JoinHandle<()>>,
    /// The socket addresses that the server is bound to.
    pub socket: SocketAddr,
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Listening {{ socket: {:?} }}", self.socket)
    }
}

impl Drop for Listening {
    fn drop(&mut self) {
        let _ = self._guard.take().map(|g| g.join());
    }
}

impl Listening {
    /// Stop the server from listening to its socket address.
    pub fn close(&mut self) -> HttpResult<()> {
        let _ = self._guard.take();
        debug!("closing server");
        //try!(self.acceptor.close());
        Ok(())
    }
}

/// A handler that can handle incoming requests for a server.
pub trait Handler: Sync + Send {
    /// Receives a `Request`/`Response` pair, and should perform some action on them.
    ///
    /// This could reading from the request, and writing to the response.
    fn handle<'a, 'k>(&'a self, Request<'a, 'k>, Response<'a, Fresh>);

    /// Called when a Request includes a `Expect: 100-continue` header.
    ///
    /// By default, this will always immediately response with a `StatusCode::Continue`,
    /// but can be overridden with custom behavior.
    fn check_continue(&self, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl<F> Handler for F where F: Fn(Request, Response<Fresh>), F: Sync + Send {
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, res: Response<'a, Fresh>) {
        self(req, res)
    }
}

#[cfg(test)]
mod tests {
    use header::Headers;
    use method::Method;
    use mock::MockStream;
    use status::StatusCode;
    use uri::RequestUri;

    use super::{Request, Response, Fresh, Handler, handle_connection};

    #[test]
    fn test_check_continue_default() {
        let mut mock = MockStream::with_input(b"\
            POST /upload HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Expect: 100-continue\r\n\
            Content-Length: 10\r\n\
            \r\n\
            1234567890\
        ");

        fn handle(_: Request, res: Response<Fresh>) {
            res.start().unwrap().end().unwrap();
        }

        handle_connection(&mut mock, &handle);
        let cont = b"HTTP/1.1 100 Continue\r\n\r\n";
        assert_eq!(&mock.write[..cont.len()], cont);
        let res = b"HTTP/1.1 200 OK\r\n";
        assert_eq!(&mock.write[cont.len()..cont.len() + res.len()], res);
    }

    #[test]
    fn test_check_continue_reject() {
        struct Reject;
        impl Handler for Reject {
            fn handle<'a, 'k>(&'a self, _: Request<'a, 'k>, res: Response<'a, Fresh>) {
                res.start().unwrap().end().unwrap();
            }

            fn check_continue(&self, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
                StatusCode::ExpectationFailed
            }
        }

        let mut mock = MockStream::with_input(b"\
            POST /upload HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Expect: 100-continue\r\n\
            Content-Length: 10\r\n\
            \r\n\
            1234567890\
        ");

        handle_connection(&mut mock, &Reject);
        assert_eq!(mock.write, &b"HTTP/1.1 417 Expectation Failed\r\n\r\n"[..]);
    }
}
<commit_msg>feat(server): allow consumer to supply an SslContext<commit_after>//! HTTP Server
//!
//! # Example
//!
//! ```no_run
//! use hyper::server::{Server, Request, Response};
//! use hyper::status::StatusCode;
//! use hyper::uri::RequestUri;
//!
//! let server = Server::http(|req: Request, mut res: Response| {
//!     *res.status_mut() = match (req.method, req.uri) {
//!         (hyper::Get, RequestUri::AbsolutePath(ref path)) if path == "/"  => {
//!             StatusCode::Ok
//!         },
//!         (hyper::Get, _) => StatusCode::NotFound,
//!         _ => StatusCode::MethodNotAllowed
//!     };
//!
//!     res.start().unwrap().end().unwrap();
//! }).listen("0.0.0.0:8080").unwrap();
use std::fmt;
use std::io::{ErrorKind, BufWriter, Write};
use std::marker::PhantomData;
use std::net::{SocketAddr, ToSocketAddrs};
use std::path::Path;
use std::thread::{self, JoinHandle};

use num_cpus;
use openssl::ssl::SslContext;

pub use self::request::Request;
pub use self::response::Response;

pub use net::{Fresh, Streaming};

use HttpError::HttpIoError;
use {HttpResult};
use buffer::BufReader;
use header::{Headers, Connection, Expect};
use header::ConnectionOption::{Close, KeepAlive};
use method::Method;
use net::{NetworkListener, NetworkStream, HttpListener};
use status::StatusCode;
use uri::RequestUri;
use version::HttpVersion::{Http10, Http11};

use self::listener::ListenerPool;

pub mod request;
pub mod response;

mod listener;

#[derive(Debug)]
enum SslConfig<'a> {
    CertAndKey(&'a Path, &'a Path),
    Context(SslContext),
}

/// A server can listen on a TCP socket.
///
/// Once listening, it will create a `Request`/`Response` pair for each
/// incoming connection, and hand them to the provided handler.
#[derive(Debug)]
pub struct Server<'a, H: Handler, L = HttpListener> {
    handler: H,
    ssl: Option<SslConfig<'a>>,
    _marker: PhantomData<L>
}

macro_rules! try_option(
    ($e:expr) => {{
        match $e {
            Some(v) => v,
            None => return None
        }
    }}
);

impl<'a, H: Handler, L: NetworkListener> Server<'a, H, L> {
    /// Creates a new server with the provided handler.
    pub fn new(handler: H) -> Server<'a, H, L> {
        Server {
            handler: handler,
            ssl: None,
            _marker: PhantomData
        }
    }
}

impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn http(handler: H) -> Server<'a, H, HttpListener> {
        Server::new(handler)
    }
    /// Creates a new server that will handler `HttpStreams`s using a TLS connection.
    pub fn https(handler: H, cert: &'a Path, key: &'a Path) -> Server<'a, H, HttpListener> {
        Server {
            handler: handler,
            ssl: Some(SslConfig::CertAndKey(cert, key)),
            _marker: PhantomData
        }
    }
    /// Creates a new server that will handler `HttpStreams`s using a TLS connection defined by an SslContext.
    pub fn https_with_context(handler: H, ssl_context: SslContext) -> Server<'a, H, HttpListener> {
        Server {
            handler: handler,
            ssl: Some(SslConfig::Context(ssl_context)),
            _marker: PhantomData
        }
    }
}

impl<'a, H: Handler + 'static> Server<'a, H, HttpListener> {
    /// Binds to a socket, and starts handling connections using a task pool.
    pub fn listen_threads<T: ToSocketAddrs>(self, addr: T, threads: usize) -> HttpResult<Listening> {
        let listener = try!(match self.ssl {
            Some(SslConfig::CertAndKey(cert, key)) => HttpListener::https(addr, cert, key),
            Some(SslConfig::Context(ssl_context)) => HttpListener::https_with_context(addr, ssl_context),
            None => HttpListener::http(addr)
        });
        with_listener(self.handler, listener, threads)
    }

    /// Binds to a socket and starts handling connections.
    pub fn listen<T: ToSocketAddrs>(self, addr: T) -> HttpResult<Listening> {
        self.listen_threads(addr, num_cpus::get() * 5 / 4)
    }
}
impl<
'a,
H: Handler + 'static,
L: NetworkListener<Stream=S> + Send + 'static,
S: NetworkStream + Clone + Send> Server<'a, H, L> {
    /// Creates a new server that will handle `HttpStream`s.
    pub fn with_listener(self, listener: L, threads: usize) -> HttpResult<Listening> {
        with_listener(self.handler, listener, threads)
    }
}

fn with_listener<H, L>(handler: H, mut listener: L, threads: usize) -> HttpResult<Listening>
where H: Handler + 'static,
L: NetworkListener + Send + 'static {
    let socket = try!(listener.local_addr());

    debug!("threads = {:?}", threads);
    let pool = ListenerPool::new(listener.clone());
    let work = move |mut stream| handle_connection(&mut stream, &handler);

    let guard = thread::spawn(move || pool.accept(work, threads));

    Ok(Listening {
        _guard: Some(guard),
        socket: socket,
    })
}

fn handle_connection<'h, S, H>(mut stream: &mut S, handler: &'h H)
where S: NetworkStream + Clone, H: Handler {
    debug!("Incoming stream");
    let addr = match stream.peer_addr() {
        Ok(addr) => addr,
        Err(e) => {
            error!("Peer Name error: {:?}", e);
            return;
        }
    };

    // FIXME: Use Type ascription
    let stream_clone: &mut NetworkStream = &mut stream.clone();
    let mut rdr = BufReader::new(stream_clone);
    let mut wrt = BufWriter::new(stream);

    let mut keep_alive = true;
    while keep_alive {
        let req = match Request::new(&mut rdr, addr) {
            Ok(req) => req,
            Err(HttpIoError(ref e)) if e.kind() == ErrorKind::ConnectionAborted => {
                trace!("tcp closed, cancelling keep-alive loop");
                break;
            }
            Err(HttpIoError(e)) => {
                debug!("ioerror in keepalive loop = {:?}", e);
                break;
            }
            Err(e) => {
                //TODO: send a 400 response
                error!("request error = {:?}", e);
                break;
            }
        };

        if req.version == Http11 && req.headers.get() == Some(&Expect::Continue) {
            let status = handler.check_continue((&req.method, &req.uri, &req.headers));
            match write!(&mut wrt, "{} {}\r\n\r\n", Http11, status) {
                Ok(..) => (),
                Err(e) => {
                    error!("error writing 100-continue: {:?}", e);
                    break;
                }
            }

            if status != StatusCode::Continue {
                debug!("non-100 status ({}) for Expect 100 request", status);
                break;
            }
        }

        keep_alive = match (req.version, req.headers.get::<Connection>()) {
            (Http10, Some(conn)) if !conn.contains(&KeepAlive) => false,
            (Http11, Some(conn)) if conn.contains(&Close)  => false,
            _ => true
        };
        let mut res = Response::new(&mut wrt);
        res.version = req.version;
        handler.handle(req, res);
        debug!("keep_alive = {:?}", keep_alive);
    }
}

/// A listening server, which can later be closed.
pub struct Listening {
    _guard: Option<JoinHandle<()>>,
    /// The socket addresses that the server is bound to.
    pub socket: SocketAddr,
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Listening {{ socket: {:?} }}", self.socket)
    }
}

impl Drop for Listening {
    fn drop(&mut self) {
        let _ = self._guard.take().map(|g| g.join());
    }
}

impl Listening {
    /// Stop the server from listening to its socket address.
    pub fn close(&mut self) -> HttpResult<()> {
        let _ = self._guard.take();
        debug!("closing server");
        //try!(self.acceptor.close());
        Ok(())
    }
}

/// A handler that can handle incoming requests for a server.
pub trait Handler: Sync + Send {
    /// Receives a `Request`/`Response` pair, and should perform some action on them.
    ///
    /// This could reading from the request, and writing to the response.
    fn handle<'a, 'k>(&'a self, Request<'a, 'k>, Response<'a, Fresh>);

    /// Called when a Request includes a `Expect: 100-continue` header.
    ///
    /// By default, this will always immediately response with a `StatusCode::Continue`,
    /// but can be overridden with custom behavior.
    fn check_continue(&self, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
        StatusCode::Continue
    }
}

impl<F> Handler for F where F: Fn(Request, Response<Fresh>), F: Sync + Send {
    fn handle<'a, 'k>(&'a self, req: Request<'a, 'k>, res: Response<'a, Fresh>) {
        self(req, res)
    }
}

#[cfg(test)]
mod tests {
    use header::Headers;
    use method::Method;
    use mock::MockStream;
    use status::StatusCode;
    use uri::RequestUri;

    use super::{Request, Response, Fresh, Handler, handle_connection};

    #[test]
    fn test_check_continue_default() {
        let mut mock = MockStream::with_input(b"\
            POST /upload HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Expect: 100-continue\r\n\
            Content-Length: 10\r\n\
            \r\n\
            1234567890\
        ");

        fn handle(_: Request, res: Response<Fresh>) {
            res.start().unwrap().end().unwrap();
        }

        handle_connection(&mut mock, &handle);
        let cont = b"HTTP/1.1 100 Continue\r\n\r\n";
        assert_eq!(&mock.write[..cont.len()], cont);
        let res = b"HTTP/1.1 200 OK\r\n";
        assert_eq!(&mock.write[cont.len()..cont.len() + res.len()], res);
    }

    #[test]
    fn test_check_continue_reject() {
        struct Reject;
        impl Handler for Reject {
            fn handle<'a, 'k>(&'a self, _: Request<'a, 'k>, res: Response<'a, Fresh>) {
                res.start().unwrap().end().unwrap();
            }

            fn check_continue(&self, _: (&Method, &RequestUri, &Headers)) -> StatusCode {
                StatusCode::ExpectationFailed
            }
        }

        let mut mock = MockStream::with_input(b"\
            POST /upload HTTP/1.1\r\n\
            Host: example.domain\r\n\
            Expect: 100-continue\r\n\
            Content-Length: 10\r\n\
            \r\n\
            1234567890\
        ");

        handle_connection(&mut mock, &Reject);
        assert_eq!(mock.write, &b"HTTP/1.1 417 Expectation Failed\r\n\r\n"[..]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_attrs)]

#[rustc_mir]
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
    // Test passing a number of arguments including a fat pointer.
    // Also returning via an out pointer
    fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
        (a, b, c)
    }
    callee(a, b, c)
}

#[rustc_mir]
fn test2(a: isize) -> isize {
    // Test passing a single argument.
    // Not using out pointer.
    fn callee(a: isize) -> isize {
        a
    }
    callee(a)
}

struct Foo;
impl Foo {
    fn inherent_method(&self, a: isize) -> isize { a }
}

#[rustc_mir]
fn test3(x: &Foo, a: isize) -> isize {
    // Test calling inherent method
    x.inherent_method(a)
}

trait Bar {
    fn extension_method(&self, a: isize) -> isize { a }
}
impl Bar for Foo {}

#[rustc_mir]
fn test4(x: &Foo, a: isize) -> isize {
    // Test calling extension method
    x.extension_method(a)
}

#[rustc_mir]
fn test5(x: &Bar, a: isize) -> isize {
    // Test calling method on trait object
    x.extension_method(a)
}

// FIXME #30661: Although this function has the #[rustc_mir] attribute it never
//               was translated via the MIR implementation because attributes
//               where not passed along to trans::base::trans_fn() for generic
//               functions.
//               Uncomment this test once the thing it tests is fixed.
// #[rustc_mir]
// fn test6<T: Bar>(x: &T, a: isize) -> isize {
//     // Test calling extension method on generic callee
//     x.extension_method(a)
// }

trait One<T = Self> {
    fn one() -> T;
}
impl One for isize {
    fn one() -> isize { 1 }
}

#[rustc_mir]
fn test7() -> isize {
    // Test calling trait static method
    <isize as One>::one()
}

struct Two;
impl Two {
    fn two() -> isize { 2 }
}

#[rustc_mir]
fn test8() -> isize {
    // Test calling impl static method
    Two::two()
}

#[rustc_mir]
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
    where F: Fn(i32, i32) -> i32
{
    f(x, y)
}

#[rustc_mir]
fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    f(x, y)
}

#[rustc_mir]
fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    // This call goes through the Fn implementation for &Fn provided in
    // core::ops::impls. It expands to a static Fn::call() that calls the
    // Fn::call() implemenation of the object shim underneath.
    f(x, y)
}

fn main() {
    assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
    assert_eq!(test2(98), 98);
    assert_eq!(test3(&Foo, 42), 42);
    assert_eq!(test4(&Foo, 970), 970);
    assert_eq!(test5(&Foo, 8576), 8576);
    // see definition of test6() above
    // assert_eq!(test6(&Foo, 12367), 12367);
    assert_eq!(test7(), 1);
    assert_eq!(test8(), 2);

    let closure = |x: i32, y: i32| { x + y };
    assert_eq!(test_closure(&closure, 100, 1), 101);
    let function_object = &closure as &Fn(i32, i32) -> i32;
    assert_eq!(test_fn_object(function_object, 100, 2), 102);
    assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
}
<commit_msg>Rollup merge of #30747 - nagisa:mir-reenable-test, r=nikomatsakis<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(rustc_attrs)]

#[rustc_mir]
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
    // Test passing a number of arguments including a fat pointer.
    // Also returning via an out pointer
    fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
        (a, b, c)
    }
    callee(a, b, c)
}

#[rustc_mir]
fn test2(a: isize) -> isize {
    // Test passing a single argument.
    // Not using out pointer.
    fn callee(a: isize) -> isize {
        a
    }
    callee(a)
}

struct Foo;
impl Foo {
    fn inherent_method(&self, a: isize) -> isize { a }
}

#[rustc_mir]
fn test3(x: &Foo, a: isize) -> isize {
    // Test calling inherent method
    x.inherent_method(a)
}

trait Bar {
    fn extension_method(&self, a: isize) -> isize { a }
}
impl Bar for Foo {}

#[rustc_mir]
fn test4(x: &Foo, a: isize) -> isize {
    // Test calling extension method
    x.extension_method(a)
}

#[rustc_mir]
fn test5(x: &Bar, a: isize) -> isize {
    // Test calling method on trait object
    x.extension_method(a)
}

#[rustc_mir]
fn test6<T: Bar>(x: &T, a: isize) -> isize {
    // Test calling extension method on generic callee
    x.extension_method(a)
}

trait One<T = Self> {
    fn one() -> T;
}
impl One for isize {
    fn one() -> isize { 1 }
}

#[rustc_mir]
fn test7() -> isize {
    // Test calling trait static method
    <isize as One>::one()
}

struct Two;
impl Two {
    fn two() -> isize { 2 }
}

#[rustc_mir]
fn test8() -> isize {
    // Test calling impl static method
    Two::two()
}

#[rustc_mir]
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
    where F: Fn(i32, i32) -> i32
{
    f(x, y)
}

#[rustc_mir]
fn test_fn_object(f: &Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    f(x, y)
}

#[rustc_mir]
fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
    // This call goes through the Fn implementation for &Fn provided in
    // core::ops::impls. It expands to a static Fn::call() that calls the
    // Fn::call() implemenation of the object shim underneath.
    f(x, y)
}

fn main() {
    assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
    assert_eq!(test2(98), 98);
    assert_eq!(test3(&Foo, 42), 42);
    assert_eq!(test4(&Foo, 970), 970);
    assert_eq!(test5(&Foo, 8576), 8576);
    assert_eq!(test6(&Foo, 12367), 12367);
    assert_eq!(test7(), 1);
    assert_eq!(test8(), 2);

    let closure = |x: i32, y: i32| { x + y };
    assert_eq!(test_closure(&closure, 100, 1), 101);
    let function_object = &closure as &Fn(i32, i32) -> i32;
    assert_eq!(test_fn_object(function_object, 100, 2), 102);
    assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
}
<|endoftext|>


<commit_before><commit_msg>Update & clean pwasm-emscripten/src/lib.rs<commit_after><|endoftext|>


<commit_before>use super::*;

/// Public information about a peer
#[derive(Clone, Debug)]
pub struct Peer {
    peer_id: PeerId,
    ltvk: PublicKey,
    kepks: VecDeque<PublicKey>,
    history: RunHistory,
}

impl Peer {
    pub fn new(peer_id: PeerId, ltvk: PublicKey, num_peers: usize) -> Self {
        Peer {
            peer_id: peer_id,
            ltvk: ltvk,
            kepks: VecDeque::with_capacity(2),
            history: RunHistory::new(num_peers),
        }
    }

    pub fn push_kepk(&mut self, kepk: PublicKey) {
        self.kepks.push_back(kepk);
        assert!(self.kepks.len() <= 2);
    }

    pub fn get_kepk(&self) -> &PublicKey {
        self.kepks.get(0).unwrap()
    }

    pub fn shift_keys(&mut self) {
        self.kepks.pop_front().unwrap();
    }

    pub fn ltvk(&self) -> &PublicKey {
        &self.ltvk
    }
}
<commit_msg>Simplify handling of next kepk<commit_after>use super::*;

/// Public information about a peer
#[derive(Clone, Debug)]
pub struct Peer {
    peer_id: PeerId,
    ltvk: PublicKey,
    next_kepk: Option<PublicKey>,
    history: RunHistory,
}

impl Peer {
    pub fn new(peer_id: PeerId, ltvk: PublicKey, next_kepk: PublicKey, num_peers: usize) -> Self {
        Peer {
            peer_id: peer_id,
            ltvk: ltvk,
            next_kepk: Some(next_kepk),
            history: RunHistory::new(num_peers),
        }
    }

    pub fn push_kepk(&mut self, kepk: PublicKey) {
        assert!(self.next_kepk.is_none());
        self.next_kepk = Some(kepk);
    }

    pub fn pop_kepk(&mut self) -> PublicKey {
        let was = self.next_kepk.unwrap();
        self.next_kepk = None;
        was
    }

    pub fn ltvk(&self) -> &PublicKey {
        &self.ltvk
    }
}
<|endoftext|>