<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A reference to a package including it's name and the specific version.
pub struct PackageRef {
    pub name: String,
    pub version: String,
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,

    lock: Option<Lock>,
    metadata: Metadata,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub fn load(crate_dir: &Path,
                binding_crate_name: Option<&str>,
                use_cargo_lock: bool) -> Result<Cargo, String> {
        let toml_path = crate_dir.join("Cargo.toml");
        let lock_path = crate_dir.join("Cargo.lock");

        let lock = if use_cargo_lock {
            Some(cargo_lock::lock(&lock_path)
                            .map_err(|x| format!("couldn't load {:?}: {:?}", lock_path, x))?)
        } else {
            None
        };
        let metadata = cargo_metadata::metadata(&toml_path)
                                      .map_err(|_| format!("couldn't execute `cargo metadata` with manifest {:?}.", toml_path))?;

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
                                  .map_err(|_| format!("couldn't load {:?}.", toml_path))?;

        let binding_crate_name = binding_crate_name.map_or(manifest.package.name.clone(),
                                                           |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name: binding_crate_name,
            lock: lock,
            metadata: metadata,
        })
    }

    pub fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name == package_name {
                return Some(PackageRef {
                    name: package_name.to_owned(),
                    version: package.version.clone(),
                });
            }
        }
        None
    }

    /// Finds the package reference for a dependency of a crate using
    /// `Cargo.lock`.
    pub fn find_dep_ref(&self, package: &PackageRef, dependency_name: &str) -> Option<PackageRef> {
        if self.lock.is_none() {
            return None;
        }
        let lock = self.lock.as_ref().unwrap();

        if lock.root.name == package.name &&
           lock.root.version == package.version {
            if let Some(ref deps) = lock.root.dependencies {
                for dep in deps {
                    let (name, version) = parse_dep_string(dep);

                    if name == dependency_name {
                        return Some(PackageRef {
                            name: name.to_owned(),
                            version: version.to_owned(),
                        });
                    }
                }
            }
            return None;
        }

        if let &Some(ref lock_packages) = &lock.package {
            for lock_package in lock_packages {
                if lock_package.name == package.name &&
                   lock_package.version == package.version {
                    if let Some(ref deps) = lock_package.dependencies {
                        for dep in deps {
                            let (name, version) = parse_dep_string(dep);

                            if name == dependency_name {
                                return Some(PackageRef {
                                    name: name.to_owned(),
                                    version: version.to_owned(),
                                });
                            }
                        }
                    }
                    return None;
                }
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    pub fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                return Path::new(&meta_package.manifest_path).parent()
                                                             .map(|x| x.to_owned());
            }
        }
        None
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");

        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib) ||
                       target.kind.contains(&kind_staticlib) ||
                       target.kind.contains(&kind_rlib) ||
                       target.kind.contains(&kind_cdylib) {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                break;
            }
        }
        None
    }

    pub fn expand_crate(&self, package: &PackageRef) -> Result<String, String> {
        cargo_expand::expand(&self.manifest_path, &package.name, &package.version)
    }
}
<commit_msg>Look for -/_ replaced crates<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A reference to a package including it's name and the specific version.
pub struct PackageRef {
    pub name: String,
    pub version: String,
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,

    lock: Option<Lock>,
    metadata: Metadata,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub fn load(crate_dir: &Path,
                binding_crate_name: Option<&str>,
                use_cargo_lock: bool) -> Result<Cargo, String> {
        let toml_path = crate_dir.join("Cargo.toml");
        let lock_path = crate_dir.join("Cargo.lock");

        let lock = if use_cargo_lock {
            Some(cargo_lock::lock(&lock_path)
                            .map_err(|x| format!("couldn't load {:?}: {:?}", lock_path, x))?)
        } else {
            None
        };
        let metadata = cargo_metadata::metadata(&toml_path)
                                      .map_err(|_| format!("couldn't execute `cargo metadata` with manifest {:?}.", toml_path))?;

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
                                  .map_err(|_| format!("couldn't load {:?}.", toml_path))?;

        let binding_crate_name = binding_crate_name.map_or(manifest.package.name.clone(),
                                                           |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name: binding_crate_name,
            lock: lock,
            metadata: metadata,
        })
    }

    pub fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name == package_name {
                return Some(PackageRef {
                    name: package_name.to_owned(),
                    version: package.version.clone(),
                });
            }
        }
        None
    }

    /// Finds the package reference for a dependency of a crate using
    /// `Cargo.lock`.
    pub fn find_dep_ref(&self, package: &PackageRef, dependency_name: &str) -> Option<PackageRef> {
        if self.lock.is_none() {
            return None;
        }
        let lock = self.lock.as_ref().unwrap();

        // the name in Cargo.lock could use '-' instead of '_', so we need to
        // look for that too.
        let replaced_name = dependency_name.replace("_", "-");

        if lock.root.name == package.name && lock.root.version == package.version {
            if let Some(ref deps) = lock.root.dependencies {
                for dep in deps {
                    let (name, version) = parse_dep_string(dep);

                    if name == dependency_name || name == &replaced_name {
                        return Some(PackageRef {
                            name: name.to_owned(),
                            version: version.to_owned(),
                        });
                    }
                }
            }
            return None;
        }

        if let &Some(ref lock_packages) = &lock.package {
            for lock_package in lock_packages {
                if lock_package.name == package.name && lock_package.version == package.version {
                    if let Some(ref deps) = lock_package.dependencies {
                        for dep in deps {
                            let (name, version) = parse_dep_string(dep);

                            if name == dependency_name || name == &replaced_name {
                                return Some(PackageRef {
                                    name: name.to_owned(),
                                    version: version.to_owned(),
                                });
                            }
                        }
                    }
                    return None;
                }
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    pub fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                return Path::new(&meta_package.manifest_path).parent()
                                                             .map(|x| x.to_owned());
            }
        }
        None
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");

        for meta_package in &self.metadata.packages {
            if meta_package.name == package.name &&
               meta_package.version == package.version {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib) ||
                       target.kind.contains(&kind_staticlib) ||
                       target.kind.contains(&kind_rlib) ||
                       target.kind.contains(&kind_cdylib) {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                break;
            }
        }
        None
    }

    pub fn expand_crate(&self, package: &PackageRef) -> Result<String, String> {
        cargo_expand::expand(&self.manifest_path, &package.name, &package.version)
    }
}
<|endoftext|>


<commit_before>//! Support for nightly features in Cargo itself
//!
//! This file is the version of `feature_gate.rs` in upstream Rust for Cargo
//! itself and is intended to be the avenue for which new features in Cargo are
//! gated by default and then eventually stabilized. All known stable and
//! unstable features are tracked in this file.
//!
//! If you're reading this then you're likely interested in adding a feature to
//! Cargo, and the good news is that it shouldn't be too hard! To do this you'll
//! want to follow these steps:
//!
//! 1. Add your feature. Do this by searching for "look here" in this file and
//!    expanding the macro invocation that lists all features with your new
//!    feature.
//!
//! 2. Find the appropriate place to place the feature gate in Cargo itself. If
//!    you're extending the manifest format you'll likely just want to modify
//!    the `Manifest::feature_gate` function, but otherwise you may wish to
//!    place the feature gate elsewhere in Cargo.
//!
//! 3. Do actually perform the feature gate, you'll want to have code that looks
//!    like:
//!
//! ```rust,ignore
//! use core::{Feature, Features};
//!
//! let feature = Feature::launch_into_space();
//! package.manifest().features().require(feature).chain_err(|| {
//!     "launching Cargo into space right now is unstable and may result in \
//!      unintended damage to your codebase, use with caution"
//! })?;
//! ```
//!
//! Notably you'll notice the `require` funciton called with your `Feature`, and
//! then you use `chain_err` to tack on more context for why the feature was
//! required when the feature isn't activated.
//!
//! And hopefully that's it! Bear with us though that this is, at the time of
//! this writing, a very new feature in Cargo. If the process differs from this
//! we'll be sure to update this documentation!

