Skip to content

Commit

Permalink
add SourceTree enum in place of all direct git::Repository uses
Browse files Browse the repository at this point in the history
  • Loading branch information
haileys committed Sep 15, 2023
1 parent 475c25f commit 2d9c08e
Showing 1 changed file with 41 additions and 25 deletions.
66 changes: 41 additions & 25 deletions src/espidf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub enum FromEnvError {
#[error("`esp-idf` repository exists but required tools not in environment")]
NotActivated {
/// The esp-idf repository detected from the environment.
esp_idf_repo: git::Repository,
esp_idf_tree: SourceTree,
/// The source error why detection failed.
#[source]
source: anyhow::Error,
Expand All @@ -122,8 +122,8 @@ pub enum FromEnvError {
/// Information about a esp-idf source and tools installation.
#[derive(Debug)]
pub struct EspIdf {
/// The esp-idf repository.
pub repository: git::Repository,
/// The esp-idf source tree.
pub tree: SourceTree,
/// The binary paths of all tools concatenated with the system `PATH` env variable.
pub exported_path: OsString,
/// The path to the python executable to be used by the esp-idf.
Expand All @@ -135,19 +135,35 @@ pub struct EspIdf {
pub is_managed_espidf: bool,
}

#[derive(Debug, Clone)]
pub enum SourceTree {
Git(git::Repository),
}

impl SourceTree {
pub fn path(&self) -> &Path {
match self {
SourceTree::Git(repo) => repo.worktree(),
}
}
}

impl EspIdf {
/// Try to detect an activated esp-idf environment.
pub fn try_from_env() -> Result<EspIdf, FromEnvError> {
// detect repo from $IDF_PATH
let idf_path = env::var_os(IDF_PATH_VAR).ok_or_else(|| {
FromEnvError::NoRepo(anyhow!("environment variable `{IDF_PATH_VAR}` not found"))
})?;
let repo = git::Repository::open(idf_path).map_err(FromEnvError::NoRepo)?;
let tree = match git::Repository::open(idf_path) {
Ok(repo) => SourceTree::Git(repo),
Err(e) => { return Err(FromEnvError::NoRepo(e)); }
};

let path_var = env::var_os("PATH").unwrap_or_default();
let not_activated = |source: Error| -> FromEnvError {
FromEnvError::NotActivated {
esp_idf_repo: repo.clone(),
esp_idf_tree: tree.clone(),
source,
}
};
Expand All @@ -172,7 +188,7 @@ impl EspIdf {
.map_err(not_activated)?;

// make sure ${IDF_PATH}/tools/idf.py matches idf.py in $PATH
let idf_py_repo = path_buf![repo.worktree(), "tools", "idf.py"];
let idf_py_repo = path_buf![tree.path(), "tools", "idf.py"];
match (idf_py.canonicalize(), idf_py_repo.canonicalize()) {
(Ok(a), Ok(b)) if a != b => {
return Err(not_activated(anyhow!(
Expand All @@ -191,15 +207,15 @@ impl EspIdf {
.with_context(|| anyhow!("python not found in $PATH"))
.map_err(not_activated)?;
let check_python_deps_py =
path_buf![repo.worktree(), "tools", "check_python_dependencies.py"];
path_buf![tree.path(), "tools", "check_python_dependencies.py"];
cmd!(&python, &check_python_deps_py)
.stdout()
.with_context(|| anyhow!("failed to check python dependencies"))
.map_err(not_activated)?;

Ok(EspIdf {
version: EspIdfVersion::try_from(&repo),
repository: repo,
version: EspIdfVersion::try_from(&tree),
tree,
exported_path: path_var,
venv_python: python,
is_managed_espidf: true,
Expand All @@ -217,8 +233,8 @@ pub struct EspIdfVersion {

impl EspIdfVersion {
/// Try to extract the esp-idf version from an actual cloned repository.
pub fn try_from(repo: &git::Repository) -> Result<Self> {
let version_cmake = path_buf![repo.worktree(), "tools", "cmake", "version.cmake"];
pub fn try_from(tree: &SourceTree) -> Result<Self> {
let version_cmake = path_buf![tree.path(), "tools", "cmake", "version.cmake"];

let base_err = || {
anyhow!(
Expand Down Expand Up @@ -302,7 +318,7 @@ pub struct Installer {
custom_install_dir: Option<PathBuf>,
#[allow(clippy::type_complexity)]
tools_provider:
Option<Box<dyn FnOnce(&git::Repository, &Result<EspIdfVersion>) -> Result<Vec<Tools>>>>,
Option<Box<dyn FnOnce(&SourceTree, &Result<EspIdfVersion>) -> Result<Vec<Tools>>>>,
}

impl Installer {
Expand All @@ -319,7 +335,7 @@ impl Installer {
#[must_use]
pub fn with_tools<F>(mut self, provider: F) -> Self
where
F: 'static + FnOnce(&git::Repository, &Result<EspIdfVersion>) -> Result<Vec<Tools>>,
F: 'static + FnOnce(&SourceTree, &Result<EspIdfVersion>) -> Result<Vec<Tools>>,
{
self.tools_provider = Some(Box::new(provider));
self
Expand Down Expand Up @@ -367,19 +383,19 @@ impl Installer {
)
})?;

let (repository, managed_repo) = match self.esp_idf_origin {
let (tree, managed_repo) = match self.esp_idf_origin {
EspIdfOrigin::Managed(managed) => (
managed.open_or_clone(
SourceTree::Git(managed.open_or_clone(
&install_dir,
git::CloneOptions::new().depth(1),
DEFAULT_ESP_IDF_REPOSITORY,
MANAGED_ESP_IDF_REPOS_DIR_BASE,
)?,
)?),
true,
),
EspIdfOrigin::Custom(repository) => (repository, false),
EspIdfOrigin::Custom(repository) => (SourceTree::Git(repository), false),
};
let version = EspIdfVersion::try_from(&repository);
let version = EspIdfVersion::try_from(&tree);

let path_var_sep = if cfg!(windows) { ';' } else { ':' };

Expand All @@ -388,10 +404,10 @@ impl Installer {
// TODO: also install python
python::check_python_at_least(3, 6)?;

let idf_tools_py = path_buf![repository.worktree(), "tools", "idf_tools.py"];
let idf_tools_py = path_buf![tree.path(), "tools", "idf_tools.py"];

let get_python_env_dir = || -> Result<String> {
cmd!(PYTHON, &idf_tools_py, "--idf-path", repository.worktree(), "--quiet", "export", "--format=key-value";
cmd!(PYTHON, &idf_tools_py, "--idf-path", tree.path(), "--quiet", "export", "--format=key-value";
ignore_exitcode=(), env=(IDF_TOOLS_PATH_VAR, &install_dir),
env_remove=(IDF_PYTHON_ENV_PATH_VAR), env_remove=("MSYSTEM"))
.stdout()?
Expand All @@ -408,7 +424,7 @@ impl Installer {
let python_env_dir: PathBuf = match get_python_env_dir() {
Ok(dir) if Path::new(&dir).exists() => dir,
_ => {
cmd!(PYTHON, &idf_tools_py, "--idf-path", repository.worktree(), "--non-interactive", "install-python-env";
cmd!(PYTHON, &idf_tools_py, "--idf-path", tree.path(), "--non-interactive", "install-python-env";
env=(IDF_TOOLS_PATH_VAR, &install_dir), env_remove=("MSYSTEM"), env_remove=(IDF_PYTHON_ENV_PATH_VAR)).run()?;
get_python_env_dir()?
}
Expand All @@ -427,7 +443,7 @@ impl Installer {
// Install tools.
let tools = self
.tools_provider
.map(|p| p(&repository, &version))
.map(|p| p(&tree, &version))
.unwrap_or(Ok(Vec::new()))?;
let mut exported_paths = HashSet::new();
for tool in tools {
Expand All @@ -439,7 +455,7 @@ impl Installer {
.flatten();

// Install the tools.
cmd!(&python, &idf_tools_py, "--idf-path", repository.worktree(), @tools_json.clone(), "install";
cmd!(&python, &idf_tools_py, "--idf-path", tree.path(), @tools_json.clone(), "install";
env=(IDF_TOOLS_PATH_VAR, &install_dir), args=(tool.tools)).run()?;

// Get the paths to the tools.
Expand All @@ -452,7 +468,7 @@ impl Installer {
// native paths in rust. So we remove that environment variable when calling
// idf_tools.py.
exported_paths.extend(
cmd!(&python, &idf_tools_py, "--idf-path", repository.worktree(), @tools_json, "--quiet", "export", "--format=key-value";
cmd!(&python, &idf_tools_py, "--idf-path", tree.path(), @tools_json, "--quiet", "export", "--format=key-value";
ignore_exitcode=(), env=(IDF_TOOLS_PATH_VAR, &install_dir), env_remove=("MSYSTEM")).stdout()?
.lines()
.find(|s| s.trim_start().starts_with("PATH="))
Expand All @@ -474,7 +490,7 @@ impl Installer {
log::debug!("Using PATH='{}'", &paths.to_string_lossy());

Ok(EspIdf {
repository,
tree,
exported_path: paths,
venv_python: python,
version,
Expand Down

0 comments on commit 2d9c08e

Please sign in to comment.