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

//! A helper class for dealing with static archives

use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use std::str;
use syntax::diagnostic::Handler as ErrorHandler;
use rustc_llvm::archive_ro::ArchiveRO;

use tempdir::TempDir;

pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";

pub struct ArchiveConfig<'a> {
    pub handler: &'a ErrorHandler,
    pub dst: PathBuf,
    pub lib_search_paths: Vec<PathBuf>,
    pub slib_prefix: String,
    pub slib_suffix: String,
    pub maybe_ar_prog: Option<String>
}

pub struct Archive<'a> {
    handler: &'a ErrorHandler,
    dst: PathBuf,
    lib_search_paths: Vec<PathBuf>,
    slib_prefix: String,
    slib_suffix: String,
    maybe_ar_prog: Option<String>
}

/// Helper for adding many files to an archive with a single invocation of
/// `ar`.
#[must_use = "must call build() to finish building the archive"]
pub struct ArchiveBuilder<'a> {
    archive: Archive<'a>,
    work_dir: TempDir,
    /// Filename of each member that should be added to the archive.
    members: Vec<PathBuf>,
    should_update_symbols: bool,
}

fn run_ar(handler: &ErrorHandler, maybe_ar_prog: &Option<String>,
          args: &str, cwd: Option<&Path>,
          paths: &[&Path]) -> Output {
    let ar = match *maybe_ar_prog {
        Some(ref ar) => &ar[..],
        None => "ar"
    };
    let mut cmd = Command::new(ar);

    cmd.arg(args).args(paths).stdout(Stdio::piped()).stderr(Stdio::piped());
    debug!("{:?}", cmd);

    match cwd {
        Some(p) => {
            cmd.current_dir(p);
            debug!("inside {:?}", p.display());
        }
        None => {}
    }

    match cmd.spawn() {
        Ok(prog) => {
            let o = prog.wait_with_output().unwrap();
            if !o.status.success() {
                handler.err(&format!("{:?} failed with: {}", cmd, o.status));
                handler.note(&format!("stdout ---\n{}",
                                  str::from_utf8(&o.stdout).unwrap()));
                handler.note(&format!("stderr ---\n{}",
                                  str::from_utf8(&o.stderr).unwrap())
                             );
                handler.abort_if_errors();
            }
            o
        },
        Err(e) => {
            handler.err(&format!("could not exec `{}`: {}", &ar[..],
                             e));
            handler.abort_if_errors();
            panic!("rustc::back::archive::run_ar() should not reach this point");
        }
    }
}

pub fn find_library(name: &str, osprefix: &str, ossuffix: &str,
                    search_paths: &[PathBuf],
                    handler: &ErrorHandler) -> PathBuf {
    // On Windows, static libraries sometimes show up as libfoo.a and other
    // times show up as foo.lib
    let oslibname = format!("{}{}{}", osprefix, name, ossuffix);
    let unixlibname = format!("lib{}.a", name);

    for path in search_paths {
        debug!("looking for {} inside {:?}", name, path);
        let test = path.join(&oslibname[..]);
        if test.exists() { return test }
        if oslibname != unixlibname {
            let test = path.join(&unixlibname[..]);
            if test.exists() { return test }
        }
    }
    handler.fatal(&format!("could not find native static library `{}`, \
                           perhaps an -L flag is missing?",
                          name));
}

impl<'a> Archive<'a> {
    fn new(config: ArchiveConfig<'a>) -> Archive<'a> {
        let ArchiveConfig { handler, dst, lib_search_paths, slib_prefix, slib_suffix,
            maybe_ar_prog } = config;
        Archive {
            handler: handler,
            dst: dst,
            lib_search_paths: lib_search_paths,
            slib_prefix: slib_prefix,
            slib_suffix: slib_suffix,
            maybe_ar_prog: maybe_ar_prog
        }
    }

    /// Opens an existing static archive
    pub fn open(config: ArchiveConfig<'a>) -> Archive<'a> {
        let archive = Archive::new(config);
        assert!(archive.dst.exists());
        archive
    }

    /// Removes a file from this archive
    pub fn remove_file(&mut self, file: &str) {
        run_ar(self.handler, &self.maybe_ar_prog, "d", None, &[&self.dst, &Path::new(file)]);
    }

    /// Lists all files in an archive
    pub fn files(&self) -> Vec<String> {
        let output = run_ar(self.handler, &self.maybe_ar_prog, "t", None, &[&self.dst]);
        let output = str::from_utf8(&output.stdout).unwrap();
        // use lines_any because windows delimits output with `\r\n` instead of
        // just `\n`
        output.lines_any().map(|s| s.to_string()).collect()
    }

    /// Creates an `ArchiveBuilder` for adding files to this archive.
    pub fn extend(self) -> ArchiveBuilder<'a> {
        ArchiveBuilder::new(self)
    }
}

impl<'a> ArchiveBuilder<'a> {
    fn new(archive: Archive<'a>) -> ArchiveBuilder<'a> {
        ArchiveBuilder {
            archive: archive,
            work_dir: TempDir::new("rsar").unwrap(),
            members: vec![],
            should_update_symbols: false,
        }
    }

    /// Create a new static archive, ready for adding files.
    pub fn create(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> {
        let archive = Archive::new(config);
        ArchiveBuilder::new(archive)
    }

    /// Adds all of the contents of a native library to this archive. This will
    /// search in the relevant locations for a library named `name`.
    pub fn add_native_library(&mut self, name: &str) -> io::Result<()> {
        let location = find_library(name,
                                    &self.archive.slib_prefix,
                                    &self.archive.slib_suffix,
                                    &self.archive.lib_search_paths,
                                    self.archive.handler);
        self.add_archive(&location, name, |_| false)
    }

    /// Adds all of the contents of the rlib at the specified path to this
    /// archive.
    ///
    /// This ignores adding the bytecode from the rlib, and if LTO is enabled
    /// then the object file also isn't added.
    pub fn add_rlib(&mut self, rlib: &Path, name: &str,
                    lto: bool) -> io::Result<()> {
        // Ignoring obj file starting with the crate name
        // as simple comparison is not enough - there
        // might be also an extra name suffix
        let obj_start = format!("{}", name);
        let obj_start = &obj_start[..];
        // Ignoring all bytecode files, no matter of
        // name
        let bc_ext = ".bytecode.deflate";

        self.add_archive(rlib, &name[..], |fname: &str| {
            let skip_obj = lto && fname.starts_with(obj_start)
                && fname.ends_with(".o");
            skip_obj || fname.ends_with(bc_ext) || fname == METADATA_FILENAME
        })
    }

    /// Adds an arbitrary file to this archive
    pub fn add_file(&mut self, file: &Path) -> io::Result<()> {
        let filename = Path::new(file.file_name().unwrap());
        let new_file = self.work_dir.path().join(&filename);
        try!(fs::copy(file, &new_file));
        self.members.push(filename.to_path_buf());
        Ok(())
    }

    /// Indicate that the next call to `build` should updates all symbols in
    /// the archive (run 'ar s' over it).
    pub fn update_symbols(&mut self) {
        self.should_update_symbols = true;
    }

    /// Combine the provided files, rlibs, and native libraries into a single
    /// `Archive`.
    pub fn build(self) -> Archive<'a> {
        // Get an absolute path to the destination, so `ar` will work even
        // though we run it from `self.work_dir`.
        let abs_dst = env::current_dir().unwrap().join(&self.archive.dst);
        assert!(!abs_dst.is_relative());
        let mut args = vec![&*abs_dst];
        let mut total_len = abs_dst.to_string_lossy().len();

        if self.members.is_empty() {
            // OSX `ar` does not allow using `r` with no members, but it does
            // allow running `ar s file.a` to update symbols only.
            if self.should_update_symbols {
                run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
                       "s", Some(self.work_dir.path()), &args[..]);
            }
            return self.archive;
        }

        // Don't allow the total size of `args` to grow beyond 32,000 bytes.
        // Windows will raise an error if the argument string is longer than
        // 32,768, and we leave a bit of extra space for the program name.
        const ARG_LENGTH_LIMIT: usize = 32_000;

        for member_name in &self.members {
            let len = member_name.to_string_lossy().len();

            // `len + 1` to account for the space that's inserted before each
            // argument.  (Windows passes command-line arguments as a single
            // string, not an array of strings.)
            if total_len + len + 1 > ARG_LENGTH_LIMIT {
                // Add the archive members seen so far, without updating the
                // symbol table (`S`).
                run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
                       "cruS", Some(self.work_dir.path()), &args[..]);

                args.clear();
                args.push(&abs_dst);
                total_len = abs_dst.to_string_lossy().len();
            }

            args.push(member_name);
            total_len += len + 1;
        }

        // Add the remaining archive members, and update the symbol table if
        // necessary.
        let flags = if self.should_update_symbols { "crus" } else { "cruS" };
        run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
               flags, Some(self.work_dir.path()), &args[..]);

        self.archive
    }

    fn add_archive<F>(&mut self, archive: &Path, name: &str,
                      mut skip: F) -> io::Result<()>
        where F: FnMut(&str) -> bool,
    {
        let archive = match ArchiveRO::open(archive) {
            Some(ar) => ar,
            None => return Err(io::Error::new(io::ErrorKind::Other,
                                              "failed to open archive")),
        };

        // Next, we must rename all of the inputs to "guaranteed unique names".
        // We write each file into `self.work_dir` under its new unique name.
        // The reason for this renaming is that archives are keyed off the name
        // of the files, so if two files have the same name they will override
        // one another in the archive (bad).
        //
        // We skip any files explicitly desired for skipping, and we also skip
        // all SYMDEF files as these are just magical placeholders which get
        // re-created when we make a new archive anyway.
        for file in archive.iter() {
            let filename = match file.name() {
                Some(s) => s,
                None => continue,
            };
            if filename.contains(".SYMDEF") { continue }
            if skip(filename) { continue }

            // An archive can contain files of the same name multiple times, so
            // we need to be sure to not have them overwrite one another when we
            // extract them. Consequently we need to find a truly unique file
            // name for us!
            let mut new_filename = String::new();
            for n in 0.. {
                let n = if n == 0 {String::new()} else {format!("-{}", n)};
                new_filename = format!("r{}-{}-{}", n, name, filename);

                // LLDB (as mentioned in back::link) crashes on filenames of
                // exactly
                // 16 bytes in length. If we're including an object file with
                //    exactly 16-bytes of characters, give it some prefix so
                //    that it's not 16 bytes.
                new_filename = if new_filename.len() == 16 {
                    format!("lldb-fix-{}", new_filename)
                } else {
                    new_filename
                };

                let present = self.members.iter().filter_map(|p| {
                    p.file_name().and_then(|f| f.to_str())
                }).any(|s| s == new_filename);
                if !present {
                    break
                }
            }
            let dst = self.work_dir.path().join(&new_filename);
            try!(try!(File::create(&dst)).write_all(file.data()));
            self.members.push(PathBuf::from(new_filename));
        }

        Ok(())
    }
}
<commit_msg>rustc_back: Refactor Archive to better express intent<commit_after>// Copyright 2013-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.