use std::env;

use util::errors::CargoResult;

enum Status {
    Stable,
    Unstable,
}

macro_rules! features {
    (
        pub struct Features {
            $([$stab:ident] $feature:ident: bool,)*
        }
    ) => (
        #[derive(Default, Clone, Debug)]
        pub struct Features {
            $($feature: bool,)*
            activated: Vec<String>,
        }

        impl Feature {
            $(
                pub fn $feature() -> &'static Feature {
                    fn get(features: &Features) -> bool {
                        features.$feature
                    }
                    static FEAT: Feature = Feature {
                        name: stringify!($feature),
                        get: get,
                    };
                    &FEAT
                }
            )*

            fn is_enabled(&self, features: &Features) -> bool {
                (self.get)(features)
            }
        }

        impl Features {
            fn status(&mut self, feature: &str) -> Option<(&mut bool, Status)> {
                if feature.contains("_") {
                    return None
                }
                let feature = feature.replace("-", "_");
                $(
                    if feature == stringify!($feature) {
                        return Some((&mut self.$feature, stab!($stab)))
                    }
                )*
                None
            }
        }
    )
}

macro_rules! stab {
    (stable) => (Status::Stable);
    (unstable) => (Status::Unstable);
}

/// A listing of all features in Cargo
///
/// "look here"
///
/// This is the macro that lists all stable and unstable features in Cargo.
/// You'll want to add to this macro whenever you add a feature to Cargo, also
/// following the directions above.
///
/// Note that all feature names here are valid Rust identifiers, but the `_`
/// character is translated to `-` when specified in the `cargo-features`
/// manifest entry in `Cargo.toml`.
features! {
    pub struct Features {

        // A dummy feature that doesn't actually gate anything, but it's used in
        // testing to ensure that we can enable stable features.
        [stable] test_dummy_stable: bool,

        // A dummy feature that gates the usage of the `im-a-teapot` manifest
        // entry. This is basically just intended for tests.
        [unstable] test_dummy_unstable: bool,
    }
}

pub struct Feature {
    name: &'static str,
    get: fn(&Features) -> bool,
}

impl Features {
    pub fn new(features: &[String],
               warnings: &mut Vec<String>) -> CargoResult<Features> {
        let mut ret = Features::default();
        for feature in features {
            ret.add(feature, warnings)?;
            ret.activated.push(feature.to_string());
        }
        Ok(ret)
    }

    fn add(&mut self, feature: &str, warnings: &mut Vec<String>) -> CargoResult<()> {
        let (slot, status) = match self.status(feature) {
            Some(p) => p,
            None => bail!("unknown cargo feature `{}`", feature),
        };

        if *slot {
            bail!("the cargo feature `{}` has already bene activated", feature);
        }

        match status {
            Status::Stable => {
                let warning = format!("the cargo feature `{}` is now stable \
                                       and is no longer necessary to be listed \
                                       in the manifest", feature);
                warnings.push(warning);
            }
            Status::Unstable if !nightly_features_allowed() => {
                bail!("the cargo feature `{}` requires a nightly version of \
                       Cargo, but this is the `{}` channel",
                      feature,
                      channel())
            }
            Status::Unstable => {}
        }

        *slot = true;

        Ok(())
    }

    pub fn activated(&self) -> &[String] {
        &self.activated
    }

    pub fn require(&self, feature: &Feature) -> CargoResult<()> {
        if feature.is_enabled(self) {
            Ok(())
        } else {
            let feature = feature.name.replace("_", "-");
            let mut msg = format!("feature `{}` is required", feature);

            if nightly_features_allowed() {
                let s = format!("\n\nconsider adding `cargo-features = [\"{0}\"]` \
                                 to the manifest", feature);
                msg.push_str(&s);
            } else {
                let s = format!("\n\n\
                    this Cargo does not support nightly features, but if you\n\
                    switch to nightly channel you can add\n\
                    `cargo-features = [\"{}\"]` to enable this feature",
                    feature);
                msg.push_str(&s);
            }
            bail!("{}", msg);
        }
    }
}

/// A parsed represetnation of all unstable flags that Cargo accepts.
///
/// Cargo, like `rustc`, accepts a suite of `-Z` flags which are intended for
/// gating unstable functionality to Cargo. These flags are only available on
/// the nightly channel of Cargo.
///
/// This struct doesn't have quite the same convenience macro that the features
/// have above, but the procedure should still be relatively stable for adding a
/// new unstable flag:
///
/// 1. First, add a field to this `CliUnstable` structure. All flags are allowed
///    to have a value as the `-Z` flags are either of the form `-Z foo` or
///    `-Z foo=bar`, and it's up to you how to parse `bar`.
///
/// 2. Add an arm to the match statement in `CliUnstable::add` below to match on
///    your new flag. The key (`k`) is what you're matching on and the value is
///    in `v`.
///
/// 3. (optional) Add a new parsing function to parse your datatype. As of now
///    there's an example for `bool`, but more can be added!
///
/// 4. In Cargo use `config.cli_unstable()` to get a reference to this structure
///    and then test for your flag or your value and act accordingly.
///
/// If you have any trouble with this, please let us know!
#[derive(Default, Debug)]
pub struct CliUnstable {
    pub print_im_a_teapot: bool,
}

impl CliUnstable {
    pub fn parse(&mut self, flags: &[String]) -> CargoResult<()> {
        if !flags.is_empty() && !nightly_features_allowed() {
            bail!("the `-Z` flag is only accepted on the nightly channel of Cargo")
        }
        for flag in flags {
            self.add(flag)?;
        }
        Ok(())
    }

    fn add(&mut self, flag: &str) -> CargoResult<()> {
        let mut parts = flag.splitn(2, '=');
        let k = parts.next().unwrap();
        let v = parts.next();

        fn parse_bool(value: Option<&str>) -> CargoResult<bool> {
            match value {
                None |
                Some("yes") => Ok(true),
                Some("no") => Ok(false),
                Some(s) => bail!("expected `no` or `yes`, found: {}", s),
            }
        }

        match k {
            "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(v)?,
            _ => bail!("unknown `-Z` flag specified: {}", k),
        }

        Ok(())
    }
}

fn channel() -> String {
    env::var("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS").unwrap_or_else(|_| {
        ::version().cfg_info.map(|c| c.release_channel)
            .unwrap_or_else(|| String::from("dev"))
    })
}

