use crate::application::services::InterpolationService;
use crate::domain::action::BookmarkAction;
use crate::domain::bookmark::Bookmark;
use crate::domain::error::DomainResult;
use crate::util::interpolation::InterpolationHelper;
use std::sync::Arc;
use tracing::{debug, instrument};
#[derive(Debug)]
pub struct EnvAction {
interpolation_service: Arc<dyn InterpolationService>,
}
impl EnvAction {
pub fn new(interpolation_service: Arc<dyn InterpolationService>) -> Self {
Self {
interpolation_service,
}
}
}
impl BookmarkAction for EnvAction {
#[instrument(skip(self, bookmark), level = "debug")]
fn execute(&self, bookmark: &Bookmark) -> DomainResult<()> {
let env_content = &bookmark.url;
let rendered_content = InterpolationHelper::render_if_needed(
env_content,
bookmark,
&self.interpolation_service,
"environment variables",
)?;
debug!("Printing environment variables to stdout for sourcing");
println!("# Environment variables from: {}", bookmark.title);
println!(
"# Usage: eval \"$(bkmr open {})\" or source <(bkmr open {})",
bookmark.id.unwrap_or(0),
bookmark.id.unwrap_or(0)
);
println!("# ----- BEGIN ENVIRONMENT VARIABLES -----");
println!("{}", rendered_content);
println!("# ----- END ENVIRONMENT VARIABLES -----");
Ok(())
}
fn description(&self) -> &'static str {
"Print environment variables for sourcing"
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::application::InterpolationServiceImpl;
use crate::domain::tag::Tag;
use crate::infrastructure::interpolation::minijinja_engine::{
MiniJinjaEngine, SafeShellExecutor,
};
use std::collections::HashSet;
#[test]
fn given_env_bookmark_when_execute_then_prints_content() {
let shell_executor = Arc::new(SafeShellExecutor::new());
let interpolation_engine = Arc::new(MiniJinjaEngine::new(shell_executor));
let interpolation_service = Arc::new(InterpolationServiceImpl::new(interpolation_engine));
let action = EnvAction::new(interpolation_service);
let env_content = "export FOO=bar\nexport BAZ=qux";
let mut tags = HashSet::new();
tags.insert(Tag::new("_env_").unwrap());
let bookmark = Bookmark {
id: Some(1),
url: env_content.to_string(),
title: "Test Environment Variables".to_string(),
description: "A test set of environment variables".to_string(),
tags,
access_count: 0,
created_at: Some(chrono::Utc::now()),
updated_at: chrono::Utc::now(),
embedding: None,
content_hash: None,
embeddable: false,
file_path: None,
file_mtime: None,
file_hash: None,
opener: None,
accessed_at: None,
};
let result = action.execute(&bookmark);
assert!(result.is_ok(), "Env action execution should succeed");
}
#[test]
fn given_env_with_template_when_execute_then_interpolates_and_prints() {
let shell_executor = Arc::new(SafeShellExecutor::new());
let interpolation_engine = Arc::new(MiniJinjaEngine::new(shell_executor));
let interpolation_service = Arc::new(InterpolationServiceImpl::new(interpolation_engine));
let action = EnvAction::new(interpolation_service);
let env_content = "export DATE={{ current_date | strftime(\"%Y-%m-%d\") }}\nexport USER={{ \"whoami\" | shell }}";
let mut tags = HashSet::new();
tags.insert(Tag::new("_env_").unwrap());
let bookmark = Bookmark {
id: Some(1),
url: env_content.to_string(),
title: "Test Env with Interpolation".to_string(),
description: "A test set of environment variables with interpolation".to_string(),
tags,
access_count: 0,
created_at: Some(chrono::Utc::now()),
updated_at: chrono::Utc::now(),
embedding: None,
content_hash: None,
embeddable: false,
file_path: None,
file_mtime: None,
file_hash: None,
opener: None,
accessed_at: None,
};
let result = action.execute(&bookmark);
assert!(result.is_ok(), "Env action execution should succeed");
}
}