use anyhow::{Context, Result, bail};
use repolith_actions::cargo_install::{CargoInstall, CargoSource};
use repolith_actions::git_clone::GitClone;
use repolith_actions::paths::expand_tilde;
use repolith_core::action::Action;
use repolith_core::manifest::{ActionEntry, Manifest, action_kind};
use repolith_core::types::ActionId;
use std::path::PathBuf;
fn default_install_to() -> PathBuf {
dirs::home_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join(".repolith")
}
pub fn build_actions_from_manifest(manifest: &Manifest) -> Result<Vec<Box<dyn Action>>> {
let mut out: Vec<Box<dyn Action>> = Vec::new();
for node in &manifest.nodes {
let mut prev_id: Option<ActionId> = None;
for (idx, entry) in node.actions.iter().enumerate() {
let kind = action_kind(entry);
let id = ActionId(format!("{}::{}::{}", node.id, kind, idx));
let deps = prev_id.iter().cloned().collect::<Vec<_>>();
let action: Box<dyn Action> = match entry {
ActionEntry::GitClone => {
let url = node.git.clone().with_context(|| {
format!(
"node `{}`: git-clone action requires `git` URL on the node",
node.id
)
})?;
let path = node
.path
.as_deref()
.map_or_else(|| PathBuf::from(format!("./{}", node.id)), expand_tilde);
Box::new(GitClone {
id: id.clone(),
repo_url: url,
path,
deps,
})
}
ActionEntry::CargoInstall {
crate_name,
features,
install_to,
} => {
let source = if let Some(p) = &node.path {
CargoSource::Path {
path: expand_tilde(p),
}
} else if let Some(url) = &node.git {
CargoSource::Git {
url: url.clone(),
branch: None,
}
} else {
bail!(
"node `{}`: cargo-install action requires either `git` or `path` on the node",
node.id
);
};
Box::new(CargoInstall {
id: id.clone(),
source,
crate_name: crate_name.clone().or_else(|| Some(node.id.clone())),
features: features.clone(),
install_to: install_to
.as_deref()
.map_or_else(default_install_to, expand_tilde),
deps,
})
}
};
out.push(action);
prev_id = Some(id);
}
}
Ok(out)
}