update utility

This commit is contained in:
KaySar12 2025-04-08 11:46:16 +07:00
parent f12b605180
commit e541836cfc
4 changed files with 193 additions and 123 deletions

View File

@ -30,26 +30,36 @@ def module(args):
f"No modules specified. Using default modules for {args.instance}",
)
args.modules = module_manager.get_modules(args.instance)
for module_name in tqdm.tqdm(
args.modules, desc="Processing modules", unit="module"
):
match args.action:
case "install":
module_manager.install(args.instance, [module_name])
case "uninstall":
module_manager.uninstall(args.instance, [module_name])
case "upgrade":
# Check if module is installed first
if not module_manager.is_module_installed(args.instance, module_name):
color_log.Show(
"INFO",
f"Module {module_name} not installed. Installing first...",
)
pbar = tqdm.tqdm(total=len(args.modules), desc="Processing modules", unit="module")
for module_name in args.modules:
try:
match args.action:
case "install":
pbar.set_description(f"Installing {module_name}")
module_manager.install(args.instance, [module_name])
# Now upgrade the module
module_manager.upgrade(args.instance, [module_name])
case _:
color_log.Show(
"FAILED",
f"Invalid action '{args.action}' for module management.",
)
case "uninstall":
pbar.set_description(f"Uninstalling {module_name}")
module_manager.uninstall(args.instance, [module_name])
case "upgrade":
# Check if module is installed first
if not module_manager.is_module_installed(args.instance, module_name):
pbar.set_description(f"Installing {module_name}")
module_manager.install(args.instance, [module_name])
pbar.set_description(f"Upgrading {module_name}")
module_manager.upgrade(args.instance, [module_name])
case _:
color_log.Show(
"FAILED",
f"Invalid action '{args.action}' for module management.",
)
return
pbar.update(1)
except Exception as e:
color_log.Show(
"FAILED",
f"Error processing module {module_name}: {str(e)}",
)
continue
pbar.close()

View File

@ -0,0 +1,154 @@
import importlib.util
import argparse
import os
import subprocess
import sys
import fcntl
import select
from ..services import config as Config
from ..lib import color_log
def set_nonblocking(fd):
"""Make a file descriptor non-blocking."""
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
def run_command(cmd, description):
"""Run a command and display output in real-time."""
try:
color_log.Show("INFO", f"Executing: {description}")
# Create process without output buffering
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0, # No buffering
universal_newlines=True
)
# Set both pipes to non-blocking mode
set_nonblocking(process.stdout.fileno())
set_nonblocking(process.stderr.fileno())
# Use select to read from pipes as data becomes available
while True:
reads = [process.stdout.fileno(), process.stderr.fileno()]
ret = select.select(reads, [], [])
for fd in ret[0]:
if fd == process.stdout.fileno():
line = process.stdout.readline()
if line:
print(line.rstrip())
if fd == process.stderr.fileno():
line = process.stderr.readline()
if line:
print(line.rstrip())
# Check if process has finished
if process.poll() is not None:
break
# Read any remaining output
stdout, stderr = process.communicate()
if stdout:
print(stdout.rstrip())
if stderr:
print(stderr.rstrip())
return process.returncode == 0
except Exception as e:
color_log.Show("FAILED", f"Error executing {description}: {str(e)}")
return False
def update_instance(instance_name, action, force_pull=False):
"""Update a single instance with git pull, module update, and service restart."""
color_log.Show("INFO", f"\n=== Starting update process for {instance_name} ===")
# 1. Pull latest code
color_log.Show("INFO", "Step 1/3: Pulling latest code...")
pull_cmd = ["python", "utility/main.py", "git", "pull", instance_name]
if force_pull:
pull_cmd.append("--force")
if not run_command(pull_cmd, f"Pulling latest code for {instance_name}"):
color_log.Show("WARNING", f"Skipping module update for {instance_name} due to pull failure")
return False
# 2. Update modules
color_log.Show("INFO", "Step 2/3: Updating modules...")
module_cmd = ["python", "utility/main.py", "module", action, instance_name]
if not run_command(module_cmd, f"Updating modules for {instance_name}"):
color_log.Show("WARNING", f"Module update failed for {instance_name}")
return False
# 3. Restart service
color_log.Show("INFO", "Step 3/3: Restarting service...")
restart_cmd = ["python", "utility/main.py", "service", "restart", instance_name]
if not run_command(restart_cmd, f"Restarting service for {instance_name}"):
color_log.Show("WARNING", f"Service restart failed for {instance_name}")
return False
color_log.Show("OK", f"=== Update process completed for {instance_name} ===\n")
return True
def main():
# Parse arguments
parser = argparse.ArgumentParser(description="Update modules for all instances")
parser.add_argument("instance", type=str, help="Instance Name")
parser.add_argument(
"action",
help="Action to perform",
choices=["uninstall", "install", "upgrade"]
)
parser.add_argument(
"config_path",
help="Path to the config file"
)
parser.add_argument(
"--force-pull",
action="store_true",
help="Force pull with hard reset (discards local changes)"
)
args = parser.parse_args()
# Load the configuration
color_log.Show("INFO", f"Loading configuration from {args.config_path}")
config = Config.Config(config_path=args.config_path)
if args.instance == "all":
# Get instances
instances = config.get_instances()
if not isinstance(instances, list):
color_log.Show("FAILED", "Error: instances is not a valid list.")
sys.exit(1)
# Process each instance
success_count = 0
for instance in instances:
if "name" not in instance:
color_log.Show("WARNING", f"Instance missing 'name' field. Skipping.")
continue
instance_name = instance["name"]
color_log.Show("INFO", f"\nProcessing instance: {instance_name}")
if update_instance(instance_name, args.action, args.force_pull):
success_count += 1
color_log.Show("OK", f"Successfully updated {instance_name}")
else:
color_log.Show("FAILED", f"Failed to update {instance_name}")
# Summary
color_log.Show("INFO", f"\nUpdate Summary:")
color_log.Show("INFO", f"Total instances: {len(instances)}")
color_log.Show("INFO", f"Successful updates: {success_count}")
color_log.Show("INFO", f"Failed updates: {len(instances) - success_count}")
else:
if update_instance(args.instance, args.action, args.force_pull):
color_log.Show("OK", f"Successfully updated {args.instance}")
else:
color_log.Show("FAILED", f"Failed to update {args.instance}")
if __name__ == "__main__":
main()