fn nightly_features_allowed() -> bool {
    match &channel()[..] {
        "nightly" | "dev" => true,
        _ => false,
    }
}
<commit_msg>Fix some typos in docs and error messages<commit_after>//! Support for nightly features in Cargo itself
//!
//! This file is the version of `feature_gate.rs` in upstream Rust for Cargo
//! itself and is intended to be the avenue for which new features in Cargo are
//! gated by default and then eventually stabilized. All known stable and
//! unstable features are tracked in this file.
//!
//! If you're reading this then you're likely interested in adding a feature to
//! Cargo, and the good news is that it shouldn't be too hard! To do this you'll
//! want to follow these steps:
//!
//! 1. Add your feature. Do this by searching for "look here" in this file and
//!    expanding the macro invocation that lists all features with your new
//!    feature.
//!
//! 2. Find the appropriate place to place the feature gate in Cargo itself. If
//!    you're extending the manifest format you'll likely just want to modify
//!    the `Manifest::feature_gate` function, but otherwise you may wish to
//!    place the feature gate elsewhere in Cargo.
//!
//! 3. To actually perform the feature gate, you'll want to have code that looks
//!    like:
//!
//! ```rust,ignore
//! use core::{Feature, Features};
//!
//! let feature = Feature::launch_into_space();
//! package.manifest().features().require(feature).chain_err(|| {
//!     "launching Cargo into space right now is unstable and may result in \
//!      unintended damage to your codebase, use with caution"
//! })?;
//! ```
//!
//! Notably you'll notice the `require` funciton called with your `Feature`, and
//! then you use `chain_err` to tack on more context for why the feature was
//! required when the feature isn't activated.
//!
//! And hopefully that's it! Bear with us though that this is, at the time of
//! this writing, a very new feature in Cargo. If the process differs from this
//! we'll be sure to update this documentation!

use std::env;

use util::errors::CargoResult;

enum Status {
    Stable,
    Unstable,
}

macro_rules! features {
    (
        pub struct Features {
            $([$stab:ident] $feature:ident: bool,)*
        }
    ) => (
        #[derive(Default, Clone, Debug)]
        pub struct Features {
            $($feature: bool,)*
            activated: Vec<String>,
        }

        impl Feature {
            $(
                pub fn $feature() -> &'static Feature {
                    fn get(features: &Features) -> bool {
                        features.$feature
                    }
                    static FEAT: Feature = Feature {
                        name: stringify!($feature),
                        get: get,
                    };
                    &FEAT
                }
            )*

            fn is_enabled(&self, features: &Features) -> bool {
                (self.get)(features)
            }
        }

        impl Features {
            fn status(&mut self, feature: &str) -> Option<(&mut bool, Status)> {
                if feature.contains("_") {
                    return None
                }
                let feature = feature.replace("-", "_");
                $(
                    if feature == stringify!($feature) {
                        return Some((&mut self.$feature, stab!($stab)))
                    }
                )*
                None
            }
        }
    )
}

macro_rules! stab {
    (stable) => (Status::Stable);
    (unstable) => (Status::Unstable);
}

/// A listing of all features in Cargo
///
/// "look here"
///
/// This is the macro that lists all stable and unstable features in Cargo.
/// You'll want to add to this macro whenever you add a feature to Cargo, also
/// following the directions above.
///
/// Note that all feature names here are valid Rust identifiers, but the `_`
/// character is translated to `-` when specified in the `cargo-features`
/// manifest entry in `Cargo.toml`.
features! {
    pub struct Features {

        // A dummy feature that doesn't actually gate anything, but it's used in
        // testing to ensure that we can enable stable features.
        [stable] test_dummy_stable: bool,

        // A dummy feature that gates the usage of the `im-a-teapot` manifest
        // entry. This is basically just intended for tests.
        [unstable] test_dummy_unstable: bool,
    }
}

pub struct Feature {
    name: &'static str,
    get: fn(&Features) -> bool,
}

impl Features {
    pub fn new(features: &[String],
               warnings: &mut Vec<String>) -> CargoResult<Features> {
        let mut ret = Features::default();
        for feature in features {
            ret.add(feature, warnings)?;
            ret.activated.push(feature.to_string());
        }
        Ok(ret)
    }

    fn add(&mut self, feature: &str, warnings: &mut Vec<String>) -> CargoResult<()> {
        let (slot, status) = match self.status(feature) {
            Some(p) => p,
            None => bail!("unknown cargo feature `{}`", feature),
        };

        if *slot {
            bail!("the cargo feature `{}` has already been activated", feature);
        }

        match status {
            Status::Stable => {
                let warning = format!("the cargo feature `{}` is now stable \
                                       and is no longer necessary to be listed \
                                       in the manifest", feature);
                warnings.push(warning);
            }
            Status::Unstable if !nightly_features_allowed() => {
                bail!("the cargo feature `{}` requires a nightly version of \
                       Cargo, but this is the `{}` channel",
                      feature,
                      channel())
            }
            Status::Unstable => {}
        }

        *slot = true;

        Ok(())
    }

    pub fn activated(&self) -> &[String] {
        &self.activated
    }

    pub fn require(&self, feature: &Feature) -> CargoResult<()> {
        if feature.is_enabled(self) {
            Ok(())
        } else {
            let feature = feature.name.replace("_", "-");
            let mut msg = format!("feature `{}` is required", feature);

            if nightly_features_allowed() {
                let s = format!("\n\nconsider adding `cargo-features = [\"{0}\"]` \
                                 to the manifest", feature);
                msg.push_str(&s);
            } else {
                let s = format!("\n\n\
                    this Cargo does not support nightly features, but if you\n\
                    switch to nightly channel you can add\n\
                    `cargo-features = [\"{}\"]` to enable this feature",
                    feature);
                msg.push_str(&s);
            }
            bail!("{}", msg);
        }
    }
}

/// A parsed representation of all unstable flags that Cargo accepts.
///
/// Cargo, like `rustc`, accepts a suite of `-Z` flags which are intended for
/// gating unstable functionality to Cargo. These flags are only available on
/// the nightly channel of Cargo.
///
/// This struct doesn't have quite the same convenience macro that the features
/// have above, but the procedure should still be relatively stable for adding a
/// new unstable flag:
///
/// 1. First, add a field to this `CliUnstable` structure. All flags are allowed
///    to have a value as the `-Z` flags are either of the form `-Z foo` or
///    `-Z foo=bar`, and it's up to you how to parse `bar`.
///
/// 2. Add an arm to the match statement in `CliUnstable::add` below to match on
///    your new flag. The key (`k`) is what you're matching on and the value is
///    in `v`.
///
/// 3. (optional) Add a new parsing function to parse your datatype. As of now
///    there's an example for `bool`, but more can be added!
///
/// 4. In Cargo use `config.cli_unstable()` to get a reference to this structure
///    and then test for your flag or your value and act accordingly.
///
/// If you have any trouble with this, please let us know!
#[derive(Default, Debug)]
pub struct CliUnstable {
    pub print_im_a_teapot: bool,
}

impl CliUnstable {
    pub fn parse(&mut self, flags: &[String]) -> CargoResult<()> {
        if !flags.is_empty() && !nightly_features_allowed() {
            bail!("the `-Z` flag is only accepted on the nightly channel of Cargo")
        }
        for flag in flags {
            self.add(flag)?;
        }
        Ok(())
    }

