use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use indexmap::IndexSet;
use scallop::{ExecStatus, functions};
use strum::{AsRefStr, Display, EnumIter, EnumString};
use super::commands::functions::emake;
use super::environment::Variable::D;
use super::hooks::{Hook, HookBuilder, HookKind};
use super::utils::makefile_exists;
use super::{BuildData, BuildFn, get_build_mut};
pub(crate) mod eapi5;
pub(crate) mod eapi6;
fn emake_install(build: &mut BuildData) -> scallop::Result<ExecStatus> {
if makefile_exists() {
let destdir = build.env.get(&D).expect("D undefined");
let args = &[&format!("DESTDIR={destdir}"), "install"];
emake(args)?;
}
Ok(ExecStatus::Success)
}
#[derive(AsRefStr, Display, EnumIter, EnumString, Debug, Copy, Clone)]
#[strum(serialize_all = "snake_case")]
pub enum PhaseKind {
PkgConfig,
PkgInfo,
PkgNofetch,
PkgPostinst,
PkgPostrm,
PkgPreinst,
PkgPrerm,
PkgPretend,
PkgSetup,
SrcCompile,
SrcConfigure,
SrcInstall,
SrcPrepare,
SrcTest,
SrcUnpack,
}
impl PhaseKind {
pub(crate) fn func(self, func: BuildFn) -> Phase {
Phase {
kind: self,
func: Some(func),
hooks: Default::default(),
}
}
pub(crate) fn pre(self, name: &str, func: BuildFn) -> HookBuilder {
HookBuilder {
phase: self,
kind: HookKind::Pre,
name: name.to_string(),
func,
priority: 0,
}
}
pub(crate) fn post(self, name: &str, func: BuildFn) -> HookBuilder {
HookBuilder {
phase: self,
kind: HookKind::Post,
name: name.to_string(),
func,
priority: 0,
}
}
pub fn name(&self) -> &str {
self.as_ref()
.split_once('_')
.unwrap_or_else(|| panic!("invalid phase name: {self}"))
.1
}
}
impl PartialEq for PhaseKind {
fn eq(&self, other: &Self) -> bool {
self.name() == other.name()
}
}
impl Eq for PhaseKind {}
impl Hash for PhaseKind {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name().hash(state);
}
}
impl Borrow<str> for PhaseKind {
fn borrow(&self) -> &str {
self.name()
}
}
impl Ord for PhaseKind {
fn cmp(&self, other: &Self) -> Ordering {
self.name().cmp(other.name())
}
}
impl PartialOrd for PhaseKind {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone)]
pub struct Phase {
pub kind: PhaseKind,
func: Option<BuildFn>,
pub(crate) hooks: HashMap<HookKind, IndexSet<Hook>>,
}
impl AsRef<str> for Phase {
fn as_ref(&self) -> &str {
self.kind.as_ref()
}
}
impl fmt::Display for Phase {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl PartialEq for Phase {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind
}
}
impl Eq for Phase {}
impl Ord for Phase {
fn cmp(&self, other: &Self) -> Ordering {
self.kind.cmp(&other.kind)
}
}
impl PartialOrd for Phase {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for Phase {
fn hash<H: Hasher>(&self, state: &mut H) {
self.kind.hash(state);
}
}
impl Borrow<PhaseKind> for Phase {
fn borrow(&self) -> &PhaseKind {
&self.kind
}
}
impl Borrow<str> for Phase {
fn borrow(&self) -> &str {
self.kind.name()
}
}
impl From<PhaseKind> for Phase {
fn from(value: PhaseKind) -> Self {
Self {
kind: value,
func: None,
hooks: Default::default(),
}
}
}
impl Phase {
#[allow(dead_code)]
pub(crate) fn run(&self) -> scallop::Result<ExecStatus> {
let build = get_build_mut();
let _scope = build.scoped(self.kind);
build.set_vars()?;
if let Some(hooks) = self.hooks.get(&HookKind::Pre) {
for hook in hooks {
hook.run(build)?;
}
}
if let Some(mut func) = functions::find(format!("pre_{self}")) {
func.execute(&[])?;
}
if let Some(mut func) = functions::find(self) {
func.execute(&[])?;
} else {
self.default()?;
}
if let Some(mut func) = functions::find(format!("post_{self}")) {
func.execute(&[])?;
}
if let Some(hooks) = self.hooks.get(&HookKind::Post) {
for hook in hooks {
hook.run(build)?;
}
}
for var in build.eapi().env() {
if var.is_allowed(&build.scope) {
var.unbind()?;
}
}
Ok(ExecStatus::Success)
}
pub(crate) fn default(&self) -> scallop::Result<ExecStatus> {
match self.func {
Some(func) => func(get_build_mut()),
None => Ok(ExecStatus::Success),
}
}
pub fn name(&self) -> &str {
self.kind.name()
}
}