<commit_before>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::{output, t};
use ignore::WalkBuilder;
use std::path::Path;
use std::process::{Command, Stdio};

fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.arg(&path);
    let cmd_debug = format!("{:?}", cmd);
    let status = cmd.status().expect("executing rustfmt");
    if !status.success() {
        eprintln!(
            "Running `{}` failed.\nIf you're running `tidy`, \
            try again with `--bless`. Or, if you just want to format \
            code, run `./x.py fmt` instead.",
            cmd_debug,
        );
        std::process::exit(1);
    }
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    if build.config.dry_run {
        return;
    }
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let git_available = match Command::new("git")
        .arg("--version")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status()
    {
        Ok(status) => status.success(),
        Err(_) => false,
    };
    if git_available {
        let in_working_tree = match Command::new("git")
            .arg("rev-parse")
            .arg("--is-inside-work-tree")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .status()
        {
            Ok(status) => status.success(),
            Err(_) => false,
        };
        if in_working_tree {
            let untracked_paths_output = output(
                Command::new("git")
                    .arg("status")
                    .arg("--porcelain")
                    .arg("--untracked-files=normal"),
            );
            let untracked_paths = untracked_paths_output
                .lines()
                .filter(|entry| entry.starts_with("??"))
                .map(|entry| {
                    entry.split(' ').nth(1).expect("every git status entry should list a path")
                });
            for untracked_path in untracked_paths {
                eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
                ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
            }
        } else {
            eprintln!("Not in git tree. Skipping git-aware format checks");
        }
    } else {
        eprintln!("Could not find usable git. Skipping git-aware format checks");
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
        eprintln!("./x.py fmt is not supported on this channel");
        std::process::exit(1);
    });
    let src = &build.src;
    let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel();
    walker.run(|| {
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                rustfmt(src, &rustfmt_path, &entry.path(), check);
            }
            ignore::WalkState::Continue
        })
    });
}
<commit_msg>Rollup merge of #81833 - the8472:parallel-bootstrap-rustfmt, r=Mark-Simulacrum<commit_after>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::{output, t};
use ignore::WalkBuilder;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::sync::mpsc::SyncSender;

fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut() {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.args(paths);
    let cmd_debug = format!("{:?}", cmd);
    let mut cmd = cmd.spawn().expect("running rustfmt");
    // poor man's async: return a closure that'll wait for rustfmt's completion
    move || {
        let status = cmd.wait().unwrap();
        if !status.success() {
            eprintln!(
                "Running `{}` failed.\nIf you're running `tidy`, \
                        try again with `--bless`. Or, if you just want to format \
                        code, run `./x.py fmt` instead.",
                cmd_debug,
            );
            std::process::exit(1);
        }
    }
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    if build.config.dry_run {
        return;
    }
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let git_available = match Command::new("git")
        .arg("--version")
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status()
    {
        Ok(status) => status.success(),
        Err(_) => false,
    };
    if git_available {
        let in_working_tree = match Command::new("git")
            .arg("rev-parse")
            .arg("--is-inside-work-tree")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .status()
        {
            Ok(status) => status.success(),
            Err(_) => false,
        };
        if in_working_tree {
            let untracked_paths_output = output(
                Command::new("git")
                    .arg("status")
                    .arg("--porcelain")
                    .arg("--untracked-files=normal"),
            );
            let untracked_paths = untracked_paths_output
                .lines()
                .filter(|entry| entry.starts_with("??"))
                .map(|entry| {
                    entry.split(' ').nth(1).expect("every git status entry should list a path")
                });
            for untracked_path in untracked_paths {
                eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
                ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
            }
        } else {
            eprintln!("Not in git tree. Skipping git-aware format checks");
        }
    } else {
        eprintln!("Could not find usable git. Skipping git-aware format checks");
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build
        .config
        .initial_rustfmt
        .as_ref()
        .unwrap_or_else(|| {
            eprintln!("./x.py fmt is not supported on this channel");
            std::process::exit(1);
        })
        .to_path_buf();
    let src = build.src.clone();
    let (tx, rx): (SyncSender<PathBuf>, _) = std::sync::mpsc::sync_channel(128);
    let walker =
        WalkBuilder::new(src.clone()).types(matcher).overrides(ignore_fmt).build_parallel();

    // there is a lot of blocking involved in spawning a child process and reading files to format.
    // spawn more processes than available concurrency to keep the CPU busy
    let max_processes = build.jobs() as usize * 2;

    // spawn child processes on a separate thread so we can batch entries we have received from ignore
    let thread = std::thread::spawn(move || {
        let mut children = VecDeque::new();
        while let Ok(path) = rx.recv() {
            // try getting a few more paths from the channel to amortize the overhead of spawning processes
            let paths: Vec<_> = rx.try_iter().take(7).chain(std::iter::once(path)).collect();

            let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check);
            children.push_back(child);

            if children.len() >= max_processes {
                // await oldest child
                children.pop_front().unwrap()();
            }
        }

        // await remaining children
        for mut child in children {
            child();
        }
    });

    walker.run(|| {
        let tx = tx.clone();
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                t!(tx.send(entry.into_path()));
            }
            ignore::WalkState::Continue
        })
    });

    drop(tx);

    thread.join().unwrap();
}
<|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.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") ||
           target.contains("emscripten") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<commit_msg>adding a check to sanity to look for the nodejs command<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.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // If a manual nodejs was added to the config,
    // of if a nodejs install is detected through bootstrap.py, use it.
    if build.config.nodejs.is_some() {
        need_cmd("nodejs".as_ref())
    }

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") ||
           target.contains("emscripten") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<|endoftext|>


