Skip to content

Commit 3913d60

Browse files
raghavyuvazhravancoderabbitai[bot]
authored
feat: nixopus update (#401)
* feat: updating nixopus option * feat: add nixopus update cli for updating just the cli * Update cli/app/commands/update/run.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: shravan || श्रvan <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 4494bbb commit 3913d60

File tree

5 files changed

+197
-0
lines changed

5 files changed

+197
-0
lines changed

cli/app/commands/update/__init__.py

Whitespace-only changes.

cli/app/commands/update/command.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from app.commands.update.run import Update
2+
from app.utils.logger import Logger
3+
import typer
4+
5+
update_app = typer.Typer(help="Update Nixopus", invoke_without_command=True)
6+
7+
8+
@update_app.callback()
9+
def update_callback(
10+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show more details while updating"),
11+
):
12+
"""Update Nixopus"""
13+
logger = Logger(verbose=verbose)
14+
update = Update(logger=logger)
15+
update.run()
16+
17+
18+
@update_app.command()
19+
def cli(
20+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show more details while updating"),
21+
):
22+
"""Update CLI tool"""
23+
logger = Logger(verbose=verbose)
24+
update = Update(logger=logger)
25+
update.update_cli()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
updating_nixopus = "Updating Nixopus..."
2+
pulling_latest_images = "Pulling latest images..."
3+
images_pulled_successfully = "Images pulled successfully"
4+
failed_to_pull_images = "Failed to pull images: {error}"
5+
starting_services = "Starting services..."
6+
failed_to_start_services = "Failed to start services: {error}"
7+
nixopus_updated_successfully = "Nixopus updated successfully"

cli/app/commands/update/run.py

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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)

cli/app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from app.commands.service.command import service_app
1717
from app.commands.test.command import test_app
1818
from app.commands.uninstall.command import uninstall_app
19+
from app.commands.update.command import update_app
1920
from app.commands.version.command import main_version_callback, version_app
2021
from app.commands.version.version import VersionCommand
2122
from app.utils.config import Config
@@ -99,6 +100,7 @@ def main(
99100
app.add_typer(proxy_app, name="proxy")
100101
app.add_typer(install_app, name="install")
101102
app.add_typer(uninstall_app, name="uninstall")
103+
app.add_typer(update_app, name="update")
102104
app.add_typer(version_app, name="version")
103105

104106
config = Config()

0 commit comments

Comments
 (0)