//! A helper class for dealing with static archives

use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use std::str;
use syntax::diagnostic::Handler as ErrorHandler;
use rustc_llvm::archive_ro::ArchiveRO;

use tempdir::TempDir;

pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";

pub struct ArchiveConfig<'a> {
    pub handler: &'a ErrorHandler,
    pub dst: PathBuf,
    pub lib_search_paths: Vec<PathBuf>,
    pub slib_prefix: String,
    pub slib_suffix: String,
    pub ar_prog: String
}

pub struct Archive<'a> {
    config: ArchiveConfig<'a>,
}

/// Helper for adding many files to an archive with a single invocation of
/// `ar`.
#[must_use = "must call build() to finish building the archive"]
pub struct ArchiveBuilder<'a> {
    archive: Archive<'a>,
    work_dir: TempDir,
    /// Filename of each member that should be added to the archive.
    members: Vec<PathBuf>,
    should_update_symbols: bool,
}

enum Action<'a> {
    Remove(&'a Path),
    AddObjects(&'a [&'a PathBuf], bool),
    UpdateSymbols,
}

pub fn find_library(name: &str, osprefix: &str, ossuffix: &str,
                    search_paths: &[PathBuf],
                    handler: &ErrorHandler) -> PathBuf {
    // On Windows, static libraries sometimes show up as libfoo.a and other
    // times show up as foo.lib
    let oslibname = format!("{}{}{}", osprefix, name, ossuffix);
    let unixlibname = format!("lib{}.a", name);

    for path in search_paths {
        debug!("looking for {} inside {:?}", name, path);
        let test = path.join(&oslibname[..]);
        if test.exists() { return test }
        if oslibname != unixlibname {
            let test = path.join(&unixlibname[..]);
            if test.exists() { return test }
        }
    }
    handler.fatal(&format!("could not find native static library `{}`, \
                           perhaps an -L flag is missing?",
                          name));
}

