2022-11-28 22:57:35 +00:00
|
|
|
/*! [`BuiltinPlanner`]s and traits to create new types which can be used to plan out an [`InstallPlan`]
|
|
|
|
|
2023-02-01 20:35:52 +00:00
|
|
|
It's a [`Planner`]s job to construct (if possible) a valid [`InstallPlan`] for the host. Some planners are operating system specific, others are device specific.
|
2022-11-28 22:57:35 +00:00
|
|
|
|
|
|
|
[`Planner`]s contain their planner specific settings, typically alongside a [`CommonSettings`][crate::settings::CommonSettings].
|
|
|
|
|
|
|
|
[`BuiltinPlanner::default()`] offers a way to get the default builtin planner for a given host.
|
|
|
|
|
|
|
|
Custom Planners can also be used to create a platform, project, or organization specific install.
|
|
|
|
|
|
|
|
A custom [`Planner`] can be created:
|
|
|
|
|
|
|
|
```rust,no_run
|
|
|
|
use std::{error::Error, collections::HashMap};
|
2022-12-19 18:26:58 +00:00
|
|
|
use nix_installer::{
|
2022-11-28 22:57:35 +00:00
|
|
|
InstallPlan,
|
|
|
|
settings::{CommonSettings, InstallSettingsError},
|
2023-02-01 20:35:52 +00:00
|
|
|
planner::{Planner, PlannerError},
|
|
|
|
action::{Action, StatefulAction, base::CreateFile},
|
2022-11-28 22:57:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
|
|
pub struct MyPlanner {
|
|
|
|
pub common: CommonSettings,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
#[typetag::serde(name = "my-planner")]
|
|
|
|
impl Planner for MyPlanner {
|
|
|
|
async fn default() -> Result<Self, PlannerError> {
|
|
|
|
Ok(Self {
|
2023-02-01 20:35:52 +00:00
|
|
|
common: CommonSettings::default().await?,
|
2022-11-28 22:57:35 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn plan(&self) -> Result<Vec<StatefulAction<Box<dyn Action>>>, PlannerError> {
|
|
|
|
Ok(vec![
|
|
|
|
// ...
|
|
|
|
|
2023-02-01 20:35:52 +00:00
|
|
|
CreateFile::plan("/example", None, None, None, "Example".to_string(), false)
|
2022-11-28 22:57:35 +00:00
|
|
|
.await
|
|
|
|
.map_err(PlannerError::Action)?.boxed(),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError> {
|
|
|
|
let Self { common } = self;
|
|
|
|
let mut map = std::collections::HashMap::default();
|
|
|
|
|
|
|
|
map.extend(common.settings()?.into_iter());
|
|
|
|
|
|
|
|
Ok(map)
|
|
|
|
}
|
2023-02-24 18:11:12 +00:00
|
|
|
|
2023-03-13 20:30:04 +00:00
|
|
|
async fn configured_settings(
|
|
|
|
&self,
|
|
|
|
) -> Result<HashMap<String, serde_json::Value>, PlannerError> {
|
|
|
|
let default = Self::default().await?.settings()?;
|
|
|
|
let configured = self.settings()?;
|
|
|
|
|
|
|
|
let mut settings: HashMap<String, serde_json::Value> = HashMap::new();
|
|
|
|
for (key, value) in configured.iter() {
|
|
|
|
if default.get(key) != Some(value) {
|
|
|
|
settings.insert(key.clone(), value.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(settings)
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:11:12 +00:00
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
async fn diagnostic_data(&self) -> Result<nix_installer::diagnostics::DiagnosticData, PlannerError> {
|
|
|
|
Ok(nix_installer::diagnostics::DiagnosticData::new(
|
2023-09-20 18:23:23 +00:00
|
|
|
self.common.diagnostic_attribution.clone(),
|
2023-02-24 18:11:12 +00:00
|
|
|
self.common.diagnostic_endpoint.clone(),
|
|
|
|
self.typetag_name().into(),
|
2023-03-13 20:30:04 +00:00
|
|
|
self.configured_settings()
|
|
|
|
.await?
|
|
|
|
.into_keys()
|
|
|
|
.collect::<Vec<_>>(),
|
2023-03-20 16:38:15 +00:00
|
|
|
self.common.ssl_cert_file.clone(),
|
2023-03-27 18:56:44 +00:00
|
|
|
)?)
|
2023-02-24 18:11:12 +00:00
|
|
|
}
|
2022-11-28 22:57:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# async fn custom_planner_install() -> color_eyre::Result<()> {
|
|
|
|
let planner = MyPlanner::default().await?;
|
|
|
|
let mut plan = InstallPlan::plan(planner).await?;
|
|
|
|
match plan.install(None).await {
|
|
|
|
Ok(()) => tracing::info!("Done"),
|
|
|
|
Err(e) => {
|
|
|
|
match e.source() {
|
|
|
|
Some(source) => tracing::error!("{e}: {}", source),
|
|
|
|
None => tracing::error!("{e}"),
|
|
|
|
};
|
|
|
|
plan.uninstall(None).await?;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
# Ok(())
|
|
|
|
# }
|
|
|
|
```
|
|
|
|
|
|
|
|
*/
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2022-10-25 18:57:09 +00:00
|
|
|
pub mod linux;
|
2023-02-10 20:35:00 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
pub mod macos;
|
|
|
|
#[cfg(target_os = "linux")]
|
2023-07-24 18:10:20 +00:00
|
|
|
pub mod ostree;
|
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
pub mod steam_deck;
|
2022-10-14 22:14:03 +00:00
|
|
|
|
2023-03-27 21:36:54 +00:00
|
|
|
use std::{collections::HashMap, path::PathBuf, string::FromUtf8Error};
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
2022-10-28 19:44:07 +00:00
|
|
|
|
2022-11-28 22:57:35 +00:00
|
|
|
use crate::{
|
2022-12-05 16:55:30 +00:00
|
|
|
action::{ActionError, StatefulAction},
|
2022-12-12 20:20:50 +00:00
|
|
|
error::HasExpectedErrors,
|
2022-12-16 18:55:28 +00:00
|
|
|
settings::{CommonSettings, InstallSettingsError},
|
2022-12-19 18:26:58 +00:00
|
|
|
Action, InstallPlan, NixInstallerError,
|
2022-11-28 22:57:35 +00:00
|
|
|
};
|
2022-10-26 22:13:42 +00:00
|
|
|
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Something which can be used to plan out an [`InstallPlan`]
|
2022-10-26 22:13:42 +00:00
|
|
|
#[async_trait::async_trait]
|
|
|
|
#[typetag::serde(tag = "planner")]
|
|
|
|
pub trait Planner: std::fmt::Debug + Send + Sync + dyn_clone::DynClone {
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Instantiate the planner with default settings, if possible
|
|
|
|
async fn default() -> Result<Self, PlannerError>
|
2022-10-26 22:13:42 +00:00
|
|
|
where
|
|
|
|
Self: Sized;
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Plan out the [`Action`]s for an [`InstallPlan`]
|
|
|
|
async fn plan(&self) -> Result<Vec<StatefulAction<Box<dyn Action>>>, PlannerError>;
|
|
|
|
/// The settings being used by the planner
|
|
|
|
fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError>;
|
2023-02-24 18:11:12 +00:00
|
|
|
|
2023-03-13 20:30:04 +00:00
|
|
|
async fn configured_settings(&self)
|
|
|
|
-> Result<HashMap<String, serde_json::Value>, PlannerError>;
|
2023-02-24 18:11:12 +00:00
|
|
|
|
2022-11-28 22:57:35 +00:00
|
|
|
/// A boxed, type erased planner
|
2022-11-08 17:58:53 +00:00
|
|
|
fn boxed(self) -> Box<dyn Planner>
|
|
|
|
where
|
|
|
|
Self: Sized + 'static,
|
|
|
|
{
|
|
|
|
Box::new(self)
|
|
|
|
}
|
2023-02-24 18:11:12 +00:00
|
|
|
|
2023-07-12 16:08:42 +00:00
|
|
|
async fn pre_uninstall_check(&self) -> Result<(), PlannerError> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn pre_install_check(&self) -> Result<(), PlannerError> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-02-24 18:11:12 +00:00
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
async fn diagnostic_data(&self) -> Result<crate::diagnostics::DiagnosticData, PlannerError>;
|
2022-10-26 22:13:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dyn_clone::clone_trait_object!(Planner);
|
2022-10-14 22:14:03 +00:00
|
|
|
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Planners built into this crate
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
|
|
#[cfg_attr(feature = "cli", derive(clap::Subcommand))]
|
2022-10-25 18:57:09 +00:00
|
|
|
pub enum BuiltinPlanner {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-09-13 16:52:41 +00:00
|
|
|
/// A planner for traditional, mutable Linux systems like Debian, RHEL, or Arch
|
2023-02-10 20:35:00 +00:00
|
|
|
Linux(linux::Linux),
|
2023-09-13 16:52:41 +00:00
|
|
|
/// A planner for the Valve Steam Deck running SteamOS
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
SteamDeck(steam_deck::SteamDeck),
|
2023-09-13 16:52:41 +00:00
|
|
|
/// A planner suitable for immutable systems using ostree, such as Fedora Silverblue
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
Ostree(ostree::Ostree),
|
2023-09-13 16:52:41 +00:00
|
|
|
/// A planner for MacOS (Darwin) systems
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
Macos(macos::Macos),
|
2022-10-14 22:14:03 +00:00
|
|
|
}
|
|
|
|
|
2022-10-25 18:57:09 +00:00
|
|
|
impl BuiltinPlanner {
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Heuristically determine the default planner for the target system
|
|
|
|
pub async fn default() -> Result<Self, PlannerError> {
|
2022-10-14 22:14:03 +00:00
|
|
|
use target_lexicon::{Architecture, OperatingSystem};
|
|
|
|
match (Architecture::host(), OperatingSystem::host()) {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-07-24 18:10:20 +00:00
|
|
|
(Architecture::X86_64, OperatingSystem::Linux) => Self::detect_linux_distro().await,
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-06 15:50:23 +00:00
|
|
|
(Architecture::X86_32(_), OperatingSystem::Linux) => {
|
2023-02-10 20:35:00 +00:00
|
|
|
Ok(Self::Linux(linux::Linux::default().await?))
|
2023-02-06 15:50:23 +00:00
|
|
|
},
|
|
|
|
#[cfg(target_os = "linux")]
|
2022-10-25 18:57:09 +00:00
|
|
|
(Architecture::Aarch64(_), OperatingSystem::Linux) => {
|
2023-02-10 20:35:00 +00:00
|
|
|
Ok(Self::Linux(linux::Linux::default().await?))
|
2022-10-25 18:57:09 +00:00
|
|
|
},
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2022-10-24 23:16:18 +00:00
|
|
|
(Architecture::X86_64, OperatingSystem::MacOSX { .. })
|
2022-10-25 18:57:09 +00:00
|
|
|
| (Architecture::X86_64, OperatingSystem::Darwin) => {
|
2023-02-10 20:35:00 +00:00
|
|
|
Ok(Self::Macos(macos::Macos::default().await?))
|
2022-10-25 18:57:09 +00:00
|
|
|
},
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2022-10-24 23:16:18 +00:00
|
|
|
(Architecture::Aarch64(_), OperatingSystem::MacOSX { .. })
|
2022-10-25 18:57:09 +00:00
|
|
|
| (Architecture::Aarch64(_), OperatingSystem::Darwin) => {
|
2023-02-10 20:35:00 +00:00
|
|
|
Ok(Self::Macos(macos::Macos::default().await?))
|
2022-10-25 18:57:09 +00:00
|
|
|
},
|
2022-11-28 22:57:35 +00:00
|
|
|
_ => Err(PlannerError::UnsupportedArchitecture(target_lexicon::HOST)),
|
2022-10-14 22:14:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-24 18:44:28 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-07-24 18:10:20 +00:00
|
|
|
async fn detect_linux_distro() -> Result<Self, PlannerError> {
|
|
|
|
let is_steam_deck =
|
|
|
|
os_release::OsRelease::new().is_ok_and(|os_release| os_release.id == "steamos");
|
|
|
|
if is_steam_deck {
|
|
|
|
return Ok(Self::SteamDeck(steam_deck::SteamDeck::default().await?));
|
|
|
|
}
|
|
|
|
|
|
|
|
let is_ostree = std::process::Command::new("ostree")
|
|
|
|
.arg("remote")
|
|
|
|
.arg("list")
|
|
|
|
.output()
|
|
|
|
.is_ok_and(|output| output.status.success());
|
|
|
|
if is_ostree {
|
|
|
|
return Ok(Self::Ostree(ostree::Ostree::default().await?));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self::Linux(linux::Linux::default().await?))
|
|
|
|
}
|
|
|
|
|
2022-12-16 18:55:28 +00:00
|
|
|
pub async fn from_common_settings(settings: CommonSettings) -> Result<Self, PlannerError> {
|
|
|
|
let mut built = Self::default().await?;
|
|
|
|
match &mut built {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Linux(inner) => inner.settings = settings,
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2022-12-16 18:55:28 +00:00
|
|
|
BuiltinPlanner::SteamDeck(inner) => inner.settings = settings,
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(inner) => inner.settings = settings,
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Macos(inner) => inner.settings = settings,
|
2022-12-16 18:55:28 +00:00
|
|
|
}
|
|
|
|
Ok(built)
|
|
|
|
}
|
|
|
|
|
2023-03-13 20:30:04 +00:00
|
|
|
pub async fn configured_settings(
|
|
|
|
&self,
|
|
|
|
) -> Result<HashMap<String, serde_json::Value>, PlannerError> {
|
2023-02-24 18:11:12 +00:00
|
|
|
match self {
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Linux(inner) => inner.configured_settings().await,
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::SteamDeck(inner) => inner.configured_settings().await,
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(inner) => inner.configured_settings().await,
|
2023-02-24 18:11:12 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
BuiltinPlanner::Macos(inner) => inner.configured_settings().await,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-19 18:26:58 +00:00
|
|
|
pub async fn plan(self) -> Result<InstallPlan, NixInstallerError> {
|
2022-10-14 22:14:03 +00:00
|
|
|
match self {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Linux(planner) => InstallPlan::plan(planner).await,
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2022-11-28 22:57:35 +00:00
|
|
|
BuiltinPlanner::SteamDeck(planner) => InstallPlan::plan(planner).await,
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(planner) => InstallPlan::plan(planner).await,
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Macos(planner) => InstallPlan::plan(planner).await,
|
2022-10-14 22:14:03 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-08 17:58:53 +00:00
|
|
|
pub fn boxed(self) -> Box<dyn Planner> {
|
|
|
|
match self {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Linux(i) => i.boxed(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2022-11-08 17:58:53 +00:00
|
|
|
BuiltinPlanner::SteamDeck(i) => i.boxed(),
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(i) => i.boxed(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Macos(i) => i.boxed(),
|
2022-11-08 17:58:53 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-04 17:32:45 +00:00
|
|
|
|
|
|
|
pub fn typetag_name(&self) -> &'static str {
|
|
|
|
match self {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Linux(i) => i.typetag_name(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-01-04 17:32:45 +00:00
|
|
|
BuiltinPlanner::SteamDeck(i) => i.typetag_name(),
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(i) => i.typetag_name(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Macos(i) => i.typetag_name(),
|
2023-01-04 17:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn settings(&self) -> Result<HashMap<String, serde_json::Value>, InstallSettingsError> {
|
|
|
|
match self {
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Linux(i) => i.settings(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-01-04 17:32:45 +00:00
|
|
|
BuiltinPlanner::SteamDeck(i) => i.settings(),
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(i) => i.settings(),
|
2023-02-01 20:35:52 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
2023-02-10 20:35:00 +00:00
|
|
|
BuiltinPlanner::Macos(i) => i.settings(),
|
2023-01-04 17:32:45 +00:00
|
|
|
}
|
|
|
|
}
|
2023-02-24 18:11:12 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
pub async fn diagnostic_data(
|
|
|
|
&self,
|
|
|
|
) -> Result<crate::diagnostics::DiagnosticData, PlannerError> {
|
|
|
|
match self {
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Linux(i) => i.diagnostic_data().await,
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::SteamDeck(i) => i.diagnostic_data().await,
|
2023-07-24 18:10:20 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
BuiltinPlanner::Ostree(i) => i.diagnostic_data().await,
|
2023-02-24 18:11:12 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
BuiltinPlanner::Macos(i) => i.diagnostic_data().await,
|
|
|
|
}
|
|
|
|
}
|
2022-10-14 22:14:03 +00:00
|
|
|
}
|
|
|
|
|
2023-03-27 21:36:54 +00:00
|
|
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
|
|
|
pub struct ShellProfileLocations {
|
|
|
|
pub fish: FishShellProfileLocations,
|
|
|
|
pub bash: Vec<PathBuf>,
|
|
|
|
pub zsh: Vec<PathBuf>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ShellProfileLocations {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
fish: FishShellProfileLocations::default(),
|
|
|
|
bash: vec![
|
|
|
|
"/etc/bashrc".into(),
|
|
|
|
"/etc/profile.d/nix.sh".into(),
|
|
|
|
"/etc/bash.bashrc".into(),
|
|
|
|
],
|
|
|
|
zsh: vec![
|
|
|
|
// https://zsh.sourceforge.io/Intro/intro_3.html
|
|
|
|
"/etc/zshrc".into(),
|
|
|
|
"/etc/zsh/zshrc".into(),
|
|
|
|
],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)]
|
|
|
|
pub struct FishShellProfileLocations {
|
|
|
|
pub confd_suffix: PathBuf,
|
|
|
|
/**
|
|
|
|
Each of these are common values of $__fish_sysconf_dir,
|
|
|
|
under which Fish will look for the file named by
|
|
|
|
`confd_suffix`.
|
|
|
|
*/
|
|
|
|
pub confd_prefixes: Vec<PathBuf>,
|
|
|
|
/// Fish has different syntax than zsh/bash, treat it separate
|
|
|
|
pub vendor_confd_suffix: PathBuf,
|
|
|
|
/**
|
|
|
|
Each of these are common values of $__fish_vendor_confdir,
|
|
|
|
under which Fish will look for the file named by
|
|
|
|
`confd_suffix`.
|
|
|
|
|
|
|
|
More info: <https://fishshell.com/docs/3.3/index.html#configuration-files>
|
|
|
|
*/
|
|
|
|
pub vendor_confd_prefixes: Vec<PathBuf>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for FishShellProfileLocations {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
confd_prefixes: vec![
|
|
|
|
"/etc/fish".into(), // standard
|
|
|
|
"/usr/local/etc/fish".into(), // their installer .pkg for macOS
|
|
|
|
"/opt/homebrew/etc/fish".into(), // homebrew
|
|
|
|
"/opt/local/etc/fish".into(), // macports
|
|
|
|
],
|
|
|
|
confd_suffix: "conf.d/nix.fish".into(),
|
|
|
|
vendor_confd_prefixes: vec!["/usr/share/fish/".into(), "/usr/local/share/fish/".into()],
|
|
|
|
vendor_confd_suffix: "vendor_conf.d/nix.fish".into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 22:57:35 +00:00
|
|
|
/// An error originating from a [`Planner`]
|
2023-03-03 20:03:51 +00:00
|
|
|
#[non_exhaustive]
|
2023-02-24 18:11:12 +00:00
|
|
|
#[derive(thiserror::Error, Debug, strum::IntoStaticStr)]
|
2022-11-28 22:57:35 +00:00
|
|
|
pub enum PlannerError {
|
2022-12-19 18:26:58 +00:00
|
|
|
/// `nix-installer` does not have a default planner for the target architecture right now
|
|
|
|
#[error("`nix-installer` does not have a default planner for the `{0}` architecture right now, pass a specific archetype")]
|
2022-10-14 22:14:03 +00:00
|
|
|
UnsupportedArchitecture(target_lexicon::Triple),
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Error executing action
|
2022-10-14 22:14:03 +00:00
|
|
|
#[error("Error executing action")]
|
2022-12-05 16:55:30 +00:00
|
|
|
Action(
|
|
|
|
#[source]
|
|
|
|
#[from]
|
|
|
|
ActionError,
|
|
|
|
),
|
2022-11-28 22:57:35 +00:00
|
|
|
/// An [`InstallSettingsError`]
|
2022-10-25 18:57:09 +00:00
|
|
|
#[error(transparent)]
|
|
|
|
InstallSettings(#[from] InstallSettingsError),
|
2023-06-01 20:00:39 +00:00
|
|
|
/// An OS Release error
|
|
|
|
#[error("Fetching `/etc/os-release`")]
|
|
|
|
OsRelease(#[source] std::io::Error),
|
2022-11-28 22:57:35 +00:00
|
|
|
/// A MacOS (Darwin) plist related error
|
2022-10-26 16:27:50 +00:00
|
|
|
#[error(transparent)]
|
|
|
|
Plist(#[from] plist::Error),
|
2023-03-22 17:58:46 +00:00
|
|
|
#[error(transparent)]
|
|
|
|
Sysctl(#[from] sysctl::SysctlError),
|
|
|
|
#[error("Detected that this process is running under Rosetta, using Nix in Rosetta is not supported (Please open an issue with your use case)")]
|
|
|
|
RosettaDetected,
|
2022-12-19 15:30:45 +00:00
|
|
|
/// A Linux SELinux related error
|
2023-05-17 14:27:14 +00:00
|
|
|
#[error("Unable to install on an SELinux system without common SELinux tooling, the binaries `restorecon`, and `semodule` are required")]
|
|
|
|
SelinuxRequirements,
|
2022-12-19 15:30:45 +00:00
|
|
|
/// A UTF-8 related error
|
|
|
|
#[error("UTF-8 error")]
|
|
|
|
Utf8(#[from] FromUtf8Error),
|
2022-11-28 22:57:35 +00:00
|
|
|
/// Custom planner error
|
|
|
|
#[error("Custom planner error")]
|
|
|
|
Custom(#[source] Box<dyn std::error::Error + Send + Sync>),
|
2022-12-12 20:20:50 +00:00
|
|
|
#[error("NixOS already has Nix installed")]
|
|
|
|
NixOs,
|
|
|
|
#[error("`nix` is already a valid command, so it is installed")]
|
|
|
|
NixExists,
|
2023-03-03 17:49:46 +00:00
|
|
|
#[error("WSL1 is not supported, please upgrade to WSL2: https://learn.microsoft.com/en-us/windows/wsl/install#upgrade-version-from-wsl-1-to-wsl-2")]
|
|
|
|
Wsl1,
|
2023-06-01 16:48:50 +00:00
|
|
|
/// Failed to execute command
|
|
|
|
#[error("Failed to execute command `{0}`")]
|
|
|
|
Command(String, #[source] std::io::Error),
|
2023-03-27 18:56:44 +00:00
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
#[error(transparent)]
|
|
|
|
Diagnostic(#[from] crate::diagnostics::DiagnosticError),
|
2022-12-12 20:20:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl HasExpectedErrors for PlannerError {
|
|
|
|
fn expected<'a>(&'a self) -> Option<Box<dyn std::error::Error + 'a>> {
|
|
|
|
match self {
|
|
|
|
this @ PlannerError::UnsupportedArchitecture(_) => Some(Box::new(this)),
|
2023-09-13 17:02:05 +00:00
|
|
|
PlannerError::Action(action_error) => action_error.kind().expected(),
|
2022-12-12 20:20:50 +00:00
|
|
|
PlannerError::InstallSettings(_) => None,
|
|
|
|
PlannerError::Plist(_) => None,
|
2023-03-22 17:58:46 +00:00
|
|
|
PlannerError::Sysctl(_) => None,
|
|
|
|
this @ PlannerError::RosettaDetected => Some(Box::new(this)),
|
2023-06-01 20:00:39 +00:00
|
|
|
PlannerError::OsRelease(_) => None,
|
2022-12-19 15:30:45 +00:00
|
|
|
PlannerError::Utf8(_) => None,
|
2023-05-17 14:27:14 +00:00
|
|
|
PlannerError::SelinuxRequirements => Some(Box::new(self)),
|
2023-05-31 20:36:44 +00:00
|
|
|
PlannerError::Custom(_e) => {
|
2023-04-10 23:16:46 +00:00
|
|
|
#[cfg(target_os = "linux")]
|
2023-05-31 20:36:44 +00:00
|
|
|
if let Some(err) = _e.downcast_ref::<linux::LinuxErrorKind>() {
|
2023-04-10 23:16:46 +00:00
|
|
|
return err.expected();
|
|
|
|
}
|
2023-07-12 16:08:42 +00:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
if let Some(err) = _e.downcast_ref::<macos::MacosError>() {
|
|
|
|
return err.expected();
|
|
|
|
}
|
2023-04-10 23:16:46 +00:00
|
|
|
None
|
|
|
|
},
|
2022-12-12 20:20:50 +00:00
|
|
|
this @ PlannerError::NixOs => Some(Box::new(this)),
|
|
|
|
this @ PlannerError::NixExists => Some(Box::new(this)),
|
2023-03-03 17:49:46 +00:00
|
|
|
this @ PlannerError::Wsl1 => Some(Box::new(this)),
|
2023-06-01 16:48:50 +00:00
|
|
|
PlannerError::Command(_, _) => None,
|
2023-03-27 18:56:44 +00:00
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
PlannerError::Diagnostic(diagnostic_error) => Some(Box::new(diagnostic_error)),
|
2022-12-12 20:20:50 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-14 22:14:03 +00:00
|
|
|
}
|
2023-03-03 22:20:17 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "diagnostics")]
|
|
|
|
impl crate::diagnostics::ErrorDiagnostic for PlannerError {
|
|
|
|
fn diagnostic(&self) -> String {
|
|
|
|
let static_str: &'static str = (self).into();
|
2023-07-17 15:34:46 +00:00
|
|
|
static_str.to_string()
|
2023-03-03 22:20:17 +00:00
|
|
|
}
|
|
|
|
}
|