use std::path::{Path, PathBuf};
#[derive(Clone, Debug, PartialEq, Eq)]
pub(super) struct DiscoveredWorkflow {
pub(super) relative_path: String,
pub(super) absolute_path: PathBuf,
pub(super) label: String,
}
pub(super) fn discover_workflow_sources(workspace: &Path) -> Vec<DiscoveredWorkflow> {
let root = workspace.join(".rho").join("workflows");
if !root.is_dir() {
return Vec::new();
}
let mut found = Vec::new();
let Ok(entries) = std::fs::read_dir(&root) else {
return Vec::new();
};
for entry in entries.flatten() {
let path = entry.path();
let Ok(file_type) = entry.file_type() else {
continue;
};
if file_type.is_file() {
if is_star_file(&path) {
push_discovered(workspace, path, &mut found);
}
continue;
}
if !file_type.is_dir() {
continue;
}
let entry_star = path.join("workflow.star");
if std::fs::symlink_metadata(&entry_star).is_ok_and(|metadata| metadata.is_file()) {
push_discovered(workspace, entry_star, &mut found);
}
}
found.sort_by(|left, right| left.relative_path.cmp(&right.relative_path));
found
}
fn is_star_file(path: &Path) -> bool {
path.extension().and_then(|ext| ext.to_str()) == Some("star")
}
fn push_discovered(workspace: &Path, absolute: PathBuf, out: &mut Vec<DiscoveredWorkflow>) {
let Ok(relative) = absolute.strip_prefix(workspace) else {
return;
};
let relative_path = relative
.components()
.map(|component| component.as_os_str().to_string_lossy())
.collect::<Vec<_>>()
.join("/");
if relative_path.is_empty() {
return;
}
let label = workflow_label(&relative_path);
out.push(DiscoveredWorkflow {
relative_path,
absolute_path: absolute,
label,
});
}
fn workflow_label(relative_path: &str) -> String {
let path = Path::new(relative_path);
if path
.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name == "workflow.star")
{
if let Some(parent) = path.parent().and_then(|parent| parent.file_name()) {
return parent.to_string_lossy().into_owned();
}
}
path.file_stem()
.map(|stem| stem.to_string_lossy().into_owned())
.unwrap_or_else(|| relative_path.to_owned())
}
#[cfg(test)]
#[path = "workflow_discover_tests.rs"]
mod tests;