impl<'a> Archive<'a> {
    fn new(config: ArchiveConfig<'a>) -> Archive<'a> {
        Archive { config: config }
    }

    /// Opens an existing static archive
    pub fn open(config: ArchiveConfig<'a>) -> Archive<'a> {
        let archive = Archive::new(config);
        assert!(archive.config.dst.exists());
        archive
    }

    /// Removes a file from this archive
    pub fn remove_file(&mut self, file: &str) {
        self.run(None, Action::Remove(Path::new(file)));
    }

    /// Lists all files in an archive
    pub fn files(&self) -> Vec<String> {
        let archive = match ArchiveRO::open(&self.config.dst) {
            Some(ar) => ar,
            None => return Vec::new(),
        };
        let ret = archive.iter().filter_map(|child| child.name())
                         .map(|name| name.to_string())
                         .collect();
        return ret;
    }

    /// Creates an `ArchiveBuilder` for adding files to this archive.
    pub fn extend(self) -> ArchiveBuilder<'a> {
        ArchiveBuilder::new(self)
    }

    fn run(&self, cwd: Option<&Path>, action: Action) -> Output {
        let abs_dst = env::current_dir().unwrap().join(&self.config.dst);
        let ar = &self.config.ar_prog;
        let mut cmd = Command::new(ar);
        cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
        self.prepare_ar_action(&mut cmd, &abs_dst, action);
        info!("{:?}", cmd);

        if let Some(p) = cwd {
            cmd.current_dir(p);
            info!("inside {:?}", p.display());
        }

        let handler = &self.config.handler;
        match cmd.spawn() {
            Ok(prog) => {
                let o = prog.wait_with_output().unwrap();
                if !o.status.success() {
                    handler.err(&format!("{:?} failed with: {}", cmd, o.status));
                    handler.note(&format!("stdout ---\n{}",
                                          str::from_utf8(&o.stdout).unwrap()));
                    handler.note(&format!("stderr ---\n{}",
                                          str::from_utf8(&o.stderr).unwrap()));
                    handler.abort_if_errors();
                }
                o
            },
            Err(e) => {
                handler.err(&format!("could not exec `{}`: {}",
                                     self.config.ar_prog, e));
                handler.abort_if_errors();
                panic!("rustc::back::archive::run() should not reach this point");
            }
        }
    }

    fn prepare_ar_action(&self, cmd: &mut Command, dst: &Path, action: Action) {
        match action {
            Action::Remove(file) => {
                cmd.arg("d").arg(dst).arg(file);
            }
            Action::AddObjects(objs, update_symbols) => {
                cmd.arg(if update_symbols {"crus"} else {"cruS"})
                   .arg(dst)
                   .args(objs);
            }
            Action::UpdateSymbols => {
                cmd.arg("s").arg(dst);
            }
        }
    }
}

impl<'a> ArchiveBuilder<'a> {
    fn new(archive: Archive<'a>) -> ArchiveBuilder<'a> {
        ArchiveBuilder {
            archive: archive,
            work_dir: TempDir::new("rsar").unwrap(),
            members: vec![],
            should_update_symbols: false,
        }
    }

    /// Create a new static archive, ready for adding files.
    pub fn create(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> {
        let archive = Archive::new(config);
        ArchiveBuilder::new(archive)
    }

    /// Adds all of the contents of a native library to this archive. This will
    /// search in the relevant locations for a library named `name`.
    pub fn add_native_library(&mut self, name: &str) -> io::Result<()> {
        let location = find_library(name,
                                    &self.archive.config.slib_prefix,
                                    &self.archive.config.slib_suffix,
                                    &self.archive.config.lib_search_paths,
                                    self.archive.config.handler);
        self.add_archive(&location, name, |_| false)
    }

    /// Adds all of the contents of the rlib at the specified path to this
    /// archive.
    ///
    /// This ignores adding the bytecode from the rlib, and if LTO is enabled
    /// then the object file also isn't added.
    pub fn add_rlib(&mut self, rlib: &Path, name: &str,
                    lto: bool) -> io::Result<()> {
        // Ignoring obj file starting with the crate name
        // as simple comparison is not enough - there
        // might be also an extra name suffix
        let obj_start = format!("{}", name);
        let obj_start = &obj_start[..];
        // Ignoring all bytecode files, no matter of
        // name
        let bc_ext = ".bytecode.deflate";

        self.add_archive(rlib, &name[..], |fname: &str| {
            let skip_obj = lto && fname.starts_with(obj_start)
                && fname.ends_with(".o");
            skip_obj || fname.ends_with(bc_ext) || fname == METADATA_FILENAME
        })
    }

    /// Adds an arbitrary file to this archive
    pub fn add_file(&mut self, file: &Path) -> io::Result<()> {
        let filename = Path::new(file.file_name().unwrap());
        let new_file = self.work_dir.path().join(&filename);
        try!(fs::copy(file, &new_file));
        self.members.push(filename.to_path_buf());
        Ok(())
    }

    /// Indicate that the next call to `build` should updates all symbols in
    /// the archive (run 'ar s' over it).
    pub fn update_symbols(&mut self) {
        self.should_update_symbols = true;
    }

    /// Combine the provided files, rlibs, and native libraries into a single
    /// `Archive`.
    pub fn build(self) -> Archive<'a> {
        // Get an absolute path to the destination, so `ar` will work even
        // though we run it from `self.work_dir`.
        let mut objects = Vec::new();
        let mut total_len = self.archive.config.dst.to_string_lossy().len();

        if self.members.is_empty() {
            if self.should_update_symbols {
                self.archive.run(Some(self.work_dir.path()),
                                 Action::UpdateSymbols);
            }
            return self.archive;
        }

        // Don't allow the total size of `args` to grow beyond 32,000 bytes.
        // Windows will raise an error if the argument string is longer than
        // 32,768, and we leave a bit of extra space for the program name.
        const ARG_LENGTH_LIMIT: usize = 32_000;

        for member_name in &self.members {
            let len = member_name.to_string_lossy().len();

            // `len + 1` to account for the space that's inserted before each
            // argument.  (Windows passes command-line arguments as a single
            // string, not an array of strings.)
            if total_len + len + 1 > ARG_LENGTH_LIMIT {
                // Add the archive members seen so far, without updating the
                // symbol table.
                self.archive.run(Some(self.work_dir.path()),
                                 Action::AddObjects(&objects, false));

                objects.clear();
                total_len = self.archive.config.dst.to_string_lossy().len();
            }

            objects.push(member_name);
            total_len += len + 1;
        }

        // Add the remaining archive members, and update the symbol table if
        // necessary.
        self.archive.run(Some(self.work_dir.path()),
                         Action::AddObjects(&objects, self.should_update_symbols));

        self.archive
    }

    fn add_archive<F>(&mut self, archive: &Path, name: &str,
                      mut skip: F) -> io::Result<()>
        where F: FnMut(&str) -> bool,
    {
        let archive = match ArchiveRO::open(archive) {
            Some(ar) => ar,
            None => return Err(io::Error::new(io::ErrorKind::Other,
                                              "failed to open archive")),
        };

        // Next, we must rename all of the inputs to "guaranteed unique names".
        // We write each file into `self.work_dir` under its new unique name.
        // The reason for this renaming is that archives are keyed off the name
        // of the files, so if two files have the same name they will override
        // one another in the archive (bad).
        //
        // We skip any files explicitly desired for skipping, and we also skip
        // all SYMDEF files as these are just magical placeholders which get
        // re-created when we make a new archive anyway.
        for file in archive.iter() {
            let filename = match file.name() {
                Some(s) => s,
                None => continue,
            };
            if filename.contains(".SYMDEF") { continue }
            if skip(filename) { continue }
            let filename = Path::new(filename).file_name().unwrap()
                                              .to_str().unwrap();

            // An archive can contain files of the same name multiple times, so
            // we need to be sure to not have them overwrite one another when we
            // extract them. Consequently we need to find a truly unique file
            // name for us!
            let mut new_filename = String::new();
            for n in 0.. {
                let n = if n == 0 {String::new()} else {format!("-{}", n)};
                new_filename = format!("r{}-{}-{}", n, name, filename);

                // LLDB (as mentioned in back::link) crashes on filenames of
                // exactly
                // 16 bytes in length. If we're including an object file with
                //    exactly 16-bytes of characters, give it some prefix so
                //    that it's not 16 bytes.
                new_filename = if new_filename.len() == 16 {
                    format!("lldb-fix-{}", new_filename)
                } else {
                    new_filename
                };

                let present = self.members.iter().filter_map(|p| {
                    p.file_name().and_then(|f| f.to_str())
                }).any(|s| s == new_filename);
                if !present {
                    break
                }
            }
            let dst = self.work_dir.path().join(&new_filename);
            try!(try!(File::create(&dst)).write_all(file.data()));
            self.members.push(PathBuf::from(new_filename));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::error::Error as StdError;
use crate::ffi::{CString, CStr, OsString, OsStr};
use crate::fmt;
use crate::io;
use crate::iter;
use libc::{self, c_int, c_char /*,c_void */};
use crate::marker::PhantomData;
use crate::mem;
use crate::memchr;
use crate::path::{self, PathBuf, Path};
use crate::ptr;
use crate::slice;
use crate::str;
use crate::sys_common::mutex::Mutex;
use crate::sys::cvt;
/*use sys::fd; this one is probably important */
use crate::vec;

const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();

// This is a terrible fix
use crate::sys::os_str::Buf;
use crate::sys_common::{FromInner, IntoInner, AsInner};

pub trait OsStringExt {
    fn from_vec(vec: Vec<u8>) -> Self;
    fn into_vec(self) -> Vec<u8>;
}

impl OsStringExt for OsString {
    fn from_vec(vec: Vec<u8>) -> OsString {
        FromInner::from_inner(Buf { inner: vec })
    }
    fn into_vec(self) -> Vec<u8> {
        self.into_inner().inner
    }
}

pub trait OsStrExt {
    fn from_bytes(slice: &[u8]) -> &Self;
    fn as_bytes(&self) -> &[u8];
}

impl OsStrExt for OsStr {
    fn from_bytes(slice: &[u8]) -> &OsStr {
        unsafe { mem::transmute(slice) }
    }
    fn as_bytes(&self) -> &[u8] {
        &self.as_inner().inner
    }
}

pub fn errno() -> i32 {
    unsafe { libc::errnoGet() }
}

pub fn set_errno(e: i32) {
    unsafe { libc::errnoSet(e as c_int); }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    let mut buf = [0 as c_char; TMPBUF_SZ];
    extern {
        fn strerror_r(
            errnum: c_int,
            buf: *mut c_char,
            buflen: libc::size_t
        ) -> c_int;
    }

    let p = buf.as_mut_ptr();
    unsafe {
        if strerror_r(errno as c_int, p, buf.len()) < 0 {
            panic!("strerror_r failure");
        }
        let p = p as *const _;
        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = Vec::with_capacity(512);
    loop {
        unsafe {
            let ptr = buf.as_mut_ptr() as *mut libc::c_char;
            if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() {
                let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
                buf.set_len(len);
                buf.shrink_to_fit();
                return Ok(PathBuf::from(OsString::from_vec(buf)));
            } else {
                let error = io::Error::last_os_error();
                if error.raw_os_error() != Some(libc::ERANGE) {
                    return Err(error);
                }
            }
            // Trigger the internal buffer resizing logic of `Vec` by requiring
            // more space than the current capacity.
            let cap = buf.capacity();
            buf.set_len(cap);
            buf.reserve(1);
        }
    }
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let p = CString::new(p.as_bytes())?;
    unsafe {
        match libc::chdir(p.as_ptr()) == (0 as c_int) {
            true => Ok(()),
            false => Err(io::Error::last_os_error()),
        }
    }
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
            fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_colon(b: &u8) -> bool { *b == b':' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_colon as fn(&u8) -> bool)
                        .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b':';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 {
            joined.push(sep)
        }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    #[cfg(test)]
    use realstd::env;

    #[cfg(not(test))]
    use crate::env;

    let exe_path = env::args().next().unwrap();
    let path = Path::new(&exe_path);
    path.canonicalize()
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

pub unsafe fn environ() -> *mut *const *const c_char {
    extern { static mut environ: *const *const c_char; }
    &mut environ
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    unsafe {
        let _guard = ENV_LOCK.lock();
        let mut environ = *environ();
        if environ == ptr::null() {
            panic!("os::env() failure getting env string from OS: {}",
                io::Error::last_os_error());
        }
        let mut result = Vec::new();
        while *environ != ptr::null() {
            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
                result.push(key_value);
            }
            environ = environ.offset(1);
        }
        return Env {
            iter: result.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
        // Strategy (copied from glibc): Variable name and value are separated
        // by an ASCII equals sign '='. Since a variable name must not be
        // empty, allow variable names starting with an equals sign. Skip all
        // malformed lines.
        if input.is_empty() {
            return None;
        }
        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
        pos.map(|p| (
            OsStringExt::from_vec(input[..p].to_vec()),
            OsStringExt::from_vec(input[p+1..].to_vec()),
        ))
    }
}

pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
    // environment variables with a nul byte can't be set, so their value is
    // always None as well
    let k = CString::new(k.as_bytes())?;
    unsafe {
        let _guard = ENV_LOCK.lock();
        let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
        let ret = if s.is_null() {
            None
        } else {
            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
        };
        Ok(ret)
    }
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = CString::new(k.as_bytes())?;
    let v = CString::new(v.as_bytes())?;

    unsafe {
        let _guard = ENV_LOCK.lock();
        cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
    }
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let nbuf = CString::new(n.as_bytes())?;

    unsafe {
        let _guard = ENV_LOCK.lock();
        cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
    }
}

pub fn page_size() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
}

pub fn temp_dir() -> PathBuf {
    crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    None
}

pub fn exit(code: i32) -> ! {
    unsafe { libc::exit(code as c_int) }
}

pub fn getpid() -> u32 {
    unsafe { libc::getpid() as u32 }
}

pub fn getppid() -> u32 {
    unsafe { libc::getppid() as u32 }
}
<commit_msg>Implemented the home_dir for VxWorks<commit_after>use crate::error::Error as StdError;
use crate::ffi::{CString, CStr, OsString, OsStr};
use crate::fmt;
use crate::io;
use crate::iter;
use libc::{self, c_int, c_char /*,c_void */};
use crate::marker::PhantomData;
use crate::mem;
use crate::memchr;
use crate::path::{self, PathBuf, Path};
use crate::ptr;
use crate::slice;
use crate::str;
use crate::sys_common::mutex::Mutex;
use crate::sys::cvt;
/*use sys::fd; this one is probably important */
use crate::vec;

const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();

// This is a terrible fix
use crate::sys::os_str::Buf;
use crate::sys_common::{FromInner, IntoInner, AsInner};

pub trait OsStringExt {
    fn from_vec(vec: Vec<u8>) -> Self;
    fn into_vec(self) -> Vec<u8>;
}

impl OsStringExt for OsString {
    fn from_vec(vec: Vec<u8>) -> OsString {
        FromInner::from_inner(Buf { inner: vec })
    }
    fn into_vec(self) -> Vec<u8> {
        self.into_inner().inner
    }
}

pub trait OsStrExt {
    fn from_bytes(slice: &[u8]) -> &Self;
    fn as_bytes(&self) -> &[u8];
}

impl OsStrExt for OsStr {
    fn from_bytes(slice: &[u8]) -> &OsStr {
        unsafe { mem::transmute(slice) }
    }
    fn as_bytes(&self) -> &[u8] {
        &self.as_inner().inner
    }
}

pub fn errno() -> i32 {
    unsafe { libc::errnoGet() }
}

pub fn set_errno(e: i32) {
    unsafe { libc::errnoSet(e as c_int); }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    let mut buf = [0 as c_char; TMPBUF_SZ];
    extern {
        fn strerror_r(
            errnum: c_int,
            buf: *mut c_char,
            buflen: libc::size_t
        ) -> c_int;
    }

    let p = buf.as_mut_ptr();
    unsafe {
        if strerror_r(errno as c_int, p, buf.len()) < 0 {
            panic!("strerror_r failure");
        }
        let p = p as *const _;
        str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = Vec::with_capacity(512);
    loop {
        unsafe {
            let ptr = buf.as_mut_ptr() as *mut libc::c_char;
            if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() {
                let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
                buf.set_len(len);
                buf.shrink_to_fit();
                return Ok(PathBuf::from(OsString::from_vec(buf)));
            } else {
                let error = io::Error::last_os_error();
                if error.raw_os_error() != Some(libc::ERANGE) {
                    return Err(error);
                }
            }
            // Trigger the internal buffer resizing logic of `Vec` by requiring
            // more space than the current capacity.
            let cap = buf.capacity();
            buf.set_len(cap);
            buf.reserve(1);
        }
    }
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    let p: &OsStr = p.as_ref();
    let p = CString::new(p.as_bytes())?;
    unsafe {
        match libc::chdir(p.as_ptr()) == (0 as c_int) {
            true => Ok(()),
            false => Err(io::Error::last_os_error()),
        }
    }
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
            fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_colon(b: &u8) -> bool { *b == b':' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_colon as fn(&u8) -> bool)
                        .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b':';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 {
            joined.push(sep)
        }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    #[cfg(test)]
    use realstd::env;

    #[cfg(not(test))]
    use crate::env;

    let exe_path = env::args().next().unwrap();
    let path = Path::new(&exe_path);
    path.canonicalize()
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

pub unsafe fn environ() -> *mut *const *const c_char {
    extern { static mut environ: *const *const c_char; }
    &mut environ
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    unsafe {
        let _guard = ENV_LOCK.lock();
        let mut environ = *environ();
        if environ == ptr::null() {
            panic!("os::env() failure getting env string from OS: {}",
                io::Error::last_os_error());
        }
        let mut result = Vec::new();
        while *environ != ptr::null() {
            if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
                result.push(key_value);
            }
            environ = environ.offset(1);
        }
        return Env {
            iter: result.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
        // Strategy (copied from glibc): Variable name and value are separated
        // by an ASCII equals sign '='. Since a variable name must not be
        // empty, allow variable names starting with an equals sign. Skip all
        // malformed lines.
        if input.is_empty() {
            return None;
        }
        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
        pos.map(|p| (
            OsStringExt::from_vec(input[..p].to_vec()),
            OsStringExt::from_vec(input[p+1..].to_vec()),
        ))
    }
}

pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
    // environment variables with a nul byte can't be set, so their value is
    // always None as well
    let k = CString::new(k.as_bytes())?;
    unsafe {
        let _guard = ENV_LOCK.lock();
        let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
        let ret = if s.is_null() {
            None
        } else {
            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
        };
        Ok(ret)
    }
}

pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
    let k = CString::new(k.as_bytes())?;
    let v = CString::new(v.as_bytes())?;

    unsafe {
        let _guard = ENV_LOCK.lock();
        cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
    }
}

pub fn unsetenv(n: &OsStr) -> io::Result<()> {
    let nbuf = CString::new(n.as_bytes())?;

    unsafe {
        let _guard = ENV_LOCK.lock();
        cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
    }
}

pub fn page_size() -> usize {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as usize
    }
}

pub fn temp_dir() -> PathBuf {
    crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    crate::env::var_os("HOME").or_else(|| None
    ).map(PathBuf::from)
}

pub fn exit(code: i32) -> ! {
    unsafe { libc::exit(code as c_int) }
}

pub fn getpid() -> u32 {
    unsafe { libc::getpid() as u32 }
}

pub fn getppid() -> u32 {
    unsafe { libc::getppid() as u32 }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, ilammy
//
// Licensed under MIT license (see LICENSE file in the root directory).
// This file may be copied, distributed, and modified only in accordance
// with the terms specified by this license.

//! Diagnostic reporting.
//!
//! This module contains types and functions used to generate, format, and report **diagnostics**:
//! error and warning messages, notifications, etc.

use std::cell::RefCell;

/// Span of a token or an expression.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span {
    /// Byte offset of the first character of the span.
    pub from: usize,

    /// Byte offset of the first character following the span (after the last character).
    pub to: usize,
}

impl Span {
    /// Makes a new span with given bounds.
    pub fn new(from: usize, to: usize) -> Span {
        assert!(from <= to);
        Span { from: from, to: to }
    }
}

/// Severity of a diagnostic.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Severity {
    /// The code is incorrect and the parser is unlikely to recover.
    Fatal,

    /// The code is incorrect.
    Error,
}

/// Reporter interface.
///
/// Reporters are used to... report various errors, warnings, suggestions, threats, (collectively
/// known as _diagnostics_) which are encountered while processing the source code.
pub trait Reporter {
    /// Report a diagnostic with given severity, message, and optional location.
    fn report(&mut self, severity: Severity, message: &str, loc: Option<Span>);
}

/// Convenience wrapper for easy reporting of diagnostics related to spans of source code.
pub struct Handler {
    reporter: RefCell<Box<Reporter>>,
}

impl Handler {
    /// Constructs a new Handler for a given reporter.
    pub fn with_reporter(reporter: Box<Reporter>) -> Handler {
        Handler {
            reporter: RefCell::new(reporter)
        }
    }

    /// Reports a fatal error at given span with the given message.
    pub fn fatal(&self, span: Span, message: &str) {
        self.reporter.borrow_mut().report(Severity::Fatal, message, Some(span));
    }

    /// Reports an error at given span with the given message.
    pub fn error(&self, span: Span, message: &str) {
        self.reporter.borrow_mut().report(Severity::Error, message, Some(span));
    }
}
<commit_msg>Introduce DiagnosticBuilder<commit_after>// Copyright (c) 2015, ilammy
//
// Licensed under MIT license (see LICENSE file in the root directory).
// This file may be copied, distributed, and modified only in accordance
// with the terms specified by this license.

//! Diagnostic reporting.
//!
//! This module contains types and functions used to generate, format, and report **diagnostics**:
//! error and warning messages, notifications, etc.

use std::cell::RefCell;

/// Span of a token or an expression.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Span {
    /// Byte offset of the first character of the span.
    pub from: usize,

    /// Byte offset of the first character following the span (after the last character).
    pub to: usize,
}

impl Span {
    /// Makes a new span with given bounds.
    pub fn new(from: usize, to: usize) -> Span {
        assert!(from <= to);
        Span { from: from, to: to }
    }
}

/// Severity of a diagnostic.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Severity {
    /// The code is incorrect and the parser is unlikely to recover.
    Fatal,

