File size: 5,296 Bytes
490ec84 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
#!/usr/bin/env python3
import os
import re
import shutil
import subprocess
from datetime import datetime
import json
# --- CONFIGURATION: Define update rules ---
UPDATES = {
"requirements.txt": {
"type": "lines",
"entries": [
"fastapi",
"gunicorn",
"uvicorn",
"flask",
"pandas==2.1.4",
"numpy==1.25.2",
"python-dotenv"
],
"comment": "# Required for agentic services"
},
".env": {
"type": "keyval",
"entries": {
"STATIC_FILES_DIR": "/app/static",
"FLASK_APP": "backend.app",
"FLASK_ENV": "production"
}
},
"Dockerfile": {
"type": "replace_section",
"pattern": r"^CMD\s+.*",
"replacement": 'CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "backend.app:app"]'
},
"angular.json": {
"type": "json_property",
"path": "projects.agentic-dashboard.architect.build.options",
"updates": {
"outputPath": "dist",
"baseHref": "/static/"
}
}
}
# --- MAIN UPDATE HANDLERS ---
class FileUpdater:
@staticmethod
def backup_file(filepath):
if not os.path.exists(filepath):
return None
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = f"{filepath}.bak_{timestamp}"
shutil.copy2(filepath, backup_path)
return backup_path
@staticmethod
def update_lines_file(path, entries, comment=None):
existing = set()
if os.path.exists(path):
with open(path, "r") as f:
existing = {line.strip().lower() for line in f.readlines() if line.strip()}
needed = [e for e in entries if e.lower() not in existing]
if not needed:
return False, None
backup = FileUpdater.backup_file(path)
with open(path, "a") as f:
if comment:
f.write(f"\n{comment}\n")
for entry in needed:
f.write(f"{entry}\n")
return True, backup
@staticmethod
def update_keyval_file(path, kvs):
existing = {}
if os.path.exists(path):
with open(path, "r") as f:
for line in f:
if "=" in line and not line.startswith("#"):
k, v = line.strip().split("=", 1)
existing[k.strip()] = v.strip()
needs_update = any(existing.get(k) != v for k, v in kvs.items())
if not needs_update:
return False, None
backup = FileUpdater.backup_file(path)
with open(path, "w") as f:
for k, v in kvs.items():
f.write(f"{k}={v}\n")
for k, v in existing.items():
if k not in kvs:
f.write(f"{k}={v}\n")
return True, backup
@staticmethod
def update_regex_file(path, pattern, replacement):
if not os.path.exists(path):
return False, None
with open(path, "r") as f:
content = f.read()
updated = re.sub(pattern, replacement, content, flags=re.MULTILINE)
if content == updated:
return False, None
backup = FileUpdater.backup_file(path)
with open(path, "w") as f:
f.write(updated)
return True, backup
@staticmethod
def update_json_file(path, json_path, updates):
if not os.path.exists(path):
return False, None
backup = FileUpdater.backup_file(path)
with open(path, "r") as f:
data = json.load(f)
keys = json_path.split(".")
ref = data
for k in keys[:-1]:
ref = ref.setdefault(k, {})
ref[keys[-1]] = {**ref.get(keys[-1], {}), **updates}
with open(path, "w") as f:
json.dump(data, f, indent=2)
return True, backup
# --- MAIN EXECUTION ---
def smart_append(base_dir="."):
print(f"\n🔧 Scanning: {os.path.abspath(base_dir)}")
for filename, rule in UPDATES.items():
path = os.path.join(base_dir, filename)
print(f"\n⚙️ Updating: {filename}")
try:
if rule["type"] == "lines":
updated, backup = FileUpdater.update_lines_file(path, rule["entries"], rule.get("comment"))
elif rule["type"] == "keyval":
updated, backup = FileUpdater.update_keyval_file(path, rule["entries"])
elif rule["type"] == "replace_section":
updated, backup = FileUpdater.update_regex_file(path, rule["pattern"], rule["replacement"])
elif rule["type"] == "json_property":
updated, backup = FileUpdater.update_json_file(path, rule["path"], rule["updates"])
else:
print("⚠️ Unknown update type.")
continue
if updated:
print(f"✅ Updated {filename} (Backup: {backup})")
else:
print(f"✓ No changes needed")
except Exception as e:
print(f"❌ Error: {e}")
if __name__ == "__main__":
import sys
directory = sys.argv[1] if len(sys.argv) > 1 else "."
smart_append(directory)
print("\n✨ All updates complete.")
|