"""
Herramientas para manejo de archivos.
"""
import hashlib
import json
from pathlib import Path
from typing import Any, Dict
import aiofiles
async def read_file_content(args: Dict[str, Any]) -> str:
"""Leer el contenido de un archivo."""
file_path = args.get("file_path")
encoding = args.get("encoding", "utf-8")
if not file_path:
return "Error: Se requiere el parámetro 'file_path'"
try:
async with aiofiles.open(file_path, "r", encoding=encoding) as f:
content = await f.read()
return f"Contenido del archivo '{file_path}':\n{content}"
except FileNotFoundError:
return f"Error: Archivo no encontrado: {file_path}"
except Exception as e:
return f"Error leyendo archivo: {str(e)}"
def read_file_content_sync(args: Dict[str, Any]) -> str:
"""Leer el contenido de un archivo (versión síncrona)."""
file_path = args.get("file_path")
encoding = args.get("encoding", "utf-8")
if not file_path:
return "Error: Se requiere el parámetro 'file_path'"
try:
with open(file_path, "r", encoding=encoding) as f:
content = f.read()
return f"Contenido del archivo '{file_path}':\n{content}"
except FileNotFoundError:
return f"Error: Archivo no encontrado: {file_path}"
except Exception as e:
return f"Error leyendo archivo: {str(e)}"
def get_file_info(args: Dict[str, Any]) -> str:
"""Obtener información detallada de un archivo."""
file_path = args.get("file_path")
if not file_path:
return "Error: Se requiere el parámetro 'file_path'"
try:
path = Path(file_path)
if not path.exists():
return f"Error: Archivo no encontrado: {file_path}"
stat = path.stat()
info = {
"nombre": path.name,
"ruta_completa": str(path.absolute()),
"tamaño_bytes": stat.st_size,
"tamaño_legible": format_file_size(stat.st_size),
"extensión": path.suffix,
"es_archivo": path.is_file(),
"es_directorio": path.is_dir(),
"fecha_modificación": stat.st_mtime,
"fecha_acceso": stat.st_atime,
"fecha_creación": stat.st_ctime,
"permisos": oct(stat.st_mode)[-3:],
}
return json.dumps(info, indent=2, ensure_ascii=False)
except Exception as e:
return f"Error obteniendo información del archivo: {str(e)}"
def list_directory(args: Dict[str, Any]) -> str:
"""Listar contenido de un directorio."""
dir_path = args.get("dir_path", ".")
show_hidden = args.get("show_hidden", False)
try:
path = Path(dir_path)
if not path.exists():
return f"Error: Directorio no encontrado: {dir_path}"
if not path.is_dir():
return f"Error: La ruta no es un directorio: {dir_path}"
items = []
for item in path.iterdir():
if not show_hidden and item.name.startswith("."):
continue
item_info = {
"nombre": item.name,
"tipo": "directorio" if item.is_dir() else "archivo",
"tamaño": format_file_size(item.stat().st_size)
if item.is_file()
else "N/A",
}
items.append(item_info)
# Ordenar por tipo y nombre
items.sort(key=lambda x: (x["tipo"], x["nombre"]))
result = f"Contenido del directorio '{dir_path}':\n"
for item in items:
result += f" {item['tipo']}: {item['nombre']} ({item['tamaño']})\n"
return result
except Exception as e:
return f"Error listando directorio: {str(e)}"
def calculate_file_hash(args: Dict[str, Any]) -> str:
"""Calcular hash de un archivo."""
file_path = args.get("file_path")
algorithm = args.get("algorithm", "md5").lower()
if not file_path:
return "Error: Se requiere el parámetro 'file_path'"
if algorithm not in ["md5", "sha1", "sha256", "sha512"]:
return "Error: Algoritmo no soportado. Use: md5, sha1, sha256, sha512"
try:
hash_obj = hashlib.new(algorithm)
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_obj.update(chunk)
hash_value = hash_obj.hexdigest()
return f"Hash {algorithm.upper()} de '{file_path}': {hash_value}"
except FileNotFoundError:
return f"Error: Archivo no encontrado: {file_path}"
except Exception as e:
return f"Error calculando hash: {str(e)}"
def search_files(args: Dict[str, Any]) -> str:
"""Buscar archivos por patrón en un directorio."""
dir_path = args.get("dir_path", ".")
pattern = args.get("pattern")
recursive = args.get("recursive", False)
if not pattern:
return "Error: Se requiere el parámetro 'pattern'"
try:
path = Path(dir_path)
if not path.exists():
return f"Error: Directorio no encontrado: {dir_path}"
if recursive:
files = list(path.rglob(pattern))
else:
files = list(path.glob(pattern))
if not files:
return f"No se encontraron archivos que coincidan con el patrón '{pattern}'"
result = f"Archivos encontrados con patrón '{pattern}':\n"
for file in files:
file_type = "directorio" if file.is_dir() else "archivo"
size = format_file_size(file.stat().st_size) if file.is_file() else "N/A"
result += f" {file_type}: {file} ({size})\n"
return result
except Exception as e:
return f"Error buscando archivos: {str(e)}"
def format_file_size(size_bytes: int) -> str:
"""Formatear tamaño de archivo en formato legible."""
if size_bytes == 0:
return "0 B"
size_names = ["B", "KB", "MB", "GB", "TB"]
i = 0
while size_bytes >= 1024 and i < len(size_names) - 1:
size_bytes /= 1024.0
i += 1
return f"{size_bytes:.1f} {size_names[i]}"
def register_file_tools(tools: Dict[str, Dict[str, Any]]) -> None:
"""Registrar herramientas de archivos."""
tools["read_file"] = {
"description": "Leer el contenido completo de un archivo",
"handler": read_file_content_sync,
"inputSchema": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Ruta del archivo a leer",
},
"encoding": {
"type": "string",
"description": "Codificación del archivo (por defecto: utf-8)",
"default": "utf-8",
},
},
"required": ["file_path"],
},
}
tools["get_file_info"] = {
"description": "Obtener información detallada de un archivo o directorio",
"handler": get_file_info,
"inputSchema": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Ruta del archivo o directorio",
}
},
"required": ["file_path"],
},
}
tools["list_directory"] = {
"description": "Listar el contenido de un directorio",
"handler": list_directory,
"inputSchema": {
"type": "object",
"properties": {
"dir_path": {
"type": "string",
"description": "Ruta del directorio (por defecto: directorio actual)",
"default": ".",
},
"show_hidden": {
"type": "boolean",
"description": "Mostrar archivos ocultos",
"default": False,
},
},
},
}
tools["calculate_file_hash"] = {
"description": "Calcular hash de un archivo",
"handler": calculate_file_hash,
"inputSchema": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "Ruta del archivo"},
"algorithm": {
"type": "string",
"description": "Algoritmo de hash (md5, sha1, sha256, sha512)",
"enum": ["md5", "sha1", "sha256", "sha512"],
"default": "md5",
},
},
"required": ["file_path"],
},
}
tools["search_files"] = {
"description": "Buscar archivos por patrón en un directorio",
"handler": search_files,
"inputSchema": {
"type": "object",
"properties": {
"dir_path": {
"type": "string",
"description": "Directorio donde buscar (por defecto: directorio actual)",
"default": ".",
},
"pattern": {
"type": "string",
"description": "Patrón de búsqueda (ej: *.py, *.txt)",
},
"recursive": {
"type": "boolean",
"description": "Búsqueda recursiva en subdirectorios",
"default": False,
},
},
"required": ["pattern"],
},
}