# src/utils.py import yaml import logging import os import sys def load_yaml(path): """加载 YAML 配置文件""" if not os.path.exists(path): logging.error(f"Config file not found: {path}") sys.exit(1) with open(path, 'r') as f: return yaml.safe_load(f) def setup_logger(work_dir, log_file="autonep.log"): """配置日志:同时输出到文件和控制台""" logger = logging.getLogger() logger.setLevel(logging.INFO) # 清楚之前的 handler 防止重复 if logger.hasHandlers(): logger.handlers.clear() # 文件 Handler file_handler = logging.FileHandler(os.path.join(work_dir, log_file)) file_handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) logger.addHandler(file_handler) # 控制台 Handler console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter('%(message)s')) # 控制台只看消息,简洁点 logger.addHandler(console_handler) return logger class Notifier: """(预留) 通知模块""" def __init__(self, url=None): self.url = url def send(self, title, msg, priority=5): # 暂时只打印日志,不实际发送 logging.info(f"[[Notification]] {title}: {msg}") # src/utils.py 添加在最后 def run_cmd_with_log(cmd, cwd, log_file="exec.log", input_str=None): """ 执行命令并将 stdout/stderr 重定向到日志文件 """ import subprocess log_path = os.path.join(cwd, log_file) mode = 'a' if os.path.exists(log_path) else 'w' with open(log_path, mode) as f: f.write(f"\n\n>>> Executing: {cmd}\n") f.write(f">>> Input: {repr(input_str)}\n") f.write("-" * 40 + "\n") f.flush() try: process = subprocess.Popen( cmd, shell=True, cwd=cwd, stdin=subprocess.PIPE if input_str else None, stdout=f, # 直接指向文件 stderr=subprocess.STDOUT, # 把错误也合并到同一个日志 text=True ) # 发送输入并等待 process.communicate(input=input_str) f.write(f"\n>>> Finished with Return Code: {process.returncode}\n") return process.returncode == 0 except Exception as e: f.write(f"\n>>> Exception: {str(e)}\n") return False