/7i' dZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ejeZdedefd Zdd eded ede e fd Zd edefdZd edefdZd edefdZdedefdZy)zdFile Utility Functions for ChefSystem. Helper functions for file operations and output management. N)Path)Optional)datetime)Output recipe_idreturnctdd|z } |jddtjd||S#t$r }tj d|dd}~wwxYw) zGet the output directory for a recipe, creating it if needed. Args: recipe_id: Recipe ID. Returns: Path: Path to recipe output directory (outputs/recipe_{id}). outputsrecipe_T)parentsexist_okz!Recipe output directory ensured: z(Error creating recipe output directory: exc_infoN)rmkdirloggerdebug Exceptionerror)r output_dires ;/mnt/ssd/data/python-lab/ChefSystem/src/utils/file_utils.pyget_recipe_output_dirrsviWYK#88J5 8 EF  ?sCd S s,A A) A$$A) source_pathexecution_notesc V t|}|jstjd|y|j stjd|yt |}|j }||z }|jrQtjjd}|d|j }||z }tjd|tj||tjd|d||jj} |j} |j!} tj"j!} t%| j'| } t)j*|||| | | | }|r2tjd |j,d |j.d |Stjd ||j1d|S#t2$r$}tjd|dYd}~yd}~wwxYw)aSave an output file for a recipe. Copies file to recipe output directory, generates unique name if needed, and creates Output record in database. Args: db_manager: DatabaseManager instance. source_path: Path to source file to copy. recipe_id: Recipe ID. execution_notes: Optional notes about this execution. Returns: Output: Created Output instance, or None on error. zSource file does not exist: NzSource path is not a file: z %Y%m%d_%H%M%S_z-File already exists, using timestamped name: z Copied file: u → )rfilenamefilepath file_type file_sizerzCreated output record: z (ID: )z#Failed to create output record for T) missing_okzError saving output file: r)rexistsrris_filernamernowstrftimeinfoshutilcopy2statst_sizesuffixabsolutecwdstr relative_torcreateridunlinkr) db_managerrrrsourcer dest_filename dest_path timestampr rabs_destabs_cwd relative_pathoutputrs rsave_output_filer>(s=k"}} LL7 }E F~~ LL6{mD E+95  .      //@I(k6;;-8M"]2I KKG W X  VY' mF85 <=NN$,, $$ %%'((*%%'H009:  ""+   KK1&//1B& STU V  LL>}oN O     -  1!5 Es)3G;(G;E/G;+G;; H(H##H(rc@ t|}|jstjd|y|j stjd|yt j dk(r#tjdt|gdnt j dk(rt jt|n]t j d k(r#tjd t|gdn'tjd t j ytjd |y#tj$r"}tjd |Yd}~yd}~wt$r$}tjd|dYd}~yd}~wwxYw)zOpen a file with the system's default application. Args: filepath: Path to file to open. Returns: bool: True if successful, False otherwise. z"Cannot open file: does not exist: FzCannot open: not a file: posixzxdg-openT)checkntdarwinopenzUnsupported platform: z Opened file: z,Error opening file (no application found?): NzError opening file: r)rr#rrr$osr% subprocessrunr0 startfiler(CalledProcessErrorrrpathrs r open_filerLws7 H~{{} LL=hZH I||~ LL4XJ? @ 77g  NNJD 2$ ? WW_ LLT # WW NNFCI.d ; LL1"''; < mH:./  ( ( CA3GH  +A3/$ ?s53D=(D=CD=$D==FE-- F9FFcn t|}|jsdddddS|jj}|j}t j t|\}}|d}|||ddS#t$r5}tjd |d ddddt|d cYd}~Sd}~wwxYw) zGet information about a file. Args: filepath: Path to file. Returns: dict: File information (size, extension, mime_type). runknownF)size extension mime_typer#Nzapplication/octet-streamTzError getting file info: r)rPrQrRr#r) rr#r+r,r- mimetypes guess_typer0rrr)rrKrPrQrRrrs r get_file_inforUs% H~{{}&  yy{""KK !++CI6 1  2I""      04t D"V    s#!A6AA66 B4?*B/)B4/B4c t|}|jstjd|y|j tj d|y#t $r$}tjd|dYd}~yd}~wwxYw)zDelete an output file from the filesystem. Args: filepath: Path to file to delete. Returns: bool: True if successful, False otherwise. z(File does not exist (already deleted?): TzDeleted file: zError deleting file: rNF)rr#rwarningr4r(rrrJs rdelete_output_filerXs|H~{{} NNEhZP Q  nXJ/0  ,QC04 @s3A(A B (BB  size_bytescDdD]}|dkr |dd|cS|dz}|ddS)zFormat file size in human-readable format. Args: size_bytes: Size in bytes. Returns: str: Formatted size (e.g., "1.5 MB"). )BKBMBGBTBg@z.1f z PB)rYunits rformat_file_sizercsK.   %Qtf- -f  S !!)rN)__doc__rEr)loggingrFrSpathlibrtypingrrsrc.database.modelsr getLogger__name__rintrr0r>boolrLdictrUrXrcrardrros  &   8 $ST(LcLcLTWLaijpaqL^)))X. C. D. b4 " " "rd