new version
This commit is contained in:
parent
522298a6ec
commit
b41cd757e4
412 changed files with 20890 additions and 6 deletions
129
config_selector.py
Executable file → Normal file
129
config_selector.py
Executable file → Normal file
|
|
@ -5,20 +5,31 @@ import json
|
|||
import shutil
|
||||
import curses
|
||||
import re
|
||||
import csv
|
||||
import filecmp
|
||||
import yaml
|
||||
from typing import List, Dict, Set, Tuple, Optional
|
||||
|
||||
# Use current directory instead of hardcoded path
|
||||
BASE_DIR = os.getcwd()
|
||||
|
||||
class ConfigSelector:
|
||||
def __init__(self, json_path: str, original_config_path: str, config_path: str):
|
||||
def __init__(self, json_path: str, original_config_path: str, config_path: str,
|
||||
old_recipe_path: str = None, changed_files_path: str = None, deleted_files_csv: str = None,
|
||||
ignored_files_yml: str = None):
|
||||
self.json_path = json_path
|
||||
self.original_config_path = original_config_path
|
||||
self.config_path = config_path
|
||||
self.old_recipe_path = old_recipe_path or os.path.join(BASE_DIR, "old_recipe_config")
|
||||
self.changed_files_path = changed_files_path or os.path.join(BASE_DIR, "changed_files")
|
||||
self.deleted_files_csv = deleted_files_csv or os.path.join(BASE_DIR, "deleted_files.csv")
|
||||
self.ignored_files_yml = ignored_files_yml or os.path.join(BASE_DIR, "ignored_files.yml")
|
||||
self.prefixes: List[str] = []
|
||||
self.matched_files: Dict[str, List[str]] = {}
|
||||
self.unmatched_files: Dict[str, List[str]] = {}
|
||||
self.ignored_files: Set[str] = set()
|
||||
self.load_prefixes()
|
||||
self.load_ignored_files()
|
||||
self.scan_configs()
|
||||
|
||||
def load_prefixes(self) -> None:
|
||||
|
|
@ -37,6 +48,23 @@ class ConfigSelector:
|
|||
print(f"Error loading JSON file: {e}")
|
||||
exit(1)
|
||||
|
||||
def load_ignored_files(self) -> None:
|
||||
"""Load ignored file names from YAML file."""
|
||||
self.ignored_files = set()
|
||||
if not os.path.exists(self.ignored_files_yml):
|
||||
return
|
||||
|
||||
try:
|
||||
with open(self.ignored_files_yml, 'r') as f:
|
||||
data = yaml.safe_load(f)
|
||||
if data:
|
||||
# Iterate through all categories in the YAML.
|
||||
for category, info in data.items():
|
||||
if isinstance(info, dict) and 'name' in info:
|
||||
self.ignored_files.add(info['name'])
|
||||
except (yaml.YAMLError, FileNotFoundError) as e:
|
||||
print(f"Warning: Error loading ignored files YAML: {e}")
|
||||
|
||||
def save_prefixes(self) -> None:
|
||||
"""Save current prefixes back to JSON file."""
|
||||
try:
|
||||
|
|
@ -118,6 +146,75 @@ class ConfigSelector:
|
|||
|
||||
print(f"Copied {copied_count} files to {self.config_path} ({processed_count} files were processed to remove UUIDs and _core structures)")
|
||||
|
||||
def compare_and_track_changes(self) -> Tuple[int, int, int]:
|
||||
"""
|
||||
Compare files between old_recipe_config and new_recipe_config.
|
||||
Copy changed files to changed_files folder.
|
||||
Track deleted files in deleted_files.csv.
|
||||
|
||||
Returns:
|
||||
Tuple of (changed_count, deleted_count, unchanged_count)
|
||||
"""
|
||||
# Ensure directories exist
|
||||
if not os.path.exists(self.changed_files_path):
|
||||
os.makedirs(self.changed_files_path)
|
||||
|
||||
# Track statistics
|
||||
changed_count = 0
|
||||
deleted_count = 0
|
||||
unchanged_count = 0
|
||||
ignored_count = 0
|
||||
deleted_files_list = []
|
||||
|
||||
# Get all files in old_recipe_config
|
||||
old_files = set()
|
||||
if os.path.exists(self.old_recipe_path):
|
||||
old_files = {f for f in os.listdir(self.old_recipe_path) if f.endswith('.yml')}
|
||||
|
||||
# Get all files in new_recipe_config
|
||||
new_files = set()
|
||||
if os.path.exists(self.config_path):
|
||||
new_files = {f for f in os.listdir(self.config_path) if f.endswith('.yml')}
|
||||
|
||||
# Find deleted files (in old but not in new)
|
||||
deleted_files = old_files - new_files
|
||||
for filename in sorted(deleted_files):
|
||||
deleted_files_list.append(filename)
|
||||
deleted_count += 1
|
||||
|
||||
# Find common files and check for changes
|
||||
common_files = old_files & new_files
|
||||
for filename in sorted(common_files):
|
||||
old_file_path = os.path.join(self.old_recipe_path, filename)
|
||||
new_file_path = os.path.join(self.config_path, filename)
|
||||
|
||||
# Compare file contents
|
||||
if filecmp.cmp(old_file_path, new_file_path, shallow=False):
|
||||
# Files are identical
|
||||
unchanged_count += 1
|
||||
else:
|
||||
# Files have changed - check if ignored
|
||||
if filename in self.ignored_files:
|
||||
# Skip copying ignored files
|
||||
ignored_count += 1
|
||||
else:
|
||||
# Copy to changed_files
|
||||
changed_dest = os.path.join(self.changed_files_path, filename)
|
||||
shutil.copy2(new_file_path, changed_dest)
|
||||
changed_count += 1
|
||||
|
||||
# Write deleted files to CSV
|
||||
with open(self.deleted_files_csv, 'w', newline='') as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
writer.writerow(['filename']) # Header
|
||||
for filename in deleted_files_list:
|
||||
writer.writerow([filename])
|
||||
|
||||
if ignored_count > 0:
|
||||
print(f"Ignored {ignored_count} changed file(s) as per ignored_files.yml")
|
||||
|
||||
return changed_count, deleted_count, unchanged_count
|
||||
|
||||
def add_prefix(self, prefix: str) -> None:
|
||||
"""Add a new prefix to the list if it doesn't exist."""
|
||||
if prefix and prefix not in self.prefixes:
|
||||
|
|
@ -301,7 +398,7 @@ def draw_menu(stdscr, selector: ConfigSelector, selected_idx: int, view_mode: st
|
|||
|
||||
# Instructions
|
||||
stdscr.addstr(h-4, 2, "LEFT/RIGHT: Navigate tree levels | SPACE: Toggle view | ENTER: Select files")
|
||||
stdscr.addstr(h-3, 2, "A: Add prefix | O: Choose prefix | D: Add current path as prefix | C: Copy | S: Save | Q: Quit")
|
||||
stdscr.addstr(h-3, 2, "A: Add prefix | O: Choose | D: Add/Del | C: Copy | M: Compare | S: Save | Q: Quit")
|
||||
|
||||
# Content area
|
||||
start_y = 3
|
||||
|
|
@ -805,11 +902,33 @@ def confirm_yaml_cleaning(stdscr, selector):
|
|||
|
||||
return confirm_dialog(stdscr, "Copy all matched files to config directory and remove UUID and _core?")
|
||||
|
||||
def show_comparison_results(stdscr, changed_count, deleted_count, unchanged_count):
|
||||
"""Show the results of file comparison."""
|
||||
h, w = stdscr.getmaxyx()
|
||||
dialog_h, dialog_w = 10, 60
|
||||
dialog_y = (h - dialog_h) // 2
|
||||
dialog_x = (w - dialog_w) // 2
|
||||
|
||||
# Draw dialog box
|
||||
dialog_win = curses.newwin(dialog_h, dialog_w, dialog_y, dialog_x)
|
||||
dialog_win.box()
|
||||
dialog_win.addstr(1, 2, "File Comparison Results", curses.A_BOLD)
|
||||
dialog_win.addstr(3, 4, f"Changed files: {changed_count}")
|
||||
dialog_win.addstr(4, 4, f"Deleted files: {deleted_count}")
|
||||
dialog_win.addstr(5, 4, f"Unchanged files: {unchanged_count}")
|
||||
dialog_win.addstr(7, 4, "Changed files copied to: changed_files/")
|
||||
dialog_win.addstr(8, 4, "Deleted files tracked in: deleted_files.csv")
|
||||
dialog_win.addstr(dialog_h - 2, 2, "Press any key to continue...")
|
||||
dialog_win.refresh()
|
||||
|
||||
# Wait for key
|
||||
stdscr.getch()
|
||||
|
||||
def main(stdscr):
|
||||
# Set paths relative to current directory
|
||||
json_path = os.path.join(BASE_DIR, "config_prefixes.json")
|
||||
original_config_path = os.path.join(BASE_DIR, "original_config")
|
||||
config_path = os.path.join(BASE_DIR, "config")
|
||||
config_path = os.path.join(BASE_DIR, "new_recipe_config")
|
||||
|
||||
# Create directories if they don't exist
|
||||
if not os.path.exists(original_config_path):
|
||||
|
|
@ -975,6 +1094,10 @@ def main(stdscr):
|
|||
elif key == ord('c') or key == ord('C'):
|
||||
if confirm_yaml_cleaning(stdscr, selector):
|
||||
selector.copy_matched_files()
|
||||
elif key == ord('m') or key == ord('M'):
|
||||
if confirm_dialog(stdscr, "Compare old and new recipe configs and track changes?"):
|
||||
changed_count, deleted_count, unchanged_count = selector.compare_and_track_changes()
|
||||
show_comparison_results(stdscr, changed_count, deleted_count, unchanged_count)
|
||||
elif key == ord('s') or key == ord('S'):
|
||||
selector.save_prefixes()
|
||||
elif key in (10, 13): # ENTER key to select individual files
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue