Files
keep/src/modes/get.rs
Andrew Phillips f6220eb16e feat: replace binary detection with text metadata check
Co-authored-by: aider (openai/andrew/openrouter/deepseek/deepseek-chat-v3.1) <aider@aider.chat>
2025-08-28 13:09:00 -03:00

91 lines
3.2 KiB
Rust

use anyhow::{anyhow, Result};
use std::io::{Write};
use crate::common::is_binary::is_binary;
use crate::common::PIPESIZE;
use crate::config;
use crate::services::item_service::ItemService;
use clap::Command;
use is_terminal::IsTerminal;
use std::path::PathBuf;
pub fn mode_get(
cmd: &mut Command,
settings: &config::Settings,
ids: &mut Vec<i64>,
tags: &mut Vec<String>,
conn: &mut rusqlite::Connection,
data_path: PathBuf,
) -> Result<()> {
if !ids.is_empty() && !tags.is_empty() {
cmd.error(clap::error::ErrorKind::InvalidValue, "Both ID and tags given, you must supply exactly one ID or at least one tag when using --get").exit();
} else if ids.len() > 1 {
cmd.error(clap::error::ErrorKind::InvalidValue, "More than one ID given, you must supply exactly one ID or at least one tag when using --get").exit();
}
let mut meta: std::collections::HashMap<String, String> = std::collections::HashMap::new();
// Collect metadata from environment variables
for (key, value) in std::env::vars() {
if key.starts_with("KEEP_META_") && key != "KEEP_META_PLUGINS" {
let meta_name = key.strip_prefix("KEEP_META_").unwrap();
meta.insert(meta_name.to_string(), value);
}
}
let item_service = ItemService::new(data_path.clone());
let item_with_meta = item_service.find_item(conn, ids, tags, &meta)
.map_err(|e| anyhow!("Unable to find matching item in database: {}", e))?;
let item_id = item_with_meta.item.id.unwrap();
// Determine if we should detect binary data
let mut detect_binary = !settings.force && std::io::stdout().is_terminal();
if detect_binary {
let meta_map = item_with_meta.meta_as_map();
if let Some(text_val) = meta_map.get("text") {
if text_val == "true" {
detect_binary = false;
} else if text_val == "false" {
return Err(anyhow!(
"Refusing to output binary data to TTY, use --force to override"
));
}
}
}
// Use streaming approach to handle large files
let mut reader = item_service.get_compression_service().stream_item_content(
data_path.join(item_id.to_string()),
&item_with_meta.item.compression
)?;
if detect_binary {
// Read only the first 8192 bytes for binary detection
let mut sample_buffer = vec![0; PIPESIZE];
let bytes_read = reader.read(&mut sample_buffer)?;
if is_binary(&sample_buffer[..bytes_read]) {
return Err(anyhow!(
"Refusing to output binary data to TTY, use --force to override"
));
}
// We need to create a new reader since we consumed some bytes
reader = item_service.get_compression_service().stream_item_content(
data_path.join(item_id.to_string()),
&item_with_meta.item.compression
)?;
}
// Stream the content to stdout
let mut stdout = std::io::stdout();
let mut buffer = [0; PIPESIZE];
loop {
let bytes_read = reader.read(&mut buffer)?;
if bytes_read == 0 {
break;
}
stdout.write_all(&buffer[..bytes_read])?;
}
Ok(())
}