Now `cargo login` stores a token per host.
If the host parameter is omitted cargo stores a token as default, i.e.
as a token for crates.io.
&options.flag_color,
options.flag_frozen,
options.flag_locked)?;
- let token = match options.arg_token.clone() {
+ let token = match options.arg_token {
Some(token) => token,
None => {
- let src = SourceId::crates_io(config)?;
- let mut src = RegistrySource::remote(&src, config);
- src.update()?;
- let config = src.config()?.unwrap();
- let host = options.flag_host.clone().unwrap_or(config.api);
+ let host = match options.flag_host {
+ Some(ref host) => host.clone(),
+ None => {
+ let src = SourceId::crates_io(config)?;
+ let mut src = RegistrySource::remote(&src, config);
+ src.update()?;
+ src.config()?.unwrap().api
+ }
+ };
+
println!("please visit {}me and paste the API Token below", host);
let mut line = String::new();
let input = io::stdin();
input.lock().read_line(&mut line).chain_err(|| {
"failed to read stdin"
})?;
- line
+ line.trim().to_string()
}
};
- let token = token.trim().to_string();
- ops::registry_login(config, token)?;
+ ops::registry_login(config, token, options.flag_host)?;
Ok(())
}
-
/// This is the main cargo registry by default, but it can be overridden in
/// a `.cargo/config`.
pub fn crates_io(config: &Config) -> CargoResult<SourceId> {
- let cfg = ops::registry_configuration(config)?;
+ let cfg = ops::registry_configuration(config, None)?;
let url = if let Some(ref index) = cfg.index {
static WARNED: AtomicBool = ATOMIC_BOOL_INIT;
if !WARNED.swap(true, SeqCst) {
use core::manifest::ManifestMetadata;
use ops;
use sources::{RegistrySource};
-use util::config::{self, Config};
+use util::config::{self, Config, Value, Definition};
use util::paths;
use util::ToUrl;
use util::errors::{CargoError, CargoResult, CargoResultExt};
}
}
-pub fn registry_configuration(config: &Config) -> CargoResult<RegistryConfig> {
- let index = config.get_string("registry.index")?.map(|p| p.val);
- let token = config.get_string("registry.token")?.map(|p| p.val);
- Ok(RegistryConfig { index: index, token: token })
+pub fn registry_configuration(config: &Config,
+ host: Option<String>) -> CargoResult<RegistryConfig> {
+ let (index, token) = match host {
+ Some(host) => {
+ (Some(Value { val: host.clone(), definition: Definition::Environment }),
+ config.get_string(&format!("registry.{}.token", host))?)
+ }
+ None => {
+ // Checking out for default index and token
+ (config.get_string("registry.index")?,
+ config.get_string("registry.token")?)
+ }
+ };
+
+ Ok(RegistryConfig {
+ index: index.map(|p| p.val),
+ token: token.map(|p| p.val)
+ })
}
pub fn registry(config: &Config,
let RegistryConfig {
token: token_config,
index: _index_config,
- } = registry_configuration(config)?;
+ } = registry_configuration(config, index.clone())?;
let token = token.or(token_config);
let sid = match index {
Some(index) => SourceId::for_registry(&index.to_url()?),
Ok(env::var("HTTP_TIMEOUT").ok().and_then(|s| s.parse().ok()))
}
-pub fn registry_login(config: &Config, token: String) -> CargoResult<()> {
- let RegistryConfig { index: _, token: old_token } = registry_configuration(config)?;
+pub fn registry_login(config: &Config,
+ token: String,
+ host: Option<String>) -> CargoResult<()> {
+ let RegistryConfig {
+ index: _,
+ token: old_token
+ } = registry_configuration(config, host.clone())?;
+
if let Some(old_token) = old_token {
if old_token == token {
return Ok(());
}
}
- config::save_credentials(config, token)
+ config::save_credentials(config, token, host)
}
pub struct OwnersOptions {
}
pub fn save_credentials(cfg: &Config,
- token: String) -> CargoResult<()> {
+ token: String,
+ host: Option<String>) -> CargoResult<()> {
let mut file = {
cfg.home_path.create_dir()?;
cfg.home_path.open_rw(Path::new("credentials"), cfg,
- "credentials' config file")?
+ "credentials' config file")?
+ };
+
+ let (key, value) = {
+ let key = "token".to_string();
+ let value = ConfigValue::String(token, file.path().to_path_buf());
+
+ if let Some(host) = host {
+ let mut map = HashMap::new();
+ map.insert(key, value);
+ (host, CV::Table(map, file.path().to_path_buf()))
+ } else {
+ (key, value)
+ }
};
let mut contents = String::new();
file.read_to_string(&mut contents).chain_err(|| {
- format!("failed to read configuration file `{}`",
- file.path().display())
+ format!("failed to read configuration file `{}`", file.path().display())
})?;
+
let mut toml = cargo_toml::parse(&contents, file.path(), cfg)?;
toml.as_table_mut()
.unwrap()
- .insert("token".to_string(),
- ConfigValue::String(token, file.path().to_path_buf()).into_toml());
+ .insert(key, value.into_toml());
let contents = toml.to_string();
file.seek(SeekFrom::Start(0))?;
fn setup_new_credentials() {
let config = cargo_home().join("credentials");
t!(fs::create_dir_all(config.parent().unwrap()));
- t!(t!(File::create(&config)).write_all(br#"
+ t!(t!(File::create(&config)).write_all(format!(r#"
token = "api-token"
- "#));
+
+ ["{registry}"]
+ token = "api-token"
+ "#, registry = registry().to_string())
+ .as_bytes()));
}
-fn check_host_token(toml: toml::Value) -> bool {
+fn check_host_token(mut toml: toml::Value, host_key: &str) -> bool {
+ for &key in [host_key, "token"].into_iter() {
+ if key.is_empty() {
+ continue
+ }
+
+ match toml {
+ toml::Value::Table(table) => {
+ if let Some(v) = table.get(key) {
+ toml = v.clone();
+ } else {
+ return false;
+ }
+ }
+ _ => break,
+ }
+ }
+
match toml {
- toml::Value::Table(table) => match table.get("token") {
- Some(v) => match v {
- &toml::Value::String(ref token) => (token.as_str() == TOKEN),
- _ => false,
- },
- None => false,
- },
+ toml::Value::String(token) => (&token == TOKEN),
_ => false,
}
}
contents.clear();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
- assert!(check_host_token(contents.parse().unwrap()));
+ assert!(check_host_token(contents.parse().unwrap(), ®istry().to_string()));
}
#[test]
let mut contents = String::new();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
- assert!(check_host_token(contents.parse().unwrap()));
+ assert!(check_host_token(contents.parse().unwrap(), ®istry().to_string()));
}
#[test]
assert_that(cargo_process().arg("login")
.arg("--host").arg(registry().to_string()).arg(TOKEN),
execs().with_status(0));
+ assert_that(cargo_process().arg("login").arg(TOKEN),
+ execs().with_status(0));
let config = cargo_home().join("config");
assert_that(&config, is_not(existing_file()));
let mut contents = String::new();
File::open(&credentials).unwrap().read_to_string(&mut contents).unwrap();
- assert!(check_host_token(contents.parse().unwrap()));
+ let toml: toml::Value = contents.parse().unwrap();
+ assert!(check_host_token(toml.clone(), ®istry().to_string()));
+ assert!(check_host_token(toml, ""));
}
#[test]
setup_old_credentials();
setup_new_credentials();
+ assert_that(cargo_process().arg("login").arg(TOKEN),
+ execs().with_status(0));
+
assert_that(cargo_process().arg("login")
.arg("--host").arg(registry().to_string()).arg(TOKEN),
execs().with_status(0));
let config = Config::new(Shell::new(), cargo_home(), cargo_home());
+
let token = config.get_string("registry.token").unwrap().map(|p| p.val);
assert!(token.unwrap() == TOKEN);
+
+ let token_host = config.get_string(&format!(r#"registry.{}.token"#, registry().to_string()))
+ .unwrap().map(|p| p.val);
+ assert!(token_host.unwrap() == TOKEN);
}
use cargotest::support::git::repo;
use cargotest::support::paths;
use cargotest::support::{project, execs};
+use cargotest::install::cargo_home;
use flate2::read::GzDecoder;
use hamcrest::assert_that;
use tar::Archive;
fn upload() -> Url { Url::from_file_path(&*upload_path()).ok().unwrap() }
fn setup() {
- let config = paths::root().join(".cargo/config");
+ let config = cargo_home().join("config");
t!(fs::create_dir_all(config.parent().unwrap()));
t!(t!(File::create(&config)).write_all(br#"
[registry]
- token = "api-token"
+ token = "api-token"
"#));
t!(fs::create_dir_all(&upload_path().join("api/v1/crates")));
+ let credentials = cargo_home().join("credentials");
+ t!(t!(File::create(&credentials)).write_all(format!(r#"
+ ["{registry}"]
+ token = "api-token"
+ "#, registry = registry().to_string())
+ .as_bytes()));
+
repo(®istry_path())
.file("config.json", &format!(r#"{{
"dl": "{0}",