forked from lix-project/lix-installer
Set NIX_SSL_CERT_FILE in the daemon (#347)
* Set NIX_SSL_CERT_FILE in the daemon * Fixups
This commit is contained in:
parent
ee06c3c750
commit
371f94ba51
|
@ -1,10 +1,13 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use bytes::{Buf, Bytes};
|
||||
use reqwest::{Certificate, Url};
|
||||
use reqwest::Url;
|
||||
use tracing::{span, Span};
|
||||
|
||||
use crate::action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction};
|
||||
use crate::{
|
||||
action::{Action, ActionDescription, ActionError, ActionTag, StatefulAction},
|
||||
parse_ssl_cert,
|
||||
};
|
||||
|
||||
/**
|
||||
Fetch a URL to the given path
|
||||
|
@ -163,23 +166,6 @@ impl Action for FetchAndUnpackNix {
|
|||
}
|
||||
}
|
||||
|
||||
async fn parse_ssl_cert(ssl_cert_file: &Path) -> Result<Certificate, ActionError> {
|
||||
let cert_buf = tokio::fs::read(ssl_cert_file)
|
||||
.await
|
||||
.map_err(|e| ActionError::Read(ssl_cert_file.to_path_buf(), e))?;
|
||||
// We actually try them since things could be `.crt` and `pem` format or `der` format
|
||||
let cert = if let Ok(cert) = Certificate::from_pem(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else if let Ok(cert) = Certificate::from_der(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else {
|
||||
return Err(ActionError::Custom(Box::new(
|
||||
FetchUrlError::UnknownCertFormat,
|
||||
)));
|
||||
};
|
||||
Ok(cert)
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum FetchUrlError {
|
||||
|
@ -195,6 +181,4 @@ pub enum FetchUrlError {
|
|||
UnknownUrlScheme,
|
||||
#[error("Unknown proxy scheme, `https://`, `socks5://`, and `http://` supported")]
|
||||
UnknownProxyScheme,
|
||||
#[error("Unknown certificate format, `der` and `pem` supported")]
|
||||
UnknownCertFormat,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use tokio::process::Command;
|
||||
use tracing::{span, Span};
|
||||
|
||||
|
@ -33,6 +34,7 @@ Configure the init to run the Nix daemon
|
|||
pub struct ConfigureInitService {
|
||||
init: InitSystem,
|
||||
start_daemon: bool,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl ConfigureInitService {
|
||||
|
@ -67,7 +69,18 @@ impl ConfigureInitService {
|
|||
pub async fn plan(
|
||||
init: InitSystem,
|
||||
start_daemon: bool,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
) -> Result<StatefulAction<Self>, ActionError> {
|
||||
let ssl_cert_file_path = if let Some(ssl_cert_file) = ssl_cert_file {
|
||||
Some(
|
||||
ssl_cert_file
|
||||
.canonicalize()
|
||||
.map_err(|e| ActionError::Canonicalize(ssl_cert_file, e))?,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match init {
|
||||
#[cfg(target_os = "macos")]
|
||||
InitSystem::Launchd => {
|
||||
|
@ -91,7 +104,12 @@ impl ConfigureInitService {
|
|||
},
|
||||
};
|
||||
|
||||
Ok(Self { init, start_daemon }.into())
|
||||
Ok(Self {
|
||||
init,
|
||||
start_daemon,
|
||||
ssl_cert_file: ssl_cert_file_path,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +170,11 @@ impl Action for ConfigureInitService {
|
|||
|
||||
#[tracing::instrument(level = "debug", skip_all)]
|
||||
async fn execute(&mut self) -> Result<(), ActionError> {
|
||||
let Self { init, start_daemon } = self;
|
||||
let Self {
|
||||
init,
|
||||
start_daemon,
|
||||
ssl_cert_file,
|
||||
} = self;
|
||||
|
||||
match init {
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@ -177,6 +199,18 @@ impl Action for ConfigureInitService {
|
|||
)
|
||||
.await?;
|
||||
|
||||
if let Some(ssl_cert_file) = ssl_cert_file {
|
||||
execute_command(
|
||||
Command::new("launchctl")
|
||||
.process_group(0)
|
||||
.arg("setenv")
|
||||
.arg("NIX_SSL_CERT_FILE")
|
||||
.arg(format!("{ssl_cert_file:?}"))
|
||||
.stdin(std::process::Stdio::null()),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if *start_daemon {
|
||||
execute_command(
|
||||
Command::new("launchctl")
|
||||
|
@ -270,6 +304,28 @@ impl Action for ConfigureInitService {
|
|||
)
|
||||
.await?;
|
||||
|
||||
if let Some(ssl_cert_file) = ssl_cert_file {
|
||||
let service_conf_dir_path = PathBuf::from(format!("{SERVICE_DEST}.d"));
|
||||
tokio::fs::create_dir(&service_conf_dir_path)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
ActionError::CreateDirectory(service_conf_dir_path.clone(), e)
|
||||
})?;
|
||||
let service_conf_file_path =
|
||||
service_conf_dir_path.join("nix-ssl-cert-file.conf");
|
||||
tokio::fs::write(
|
||||
service_conf_file_path,
|
||||
format!(
|
||||
"\
|
||||
[Service]\n\
|
||||
Environment=\"NIX_SSL_CERT_FILE={ssl_cert_file:?}\"\n\
|
||||
"
|
||||
),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ActionError::Write(ssl_cert_file.clone(), e))?;
|
||||
}
|
||||
|
||||
if *start_daemon || socket_was_active {
|
||||
enable(SOCKET_SRC, true).await?;
|
||||
} else {
|
||||
|
@ -382,6 +438,13 @@ impl Action for ConfigureInitService {
|
|||
)
|
||||
.await?;
|
||||
|
||||
if self.ssl_cert_file.is_some() {
|
||||
let service_conf_dir_path = PathBuf::from(format!("{SERVICE_DEST}.d"));
|
||||
tokio::fs::remove_dir_all(&service_conf_dir_path)
|
||||
.await
|
||||
.map_err(|e| ActionError::Remove(service_conf_dir_path.clone(), e))?;
|
||||
}
|
||||
|
||||
tokio::fs::remove_file(TMPFILES_DEST)
|
||||
.await
|
||||
.map_err(|e| ActionError::Remove(PathBuf::from(TMPFILES_DEST), e))?;
|
||||
|
|
|
@ -162,6 +162,7 @@ impl Planner for MyPlanner {
|
|||
.await?
|
||||
.into_keys()
|
||||
.collect::<Vec<_>>(),
|
||||
self.common.ssl_cert_file.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +198,7 @@ use std::{error::Error, process::Output};
|
|||
use tokio::task::JoinError;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::error::HasExpectedErrors;
|
||||
use crate::{error::HasExpectedErrors, CertificateError};
|
||||
|
||||
/// An action which can be reverted or completed, with an action state
|
||||
///
|
||||
|
@ -305,6 +306,9 @@ pub enum ActionError {
|
|||
/// A custom error
|
||||
#[error(transparent)]
|
||||
Custom(Box<dyn std::error::Error + Send + Sync>),
|
||||
/// An error to do with certificates
|
||||
#[error(transparent)]
|
||||
Certificate(#[from] CertificateError),
|
||||
/// A child error
|
||||
#[error("Child action `{0}`")]
|
||||
Child(ActionTag, #[source] Box<ActionError>),
|
||||
|
|
|
@ -5,13 +5,14 @@ When enabled with the `diagnostics` feature (default) this module provides autom
|
|||
That endpoint can be a URL such as `https://our.project.org/nix-installer/diagnostics` or `file:///home/$USER/diagnostic.json` which receives a [`DiagnosticReport`] in JSON format.
|
||||
*/
|
||||
|
||||
use std::time::Duration;
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
|
||||
use os_release::OsRelease;
|
||||
use reqwest::Url;
|
||||
|
||||
use crate::{
|
||||
action::ActionError, planner::PlannerError, settings::InstallSettingsError, NixInstallerError,
|
||||
action::ActionError, parse_ssl_cert, planner::PlannerError, settings::InstallSettingsError,
|
||||
CertificateError, NixInstallerError,
|
||||
};
|
||||
|
||||
/// The static of an action attempt
|
||||
|
@ -57,12 +58,18 @@ pub struct DiagnosticData {
|
|||
triple: String,
|
||||
is_ci: bool,
|
||||
endpoint: Option<Url>,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
/// Generally this includes the [`strum::IntoStaticStr`] representation of the error, we take special care not to include parameters of the error (which may include secrets)
|
||||
failure_chain: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl DiagnosticData {
|
||||
pub fn new(endpoint: Option<Url>, planner: String, configured_settings: Vec<String>) -> Self {
|
||||
pub fn new(
|
||||
endpoint: Option<Url>,
|
||||
planner: String,
|
||||
configured_settings: Vec<String>,
|
||||
ssl_cert_file: Option<PathBuf>,
|
||||
) -> Self {
|
||||
let (os_name, os_version) = match OsRelease::new() {
|
||||
Ok(os_release) => (os_release.name, os_release.version),
|
||||
Err(_) => ("unknown".into(), "unknown".into()),
|
||||
|
@ -78,6 +85,7 @@ impl DiagnosticData {
|
|||
os_version,
|
||||
triple: target_lexicon::HOST.to_string(),
|
||||
is_ci,
|
||||
ssl_cert_file,
|
||||
failure_chain: None,
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +135,7 @@ impl DiagnosticData {
|
|||
triple,
|
||||
is_ci,
|
||||
endpoint: _,
|
||||
ssl_cert_file: _,
|
||||
failure_chain,
|
||||
} = self;
|
||||
DiagnosticReport {
|
||||
|
@ -159,7 +168,15 @@ impl DiagnosticData {
|
|||
match endpoint.scheme() {
|
||||
"https" | "http" => {
|
||||
tracing::debug!("Sending diagnostic to `{endpoint}`");
|
||||
let client = reqwest::Client::new();
|
||||
let mut buildable_client = reqwest::Client::builder();
|
||||
if let Some(ssl_cert_file) = &self.ssl_cert_file {
|
||||
let ssl_cert = parse_ssl_cert(&ssl_cert_file).await?;
|
||||
buildable_client = buildable_client.add_root_certificate(ssl_cert);
|
||||
}
|
||||
let client = buildable_client
|
||||
.build()
|
||||
.map_err(|e| DiagnosticError::Reqwest(e))?;
|
||||
|
||||
let res = client
|
||||
.post(endpoint.clone())
|
||||
.body(serialized)
|
||||
|
@ -206,6 +223,8 @@ pub enum DiagnosticError {
|
|||
#[source]
|
||||
serde_json::Error,
|
||||
),
|
||||
#[error(transparent)]
|
||||
Certificate(#[from] CertificateError),
|
||||
}
|
||||
|
||||
pub trait ErrorDiagnostic {
|
||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -80,7 +80,7 @@ mod plan;
|
|||
pub mod planner;
|
||||
pub mod settings;
|
||||
|
||||
use std::{ffi::OsStr, process::Output};
|
||||
use std::{ffi::OsStr, path::Path, process::Output};
|
||||
|
||||
use action::{Action, ActionError};
|
||||
|
||||
|
@ -88,6 +88,7 @@ pub use error::NixInstallerError;
|
|||
pub use plan::InstallPlan;
|
||||
use planner::BuiltinPlanner;
|
||||
|
||||
use reqwest::Certificate;
|
||||
use tokio::process::Command;
|
||||
|
||||
#[tracing::instrument(level = "debug", skip_all, fields(command = %format!("{:?}", command.as_std())))]
|
||||
|
@ -111,3 +112,28 @@ fn set_env(k: impl AsRef<OsStr>, v: impl AsRef<OsStr>) {
|
|||
tracing::trace!("Setting env");
|
||||
std::env::set_var(k.as_ref(), v.as_ref());
|
||||
}
|
||||
|
||||
async fn parse_ssl_cert(ssl_cert_file: &Path) -> Result<Certificate, CertificateError> {
|
||||
let cert_buf = tokio::fs::read(ssl_cert_file)
|
||||
.await
|
||||
.map_err(|e| CertificateError::Read(ssl_cert_file.to_path_buf(), e))?;
|
||||
// We actually try them since things could be `.crt` and `pem` format or `der` format
|
||||
let cert = if let Ok(cert) = Certificate::from_pem(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else if let Ok(cert) = Certificate::from_der(cert_buf.as_slice()) {
|
||||
cert
|
||||
} else {
|
||||
return Err(CertificateError::UnknownCertFormat);
|
||||
};
|
||||
Ok(cert)
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CertificateError {
|
||||
#[error(transparent)]
|
||||
Reqwest(reqwest::Error),
|
||||
#[error("Read path `{0}`")]
|
||||
Read(std::path::PathBuf, #[source] std::io::Error),
|
||||
#[error("Unknown certificate format, `der` and `pem` supported")]
|
||||
UnknownCertFormat,
|
||||
}
|
||||
|
|
|
@ -84,10 +84,14 @@ impl Planner for Linux {
|
|||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
ConfigureInitService::plan(self.init.init, self.init.start_daemon)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
ConfigureInitService::plan(
|
||||
self.init.init,
|
||||
self.init.start_daemon,
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
|
@ -130,6 +134,7 @@ impl Planner for Linux {
|
|||
.await?
|
||||
.into_keys()
|
||||
.collect::<Vec<_>>(),
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,10 +142,14 @@ impl Planner for Macos {
|
|||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
ConfigureInitService::plan(InitSystem::Launchd, true)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
ConfigureInitService::plan(
|
||||
InitSystem::Launchd,
|
||||
true,
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
RemoveDirectory::plan(crate::settings::SCRATCH_DIR)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
|
@ -200,6 +204,7 @@ impl Planner for Macos {
|
|||
.await?
|
||||
.into_keys()
|
||||
.collect::<Vec<_>>(),
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ impl Planner for MyPlanner {
|
|||
.await?
|
||||
.into_keys()
|
||||
.collect::<Vec<_>>(),
|
||||
self.common.ssl_cert_file.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,10 +226,14 @@ impl Planner for SteamDeck {
|
|||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
// Init is required for the steam-deck archetype to make the `/nix` mount
|
||||
ConfigureInitService::plan(InitSystem::Systemd, true)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
ConfigureInitService::plan(
|
||||
InitSystem::Systemd,
|
||||
true,
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
.boxed(),
|
||||
StartSystemdUnit::plan("ensure-symlinked-units-resolve.service".to_string(), true)
|
||||
.await
|
||||
.map_err(PlannerError::Action)?
|
||||
|
@ -282,6 +286,7 @@ impl Planner for SteamDeck {
|
|||
.await?
|
||||
.into_keys()
|
||||
.collect::<Vec<_>>(),
|
||||
self.settings.ssl_cert_file.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ pub struct CommonSettings {
|
|||
long = "no-modify-profile"
|
||||
)
|
||||
)]
|
||||
pub(crate) modify_profile: bool,
|
||||
pub modify_profile: bool,
|
||||
|
||||
/// Number of build users to create
|
||||
#[cfg_attr(
|
||||
|
@ -81,7 +81,7 @@ pub struct CommonSettings {
|
|||
global = true
|
||||
)
|
||||
)]
|
||||
pub(crate) nix_build_user_count: u32,
|
||||
pub nix_build_user_count: u32,
|
||||
|
||||
/// The Nix build group name
|
||||
#[cfg_attr(
|
||||
|
@ -93,7 +93,7 @@ pub struct CommonSettings {
|
|||
global = true
|
||||
)
|
||||
)]
|
||||
pub(crate) nix_build_group_name: String,
|
||||
pub nix_build_group_name: String,
|
||||
|
||||
/// The Nix build group GID
|
||||
#[cfg_attr(
|
||||
|
@ -105,7 +105,7 @@ pub struct CommonSettings {
|
|||
global = true
|
||||
)
|
||||
)]
|
||||
pub(crate) nix_build_group_id: u32,
|
||||
pub nix_build_group_id: u32,
|
||||
|
||||
/// The Nix build user prefix (user numbers will be postfixed)
|
||||
#[cfg_attr(
|
||||
|
@ -120,7 +120,7 @@ pub struct CommonSettings {
|
|||
all(target_os = "linux", feature = "cli"),
|
||||
clap(default_value = "nixbld")
|
||||
)]
|
||||
pub(crate) nix_build_user_prefix: String,
|
||||
pub nix_build_user_prefix: String,
|
||||
|
||||
/// The Nix build user base UID (ascending)
|
||||
#[cfg_attr(
|
||||
|
@ -133,7 +133,7 @@ pub struct CommonSettings {
|
|||
all(target_os = "linux", feature = "cli"),
|
||||
clap(default_value_t = 30_000)
|
||||
)]
|
||||
pub(crate) nix_build_user_id_base: u32,
|
||||
pub nix_build_user_id_base: u32,
|
||||
|
||||
/// The Nix package URL
|
||||
#[cfg_attr(
|
||||
|
@ -170,15 +170,15 @@ pub struct CommonSettings {
|
|||
default_value = NIX_AARCH64_LINUX_URL,
|
||||
)
|
||||
)]
|
||||
pub(crate) nix_package_url: Url,
|
||||
pub nix_package_url: Url,
|
||||
|
||||
/// The proxy to use (if any), valid proxy bases are `https://$URL`, `http://$URL` and `socks5://$URL`
|
||||
#[cfg_attr(feature = "cli", clap(long, env = "NIX_INSTALLER_PROXY"))]
|
||||
pub(crate) proxy: Option<Url>,
|
||||
pub proxy: Option<Url>,
|
||||
|
||||
/// An SSL cert to use (if any), used for fetching Nix and sets `NIX_SSL_CERT_FILE` for Nix
|
||||
#[cfg_attr(feature = "cli", clap(long, env = "NIX_INSTALLER_SSL_CERT_FILE"))]
|
||||
pub(crate) ssl_cert_file: Option<PathBuf>,
|
||||
pub ssl_cert_file: Option<PathBuf>,
|
||||
|
||||
/// Extra configuration lines for `/etc/nix.conf`
|
||||
#[cfg_attr(feature = "cli", clap(long, action = ArgAction::Set, num_args = 0.., value_delimiter = ',', env = "NIX_INSTALLER_EXTRA_CONF", global = true))]
|
||||
|
@ -195,7 +195,7 @@ pub struct CommonSettings {
|
|||
env = "NIX_INSTALLER_FORCE"
|
||||
)
|
||||
)]
|
||||
pub(crate) force: bool,
|
||||
pub force: bool,
|
||||
|
||||
#[cfg(feature = "diagnostics")]
|
||||
/// The URL or file path for an installation diagnostic to be sent
|
||||
|
@ -379,69 +379,6 @@ async fn linux_detect_systemd_started() -> bool {
|
|||
started
|
||||
}
|
||||
|
||||
// Builder Pattern
|
||||
impl CommonSettings {
|
||||
/// Number of build users to create
|
||||
pub fn nix_build_user_count(&mut self, count: u32) -> &mut Self {
|
||||
self.nix_build_user_count = count;
|
||||
self
|
||||
}
|
||||
|
||||
/// Modify the user profile to automatically load nix
|
||||
pub fn modify_profile(&mut self, toggle: bool) -> &mut Self {
|
||||
self.modify_profile = toggle;
|
||||
self
|
||||
}
|
||||
|
||||
/// The Nix build group name
|
||||
pub fn nix_build_group_name(&mut self, val: String) -> &mut Self {
|
||||
self.nix_build_group_name = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// The Nix build group GID
|
||||
pub fn nix_build_group_id(&mut self, count: u32) -> &mut Self {
|
||||
self.nix_build_group_id = count;
|
||||
self
|
||||
}
|
||||
|
||||
/// The Nix build user prefix (user numbers will be postfixed)
|
||||
pub fn nix_build_user_prefix(&mut self, val: String) -> &mut Self {
|
||||
self.nix_build_user_prefix = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// The Nix build user base UID (ascending)
|
||||
pub fn nix_build_user_id_base(&mut self, count: u32) -> &mut Self {
|
||||
self.nix_build_user_id_base = count;
|
||||
self
|
||||
}
|
||||
|
||||
/// The Nix package URL
|
||||
pub fn nix_package_url(&mut self, url: Url) -> &mut Self {
|
||||
self.nix_package_url = url;
|
||||
self
|
||||
}
|
||||
/// Extra configuration lines for `/etc/nix.conf`
|
||||
pub fn extra_conf(&mut self, extra_conf: Vec<String>) -> &mut Self {
|
||||
self.extra_conf = extra_conf;
|
||||
self
|
||||
}
|
||||
|
||||
/// If `nix-installer` should forcibly recreate files it finds existing
|
||||
pub fn force(&mut self, force: bool) -> &mut Self {
|
||||
self.force = force;
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "diagnostics")]
|
||||
/// The URL or file path for an [`DiagnosticReport`][crate::diagnostics::DiagnosticReport] to be sent
|
||||
pub fn diagnostic_endpoint(&mut self, diagnostic_endpoint: Option<Url>) -> &mut Self {
|
||||
self.diagnostic_endpoint = diagnostic_endpoint;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
|
||||
#[cfg_attr(feature = "cli", derive(clap::Parser))]
|
||||
|
@ -456,7 +393,7 @@ pub struct InitSettings {
|
|||
all(target_os = "linux", feature = "cli"),
|
||||
clap(default_value_t = InitSystem::Systemd)
|
||||
)]
|
||||
pub(crate) init: InitSystem,
|
||||
pub init: InitSystem,
|
||||
|
||||
/// Start the daemon (if not `--init none`)
|
||||
#[cfg_attr(
|
||||
|
@ -470,7 +407,7 @@ pub struct InitSettings {
|
|||
long = "no-start-daemon"
|
||||
)
|
||||
)]
|
||||
pub(crate) start_daemon: bool,
|
||||
pub start_daemon: bool,
|
||||
}
|
||||
|
||||
impl InitSettings {
|
||||
|
|
Loading…
Reference in a new issue