Code Version Scanner

 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()