Skip to content

Commit

Permalink
Add some more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Dodd committed Oct 1, 2017
1 parent a888e11 commit 72899f5
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 7 deletions.
50 changes: 47 additions & 3 deletions src/cargo/core/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,60 @@ use termcolor::{self, StandardStream, Color, ColorSpec, WriteColor};

use util::errors::CargoResult;

#[derive(Clone, Copy, PartialEq)]
/// The requested verbosity of output
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
Verbose,
Normal,
Quiet
}

/// An abstraction around a `Write`able object that remembers preferences for output verbosity and
/// color.
pub struct Shell {
/// the `Write`able object, either with or without color support (represented by different enum
/// variants)
err: ShellOut,
/// How verbose messages should be
verbosity: Verbosity,
}

impl fmt::Debug for Shell {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Shell")
match &self.err {
&ShellOut::Write(_) => f.debug_struct("Shell")
.field("verbosity", &self.verbosity)
.finish(),
&ShellOut::Stream(_, color_choice) => f.debug_struct("Shell")
.field("verbosity", &self.verbosity)
.field("color_choice", &color_choice)
.finish()
}
}
}

/// A `Write`able object, either with or without color support
enum ShellOut {
/// A plain write object without color support
Write(Box<Write>),
/// Color-enabled stdio, with information on whether color should be used
Stream(StandardStream, ColorChoice),
}

#[derive(PartialEq, Clone, Copy)]
/// Whether messages should use color output
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum ColorChoice {
/// Force color output
Always,
/// Force disable color output
Never,
/// Intelligently guess whether to use color output
CargoAuto,
}

