Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

103 changes: 102 additions & 1 deletion Cargo.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git",
tera = "1.20"
termion = "4.0"
tokio = { version = "1.38", features = ["rt-multi-thread", "macros", "fs", "process", "io-std"] }
toml = { version = "0.9.8", features = ["serde"] }
tower-http = { version = "0.5", features = ["validate-request"] }
tracing = "0.1"
tracing-indicatif = "0.3.9"
Expand Down
1 change: 1 addition & 0 deletions rust/stackablectl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ serde.workspace = true
snafu.workspace = true
tera.workspace = true
tokio.workspace = true
toml.workspace = true
tracing-subscriber.workspace = true
tracing.workspace = true
tracing-indicatif.workspace = true
Expand Down
55 changes: 34 additions & 21 deletions rust/stackablectl/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::{env, sync::Arc};
use std::{env, path::Path, sync::Arc};

use clap::{Parser, Subcommand, ValueEnum};
use directories::ProjectDirs;
use snafu::{ResultExt, Snafu};
use snafu::{OptionExt, ResultExt, Snafu};
use stackable_cockpit::{
constants::{HELM_REPO_NAME_DEV, HELM_REPO_NAME_STABLE, HELM_REPO_NAME_TEST},
helm,
Expand All @@ -20,6 +20,7 @@ use tracing_indicatif::indicatif_eprintln;
use crate::{
args::{CommonFileArgs, CommonOperatorConfigsArgs, CommonRepoArgs},
cmds::{cache, completions, debug, demo, operator, release, stack, stacklet, version},
config::UserConfig,
constants::{
DEMOS_REPOSITORY_DEMOS_SUBPATH, DEMOS_REPOSITORY_STACKS_SUBPATH, DEMOS_REPOSITORY_URL_BASE,
ENV_KEY_DEMO_FILES, ENV_KEY_RELEASE_FILES, ENV_KEY_STACK_FILES, REMOTE_RELEASE_FILE,
Expand Down Expand Up @@ -69,6 +70,9 @@ pub enum Error {

#[snafu(display("failed to initialize transfer client"))]
InitializeTransferClient { source: xfer::Error },

#[snafu(display("failed to retrieve XDG directories"))]
RetrieveXdgDirectories,
}

#[derive(Debug, Snafu)]
Expand Down Expand Up @@ -169,27 +173,29 @@ impl Cli {
Ok(())
}

pub fn cache_settings(&self) -> Result<Settings, CacheSettingsError> {
fn cache_settings(&self, cache_directory: &Path) -> Result<Settings, CacheSettingsError> {
if self.no_cache {
tracing::debug!("Cache disabled");
Ok(Settings::disabled())
} else {
let project_dir = ProjectDirs::from(
USER_DIR_QUALIFIER,
USER_DIR_ORGANIZATION_NAME,
USER_DIR_APPLICATION_NAME,
)
.ok_or(CacheSettingsError::UserDir)?;

let cache_dir = project_dir.cache_dir();
tracing::debug!(
cache_dir = %cache_dir.to_string_lossy(),
cache_directory = %cache_directory.to_string_lossy(),
"Setting cache directory"
);
Ok(Settings::disk(cache_dir))
Ok(Settings::disk(cache_directory))
}
}

#[allow(clippy::result_large_err)]
fn xdg_directories() -> Result<ProjectDirs, Error> {
ProjectDirs::from(
USER_DIR_QUALIFIER,
USER_DIR_ORGANIZATION_NAME,
USER_DIR_APPLICATION_NAME,
)
.context(RetrieveXdgDirectoriesSnafu)
}

#[instrument(skip_all)]
pub async fn run(self) -> Result<String, Error> {
// FIXME (Techassi): There might be a better way to handle this with
Expand All @@ -202,7 +208,15 @@ impl Cli {
_ => self.add_helm_repos().context(AddHelmReposSnafu)?,
}

let cache_settings = self.cache_settings().context(RetrieveCacheSettingsSnafu)?;
let xdg_directories = Cli::xdg_directories()?;
// TODO (@Techassi): Move this file name to a constant
let user_config_path = xdg_directories.config_dir().join("config.toml");

let user_config = UserConfig::from_file_or_default(user_config_path).unwrap();

let cache_settings = self
.cache_settings(xdg_directories.cache_dir())
.context(RetrieveCacheSettingsSnafu)?;
let transfer_client = xfer::Client::new(cache_settings)
.await
.context(InitializeTransferClientSnafu)?;
Expand All @@ -225,13 +239,12 @@ impl Cli {
.await;

// Only run the version check in the background if the user runs ANY other command than
// the version command. Also only report if the current version is outdated.
let check_version_in_background = !matches!(self.subcommand, Command::Version(_));
let release_check_future = release_check::version_notice_output(
transfer_client.clone(),
check_version_in_background,
true,
);
// the version command and the check isn't disabled via the user config. Also only report
// if the current version is outdated.
let check_version =
!matches!(self.subcommand, Command::Version(_)) && user_config.version.check_enabled;
let release_check_future =
release_check::version_notice_output(transfer_client.clone(), check_version, true);
let release_check_future =
tokio::time::timeout(std::time::Duration::from_secs(2), release_check_future);

Expand Down
56 changes: 56 additions & 0 deletions rust/stackablectl/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::path::{Path, PathBuf};

use serde::Deserialize;
use snafu::{ResultExt, Snafu};

#[derive(Debug, Default, Deserialize)]
pub struct UserConfig {
pub version: VersionOptions,
}

#[derive(Debug, Deserialize)]
pub struct VersionOptions {
pub check_enabled: bool,
}

#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("failed to read config file from {path}", path = path.display()))]
Read {
source: std::io::Error,
path: PathBuf,
},

#[snafu(display("failed to deserialize config file located at {path} as TOML", path = path.display()))]
Deserialize {
source: toml::de::Error,
path: PathBuf,
},
}

impl UserConfig {
/// Reads [`UserConfig`] from `path` or if not found, falls back to the default config.
pub fn from_file_or_default<P>(path: P) -> Result<Self, Error>
where
P: AsRef<Path>,
{
let path = path.as_ref();

match std::fs::read_to_string(path) {
Ok(contents) => toml::from_str(&contents).context(DeserializeSnafu { path }),
Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(Self::default()),
Err(err) => Err(Error::Read {
path: path.to_path_buf(),
source: err,
}),
}
}
}

impl Default for VersionOptions {
fn default() -> Self {
Self {
check_enabled: true,
}
}
}
1 change: 1 addition & 0 deletions rust/stackablectl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod args;
pub mod cli;
pub mod cmds;
pub mod config;
pub mod constants;
pub mod output;
pub mod release_check;
Expand Down
Loading