use std::path::PathBuf;
+use std::fs;
use clap::{self, SubCommand};
use cargo::CargoResult;
use cargo::core::Workspace;
use cargo::ops::{CompileFilter, CompileMode, CompileOptions, MessageFormat, NewOptions, Packages,
VersionControl};
+use cargo::util::paths;
use cargo::util::important_paths::find_root_manifest_for_wd;
pub use clap::{AppSettings, Arg, ArgMatches};
Ok(arg)
}
+ /// Returns value of the `name` command-line argument as an absolute path
+ fn value_of_path(&self, name: &str, config: &Config) -> Option<PathBuf> {
+ self._value_of(name).map(|path| config.cwd().join(path))
+ }
+
fn root_manifest(&self, config: &Config) -> CargoResult<PathBuf> {
- let manifest_path = self._value_of("manifest-path");
- find_root_manifest_for_wd(manifest_path, config.cwd())
+ if let Some(path) = self.value_of_path("manifest-path", config) {
+ // In general, we try to avoid normalizing paths in Cargo,
+ // but in this particular case we need it to fix #3586.
+ let path = paths::normalize_path(&path);
+ if !path.ends_with("Cargo.toml") {
+ bail!("the manifest-path must be a path to a Cargo.toml file")
+ }
+ if !fs::metadata(&path).is_ok() {
+ bail!(
+ "manifest path `{}` does not exist",
+ self._value_of("manifest-path").unwrap()
+ )
+ }
+ return Ok(path);
+ }
+ find_root_manifest_for_wd(config.cwd())
}
fn workspace<'a>(&self, config: &'a Config) -> CargoResult<Workspace<'a>> {
Ok(compile_opts)
}
- fn new_options(&self) -> CargoResult<NewOptions> {
+ fn new_options(&self, config: &Config) -> CargoResult<NewOptions> {
let vcs = self._value_of("vcs").map(|vcs| match vcs {
"git" => VersionControl::Git,
"hg" => VersionControl::Hg,
vcs,
self._is_present("bin"),
self._is_present("lib"),
- self._value_of("path").unwrap().to_string(),
+ self.value_of_path("path", config).unwrap(),
self._value_of("name").map(|s| s.to_string()),
)
}
}
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
- let opts = args.new_options()?;
+ let opts = args.new_options(config)?;
ops::init(&opts, config)?;
config
.shell()
GitReference::Branch("master".to_string())
};
SourceId::for_git(&url, gitref)?
- } else if let Some(path) = args.value_of("path") {
- SourceId::for_path(&config.cwd().join(path))?
+ } else if let Some(path) = args.value_of_path("path", config) {
+ SourceId::for_path(&path)?
} else if krates.is_empty() {
SourceId::for_path(config.cwd())?
} else {
}
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
- let opts = args.new_options()?;
+ let opts = args.new_options(config)?;
ops::new(&opts, config)?;
let path = args.value_of("path").unwrap();
config
use std::env;
use std::fs;
use std::fmt;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use git2::Config as GitConfig;
use git2::Repository as GitRepository;
pub struct NewOptions {
pub version_control: Option<VersionControl>,
pub kind: NewProjectKind,
- pub path: String,
+ /// Absolute path to the directory for the new project
+ pub path: PathBuf,
pub name: Option<String>,
}
version_control: Option<VersionControl>,
bin: bool,
lib: bool,
- path: String,
+ path: PathBuf,
name: Option<String>,
) -> CargoResult<NewOptions> {
let kind = match (bin, lib) {
}
pub fn new(opts: &NewOptions, config: &Config) -> CargoResult<()> {
- let path = config.cwd().join(&opts.path);
- if fs::metadata(&path).is_ok() {
+ let path = &opts.path;
+ if fs::metadata(path).is_ok() {
bail!(
"destination `{}` already exists\n\n\
- Use `cargo init` to initialize the directory\
- ",
+ Use `cargo init` to initialize the directory",
path.display()
)
}
- let name = get_name(&path, opts)?;
+ let name = get_name(path, opts)?;
check_name(name, opts)?;
let mkopts = MkOptions {
}
pub fn init(opts: &NewOptions, config: &Config) -> CargoResult<()> {
- let path = config.cwd().join(&opts.path);
+ let path = &opts.path;
- let cargotoml_path = path.join("Cargo.toml");
- if fs::metadata(&cargotoml_path).is_ok() {
+ if fs::metadata(&path.join("Cargo.toml")).is_ok() {
bail!("`cargo init` cannot be run on existing Cargo projects")
}
let mkopts = MkOptions {
version_control,
- path: &path,
+ path,
name,
bin: src_paths_types.iter().any(|x| x.bin),
source_files: src_paths_types,
let name = match opts.krate {
Some(ref name) => name.clone(),
None => {
- let manifest_path = find_root_manifest_for_wd(None, config.cwd())?;
+ let manifest_path = find_root_manifest_for_wd(config.cwd())?;
let ws = Workspace::new(&manifest_path, config)?;
ws.current()?.package_id().name().to_string()
}
let name = match krate {
Some(name) => name,
None => {
- let manifest_path = find_root_manifest_for_wd(None, config.cwd())?;
+ let manifest_path = find_root_manifest_for_wd(config.cwd())?;
let ws = Workspace::new(&manifest_path, config)?;
ws.current()?.package_id().name().to_string()
}
use util::errors::CargoResult;
use util::paths;
-/// Iteratively search for `file` in `pwd` and its parents, returning
-/// the path of the directory.
-pub fn find_project(pwd: &Path, file: &str) -> CargoResult<PathBuf> {
- find_project_manifest(pwd, file).map(|mut p| {
- // remove the file, leaving just the directory
- p.pop();
- p
- })
-}
-
-/// Iteratively search for `file` in `pwd` and its parents, returning
-/// the path to the file.
-pub fn find_project_manifest(pwd: &Path, file: &str) -> CargoResult<PathBuf> {
- let mut current = pwd;
-
- loop {
+/// Find the root Cargo.toml
+pub fn find_root_manifest_for_wd(cwd: &Path) -> CargoResult<PathBuf> {
+ let file = "Cargo.toml";
+ for current in paths::ancestors(cwd) {
let manifest = current.join(file);
if fs::metadata(&manifest).is_ok() {
return Ok(manifest);
}
-
- match current.parent() {
- Some(p) => current = p,
- None => break,
- }
}
bail!(
"could not find `{}` in `{}` or any parent directory",
file,
- pwd.display()
+ cwd.display()
)
}
-/// Find the root Cargo.toml
-pub fn find_root_manifest_for_wd(manifest_path: Option<&str>, cwd: &Path) -> CargoResult<PathBuf> {
- match manifest_path {
- Some(path) => {
- let absolute_path = paths::normalize_path(&cwd.join(&path));
- if !absolute_path.ends_with("Cargo.toml") {
- bail!("the manifest-path must be a path to a Cargo.toml file")
- }
- if !fs::metadata(&absolute_path).is_ok() {
- bail!("manifest path `{}` does not exist", path)
- }
- Ok(absolute_path)
- }
- None => find_project_manifest(cwd, "Cargo.toml"),
- }
-}
-
/// Return the path to the `file` in `pwd`, if it exists.
pub fn find_project_manifest_exact(pwd: &Path, file: &str) -> CargoResult<PathBuf> {
let manifest = pwd.join(file);