<commit_before>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build
        .hosts
        .iter()
        .map(|host| {
            build
                .config
                .target_config
                .get(host)
                .map(|config| config.llvm_config.is_none())
                .unwrap_or(true)
        })
        .any(|build_llvm_ourselves| build_llvm_ourselves);
    if building_llvm || build.config.any_sanitizers_enabled() {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        build
            .config
            .target_config
            .entry(target.clone())
            .or_insert(Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone()).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<commit_msg>Don't require cmake and ninja when the LLVM backend is not used<commit_after>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::cache::INTERNER;
use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
        && build
            .hosts
            .iter()
            .map(|host| {
                build
                    .config
                    .target_config
                    .get(host)
                    .map(|config| config.llvm_config.is_none())
                    .unwrap_or(true)
            })
            .any(|build_llvm_ourselves| build_llvm_ourselves);
    if building_llvm || build.config.any_sanitizers_enabled() {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
        // Externally configured LLVM requires FileCheck to exist
        let filecheck = build.llvm_filecheck(build.build);
        if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
            panic!("FileCheck executable {:?} does not exist", filecheck);
        }
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        build
            .config
            .target_config
            .entry(target.clone())
            .or_insert(Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone()).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

//! Integer and floating-point number formatting

// FIXME: #6220 Implement floating point formatting

#![allow(unsigned_negate)]

use collections::Collection;
use fmt;
use iter::DoubleEndedIterator;
use num::{Int, cast, zero};
use slice::{ImmutableVector, MutableVector};

#[cfg(stage0)]
use iter::Iterator;         // NOTE(stage0): Remove after snapshot.
#[cfg(stage0)]
use option::{Some, None};   // NOTE(stage0): Remove after snapshot.

/// A type that represents a specific radix
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str { "" }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 64
        // characters for a base 2 number.
        let mut buf = [0u8, ..64];
        let base = cast(self.base()).unwrap();
        let mut curr = buf.len();
        let is_positive = x >= zero();
        if is_positive {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.mut_iter().rev() {
                let n = x % base;                         // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero() { break; }                 // No more digits left to accumulate.
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.mut_iter().rev() {
                let n = -(x % base);                      // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero() { break; }                 // No more digits left to accumulate.
            }
        }
        f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr))
    }
}

/// A binary (base 2) radix
#[deriving(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[deriving(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[deriving(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[deriving(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[deriving(Clone, PartialEq)]
pub struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix!(Binary,    2, "0b", x @  0 .. 2 => '0' as u8 + x)
radix!(Octal,     8, "0o", x @  0 .. 7 => '0' as u8 + x)
radix!(Decimal,  10, "",   x @  0 .. 9 => '0' as u8 + x)
radix!(LowerHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
                           x @ 10 ..15 => 'a' as u8 + (x - 10))
radix!(UpperHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
                           x @ 10 ..15 => 'A' as u8 + (x - 10))

/// A radix with in the range of `2..36`.
#[deriving(Clone, PartialEq)]
pub struct Radix {
    base: u8,
}

impl Radix {
    fn new(base: u8) -> Radix {
        assert!(2 <= base && base <= 36, "the base must be in the range of 0..36: {}", base);
        Radix { base: base }
    }
}

impl GenericRadix for Radix {
    fn base(&self) -> u8 { self.base }
    fn digit(&self, x: u8) -> u8 {
        match x {
            x @  0 ..9 => '0' as u8 + x,
            x if x < self.base() => 'a' as u8 + (x - 10),
            x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
        }
    }
}

/// A helper type for formatting radixes.
pub struct RadixFmt<T, R>(T, R);

/// Constructs a radix formatter in the range of `2..36`.
///
/// # Example
///
/// ~~~
/// use std::fmt::radix;
/// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string());
/// ~~~
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
    RadixFmt(x, Radix::new(base))
}

macro_rules! radix_fmt {
    ($T:ty as $U:ty, $fmt:ident) => {
        impl fmt::Show for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
            }
        }
    }
}
macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}
macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        int_base!(Show     for $Int as $Int   -> Decimal)
        int_base!(Signed   for $Int as $Int   -> Decimal)
        int_base!(Binary   for $Int as $Uint  -> Binary)
        int_base!(Octal    for $Int as $Uint  -> Octal)
        int_base!(LowerHex for $Int as $Uint  -> LowerHex)
        int_base!(UpperHex for $Int as $Uint  -> UpperHex)
        radix_fmt!($Int as $Int, fmt_int)

        int_base!(Show     for $Uint as $Uint -> Decimal)
        int_base!(Unsigned for $Uint as $Uint -> Decimal)
        int_base!(Binary   for $Uint as $Uint -> Binary)
        int_base!(Octal    for $Uint as $Uint -> Octal)
        int_base!(LowerHex for $Uint as $Uint -> LowerHex)
        int_base!(UpperHex for $Uint as $Uint -> UpperHex)
        radix_fmt!($Uint as $Uint, fmt_int)
    }
}
integer!(int, uint)
integer!(i8, u8)
integer!(i16, u16)
integer!(i32, u32)
integer!(i64, u64)
<commit_msg>auto merge of #15979 : Randati/rust/patch-2, r=kballard<commit_after>// Copyright 2014 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.

//! Integer and floating-point number formatting

// FIXME: #6220 Implement floating point formatting

#![allow(unsigned_negate)]

use collections::Collection;
use fmt;
use iter::DoubleEndedIterator;
use num::{Int, cast, zero};
use slice::{ImmutableVector, MutableVector};

#[cfg(stage0)]
use iter::Iterator;         // NOTE(stage0): Remove after snapshot.
#[cfg(stage0)]
use option::{Some, None};   // NOTE(stage0): Remove after snapshot.

/// A type that represents a specific radix
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str { "" }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 64
        // characters for a base 2 number.
        let mut buf = [0u8, ..64];
        let base = cast(self.base()).unwrap();
        let mut curr = buf.len();
        let is_positive = x >= zero();
        if is_positive {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.mut_iter().rev() {
                let n = x % base;                         // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero() { break; }                 // No more digits left to accumulate.
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.mut_iter().rev() {
                let n = -(x % base);                      // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero() { break; }                 // No more digits left to accumulate.
            }
        }
        f.pad_integral(is_positive, self.prefix(), buf.slice_from(curr))
    }
}