impl Shell {
/// Create a new shell (color choice and verbosity), defaulting to 'auto' color and verbose
/// output.
pub fn new() -> Shell {
Shell {
err: ShellOut::Stream(
Expand All @@ -48,13 +71,16 @@ impl Shell {
}
}

/// Create a shell from a plain writable object, with no color, and max verbosity.
pub fn from_write(out: Box<Write>) -> Shell {
Shell {
err: ShellOut::Write(out),
verbosity: Verbosity::Verbose,
}
}

/// Print a message, where the status will have `color` color, and can be justified. The
/// messages follows without color.
fn print(&mut self,
status: &fmt::Display,
message: &fmt::Display,
Expand All @@ -68,16 +94,19 @@ impl Shell {
}
}

/// Get a reference to the underlying writer
pub fn err(&mut self) -> &mut Write {
self.err.as_write()
}

/// Shortcut to right-align and color green a status message.
pub fn status<T, U>(&mut self, status: T, message: U) -> CargoResult<()>
where T: fmt::Display, U: fmt::Display
{
self.print(&status, &message, Green, true)
}

/// Shortcut to right-align a status message.
pub fn status_with_color<T, U>(&mut self,
status: T,
message: U,
Expand All @@ -87,6 +116,7 @@ impl Shell {
self.print(&status, &message, color, true)
}

/// Run the callback only if we are in verbose mode
pub fn verbose<F>(&mut self, mut callback: F) -> CargoResult<()>
where F: FnMut(&mut Shell) -> CargoResult<()>
{
Expand All @@ -96,6 +126,7 @@ impl Shell {
}
}

/// Run the callback if we are not in verbose mode.
pub fn concise<F>(&mut self, mut callback: F) -> CargoResult<()>
where F: FnMut(&mut Shell) -> CargoResult<()>
{
Expand All @@ -105,25 +136,30 @@ impl Shell {
}
}

/// Print a red 'error' message
pub fn error<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
self.print(&"error:", &message, Red, false)
}

/// Print an amber 'warning' message
pub fn warn<T: fmt::Display>(&mut self, message: T) -> CargoResult<()> {
match self.verbosity {
Verbosity::Quiet => Ok(()),
_ => self.print(&"warning:", &message, Yellow, false),
}
}

/// Update the verbosity of the shell
pub fn set_verbosity(&mut self, verbosity: Verbosity) {
self.verbosity = verbosity;
}

/// Get the verbosity of the shell
pub fn verbosity(&self) -> Verbosity {
self.verbosity
}

/// Update the color choice (always, never, or auto) from a string.
pub fn set_color_choice(&mut self, color: Option<&str>) -> CargoResult<()> {
if let ShellOut::Stream(ref mut err, ref mut cc) = self.err {
let cfg = match color {
Expand All @@ -142,6 +178,10 @@ impl Shell {
Ok(())
}

/// Get the current color choice
///
/// If we are not using a color stream, this will always return Never, even if the color choice
/// has been set to something else.
pub fn color_choice(&self) -> ColorChoice {
match self.err {
ShellOut::Stream(_, cc) => cc,
Expand All @@ -151,6 +191,8 @@ impl Shell {
}

impl ShellOut {
/// Print out a message with a status. The status comes first and is bold + the given color.
/// The status can be justified, in which case the max width that will right align is 12 chars.
fn print(&mut self,
status: &fmt::Display,
message: &fmt::Display,
Expand Down Expand Up @@ -182,6 +224,7 @@ impl ShellOut {
Ok(())
}

/// Get this object as a `io::Write`.
fn as_write(&mut self) -> &mut Write {
match *self {
ShellOut::Stream(ref mut err, _) => err,
Expand All @@ -191,6 +234,7 @@ impl ShellOut {
}

impl ColorChoice {
/// Convert our color choice to termcolor's version
fn to_termcolor_color_choice(&self) -> termcolor::ColorChoice {
match *self {
ColorChoice::Always => termcolor::ColorChoice::Always,
Expand Down
70 changes: 67 additions & 3 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,44 @@ use super::layout::Layout;
use super::links::Links;
use super::{Kind, Compilation, BuildConfig};

/// All information needed to define a Unit.
///
/// A unit is an object that has enough information so that cargo knows how to build it.
/// For example, if your project has dependencies, then every dependency will be built as a library
/// unit. If your project is a library, then it will be built as a library unit as well, or if it
/// is a binary with `main.rs`, then a binary will be output. There are also separate unit types
/// for `test`ing and `check`ing, amongst others.
///
/// The unit also holds information about all possible metadata about the package in `pkg`.
///
/// A unit needs to know extra information in addition to the type and root source file. For
/// example, it needs to know the target architecture (OS, chip arch etc.) and it needs to know
/// whether you want a debug or release build. There is enough information in this struct to figure
/// all that out.
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct Unit<'a> {
/// Information about avaiable targets, which files to include/exclude, etc. Basically stuff in
/// `Cargo.toml`.
pub pkg: &'a Package,
/// Information about the specific target to build, out of the possible targets in `pkg`. Not
/// to be confused with *target-triple* (or *target architecture* ...), the target arch for a
/// build.
pub target: &'a Target,
/// The profile contains information about *how* the build should be run, including debug
/// level, extra args to pass to rustc, etc.
pub profile: &'a Profile,
/// Whether this compilation unit is for the host or target architecture.
///
/// For example, when
/// cross compiling and using a custom build script, the build script needs to be compiled for
/// the host architecture so the host rustc can use it (when compiling to the target
/// architecture).
pub kind: Kind,
}

/// The build context, containing all information about a build task
pub struct Context<'a, 'cfg: 'a> {
/// The workspace the build is for
pub ws: &'a Workspace<'cfg>,
pub config: &'cfg Config,
pub resolve: &'a Resolve,
Expand All @@ -50,13 +79,21 @@ pub struct Context<'a, 'cfg: 'a> {
pub used_in_plugin: HashSet<Unit<'a>>,
pub jobserver: Client,

/// The target directory layout for the host (and target if it is the same as host)
host: Layout,
/// The target directory layout for the target (if different from then host)
target: Option<Layout>,
target_info: TargetInfo,
host_info: TargetInfo,
profiles: &'a Profiles,
incremental_enabled: bool,

/// For each Unit, a list all files produced as a triple of
///
/// - File name that will be produced by the build process (in `deps`)
/// - If it should be linked into `target`, and what it should be called (e.g. without
/// metadata).
/// - Whether it is something you can link against (e.g. a library)
target_filenames: HashMap<Unit<'a>, Arc<Vec<(PathBuf, Option<PathBuf>, bool)>>>,
target_metadatas: HashMap<Unit<'a>, Option<Metadata>>,
}
Expand Down Expand Up @@ -210,6 +247,10 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
Ok(())
}

/// A recursive function that checks all crate types (`rlib`, ...) are in `crate_types`
/// for this unit and its dependencies.
///
/// Tracks visited units to avoid unnecessary work.
fn visit_crate_type(&self,
unit: &Unit<'a>,
crate_types: &mut BTreeSet<String>,
Expand Down Expand Up @@ -660,7 +701,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
}
}
};

//info!("{:?}", unit);
match *unit.target.kind() {
TargetKind::Bin |
TargetKind::CustomBuild |
Expand Down Expand Up @@ -1038,8 +1079,23 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
}
}

// Acquire extra flags to pass to the compiler from the
// RUSTFLAGS environment variable and similar config values
/// Acquire extra flags to pass to the compiler from various locations.
///
/// The locations are:
///
/// - the `RUSTFLAGS` environment variable
///
/// then if this was not found
///
/// - `target.*.rustflags` from the manifest (Cargo.toml)
/// - `target.cfg(..).rustflags` from the manifest
///
/// then if neither of these were found
///
/// - `build.rustflags` from the manifest
///
/// Note that if a `target` is specified, no args will be passed to host code (plugins, build
/// scripts, ...), even if it is the same as the target.
fn env_args(config: &Config,
build_config: &BuildConfig,
target_info: &TargetInfo,
Expand Down Expand Up @@ -1136,6 +1192,14 @@ impl fmt::Display for Metadata {
}
}

/// Takes rustc output (using specialized command line args), and calculates the file prefix and
/// suffix for the given crate type, or returns None if the type is not supported. (e.g. for a
/// rust library like libcargo.rlib, prefix = "lib", suffix = "rlib").
///
/// The caller needs to ensure that the lines object is at the correct line for the given crate
/// type: this is not checked.
// This function can not handle more than 1 file per type (with wasm32-unknown-emscripten, there
// are 2 files for bin (.wasm and .js))
fn parse_crate_type(
crate_type: &str,
error: &str,
Expand Down
21 changes: 21 additions & 0 deletions src/cargo/ops/cargo_rustc/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ use std::path::{PathBuf, Path};
use core::Workspace;
use util::{Config, FileLock, CargoResult, Filesystem};

/// Contains the paths of all target output locations.
///
/// See module docs for more information.
pub struct Layout {
root: PathBuf,
deps: PathBuf,
Expand All @@ -64,6 +67,7 @@ pub struct Layout {
incremental: PathBuf,
fingerprint: PathBuf,
examples: PathBuf,
/// The lockfile for a build, will be unlocked when this struct is `drop`ped.
_lock: FileLock,
}

Expand All @@ -74,6 +78,12 @@ pub fn is_bad_artifact_name(name: &str) -> bool {
}

impl Layout {
/// Calcuate the paths for build output, lock the build directory, and return as a Layout.
///
/// This function will block if the directory is already locked.
///
/// Differs from `at` in that it calculates the root path from the workspace target directory,
/// adding the target triple and the profile (debug, release, ...).
pub fn new(ws: &Workspace,
triple: Option<&str>,
dest: &str) -> CargoResult<Layout> {
Expand All @@ -88,6 +98,9 @@ impl Layout {
Layout::at(ws.config(), path)
}

/// Calcuate the paths for build output, lock the build directory, and return as a Layout.
///
/// This function will block if the directory is already locked.
pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
// For now we don't do any more finer-grained locking on the artifact
// directory, so just lock the entire thing for the duration of this
Expand Down Expand Up @@ -136,6 +149,7 @@ impl Layout {
}
}

/// Make sure all directories stored in the Layout exist on the filesystem.
pub fn prepare(&mut self) -> io::Result<()> {
if fs::metadata(&self.root).is_err() {
fs::create_dir_all(&self.root)?;
Expand All @@ -160,11 +174,18 @@ impl Layout {
}
}

/// Fetch the root path.
pub fn dest(&self) -> &Path { &self.root }
/// Fetch the deps path.
pub fn deps(&self) -> &Path { &self.deps }
/// Fetch the examples path.
pub fn examples(&self) -> &Path { &self.examples }
/// Fetch the root path.
pub fn root(&self) -> &Path { &self.root }
/// Fetch the incremental path.
pub fn incremental(&self) -> &Path { &self.incremental }
/// Fetch the fingerprint path.
pub fn fingerprint(&self) -> &Path { &self.fingerprint }
/// Fetch the build path.
pub fn build(&self) -> &Path { &self.build }
}
Loading

0 comments on commit 72899f5

Please sign in to comment.