Skip to content

Commit dda2965

Browse files
authored
refactor(utils): decompose lib.py into focused utility modules (#634)
1 parent c5edbb2 commit dda2965

File tree

12 files changed

+328
-282
lines changed

12 files changed

+328
-282
lines changed

cli/app/commands/clone/clone.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import subprocess
33
from typing import Optional
44

5-
from app.utils.lib import DirectoryManager
5+
from app.utils.directory_manager import path_exists_and_not_force, remove_directory
66
from app.utils.protocols import LoggerProtocol
77

88
from .messages import (
@@ -60,10 +60,12 @@ def _build_clone_command(repo: str, path: str, branch: Optional[str] = None) ->
6060
return cmd
6161

6262

63-
def _execute_git_clone(repo: str, path: str, branch: Optional[str], logger: Optional[LoggerProtocol] = None) -> tuple[bool, Optional[str]]:
63+
def _execute_git_clone(
64+
repo: str, path: str, branch: Optional[str], logger: Optional[LoggerProtocol] = None
65+
) -> tuple[bool, Optional[str]]:
6466
"""Execute git clone command."""
6567
cmd = _build_clone_command(repo, path, branch)
66-
68+
6769
if logger:
6870
logger.debug(debug_executing_git_clone.format(command=" ".join(cmd)))
6971

@@ -89,8 +91,7 @@ def _prepare_target_directory(path: str, force: bool, logger: Optional[LoggerPro
8991
if force and os.path.exists(path):
9092
if logger:
9193
logger.debug(debug_removing_directory.format(path=path))
92-
dir_manager = DirectoryManager()
93-
success = dir_manager.remove_directory(path, logger)
94+
success = remove_directory(path, logger)
9495
if not success and logger:
9596
logger.debug(debug_directory_removal_failed)
9697
return success
@@ -99,8 +100,7 @@ def _prepare_target_directory(path: str, force: bool, logger: Optional[LoggerPro
99100

100101
def _validate_prerequisites(path: str, force: bool, logger: Optional[LoggerProtocol] = None) -> bool:
101102
"""Validate prerequisites for cloning."""
102-
dir_manager = DirectoryManager()
103-
if dir_manager.path_exists_and_not_force(path, force):
103+
if path_exists_and_not_force(path, force):
104104
if logger:
105105
logger.debug(debug_path_exists_force_disabled.format(path=path))
106106
logger.error(path_already_exists_use_force.format(path=path))
@@ -117,25 +117,25 @@ def clone_repository(
117117
) -> tuple[bool, Optional[str]]:
118118
"""Clone a git repository."""
119119
import time
120-
120+
121121
start_time = time.time()
122-
122+
123123
repo = _validate_repo(repo)
124124
path = _validate_path(path)
125-
125+
126126
if logger:
127127
logger.debug(debug_cloning_repo.format(repo=repo, path=path, force=force))
128-
128+
129129
if not _validate_prerequisites(path, force, logger):
130130
return False, prerequisites_validation_failed
131-
131+
132132
if not _prepare_target_directory(path, force, logger):
133133
return False, failed_to_prepare_target_directory
134-
134+
135135
success, error = _execute_git_clone(repo, path, branch, logger)
136-
136+
137137
duration = time.time() - start_time
138138
if logger:
139139
logger.debug(debug_clone_completed.format(duration=f"{duration:.2f}", success=success))
140-
140+
141141
return success, error

cli/app/commands/install/deps.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import subprocess
44

55
from app.utils.config import DEPS, Config
6-
from app.utils.lib import HostInformation, ParallelProcessor
6+
from app.utils.host_information import get_os_name, get_package_manager
7+
from app.utils.parallel_processor import process_parallel
78
from app.utils.logger import create_logger
89

910
from .messages import (
@@ -122,8 +123,8 @@ def check_dependency(self, dep, package_manager):
122123
def install_all_deps(verbose=False, output="text", dry_run=False):
123124
logger = create_logger(verbose=verbose)
124125
deps = get_deps_from_config()
125-
os_name = HostInformation.get_os_name()
126-
package_manager = HostInformation.get_package_manager()
126+
os_name = get_os_name()
127+
package_manager = get_package_manager()
127128
if not package_manager:
128129
raise Exception(no_supported_package_manager)
129130
installed = get_installed_deps(deps, os_name, package_manager, verbose=verbose)
@@ -138,7 +139,7 @@ def error_handler(dep, exc):
138139
logger.error(f"Failed to install {dep['name']}: {exc}")
139140
return {"dependency": dep["name"], "installed": False}
140141

141-
results = ParallelProcessor.process_items(
142+
results = process_parallel(
142143
to_install,
143144
install_wrapper,
144145
max_workers=min(len(to_install), 8),

cli/app/commands/install/development.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
VIEW_ENV_FILE,
3030
VIEW_PORT,
3131
)
32-
from app.utils.lib import FileManager, HostInformation
32+
from app.utils.directory_manager import create_directory
33+
from app.utils.file_manager import get_directory_path, set_permissions
34+
from app.utils.host_information import get_os_name, get_package_manager
3335
from app.utils.protocols import LoggerProtocol
3436
from app.utils.timeout import TimeoutWrapper
3537

@@ -323,8 +325,8 @@ def _run_preflight_checks(self):
323325
def _check_and_install_dependencies(self):
324326
"""Check dependencies and install only if missing"""
325327
deps = get_deps_from_config()
326-
os_name = HostInformation.get_os_name()
327-
package_manager = HostInformation.get_package_manager()
328+
os_name = get_os_name()
329+
package_manager = get_package_manager()
328330

329331
if not package_manager:
330332
raise Exception("No supported package manager found")
@@ -383,13 +385,13 @@ def _create_env_files(self):
383385
self.logger.info(f" - View: {view_env_file}")
384386
return
385387

386-
FileManager.create_directory(FileManager.get_directory_path(api_env_file), logger=self.logger)
387-
FileManager.create_directory(FileManager.get_directory_path(view_env_file), logger=self.logger)
388+
create_directory(get_directory_path(api_env_file), logger=self.logger)
389+
create_directory(get_directory_path(view_env_file), logger=self.logger)
388390

389391
# Get combined env file path
390392
full_source_path = self._get_config("full_source_path")
391393
combined_env_file = os.path.join(full_source_path, ".env")
392-
FileManager.create_directory(FileManager.get_directory_path(combined_env_file), logger=self.logger)
394+
create_directory(get_directory_path(combined_env_file), logger=self.logger)
393395

394396
services = [
395397
("api", "services.api.env", api_env_file),
@@ -403,7 +405,7 @@ def _create_env_files(self):
403405
success, error = write_env_file(env_file, updated_env_values, self.logger)
404406
if not success:
405407
raise Exception(f"{env_file_creation_failed} {service_name}: {error}")
406-
file_perm_success, file_perm_error = FileManager.set_permissions(env_file, 0o644)
408+
file_perm_success, file_perm_error = set_permissions(env_file, 0o644)
407409
if not file_perm_success:
408410
raise Exception(f"{env_file_permissions_failed} {service_name}: {file_perm_error}")
409411
self.logger.debug(created_env_file.format(service_name=service_name, env_file=env_file))
@@ -420,7 +422,7 @@ def _create_env_files(self):
420422
if not success:
421423
raise Exception(f"{env_file_creation_failed} combined: {error}")
422424

423-
file_perm_success, file_perm_error = FileManager.set_permissions(combined_env_file, 0o644)
425+
file_perm_success, file_perm_error = set_permissions(combined_env_file, 0o644)
424426
if not file_perm_success:
425427
raise Exception(f"{env_file_permissions_failed} combined: {file_perm_error}")
426428

@@ -559,6 +561,12 @@ def _load_proxy(self):
559561

560562
def _start_all_services(self):
561563
"""Start all services (API, View, DB, Redis, Caddy) using Docker Compose"""
564+
compose_file = self._get_config("compose_file_path")
565+
566+
if self.dry_run:
567+
self.logger.info(f"[DRY RUN] Would start services using {compose_file}")
568+
return
569+
562570
env_vars = {}
563571
if self.api_port is not None:
564572
env_vars["API_PORT"] = str(self.api_port)
@@ -588,7 +596,7 @@ def _start_all_services(self):
588596
name=self._get_config("service_name"),
589597
detach=self._get_config("service_detach"),
590598
env_file=None,
591-
compose_file=self._get_config("compose_file_path"),
599+
compose_file=compose_file,
592600
logger=self.logger,
593601
)
594602
except TimeoutError:

cli/app/commands/install/run.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
VIEW_PORT,
3939
Config,
4040
)
41-
from app.utils.lib import FileManager, HostInformation
41+
from app.utils.directory_manager import create_directory
42+
from app.utils.file_manager import get_directory_path, set_permissions
43+
from app.utils.host_information import get_public_ip
4244
from app.utils.protocols import LoggerProtocol
4345
from app.utils.timeout import TimeoutWrapper
4446

@@ -207,7 +209,7 @@ def _is_custom_repo_or_branch(self):
207209
def _get_host_ip(self) -> str:
208210
if self.host_ip:
209211
return self.host_ip
210-
return HostInformation.get_public_ip()
212+
return get_public_ip()
211213

212214
def run(self):
213215
steps = [
@@ -334,9 +336,9 @@ def _create_env_files(self):
334336

335337
full_source_path = self._get_config("full_source_path")
336338
combined_env_file = os.path.join(full_source_path, ".env")
337-
FileManager.create_directory(FileManager.get_directory_path(api_env_file), logger=self.logger)
338-
FileManager.create_directory(FileManager.get_directory_path(view_env_file), logger=self.logger)
339-
FileManager.create_directory(FileManager.get_directory_path(combined_env_file), logger=self.logger)
339+
create_directory(get_directory_path(api_env_file), logger=self.logger)
340+
create_directory(get_directory_path(view_env_file), logger=self.logger)
341+
create_directory(get_directory_path(combined_env_file), logger=self.logger)
340342

341343
services = [
342344
("api", "services.api.env", api_env_file),
@@ -348,7 +350,7 @@ def _create_env_files(self):
348350
success, error = write_env_file(env_file, updated_env_values, self.logger)
349351
if not success:
350352
raise Exception(f"{env_file_creation_failed} {service_name}: {error}")
351-
file_perm_success, file_perm_error = FileManager.set_permissions(env_file, 0o644)
353+
file_perm_success, file_perm_error = set_permissions(env_file, 0o644)
352354
if not file_perm_success:
353355
raise Exception(f"{env_file_permissions_failed} {service_name}: {file_perm_error}")
354356
self.logger.debug(created_env_file.format(service_name=service_name, env_file=env_file))
@@ -364,7 +366,7 @@ def _create_env_files(self):
364366

365367
if not success:
366368
raise Exception(f"{env_file_creation_failed} combined: {error}")
367-
file_perm_success, file_perm_error = FileManager.set_permissions(combined_env_file, 0o644)
369+
file_perm_success, file_perm_error = set_permissions(combined_env_file, 0o644)
368370
if not file_perm_success:
369371
raise Exception(f"{env_file_permissions_failed} combined: {file_perm_error}")
370372
self.logger.debug(created_env_file.format(service_name="combined", env_file=combined_env_file))
@@ -423,6 +425,12 @@ def _setup_ssh(self):
423425
raise Exception(ssh_setup_failed)
424426

425427
def _start_services(self):
428+
compose_file = self._get_config("compose_file_path")
429+
430+
if self.dry_run:
431+
self.logger.info(f"[DRY RUN] Would start services using {compose_file}")
432+
return
433+
426434
env_vars = {}
427435
if self.api_port is not None:
428436
env_vars["API_PORT"] = str(self.api_port)
@@ -452,7 +460,7 @@ def _start_services(self):
452460
name="all",
453461
detach=True,
454462
env_file=None,
455-
compose_file=self._get_config("compose_file_path"),
463+
compose_file=compose_file,
456464
logger=self.logger,
457465
)
458466
except TimeoutError:
@@ -561,10 +569,10 @@ def _copy_caddyfile_to_target(self, full_source_path: str):
561569
source_caddyfile = os.path.join(full_source_path, "helpers", "Caddyfile")
562570
target_dir = _config.get(CADDY_CONFIG_VOLUME)
563571
target_caddyfile = os.path.join(target_dir, "Caddyfile")
564-
FileManager.create_directory(target_dir, logger=self.logger)
572+
create_directory(target_dir, logger=self.logger)
565573
if os.path.exists(source_caddyfile):
566574
shutil.copy2(source_caddyfile, target_caddyfile)
567-
FileManager.set_permissions(target_caddyfile, 0o644, logger=self.logger)
575+
set_permissions(target_caddyfile, 0o644, logger=self.logger)
568576
self.logger.debug(f"Copied Caddyfile from {source_caddyfile} to {target_caddyfile}")
569577
else:
570578
self.logger.warning(f"Source Caddyfile not found at {source_caddyfile}")

cli/app/commands/install/ssh.py

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@
55

66
from pydantic import BaseModel, Field, field_validator
77

8-
from app.utils.lib import FileManager
8+
from app.utils.directory_manager import create_directory
9+
from app.utils.file_manager import (
10+
append_to_file,
11+
expand_user_path,
12+
get_directory_path,
13+
get_public_key_path,
14+
read_file_content,
15+
set_permissions,
16+
)
917
from app.utils.logger import create_logger
1018
from app.utils.output_formatter import OutputFormatter
1119
from app.utils.protocols import LoggerProtocol
@@ -140,7 +148,6 @@ def format_dry_run(self, config: "SSHConfig") -> str:
140148

141149
class SSHKeyManager:
142150
def __init__(self, logger: LoggerProtocol):
143-
self.file_manager = FileManager()
144151
self.logger = logger
145152

146153
def _check_ssh_keygen_availability(self) -> tuple[bool, str]:
@@ -201,15 +208,15 @@ def set_key_permissions(self, private_key_path: str, public_key_path: str) -> tu
201208
self.logger.debug(debug_ssh_permission_setting.format(private_key=private_key_path, public_key=public_key_path))
202209
try:
203210
self.logger.debug(debug_ssh_private_key_permissions.format(path=private_key_path))
204-
private_success, private_error = self.file_manager.set_permissions(
211+
private_success, private_error = set_permissions(
205212
private_key_path, stat.S_IRUSR | stat.S_IWUSR, self.logger
206213
)
207214
if not private_success:
208215
self.logger.debug(debug_ssh_private_key_permissions_failed.format(error=private_error))
209216
return False, private_error
210217

211218
self.logger.debug(debug_ssh_public_key_permissions.format(path=public_key_path))
212-
public_success, public_error = self.file_manager.set_permissions(
219+
public_success, public_error = set_permissions(
213220
public_key_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH, self.logger
214221
)
215222
if not public_success:
@@ -227,7 +234,7 @@ def create_ssh_directory(self, ssh_dir: str) -> tuple[bool, str]:
227234
self.logger.debug(debug_ssh_directory_creation.format(directory=ssh_dir, permissions=oct(permissions)))
228235
try:
229236
self.logger.debug(debug_ssh_directory_check.format(directory=ssh_dir))
230-
success, error = self.file_manager.create_directory(ssh_dir, permissions, self.logger)
237+
success, error = create_directory(ssh_dir, permissions, self.logger)
231238
if success:
232239
self.logger.debug(debug_ssh_directory_created.format(directory=ssh_dir))
233240
else:
@@ -242,12 +249,12 @@ def add_to_authorized_keys(self, public_key_path: str) -> tuple[bool, str]:
242249
self.logger.debug(adding_to_authorized_keys)
243250
self.logger.debug(debug_ssh_authorized_keys_read.format(path=public_key_path))
244251

245-
success, content, error = self.file_manager.read_file_content(public_key_path, self.logger)
252+
success, content, error = read_file_content(public_key_path, self.logger)
246253
if not success:
247254
self.logger.debug(debug_ssh_public_key_read_failed.format(error=error))
248255
return False, error or failed_to_read_public_key
249256

250-
ssh_dir = self.file_manager.expand_user_path("~/.ssh")
257+
ssh_dir = expand_user_path("~/.ssh")
251258
authorized_keys_path = os.path.join(ssh_dir, "authorized_keys")
252259
self.logger.debug(debug_ssh_authorized_keys_path.format(path=authorized_keys_path))
253260

@@ -269,7 +276,7 @@ def add_to_authorized_keys(self, public_key_path: str) -> tuple[bool, str]:
269276
return False, f"Failed to create authorized_keys file: {e}"
270277

271278
self.logger.debug(debug_ssh_authorized_keys_append.format(path=authorized_keys_path))
272-
success, error = self.file_manager.append_to_file(authorized_keys_path, content, self.logger)
279+
success, error = append_to_file(authorized_keys_path, content, logger=self.logger)
273280
if not success:
274281
self.logger.debug(debug_ssh_authorized_keys_append_failed.format(error=error))
275282
return False, error or failed_to_append_to_authorized_keys
@@ -374,7 +381,6 @@ def __init__(self, config: SSHConfig, logger: LoggerProtocol = None, ssh_manager
374381
self.config = config
375382
self.ssh_manager = ssh_manager or SSHKeyManager(self.logger)
376383
self.formatter = SSHFormatter()
377-
self.file_manager = FileManager()
378384

379385
def _validate_prerequisites(self) -> bool:
380386
self.logger.debug(
@@ -383,7 +389,7 @@ def _validate_prerequisites(self) -> bool:
383389
)
384390
)
385391

386-
expanded_key_path = self.file_manager.expand_user_path(self.config.path)
392+
expanded_key_path = expand_user_path(self.config.path)
387393
self.logger.debug(debug_ssh_path_expansion.format(original=self.config.path, expanded=expanded_key_path))
388394

389395
if os.path.exists(expanded_key_path):
@@ -428,8 +434,8 @@ def generate_ssh_key(self) -> SSHResult:
428434
dry_run_output = self.formatter.format_dry_run(self.config)
429435
return self._create_result(True, dry_run_output)
430436

431-
expanded_path = self.file_manager.expand_user_path(self.config.path)
432-
ssh_dir = self.file_manager.get_directory_path(expanded_path)
437+
expanded_path = expand_user_path(self.config.path)
438+
ssh_dir = get_directory_path(expanded_path)
433439
self.logger.debug(debug_ssh_key_directory_info.format(directory=ssh_dir))
434440

435441
if self.config.create_ssh_directory:
@@ -449,7 +455,7 @@ def generate_ssh_key(self) -> SSHResult:
449455

450456
if self.config.set_permissions:
451457
self.logger.debug(debug_ssh_permissions_enabled)
452-
public_key_path = self.file_manager.get_public_key_path(expanded_path)
458+
public_key_path = get_public_key_path(expanded_path)
453459
self.logger.debug(debug_ssh_public_key_path_info.format(path=public_key_path))
454460
success, error = self.ssh_manager.set_key_permissions(expanded_path, public_key_path)
455461
if not success:
@@ -458,7 +464,7 @@ def generate_ssh_key(self) -> SSHResult:
458464

459465
if self.config.add_to_authorized_keys:
460466
self.logger.debug(debug_ssh_authorized_keys_enabled)
461-
public_key_path = self.file_manager.get_public_key_path(expanded_path)
467+
public_key_path = get_public_key_path(expanded_path)
462468
success, error = self.ssh_manager.add_to_authorized_keys(public_key_path)
463469
if not success:
464470
self.logger.debug(debug_ssh_authorized_keys_failed_abort.format(error=error))

0 commit comments

Comments
 (0)