Skip to main content

Environment

Struct Environment 

Source
pub struct Environment {
    pub variables: BTreeMap<String, String>,
    pub auth: Option<Auth>,
    pub source: Option<PathBuf>,
    /* private fields */
}
Expand description

A set of variables a request can be sent against.

Environment::default is the empty environment: no variables, and no file behind it. That is the state of a project with no .sendra/environments/ at all, and it is not an error — a request with no {{...}} in it is untouched by substitution, so Sendra behaves exactly as it did before this existed.

Fields§

§variables: BTreeMap<String, String>

The file’s contents, verbatim. Values still hold their ${VAR} references: those are resolved when a variable is used, not when the file is read. See Environment::lookup.

§auth: Option<Auth>

A default auth: block, reusing Request::auth’s exact shape, applied by Environment::apply to every request run against this environment that sets no auth: of its own.

Fully replaced, never merged, by a request’s own auth: — the same “two things claiming ownership of one setting” stance Request::auth already takes against an explicit Authorization header, applied one layer up: a request that wants different credentials than its environment’s default writes its own auth: block, in full, rather than overriding one field of this one.

bearer/basic/api_key still hold unsubstituted {{var}}/${VAR} text here, exactly like variables — resolved, against this same environment, only when apply actually uses it.

§source: Option<PathBuf>

The file this came from, or None for an environment that was not read from disk (the empty default, or one built in a test). Carried so a missing-variable error can name the file to go and fix.

Implementations§

Source§

impl Environment

Source

pub fn apply(&self, request: &Request) -> Result<Request, SendraError>

Substitute this environment into request, returning the request as it will be sent.

Every {{name}} in url, in each header name, in each header value, in body and in the values of the assertions block is replaced. An unknown name is VariableNotFound, and a value whose ${VAR} is not in the OS environment is EnvVarNotSet — never an empty string, and never a half-substituted request. The whole request is built before it is sent, so both failures land before any of its bytes go out.

Headers are substituted in place, entry by entry, so order is preserved exactly as written in the file. Two header names that were distinct in the file can collide once substituted ({{prefix}}-Key and X-Key, say) — that used to be an error back when headers were a map and a silent collision would have dropped a value, but Request.headers is a Vec that allows a name to repeat, so a post-substitution collision is now exactly that: two headers of the same name, sent as written.

Assertions are substituted for the same reason the rest of the file is: what a staging response should say is exactly as environment-dependent as what the request asks for, and body_contains: '{{tenant}}' would otherwise compare against the literal braces. See apply_assertions for the one line it draws.

Source

pub fn apply_collection( &self, collection: &Collection, ) -> Result<Collection, SendraError>

Environment::apply for every request in a collection, in file order.

All or nothing: one request that cannot be substituted fails the whole call. That suits a caller that wants a fully-resolved collection in hand, which is what this returns. It is not what sendra run does with a collection — there each request is substituted as it is reached, so a broken one fails on its own and the requests around it are still sent, in the same way a refused connection does not cancel its siblings. A caller wanting those per-request outcomes calls Environment::apply in a loop and keeps each Result.

The collection’s own name is left alone for the same reason a request’s is.

Source

pub fn apply_document( &self, document: &Document, ) -> Result<Document, SendraError>

Environment::apply over whichever shape a file turned out to hold.

Source§

impl Environment

Source

pub fn from_yaml_str(yaml: &str) -> Result<Self, SendraError>

Parse an environment from a YAML string.

Source

pub fn from_path(path: impl AsRef<Path>) -> Result<Self, SendraError>

Read and parse an environment file from disk.

Source

pub fn resolve(name: &str) -> Result<Self, SendraError>

Find and load the environment called name, starting from the current directory.

A missing environment file is not an error, it is the empty environment — the same call the config module makes for a missing config file. What is an error is a request asking for a variable the environment does not have, empty or not; that surfaces in Environment::apply, where the message can name the variable.

Source

pub fn resolve_from(start_dir: &Path, name: &str) -> Result<Self, SendraError>

Environment::resolve with the starting directory passed in, so the search is testable against a temporary tree without changing the process’s working directory.

Source

pub fn with_captured(&self, captured: &BTreeMap<String, String>) -> Self

This environment as it stands at one point in a run: the file’s own variables, plus everything captured by the requests that have already finished.

This is the whole of the accumulating store. A run holds one growing map and calls this once per request, so the environment a request is substituted against is a view built from the captures that existed when that request was reached — request 3 sees what 1 and 2 captured, request 1 sees nothing, and no request can see forwards. Threading the growth through a rebuilt value rather than through a mutable Environment is what makes that structural instead of a rule the loop has to remember: there is no &mut Environment anywhere for a later capture to reach an earlier request through.

The copy is a BTreeMap clone per request, which is nothing at the sizes a hand-written collection reaches, and it buys the property that the value handed to apply cannot change underneath it.

Nothing else changes: source, auth, and the OS-environment override tests use, are carried through untouched.

Source

pub fn names(&self) -> Vec<String>

The variable names this environment’s file defines, sorted — the list a “no variable named X” error offers, the way RequestNotFound offers request names.

Captured names are deliberately not in here: this list is offered under the name of the file it came from, and a capture did not come from that file. They are reported beside it — see captured_names.

Source

pub fn captured_names(&self) -> Vec<String>

The names captured by earlier requests in this run, sorted. Empty unless with_captured put something there.

Source

pub fn is_empty(&self) -> bool

Whether this environment defines no variables at all — captures included, since a {{name}} can resolve against either.

Source

pub fn validate(&self) -> Result<(), SendraError>

Every rule Deserialize cannot express, checked directly rather than only ever at parse time: auth’s own mutual-exclusivity and (for oauth) grant-field rules — the exact same checks from_file already runs when reading a file from disk, exposed here so a caller building or mutating an Environment in memory (a front-end applying an edit, say) can ask the question before save_to_path ever writes it, the same “check before writing rather than only discover it broken on the next load” reasoning Document::validate documents for its own callers. variables has no rule of its own to check: every BTreeMap<String, String>, empty included, is already a valid environment — see this module’s own doc comment on why an empty file is not an error.

Source

pub fn to_yaml_string(&self) -> Result<String, SendraError>

Serializes this environment back to YAML, exactly the flat shape from_yaml_str/from_path parse: every variable as a top-level key, plus auth: when set — see EnvironmentFile’s own Serialize impl for why this goes through that type’s hand-written map serialization rather than a derived one on Environment itself. captured/os_env_override are runtime-only (never part of a file — see their own doc comments) and so play no part here; only variables and auth round-trip.

Source

pub fn save_to_path(&self, path: impl AsRef<Path>) -> Result<(), SendraError>

Writes this environment back to path, atomically — the exact same write-to-a-sibling-temp-file-then-rename guarantee Document::save_to_path documents for a collection file, reusing its own [unique_temp_path] helper rather than a second implementation of the same atomicity argument. Refuses to write an invalid environment (see validate) before the temp file is even created, for the same reason Document::save_to_path checks first: an in-memory edit that left auth invalid would otherwise still produce a file that parses back as YAML but fails validation the next time anything loads it.

Trait Implementations§

Source§

impl Clone for Environment

Source§

fn clone(&self) -> Environment

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Environment

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Environment

Source§

fn default() -> Environment

Returns the “default value” for a type. Read more
Source§

impl Eq for Environment

Source§

impl PartialEq for Environment

Source§

fn eq(&self, other: &Environment) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Environment

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more