    fn add(&mut self, flag: &str) -> CargoResult<()> {
        let mut parts = flag.splitn(2, '=');
        let k = parts.next().unwrap();
        let v = parts.next();

        fn parse_bool(value: Option<&str>) -> CargoResult<bool> {
            match value {
                None |
                Some("yes") => Ok(true),
                Some("no") => Ok(false),
                Some(s) => bail!("expected `no` or `yes`, found: {}", s),
            }
        }

        match k {
            "print-im-a-teapot" => self.print_im_a_teapot = parse_bool(v)?,
            _ => bail!("unknown `-Z` flag specified: {}", k),
        }

        Ok(())
    }
}

fn channel() -> String {
    env::var("__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS").unwrap_or_else(|_| {
        ::version().cfg_info.map(|c| c.release_channel)
            .unwrap_or_else(|| String::from("dev"))
    })
}

fn nightly_features_allowed() -> bool {
    match &channel()[..] {
        "nightly" | "dev" => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>use crate::core::{Shell, Workspace};
use crate::ops;
use crate::util::config::PathAndArgs;
use crate::util::CargoResult;
use serde::Deserialize;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

/// Strongly typed options for the `cargo doc` command.
#[derive(Debug)]
pub struct DocOptions {
    /// Whether to attempt to open the browser after compiling the docs
    pub open_result: bool,
    /// Options to pass through to the compiler
    pub compile_opts: ops::CompileOptions,
}

#[derive(Deserialize)]
struct CargoDocConfig {
    /// Browser to use to open docs. If this is unset, the value of the environment variable
    /// `BROWSER` will be used.
    browser: Option<PathAndArgs>,
}

/// Main method for `cargo doc`.
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
    let compilation = ops::compile(ws, &options.compile_opts)?;

    if options.open_result {
        let name = &compilation.root_crate_names[0];
        let kind = options.compile_opts.build_config.single_requested_kind()?;
        let path = compilation.root_output[&kind]
            .with_file_name("doc")
            .join(&name)
            .join("index.html");
        if path.exists() {
            let mut shell = ws.config().shell();
            shell.status("Opening", path.display())?;
            let cfg = ws.config().get::<CargoDocConfig>("doc")?;
            open_docs(
                &path,
                &mut shell,
                cfg.browser
                    .map(|path_args| (path_args.path.resolve_program(ws.config()), path_args.args)),
            )?;
        }
    }

    Ok(())
}

fn open_docs(
    path: &Path,
    shell: &mut Shell,
    config_browser: Option<(PathBuf, Vec<String>)>,
) -> CargoResult<()> {
    let browser =
        config_browser.or_else(|| Some((PathBuf::from(std::env::var_os("BROWSER")?), Vec::new())));

    match browser {
        Some((browser, initial_args)) => {
            if let Err(e) = Command::new(&browser).args(initial_args).arg(path).status() {
                shell.warn(format!(
                    "Couldn't open docs with {}: {}",
                    browser.to_string_lossy(),
                    e
                ))?;
            }
        }
        None => {
            if let Err(e) = opener::open(&path) {
                let e = e.into();
                crate::display_warning_with_error("couldn't open docs", &e, shell);
            }
        }
    };

    Ok(())
}
<commit_msg>Put cfg in a scope so it's not borrowed twice<commit_after>use crate::core::{Shell, Workspace};
use crate::ops;
use crate::util::config::PathAndArgs;
use crate::util::CargoResult;
use serde::Deserialize;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

/// Strongly typed options for the `cargo doc` command.
#[derive(Debug)]
pub struct DocOptions {
    /// Whether to attempt to open the browser after compiling the docs
    pub open_result: bool,
    /// Options to pass through to the compiler
    pub compile_opts: ops::CompileOptions,
}

#[derive(Deserialize)]
struct CargoDocConfig {
    /// Browser to use to open docs. If this is unset, the value of the environment variable
    /// `BROWSER` will be used.
    browser: Option<PathAndArgs>,
}

/// Main method for `cargo doc`.
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
    let compilation = ops::compile(ws, &options.compile_opts)?;

    if options.open_result {
        let name = &compilation.root_crate_names[0];
        let kind = options.compile_opts.build_config.single_requested_kind()?;
        let path = compilation.root_output[&kind]
            .with_file_name("doc")
            .join(&name)
            .join("index.html");
        if path.exists() {
            let config_browser = {
                let cfg = ws.config().get::<CargoDocConfig>("doc")?;

                cfg.browser
                    .map(|path_args| (path_args.path.resolve_program(ws.config()), path_args.args))
            };

            let mut shell = ws.config().shell();
            shell.status("Opening", path.display())?;
            open_docs(&path, &mut shell, config_browser)?;
        }
    }

    Ok(())
}

fn open_docs(
    path: &Path,
    shell: &mut Shell,
    config_browser: Option<(PathBuf, Vec<String>)>,
) -> CargoResult<()> {
    let browser =
        config_browser.or_else(|| Some((PathBuf::from(std::env::var_os("BROWSER")?), Vec::new())));

    match browser {
        Some((browser, initial_args)) => {
            if let Err(e) = Command::new(&browser).args(initial_args).arg(path).status() {
                shell.warn(format!(
                    "Couldn't open docs with {}: {}",
                    browser.to_string_lossy(),
                    e
                ))?;
            }
        }
        None => {
            if let Err(e) = opener::open(&path) {
                let e = e.into();
                crate::display_warning_with_error("couldn't open docs", &e, shell);
            }
        }
    };

    Ok(())
}
<|endoftext|>


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

fn get_aba_or_abba(s: &String, abba: bool) -> Vec<(char, char)>{
  let mut aba_vec = Vec::new();
  let mut char_vec = VecDeque::new();
  let len = if abba {4} else {3};

  for ch in s.chars() {
    char_vec.push_back(ch);

    // Only look at characters for the given pattern
    if char_vec.len() > len {
      char_vec.pop_front();
    }

    // if we have enough chars to look for a pattern, see if we've found the pattern
    if char_vec.len() == len {
      if char_vec[1] != char_vec[0]{
        if (abba && char_vec[0] == char_vec[3] && char_vec[1] == char_vec[2]) ||
           (!abba && char_vec[0] == char_vec[2]) {
          aba_vec.push((char_vec[0],char_vec[1]));
        }
      }
    }
  }

  return aba_vec;
}

fn main() {

  let mut f = File::open("day7.txt").unwrap();
  let mut f_s = String::new();
  f.read_to_string(&mut f_s).unwrap();

  let mut tls_count = 0; // part 1
  let mut ssl_count = 0; // part 2

  for l in f_s.lines() {
    let mut s: String = l.to_string();
    let mut supernet_bits = String::new();
    let mut hypernet_bits = String::new();

    while s.len() > 0 {
      let supernet_offset = s.find('[').unwrap_or(s.len());
      supernet_bits.extend(s.drain(..supernet_offset));

      let hypernet_offset = s.find(']').unwrap_or(s.len());
      hypernet_bits.extend(s.drain(..hypernet_offset));
    }

    if get_aba_or_abba(&supernet_bits, true).len() != 0 && get_aba_or_abba(&hypernet_bits, true).len() == 0{
      tls_count += 1;
    }

    let bab_list = get_aba_or_abba(&hypernet_bits, false);
    for aba in get_aba_or_abba(&supernet_bits, false) {
      if bab_list.contains(&(aba.1, aba.0)) {
        ssl_count += 1;
        break;
      }
    }
  }
  println!("TLS Supporting IPs: {:?}", tls_count);
  println!("SSL Supporting IPs: {:?}", ssl_count);
}
<commit_msg>Made Bill happier - got rid of extra string copies<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;

