bsc

Comprehensive codebase and cou...
Log | Files | Refs | README | LICENSE

deploy_pipeline.py (9921B)


      1 # Author  : Amit Dutta <amitdutta4255@gmail.com>
      2 # Date    : 06 Feb 2026
      3 # Repo    : https://github.com/notamitgamer/bsc
      4 # License : MIT License (See the LICENSE file for details)
      5 # Copyright (c) 2026 Amit Dutta
      6 
      7 import os
      8 import subprocess
      9 import shutil
     10 import stat
     11 import socket
     12 import sys
     13 from datetime import datetime
     14 
     15 BSC_REPO_ROOT = r"G:\bsc"
     16 GENERATE_INDEX_SCRIPT = r"G:\bsc\docs\generate_index.py"
     17 ARANAG_SITE_DESKTOP = r"C:\Users\PC\Desktop\amit.is-a.dev"
     18 BSC_LOCAL_BACKUP = r"G:\bsc_local"
     19 ARANAG_REPO_ROOT = r"G:\aranag"
     20 
     21 MIN_DISK_SPACE_MB = 500
     22 
     23 ARANAG_PRESERVE = [
     24     "ada-web",
     25     "compiler",
     26     "README.md",
     27     "sitemap.xml",
     28     ".firebase",
     29     ".git",
     30     "esal",
     31     "amit.is-a.dev"
     32 ]
     33 
     34 def remove_readonly(func, path, exc_info):
     35     try:
     36         os.chmod(path, stat.S_IWRITE)
     37         func(path)
     38     except Exception as e:
     39         print(f"Failed to force delete {path}: {e}")
     40 
     41 def check_internet(host="8.8.8.8", port=53, timeout=3):
     42     try:
     43         socket.setdefaulttimeout(timeout)
     44         socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
     45         return True
     46     except socket.error:
     47         return False
     48 
     49 def get_free_space_mb(folder):
     50     total, used, free = shutil.disk_usage(folder)
     51     return free // (2**20)
     52 
     53 def is_tool_installed(name):
     54     return shutil.which(name) is not None
     55 
     56 def pre_check():
     57     print("\n--- Step 0: System Pre-Checks ---")
     58     
     59     print("Checking internet connection...", end=" ")
     60     if check_internet():
     61         print("[OK]")
     62     else:
     63         print("[FAILED]")
     64         print("Error: No internet connection detected. Cannot push to Git or Firebase.")
     65         return False
     66 
     67     print("Checking required tools...", end=" ")
     68     missing_tools = []
     69     if not is_tool_installed("git"):
     70         missing_tools.append("git")
     71     
     72     if not is_tool_installed("firebase"):
     73         if not is_tool_installed("firebase.cmd"):
     74              missing_tools.append("firebase")
     75 
     76     if missing_tools:
     77         print("[FAILED]")
     78         print(f"Error: The following tools are missing from PATH: {', '.join(missing_tools)}")
     79         return False
     80     print("[OK]")
     81 
     82     backup_drive = os.path.splitdrive(BSC_LOCAL_BACKUP)[0]
     83     if not backup_drive: 
     84         backup_drive = "." 
     85     else:
     86         backup_drive += "\\"
     87         
     88     print(f"Checking disk space on {backup_drive}...", end=" ")
     89     try:
     90         free_space = get_free_space_mb(backup_drive)
     91         if free_space < MIN_DISK_SPACE_MB:
     92             print("[FAILED]")
     93             print(f"Error: Not enough disk space. Free: {free_space}MB, Required: {MIN_DISK_SPACE_MB}MB")
     94             return False
     95         print(f"[OK] ({free_space} MB free)")
     96     except Exception as e:
     97         print(f"[WARNING] Could not check disk space: {e}")
     98 
     99     return True
    100 
    101 def run_generate_index():
    102     print("\n--- Step 1: Generating Index HTML ---")
    103     
    104     index_path = os.path.join(BSC_REPO_ROOT, "docs", "index.html")
    105     old_content = ""
    106     
    107     if os.path.exists(index_path):
    108         try:
    109             with open(index_path, 'r', encoding='utf-8') as f:
    110                 old_content = f.read()
    111         except Exception:
    112             pass
    113 
    114     if os.path.exists(GENERATE_INDEX_SCRIPT):
    115         try:
    116             subprocess.run(["python", GENERATE_INDEX_SCRIPT], check=True)
    117             print("[Success] Index generation script executed.")
    118         except subprocess.CalledProcessError:
    119             print("[Error] Failed to run generate_index.py")
    120             return False
    121     else:
    122         print(f"[Error] Script not found at: {GENERATE_INDEX_SCRIPT}")
    123         return False
    124 
    125     new_content = ""
    126     if os.path.exists(index_path):
    127         try:
    128             with open(index_path, 'r', encoding='utf-8') as f:
    129                 new_content = f.read()
    130         except Exception:
    131             pass
    132 
    133     if old_content != new_content:
    134         print("[Info] Changes detected in index.html.")
    135         return True
    136     else:
    137         print("[Info] No changes detected in index.html.")
    138         return False
    139 
    140 def git_workflow_bsc():
    141     print("\n--- Step 2: Git Push (Primary Repo: bsc) ---")
    142     
    143     if not os.path.exists(BSC_REPO_ROOT):
    144         print(f"[Error] Repository root not found: {BSC_REPO_ROOT}")
    145         return
    146 
    147     os.chdir(BSC_REPO_ROOT)
    148     
    149     print("> git add .")
    150     try:
    151         subprocess.run(["git", "add", "."], check=True)
    152     except subprocess.CalledProcessError:
    153         print("[Error] 'git add' failed.")
    154         return
    155 
    156     try:
    157         result = subprocess.run(
    158             ["git", "diff", "--name-only", "--cached"],
    159             capture_output=True, text=True, check=True
    160         )
    161         changed_files = result.stdout.strip().splitlines()
    162     except subprocess.CalledProcessError:
    163         changed_files = []
    164 
    165     if not changed_files:
    166         print("[Info] No changes detected in 'bsc'. Skipping commit/push.")
    167         return
    168 
    169     # 1. Filter out docs/index.html (it's auto-generated)
    170     relevant_files = [f for f in changed_files if "docs/index.html" not in f.replace('\\', '/')]
    171 
    172     # 2. Separate "docs" files from "source code" files
    173     # We check if a file starts with "docs/"
    174     non_docs_files = [f for f in relevant_files if not f.replace('\\', '/').startswith('docs/')]
    175 
    176     # 3. Decision Logic:
    177     # If we have non-docs changes (like Semester_1/code.c), we prioritize those paths.
    178     # We ignore 'docs/' changes in the path calculation so it doesn't default to Root.
    179     if non_docs_files:
    180         files_to_check = non_docs_files
    181     else:
    182         # If ONLY docs changed (or only index.html changed), use whatever we have
    183         files_to_check = relevant_files if relevant_files else changed_files
    184 
    185     changed_dirs = [os.path.dirname(f.replace('/', os.sep)) for f in files_to_check]
    186     
    187     if not changed_dirs:
    188         common_path = ""
    189     else:
    190         try:
    191             common_path = os.path.commonpath(changed_dirs)
    192         except ValueError:
    193             common_path = ""
    194 
    195     path_str = f".\\{common_path}" if common_path else ".\\{root}"
    196     
    197     print(f"[Detected Changes in]: {path_str}")
    198     user_message = input(f"Enter commit message for '{path_str}': ")
    199     if not user_message:
    200         print("Commit message cannot be empty. Aborting git push.")
    201         return
    202 
    203     today = datetime.now().strftime("%Y-%m-%d")
    204     full_commit_msg = f"[{today}] : {path_str} : {user_message}"
    205     
    206     print(f"> git commit -m \"{full_commit_msg}\"")
    207     try:
    208         subprocess.run(["git", "commit", "-m", full_commit_msg], check=True)
    209         print("> git push")
    210     except subprocess.CalledProcessError as e:
    211         print(f"[Error] Git command failed: {e}")
    212 
    213 def deploy_firebase():
    214     print("\n--- Step 3: Firebase Deploy ---")
    215     if not os.path.exists(ARANAG_SITE_DESKTOP):
    216         print(f"[Error] Firebase project path not found: {ARANAG_SITE_DESKTOP}")
    217         return
    218 
    219     os.chdir(ARANAG_SITE_DESKTOP)
    220     print(f"Deploying from: {ARANAG_SITE_DESKTOP}")
    221     try:
    222         subprocess.run("firebase deploy --only hosting", shell=True, check=True)
    223         print("[Success] Firebase deployment complete.")
    224     except subprocess.CalledProcessError:
    225         print("[Error] Firebase deploy failed.")
    226 
    227 def sync_bsc_local():
    228     print("\n--- Step 4: Syncing to G:\\bsc_local ---")
    229     try:
    230         if os.path.exists(BSC_LOCAL_BACKUP):
    231             print(f"Cleaning {BSC_LOCAL_BACKUP}...")
    232             shutil.rmtree(BSC_LOCAL_BACKUP, onerror=remove_readonly)
    233         
    234         print(f"Copying from {BSC_REPO_ROOT} to {BSC_LOCAL_BACKUP}...")
    235         shutil.copytree(BSC_REPO_ROOT, BSC_LOCAL_BACKUP)
    236         print("[Success] bsc_local synced.")
    237     except Exception as e:
    238         print(f"[Error] Sync failed: {e}")
    239 
    240 def update_and_push_aranag():
    241     print("\n--- Step 5: Updating G:\\aranag & Pushing ---")
    242     
    243     if not os.path.exists(ARANAG_REPO_ROOT):
    244         print(f"[Error] Path not found: {ARANAG_REPO_ROOT}")
    245         return
    246 
    247     print("Cleaning G:\\aranag (preserving specific files)...")
    248     for item in os.listdir(ARANAG_REPO_ROOT):
    249         if item in ARANAG_PRESERVE:
    250             continue
    251         
    252         item_path = os.path.join(ARANAG_REPO_ROOT, item)
    253         try:
    254             if os.path.isdir(item_path):
    255                 shutil.rmtree(item_path, onerror=remove_readonly)
    256             else:
    257                 os.remove(item_path)
    258         except Exception as e:
    259             print(f"Warning: Could not delete {item}: {e}")
    260 
    261     print(f"Copying from {ARANAG_SITE_DESKTOP} to {ARANAG_REPO_ROOT}...")
    262     try:
    263         shutil.copytree(ARANAG_SITE_DESKTOP, ARANAG_REPO_ROOT, dirs_exist_ok=True)
    264     except Exception as e:
    265         print(f"[Error] Copy failed: {e}")
    266         return
    267 
    268     os.chdir(ARANAG_REPO_ROOT)
    269     print("Git pushing G:\\aranag...")
    270     
    271     try:
    272         subprocess.run(["git", "add", "."], check=True)
    273         
    274         status = subprocess.run(["git", "status", "--porcelain"], capture_output=True, text=True)
    275         if status.stdout.strip():
    276             commit_msg = f"Automated Update: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
    277             subprocess.run(["git", "commit", "-m", commit_msg], check=True)
    278             subprocess.run(["git", "push"], check=True)
    279             print("[Success] G:\\aranag updated and pushed.")
    280         else:
    281             print("[Info] No changes to push in G:\\aranag.")
    282             
    283     except subprocess.CalledProcessError as e:
    284         print(f"[Error] Git operations on aranag failed: {e}")
    285 
    286 def main():
    287     print("=== STARTING AUTOMATION PIPELINE ===")
    288     
    289     if not pre_check():
    290         print("\n[Aborted] Pre-checks failed. Please resolve the errors above.")
    291         return
    292 
    293     index_changed = run_generate_index()
    294 
    295     git_workflow_bsc()
    296 
    297     if index_changed:
    298         deploy_firebase()
    299     else:
    300         print("\n[Skip] Index unchanged. Skipping Firebase deploy.")
    301 
    302     sync_bsc_local()
    303 
    304     # removed the auto git upload for the main website folder.
    305     
    306     print("\n=== PIPELINE FINISHED ===")
    307 
    308 if __name__ == "__main__":
    309     main()
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror