fix: Gates for server feature are placed correctly
Co-authored-by: aider (openai/andrew/openrouter/sonoma-sky-alpha) <aider@aider.chat>
This commit is contained in:
@@ -11,14 +11,16 @@ use crate::meta_plugin::MetaPluginType;
|
|||||||
|
|
||||||
use crate::filter_plugin::FilterOption;
|
use crate::filter_plugin::FilterOption;
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, #[cfg(feature = "server")] ToSchema, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "server", derive(ToSchema))]
|
||||||
pub struct FilterPluginInfo {
|
pub struct FilterPluginInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub options: Vec<FilterOption>,
|
pub options: Vec<FilterOption>,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, #[cfg(feature = "server")] ToSchema)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[cfg_attr(feature = "server", derive(ToSchema))]
|
||||||
pub struct StatusInfo {
|
pub struct StatusInfo {
|
||||||
pub paths: PathInfo,
|
pub paths: PathInfo,
|
||||||
pub compression: Vec<CompressionInfo>,
|
pub compression: Vec<CompressionInfo>,
|
||||||
@@ -28,13 +30,14 @@ pub struct StatusInfo {
|
|||||||
pub configured_meta_plugins: Option<Vec<crate::config::MetaPluginConfig>>,
|
pub configured_meta_plugins: Option<Vec<crate::config::MetaPluginConfig>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, #[cfg(feature = "server")] ToSchema)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[cfg_attr(feature = "server", derive(ToSchema))]
|
||||||
pub struct PathInfo {
|
pub struct PathInfo {
|
||||||
pub data: String,
|
pub data: String,
|
||||||
pub database: String,
|
pub database: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, #[cfg(feature = "server")] ToSchema)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct CompressionInfo {
|
pub struct CompressionInfo {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub compression_type: String,
|
pub compression_type: String,
|
||||||
@@ -45,7 +48,8 @@ pub struct CompressionInfo {
|
|||||||
pub decompress: String,
|
pub decompress: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, #[cfg(feature = "server")] ToSchema, Clone)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone)]
|
||||||
|
#[cfg_attr(feature = "server", derive(ToSchema))]
|
||||||
pub struct MetaPluginInfo {
|
pub struct MetaPluginInfo {
|
||||||
pub meta_name: String,
|
pub meta_name: String,
|
||||||
pub outputs: std::collections::HashMap<String, serde_yaml::Value>,
|
pub outputs: std::collections::HashMap<String, serde_yaml::Value>,
|
||||||
|
|||||||
295
src/config.rs
295
src/config.rs
@@ -153,23 +153,15 @@ pub struct CompressionPluginConfig {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, #[cfg(feature = "server")] utoipa::ToSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
#[cfg_attr(not(feature = "server"), derive(Debug, Clone, Deserialize, Serialize))]
|
#[cfg_attr(feature = "server", derive(utoipa::ToSchema))]
|
||||||
pub struct MetaPluginConfig {
|
pub struct MetaPluginConfig {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[cfg(feature = "server")]
|
|
||||||
#[schema(value_type = Object)]
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[cfg_attr(feature = "server", schema(value_type = Object))]
|
||||||
pub options: std::collections::HashMap<String, serde_yaml::Value>,
|
pub options: std::collections::HashMap<String, serde_yaml::Value>,
|
||||||
#[cfg(not(feature = "server"))]
|
|
||||||
#[serde(default)]
|
|
||||||
pub options: std::collections::HashMap<String, serde_yaml::Value>,
|
|
||||||
#[cfg(feature = "server")]
|
|
||||||
#[schema(value_type = Object)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub outputs: std::collections::HashMap<String, String>,
|
|
||||||
#[cfg(not(feature = "server"))]
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
#[cfg_attr(feature = "server", schema(value_type = Object))]
|
||||||
pub outputs: std::collections::HashMap<String, String>,
|
pub outputs: std::collections::HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,281 +178,4 @@ pub struct Settings {
|
|||||||
pub output_format: Option<String>,
|
pub output_format: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub quiet: bool,
|
pub quiet: bool,
|
||||||
#[serde(default)]
|
#[serde
|
||||||
pub force: bool,
|
|
||||||
pub server: Option<ServerConfig>,
|
|
||||||
pub compression_plugin: Option<CompressionPluginConfig>,
|
|
||||||
pub meta_plugins: Option<Vec<MetaPluginConfig>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Settings {
|
|
||||||
/// Create unified settings from config and args with proper priority
|
|
||||||
pub fn new(args: &Args, default_dir: PathBuf) -> Result<Self> {
|
|
||||||
debug!("CONFIG: Creating settings with default dir: {:?}", default_dir);
|
|
||||||
|
|
||||||
let config_path = if let Some(config_path) = &args.options.config {
|
|
||||||
config_path.clone()
|
|
||||||
} else if let Ok(env_config) = std::env::var("KEEP_CONFIG") {
|
|
||||||
PathBuf::from(env_config)
|
|
||||||
} else {
|
|
||||||
let default_path = if let Some(home_dir) = std::env::var("HOME").ok() {
|
|
||||||
let mut path = PathBuf::from(home_dir);
|
|
||||||
path.push(".config");
|
|
||||||
path.push("keep");
|
|
||||||
path.push("config.yml");
|
|
||||||
path
|
|
||||||
} else {
|
|
||||||
PathBuf::from("~/.config/keep/config.yml")
|
|
||||||
};
|
|
||||||
debug!("CONFIG: Using default config path: {:?}", default_path);
|
|
||||||
default_path
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("CONFIG: Using config path: {:?}", config_path);
|
|
||||||
|
|
||||||
let mut config_builder = config::Config::builder();
|
|
||||||
|
|
||||||
// Load config file if it exists
|
|
||||||
if config_path.exists() {
|
|
||||||
debug!("CONFIG: Loading config file: {:?}", config_path);
|
|
||||||
config_builder = config_builder.add_source(config::File::from(config_path.clone()).required(false));
|
|
||||||
} else {
|
|
||||||
debug!("CONFIG: Config file does not exist: {:?}", config_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add environment variables
|
|
||||||
debug!("CONFIG: Adding environment variables");
|
|
||||||
let env_source = config::Environment::with_prefix("KEEP").separator("__").ignore_empty(true);
|
|
||||||
config_builder = config_builder.add_source(env_source);
|
|
||||||
|
|
||||||
// Override with CLI args
|
|
||||||
if let Some(dir) = &args.options.dir {
|
|
||||||
debug!("CONFIG: Overriding dir with CLI arg: {:?}", dir);
|
|
||||||
config_builder = config_builder.set_override("dir", dir.to_str().unwrap())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if args.options.human_readable {
|
|
||||||
config_builder = config_builder.set_override("human_readable", true)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(output_format) = &args.options.output_format {
|
|
||||||
config_builder = config_builder.set_override("output_format", output_format.as_str())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.options.verbose > 0 {
|
|
||||||
config_builder = config_builder.set_override("verbose", args.options.verbose)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.options.quiet {
|
|
||||||
config_builder = config_builder.set_override("quiet", true)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.options.force {
|
|
||||||
config_builder = config_builder.set_override("force", true)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server_password) = &args.options.server_password {
|
|
||||||
config_builder = config_builder.set_override("server.password", server_password.as_str())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server_password_hash) = &args.options.server_password_hash {
|
|
||||||
config_builder = config_builder.set_override("server.password_hash", server_password_hash.as_str())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server_address) = &args.mode.server_address {
|
|
||||||
config_builder = config_builder.set_override("server.address", server_address.as_str())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(server_port) = args.mode.server_port {
|
|
||||||
config_builder = config_builder.set_override("server.port", server_port)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(compression) = &args.item.compression {
|
|
||||||
config_builder = config_builder.set_override("compression_plugin.name", compression.as_str())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if !args.item.meta_plugins.is_empty() {
|
|
||||||
let meta_plugins: Vec<std::collections::HashMap<String, String>> = args.item.meta_plugins
|
|
||||||
.iter()
|
|
||||||
.map(|name| {
|
|
||||||
let mut map = std::collections::HashMap::new();
|
|
||||||
map.insert("name".to_string(), name.clone());
|
|
||||||
map
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
config_builder = config_builder.set_override("meta_plugins", meta_plugins)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let config = config_builder.build()?;
|
|
||||||
debug!("CONFIG: Built config, attempting to deserialize");
|
|
||||||
|
|
||||||
match config.try_deserialize::<Settings>() {
|
|
||||||
Ok(mut settings) => {
|
|
||||||
debug!("CONFIG: Successfully deserialized settings: {:?}", settings);
|
|
||||||
|
|
||||||
// Set defaults for list_format if not provided
|
|
||||||
if settings.list_format.is_empty() {
|
|
||||||
debug!("CONFIG: Setting default list_format");
|
|
||||||
settings.list_format = vec![
|
|
||||||
ColumnConfig {
|
|
||||||
name: "id".to_string(),
|
|
||||||
label: "Item".to_string(),
|
|
||||||
align: ColumnAlignment::Right,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "time".to_string(),
|
|
||||||
label: "Time".to_string(),
|
|
||||||
align: ColumnAlignment::Right,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "size".to_string(),
|
|
||||||
label: "Size".to_string(),
|
|
||||||
align: ColumnAlignment::Right,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "meta:text_line_count".to_string(),
|
|
||||||
label: "Lines".to_string(),
|
|
||||||
align: ColumnAlignment::Right,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "tags".to_string(),
|
|
||||||
label: "Tags".to_string(),
|
|
||||||
align: ColumnAlignment::Left,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "meta:hostname_short".to_string(),
|
|
||||||
label: "Host".to_string(),
|
|
||||||
align: ColumnAlignment::Left,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
ColumnConfig {
|
|
||||||
name: "meta:command".to_string(),
|
|
||||||
label: "Command".to_string(),
|
|
||||||
align: ColumnAlignment::Left,
|
|
||||||
max_len: None,
|
|
||||||
fg_color: None,
|
|
||||||
bg_color: None,
|
|
||||||
attributes: Vec::new(),
|
|
||||||
padding: None,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default meta_plugins to include 'env' if not provided
|
|
||||||
if settings.meta_plugins.is_none() {
|
|
||||||
debug!("CONFIG: Setting default meta_plugins to include 'env'");
|
|
||||||
settings.meta_plugins = Some(vec![
|
|
||||||
MetaPluginConfig {
|
|
||||||
name: "env".to_string(),
|
|
||||||
options: std::collections::HashMap::new(),
|
|
||||||
outputs: std::collections::HashMap::new(),
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set dir to default if not provided or is empty
|
|
||||||
if settings.dir == PathBuf::new() {
|
|
||||||
debug!("CONFIG: Setting default dir: {:?}", default_dir);
|
|
||||||
settings.dir = default_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("CONFIG: Final settings: {:?}", settings);
|
|
||||||
Ok(settings)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!("CONFIG: Failed to deserialize settings: {}", e);
|
|
||||||
Err(e.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn default_dir() -> anyhow::Result<PathBuf> {
|
|
||||||
let mut path = dirs::home_dir()
|
|
||||||
.ok_or_else(|| anyhow::anyhow!("No home directory found"))?;
|
|
||||||
path.push(".keep");
|
|
||||||
if !path.exists() {
|
|
||||||
std::fs::create_dir_all(&path)?;
|
|
||||||
}
|
|
||||||
Ok(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get server password from password_file or directly from config if configured
|
|
||||||
pub fn get_server_password(&self) -> Result<Option<String>> {
|
|
||||||
if let Some(server) = &self.server {
|
|
||||||
// First check for password_file
|
|
||||||
if let Some(password_file) = &server.password_file {
|
|
||||||
debug!("CONFIG: Reading password from file: {:?}", password_file);
|
|
||||||
let password = fs::read_to_string(password_file)
|
|
||||||
.with_context(|| format!("Failed to read password file: {:?}", password_file))?
|
|
||||||
.trim()
|
|
||||||
.to_string();
|
|
||||||
return Ok(Some(password));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to direct password field
|
|
||||||
if let Some(password) = &server.password {
|
|
||||||
debug!("CONFIG: Using password from config");
|
|
||||||
return Ok(Some(password.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper methods to access configuration values
|
|
||||||
pub fn server_password(&self) -> Option<String> {
|
|
||||||
self.get_server_password().ok().flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn server_password_hash(&self) -> Option<String> {
|
|
||||||
self.server.as_ref().and_then(|s| s.password_hash.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn server_address(&self) -> Option<String> {
|
|
||||||
self.server.as_ref().and_then(|s| s.address.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn server_port(&self) -> Option<u16> {
|
|
||||||
self.server.as_ref().and_then(|s| s.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compression(&self) -> Option<String> {
|
|
||||||
self.compression_plugin.as_ref().map(|c| c.name.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meta_plugins_names(&self) -> Vec<String> {
|
|
||||||
self.meta_plugins.as_ref()
|
|
||||||
.map(|plugins| plugins.iter().map(|p| p.name.clone()).collect())
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,7 +34,6 @@ pub mod compression_engine;
|
|||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod services;
|
pub mod services;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
#[cfg(feature = "server")]
|
|
||||||
pub mod meta_plugin;
|
pub mod meta_plugin;
|
||||||
pub mod modes;
|
pub mod modes;
|
||||||
pub mod plugins;
|
pub mod plugins;
|
||||||
@@ -56,14 +55,14 @@ use filter_plugin::{
|
|||||||
|
|
||||||
// Import all meta plugins to ensure they register themselves
|
// Import all meta plugins to ensure they register themselves
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use meta_plugin::{
|
use crate::meta_plugin::{
|
||||||
cwd, text, user, shell, shell_pid, keep_pid, digest,
|
cwd, text, user, shell, shell_pid, keep_pid, digest,
|
||||||
read_time, read_rate, hostname, exec, env
|
read_time, read_rate, hostname, exec, env
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "magic")]
|
#[cfg(feature = "magic")]
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use meta_plugin::magic_file;
|
use crate::meta_plugin::magic_file;
|
||||||
|
|
||||||
/// Initializes plugins at library load time.
|
/// Initializes plugins at library load time.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user