/// A binary (base 2) radix
#[deriving(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[deriving(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[deriving(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[deriving(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[deriving(Clone, PartialEq)]
pub struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix!(Binary,    2, "0b", x @  0 .. 2 => '0' as u8 + x)
radix!(Octal,     8, "0o", x @  0 .. 7 => '0' as u8 + x)
radix!(Decimal,  10, "",   x @  0 .. 9 => '0' as u8 + x)
radix!(LowerHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
                           x @ 10 ..15 => 'a' as u8 + (x - 10))
radix!(UpperHex, 16, "0x", x @  0 .. 9 => '0' as u8 + x,
                           x @ 10 ..15 => 'A' as u8 + (x - 10))

/// A radix with in the range of `2..36`.
#[deriving(Clone, PartialEq)]
pub struct Radix {
    base: u8,
}

impl Radix {
    fn new(base: u8) -> Radix {
        assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base);
        Radix { base: base }
    }
}

impl GenericRadix for Radix {
    fn base(&self) -> u8 { self.base }
    fn digit(&self, x: u8) -> u8 {
        match x {
            x @  0 ..9 => '0' as u8 + x,
            x if x < self.base() => 'a' as u8 + (x - 10),
            x => fail!("number not in the range 0..{}: {}", self.base() - 1, x),
        }
    }
}

/// A helper type for formatting radixes.
pub struct RadixFmt<T, R>(T, R);

/// Constructs a radix formatter in the range of `2..36`.
///
/// # Example
///
/// ~~~
/// use std::fmt::radix;
/// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string());
/// ~~~
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
    RadixFmt(x, Radix::new(base))
}

macro_rules! radix_fmt {
    ($T:ty as $U:ty, $fmt:ident) => {
        impl fmt::Show for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
            }
        }
    }
}
macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}
macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        int_base!(Show     for $Int as $Int   -> Decimal)
        int_base!(Signed   for $Int as $Int   -> Decimal)
        int_base!(Binary   for $Int as $Uint  -> Binary)
        int_base!(Octal    for $Int as $Uint  -> Octal)
        int_base!(LowerHex for $Int as $Uint  -> LowerHex)
        int_base!(UpperHex for $Int as $Uint  -> UpperHex)
        radix_fmt!($Int as $Int, fmt_int)

        int_base!(Show     for $Uint as $Uint -> Decimal)
        int_base!(Unsigned for $Uint as $Uint -> Decimal)
        int_base!(Binary   for $Uint as $Uint -> Binary)
        int_base!(Octal    for $Uint as $Uint -> Octal)
        int_base!(LowerHex for $Uint as $Uint -> LowerHex)
        int_base!(UpperHex for $Uint as $Uint -> UpperHex)
        radix_fmt!($Uint as $Uint, fmt_int)
    }
}
integer!(int, uint)
integer!(i8, u8)
integer!(i16, u16)
integer!(i32, u32)
integer!(i64, u64)
<|endoftext|>


<commit_before>// Copyright 2012 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.

use marker::Unsize;

/// Trait that indicates that this is a pointer or a wrapper for one,
/// where unsizing can be performed on the pointee.
///
/// See the [DST coercion RfC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce]
/// for more details.
///
/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize<U>`
/// by converting from a thin pointer to a fat pointer.
///
/// For custom types, the coercion here works by coercing `Foo<T>` to `Foo<U>`
/// provided an impl of `CoerceUnsized<Foo<U>> for Foo<T>` exists.
/// Such an impl can only be written if `Foo<T>` has only a single non-phantomdata
/// field involving `T`. If the type of that field is `Bar<T>`, an implementation
/// of `CoerceUnsized<Bar<U>> for Bar<T>` must exist. The coercion will work by
/// coercing the `Bar<T>` field into `Bar<U>` and filling in the rest of the fields
/// from `Foo<T>` to create a `Foo<U>`. This will effectively drill down to a pointer
/// field and coerce that.
///
/// Generally, for smart pointers you will implement
/// `CoerceUnsized<Ptr<U>> for Ptr<T> where T: Unsize<U>, U: ?Sized`, with an
/// optional `?Sized` bound on `T` itself. For wrapper types that directly embed `T`
/// like `Cell<T>` and `RefCell<T>`, you
/// can directly implement `CoerceUnsized<Wrap<U>> for Wrap<T> where T: CoerceUnsized<U>`.
/// This will let coercions of types like `Cell<Box<T>>` work.
///
/// [`Unsize`][unsize] is used to mark types which can be coerced to DSTs if behind
/// pointers. It is implemented automatically by the compiler.
///
/// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
/// [unsize]: ../marker/trait.Unsize.html
/// [nomicon-coerce]: ../../nomicon/coercions.html
#[unstable(feature = "coerce_unsized", issue = "27732")]
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {
    // Empty.
}

// &mut T -> &mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
// &mut T -> &U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
// &mut T -> *mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
// &mut T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}

// &T -> &U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
// &T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}

// *mut T -> *mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
// *mut T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}

// *const T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
<commit_msg>Rollup merge of #52905 - pravic:unsize-typo, r=alexcrichton<commit_after>// Copyright 2012 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.

use marker::Unsize;

/// Trait that indicates that this is a pointer or a wrapper for one,
/// where unsizing can be performed on the pointee.
///
/// See the [DST coercion RFC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce]
/// for more details.
///
/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize<U>`
/// by converting from a thin pointer to a fat pointer.
///
/// For custom types, the coercion here works by coercing `Foo<T>` to `Foo<U>`
/// provided an impl of `CoerceUnsized<Foo<U>> for Foo<T>` exists.
/// Such an impl can only be written if `Foo<T>` has only a single non-phantomdata
/// field involving `T`. If the type of that field is `Bar<T>`, an implementation
/// of `CoerceUnsized<Bar<U>> for Bar<T>` must exist. The coercion will work by
/// coercing the `Bar<T>` field into `Bar<U>` and filling in the rest of the fields
/// from `Foo<T>` to create a `Foo<U>`. This will effectively drill down to a pointer
/// field and coerce that.
///
/// Generally, for smart pointers you will implement
/// `CoerceUnsized<Ptr<U>> for Ptr<T> where T: Unsize<U>, U: ?Sized`, with an
/// optional `?Sized` bound on `T` itself. For wrapper types that directly embed `T`
/// like `Cell<T>` and `RefCell<T>`, you
/// can directly implement `CoerceUnsized<Wrap<U>> for Wrap<T> where T: CoerceUnsized<U>`.
/// This will let coercions of types like `Cell<Box<T>>` work.
///
/// [`Unsize`][unsize] is used to mark types which can be coerced to DSTs if behind
/// pointers. It is implemented automatically by the compiler.
///
/// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
/// [unsize]: ../marker/trait.Unsize.html
/// [nomicon-coerce]: ../../nomicon/coercions.html
#[unstable(feature = "coerce_unsized", issue = "27732")]
#[lang = "coerce_unsized"]
pub trait CoerceUnsized<T> {
    // Empty.
}