    /// The code is incorrect.
    Error,
}

/// Reporter interface.
///
/// Reporters are used to... report various errors, warnings, suggestions, threats, (collectively
/// known as _diagnostics_) which are encountered while processing the source code.
pub trait Reporter {
    /// Report a diagnostic with given severity, message, and optional location.
    fn report(&mut self, severity: Severity, message: &str, loc: Option<Span>);
}

/// Convenience wrapper for easy reporting of diagnostics related to spans of source code.
///
/// The diagnostics may be reported either immediately using methods like
/// [`error()`](#method.error), or they can be constructed incrementally with the help of methods
/// like [`prepare_error()`](#method.prepare_error).
pub struct Handler {
    reporter: RefCell<Box<Reporter>>,
}

impl Handler {
    /// Constructs a new Handler for a given reporter.
    pub fn with_reporter(reporter: Box<Reporter>) -> Handler {
        Handler {
            reporter: RefCell::new(reporter)
        }
    }

    /// Reports a fatal error at given span with the given message.
    pub fn fatal(&self, span: Span, message: &str) {
        self.reporter.borrow_mut().report(Severity::Fatal, message, Some(span));
    }

    /// Reports an error at given span with the given message.
    pub fn error(&self, span: Span, message: &str) {
        self.reporter.borrow_mut().report(Severity::Error, message, Some(span));
    }

    /// Start building a fatal error at given span with the given message.
    pub fn prepare_fatal<'a>(&'a self, span: Span, message: &str) -> DiagnosticBuilder<'a> {
        let mut diagnostic = DiagnosticBuilder::new(&self.reporter, Severity::Fatal, message);
        diagnostic.span(span);
        return diagnostic;
    }

    /// Start building an error at given span with the given message.
    pub fn prepare_error<'a>(&'a self, span: Span, message: &str) -> DiagnosticBuilder<'a> {
        let mut diagnostic = DiagnosticBuilder::new(&self.reporter, Severity::Error, message);
        diagnostic.span(span);
        return diagnostic;
    }
}

/// Delayed diagnostic builder.
///
/// Some errors produce diagnostics which may be refined on upper processsing levels. This builder
/// allows to construct an initial diagnostic and keep this data around while the error bubbles up
/// to higher levels. Callers may fill in additional data before finally reporting the diagnostic.
///
/// Builders cannot be directly instantiated. Use [`Handler`'s](struct.Handler.html) methods like
/// [`prepare_fatal()`](struct.Handler.html#method.prepare_fatal) to start building a diagnostic.
/// The diagnostic can then be reported to the handler's `Reporter` with
/// [`report()`](#method.report).
///
/// The builder is marked with `#[must_use]` and will panic if [`report()`](#method.report)
/// has not been called during its lifetime. This ensures that diagnostics cannot be lost
/// during processing.
#[must_use]
pub struct DiagnosticBuilder<'a> {
    /// The reporter that will be used to report this diagnostic when it is complete.
    reporter: &'a RefCell<Box<Reporter>>,

    /// Set to true when the diagnostic has been reported.
    completed: bool,

    /// Diagnostic severity.
    severity: Severity,

    /// Diagnostic message.
    message: String,

    /// Diagnostic location (optional).
    location: Option<Span>,
}