fn get_aba_or_abba(s: &String, abba: bool) -> Vec<(char, char)>{
  let mut aba_vec = Vec::new();
  let mut char_vec = VecDeque::new();
  let len = if abba {4} else {3};

  for ch in s.chars() {
    char_vec.push_back(ch);

    // Only look at characters for the given pattern
    if char_vec.len() > len {
      char_vec.pop_front();
    }

    // if we have enough chars to look for a pattern, see if we've found the pattern
    if char_vec.len() == len {
      if char_vec[1] != char_vec[0]{
        if (abba && char_vec[0] == char_vec[3] && char_vec[1] == char_vec[2]) ||
           (!abba && char_vec[0] == char_vec[2]) {
          aba_vec.push((char_vec[0],char_vec[1]));
        }
      }
    }
  }

  return aba_vec;
}

fn main() {

  let mut f = File::open("day7.txt").unwrap();
  let mut f_s = String::new();
  f.read_to_string(&mut f_s).unwrap();

  let mut tls_count = 0; // part 1
  let mut ssl_count = 0; // part 2

  for l in f_s.lines() {
    let mut s: String = l.to_string();
    let mut supernet_bits = String::new();
    let mut hypernet_bits = String::new();

    while s.len() > 0 {
      let supernet_offset = s.find('[').unwrap_or(s.len());
      supernet_bits.extend(s.drain(..supernet_offset));

      let hypernet_offset = s.find(']').unwrap_or(s.len());
      hypernet_bits.extend(s.drain(..hypernet_offset));
    }

    if get_aba_or_abba(&supernet_bits, true).len() != 0 &&
       get_aba_or_abba(&hypernet_bits, true).len() == 0 {
      tls_count += 1;
    }

    let bab_list = get_aba_or_abba(&hypernet_bits, false);
    for aba in get_aba_or_abba(&supernet_bits, false) {
      if bab_list.contains(&(aba.1, aba.0)) {
        ssl_count += 1;
        break;
      }
    }
  }
  println!("TLS Supporting IPs: {:?}", tls_count);
  println!("SSL Supporting IPs: {:?}", ssl_count);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements traversal over the DOM tree. The traversal starts in sequential
//! mode, and optionally parallelizes as it discovers work.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{SendNode, TElement, TNode};
use parallel;
use parallel::{DispatchMode, WORK_UNIT_MAX};
use rayon;
use scoped_tls::ScopedTLS;
use std::borrow::Borrow;
use std::collections::VecDeque;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// Do a DOM traversal for top-down and (optionally) bottom-up processing,
/// generic over `D`.
///
/// We use an adaptive traversal strategy. We start out with simple sequential
/// processing, until we arrive at a wide enough level in the DOM that the
/// parallel traversal would parallelize it. If a thread pool is provided, we
/// then transfer control over to the parallel traversal.
pub fn traverse_dom<E, D>(
    traversal: &D,
    root: E,
    token: PreTraverseToken,
    pool: Option<&rayon::ThreadPool>
)
where
    E: TElement,
    D: DomTraversal<E>,
{
    debug_assert!(token.should_traverse());

    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Declare the main-thread context, as well as the worker-thread contexts,
    // which we may or may not instantiate. It's important to declare the worker-
    // thread contexts first, so that they get dropped second. This matters because:
    //   * ThreadLocalContexts borrow AtomicRefCells in TLS.
    //   * Dropping a ThreadLocalContext can run SequentialTasks.
    //   * Sequential tasks may call into functions like
    //     Servo_StyleSet_GetBaseComputedValuesForElement, which instantiate a
    //     ThreadLocalStyleContext on the main thread. If the main thread
    //     ThreadLocalStyleContext has not released its TLS borrow by that point,
    //     we'll panic on double-borrow.
    let mut maybe_tls: Option<ScopedTLS<ThreadLocalStyleContext<E>>> = None;
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    let mut discovered =
        VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
    let mut depth = root.depth();
    let mut nodes_remaining_at_current_depth = 1;
    discovered.push_back(unsafe { SendNode::new(root.as_node()) });
    while let Some(node) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
            children_to_process += 1;
            discovered.push_back(unsafe { SendNode::new(n) });
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             *node, children_to_process);

        nodes_remaining_at_current_depth -= 1;
        if nodes_remaining_at_current_depth == 0 {
            depth += 1;
            // If there is enough work to parallelize over, and the caller allows
            // parallelism, switch to the parallel driver. We do this only when
            // moving to the next level in the dom so that we can pass the same
            // depth for all the children.
            if pool.is_some() && discovered.len() > WORK_UNIT_MAX {
                let pool = pool.unwrap();
                maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool));
                let root_opaque = root.as_node().opaque();
                let drain = discovered.drain(..);
                pool.install(|| {
                    rayon::scope(|scope| {
                        parallel::traverse_nodes(
                            drain,
                            DispatchMode::TailCall,
                            /* recursion_ok = */ true,
                            root_opaque,
                            PerLevelTraversalData { current_dom_depth: depth },
                            scope,
                            pool,
                            traversal,
                            maybe_tls.as_ref().unwrap()
                        );
                    });
                });
                break;
            }
            nodes_remaining_at_current_depth = discovered.len();
        }
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        let mut aggregate =
            mem::replace(&mut context.thread_local.statistics, Default::default());
        let parallel = maybe_tls.is_some();
        if let Some(tls) = maybe_tls {
            let slots = unsafe { tls.unsafe_get() };
            aggregate = slots.iter().fold(aggregate, |acc, t| {
                match *t.borrow() {
                    None => acc,
                    Some(ref cx) => &cx.borrow().statistics + &acc,
                }
            });
        }
        aggregate.finish(traversal, parallel, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}
<commit_msg>style: Avoid dropping the other threads' TLS contexts too early.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Implements traversal over the DOM tree. The traversal starts in sequential
//! mode, and optionally parallelizes as it discovers work.

#![deny(missing_docs)]

use context::{StyleContext, ThreadLocalStyleContext};
use dom::{SendNode, TElement, TNode};
use parallel;
use parallel::{DispatchMode, WORK_UNIT_MAX};
use rayon;
use scoped_tls::ScopedTLS;
use std::borrow::Borrow;
use std::collections::VecDeque;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};

