
Variables.pudu
Pudu119 lines5.1 KB
1/** @Environment.Variables.Module — loaded values settled over the process */2module PuduLangEnvironment.Variables34import Std.App.Secret as Secret5import Std.Env as Env6import Std.Map as Map7import Std.Process as Process8import PuduLangEnvironment.Constants.Messages as Messages9import PuduLangEnvironment.Constants.Names as Names10import PuduLangEnvironment.Domain.Layers as Layers11import PuduLangEnvironment.Domain.Values as Values12import PuduLangEnvironment as Environment13import PuduLangEnvironment.Utils.Template as Template1415/** @Environment.Variables.Variables — a settled view whose values stay hidden */16export type Variables = {17 lookup: fn(Str) -> Option[Str],18 applied: Array[Str],19 sources: Array[Str],20 skipped: Array[Environment.Problem]21}22232425export fn settled(loaded: &Map[Str, Str], current: &Map[Str, Str], overwrite: Bool, sources: Array[Str], skipped: Array[Environment.Problem]) -> Variables {26 let view = Layers.settle(loaded, current, overwrite)27 let values = view.values28 Variables{lookup: fn(key: Str) -> Option[Str] { values.get(key) }, applied: view.applied, sources: sources, skipped: skipped}29}303132export fn process() -> Variables {33 settled(&Map.empty(), &Map.fromPairs(&Env.variables()), true, [], [])34}353637export fn find(variables: &Variables, key: Str) -> Option[Str] {38 let held = (variables.lookup)(key) ?39 if held.isEmpty() { None } else { Some(held) }40}414243export fn has(variables: &Variables, key: Str) -> Bool { find(variables, key) != None }444546export fn text(variables: &Variables, key: Str) -> Result[Str, Environment.Problem] {47 match find(variables, key) {48 case Some(held) => Ok(held)49 case None => Err(Environment.Missing([key]))50 }51}525354export fn int(variables: &Variables, key: Str) -> Result[Int, Environment.Problem] {55 converted(variables, key, Values.toInt, Names.KIND_INT)56}575859export fn findInt(variables: &Variables, key: Str) -> Option[Int] { Values.toInt(find(variables, key) ?) }606162export fn float(variables: &Variables, key: Str) -> Result[Float64, Environment.Problem] {63 converted(variables, key, Values.toFloat, Names.KIND_FLOAT)64}656667export fn findFloat(variables: &Variables, key: Str) -> Option[Float64] { Values.toFloat(find(variables, key) ?) }686970export fn decimal(variables: &Variables, key: Str) -> Result[Decimal, Environment.Problem] {71 converted(variables, key, Values.toDecimal, Names.KIND_DECIMAL)72}737475export fn findDecimal(variables: &Variables, key: Str) -> Option[Decimal] { Values.toDecimal(find(variables, key) ?) }767778export fn bool(variables: &Variables, key: Str) -> Result[Bool, Environment.Problem] {79 converted(variables, key, Values.toBool, Names.KIND_BOOL)80}818283export fn findBool(variables: &Variables, key: Str) -> Option[Bool] { Values.toBool(find(variables, key) ?) }848586export fn secret(variables: &Variables, key: Str) -> Result[Secret.Secret, Environment.Problem] {87 Ok(Secret.secret(text(variables, key) ?))88}89909192export fn require(variables: &Variables, keys: &Array[Str]) -> Result[(), Environment.Problem] {93 let absent = keys.filter(|key: Str| !has(variables, key))94 if absent.isEmpty() { Ok(()) } else { Err(Environment.Missing(absent)) }95}969798export fn apply(variables: &Variables, launch: &Process.Launch) -> Process.Launch {99 var given = *launch100 for key in variables.applied {101 if let Some(held) = (variables.lookup)(key) { given = Process.Launch{..given, variables: given.variables.push((key, held))} }102 }103 given104}105106107export fn describe(variables: &Variables) -> Str {108 let from = if variables.sources.isEmpty() { Messages.NO_SOURCES } else { variables.sources.join(Messages.LIST_SEPARATOR) }109 Template.fill(Messages.DESCRIBED, &[show(variables.applied.length()), from])110}111112113fn converted[T](variables: &Variables, key: Str, convert: fn(Str) -> Option[T], kind: Str) -> Result[T, Environment.Problem] {114 match convert(text(variables, key) ?) {115 case Some(value) => Ok(value)116 case None => Err(Environment.Malformed(key, kind))117 }118}119