// &mut T -> &mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
// &mut T -> &U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
// &mut T -> *mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
// &mut T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}

// &T -> &U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
// &T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}

// *mut T -> *mut U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
// *mut T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}

// *const T -> *const U
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
<|endoftext|>


<commit_before>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;

use clap::{Arg, App};

const BUF_SIZE: usize = 30_000;

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode);
}

fn interpret(program: Vec<char>, debug: bool) {
    if debug {
        println_stderr!("last instruction number,last instruction,current pointer,memory dump");
    }

    let mut buffer = [0u8; BUF_SIZE];

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => p = (p + 1) % BUF_SIZE,
            '<' => p = (p - 1) % BUF_SIZE,
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next(); if chr.is_none() {
                    break;
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{},{},{},{}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<commit_msg>Made brainfuck interpreter have an infinite tape that expands lazily as needed<commit_after>/// Brainfuck language interpreter
/// As specified here: http://www.muppetlabs.com/~breadbox/bf/
#[macro_use]
extern crate clap;

use std::process;
use std::path::{Path};
use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::collections::VecDeque;

use clap::{Arg, App};

macro_rules! exit_with_error(
    ($($arg:tt)*) => { {
        writeln!(&mut ::std::io::stderr(), $($arg)*)
            .expect("Failed while printing to stderr");
        process::exit(1);
    } }
);

macro_rules! println_stderr(
    ($($arg:tt)*) => { {
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

fn main() {
    let args = App::new(crate_name!())
        .version(crate_version!())
        .version_short("v")
        .author(crate_authors!())
        .about("Brainfuck interpreter companion to the brain language compiler")
        .arg(Arg::with_name("input-file")
            .help("The brainfuck file to process. Should contain brainfuck instructions")
            .value_name("file")
            .takes_value(true)
            .required(true)
        )
        .arg(Arg::with_name("debug-enabled")
            .short("D")
            .long("debug")
            .help("Enables debug mode which outputs debugging information to stderr")
        )
        .get_matches();

    let source_path = Path::new(args.value_of("input-file").unwrap());
    if !source_path.exists() || !source_path.is_file() {
        exit_with_error!("Not a valid file: '{}'", source_path.display());
    }

    let debug_mode = args.is_present("debug-enabled");

    let f = File::open(source_path).unwrap_or_else(|e| {
        exit_with_error!("Could not open source file: {}", e);
    });

    let program = f.bytes().map(
        |c| c.expect("Fatal: Could not read char") as char
    ).collect::<Vec<char>>();

    interpret(program, debug_mode);
}

fn interpret(program: Vec<char>, debug: bool) {
    if debug {
        println_stderr!("last instruction number,last instruction,current pointer,memory dump");
    }

    let mut buffer: VecDeque<u8> = VecDeque::new();
    // Make sure there is at least one cell to begin with
    buffer.push_back(0u8);

    // p is the position "pointer" in the buffer
    let mut p: usize = 0;
    // i is the instruction index in the program
    let mut i: usize = 0;

    loop {
        if i >= program.len() {
            break;
        }
        let c = program[i];
        i += 1;

        match c {
            '>' => {
                p += 1;
                if p >= buffer.len() {
                    buffer.push_back(0u8);
                }
            },
            '<' => {
                if p == 0 {
                    buffer.push_front(0u8);
                }
                else {
                    p -= 1;
                }
            },
            '+' => buffer[p] = buffer[p].wrapping_add(1),
            '-' => buffer[p] = buffer[p].wrapping_sub(1),
            '.' => print!("{}", buffer[p] as char),
            ',' => {
                let chr = io::stdin().bytes().next();
                if chr.is_none() {
                    break;
                }
                buffer[p] = chr.unwrap().expect("Could not read input");
            },
            '[' => {
                if buffer[p] == 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            ']' => {
                if buffer[p] != 0 {
                    i = find_matching(&program, i - 1) + 1;
                }
            },
            _ => continue,
        }

        if debug {
            println_stderr!("{},{},{},{}", i-1, c, p,
                buffer.iter().fold(String::new(), |acc, v| format!("{} {}", acc, v)));
        }
    }
}

/// Finds the matching '[' or ']' for the given position within the program
/// panics if a match is not found
fn find_matching(program: &Vec<char>, start: usize) -> usize {
    let direction: isize = match program[start] {
        '[' => 1,
        ']' => -1,
        _ => unreachable!(),
    };

    let mut count = direction;
    let mut current = start;
    loop {
        if (direction < 0 && current == 0) || (direction > 0 && current >= program.len() - 1) {
            panic!("Could not find matching parenthesis for instruction {}", start);
        }
        current = (current as isize + direction) as usize;
        let c = program[current];

        count = match c {
            '[' => count + 1,
            ']' => count - 1,
            _ => count,
        };

        if count == 0 {
            break;
        }
    }

    current
}
<|endoftext|>


<commit_before>use std::env;
use std::path::PathBuf;

use cratesfyi::db::{self, add_path_into_database, connect_db};
use cratesfyi::utils::{add_crate_to_queue, remove_crate_priority, set_crate_priority};
use cratesfyi::Server;
use cratesfyi::{DocBuilder, DocBuilderOptions, RustwideBuilder};
use structopt::StructOpt;

pub fn main() {
    logger_init();

    CommandLine::from_args().handle_args();
}

fn logger_init() {
    use std::io::Write;

    let mut builder = env_logger::Builder::new();
    builder.format(|buf, record| {
        writeln!(
            buf,
            "{} [{}] {}: {}",
            time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
            record.level(),
            record.target(),
            record.args()
        )
    });
    builder.parse_filters(
        env::var("RUST_LOG")
            .ok()
            .as_deref()
            .unwrap_or("cratesfyi=info"),
    );

    rustwide::logging::init_with(builder.build());
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
#[structopt(
    name = "cratesfyi",
    about = env!("CARGO_PKG_DESCRIPTION"),
    version = cratesfyi::BUILD_VERSION,
    rename_all = "kebab-case",
)]
enum CommandLine {
    Build(Build),

    /// Starts web server
    StartWebServer {
        #[structopt(name = "SOCKET_ADDR", default_value = "0.0.0.0:3000")]
        socket_addr: String,
    },

    /// Starts cratesfyi daemon
    Daemon {
        /// Run the server in the foreground instead of detaching a child
        #[structopt(name = "FOREGROUND", short = "f", long = "foreground")]
        foreground: bool,
    },

    /// Database operations
    Database {
        #[structopt(subcommand)]
        subcommand: DatabaseSubcommand,
    },

    /// Interactions with the build queue
    Queue {
        #[structopt(subcommand)]
        subcommand: QueueSubcommand,
    },
}

impl CommandLine {
    pub fn handle_args(self) {
        match self {
            Self::Build(build) => build.handle_args(),
            Self::StartWebServer { socket_addr } => {
                Server::start(Some(&socket_addr));
            }
            Self::Daemon { foreground } => cratesfyi::utils::start_daemon(!foreground),
            Self::Database { subcommand } => subcommand.handle_args(),
            Self::Queue { subcommand } => subcommand.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum QueueSubcommand {
    /// Add a crate to the build queue
    Add {
        /// Name of crate to build
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
        /// Version of crate to build
        #[structopt(name = "CRATE_VERSION")]
        crate_version: String,
        /// Priority of build (new crate builds get priority 0)
        #[structopt(
            name = "BUILD_PRIORITY",
            short = "p",
            long = "priority",
            default_value = "5"
        )]
        build_priority: i32,
    },

    /// Interactions with build queue priorities
    DefaultPriority {
        #[structopt(subcommand)]
        subcommand: PrioritySubcommand,
    },
}

impl QueueSubcommand {
    pub fn handle_args(self) {
        match self {
            Self::Add {
                crate_name,
                crate_version,
                build_priority,
            } => {
                let conn = connect_db().expect("Could not connect to database");
                add_crate_to_queue(&conn, &crate_name, &crate_version, build_priority)
                    .expect("Could not add crate to queue");
            }

            Self::DefaultPriority { subcommand } => subcommand.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum PrioritySubcommand {
    /// Set all crates matching a pattern to a priority level
    Set {
        /// See https://www.postgresql.org/docs/current/functions-matching.html for pattern syntax
        #[structopt(name = "PATTERN")]
        pattern: String,
        /// The priority to give crates matching the given `PATTERN`
        priority: i32,
    },

    /// Remove the prioritization of crates for a pattern
    Remove {
        /// See https://www.postgresql.org/docs/current/functions-matching.html for pattern syntax
        #[structopt(name = "PATTERN")]
        pattern: String,
    },
}

impl PrioritySubcommand {
    pub fn handle_args(self) {
        match self {
            Self::Set { pattern, priority } => {
                let conn = connect_db().expect("Could not connect to the database");

                set_crate_priority(&conn, &pattern, priority)
                    .expect("Could not set pattern's priority");
            }

            Self::Remove { pattern } => {
                let conn = connect_db().expect("Could not connect to the database");

                if let Some(priority) = remove_crate_priority(&conn, &pattern)
                    .expect("Could not remove pattern's priority")
                {
                    println!("Removed pattern with priority {}", priority);
                } else {
                    println!("Pattern did not exist and so was not removed");
                }
            }
        }
    }
}

/// Builds documentation in a chroot environment
#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
#[structopt(rename_all = "kebab-case")]
struct Build {
    #[structopt(
        name = "PREFIX",
        short = "P",
        long = "prefix",
        env = "CRATESFYI_PREFIX"
    )]
    prefix: PathBuf,

    /// Sets crates.io-index path
    #[structopt(name = "CRATES_IO_INDEX_PATH", long = "crates-io-index-path")]
    crates_io_index_path: Option<PathBuf>,

    /// Skips building documentation if documentation exists
    #[structopt(name = "SKIP_IF_EXISTS", short = "s", long = "skip")]
    skip_if_exists: bool,

    /// Skips building documentation if build log exists
    #[structopt(name = "SKIP_IF_LOG_EXISTS", long = "skip-if-log-exists")]
    skip_if_log_exists: bool,

    /// Keeps build directory after build.
    #[structopt(
        name = "KEEP_BUILD_DIRECTORY",
        short = "k",
        long = "keep-build-directory"
    )]
    keep_build_directory: bool,

    #[structopt(subcommand)]
    subcommand: BuildSubcommand,
}

impl Build {
    pub fn handle_args(self) {
        let docbuilder = {
            let mut doc_options = DocBuilderOptions::from_prefix(self.prefix);

            if let Some(crates_io_index_path) = self.crates_io_index_path {
                doc_options.crates_io_index_path = crates_io_index_path;
            }

            doc_options.skip_if_exists = self.skip_if_exists;
            doc_options.skip_if_log_exists = self.skip_if_log_exists;
            doc_options.keep_build_directory = self.keep_build_directory;

            doc_options
                .check_paths()
                .expect("The given paths were invalid");

            DocBuilder::new(doc_options)
        };

        self.subcommand.handle_args(docbuilder);
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum BuildSubcommand {
    /// Builds documentation of every crate
    World,

    /// Builds documentation for a crate
    Crate {
        /// Crate name
        #[structopt(
            name = "CRATE_NAME",
            required_unless("LOCAL"),
            requires("CRATE_VERSION")
        )]
        crate_name: String,

        /// Version of crate
        #[structopt(name = "CRATE_VERSION")]
        crate_version: String,

        /// Build a crate at a specific path
        #[structopt(short = "l", long = "local", conflicts_with_all(&["CRATE_NAME", "CRATE_VERSION"]))]
        local: Option<PathBuf>,
    },

    /// update the currently installed rustup toolchain
    UpdateToolchain {
        /// Update the toolchain only if no toolchain is currently installed
        #[structopt(name = "ONLY_FIRST_TIME", long = "only-first-time")]
        only_first_time: bool,
    },

    /// Adds essential files for the installed version of rustc
    AddEssentialFiles,

    /// Locks cratesfyi daemon to stop building new crates
    Lock,

    /// Unlocks cratesfyi daemon to continue building new crates
    Unlock,

    PrintOptions,
}

impl BuildSubcommand {
    pub fn handle_args(self, mut docbuilder: DocBuilder) {
        match self {
            Self::World => {
                docbuilder.load_cache().expect("Failed to load cache");

                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .build_world(&mut docbuilder)
                    .expect("Failed to build world");

                docbuilder.save_cache().expect("Failed to save cache");
            }

            Self::Crate {
                crate_name,
                crate_version,
                local,
            } => {
                docbuilder.load_cache().expect("Failed to load cache");
                let mut builder = RustwideBuilder::init().expect("failed to initialize rustwide");

                if let Some(path) = local {
                    builder
                        .build_local_package(&mut docbuilder, &path)
                        .expect("Building documentation failed");
                } else {
                    builder
                        .build_package(&mut docbuilder, &crate_name, &crate_version, None)
                        .expect("Building documentation failed");
                }

                docbuilder.save_cache().expect("Failed to save cache");
            }

            Self::UpdateToolchain { only_first_time } => {
                if only_first_time {
                    let conn = db::connect_db().unwrap();
                    let res = conn
                        .query("SELECT * FROM config WHERE name = 'rustc_version';", &[])
                        .unwrap();

                    if !res.is_empty() {
                        println!("update-toolchain was already called in the past, exiting");
                        return;
                    }
                }

                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .update_toolchain()
                    .expect("failed to update toolchain");
            }

            Self::AddEssentialFiles => {
                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .add_essential_files()
                    .expect("failed to add essential files");
            }

            Self::Lock => docbuilder.lock().expect("Failed to lock"),
            Self::Unlock => docbuilder.unlock().expect("Failed to unlock"),
            Self::PrintOptions => println!("{:?}", docbuilder.options()),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum DatabaseSubcommand {
    #[structopt(name = "move-to-s3")]
    MoveToS3,

    /// Run database migrations
    Migrate {
        /// The database version to migrate to
        #[structopt(name = "VERSION")]
        version: Option<i64>,
    },

    /// Updates github stats for crates.
    UpdateGithubFields,

    AddDirectory {
        /// Path of file or directory
        #[structopt(name = "DIRECTORY")]
        directory: PathBuf,
        /// Prefix of files in database
        #[structopt(name = "PREFIX", env = "CRATESFYI_PREFIX")]
        prefix: String,
    },

    /// Updates monthly release activity chart
    UpdateReleaseActivity,

    /// Updates search index
    UpdateSearchIndex,

    /// Removes a whole crate from the database
    DeleteCrate {
        /// Name of the crate to delete
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },

    /// Blacklist operations
    Blacklist {
        #[structopt(subcommand)]
        command: BlacklistSubcommand,
    },
}

impl DatabaseSubcommand {
    pub fn handle_args(self) {
        match self {
            Self::MoveToS3 => {
                let conn = db::connect_db().expect("failed to connect to the database");

                let (mut count, mut total) = (1, 0);
                while count != 0 {
                    count = db::move_to_s3(&conn, 5_000).expect("Failed to upload batch to S3");
                    total += count;

                    eprintln!(
                        "moved {} rows to s3 in this batch, total moved so far: {}",
                        count, total
                    );
                }
            }

            Self::Migrate { version } => {
                let conn = connect_db().expect("failed to connect to the database");
                db::migrate(version, &conn).expect("Failed to run database migrations");
            }

            Self::UpdateGithubFields => {
                cratesfyi::utils::github_updater().expect("Failed to update github fields");
            }

            Self::AddDirectory { directory, prefix } => {
                let conn = db::connect_db().expect("failed to connect to the database");
                add_path_into_database(&conn, &prefix, directory)
                    .expect("Failed to add directory into database");
            }

            // FIXME: This is actually util command not database
            Self::UpdateReleaseActivity => cratesfyi::utils::update_release_activity()
                .expect("Failed to update release activity"),

            Self::UpdateSearchIndex => {
                let conn = db::connect_db().expect("failed to connect to the database");
                db::update_search_index(&conn).expect("Failed to update search index");
            }

            Self::DeleteCrate { crate_name } => {
                let conn = db::connect_db().expect("failed to connect to the database");
                db::delete_crate(&conn, &crate_name).expect("failed to delete the crate");
            }

            Self::Blacklist { command } => command.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum BlacklistSubcommand {
    /// List all crates on the blacklist
    List,

    /// Add a crate to the blacklist
    Add {
        /// Crate name
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },

    /// Remove a crate from the blacklist
    Remove {
        /// Crate name
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },
}

impl BlacklistSubcommand {
    fn handle_args(self) {
        let conn = db::connect_db().expect("failed to connect to the database");

        match self {
            Self::List => {
                let crates =
                    db::blacklist::list_crates(&conn).expect("failed to list crates on blacklist");

                println!("{}", crates.join("\n"));
            }

            Self::Add { crate_name } => db::blacklist::add_crate(&conn, &crate_name)
                .expect("failed to add crate to blacklist"),

            Self::Remove { crate_name } => db::blacklist::remove_crate(&conn, &crate_name)
                .expect("failed to remove crate from blacklist"),
        }
    }
}
<commit_msg>Removed 'move-to-s3'<commit_after>use std::env;
use std::path::PathBuf;

use cratesfyi::db::{self, add_path_into_database, connect_db};
use cratesfyi::utils::{add_crate_to_queue, remove_crate_priority, set_crate_priority};
use cratesfyi::Server;
use cratesfyi::{DocBuilder, DocBuilderOptions, RustwideBuilder};
use structopt::StructOpt;

pub fn main() {
    logger_init();

    CommandLine::from_args().handle_args();
}

fn logger_init() {
    use std::io::Write;

    let mut builder = env_logger::Builder::new();
    builder.format(|buf, record| {
        writeln!(
            buf,
            "{} [{}] {}: {}",
            time::now().strftime("%Y/%m/%d %H:%M:%S").unwrap(),
            record.level(),
            record.target(),
            record.args()
        )
    });
    builder.parse_filters(
        env::var("RUST_LOG")
            .ok()
            .as_deref()
            .unwrap_or("cratesfyi=info"),
    );

    rustwide::logging::init_with(builder.build());
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
#[structopt(
    name = "cratesfyi",
    about = env!("CARGO_PKG_DESCRIPTION"),
    version = cratesfyi::BUILD_VERSION,
    rename_all = "kebab-case",
)]
enum CommandLine {
    Build(Build),

    /// Starts web server
    StartWebServer {
        #[structopt(name = "SOCKET_ADDR", default_value = "0.0.0.0:3000")]
        socket_addr: String,
    },

    /// Starts cratesfyi daemon
    Daemon {
        /// Run the server in the foreground instead of detaching a child
        #[structopt(name = "FOREGROUND", short = "f", long = "foreground")]
        foreground: bool,
    },

    /// Database operations
    Database {
        #[structopt(subcommand)]
        subcommand: DatabaseSubcommand,
    },

    /// Interactions with the build queue
    Queue {
        #[structopt(subcommand)]
        subcommand: QueueSubcommand,
    },
}

impl CommandLine {
    pub fn handle_args(self) {
        match self {
            Self::Build(build) => build.handle_args(),
            Self::StartWebServer { socket_addr } => {
                Server::start(Some(&socket_addr));
            }
            Self::Daemon { foreground } => cratesfyi::utils::start_daemon(!foreground),
            Self::Database { subcommand } => subcommand.handle_args(),
            Self::Queue { subcommand } => subcommand.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum QueueSubcommand {
    /// Add a crate to the build queue
    Add {
        /// Name of crate to build
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
        /// Version of crate to build
        #[structopt(name = "CRATE_VERSION")]
        crate_version: String,
        /// Priority of build (new crate builds get priority 0)
        #[structopt(
            name = "BUILD_PRIORITY",
            short = "p",
            long = "priority",
            default_value = "5"
        )]
        build_priority: i32,
    },

    /// Interactions with build queue priorities
    DefaultPriority {
        #[structopt(subcommand)]
        subcommand: PrioritySubcommand,
    },
}

impl QueueSubcommand {
    pub fn handle_args(self) {
        match self {
            Self::Add {
                crate_name,
                crate_version,
                build_priority,
            } => {
                let conn = connect_db().expect("Could not connect to database");
                add_crate_to_queue(&conn, &crate_name, &crate_version, build_priority)
                    .expect("Could not add crate to queue");
            }

            Self::DefaultPriority { subcommand } => subcommand.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum PrioritySubcommand {
    /// Set all crates matching a pattern to a priority level
    Set {
        /// See https://www.postgresql.org/docs/current/functions-matching.html for pattern syntax
        #[structopt(name = "PATTERN")]
        pattern: String,
        /// The priority to give crates matching the given `PATTERN`
        priority: i32,
    },

    /// Remove the prioritization of crates for a pattern
    Remove {
        /// See https://www.postgresql.org/docs/current/functions-matching.html for pattern syntax
        #[structopt(name = "PATTERN")]
        pattern: String,
    },
}

impl PrioritySubcommand {
    pub fn handle_args(self) {
        match self {
            Self::Set { pattern, priority } => {
                let conn = connect_db().expect("Could not connect to the database");

                set_crate_priority(&conn, &pattern, priority)
                    .expect("Could not set pattern's priority");
            }

            Self::Remove { pattern } => {
                let conn = connect_db().expect("Could not connect to the database");

                if let Some(priority) = remove_crate_priority(&conn, &pattern)
                    .expect("Could not remove pattern's priority")
                {
                    println!("Removed pattern with priority {}", priority);
                } else {
                    println!("Pattern did not exist and so was not removed");
                }
            }
        }
    }
}

/// Builds documentation in a chroot environment
#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
#[structopt(rename_all = "kebab-case")]
struct Build {
    #[structopt(
        name = "PREFIX",
        short = "P",
        long = "prefix",
        env = "CRATESFYI_PREFIX"
    )]
    prefix: PathBuf,

    /// Sets crates.io-index path
    #[structopt(name = "CRATES_IO_INDEX_PATH", long = "crates-io-index-path")]
    crates_io_index_path: Option<PathBuf>,

    /// Skips building documentation if documentation exists
    #[structopt(name = "SKIP_IF_EXISTS", short = "s", long = "skip")]
    skip_if_exists: bool,

    /// Skips building documentation if build log exists
    #[structopt(name = "SKIP_IF_LOG_EXISTS", long = "skip-if-log-exists")]
    skip_if_log_exists: bool,

    /// Keeps build directory after build.
    #[structopt(
        name = "KEEP_BUILD_DIRECTORY",
        short = "k",
        long = "keep-build-directory"
    )]
    keep_build_directory: bool,

    #[structopt(subcommand)]
    subcommand: BuildSubcommand,
}

impl Build {
    pub fn handle_args(self) {
        let docbuilder = {
            let mut doc_options = DocBuilderOptions::from_prefix(self.prefix);

            if let Some(crates_io_index_path) = self.crates_io_index_path {
                doc_options.crates_io_index_path = crates_io_index_path;
            }

            doc_options.skip_if_exists = self.skip_if_exists;
            doc_options.skip_if_log_exists = self.skip_if_log_exists;
            doc_options.keep_build_directory = self.keep_build_directory;

            doc_options
                .check_paths()
                .expect("The given paths were invalid");

            DocBuilder::new(doc_options)
        };

        self.subcommand.handle_args(docbuilder);
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum BuildSubcommand {
    /// Builds documentation of every crate
    World,

    /// Builds documentation for a crate
    Crate {
        /// Crate name
        #[structopt(
            name = "CRATE_NAME",
            required_unless("LOCAL"),
            requires("CRATE_VERSION")
        )]
        crate_name: String,

        /// Version of crate
        #[structopt(name = "CRATE_VERSION")]
        crate_version: String,

        /// Build a crate at a specific path
        #[structopt(short = "l", long = "local", conflicts_with_all(&["CRATE_NAME", "CRATE_VERSION"]))]
        local: Option<PathBuf>,
    },

    /// update the currently installed rustup toolchain
    UpdateToolchain {
        /// Update the toolchain only if no toolchain is currently installed
        #[structopt(name = "ONLY_FIRST_TIME", long = "only-first-time")]
        only_first_time: bool,
    },

    /// Adds essential files for the installed version of rustc
    AddEssentialFiles,

    /// Locks cratesfyi daemon to stop building new crates
    Lock,

    /// Unlocks cratesfyi daemon to continue building new crates
    Unlock,

    PrintOptions,
}

impl BuildSubcommand {
    pub fn handle_args(self, mut docbuilder: DocBuilder) {
        match self {
            Self::World => {
                docbuilder.load_cache().expect("Failed to load cache");

                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .build_world(&mut docbuilder)
                    .expect("Failed to build world");

                docbuilder.save_cache().expect("Failed to save cache");
            }

            Self::Crate {
                crate_name,
                crate_version,
                local,
            } => {
                docbuilder.load_cache().expect("Failed to load cache");
                let mut builder = RustwideBuilder::init().expect("failed to initialize rustwide");

                if let Some(path) = local {
                    builder
                        .build_local_package(&mut docbuilder, &path)
                        .expect("Building documentation failed");
                } else {
                    builder
                        .build_package(&mut docbuilder, &crate_name, &crate_version, None)
                        .expect("Building documentation failed");
                }

                docbuilder.save_cache().expect("Failed to save cache");
            }

            Self::UpdateToolchain { only_first_time } => {
                if only_first_time {
                    let conn = db::connect_db().unwrap();
                    let res = conn
                        .query("SELECT * FROM config WHERE name = 'rustc_version';", &[])
                        .unwrap();

                    if !res.is_empty() {
                        println!("update-toolchain was already called in the past, exiting");
                        return;
                    }
                }

                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .update_toolchain()
                    .expect("failed to update toolchain");
            }

            Self::AddEssentialFiles => {
                let mut builder = RustwideBuilder::init().unwrap();
                builder
                    .add_essential_files()
                    .expect("failed to add essential files");
            }

            Self::Lock => docbuilder.lock().expect("Failed to lock"),
            Self::Unlock => docbuilder.unlock().expect("Failed to unlock"),
            Self::PrintOptions => println!("{:?}", docbuilder.options()),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum DatabaseSubcommand {
    /// Run database migrations
    Migrate {
        /// The database version to migrate to
        #[structopt(name = "VERSION")]
        version: Option<i64>,
    },

    /// Updates github stats for crates.
    UpdateGithubFields,

    AddDirectory {
        /// Path of file or directory
        #[structopt(name = "DIRECTORY")]
        directory: PathBuf,
        /// Prefix of files in database
        #[structopt(name = "PREFIX", env = "CRATESFYI_PREFIX")]
        prefix: String,
    },

    /// Updates monthly release activity chart
    UpdateReleaseActivity,

    /// Updates search index
    UpdateSearchIndex,

    /// Removes a whole crate from the database
    DeleteCrate {
        /// Name of the crate to delete
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },

    /// Blacklist operations
    Blacklist {
        #[structopt(subcommand)]
        command: BlacklistSubcommand,
    },
}

impl DatabaseSubcommand {
    pub fn handle_args(self) {
        match self {
            Self::Migrate { version } => {
                let conn = connect_db().expect("failed to connect to the database");
                db::migrate(version, &conn).expect("Failed to run database migrations");
            }

            Self::UpdateGithubFields => {
                cratesfyi::utils::github_updater().expect("Failed to update github fields");
            }

            Self::AddDirectory { directory, prefix } => {
                let conn = db::connect_db().expect("failed to connect to the database");
                add_path_into_database(&conn, &prefix, directory)
                    .expect("Failed to add directory into database");
            }

            // FIXME: This is actually util command not database
            Self::UpdateReleaseActivity => cratesfyi::utils::update_release_activity()
                .expect("Failed to update release activity"),

            Self::UpdateSearchIndex => {
                let conn = db::connect_db().expect("failed to connect to the database");
                db::update_search_index(&conn).expect("Failed to update search index");
            }

            Self::DeleteCrate { crate_name } => {
                let conn = db::connect_db().expect("failed to connect to the database");
                db::delete_crate(&conn, &crate_name).expect("failed to delete the crate");
            }

            Self::Blacklist { command } => command.handle_args(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, StructOpt)]
enum BlacklistSubcommand {
    /// List all crates on the blacklist
    List,

    /// Add a crate to the blacklist
    Add {
        /// Crate name
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },

    /// Remove a crate from the blacklist
    Remove {
        /// Crate name
        #[structopt(name = "CRATE_NAME")]
        crate_name: String,
    },
}

impl BlacklistSubcommand {
    fn handle_args(self) {
        let conn = db::connect_db().expect("failed to connect to the database");

        match self {
            Self::List => {
                let crates =
                    db::blacklist::list_crates(&conn).expect("failed to list crates on blacklist");

                println!("{}", crates.join("\n"));
            }

            Self::Add { crate_name } => db::blacklist::add_crate(&conn, &crate_name)
                .expect("failed to add crate to blacklist"),

            Self::Remove { crate_name } => db::blacklist::remove_crate(&conn, &crate_name)
                .expect("failed to remove crate from blacklist"),
        }
    }
}
<|endoftext|>