View File

@ -1,99 +0,0 @@
import importlib.util
import argparse
import os
import subprocess
import sys
from ..services import config as Config
from ..lib import color_log
def run_command(cmd, description):
"""Run a command and handle its output."""
try:
color_log.Show("INFO", f"Executing: {description}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.stdout:
print(result.stdout.strip())
if result.stderr:
print(result.stderr.strip())
return result.returncode == 0
except subprocess.CalledProcessError as e:
color_log.Show("FAILED", f"Error executing {description}: {str(e)}")
return False
def update_instance(instance_name, action, force_pull=False):
"""Update a single instance with git pull, module update, and service restart."""
# 1. Pull latest code
pull_cmd = ["python", "utility/main.py", "git", "pull", instance_name]
if force_pull:
pull_cmd.append("--force")
if not run_command(pull_cmd, f"Pulling latest code for {instance_name}"):
color_log.Show("WARNING", f"Skipping module update for {instance_name} due to pull failure")
return False
# 2. Update modules
module_cmd = ["python", "utility/main.py", "module", action, instance_name]
if not run_command(module_cmd, f"Updating modules for {instance_name}"):
color_log.Show("WARNING", f"Module update failed for {instance_name}")
return False
# 3. Restart service
restart_cmd = ["python", "utility/main.py", "service", "restart", instance_name]
if not run_command(restart_cmd, f"Restarting service for {instance_name}"):
color_log.Show("WARNING", f"Service restart failed for {instance_name}")
return False
return True
def main():
# Parse arguments
parser = argparse.ArgumentParser(description="Update modules for all instances")
parser.add_argument(
"action",
help="Action to perform",
choices=["uninstall", "install", "upgrade"]
)
parser.add_argument(
"config_path",
help="Path to the config file"
)
parser.add_argument(
"--force-pull",
action="store_true",
help="Force pull with hard reset (discards local changes)"
)
args = parser.parse_args()
# Load the configuration
color_log.Show("INFO", f"Loading configuration from {args.config_path}")
config = Config.Config(config_path=args.config_path)
# Get instances
instances = config.get_instances()
if not isinstance(instances, list):
color_log.Show("FAILED", "Error: instances is not a valid list.")
sys.exit(1)
# Process each instance
success_count = 0
for instance in instances:
if "name" not in instance:
color_log.Show("WARNING", f"Instance missing 'name' field. Skipping.")
continue
instance_name = instance["name"]
color_log.Show("INFO", f"\nProcessing instance: {instance_name}")
if update_instance(instance_name, args.action, args.force_pull):
success_count += 1
color_log.Show("OK", f"Successfully updated {instance_name}")
else:
color_log.Show("FAILED", f"Failed to update {instance_name}")
# Summary
color_log.Show("INFO", f"\nUpdate Summary:")
color_log.Show("INFO", f"Total instances: {len(instances)}")
color_log.Show("INFO", f"Successful updates: {success_count}")
color_log.Show("INFO", f"Failed updates: {len(instances) - success_count}")
if __name__ == "__main__":
main()

View File

@ -1,8 +1,13 @@
UTILITY_DIR =${PWD}/utility
SCRIPTS_DIR = ${UTILITY_DIR}/scripts
UTILITY_CONFIG = ${PWD}/utility/config/settings.yaml
update_modules_all:
${PYTHON} -m utility.scripts.update_modules upgrade ${UTILITY_CONFIG}
# Default values for update_modules
INSTANCE ?= all
ACTION ?= upgrade
update_modules:
${PYTHON} -m utility.scripts.modules_management ${INSTANCE} ${ACTION} ${UTILITY_CONFIG}
cleanup_addons:
@bash ${SCRIPT_PATH}/clean_up_addons.sh $(shell echo $(ADDONS) | tr ',' ' ')
gen_config: