use std::rc::Rc;
use crate::{submodule, Repository};
impl Repository {
/// Open the `.gitmodules` file as present in the worktree, or return `None` if no such file is available.
/// Note that git configuration is also contributing to the result based on the current snapshot.
///
/// Note that his method will not look in other places, like the index or the `HEAD` tree.
// TODO(submodule): make it use an updated snapshot instead once we have `config()`.
pub fn open_modules_file(&self) -> Result, submodule::open_modules_file::Error> {
let path = match self.modules_path() {
Some(path) => path,
None => return Ok(None),
};
let buf = match std::fs::read(&path) {
Ok(buf) => buf,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(err) => return Err(err.into()),
};
Ok(Some(gix_submodule::File::from_bytes(
&buf,
path,
&self.config.resolved,
)?))
}
/// Return a shared [`.gitmodules` file](crate::submodule::File) which is updated automatically if the in-memory snapshot
/// has become stale as the underlying file on disk has changed. The snapshot based on the file on disk is shared across all
/// clones of this repository.
///
/// If a file on disk isn't present, we will try to load it from the index, and finally from the current tree.
/// In the latter two cases, the result will not be cached in this repository instance as we can't detect freshness anymore,
/// so time this method is called a new [modules file](submodule::ModulesSnapshot) will be created.
///
/// Note that git configuration is also contributing to the result based on the current snapshot.
///
// TODO(submodule): make it use an updated snapshot instead once we have `config()`.
pub fn modules(&self) -> Result , submodule::modules::Error> {
match self.modules.recent_snapshot(
|| {
self.modules_path()
.and_then(|path| path.metadata().and_then(|m| m.modified()).ok())
},
|| self.open_modules_file(),
)? {
Some(m) => Ok(Some(m)),
None => {
let id = match self.try_index()?.and_then(|index| {
index
.entry_by_path(submodule::MODULES_FILE.into())
.map(|entry| entry.id)
}) {
Some(id) => id,
None => match self
.head_commit()?
.tree()?
.find_entry(submodule::MODULES_FILE)
.map(|entry| entry.inner.oid)
{
Some(id) => id.to_owned(),
None => return Ok(None),
},
};
Ok(Some(gix_features::threading::OwnShared::new(
gix_submodule::File::from_bytes(&self.find_object(id)?.data, None, &self.config.resolved)
.map_err(submodule::open_modules_file::Error::from)?
.into(),
)))
}
}
}
/// Return the list of available submodules, or `None` if there is no submodule configuration.
#[doc(alias = "git2")]
pub fn submodules(&self) -> Result >>, submodule::modules::Error> {
let modules = match self.modules()? {
None => return Ok(None),
Some(m) => m,
};
let shared_state = Rc::new(submodule::SharedState::new(self, modules));
Ok(Some(
shared_state
.modules
.names()
.map(ToOwned::to_owned)
.collect::>()
.into_iter()
.map(move |name| crate::Submodule {
state: shared_state.clone(),
name,
}),
))
}
}