envvars/lib.rs
1//! # envvars
2//!
3//! `envvars` helps to detect a list of available shells and related environment
4//! variables. If works in two steps:
5//!
6//! - detecting a list of available shells and creating `Profile` for each found
7//! shell
8//! - loading a list of environment variables for selected or each shell
9//!
10//! ## Usage
11//!
12//! Getting all available (detected) shells and related to each shell list of
13//! environment variables
14//!
15//! ```
16//! use envvars::{get_profiles, Profile};
17//!
18//! let mut profiles: Vec<Profile> = get_profiles().unwrap();
19//!
20//! // By default profile doesn't have loaded list of environment variables.
21//! // It should be loaded calling method load().
22//! profiles.iter_mut().for_each(|profile| {
23//! // Attempt to load envvars
24//! if let Err(err) = profile.load() {
25//! eprintln!("Cannot load envvars for {}: {err}", profile.name);
26//! }
27//! if let Some(envvars) = &profile.envvars {
28//! println!("Environment variables for {}", profile.name);
29//! envvars.iter().for_each(|(key, value)| {
30//! println!("{key}: {value}");
31//! });
32//! }
33//! });
34//! ```
35//!
36//! Extract environment variables without shell context.
37//!
38//! ```
39//! use std::collections::HashMap;
40//! use envvars::get_context_envvars;
41//!
42//! let vars: HashMap<String, String> = get_context_envvars().unwrap();
43//!
44//! assert!(vars.contains_key("PATH") || vars.contains_key("Path") || vars.contains_key("path"));
45//! ```
46//!
47//! ## Diffrence from `std::env::vars`
48//!
49//! `envvars` actually executes each found `shell` it means: all settings of the target
50//! shell will be inited before a list of environment variables will be requested. That's
51//! very sensitive if the configuration of some shell includes some initialization script,
52//! which affects environment variables. That means in some cases `std::env::vars` and
53//! `envvars` could give different results.
54//!
55//! ## How it works
56//!
57//! Under the hood, `envvars` takes each shell, and executes it with a command,
58//! which posts a list of environment variables to `stdout`. As soon as executing
59//! is done, `envvars` reads `stdout` and parse environment variables into
60//! `HashMap<String, String>`.
61//!
62//! As soon as extracting process could take a sensitive time (~1sec on windows
63//! and ~10ms on Unix-based OS), `envvars` doesn't extract environment variables
64//! during detecting the shell's profiles. That's the developer's decision when it
65//! should be done for the selected or each profile.
66//!
67//! `envvars` creates a small executable application in the system's temporary folder.
68//! This application is used to "drop" list of environment variables into `stdout`
69//! of the parent process and does nothing else. As soon as `envvars` instance is
70//! dropped, the application would be removed from the disk.
71//!
72//! For security reasons `envvars` checks the checksum of the extractor each time
73//! before using it. If a checksum is invalid (the file was damaged/changed etc),
74//! `envars` will remove a corrupted file and create a new one.
75//!
76//! ## Unix specific
77//!
78//! `envvars` reads `/etc/shells` and analyze each shell from a list
79//!
80//! ## Windows specific
81//!
82//! `envvars` checks for availability next shells:
83//! - Command Prompt
84//! - Windows PowerShell
85//! - .NET Core PowerShell Global Tool
86//! - Cygwin x64
87//! - Cygwin
88//! - bash (MSYS2)
89//! - GitBash
90//!
91//! ## Guaranteed results
92//!
93//! Because `envvars` tries to initialize each shell and "drop" a list of environment
94//! variables to `stdout`, the shell should support the possibility to put a command as
95//! an argument, for example: `/bin/bash -c path_to_command`. Obviously not many, but
96//! still some shells don't support it (like windows command prompt). In this case, you
97//! still can use `get_context_envvars()` to get a list of environment variables without
98//! the shell's context.
99//!
100
101#[macro_use]
102extern crate lazy_static;
103use std::{collections::HashMap, sync::Mutex};
104mod assets;
105mod checksum;
106mod decoder;
107mod error;
108mod extractor;
109mod profiles;
110
111pub use error::Error;
112pub use extractor::cleanup;
113use extractor::Extractor;
114pub use profiles::{get as get_profiles, Profile};
115
116lazy_static! {
117 #[doc(hidden)]
118 static ref EXTRACTOR: Mutex<Extractor> = Mutex::new(Extractor::new());
119}
120
121/// Extract environment variables without shell context.
122///
123/// # Examples
124///
125/// ```
126/// use std::collections::HashMap;
127/// use envvars::get_context_envvars;
128///
129/// let vars: HashMap<String, String> = get_context_envvars().unwrap();
130///
131/// assert!(vars.contains_key("PATH") || vars.contains_key("Path") || vars.contains_key("path"));
132/// ```
133pub fn get_context_envvars() -> Result<HashMap<String, String>, Error> {
134 EXTRACTOR
135 .lock()
136 .map_err(|e| Error::PoisonError(e.to_string()))?
137 .get(None, &Vec::new())
138}