impl<'a> DiagnosticBuilder<'a> {
    /// Make a new diagnostic builder.
    ///
    /// This is an internal convenience wrapper for builder construction. Use Handler's methods
    /// to instantiate properly filled-in diagnostic builders.
    fn new(reporter: &'a RefCell<Box<Reporter>>, severity: Severity, message: &str)
        -> DiagnosticBuilder<'a>
    {
        DiagnosticBuilder {
            reporter: reporter,
            completed: false,
            severity: severity,
            message: message.to_owned(),
            location: None,
        }
    }

    /// Report the complete diagnostic.
    ///
    /// Each diagnostic is reported only once.
    pub fn report(&mut self) {
        if self.completed {
            return;
        }
        self.reporter.borrow_mut().report(self.severity, &self.message, self.location);
        self.completed = true;
    }

    /// Set the span of the diagnostic.
    pub fn span(&mut self, span: Span) -> &mut Self {
        self.location = Some(span);
        self
    }
}

/// Panic if the constructed diagnostic has not been reported yet.
impl<'a> Drop for DiagnosticBuilder<'a> {
    fn drop(&mut self) {
        if !self.completed {
            panic!("dropped incomplete diagnostic")
        }
    }
}
<|endoftext|>


<commit_before>// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80
// characters.  In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use
// `:set tw=0` to disable.
register_diagnostics! {

E0178: r##"
In types, the `+` type operator has low precedence, so it is often necessary
to use parentheses.

For example:

```compile_fail,E0178
trait Foo {}

struct Bar<'a> {
    w: &'a Foo + Copy,   // error, use &'a (Foo + Copy)
    x: &'a Foo + 'a,     // error, use &'a (Foo + 'a)
    y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)
    z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)
}
```

More details can be found in [RFC 438].

[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
"##,

E0536: r##"
The `not` cfg-predicate was malformed.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` predicate expects one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0537: r##"
An unknown predicate was used inside the `cfg` attribute.

Erroneous code example:

```compile_fail,E0537
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

pub fn main() {}
```

The `cfg` attribute supports only three kinds of predicates:

 * any
 * all
 * not

Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0538: r##"
Attribute contains same meta item more than once.

Erroneous code example:

```compile_fail,E0538
#[deprecated(
    since="1.0.0",
    note="First deprecation note.",
    note="Second deprecation note." // error: multiple same meta item
)]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. Each key may only be
used once in each attribute.

To fix the problem, remove all but one of the meta items with the same key.

Example:

```
#[deprecated(
    since="1.0.0",
    note="First deprecation note."
)]
fn deprecated_function() {}
```
"##,

E0541: r##"
An unknown meta item was used.

Erroneous code example:

```compile_fail,E0541
#[deprecated(
    since="1.0.0",
    // error: unknown meta item
    reason="Example invalid meta item. Should be 'note'")
]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. The keys provided
must be one of the valid keys for the specified attribute.

To fix the problem, either remove the unknown meta item, or rename it if you
provided the wrong name.

In the erroneous code example above, the wrong name was provided, so changing
to a correct one it will fix the error. Example:

```
#[deprecated(
    since="1.0.0",
    note="This is a valid meta item for the deprecated attribute."
)]
fn deprecated_function() {}
```
"##,

E0550: r##"
More than one `deprecated` attribute has been put on an item.

Erroneous code example:

```compile_fail,E0550
#[deprecated(note = "because why not?")]
#[deprecated(note = "right?")] // error!
fn the_banished() {}
```

The `deprecated` attribute can only be present **once** on an item.

```
#[deprecated(note = "because why not, right?")]
fn the_banished() {} // ok!
```
"##,

E0552: r##"
A unrecognized representation attribute was used.

Erroneous code example:

```compile_fail,E0552
#[repr(D)] // error: unrecognized representation hint
struct MyStruct {
    my_field: usize
}
```

You can use a `repr` attribute to tell the compiler how you want a struct or
enum to be laid out in memory.

Make sure you're using one of the supported options:

```
#[repr(C)] // ok!
struct MyStruct {
    my_field: usize
}
```

For more information about specifying representations, see the ["Alternative
Representations" section] of the Rustonomicon.

["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html
"##,

E0554: r##"
Feature attributes are only allowed on the nightly release channel. Stable or
beta compilers will not comply.

Example of erroneous code (on a stable compiler):

```ignore (depends on release channel)
#![feature(non_ascii_idents)] // error: `#![feature]` may not be used on the
                              //        stable release channel
```

If you need the feature, make sure to use a nightly release of the compiler
(but be warned that the feature may be removed or altered in the future).
"##,

E0557: r##"
A feature attribute named a feature that has been removed.

Erroneous code example:

```compile_fail,E0557
#![feature(managed_boxes)] // error: feature has been removed
```

Delete the offending feature attribute.
"##,

E0565: r##"
A literal was used in a built-in attribute that doesn't support literals.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[inline("always")] // error: unsupported literal
pub fn something() {}
```

Literals in attributes are new and largely unsupported in built-in attributes.
Work to support literals where appropriate is ongoing. Try using an unquoted
name instead:

```
#[inline(always)]
pub fn something() {}
```
"##,

E0583: r##"
A file wasn't found for an out-of-line module.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
mod file_that_doesnt_exist; // error: file not found for module

fn main() {}
```

Please be sure that a file corresponding to the module exists. If you
want to use a module named `file_that_doesnt_exist`, you need to have a file
named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the
same directory.
"##,

E0585: r##"
A documentation comment that doesn't document anything was found.

Erroneous code example:

```compile_fail,E0585
fn main() {
    // The following doc comment will fail:
    /// This is a useless doc comment!
}
```

Documentation comments need to be followed by items, including functions,
types, modules, etc. Examples:

```
/// I'm documenting the following struct:
struct Foo;

/// I'm documenting the following function:
fn foo() {}
```
"##,

E0586: r##"
An inclusive range was used with no end.

Erroneous code example:

```compile_fail,E0586
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=]; // error: inclusive range was used with no end
}
```

An inclusive range needs an end in order to *include* it. If you just need a
start and no end, use a non-inclusive range (with `..`):

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..]; // ok!
}
```

Or put an end to your inclusive range:

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=3]; // ok!
}
```
"##,

E0589: r##"
The value of `N` that was specified for `repr(align(N))` was not a power
of two, or was greater than 2^29.

```compile_fail,E0589
#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
enum Foo {
    Bar(u64),
}
```
"##,

E0658: r##"
An unstable feature was used.

Erroneous code example:

```compile_fail,E658
#[repr(u128)] // error: use of unstable library feature 'repr128'
enum Foo {
    Bar(u64),
}
```

If you're using a stable or a beta version of rustc, you won't be able to use
any unstable features. In order to do so, please switch to a nightly version of
rustc (by using rustup).

If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:

```
#![feature(repr128)]

#[repr(u128)] // ok!
enum Foo {
    Bar(u64),
}
```
"##,

E0633: r##"
The `unwind` attribute was malformed.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[unwind()] // error: expected one argument
pub extern fn something() {}

fn main() {}
```

The `#[unwind]` attribute should be used as follows:

- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
  should abort the process if it attempts to unwind. This is the safer
  and preferred option.

- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
  should be allowed to unwind. This can easily result in Undefined
  Behavior (UB), so be careful.

NB. The default behavior here is "allowed", but this is unspecified
and likely to change in the future.

"##,

E0704: r##"
This error indicates that a incorrect visibility restriction was specified.

Example of erroneous code:

```compile_fail,E0704
mod foo {
    pub(foo) struct Bar {
        x: i32
    }
}
```

To make struct `Bar` only visible in module `foo` the `in` keyword should be
used:
```
mod foo {
    pub(in crate::foo) struct Bar {
        x: i32
    }
}
# fn main() {}
```

For more information see the Rust Reference on [Visibility].

[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
"##,

E0705: r##"
A `#![feature]` attribute was declared for a feature that is stable in
the current edition, but not in all editions.

Erroneous code example:

```ignore (limited to a warning during 2018 edition development)
#![feature(rust_2018_preview)]
#![feature(test_2018_feature)] // error: the feature
                               // `test_2018_feature` is
                               // included in the Rust 2018 edition
```

"##,

E0725: r##"
A feature attribute named a feature that was disallowed in the compiler
command line flags.

Erroneous code example:

```ignore (can't specify compiler flags from doctests)
#![feature(never_type)] // error: the feature `never_type` is not in
                        // the list of allowed features
```

Delete the offending feature attribute, or add it to the list of allowed
features in the `-Z allow_features` flag.
"##,

;

    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
//  E0548, // replaced with a generic attribute input check
    // rustc_deprecated attribute must be paired with either stable or unstable
    // attribute
    E0549,
    E0551, // incorrect meta item
    E0553, // multiple rustc_const_unstable attributes
//  E0555, // replaced with a generic attribute input check
    E0556, // malformed feature, expected just one word
    E0584, // file for module `..` found at both .. and ..
    E0629, // missing 'feature' (rustc_const_unstable)
    // rustc_const_unstable attribute must be paired with stable/unstable
    // attribute
    E0630,
    E0693, // incorrect `repr(align)` attribute format
//  E0694, // an unknown tool name found in scoped attributes
    E0703, // invalid ABI
    E0717, // rustc_promotable without stability attribute
}
<commit_msg>Add E0551 long error explanation<commit_after>// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80
// characters.  In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use
// `:set tw=0` to disable.
register_diagnostics! {

E0178: r##"
In types, the `+` type operator has low precedence, so it is often necessary
to use parentheses.

For example:

```compile_fail,E0178
trait Foo {}

struct Bar<'a> {
    w: &'a Foo + Copy,   // error, use &'a (Foo + Copy)
    x: &'a Foo + 'a,     // error, use &'a (Foo + 'a)
    y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)
    z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)
}
```

More details can be found in [RFC 438].

[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
"##,

E0536: r##"
The `not` cfg-predicate was malformed.

Erroneous code example:

```compile_fail,E0536
#[cfg(not())] // error: expected 1 cfg-pattern
pub fn something() {}

pub fn main() {}
```

The `not` predicate expects one cfg-pattern. Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0537: r##"
An unknown predicate was used inside the `cfg` attribute.

Erroneous code example:

```compile_fail,E0537
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

pub fn main() {}
```

The `cfg` attribute supports only three kinds of predicates:

 * any
 * all
 * not

Example:

```
#[cfg(not(target_os = "linux"))] // ok!
pub fn something() {}

pub fn main() {}
```

For more information about the cfg attribute, read:
https://doc.rust-lang.org/reference.html#conditional-compilation
"##,

E0538: r##"
Attribute contains same meta item more than once.

Erroneous code example:

```compile_fail,E0538
#[deprecated(
    since="1.0.0",
    note="First deprecation note.",
    note="Second deprecation note." // error: multiple same meta item
)]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. Each key may only be
used once in each attribute.

To fix the problem, remove all but one of the meta items with the same key.

Example:

```
#[deprecated(
    since="1.0.0",
    note="First deprecation note."
)]
fn deprecated_function() {}
```
"##,

E0541: r##"
An unknown meta item was used.

Erroneous code example:

```compile_fail,E0541
#[deprecated(
    since="1.0.0",
    // error: unknown meta item
    reason="Example invalid meta item. Should be 'note'")
]
fn deprecated_function() {}
```

Meta items are the key-value pairs inside of an attribute. The keys provided
must be one of the valid keys for the specified attribute.

To fix the problem, either remove the unknown meta item, or rename it if you
provided the wrong name.

In the erroneous code example above, the wrong name was provided, so changing
to a correct one it will fix the error. Example:

```
#[deprecated(
    since="1.0.0",
    note="This is a valid meta item for the deprecated attribute."
)]
fn deprecated_function() {}
```
"##,

E0550: r##"
More than one `deprecated` attribute has been put on an item.

Erroneous code example:

```compile_fail,E0550
#[deprecated(note = "because why not?")]
#[deprecated(note = "right?")] // error!
fn the_banished() {}
```

The `deprecated` attribute can only be present **once** on an item.

```
#[deprecated(note = "because why not, right?")]
fn the_banished() {} // ok!
```
"##,

E0551: r##"
An invalid meta-item was used inside an attribute.

Erroneous code example:

```compile_fail,E0551
#[deprecated(note)] // error!
fn i_am_deprecated() {}
```

Meta items are the key-value pairs inside of an attribute. To fix this issue,
you need to give a value to the `note` key. Example:

```
#[deprecated(note = "because")] // ok!
fn i_am_deprecated() {}
```
"##,

E0552: r##"
A unrecognized representation attribute was used.

Erroneous code example:

```compile_fail,E0552
#[repr(D)] // error: unrecognized representation hint
struct MyStruct {
    my_field: usize
}
```

You can use a `repr` attribute to tell the compiler how you want a struct or
enum to be laid out in memory.

Make sure you're using one of the supported options:

```
#[repr(C)] // ok!
struct MyStruct {
    my_field: usize
}
```

For more information about specifying representations, see the ["Alternative
Representations" section] of the Rustonomicon.

["Alternative Representations" section]: https://doc.rust-lang.org/nomicon/other-reprs.html
"##,

E0554: r##"
Feature attributes are only allowed on the nightly release channel. Stable or
beta compilers will not comply.

Example of erroneous code (on a stable compiler):

```ignore (depends on release channel)
#![feature(non_ascii_idents)] // error: `#![feature]` may not be used on the
                              //        stable release channel
