diff --git a/cli/git.py b/cli/git.py new file mode 100644 index 0000000..686d5d0 --- /dev/null +++ b/cli/git.py @@ -0,0 +1,11 @@ +# cli/module.py +import tqdm +from services.git.handler import GitHandler +import lib.color_log as color_log + +def setup_cli(subparsers): + pass + +def git(args): + git_handler = GitHandler(args.repo_url, args.local_path, args.branch) + git_handler.pull_updates() diff --git a/cli/module.py b/cli/module.py index 07f6994..b1efe73 100644 --- a/cli/module.py +++ b/cli/module.py @@ -39,6 +39,14 @@ def module(args): 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...", + ) + module_manager.install(args.instance, [module_name]) + # Now upgrade the module module_manager.upgrade(args.instance, [module_name]) case _: color_log.Show( diff --git a/services/git/handler.py b/services/git/handler.py index 7e267f1..af568d5 100644 --- a/services/git/handler.py +++ b/services/git/handler.py @@ -1,34 +1,117 @@ import git import os -from git import Repo +from services.odoo.connection import OdooConnection +import lib.color_log as color_log +import subprocess class GitHandler: - def __init__(self, repo_url, local_path, branch="main"): - self.repo_url = repo_url - self.local_path = local_path - self.branch = branch - self.repo = None + def __init__(self, config_path="config/settings.yaml"): + self.config = OdooConnection(config_path) - def clone_or_open_repo(self): - if not os.path.exists(self.local_path): - print(f"Cloning repository from {self.repo_url} to {self.local_path}") - self.repo = Repo.clone_from(self.repo_url, self.local_path) - else: - print(f"Opening existing repository at {self.local_path}") - self.repo = Repo(self.local_path) - - def pull_updates(self): + def _execute_command(self, cmd, instance_name): + """Execute a shell command and handle errors.""" try: - self.clone_or_open_repo() - print(f"Checking out and pulling branch: {self.branch}") - self.repo.git.checkout(self.branch) - self.repo.remotes.origin.pull() - print("Repository updated successfully.") + color_log.Show("INFO", f"Executing command: {cmd}") + subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True) + color_log.Show("OK", f"Command executed successfully for {instance_name}") + except subprocess.CalledProcessError as e: + color_log.Show( + "FAILED", + f"Error performing git operation for {instance_name}: {e}", + ) + + raise + def clone_or_open_repo(self, instance_name=None, repo_url=None, branch=None): + """Clone or open repository with SSH support""" + try: + if not instance_name: + # Local operation + if not os.path.exists(self.local_path): + cmd = f"git clone -b {branch or 'main'} {repo_url} {self.local_path}" + self._execute_command(cmd, "local") + return True + + # Remote operation + instance = self.config.get_instance(instance_name) + if not instance: + raise ValueError(f"Instance {instance_name} not found") + + # Check if repo exists + check_cmd = f"test -d {self.local_path}/.git && echo 'exists' || echo 'not exists'" + result = self._execute_command(check_cmd, instance_name) + + if "not exists" in result: + # Clone repository + cmd = self._get_command(instance, "clone", repo_url, branch) + self._execute_command(cmd, instance_name) return True - except git.GitCommandError as e: - print(f"Error pulling updates: {e}") + + except Exception as e: + color_log.Show("FAILED", f"Error in clone_or_open_repo: {e}") + return False + + def pull_updates(self, instance_name=None, branch=None): + """Pull updates with SSH support""" + try: + if not instance_name: + # Local operation + cmd = f"git --git-dir={self.local_path}/.git --work-tree={self.local_path} pull origin {branch or 'main'}" + self._execute_command(cmd, "local") + return True + + # Remote operation + instance = self.config.get_instance(instance_name) + if not instance: + raise ValueError(f"Instance {instance_name} not found") + + cmd = self._get_command(instance, "pull", branch=branch) + self._execute_command(cmd, instance_name) + return True + + except Exception as e: + color_log.Show("FAILED", f"Error pulling updates: {e}") return False def get_current_commit(self): return self.repo.head.commit.hexsha if self.repo else None + def _get_command(self, instance, action, repo_url=None, branch=None): + """ + Generate the appropriate git command based on instance type and action. + + Args: + instance (dict): Instance configuration + action (str): Git action (clone/pull) + repo_url (str, optional): Repository URL for clone operation + branch (str, optional): Branch name + + Returns: + str: Generated git command + """ + host = instance["host"] + ssh_settings = instance.get("ssh", {}) + ssh_user = ssh_settings.get("user", "root") + ssh_key_path = ssh_settings.get("key_path") + + local_host = host in ["localhost", "127.0.0.1"] + + # Base git command + if action == "clone": + if not repo_url: + raise ValueError("Repository URL is required for clone operation") + cmd = f"git clone -b {branch or 'main'} {repo_url} {self.local_path}" + elif action == "pull": + cmd = f"git --git-dir={self.local_path}/.git --work-tree={self.local_path} pull origin {branch or 'main'}" + else: + raise ValueError(f"Unsupported git action: {action}") + + # Wrap with SSH if remote host + if not local_host: + if not ssh_key_path: + cmd = f"ssh -t {ssh_user}@{host} 'sudo {cmd}'" + else: + cmd = f"ssh -i {ssh_key_path} {ssh_user}@{host} 'sudo {cmd}'" + + return cmd + + \ No newline at end of file diff --git a/services/odoo/module.py b/services/odoo/module.py index 9af5187..ef15d64 100644 --- a/services/odoo/module.py +++ b/services/odoo/module.py @@ -85,3 +85,29 @@ class OdooModuleManager: def upgrade(self, instance_name: str = None, module_names: list = None) -> None: """Upgrade multiple modules for the specified instance(s).""" self._manage_module("upgrade", instance_name, module_names) + + def is_module_installed(self, instance_name: str, module_name: str) -> bool: + """Check if a module is installed in the specified instance. + + Args: + instance_name (str): Name of the Odoo instance + module_name (str): Name of the module to check + + Returns: + bool: True if the module is installed, False otherwise + """ + self.config.connect(instance_name) + try: + module_ids = self.config.execute( + instance_name, + "ir.module.module", + "search", + [("name", "=", module_name), ("state", "=", "installed")], + ) + return bool(module_ids) + except Exception as e: + color_log.Show( + "FAILED", + f"Error checking module {module_name} in {instance_name}: {e}", + ) + return False