fn load(&mut self, source_id: &SourceId, kind: Kind) -> CargoResult<()> {
(|| {
+ debug!("loading source {}", source_id);
let source = self.source_config.load(source_id)?;
assert_eq!(source.source_id(), source_id);
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");
}
impl<'cfg> RegistryData for LocalRegistry<'cfg> {
+ fn prepare(&self) -> CargoResult<()> {
+ Ok(())
+ }
+
fn index_path(&self) -> &Filesystem {
&self.index_path
}
}
pub trait RegistryData {
+ fn prepare(&self) -> CargoResult<()>;
fn index_path(&self) -> &Filesystem;
fn load(
&self,
// come back with no summaries, then our registry may need to be
// updated, so we fall back to performing a lazy update.
if dep.source_id().precise().is_some() && !self.updated {
+ debug!("attempting query without update");
let mut called = false;
self.index.query(dep, &mut *self.ops, &mut |s| {
called = true;
if called {
return Ok(());
} else {
+ debug!("falling back to an update");
self.do_update()?;
}
}
// --precise` request
if self.source_id.precise() != Some("locked") {
self.do_update()?;
+ } else {
+ debug!("skipping update due to locked registry");
}
Ok(())
}
// Fast path without a lock
if let Ok(repo) = git2::Repository::open(&path) {
+ trace!("opened a repo without a lock");
return Ok(repo);
}
// Ok, now we need to lock and try the whole thing over again.
+ trace!("acquiring registry index lock");
let lock =
self.index_path
.open_rw(Path::new(INDEX_LOCK), self.config, "the registry index")?;
// like enough time has passed or if we change the directory
// that the folder is located in, such as by changing the
// hash at the end of the directory.
- Ok(git2::Repository::init(&path)?)
+ //
+ // Note that in the meantime we also skip `init.templatedir`
+ // as it can be misconfigured sometimes or otherwise add
+ // things that we don't want.
+ let mut opts = git2::RepositoryInitOptions::new();
+ opts.external_template(false);
+ Ok(git2::Repository::init_opts(&path, &opts).chain_err(|| {
+ "failed to initialized index git repository"
+ })?)
}
}
})
}
impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
+ fn prepare(&self) -> CargoResult<()> {
+ self.repo()?; // create intermediate dirs and initialize the repo
+ Ok(())
+ }
+
fn index_path(&self) -> &Filesystem {
&self.index_path
}
}
fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
- self.repo()?; // create intermediate dirs and initialize the repo
+ debug!("loading config");
+ self.prepare()?;
let _lock =
self.index_path
.open_ro(Path::new(INDEX_LOCK), self.config, "the registry index")?;
config = Some(serde_json::from_slice(json)?);
Ok(())
})?;
+ trace!("config loaded");
Ok(config)
}
return Ok(());
}
+ debug!("updating the index");
+
// Ensure that we'll actually be able to acquire an HTTP handle later on
// once we start trying to download crates. This will weed out any
// problems with `.cargo/config` configuration related to HTTP.
// hit the index, which may not actually read this configuration.
self.config.http()?;
- self.repo()?;
+ self.prepare()?;
self.head.set(None);
*self.tree.borrow_mut() = None;
let _lock =
D: fmt::Display + Send + Sync + 'static,
{
self.map_err(|failure| {
+ let err = failure.into();
let context = f();
- failure.into().context(context)
+ trace!("error: {}", err);
+ trace!("\tcontext: {}", context);
+ err.context(context)
})
}
}
use std::io::prelude::*;
use std::path::PathBuf;
+use cargo::util::paths::remove_dir_all;
use cargotest::cargo_process;
use cargotest::support::git;
use cargotest::support::paths::{self, CargoPathExt};
),
);
}
+
+#[test]
+fn git_init_templatedir_missing() {
+ Package::new("foo", "0.2.0").dep("bar", "*").publish();
+ Package::new("bar", "0.2.0").publish();
+
+ let p = project("foo")
+ .file(
+ "Cargo.toml",
+ r#"
+ [project]
+ name = "fo"
+ version = "0.5.0"
+ authors = []
+
+ [dependencies]
+ foo = "0.2"
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ assert_that(
+ p.cargo("build"),
+ execs().with_status(0)
+ );
+
+ remove_dir_all(paths::home().join(".cargo/registry")).unwrap();
+ File::create(paths::home().join(".gitconfig"))
+ .unwrap()
+ .write_all(br#"
+ [init]
+ templatedir = nowhere
+ "#)
+ .unwrap();
+
+ assert_that(
+ p.cargo("build"),
+ execs().with_status(0)
+ );
+ assert_that(
+ p.cargo("build"),
+ execs().with_status(0)
+ );
+}