```

If you need the feature, make sure to use a nightly release of the compiler
(but be warned that the feature may be removed or altered in the future).
"##,

E0557: r##"
A feature attribute named a feature that has been removed.

Erroneous code example:

```compile_fail,E0557
#![feature(managed_boxes)] // error: feature has been removed
```

Delete the offending feature attribute.
"##,

E0565: r##"
A literal was used in a built-in attribute that doesn't support literals.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[inline("always")] // error: unsupported literal
pub fn something() {}
```

Literals in attributes are new and largely unsupported in built-in attributes.
Work to support literals where appropriate is ongoing. Try using an unquoted
name instead:

```
#[inline(always)]
pub fn something() {}
```
"##,

E0583: r##"
A file wasn't found for an out-of-line module.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
mod file_that_doesnt_exist; // error: file not found for module

fn main() {}
```

Please be sure that a file corresponding to the module exists. If you
want to use a module named `file_that_doesnt_exist`, you need to have a file
named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the
same directory.
"##,

E0585: r##"
A documentation comment that doesn't document anything was found.

Erroneous code example:

```compile_fail,E0585
fn main() {
    // The following doc comment will fail:
    /// This is a useless doc comment!
}
```

Documentation comments need to be followed by items, including functions,
types, modules, etc. Examples:

```
/// I'm documenting the following struct:
struct Foo;

/// I'm documenting the following function:
fn foo() {}
```
"##,

E0586: r##"
An inclusive range was used with no end.

Erroneous code example:

```compile_fail,E0586
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=]; // error: inclusive range was used with no end
}
```

An inclusive range needs an end in order to *include* it. If you just need a
start and no end, use a non-inclusive range (with `..`):

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..]; // ok!
}
```

Or put an end to your inclusive range:

```
fn main() {
    let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1];
    let x = &tmp[1..=3]; // ok!
}
```
"##,

E0589: r##"
The value of `N` that was specified for `repr(align(N))` was not a power
of two, or was greater than 2^29.

```compile_fail,E0589
#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
enum Foo {
    Bar(u64),
}
```
"##,

E0658: r##"
An unstable feature was used.

Erroneous code example:

```compile_fail,E658
#[repr(u128)] // error: use of unstable library feature 'repr128'
enum Foo {
    Bar(u64),
}
```

If you're using a stable or a beta version of rustc, you won't be able to use
any unstable features. In order to do so, please switch to a nightly version of
rustc (by using rustup).

If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:

```
#![feature(repr128)]

#[repr(u128)] // ok!
enum Foo {
    Bar(u64),
}
```
"##,

E0633: r##"
The `unwind` attribute was malformed.

Erroneous code example:

```ignore (compile_fail not working here; see Issue #43707)
#[unwind()] // error: expected one argument
pub extern fn something() {}

fn main() {}
```

The `#[unwind]` attribute should be used as follows:

- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
  should abort the process if it attempts to unwind. This is the safer
  and preferred option.

- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
  should be allowed to unwind. This can easily result in Undefined
  Behavior (UB), so be careful.

NB. The default behavior here is "allowed", but this is unspecified
and likely to change in the future.

"##,

E0704: r##"
This error indicates that a incorrect visibility restriction was specified.

Example of erroneous code:

```compile_fail,E0704
mod foo {
    pub(foo) struct Bar {
        x: i32
    }
}
```

To make struct `Bar` only visible in module `foo` the `in` keyword should be
used:
```
mod foo {
    pub(in crate::foo) struct Bar {
        x: i32
    }
}
# fn main() {}
```

For more information see the Rust Reference on [Visibility].

[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html
"##,

E0705: r##"
A `#![feature]` attribute was declared for a feature that is stable in
the current edition, but not in all editions.

Erroneous code example:

```ignore (limited to a warning during 2018 edition development)
#![feature(rust_2018_preview)]
#![feature(test_2018_feature)] // error: the feature
                               // `test_2018_feature` is
                               // included in the Rust 2018 edition
```

"##,

E0725: r##"
A feature attribute named a feature that was disallowed in the compiler
command line flags.

Erroneous code example:

```ignore (can't specify compiler flags from doctests)
#![feature(never_type)] // error: the feature `never_type` is not in
                        // the list of allowed features
```

Delete the offending feature attribute, or add it to the list of allowed
features in the `-Z allow_features` flag.
"##,

;

    E0539, // incorrect meta item
    E0540, // multiple rustc_deprecated attributes
    E0542, // missing 'since'
    E0543, // missing 'reason'
    E0544, // multiple stability levels
    E0545, // incorrect 'issue'
    E0546, // missing 'feature'
    E0547, // missing 'issue'
//  E0548, // replaced with a generic attribute input check
    // rustc_deprecated attribute must be paired with either stable or unstable
    // attribute
    E0549,
    E0553, // multiple rustc_const_unstable attributes
//  E0555, // replaced with a generic attribute input check
    E0556, // malformed feature, expected just one word
    E0584, // file for module `..` found at both .. and ..
    E0629, // missing 'feature' (rustc_const_unstable)
    // rustc_const_unstable attribute must be paired with stable/unstable
    // attribute
    E0630,
    E0693, // incorrect `repr(align)` attribute format
//  E0694, // an unknown tool name found in scoped attributes
    E0703, // invalid ABI
    E0717, // rustc_promotable without stability attribute
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::path::Path;
use std::str;

use semver::Version;
use serde_json;

use core::dependency::Dependency;
use core::{PackageId, SourceId, Summary};
use sources::registry::RegistryData;
use sources::registry::{RegistryPackage, INDEX_LOCK};
use util::{internal, CargoResult, Config, Filesystem};

pub struct RegistryIndex<'cfg> {
    source_id: SourceId,
    path: Filesystem,
    cache: HashMap<&'static str, Vec<(Summary, bool)>>,
    hashes: HashMap<&'static str, HashMap<Version, String>>, // (name, vers) => cksum
    config: &'cfg Config,
    locked: bool,
}

