Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 26 additions & 30 deletions script.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,23 @@
REPO_OWNER = "NammaLakes"
REPO_NAME = "node"
BRANCH = "main"
LOCAL_REPO_PATH = "Add Local Path"
BACKUP_PATH = "Add a path for backup"
LOCAL_REPO_PATH = r"local_repo_path"
BACKUP_PATH = "" #add if this is a private repo
Copy link

Copilot AI Apr 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty BACKUP_PATH may lead to unintended behavior when creating or restoring backups; consider providing a valid default path or adding a guard clause to handle empty values.

Suggested change
BACKUP_PATH = "" #add if this is a private repo
BACKUP_PATH = "backup" # Default backup path; update if needed

Copilot uses AI. Check for mistakes.

# GitHub API URL for commits
GITHUB_API_URL = (
f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/commits?sha={BRANCH}"
)
GITHUB_API_URL = f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/commits?sha={BRANCH}"


# Optional: GitHub Personal Access Token (if using a private repo)
GITHUB_TOKEN = "your-github-token"
# Optional: GitHub Personal Access Token
GITHUB_TOKEN = "" # keep empty if public repo


def get_latest_commit():
"""Fetch the latest commit SHA from GitHub API."""
headers = {}
if GITHUB_TOKEN:
headers["Authorization"] = f"token {GITHUB_TOKEN}"

try:
response = requests.get(GITHUB_API_URL, headers=headers)
response = requests.get(GITHUB_API_URL, headers=headers, timeout=10)
response.raise_for_status()
commits = response.json()
return commits[0]["sha"] if commits else None
Expand All @@ -36,23 +32,28 @@ def get_latest_commit():
return None


def get_latest_commit():
"""Fetch the latest commit SHA from GitHub API for a public repo."""
def get_local_commit():
try:
response = requests.get(GITHUB_API_URL, timeout=10) # No auth needed
response.raise_for_status()
commits = response.json()
return commits[0]["sha"] if commits else None
except requests.exceptions.RequestException as e:
print(f"Error checking for updates: {e}")
result = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=LOCAL_REPO_PATH,
capture_output=True,
text=True,
)
if result.returncode == 0:
return result.stdout.strip()
else:
print(f"Error getting local commit: {result.stderr}")
return None
except Exception as e:
print(f"Exception getting local commit: {e}")
return None


def create_backup():
"""Create a backup of the current repository."""
try:
if os.path.exists(BACKUP_PATH):
shutil.rmtree(BACKUP_PATH) # Remove old backup
shutil.rmtree(BACKUP_PATH)
shutil.copytree(LOCAL_REPO_PATH, BACKUP_PATH)
print("Backup created successfully.")
return True
Expand All @@ -62,22 +63,20 @@ def create_backup():


def restore_backup():
"""Restore the backup if update fails."""
try:
if os.path.exists(BACKUP_PATH):
if os.path.exists(LOCAL_REPO_PATH):
shutil.rmtree(LOCAL_REPO_PATH) # Delete failed update
shutil.rmtree(LOCAL_REPO_PATH)
shutil.copytree(BACKUP_PATH, LOCAL_REPO_PATH)
print("Rollback successful: Restored backup.")
print("Rollback successful.")
else:
print("No backup found to restore.")
except Exception as e:
print(f"Error restoring backup: {e}")


def update_repository():
"""Pull the latest changes from GitHub after backing up."""
if create_backup(): # Only proceed if backup is successful
if create_backup():
try:
print("Pulling latest changes from GitHub...")
result = subprocess.run(
Expand All @@ -86,14 +85,12 @@ def update_repository():
capture_output=True,
text=True,
)

if result.returncode == 0:
print("Repository updated successfully.")
shutil.rmtree(BACKUP_PATH) # Delete backup after a successful update
shutil.rmtree(BACKUP_PATH)
else:
print(f"Update failed: {result.stderr}. Restoring backup...")
restore_backup()

