diff --git a/CHANGELOG.md b/CHANGELOG.md index 20fb4cb..01a471c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.5] - 2025-09-09 + +## Change + +- Oggit fast restore + + ## [1.4.4] - 2025-09-09 ## Change diff --git a/ogclient/interfaceAdm/RestaurarImagenGit b/ogclient/interfaceAdm/RestaurarImagenGit index cd441e3..a5441e1 100755 --- a/ogclient/interfaceAdm/RestaurarImagenGit +++ b/ogclient/interfaceAdm/RestaurarImagenGit @@ -4,6 +4,8 @@ import resource import logging import subprocess +sys.path.insert(0, "/opt/opengnsys/lib/python3-test") + import NetLib import ogGlobals import SystemLib diff --git a/ogclient/lib/python3/GitLib/__init__.py b/ogclient/lib/python3/GitLib/__init__.py index cc78988..0d8860a 100755 --- a/ogclient/lib/python3/GitLib/__init__.py +++ b/ogclient/lib/python3/GitLib/__init__.py @@ -1479,7 +1479,7 @@ class OpengnsysGitLibrary: self.logger.info("initRepo done") return True - def cloneRepo(self, repo_name, destination, boot_device, ref = None, branch = None): + def cloneRepo(self, repo_name, destination, boot_device, ref = None, branch = None, delete_existing_repo = False, format_existing = False): """ Clones a repository to a specified destination and sets up the bootloader. @@ -1487,6 +1487,9 @@ class OpengnsysGitLibrary: repo_name (str): The name of the repository to clone. destination (str): The destination directory where the repository will be cloned. boot_device (str): The boot device to install the bootloader. + delete_existing_repo (bool): Whether to delete an existing repository and re-create from scratch, + even if the repo is the one we need. + format_existing (bool): Whether to format the filesystem even if we don't need to. Raises: RequirementException: If the repository metadata is incorrect or if the repository's @@ -1496,18 +1499,38 @@ class OpengnsysGitLibrary: Info: Logs the start of the cloning process. Debug: Logs the repository URL, EFI compatibility of the repository and the system. """ - self.logger.info(f"Cloning repo: {repo_name} => {destination}") + self.logger.info(f"Cloning repo : {repo_name} => {destination}") repo_url = self._getOgRepository(repo_name) real_git_dir = os.path.join(self.cache_dir, f"git-{repo_name}") - - if os.path.exists(real_git_dir): - self.logger.debug(f"Removing existing repository {real_git_dir}") - shutil.rmtree(real_git_dir) + repo = None self.logger.debug(f"URL: {repo_url}") + if os.path.exists(real_git_dir): + if delete_existing_repo: + self.logger.info("There is an existing repository, but a full reset will be done") + repo = None + else: + self.logger.info("Verifying existing repository at %s", real_git_dir) + repo = git.Repo.init(real_git_dir, bare=True) + + if "origin" in repo.remotes: + if repo_url in repo.remotes.origin.urls: + self.logger.info("Remote URL of existing repository matches") + else: + self.logger.info("Existing repo points to a different URL, will delete.") + repo = None + else: + self.logger.info("Existing repo has no origin remote, will delete.") + repo = None + + if repo is None: + self.logger.debug(f"Removing existing repository %s", real_git_dir) + os._exit(10) + shutil.rmtree(real_git_dir) + all_metadata = self._get_repo_metadata(repo_name) metadata = all_metadata["metadata.json"] fs_data = all_metadata["filesystems.json"] @@ -1528,50 +1551,80 @@ class OpengnsysGitLibrary: if repo_is_efi != efi: raise RequirementException("Repositorio usa sistema de arranque incompatible con sistema actual") - self.fs.unmount(device = destination) + if repo is None or format_existing: + self.logger.info("Creating a new filesystem at %s") + self.fs.unmount(device = destination) - filesystem_map = {"/" : destination} + filesystem_map = {"/" : destination} - self._create_filesystems(fs_data, filesystem_map) + self._create_filesystems(fs_data, filesystem_map) - destination_dir = "/mnt/repo-" + repo_name + destination_dir = "/mnt/repo-" + repo_name - self.fs.mount(destination, destination_dir) + self.fs.mount(destination, destination_dir) - self._delete_contents(destination_dir) - - self.logger.info("Cloning repository from %s", repo_url) - - - - - if branch: - # We've got a nearby branch, start from that - self.logger.debug("Cloning repo %s, branch %s", repo_url, branch) - repo = git.Repo.clone_from(repo_url, destination_dir, branch = branch, multi_options = [f"--separate-git-dir={real_git_dir}"], progress=self.progress_callback) + self._delete_contents(destination_dir) else: - # Start from main instead - self.logger.debug("Cloning repo %s", repo_url) - repo = git.Repo.clone_from(repo_url, destination_dir, multi_options = [f"--separate-git-dir={real_git_dir}"], progress=self.progress_callback) + destination_dir = "/mnt/repo-" + repo_name + self.logger.info("Mounting existing filesystem %s at %s", destination, destination_dir) + self.fs.unmount(device = destination) + self.fs.mount(destination, destination_dir) + + # Change from bare repo to our checked out repo + self.logger.info("Opening repo from %s now", destination_dir) + + git_dotdir = os.path.join(destination, ".git") + if os.path.exists(git_dotdir): + self.logger.debug("Replacing .git directory, gitpython doesn't like the file method") + os.unlink(git_dotdir) + os.symlink(src = real_git_dir, dst = git_dotdir) + + self.logger.info("Re-opening git repo at %s", destination_dir) + repo = git.Repo(destination_dir) + + self.logger.info("Forcing git repo to non-bare status") + repo.config_writer().set_value("core", "bare", "false").release() + + self.logger.info("Re-opening git repo again after non-bare adjustment at %s", destination_dir) + repo = git.Repo(destination_dir) + + self.logger.info("New repo is %s", repo) - self.logger.debug("Checking out indicated branch %s", branch) - remote_branch_ref = repo.heads[branch] - if branch in repo.heads: - self.logger.debug("Local branch %s exists, checking it out first", branch) - repo.git.checkout(branch) + if repo is None: + self.logger.info("Cloning repository from %s", repo_url) - self.logger.debug("Resetting branch %s to ref %s", branch, ref) - repo.git.reset("--hard", ref) + if branch: + # We've got a nearby branch, start from that + self.logger.debug("Cloning repo %s, branch %s", repo_url, branch) + repo = git.Repo.clone_from(repo_url, destination_dir, branch = branch, multi_options = [f"--separate-git-dir={real_git_dir}"], progress=self.progress_callback) else: - if ref: - self.logger.debug("Local branch adjusted to ref %s", ref) - local_ref = repo.create_head(branch, ref) - else: - self.logger.debug("Local branch is set to remote branch %s", remote_branch_ref) - local_ref = repo.create_head(branch, remote_branch_ref) - local_ref.set_tracking_branch(remote_branch_ref) + # Start from main instead + self.logger.debug("Cloning repo %s", repo_url) + repo = git.Repo.clone_from(repo_url, destination_dir, multi_options = [f"--separate-git-dir={real_git_dir}"], progress=self.progress_callback) + else: + self.logger.info("Fetching updates from remote in %s", repo) + for remote in repo.remotes: + remote.fetch() + + self.logger.debug("Checking out indicated branch %s", branch) + remote_branch_ref = repo.heads[branch] + + if branch in repo.heads: + self.logger.debug("Local branch %s exists, checking it out first", branch) + repo.git.checkout(branch) + + self.logger.debug("Resetting branch %s to ref %s", branch, ref) + repo.git.reset("--hard", ref) + else: + if ref: + self.logger.debug("Local branch adjusted to ref %s", ref) + local_ref = repo.create_head(branch, ref) + else: + self.logger.debug("Local branch is set to remote branch %s", remote_branch_ref) + local_ref = repo.create_head(branch, remote_branch_ref) + local_ref.set_tracking_branch(remote_branch_ref) self.logger.debug("Checking out local branch %s", branch) local_ref.checkout()