impl<'cfg> RegistryIndex<'cfg> {
    pub fn new(
        id: &SourceId,
        path: &Filesystem,
        config: &'cfg Config,
        locked: bool,
    ) -> RegistryIndex<'cfg> {
        RegistryIndex {
            source_id: id.clone(),
            path: path.clone(),
            cache: HashMap::new(),
            hashes: HashMap::new(),
            config,
            locked,
        }
    }

    /// Return the hash listed for a specified PackageId.
    pub fn hash(&mut self, pkg: &PackageId, load: &mut RegistryData) -> CargoResult<String> {
        let name = pkg.name().as_str();
        let version = pkg.version();
        if let Some(s) = self.hashes.get(name).and_then(|v| v.get(version)) {
            return Ok(s.clone());
        }
        // Ok, we're missing the key, so parse the index file to load it.
        self.summaries(name, load)?;
        self.hashes
            .get(name)
            .and_then(|v| v.get(version))
            .ok_or_else(|| internal(format!("no hash listed for {}", pkg)))
            .map(|s| s.clone())
    }

    /// Parse the on-disk metadata for the package provided
    ///
    /// Returns a list of pairs of (summary, yanked) for the package name
    /// specified.
    pub fn summaries(
        &mut self,
        name: &'static str,
        load: &mut RegistryData,
    ) -> CargoResult<&Vec<(Summary, bool)>> {
        if self.cache.contains_key(name) {
            return Ok(&self.cache[name]);
        }
        let summaries = self.load_summaries(name, load)?;
        self.cache.insert(name, summaries);
        Ok(&self.cache[name])
    }

    fn load_summaries(
        &mut self,
        name: &str,
        load: &mut RegistryData,
    ) -> CargoResult<Vec<(Summary, bool)>> {
        // Prepare the `RegistryData` which will lazily initialize internal data
        // structures. Note that this is also importantly needed to initialize
        // to avoid deadlocks where we acquire a lock below but the `load`
        // function inside *also* wants to acquire a lock. See an instance of
        // this on #5551.
        load.prepare()?;
        let (root, _lock) = if self.locked {
            let lock = self
                .path
                .open_ro(Path::new(INDEX_LOCK), self.config, "the registry index");
            match lock {
                Ok(lock) => (lock.path().parent().unwrap().to_path_buf(), Some(lock)),
                Err(_) => return Ok(Vec::new()),
            }
        } else {
            (self.path.clone().into_path_unlocked(), None)
        };

        let fs_name = name
            .chars()
            .flat_map(|c| c.to_lowercase())
            .collect::<String>();

        // see module comment for why this is structured the way it is
        let path = match fs_name.len() {
            1 => format!("1/{}", fs_name),
            2 => format!("2/{}", fs_name),
            3 => format!("3/{}/{}", &fs_name[..1], fs_name),
            _ => format!("{}/{}/{}", &fs_name[0..2], &fs_name[2..4], fs_name),
        };
        let mut ret = Vec::new();
        let mut hit_closure = false;
        let err = load.load(&root, Path::new(&path), &mut |contents| {
            hit_closure = true;
            let contents = str::from_utf8(contents)
                .map_err(|_| format_err!("registry index file was not valid utf-8"))?;
            ret.reserve(contents.lines().count());
            let lines = contents.lines().map(|s| s.trim()).filter(|l| !l.is_empty());

            let online = !self.config.cli_unstable().offline;
            // Attempt forwards-compatibility on the index by ignoring
            // everything that we ourselves don't understand, that should
            // allow future cargo implementations to break the
            // interpretation of each line here and older cargo will simply
            // ignore the new lines.
            ret.extend(lines.filter_map(|line| {
                let (summary, locked) = match self.parse_registry_package(line) {
                    Ok(p) => p,
                    Err(e) => {
                        info!("failed to parse `{}` registry package: {}", name, e);
                        trace!("line: {}", line);
                        return None;
                    }
                };
                if online || load.is_crate_downloaded(summary.package_id()) {
                    Some((summary, locked))
                } else {
                    None
                }
            }));

            Ok(())
        });

        // We ignore lookup failures as those are just crates which don't exist
        // or we haven't updated the registry yet. If we actually ran the
        // closure though then we care about those errors.
        if hit_closure {
            err?;
        }

        Ok(ret)
    }

    /// Parse a line from the registry's index file into a Summary for a
    /// package.
    ///
    /// The returned boolean is whether or not the summary has been yanked.
    fn parse_registry_package(&mut self, line: &str) -> CargoResult<(Summary, bool)> {
        let RegistryPackage {
            name,
            vers,
            cksum,
            deps,
            features,
            yanked,
            links,
        } = serde_json::from_str(line)?;
        let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
        let name = pkgid.name();
        let deps = deps
            .into_iter()
            .map(|dep| dep.into_dep(&self.source_id))
            .collect::<CargoResult<Vec<_>>>()?;
        let summary = Summary::new(pkgid, deps, features, links, false)?;
        let summary = summary.set_checksum(cksum.clone());
        self.hashes
            .entry(name.as_str())
            .or_insert_with(HashMap::new)
            .insert(vers, cksum);
        Ok((summary, yanked.unwrap_or(false)))
    }

    pub fn query(
        &mut self,
        dep: &Dependency,
        load: &mut RegistryData,
        f: &mut FnMut(Summary),
    ) -> CargoResult<()> {
        let source_id = self.source_id.clone();
        let summaries = self.summaries(dep.name().as_str(), load)?;
        let summaries = summaries
            .iter()
            .filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked)
            .map(|s| s.0.clone());

        // Handle `cargo update --precise` here. If specified, our own source
        // will have a precise version listed of the form
        // `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
        // this source, `<p_req>` is the version installed and `<f_req> is the
        // version requested (argument to `--precise`).
        let summaries = summaries.filter(|s| match source_id.precise() {
            Some(p) if p.starts_with(&*dep.name()) && p[dep.name().len()..].starts_with('=') => {
                let mut vers = p[dep.name().len() + 1..].splitn(2, "->");
                if dep
                    .version_req()
                    .matches(&Version::parse(vers.next().unwrap()).unwrap())
                {
                    vers.next().unwrap() == s.version().to_string()
                } else {
                    true
                }
            }
            _ => true,
        });

        for summary in summaries {
            if dep.matches(&summary) {
                f(summary);
            }
        }
        Ok(())
    }
}
<commit_msg>make index lookup robust to _ vs -<commit_after>use std::collections::HashMap;
use std::path::Path;
use std::str;

use semver::Version;
use serde_json;

use core::dependency::Dependency;
use core::{PackageId, SourceId, Summary};
use sources::registry::RegistryData;
use sources::registry::{RegistryPackage, INDEX_LOCK};
use util::{internal, CargoResult, Config, Filesystem};

pub struct RegistryIndex<'cfg> {
    source_id: SourceId,
    path: Filesystem,
    cache: HashMap<&'static str, Vec<(Summary, bool)>>,
    hashes: HashMap<&'static str, HashMap<Version, String>>, // (name, vers) => cksum
    config: &'cfg Config,
    locked: bool,
}