/// Do a DOM traversal for top-down and (optionally) bottom-up processing,
/// generic over `D`.
///
/// We use an adaptive traversal strategy. We start out with simple sequential
/// processing, until we arrive at a wide enough level in the DOM that the
/// parallel traversal would parallelize it. If a thread pool is provided, we
/// then transfer control over to the parallel traversal.
pub fn traverse_dom<E, D>(
    traversal: &D,
    root: E,
    token: PreTraverseToken,
    pool: Option<&rayon::ThreadPool>
)
where
    E: TElement,
    D: DomTraversal<E>,
{
    debug_assert!(token.should_traverse());

    let dump_stats = traversal.shared_context().options.dump_style_statistics;
    let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };

    // Declare the main-thread context, as well as the worker-thread contexts,
    // which we may or may not instantiate. It's important to declare the worker-
    // thread contexts first, so that they get dropped second. This matters because:
    //   * ThreadLocalContexts borrow AtomicRefCells in TLS.
    //   * Dropping a ThreadLocalContext can run SequentialTasks.
    //   * Sequential tasks may call into functions like
    //     Servo_StyleSet_GetBaseComputedValuesForElement, which instantiate a
    //     ThreadLocalStyleContext on the main thread. If the main thread
    //     ThreadLocalStyleContext has not released its TLS borrow by that point,
    //     we'll panic on double-borrow.
    let mut maybe_tls: Option<ScopedTLS<ThreadLocalStyleContext<E>>> = None;
    let mut tlc = ThreadLocalStyleContext::new(traversal.shared_context());
    let mut context = StyleContext {
        shared: traversal.shared_context(),
        thread_local: &mut tlc,
    };

    // Process the nodes breadth-first, just like the parallel traversal does.
    // This helps keep similar traversal characteristics for the style sharing
    // cache.
    let mut discovered =
        VecDeque::<SendNode<E::ConcreteNode>>::with_capacity(WORK_UNIT_MAX * 2);
    let mut depth = root.depth();
    let mut nodes_remaining_at_current_depth = 1;
    discovered.push_back(unsafe { SendNode::new(root.as_node()) });
    while let Some(node) = discovered.pop_front() {
        let mut children_to_process = 0isize;
        let traversal_data = PerLevelTraversalData { current_dom_depth: depth };
        traversal.process_preorder(&traversal_data, &mut context, *node, |n| {
            children_to_process += 1;
            discovered.push_back(unsafe { SendNode::new(n) });
        });

        traversal.handle_postorder_traversal(&mut context, root.as_node().opaque(),
                                             *node, children_to_process);

        nodes_remaining_at_current_depth -= 1;
        if nodes_remaining_at_current_depth == 0 {
            depth += 1;
            // If there is enough work to parallelize over, and the caller allows
            // parallelism, switch to the parallel driver. We do this only when
            // moving to the next level in the dom so that we can pass the same
            // depth for all the children.
            if pool.is_some() && discovered.len() > WORK_UNIT_MAX {
                let pool = pool.unwrap();
                maybe_tls = Some(ScopedTLS::<ThreadLocalStyleContext<E>>::new(pool));
                let root_opaque = root.as_node().opaque();
                let drain = discovered.drain(..);
                pool.install(|| {
                    rayon::scope(|scope| {
                        parallel::traverse_nodes(
                            drain,
                            DispatchMode::TailCall,
                            /* recursion_ok = */ true,
                            root_opaque,
                            PerLevelTraversalData { current_dom_depth: depth },
                            scope,
                            pool,
                            traversal,
                            maybe_tls.as_ref().unwrap()
                        );
                    });
                });
                break;
            }
            nodes_remaining_at_current_depth = discovered.len();
        }
    }

    // Dump statistics to stdout if requested.
    if dump_stats {
        let mut aggregate =
            mem::replace(&mut context.thread_local.statistics, Default::default());
        let parallel = maybe_tls.is_some();
        if let Some(ref mut tls) = maybe_tls {
            let slots = unsafe { tls.unsafe_get() };
            aggregate = slots.iter().fold(aggregate, |acc, t| {
                match *t.borrow() {
                    None => acc,
                    Some(ref cx) => &cx.borrow().statistics + &acc,
                }
            });
        }
        aggregate.finish(traversal, parallel, start_time.unwrap());
        if aggregate.is_large_traversal() {
            println!("{}", aggregate);
        }
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

mod cmd;
pub mod install;
pub mod pre_commit;

pub mod codegen;
mod ast_src;

use anyhow::Context;
use std::{
    env, fs,
    io::Write,
    path::{Path, PathBuf},
    process::{Command, Stdio},
};

use crate::{cmd::run, codegen::Mode};

pub use anyhow::Result;

const TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(1)
    .unwrap()
    .to_path_buf()
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    ensure_rustfmt()?;

    if mode == Mode::Verify {
        run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
    } else {
        run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
    }
    Ok(())
}

fn reformat(text: impl std::fmt::Display) -> Result<String> {
    ensure_rustfmt()?;
    let mut rustfmt = Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
        .arg(project_root().join("rustfmt.toml"))
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    write!(rustfmt.stdin.take().unwrap(), "{}", text)?;
    let output = rustfmt.wait_with_output()?;
    let stdout = String::from_utf8(output.stdout)?;
    let preamble = "Generated file, do not edit by hand, see `crate/ra_tools/src/codegen`";
    Ok(format!("//! {}\n\n{}", preamble, stdout))
}

fn ensure_rustfmt() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => return Ok(()),
        _ => (),
    };
    run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_clippy() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_clippy().context("install clippy")?,
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::map_clone", // FIXME: remove when Iterator::copied stabilizes (1.36.0)
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run(
        &format!(
            "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
            TOOLCHAIN,
            allowed_lints.join(" -A ")
        ),
        ".",
    )?;
    Ok(())
}

