Skip to main content

cageforge_command/environment/
model.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use std::collections::{BTreeMap, HashMap};
4use std::ffi::OsString;
5
6use wildmatch::WildMatch;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub(super) struct CaseFoldedText(pub(super) Vec<Vec<char>>);
10
11/// Environment construction rules for a command.
12///
13/// Overrides are kept in a sorted map for deterministic inspection and are
14/// applied by a backend after selecting the requested base environment. A
15/// value of [`EnvironmentOverride::Remove`] is distinct from setting an empty
16/// string. Variable names are one logical, case-insensitive namespace, so a
17/// later case variant replaces an earlier override.
18#[derive(Debug, Clone)]
19pub struct EnvironmentSpec {
20    pub(super) base: EnvironmentBase,
21    pub(super) overrides: BTreeMap<OsString, EnvironmentOverride>,
22    pub(super) override_names: HashMap<EnvironmentNameKey, OsString>,
23    pub(super) filters: BTreeMap<EnvironmentPattern, EnvironmentFilterAction>,
24}
25
26/// A base environment selected by the process adapter.
27///
28/// The constructors encode the base that the variables represent. This keeps
29/// an [`EnvironmentSpec`] from being applied to an arbitrarily broad map while
30/// claiming that the map is empty or platform-core input.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct EnvironmentInput {
33    pub(super) base: EnvironmentBase,
34    pub(super) variables: BTreeMap<OsString, OsString>,
35}
36
37/// A platform-selected snapshot used to construct a core environment input.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct CoreEnvironment {
40    pub(super) variables: BTreeMap<OsString, OsString>,
41}
42
43/// An explicit change to one environment variable.
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub enum EnvironmentOverride {
46    /// Set the variable to the given value.
47    Set(OsString),
48    /// Remove the variable from the final environment.
49    Remove,
50}
51
52/// A wildcard pattern matched against an environment variable name.
53///
54/// The pattern language is deliberately small and portable: `*` matches zero
55/// or more Unicode scalar values and `?` matches one. Matching is
56/// case-insensitive so the same policy is safe on POSIX and Windows hosts.
57#[derive(Debug, Clone)]
58pub struct EnvironmentPattern {
59    pub(super) original: String,
60    pub(super) canonical: CaseFoldedText,
61    pub(super) matcher: WildMatch,
62}
63
64/// A case-insensitive identity key for an operating-system environment name.
65///
66/// Valid Unicode names use the portable case-insensitive Cageforge policy.
67/// Malformed native strings retain their exact code units or bytes so distinct
68/// names can never collide through lossy conversion. Backends and composition
69/// layers can use this key to deduplicate names consistently with
70/// [`EnvironmentSpec`].
71#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
72pub struct EnvironmentNameKey(pub(super) EnvironmentNameIdentity);
73
74#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
75pub(super) enum EnvironmentNameIdentity {
76    Folded(CaseFoldedText),
77    #[cfg(unix)]
78    NativeBytes(Vec<u8>),
79    #[cfg(windows)]
80    NativeWide(Vec<u16>),
81}
82
83/// The action applied to a matching environment-variable pattern.
84///
85/// Include and exclude are evaluated with named precedence rules; their enum
86/// declaration order is not an environment authorization order.
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88pub enum EnvironmentFilterAction {
89    /// Retain matching variables when the include allowlist is active.
90    Include,
91    /// Remove matching variables with deny precedence over inclusion.
92    Exclude,
93}
94
95/// Selects the base environment from which a command is launched.
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
97pub enum EnvironmentBase {
98    /// Inherit every variable from the launching process.
99    All,
100    /// Inherit the platform's conservative set of core variables.
101    Core,
102    /// Start with no inherited variables.
103    None,
104}