impl<'cfg> RegistryIndex<'cfg> {
    pub fn new(
        id: &SourceId,
        path: &Filesystem,
        config: &'cfg Config,
        locked: bool,
    ) -> RegistryIndex<'cfg> {
        RegistryIndex {
            source_id: id.clone(),
            path: path.clone(),
            cache: HashMap::new(),
            hashes: HashMap::new(),
            config,
            locked,
        }
    }

    /// Return the hash listed for a specified PackageId.
    pub fn hash(&mut self, pkg: &PackageId, load: &mut RegistryData) -> CargoResult<String> {
        let name = pkg.name().as_str();
        let version = pkg.version();
        if let Some(s) = self.hashes.get(name).and_then(|v| v.get(version)) {
            return Ok(s.clone());
        }
        // Ok, we're missing the key, so parse the index file to load it.
        self.summaries(name, load)?;
        self.hashes
            .get(name)
            .and_then(|v| v.get(version))
            .ok_or_else(|| internal(format!("no hash listed for {}", pkg)))
            .map(|s| s.clone())
    }

    /// Parse the on-disk metadata for the package provided
    ///
    /// Returns a list of pairs of (summary, yanked) for the package name
    /// specified.
    pub fn summaries(
        &mut self,
        name: &'static str,
        load: &mut RegistryData,
    ) -> CargoResult<&Vec<(Summary, bool)>> {
        if self.cache.contains_key(name) {
            return Ok(&self.cache[name]);
        }
        let summaries = self.load_summaries(name, load)?;
        self.cache.insert(name, summaries);
        Ok(&self.cache[name])
    }

    fn load_summaries(
        &mut self,
        name: &str,
        load: &mut RegistryData,
    ) -> CargoResult<Vec<(Summary, bool)>> {
        // Prepare the `RegistryData` which will lazily initialize internal data
        // structures. Note that this is also importantly needed to initialize
        // to avoid deadlocks where we acquire a lock below but the `load`
        // function inside *also* wants to acquire a lock. See an instance of
        // this on #5551.
        load.prepare()?;
        let (root, _lock) = if self.locked {
            let lock = self
                .path
                .open_ro(Path::new(INDEX_LOCK), self.config, "the registry index");
            match lock {
                Ok(lock) => (lock.path().parent().unwrap().to_path_buf(), Some(lock)),
                Err(_) => return Ok(Vec::new()),
            }
        } else {
            (self.path.clone().into_path_unlocked(), None)
        };

        let fs_name = name
            .chars()
            .flat_map(|c| c.to_lowercase())
            .collect::<String>();

        // see module comment for why this is structured the way it is
        let raw_path = match fs_name.len() {
            1 => format!("1/{}", fs_name),
            2 => format!("2/{}", fs_name),
            3 => format!("3/{}/{}", &fs_name[..1], fs_name),
            _ => format!("{}/{}/{}", &fs_name[0..2], &fs_name[2..4], fs_name),
        };
        let num_hyphen_underscore = raw_path.chars()
            .filter(|&c| c == '_' || c == '-')
            .count();
        let mut ret = Vec::new();
        // Crates.io treats hyphen and underscores as interchangeable
        // but, the index and old cargo do not. So the index must store uncanonicalized version
        // of the name so old cargos can find it.
        // This loop tries all possible combinations of
        // hyphen and underscores to find the uncanonicalized one.
        for hyphen_combination_num in 0u16..(1 << num_hyphen_underscore) {
            let path = raw_path.chars()
                .scan(0u32, |s, c| if c == '_' || c == '-' {
                    let out = Some(if (hyphen_combination_num & (1u16 << *s)) > 0 { '_' } else { '-' });
                    *s += 1;
                    out
                } else {
                    Some(c)
                })
                .collect::<String>();
            let mut hit_closure = false;
            let err = load.load(&root, Path::new(&path), &mut |contents| {
                hit_closure = true;
                let contents = str::from_utf8(contents)
                    .map_err(|_| format_err!("registry index file was not valid utf-8"))?;
                ret.reserve(contents.lines().count());
                let lines = contents.lines().map(|s| s.trim()).filter(|l| !l.is_empty());

                let online = !self.config.cli_unstable().offline;
                // Attempt forwards-compatibility on the index by ignoring
                // everything that we ourselves don't understand, that should
                // allow future cargo implementations to break the
                // interpretation of each line here and older cargo will simply
                // ignore the new lines.
                ret.extend(lines.filter_map(|line| {
                    let (summary, locked) = match self.parse_registry_package(line) {
                        Ok(p) => p,
                        Err(e) => {
                            info!("failed to parse `{}` registry package: {}", name, e);
                            trace!("line: {}", line);
                            return None;
                        }
                    };
                    if online || load.is_crate_downloaded(summary.package_id()) {
                        Some((summary, locked))
                    } else {
                        None
                    }
                }));

                Ok(())
            });

            // We ignore lookup failures as those are just crates which don't exist
            // or we haven't updated the registry yet. If we actually ran the
            // closure though then we care about those errors.
            if hit_closure {
                err?;
                // Crates.io ensures that there is only one hyphen and underscore equivalent
                // result in the index so return when we find it.
                return Ok(ret);
            }
        }

        Ok(ret)
    }

    /// Parse a line from the registry's index file into a Summary for a
    /// package.
    ///
    /// The returned boolean is whether or not the summary has been yanked.
    fn parse_registry_package(&mut self, line: &str) -> CargoResult<(Summary, bool)> {
        let RegistryPackage {
            name,
            vers,
            cksum,
            deps,
            features,
            yanked,
            links,
        } = serde_json::from_str(line)?;
        let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
        let name = pkgid.name();
        let deps = deps
            .into_iter()
            .map(|dep| dep.into_dep(&self.source_id))
            .collect::<CargoResult<Vec<_>>>()?;
        let summary = Summary::new(pkgid, deps, features, links, false)?;
        let summary = summary.set_checksum(cksum.clone());
        self.hashes
            .entry(name.as_str())
            .or_insert_with(HashMap::new)
            .insert(vers, cksum);
        Ok((summary, yanked.unwrap_or(false)))
    }

    pub fn query(
        &mut self,
        dep: &Dependency,
        load: &mut RegistryData,
        f: &mut FnMut(Summary),
    ) -> CargoResult<()> {
        let source_id = self.source_id.clone();
        let summaries = self.summaries(dep.name().as_str(), load)?;
        let summaries = summaries
            .iter()
            .filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked)
            .map(|s| s.0.clone());

        // Handle `cargo update --precise` here. If specified, our own source
        // will have a precise version listed of the form
        // `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
        // this source, `<p_req>` is the version installed and `<f_req> is the
        // version requested (argument to `--precise`).
        let summaries = summaries.filter(|s| match source_id.precise() {
            Some(p) if p.starts_with(&*dep.name()) && p[dep.name().len()..].starts_with('=') => {
                let mut vers = p[dep.name().len() + 1..].splitn(2, "->");
                if dep
                    .version_req()
                    .matches(&Version::parse(vers.next().unwrap()).unwrap())
                {
                    vers.next().unwrap() == s.version().to_string()
                } else {
                    true
                }
            }
            _ => true,
        });

        for summary in summaries {
            if dep.matches(&summary) {
                f(summary);
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// This module provides routines for reading ripgrep config "rc" files. The
// primary output of these routines is a sequence of arguments, where each
// argument corresponds precisely to one shell argument.

use std::env;
use std::error::Error;
use std::ffi::OsString;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use bstr::{io::BufReadExt, ByteSlice};
use log;

use crate::Result;

/// Return a sequence of arguments derived from ripgrep rc configuration files.
pub fn args() -> Vec<OsString> {
    let config_path = match env::var_os("RIPGREP_CONFIG_PATH") {
        None => return vec![],
        Some(config_path) => {
            if config_path.is_empty() {
                return vec![];
            }
            PathBuf::from(config_path)
        }
    };
    let (args, errs) = match parse(&config_path) {
        Ok((args, errs)) => (args, errs),
        Err(err) => {
            message!("{}", err);
            return vec![];
        }
    };
    if !errs.is_empty() {
        for err in errs {
            message!("{}:{}", config_path.display(), err);
        }
    }
    log::debug!(
        "{}: arguments loaded from config file: {:?}",
        config_path.display(),
        args
    );
    args
}

/// Parse a single ripgrep rc file from the given path.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the file could not be read, then an error is returned. If there was
/// a problem parsing one or more lines in the file, then errors are returned
/// for each line in addition to successfully parsed arguments.
fn parse<P: AsRef<Path>>(
    path: P,
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
    let path = path.as_ref();
    match File::open(&path) {
        Ok(file) => parse_reader(file),
        Err(err) => Err(From::from(format!("{}: {}", path.display(), err))),
    }
}

/// Parse a single ripgrep rc file from the given reader.
///
/// Callers should not provided a buffered reader, as this routine will use its
/// own buffer internally.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the reader could not be read, then an error is returned. If there was a
/// problem parsing one or more lines, then errors are returned for each line
/// in addition to successfully parsed arguments.
fn parse_reader<R: io::Read>(
    rdr: R,
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
    let bufrdr = io::BufReader::new(rdr);
    let (mut args, mut errs) = (vec![], vec![]);
    let mut line_number = 0;
    bufrdr.for_byte_line_with_terminator(|line| {
        line_number += 1;

        let line = line.trim();
        if line.is_empty() || line[0] == b'#' {
            return Ok(true);
        }
        match line.to_os_str() {
            Ok(osstr) => {
                args.push(osstr.to_os_string());
            }
            Err(err) => {
                errs.push(format!("{}: {}", line_number, err).into());
            }
        }
        Ok(true)
    })?;
    Ok((args, errs))
}

#[cfg(test)]
mod tests {
    use super::parse_reader;
    use std::ffi::OsString;

    #[test]
    fn basic() {
        let (args, errs) = parse_reader(
            &b"\
# Test
--context=0
   --smart-case
-u

   # --bar
--foo
"[..],
        )
        .unwrap();
        assert!(errs.is_empty());
        let args: Vec<String> =
            args.into_iter().map(|s| s.into_string().unwrap()).collect();
        assert_eq!(args, vec!["--context=0", "--smart-case", "-u", "--foo",]);
    }

    // We test that we can handle invalid UTF-8 on Unix-like systems.
    #[test]
    #[cfg(unix)]
    fn error() {
        use std::os::unix::ffi::OsStringExt;

        let (args, errs) = parse_reader(
            &b"\
quux
foo\xFFbar
baz
"[..],
        )
        .unwrap();
        assert!(errs.is_empty());
        assert_eq!(
            args,
            vec![
                OsString::from("quux"),
                OsString::from_vec(b"foo\xFFbar".to_vec()),
                OsString::from("baz"),
            ]
        );
    }

    // ... but test that invalid UTF-8 fails on Windows.
    #[test]
    #[cfg(not(unix))]
    fn error() {
        let (args, errs) = parse_reader(
            &b"\
quux
foo\xFFbar
baz
"[..],
        )
        .unwrap();
        assert_eq!(errs.len(), 1);
        assert_eq!(args, vec![OsString::from("quux"), OsString::from("baz"),]);
    }
}
<commit_msg>cli: improve configuration failure mode<commit_after>// This module provides routines for reading ripgrep config "rc" files. The
// primary output of these routines is a sequence of arguments, where each
// argument corresponds precisely to one shell argument.

use std::env;
use std::error::Error;
use std::ffi::OsString;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};

use bstr::{io::BufReadExt, ByteSlice};
use log;

use crate::Result;

/// Return a sequence of arguments derived from ripgrep rc configuration files.
pub fn args() -> Vec<OsString> {
    let config_path = match env::var_os("RIPGREP_CONFIG_PATH") {
        None => return vec![],
        Some(config_path) => {
            if config_path.is_empty() {
                return vec![];
            }
            PathBuf::from(config_path)
        }
    };
    let (args, errs) = match parse(&config_path) {
        Ok((args, errs)) => (args, errs),
        Err(err) => {
            message!(
                "failed to read the file specified in RIPGREP_CONFIG_PATH: {}",
                err
            );
            return vec![];
        }
    };
    if !errs.is_empty() {
        for err in errs {
            message!("{}:{}", config_path.display(), err);
        }
    }
    log::debug!(
        "{}: arguments loaded from config file: {:?}",
        config_path.display(),
        args
    );
    args
}

/// Parse a single ripgrep rc file from the given path.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the file could not be read, then an error is returned. If there was
/// a problem parsing one or more lines in the file, then errors are returned
/// for each line in addition to successfully parsed arguments.
fn parse<P: AsRef<Path>>(
    path: P,
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
    let path = path.as_ref();
    match File::open(&path) {
        Ok(file) => parse_reader(file),
        Err(err) => Err(From::from(format!("{}: {}", path.display(), err))),
    }
}

/// Parse a single ripgrep rc file from the given reader.
///
/// Callers should not provided a buffered reader, as this routine will use its
/// own buffer internally.
///
/// On success, this returns a set of shell arguments, in order, that should
/// be pre-pended to the arguments given to ripgrep at the command line.
///
/// If the reader could not be read, then an error is returned. If there was a
/// problem parsing one or more lines, then errors are returned for each line
/// in addition to successfully parsed arguments.
fn parse_reader<R: io::Read>(
    rdr: R,
) -> Result<(Vec<OsString>, Vec<Box<dyn Error>>)> {
    let bufrdr = io::BufReader::new(rdr);
    let (mut args, mut errs) = (vec![], vec![]);
    let mut line_number = 0;
    bufrdr.for_byte_line_with_terminator(|line| {
        line_number += 1;

        let line = line.trim();
        if line.is_empty() || line[0] == b'#' {
            return Ok(true);
        }
        match line.to_os_str() {
            Ok(osstr) => {
                args.push(osstr.to_os_string());
            }
            Err(err) => {
                errs.push(format!("{}: {}", line_number, err).into());
            }
        }
        Ok(true)
    })?;
    Ok((args, errs))
}

#[cfg(test)]
mod tests {
    use super::parse_reader;
    use std::ffi::OsString;

    #[test]
    fn basic() {
        let (args, errs) = parse_reader(
            &b"\
# Test
--context=0
   --smart-case
-u

   # --bar
--foo
"[..],
        )
        .unwrap();
        assert!(errs.is_empty());
        let args: Vec<String> =
            args.into_iter().map(|s| s.into_string().unwrap()).collect();
        assert_eq!(args, vec!["--context=0", "--smart-case", "-u", "--foo",]);
    }

    // We test that we can handle invalid UTF-8 on Unix-like systems.
    #[test]
    #[cfg(unix)]
    fn error() {
        use std::os::unix::ffi::OsStringExt;

        let (args, errs) = parse_reader(
            &b"\
quux
foo\xFFbar
baz
"[..],
        )
        .unwrap();
        assert!(errs.is_empty());
        assert_eq!(
            args,
            vec![
                OsString::from("quux"),
                OsString::from_vec(b"foo\xFFbar".to_vec()),
                OsString::from("baz"),
            ]
        );
    }

    // ... but test that invalid UTF-8 fails on Windows.
    #[test]
    #[cfg(not(unix))]
    fn error() {
        let (args, errs) = parse_reader(
            &b"\
quux
foo\xFFbar
baz
"[..],
        )
        .unwrap();
        assert_eq!(errs.len(), 1);
        assert_eq!(args, vec![OsString::from("quux"), OsString::from("baz"),]);
    }
}
<|endoftext|>