fn install_clippy() -> Result<()> {
    run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_fuzzer() -> Result<()> {
    match Command::new("cargo")
        .args(&["fuzz", "--help"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => run("cargo install cargo-fuzz", ".")?,
    };

    run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
}

/// Cleans the `./target` dir after the build such that only
/// dependencies are cached on CI.
pub fn run_pre_cache() -> Result<()> {
    let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
    if !slow_tests_cookie.exists() {
        panic!("slow tests were skipped on CI!")
    }
    rm_rf(slow_tests_cookie)?;

    for entry in Path::new("./target/debug").read_dir()? {
        let entry = entry?;
        if entry.file_type().map(|it| it.is_file()).ok() == Some(true) {
            // Can't delete yourself on windows :-(
            if !entry.path().ends_with("xtask.exe") {
                rm_rf(&entry.path())?
            }
        }
    }

    fs::remove_file("./target/.rustc_info.json")?;
    let to_delete = ["ra_", "heavy_test"];
    for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
        for entry in Path::new(dir).read_dir()? {
            let entry = entry?;
            if to_delete.iter().any(|&it| entry.path().display().to_string().contains(it)) {
                rm_rf(&entry.path())?
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> Result<()> {
    if path.is_file() { fs::remove_file(path) } else { fs::remove_dir_all(path) }
        .with_context(|| format!("failed to remove {:?}", path))
}
<commit_msg>todo(codegen): added todo to change the reference to removed ra_tools crate<commit_after>//! FIXME: write short doc here

mod cmd;
pub mod install;
pub mod pre_commit;

pub mod codegen;
mod ast_src;

use anyhow::Context;
use std::{
    env, fs,
    io::Write,
    path::{Path, PathBuf},
    process::{Command, Stdio},
};

use crate::{cmd::run, codegen::Mode};

pub use anyhow::Result;

const TOOLCHAIN: &str = "stable";

pub fn project_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(1)
    .unwrap()
    .to_path_buf()
}

pub fn run_rustfmt(mode: Mode) -> Result<()> {
    ensure_rustfmt()?;

    if mode == Mode::Verify {
        run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
    } else {
        run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
    }
    Ok(())
}

fn reformat(text: impl std::fmt::Display) -> Result<String> {
    ensure_rustfmt()?;
    let mut rustfmt = Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
        .arg(project_root().join("rustfmt.toml"))
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    write!(rustfmt.stdin.take().unwrap(), "{}", text)?;
    let output = rustfmt.wait_with_output()?;
    let stdout = String::from_utf8(output.stdout)?;
    // TODO: update the preable: replace ra_tools with the relevant path
    let preamble = "Generated file, do not edit by hand, see `crate/ra_tools/src/codegen`";
    Ok(format!("//! {}\n\n{}", preamble, stdout))
}

fn ensure_rustfmt() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => return Ok(()),
        _ => (),
    };
    run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_clippy() -> Result<()> {
    match Command::new("rustup")
        .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => install_clippy().context("install clippy")?,
    };

    let allowed_lints = [
        "clippy::collapsible_if",
        "clippy::map_clone", // FIXME: remove when Iterator::copied stabilizes (1.36.0)
        "clippy::needless_pass_by_value",
        "clippy::nonminimal_bool",
        "clippy::redundant_pattern_matching",
    ];
    run(
        &format!(
            "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
            TOOLCHAIN,
            allowed_lints.join(" -A ")
        ),
        ".",
    )?;
    Ok(())
}

fn install_clippy() -> Result<()> {
    run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
    run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
}

pub fn run_fuzzer() -> Result<()> {
    match Command::new("cargo")
        .args(&["fuzz", "--help"])
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
    {
        Ok(status) if status.success() => (),
        _ => run("cargo install cargo-fuzz", ".")?,
    };

    run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
}

/// Cleans the `./target` dir after the build such that only
/// dependencies are cached on CI.
pub fn run_pre_cache() -> Result<()> {
    let slow_tests_cookie = Path::new("./target/.slow_tests_cookie");
    if !slow_tests_cookie.exists() {
        panic!("slow tests were skipped on CI!")
    }
    rm_rf(slow_tests_cookie)?;

    for entry in Path::new("./target/debug").read_dir()? {
        let entry = entry?;
        if entry.file_type().map(|it| it.is_file()).ok() == Some(true) {
            // Can't delete yourself on windows :-(
            if !entry.path().ends_with("xtask.exe") {
                rm_rf(&entry.path())?
            }
        }
    }

    fs::remove_file("./target/.rustc_info.json")?;
    let to_delete = ["ra_", "heavy_test"];
    for &dir in ["./target/debug/deps", "target/debug/.fingerprint"].iter() {
        for entry in Path::new(dir).read_dir()? {
            let entry = entry?;
            if to_delete.iter().any(|&it| entry.path().display().to_string().contains(it)) {
                rm_rf(&entry.path())?
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> Result<()> {
    if path.is_file() { fs::remove_file(path) } else { fs::remove_dir_all(path) }
        .with_context(|| format!("failed to remove {:?}", path))
}
<|endoftext|>


<commit_before>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::file::*;
use redox::io::*;
use redox::console::*;
use redox::env::*;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>,
}

impl Command {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();
        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>| {
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Some(arg) => {
                            if first {
                                first = false
                            } else {
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        }
                        None => (),
                    }
                }
                println!("{}", echo);
            },
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(arg) => {
                        File::exec(arg);
                    },
                    None => (),
                }
            },
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(arg) => {
                        let path = arg.clone();
                        println!("URL: {}", path);

                        let mut commands = String::new();
                        if let Some(mut file) = File::open(&path) {
                            file.read_to_string(&mut commands);
                        }

                        for command in commands.split('\n') {
                            exec!(command);
                        }
                    }
                    None => (),
                }
            },
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    for i in 2..args.len() {
                        if let Some(arg) = args.get(i) {
                            if i >= 3 {
                                string.push_str(" ");
                            }
                            string.push_str(arg);
                        }
                    }
                    string.push_str("\r\n\r\n");

                    match file.write(&string.as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget".to_string(),
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl Application {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &String) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if *command_string == "$" {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + "\n" + &variable.name + "=" + &variable.value;
            }
            println!("{}", variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if arg.len() > 0 {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Some(cmd) => {
                if cmd == "if" {
                    let mut value = false;

                    match args.get(1) {
                        Some(left) => match args.get(2) {
                            Some(cmp) => match args.get(3) {
                                Some(right) => {
                                    if cmp == "==" {
                                        value = *left == *right;
                                    } else if cmp == "!=" {
                                        value = *left != *right;
                                    } else if cmp == ">" {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    } else if cmp == ">=" {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    } else if cmp == "<" {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    } else if cmp == "<=" {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    } else {
                                        println!("Unknown comparison: {}", cmp);
                                    }
                                }
                                None => (),
                            },
                            None => (),
                        },
                        None => (),
                    }

                    self.modes.insert(0, Mode { value: value });
                    return;
                }

                if cmd == "else" {
                    let mut syntax_error = false;
                    match self.modes.get_mut(0) {
                        Some(mode) => mode.value = !mode.value,
                        None => syntax_error = true,
                    }
                    if syntax_error {
                        println!("Syntax error: else found with no previous if");
                    }
                    return;
                }

                if cmd == "fi" {
                    let mut syntax_error = false;
                    if self.modes.len() > 0 {
                        self.modes.remove(0);
                    } else {
                        syntax_error = true;
                    }
                    if syntax_error {
                        println!("Syntax error: fi found with no previous if");
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if !mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find('=') {
                    Some(i) => {
                        let name = cmd[0 .. i].to_string();
                        let mut value = cmd[i + 1 .. cmd.len()].to_string();

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Some(arg) => value = value + " " + &arg,
                                None => (),
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    None => break,
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        } else {
                            for variable in self.variables.iter_mut() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable {
                                name: name,
                                value: value,
                            });
                        }
                        return;
                    }
                    None => (),
                }

                //Commands
                for command in self.commands.iter() {
                    if command.name == *cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                println!("Unknown command: '{}'", cmd);

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + " " + &command.name;
                }
                println!("{}", help);
            }
            None => (),
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        console_title(&"Terminal".to_string());

        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        while let Some(command) = readln!() {
            println!("# {}", command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Unknown issue with terminal temporarily solved<commit_after>use redox::ops::DerefMut;
use redox::string::*;
use redox::vec::Vec;
use redox::boxed::Box;
use redox::fs::file::*;
use redox::io::*;
use redox::console::*;
use redox::env::*;
use redox::to_num::*;

/* Magic Macros { */
static mut application: *mut Application = 0 as *mut Application;

/// Execute a command
macro_rules! exec {
    ($cmd:expr) => ({
        unsafe {
            (*application).on_command(&$cmd.to_string());
        }
    })
}
/* } Magic Macros */

/// A command
pub struct Command {
    pub name: String,
    pub main: Box<Fn(&Vec<String>)>,
}

impl Command {
    /// Return the vector of the commands
    // TODO: Use a more efficient collection instead
    pub fn vec() -> Vec<Self> {
        let mut commands: Vec<Self> = Vec::new();
        commands.push(Command {
            name: "echo".to_string(),
            main: box |args: &Vec<String>| {
                let mut echo = String::new();
                let mut first = true;
                for i in 1..args.len() {
                    match args.get(i) {
                        Some(arg) => {
                            if first {
                                first = false
                            } else {
                                echo = echo + " ";
                            }
                            echo = echo + arg;
                        }
                        None => (),
                    }
                }
                println!("{}", echo);
            },
        });

        commands.push(Command {
            name: "open".to_string(),
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(arg) => {
                        File::exec(arg);
                    },
                    None => (),
                }
            },
        });

        commands.push(Command {
            name: "run".to_string(),
            main: box |args: &Vec<String>| {
                match args.get(1) {
                    Some(arg) => {
                        let path = arg.clone();
                        println!("URL: {}", path);

                        let mut commands = String::new();
                        if let Some(mut file) = File::open(&path) {
                            file.read_to_string(&mut commands);
                        }

                        for command in commands.split('\n') {
                            exec!(command);
                        }
                    }
                    None => (),
                }
            },
        });

        commands.push(Command {
            name: "send".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    for i in 2..args.len() {
                        if let Some(arg) = args.get(i) {
                            if i >= 3 {
                                string.push_str(" ");
                            }
                            string.push_str(arg);
                        }
                    }
                    string.push_str("\r\n\r\n");

                    match file.write(&string.as_bytes()) {
                        Some(size) => println!("Wrote {} bytes", size),
                        None => println!("Failed to write"),
                    }

                    string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "url".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut string = String::new();
                    match file.read_to_string(&mut string) {
                        Some(_) => println!("{}", string),
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "url_hex".to_string(),
            main: box |args: &Vec<String>| {
                let path;
                match args.get(1) {
                    Some(arg) => path = arg.clone(),
                    None => path = String::new(),
                }
                println!("URL: {}", path);

                if let Some(mut file) = File::open(&path) {
                    let mut vec: Vec<u8> = Vec::new();
                    match file.read_to_end(&mut vec) {
                        Some(_) => {
                            let mut line = "HEX:".to_string();
                            for byte in vec.iter() {
                                line = line + " " + &format!("{:X}", *byte);
                            }
                            println!("{}", line);
                        }
                        None => println!("Failed to read"),
                    }
                }
            },
        });

        commands.push(Command {
            name: "wget".to_string(),
            main: box |args: &Vec<String>| {
                if let Some(host) = args.get(1) {
                    if let Some(req) = args.get(2) {
                        if let Some(mut con) = File::open(&("tcp://".to_string() + host)) {
                            con.write(("GET ".to_string() + req + " HTTP/1.1").as_bytes());

                            let mut res = Vec::new();
                            con.read_to_end(&mut res);

                            if let Some(mut file) = File::open(&req) {
                                file.write(&res);
                            }
                        }
                    } else {
                        println!("No request given");
                    }
                } else {
                    println!("No url given");
                }
            },
        });

        commands
    }
}

/// A (env) variable
pub struct Variable {
    pub name: String,
    pub value: String,
}

pub struct Mode {
    value: bool,
}

/// An application
pub struct Application {
    commands: Vec<Command>,
    variables: Vec<Variable>,
    modes: Vec<Mode>,
}

impl Application {
    /// Create a new empty application
    pub fn new() -> Self {
        return Application {
            commands: Command::vec(),
            variables: Vec::new(),
            modes: Vec::new(),
        };
    }

    fn on_command(&mut self, command_string: &String) {
        //Comment
        if command_string.starts_with('#') {
            return;
        }

        //Show variables
        if *command_string == "$" {
            let mut variables = String::new();
            for variable in self.variables.iter() {
                variables = variables + "\n" + &variable.name + "=" + &variable.value;
            }
            println!("{}", variables);
            return;
        }

        //Explode into arguments, replace variables
        let mut args: Vec<String> = Vec::<String>::new();
        for arg in command_string.split(' ') {
            if arg.len() > 0 {
                if arg.starts_with('$') {
                    let name = arg[1 .. arg.len()].to_string();
                    for variable in self.variables.iter() {
                        if variable.name == name {
                            args.push(variable.value.clone());
                            break;
                        }
                    }
                } else {
                    args.push(arg.to_string());
                }
            }
        }

        //Execute commands
        match args.get(0) {
            Some(cmd) => {
                if cmd == "if" {
                    let mut value = false;

                    match args.get(1) {
                        Some(left) => match args.get(2) {
                            Some(cmp) => match args.get(3) {
                                Some(right) => {
                                    if cmp == "==" {
                                        value = *left == *right;
                                    } else if cmp == "!=" {
                                        value = *left != *right;
                                    } else if cmp == ">" {
                                        value = left.to_num_signed() > right.to_num_signed();
                                    } else if cmp == ">=" {
                                        value = left.to_num_signed() >= right.to_num_signed();
                                    } else if cmp == "<" {
                                        value = left.to_num_signed() < right.to_num_signed();
                                    } else if cmp == "<=" {
                                        value = left.to_num_signed() <= right.to_num_signed();
                                    } else {
                                        println!("Unknown comparison: {}", cmp);
                                    }
                                }
                                None => (),
                            },
                            None => (),
                        },
                        None => (),
                    }

                    self.modes.insert(0, Mode { value: value });
                    return;
                }

                if cmd == "else" {
                    let mut syntax_error = false;
                    match self.modes.get_mut(0) {
                        Some(mode) => mode.value = !mode.value,
                        None => syntax_error = true,
                    }
                    if syntax_error {
                        println!("Syntax error: else found with no previous if");
                    }
                    return;
                }

                if cmd == "fi" {
                    let mut syntax_error = false;
                    if self.modes.len() > 0 {
                        self.modes.remove(0);
                    } else {
                        syntax_error = true;
                    }
                    if syntax_error {
                        println!("Syntax error: fi found with no previous if");
                    }
                    return;
                }

                for mode in self.modes.iter() {
                    if !mode.value {
                        return;
                    }
                }

                //Set variables
                match cmd.find('=') {
                    Some(i) => {
                        let name = cmd[0 .. i].to_string();
                        let mut value = cmd[i + 1 .. cmd.len()].to_string();

                        if name.len() == 0 {
                            return;
                        }

                        for i in 1..args.len() {
                            match args.get(i) {
                                Some(arg) => value = value + " " + &arg,
                                None => (),
                            }
                        }

                        if value.len() == 0 {
                            let mut remove = -1;
                            for i in 0..self.variables.len() {
                                match self.variables.get(i) {
                                    Some(variable) => if variable.name == name {
                                        remove = i as isize;
                                        break;
                                    },
                                    None => break,
                                }
                            }

                            if remove >= 0 {
                                self.variables.remove(remove as usize);
                            }
                        } else {
                            for variable in self.variables.iter_mut() {
                                if variable.name == name {
                                    variable.value = value;
                                    return;
                                }
                            }

                            self.variables.push(Variable {
                                name: name,
                                value: value,
                            });
                        }
                        return;
                    }
                    None => (),
                }

                //Commands
                for command in self.commands.iter() {
                    write!(stdout(), "'{}' == '{}'", command.name, cmd);
                    if &command.name == cmd {
                        (*command.main)(&args);
                        return;
                    }
                }

                println!("Unknown command: '{}'", cmd);

                let mut help = "Commands:".to_string();
                for command in self.commands.iter() {
                    help = help + " " + &command.name;
                }
                println!("{}", help);
            }
            None => (),
        }
    }

    /// Run the application
    pub fn main(&mut self) {
        console_title(&"Terminal".to_string());

        println!("Type help for a command list");
        if let Some(arg) = args().get(1) {
            let command = "run ".to_string() + arg;
            println!("# {}", command);
            self.on_command(&command);
        }

        while let Some(command) = readln!() {
            println!("# {}", command);
            if command.len() > 0 {
                self.on_command(&command);
            }
        }
    }
}

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>