|
| 1 | +import platform |
| 2 | +import subprocess |
| 3 | + |
| 4 | +from app.commands.service.base import BaseDockerCommandBuilder, BaseDockerService |
| 5 | +from app.utils.logger import Logger |
| 6 | +from app.utils.config import Config, DEFAULT_COMPOSE_FILE |
| 7 | +from app.utils.config import NIXOPUS_CONFIG_DIR |
| 8 | +from .messages import ( |
| 9 | + updating_nixopus, |
| 10 | + pulling_latest_images, |
| 11 | + images_pulled_successfully, |
| 12 | + failed_to_pull_images, |
| 13 | + starting_services, |
| 14 | + failed_to_start_services, |
| 15 | + nixopus_updated_successfully, |
| 16 | +) |
| 17 | + |
| 18 | +# TODO: Add support for staging or forked repository update is not availlable yet |
| 19 | + |
| 20 | +PACKAGE_JSON_URL = "https://raw.githubusercontent.com/raghavyuva/nixopus/master/package.json" |
| 21 | +RELEASES_BASE_URL = "https://github.com/raghavyuva/nixopus/releases/download" |
| 22 | + |
| 23 | +class Update: |
| 24 | + def __init__(self, logger: Logger): |
| 25 | + self.logger = logger |
| 26 | + self.config = Config() |
| 27 | + |
| 28 | + def run(self): |
| 29 | + compose_file = self.config.get_yaml_value(DEFAULT_COMPOSE_FILE) |
| 30 | + compose_file_path = self.config.get_yaml_value(NIXOPUS_CONFIG_DIR) + "/" + compose_file |
| 31 | + env_file_path = self.config.get_yaml_value(NIXOPUS_CONFIG_DIR) + "/.env" |
| 32 | + self.logger.info(updating_nixopus) |
| 33 | + |
| 34 | + docker_service = BaseDockerService(self.logger, "pull") |
| 35 | + |
| 36 | + self.logger.debug(pulling_latest_images) |
| 37 | + success, output = docker_service.execute_services(compose_file=compose_file_path, env_file=env_file_path) |
| 38 | + |
| 39 | + if not success: |
| 40 | + self.logger.error(failed_to_pull_images.format(error=output)) |
| 41 | + return |
| 42 | + |
| 43 | + self.logger.debug(images_pulled_successfully) |
| 44 | + |
| 45 | + docker_service_up = BaseDockerService(self.logger, "up") |
| 46 | + self.logger.debug(starting_services) |
| 47 | + success, output = docker_service_up.execute_services(compose_file=compose_file_path, env_file=env_file_path, detach=True) |
| 48 | + |
| 49 | + if not success: |
| 50 | + self.logger.error(failed_to_start_services.format(error=output)) |
| 51 | + return |
| 52 | + |
| 53 | + self.logger.info(nixopus_updated_successfully) |
| 54 | + |
| 55 | + def update_cli(self): |
| 56 | + self.logger.info("Updating CLI tool...") |
| 57 | + try: |
| 58 | + import platform |
| 59 | + import urllib.request |
| 60 | + import json |
| 61 | + import tempfile |
| 62 | + import os |
| 63 | + |
| 64 | + arch = self._detect_arch() |
| 65 | + pkg_type = self._detect_os() |
| 66 | + |
| 67 | + with urllib.request.urlopen(PACKAGE_JSON_URL) as response: |
| 68 | + package_json = json.loads(response.read().decode()) |
| 69 | + |
| 70 | + cli_version = package_json.get("cli-version") |
| 71 | + if not cli_version: |
| 72 | + self.logger.error("Could not find cli-version in package.json") |
| 73 | + return |
| 74 | + |
| 75 | + cli_packages = package_json.get("cli-packages", []) |
| 76 | + package_name = self._build_package_name(cli_version, arch, pkg_type) |
| 77 | + |
| 78 | + if package_name not in cli_packages: |
| 79 | + self.logger.error(f"Package {package_name} not found in available packages") |
| 80 | + return |
| 81 | + |
| 82 | + download_url = f"{RELEASES_BASE_URL}/nixopus-{cli_version}/{package_name}" |
| 83 | + |
| 84 | + with tempfile.NamedTemporaryFile(delete=False) as temp_file: |
| 85 | + urllib.request.urlretrieve(download_url, temp_file.name) |
| 86 | + |
| 87 | + if pkg_type == "tar": |
| 88 | + self._install_tar_package(temp_file.name) |
| 89 | + else: |
| 90 | + self._install_system_package(temp_file.name, pkg_type) |
| 91 | + |
| 92 | + os.unlink(temp_file.name) |
| 93 | + |
| 94 | + self.logger.info("CLI tool updated successfully") |
| 95 | + |
| 96 | + except Exception as e: |
| 97 | + self.logger.error(f"Failed to update CLI tool: {str(e)}") |
| 98 | + |
| 99 | + def _detect_arch(self): |
| 100 | + arch = platform.machine().lower() |
| 101 | + if arch in ["x86_64", "amd64"]: |
| 102 | + return "amd64" |
| 103 | + elif arch in ["aarch64", "arm64"]: |
| 104 | + return "arm64" |
| 105 | + else: |
| 106 | + raise Exception(f"Unsupported architecture: {arch}") |
| 107 | + |
| 108 | + def _detect_os(self): |
| 109 | + system = platform.system().lower() |
| 110 | + if system == "darwin": |
| 111 | + return "tar" |
| 112 | + elif system == "linux": |
| 113 | + try: |
| 114 | + subprocess.run(["apt", "--version"], capture_output=True, check=True) |
| 115 | + return "deb" |
| 116 | + except: |
| 117 | + try: |
| 118 | + subprocess.run(["yum", "--version"], capture_output=True, check=True) |
| 119 | + return "rpm" |
| 120 | + except: |
| 121 | + try: |
| 122 | + subprocess.run(["apk", "--version"], capture_output=True, check=True) |
| 123 | + return "apk" |
| 124 | + except: |
| 125 | + return "tar" |
| 126 | + else: |
| 127 | + return "tar" |
| 128 | + |
| 129 | + def _build_package_name(self, version, arch, pkg_type): |
| 130 | + if pkg_type == "deb": |
| 131 | + return f"nixopus_{version}_{arch}.deb" |
| 132 | + elif pkg_type == "rpm": |
| 133 | + arch_name = "x86_64" if arch == "amd64" else "aarch64" |
| 134 | + return f"nixopus-{version}-1.{arch_name}.rpm" |
| 135 | + elif pkg_type == "apk": |
| 136 | + return f"nixopus_{version}_{arch}.apk" |
| 137 | + elif pkg_type == "tar": |
| 138 | + return f"nixopus-{version}.tar" |
| 139 | + else: |
| 140 | + raise Exception(f"Unknown package type: {pkg_type}") |
| 141 | + |
| 142 | + def _install_tar_package(self, package_path): |
| 143 | + subprocess.run(["tar", "-xf", package_path, "-C", "/tmp"], check=True) |
| 144 | + |
| 145 | + try: |
| 146 | + subprocess.run(["cp", "/tmp/usr/local/bin/nixopus", "/usr/local/bin/"], check=True) |
| 147 | + subprocess.run(["chmod", "+x", "/usr/local/bin/nixopus"], check=True) |
| 148 | + except subprocess.CalledProcessError: |
| 149 | + subprocess.run(["sudo", "mkdir", "-p", "/usr/local/bin"], check=True) |
| 150 | + subprocess.run(["sudo", "cp", "/tmp/usr/local/bin/nixopus", "/usr/local/bin/"], check=True) |
| 151 | + subprocess.run(["sudo", "chmod", "+x", "/usr/local/bin/nixopus"], check=True) |
| 152 | + |
| 153 | + def _install_system_package(self, package_path, pkg_type): |
| 154 | + if pkg_type == "deb": |
| 155 | + subprocess.run(["sudo", "dpkg", "-i", package_path], check=True) |
| 156 | + subprocess.run(["sudo", "apt-get", "install", "-f", "-y"], check=True) |
| 157 | + elif pkg_type == "rpm": |
| 158 | + try: |
| 159 | + subprocess.run(["sudo", "dnf", "install", "-y", package_path], check=True) |
| 160 | + except subprocess.CalledProcessError: |
| 161 | + subprocess.run(["sudo", "yum", "install", "-y", package_path], check=True) |
| 162 | + elif pkg_type == "apk": |
| 163 | + subprocess.run(["sudo", "apk", "add", "--allow-untrusted", package_path], check=True) |
0 commit comments