Skip to content

fix : command structure and wip install command #291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
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
51 changes: 37 additions & 14 deletions cli/app/commands/clone/clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,16 @@
from app.utils.output_formatter import OutputFormatter
from app.utils.protocols import LoggerProtocol

from ..install.messages import (
cloning_repo_into_path,
from .messages import (
debug_cloning_repo,
debug_executing_git_clone,
debug_git_clone_success,
debug_git_clone_failed,
debug_unexpected_error,
debug_removing_directory,
debug_directory_removal_failed,
debug_path_exists_force_disabled,
debug_clone_completed,
default_branch,
dry_run_branch,
dry_run_command,
Expand All @@ -20,9 +28,7 @@
dry_run_repository,
dry_run_target_path,
end_dry_run,
executing_command,
failed_to_prepare_target_directory,
git_clone_failed,
invalid_path,
invalid_repo,
invalid_repository_url,
Expand All @@ -32,7 +38,6 @@
prerequisites_validation_failed,
successfully_cloned,
target_path_not_exists,
unexpected_error_during_clone,
unknown_error,
)

Expand Down Expand Up @@ -98,17 +103,18 @@ def __init__(self, logger: LoggerProtocol):

def clone_repository(self, repo: str, path: str, branch: str = None) -> tuple[bool, str]:
cmd = GitCommandBuilder.build_clone_command(repo, path, branch)

self.logger.debug(debug_executing_git_clone.format(command=' '.join(cmd)))

try:
self.logger.info(executing_command.format(command=" ".join(cmd)))
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
self.logger.success(successfully_cloned.format(repo=repo, path=path))
self.logger.debug(debug_git_clone_success)
return True, None
except subprocess.CalledProcessError as e:
self.logger.error(git_clone_failed.format(error=e.stderr))
self.logger.debug(debug_git_clone_failed.format(code=e.returncode, error=e.stderr))
return False, e.stderr
except Exception as e:
self.logger.error(unexpected_error_during_clone.format(error=e))
self.logger.debug(debug_unexpected_error.format(error_type=type(e).__name__, error=str(e)))
return False, str(e)


Expand All @@ -118,7 +124,7 @@ class CloneResult(BaseModel):
branch: Optional[str]
force: bool
verbose: bool
output: str
output: str = ""
success: bool = False
error: Optional[str] = None

Expand Down Expand Up @@ -180,17 +186,22 @@ def __init__(self, config: CloneConfig, logger: LoggerProtocol = None, cloner: G

def _prepare_target_directory(self) -> bool:
if self.config.force and os.path.exists(self.config.path):
return self.dir_manager.remove_directory(self.config.path, self.logger)
self.logger.debug(debug_removing_directory.format(path=self.config.path))
success = self.dir_manager.remove_directory(self.config.path, self.logger)
if not success:
self.logger.debug(debug_directory_removal_failed)
return success
return True

def _validate_prerequisites(self) -> bool:
if self.dir_manager.path_exists_and_not_force(self.config.path, self.config.force):
self.logger.debug(debug_path_exists_force_disabled.format(path=self.config.path))
self.logger.error(path_already_exists_use_force.format(path=self.config.path))
return False
return True

def _create_result(self, success: bool, error: str = None) -> CloneResult:
return CloneResult(
result = CloneResult(
repo=self.config.repo,
path=self.config.path,
branch=self.config.branch,
Expand All @@ -200,9 +211,14 @@ def _create_result(self, success: bool, error: str = None) -> CloneResult:
success=success,
error=error,
)
result.output = self.formatter.format_output(result, self.config.output)
return result

def clone(self) -> CloneResult:
self.logger.debug(cloning_repo_into_path.format(repo=self.config.repo, path=self.config.path))
import time
start_time = time.time()

self.logger.debug(debug_cloning_repo.format(repo=self.config.repo, path=self.config.path, force=self.config.force))

if not self._validate_prerequisites():
return self._create_result(False, prerequisites_validation_failed)
Expand All @@ -211,6 +227,9 @@ def clone(self) -> CloneResult:
return self._create_result(False, failed_to_prepare_target_directory)

success, error = self.cloner.clone_repository(self.config.repo, self.config.path, self.config.branch)

duration = time.time() - start_time
self.logger.debug(debug_clone_completed.format(duration=f"{duration:.2f}", success=success))

return self._create_result(success, error)

Expand All @@ -219,7 +238,7 @@ def clone_and_format(self) -> str:
return self.formatter.format_dry_run(self.config)

result = self.clone()
return self.formatter.format_output(result, self.config.output)
return result.output


class Clone:
Expand All @@ -231,5 +250,9 @@ def clone(self, config: CloneConfig) -> CloneResult:
service = CloneService(config, logger=self.logger)
return service.clone()

def clone_and_format(self, config: CloneConfig) -> str:
service = CloneService(config, logger=self.logger)
return service.clone_and_format()

def format_output(self, result: CloneResult, output: str) -> str:
return self.formatter.format_output(result, output)
57 changes: 54 additions & 3 deletions cli/app/commands/clone/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,26 @@

from app.utils.logger import Logger
from app.utils.config import Config, DEFAULT_REPO, DEFAULT_BRANCH, DEFAULT_PATH, NIXOPUS_CONFIG_DIR
from app.utils.timeout import TimeoutWrapper

from .clone import Clone, CloneConfig
from .messages import (
debug_clone_command_invoked,
debug_repo_param,
debug_branch_param,
debug_path_param,
debug_force_param,
debug_verbose_param,
debug_output_param,
debug_dry_run_param,
debug_executing_dry_run,
debug_dry_run_completed,
debug_clone_operation_result,
debug_clone_operation_failed,
debug_clone_operation_completed,
debug_exception_caught,
debug_exception_details,
)

config = Config()
nixopus_config_dir = config.get_yaml_value(NIXOPUS_CONFIG_DIR)
Expand All @@ -22,14 +40,47 @@ def clone_callback(
verbose: bool = typer.Option(False, "--verbose", "-v", help="Verbose output"),
output: str = typer.Option("text", "--output", "-o", help="Output format, text, json"),
dry_run: bool = typer.Option(False, "--dry-run", "-d", help="Dry run"),
timeout: int = typer.Option(10, "--timeout", "-t", help="Timeout in seconds"),
):
"""Clone a repository"""
try:
logger = Logger(verbose=verbose)
logger.debug(debug_clone_command_invoked)
logger.debug(debug_repo_param.format(repo=repo))
logger.debug(debug_branch_param.format(branch=branch))
logger.debug(debug_path_param.format(path=path))
logger.debug(debug_force_param.format(force=force))
logger.debug(debug_verbose_param.format(verbose=verbose))
logger.debug(debug_output_param.format(output=output))
logger.debug(debug_dry_run_param.format(dry_run=dry_run))

config = CloneConfig(repo=repo, branch=branch, path=path, force=force, verbose=verbose, output=output, dry_run=dry_run)

clone_operation = Clone(logger=logger)
result = clone_operation.clone(config)
logger.success(result.output)
except Exception as e:

with TimeoutWrapper(timeout):
if config.dry_run:
logger.debug(debug_executing_dry_run)
formatted_output = clone_operation.clone_and_format(config)
logger.info(formatted_output)
logger.debug(debug_dry_run_completed)
else:
result = clone_operation.clone(config)
logger.debug(debug_clone_operation_result.format(success=result.success))

if not result.success:
logger.error(result.output)
logger.debug(debug_clone_operation_failed)
raise typer.Exit(1)

logger.debug(debug_clone_operation_completed)
logger.info(result.output)

except TimeoutError as e:
logger.error(e)
raise typer.Exit(1)
except Exception as e:
logger.debug(debug_exception_caught.format(error_type=type(e).__name__, error=str(e)))
logger.debug(debug_exception_details.format(error=e))
logger.error(str(e))
raise typer.Exit(1)
44 changes: 44 additions & 0 deletions cli/app/commands/clone/messages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
debug_cloning_repo = "Cloning {repo} to {path} (force: {force})"
debug_executing_git_clone = "Executing git clone: {command}"
debug_git_clone_success = "Git clone completed successfully"
debug_git_clone_failed = "Git clone failed (code: {code}): {error}"
debug_unexpected_error = "Unexpected error: {error_type}: {error}"
debug_removing_directory = "Removing existing directory: {path}"
debug_directory_removal_failed = "Failed to remove existing directory"
debug_path_exists_force_disabled = "Path exists and force disabled: {path}"
debug_clone_completed = "Clone completed in {duration}s - success: {success}"
debug_clone_command_invoked = "Clone command invoked with parameters:"
debug_repo_param = " repo: {repo}"
debug_branch_param = " branch: {branch}"
debug_path_param = " path: {path}"
debug_force_param = " force: {force}"
debug_verbose_param = " verbose: {verbose}"
debug_output_param = " output: {output}"
debug_dry_run_param = " dry_run: {dry_run}"
debug_executing_dry_run = "Executing dry run mode"
debug_dry_run_completed = "Dry run completed successfully"
debug_clone_operation_result = "Clone operation result - success: {success}"
debug_clone_operation_failed = "Clone operation failed, raising exit"
debug_clone_operation_completed = "Clone operation completed successfully"
debug_exception_caught = "Exception caught in clone callback: {error_type}: {error}"
debug_exception_details = "Exception details: {error}"
path_already_exists_use_force = "Path {path} already exists. Use --force to overwrite."
prerequisites_validation_failed = "Prerequisites validation failed"
failed_to_prepare_target_directory = "Failed to prepare target directory"
invalid_repo = "Invalid repository format"
invalid_repository_url = "Invalid repository URL format"
invalid_path = "Invalid path format"
unknown_error = "Unknown error"
successfully_cloned = "Successfully cloned {repo} to {path}"
dry_run_mode = "=== DRY RUN MODE ==="
dry_run_command_would_be_executed = "The following command would be executed:"
dry_run_command = "Command: {command}"
dry_run_repository = "Repository: {repo}"
dry_run_branch = "Branch: {branch}"
dry_run_target_path = "Target path: {path}"
dry_run_force_mode = "Force mode: {force}"
path_exists_will_overwrite = "Path {path} exists and will be overwritten (force mode)"
path_exists_would_fail = "Path {path} exists - clone would fail without --force"
target_path_not_exists = "Target path {path} does not exist"
end_dry_run = "=== END DRY RUN ==="
default_branch = "default"
Loading