except Exception as e:
print(f"Update process failed: {e}. Rolling back...")
restore_backup()
Expand All @@ -102,10 +99,9 @@ def update_repository():


def main():
"""Check for updates and apply them safely."""
print("Checking for updates...")
latest_commit = get_latest_commit()
local_commit = get_latest_commit()
local_commit = get_local_commit()

if latest_commit and local_commit:
if latest_commit != local_commit:
Expand Down
81 changes: 81 additions & 0 deletions server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from fastapi import FastAPI, Query
from typing import List
import subprocess
import os
import shutil
from datetime import datetime

app = FastAPI()

# Configuration
LOCAL_REPO_BASE = r"" #it shoukd be the path to the folder where the node id(sensor) are stored
BRANCH = "main"
Comment on lines +11 to +12
Copy link

Copilot AI Apr 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in the comment: 'shoukd' should be corrected to 'should' to improve clarity.

Suggested change
LOCAL_REPO_BASE = r"" #it shoukd be the path to the folder where the node id(sensor) are stored
BRANCH = "main"
LOCAL_REPO_BASE = r"" #it should be the path to the folder where the node id(sensor) are stored

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +12
Copy link

Copilot AI Apr 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Correct the typo 'shoukd' to 'should' in the comment.

Suggested change
LOCAL_REPO_BASE = r"" #it shoukd be the path to the folder where the node id(sensor) are stored
BRANCH = "main"
LOCAL_REPO_BASE = r"" #it should be the path to the folder where the node id(sensor) are stored

Copilot uses AI. Check for mistakes.
LOG_FILE = os.path.join(LOCAL_REPO_BASE, "update_logs.txt")

@app.post("/update-node/")
async def update_node(node_id: str = Query(...)):
return await process_node_update(node_id)

@app.post("/update-multiple-nodes/")
async def update_multiple_nodes(node_ids: List[str] = Query(...)):
results = {}
for node_id in node_ids:
result = await process_node_update(node_id)
results[node_id] = result
return results

async def process_node_update(node_id):
repo_path = os.path.join(LOCAL_REPO_BASE, node_id)
backup_path = os.path.join(LOCAL_REPO_BASE, f"{node_id}_backup")

if not os.path.exists(repo_path):
log(f"ERROR: Node {node_id} does not exist.")
return {"error": f"Node {node_id} does not exist."}

try:
# Backup
if os.path.exists(backup_path):
shutil.rmtree(backup_path)
shutil.copytree(repo_path, backup_path)
print(f"Backup created for {node_id}.")
log(f"Backup created for {node_id}.")

# Git pull
result = subprocess.run(
["git", "pull", "origin", BRANCH],
cwd=repo_path,
capture_output=True,
text=True,
)

if result.returncode == 0:
print(f"Update successful for {node_id}.")
shutil.rmtree(backup_path) # Remove backup after success
log(f"SUCCESS: Updated {node_id}")
return {"message": f"Node {node_id} updated successfully."}
else:
print(f"Update failed for {node_id}: {result.stderr}")
rollback(repo_path, backup_path)
log(f"ERROR: Update failed for {node_id}. Rolled back.")
return {"error": f"Update failed for {node_id}. Rolled back."}

except Exception as e:
print(f"Exception during update for {node_id}: {e}")
rollback(repo_path, backup_path)
log(f"EXCEPTION: {e}")
return {"error": f"Exception during update for {node_id}. Rolled back."}

def rollback(repo_path, backup_path):
if os.path.exists(backup_path):
if os.path.exists(repo_path):
shutil.rmtree(repo_path)
shutil.copytree(backup_path, repo_path)
print("Rollback successful.")
log("Rollback successful.")
else:
print("No backup found to rollback.")
log("No backup found to rollback.")

def log(message):
with open(LOG_FILE, "a") as f:
f.write(f"[{datetime.now()}] {message}\n")
Loading