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