Dependencies are :
pandas
openpyxl
tk
batch File :
@echo off
start /B pythonw "VersionScanner.py"
exit
Code:
import os, threading, tkinter as tk
from tkinter import filedialog, messagebox, ttk
import pandas as pd
from datetime import datetime
from openpyxl.styles import Border, Side, Alignment
class VersionScannerApp:
def __init__(self, root):
self.root = root
self.root.title("Version Scanner")
w, h = 800, 400
self.root.geometry(f"{w}x{h}+{int((root.winfo_screenwidth()-w)/2)}+{int((root.winfo_screenheight()-h)/2)}")
frame_top = tk.Frame(root); frame_top.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10)
frame_mid = tk.Frame(root); frame_mid.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=10, pady=5)
frame_bot = tk.Frame(root); frame_bot.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=5)
self.scan_btn = tk.Button(frame_top, text="Select Folder & Scan", command=self.start_scan, padx=20, pady=5, bg="#dddddd")
self.scan_btn.pack(side=tk.LEFT)
tk.Button(frame_top, text="Cleanup Old Results", command=self.cleanup_old, padx=20, pady=5, bg="#ffdddd").pack(side=tk.LEFT, padx=10)
self.status_var = tk.StringVar(value="Ready")
tk.Label(frame_top, textvariable=self.status_var, fg="blue").pack(side=tk.LEFT, padx=20)
cols = ("filename", "version", "purpose", "filepath")
self.tree = ttk.Treeview(frame_mid, columns=cols, show="headings")
for c, w in zip(cols, [150, 200, 300, 100]): self.tree.heading(c, text=c.title()); self.tree.column(c, width=w)
sb = ttk.Scrollbar(frame_mid, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=sb.set); self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True); sb.pack(side=tk.RIGHT, fill=tk.Y)
tk.Label(frame_bot, text="Activity Log:").pack(anchor="w")
self.log_text = tk.Text(frame_bot, height=8, state='disabled'); self.log_text.pack(fill=tk.X)
def log(self, msg):
self.log_text.config(state='normal'); self.log_text.insert(tk.END, msg + "\n"); self.log_text.see(tk.END); self.log_text.config(state='disabled')
def start_scan(self):
path = filedialog.askdirectory()
if not path: return
[self.tree.delete(i) for i in self.tree.get_children()]
self.log_text.config(state='normal'); self.log_text.delete(1.0, tk.END); self.log_text.config(state='disabled')
threading.Thread(target=self.scan_folder, args=(path,), daemon=True).start()
def cleanup_old(self):
count = 0
try:
for f in os.listdir(os.path.dirname(os.path.abspath(__file__))):
if f.startswith("Version_Details_") and f.endswith(".xlsx"):
os.remove(os.path.join(os.path.dirname(os.path.abspath(__file__)), f)); count += 1
self.log(f"Deleted {count} old files."); messagebox.showinfo("Cleanup", f"Deleted {count} old result files.")
except Exception as e: self.log(f"Cleanup Error: {e}"); messagebox.showerror("Error", str(e))
def scan_folder(self, folder_path):
self.scan_btn.config(state=tk.DISABLED); self.status_var.set("Scanning..."); data = []
try:
for root, _, files in os.walk(folder_path):
for file in files:
fpath = os.path.normpath(os.path.join(root, file)); self.log(f"Scanning: {file}")
try:
with open(fpath, 'r', encoding='utf-8', errors='ignore') as f: lines = f.readlines()
found_hist = False
for i, line in enumerate(lines):
if "Revision History:" in line: found_hist = True; continue
if found_hist and "Version:" in line:
v_txt = line.strip(); p_txt = lines[i+1].strip() if i+1 < len(lines) else ""
data.append({"filename": file, "filepath": fpath, "version": v_txt, "purpose": p_txt})
self.root.after(0, lambda f=file, v=v_txt, p=p_txt, fp=fpath: self.tree.insert("", tk.END, values=(f, v, p, fp)))
self.log(f" -> Found: {v_txt}"); break
except: pass
if data: self.save_excel(data)
else: self.status_var.set("No matches found."); self.log("Scan complete. No matches.")
except Exception as e: self.status_var.set("Error"); self.log(f"Error: {e}"); messagebox.showerror("Error", str(e))
finally: self.scan_btn.config(state=tk.NORMAL); self.status_var.set("Ready") if self.status_var.get()=="Scanning..." else None
def save_excel(self, data):
try:
self.log("Saving..."); out = os.path.join(os.path.dirname(os.path.abspath(__file__)), f"Version_Details_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx")
with pd.ExcelWriter(out, engine='openpyxl') as writer:
pd.DataFrame(data).to_excel(writer, sheet_name='Version Details', index=False); ws = writer.sheets['Version Details']
thin = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin'))
for col in ws.columns:
max_len = max([len(str(c.value)) for c in col if c.value] + [0]); ws.column_dimensions[col[0].column_letter].width = max_len + 2
for c in col: c.border = thin; c.alignment = Alignment(horizontal='center', vertical='center') if c.row == 1 else Alignment()
self.log(f"Saved: {out}"); self.status_var.set("Saved Successfully"); messagebox.showinfo("Success", f"Data saved to:\n{out}")
except Exception as e: self.log(f"Save Error: {e}"); messagebox.showerror("Save Error", str(e))
if __name__ == "__main__": root = tk.Tk(); app = VersionScannerApp(root); root.mainloop()