use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq)]
pub enum ShadowType {
ShellBuiltin(String), PathExecutable(String), }
#[derive(Debug, Clone, PartialEq)]
pub enum TaskDefinitionType {
Makefile,
PackageJson,
PyprojectToml,
ShellScript,
Taskfile,
MavenPom,
Gradle,
GitHubActions,
DockerCompose,
TravisCi,
CMake,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TaskRunner {
Make,
NodeNpm,
NodeYarn,
NodePnpm,
NodeBun,
PythonUv,
PythonPoetry,
PythonPoe,
ShellScript,
Task,
Maven,
Gradle,
Act,
DockerCompose,
TravisCi,
CMake,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)]
pub enum TaskFileStatus {
Parsed,
NotImplemented,
ParseError(String),
NotReadable(String),
NotFound,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TaskDefinitionFile {
pub path: PathBuf,
pub definition_type: TaskDefinitionType,
pub status: TaskFileStatus,
}
#[derive(Debug, Default)]
#[allow(dead_code)]
pub struct DiscoveredTaskDefinitions {
pub makefile: Option<TaskDefinitionFile>,
pub package_json: Option<TaskDefinitionFile>,
pub pyproject_toml: Option<TaskDefinitionFile>,
pub taskfile: Option<TaskDefinitionFile>,
pub maven_pom: Option<TaskDefinitionFile>,
pub gradle: Option<TaskDefinitionFile>,
pub github_actions: Option<TaskDefinitionFile>,
pub docker_compose: Option<TaskDefinitionFile>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Task {
pub name: String,
pub file_path: PathBuf,
pub definition_type: TaskDefinitionType,
pub runner: TaskRunner,
pub source_name: String,
pub description: Option<String>,
pub shadowed_by: Option<ShadowType>,
pub disambiguated_name: Option<String>,
}
impl TaskRunner {
pub fn get_command(&self, task: &Task) -> String {
match self {
TaskRunner::Make => format!("make {}", task.source_name),
TaskRunner::NodeNpm => format!("npm run {}", task.source_name),
TaskRunner::NodeYarn => format!("yarn run {}", task.source_name),
TaskRunner::NodePnpm => format!("pnpm run {}", task.source_name),
TaskRunner::NodeBun => format!("bun run {}", task.source_name),
TaskRunner::PythonUv => format!("uv run {}", task.source_name),
TaskRunner::PythonPoetry => format!("poetry run {}", task.source_name),
TaskRunner::PythonPoe => format!("poe {}", task.source_name),
TaskRunner::ShellScript => format!("./{}", task.source_name),
TaskRunner::Task => format!("task {}", task.source_name),
TaskRunner::Maven => format!("mvn {}", task.source_name),
TaskRunner::Gradle => format!("gradle {}", task.source_name),
TaskRunner::Act => format!("act -W {}", task.file_path.display()),
TaskRunner::DockerCompose => {
if task.source_name == "up" {
"docker compose up".to_string()
} else if task.source_name == "down" {
"docker compose down".to_string()
} else {
format!("docker compose run {}", task.source_name)
}
}
TaskRunner::TravisCi => {
format!(
"# Travis CI task '{}' - not executable locally",
task.source_name
)
}
TaskRunner::CMake => {
format!(
"cmake -S . -B build && cmake --build build --target {}",
task.source_name
)
}
}
}
pub fn short_name(&self) -> &'static str {
match self {
TaskRunner::Make => "make",
TaskRunner::NodeNpm => "npm",
TaskRunner::NodeYarn => "yarn",
TaskRunner::NodePnpm => "pnpm",
TaskRunner::NodeBun => "bun",
TaskRunner::PythonUv => "uv",
TaskRunner::PythonPoetry => "poetry",
TaskRunner::PythonPoe => "poe",
TaskRunner::ShellScript => "sh",
TaskRunner::Task => "task",
TaskRunner::Maven => "mvn",
TaskRunner::Gradle => "gradle",
TaskRunner::Act => "act",
TaskRunner::DockerCompose => "docker compose",
TaskRunner::TravisCi => "travis",
TaskRunner::CMake => "cmake",
}
}
}
#[derive(Debug, Default)]
#[allow(dead_code)]
pub struct DiscoveredTasks {
pub tasks: Vec<Task>,
pub errors: Vec<String>,
pub definitions: DiscoveredTaskDefinitions,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum AllowScope {
Once,
Task,
File,
Directory,
Deny,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AllowlistEntry {
#[serde(
serialize_with = "serialize_path",
deserialize_with = "deserialize_path"
)]
pub path: PathBuf,
pub scope: AllowScope,
pub tasks: Option<Vec<String>>,
}
fn serialize_path<S>(path: &PathBuf, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&path.to_string_lossy())
}
fn deserialize_path<'de, D>(deserializer: D) -> Result<PathBuf, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(PathBuf::from(s))
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct Allowlist {
#[serde(default)]
pub entries: Vec<AllowlistEntry>,
}