diff --git a/CIME/case/case_setup.py b/CIME/case/case_setup.py index 9cba75a4c09..1679daf8994 100644 --- a/CIME/case/case_setup.py +++ b/CIME/case/case_setup.py @@ -527,37 +527,27 @@ def case_setup(self, clean=False, test_mode=False, reset=False, keep=None): def _create_case_repo(self, caseroot): - version = run_cmd_no_fail("git --version") - result = re.findall(r"([0-9]+)\.([0-9]+)\.?[0-9]*", version) - major = int(result[0][0]) - minor = int(result[0][1]) - - # gitinterface needs git version 2.28 or newer - if major > 2 or (major == 2 and minor >= 28): - self._gitinterface = GitInterface( - caseroot, logger, branch=self.get_value("CASE") + + self._gitinterface = GitInterface(caseroot, logger, branch=self.get_value("CASE")) + if self._gitinterface and not os.path.exists(os.path.join(caseroot, ".gitignore")): + safe_copy( + os.path.join( + self.get_value("CIMEROOT"), + "CIME", + "data", + "templates", + "gitignore.template", + ), + os.path.join(caseroot, ".gitignore"), + ) + append_case_status( + "", "", "local git repository created", gitinterface=self._gitinterface ) - if not os.path.exists(os.path.join(caseroot, ".gitignore")): - safe_copy( - os.path.join( - self.get_value("CIMEROOT"), - "CIME", - "data", - "templates", - "gitignore.template", - ), - os.path.join(caseroot, ".gitignore"), - ) - append_case_status( - "", "", "local git repository created", gitinterface=self._gitinterface - ) # add all files in caseroot to local repository self._gitinterface._git_command("add", "*") - else: - logger.warning("git interface requires git version 2.28 or newer") - + elif not self._gitinterface: append_case_status( "", "", - f"local git version too old for cime git interface {major}.{minor}", + "Local git version too old for cime git interface, version 2.28 or newer required.", ) diff --git a/CIME/gitinterface.py b/CIME/gitinterface.py index cfb0c42fcb4..790f1fc70f2 100644 --- a/CIME/gitinterface.py +++ b/CIME/gitinterface.py @@ -1,18 +1,35 @@ -import sys +import sys, shutil, re from CIME.utils import run_cmd_no_fail from pathlib import Path class GitInterface: def __init__(self, repo_path, logger, branch=None): + major = 0 + minor = 0 + self.logger = logger + self._defined = False + if shutil.which("git"): + version = run_cmd_no_fail("git --version") + result = re.findall(r"([0-9]+)\.([0-9]+)\.?[0-9]*", version) + major = int(result[0][0]) + minor = int(result[0][1]) + if major < 2 or (major == 2 and minor < 28): + logger.warning( + "Git not found or git version too old for cesm git interface {} {}".format( + major, minor + ) + ) + return + logger.debug("Initialize GitInterface for {}".format(repo_path)) + self._defined = True if isinstance(repo_path, str): self.repo_path = Path(repo_path).resolve() elif isinstance(repo_path, Path): self.repo_path = repo_path.resolve() else: raise TypeError("repo_path must be a str or Path object") - self.logger = logger try: import git @@ -28,9 +45,11 @@ def __init__(self, repo_path, logger, branch=None): if not (self.repo_path / ".git").exists(): self._init_git_repo(branch=branch) msg = "Using shell interface to git" - self.logger.debug(msg) + logger.debug(msg) def _git_command(self, operation, *args): + if not self._defined: + return self.logger.debug(operation) if self._use_module and operation != "submodule": try: @@ -41,6 +60,8 @@ def _git_command(self, operation, *args): return ["git", "-C", str(self.repo_path), operation] + list(args) def _init_git_repo(self, branch=None): + if not self._defined: + return if self._use_module: self.repo = self.git.Repo.init(str(self.repo_path)) if branch: @@ -53,6 +74,8 @@ def _init_git_repo(self, branch=None): # pylint: disable=unused-argument def git_operation(self, operation, *args, **kwargs): + if not self._defined: + return command = self._git_command(operation, *args) if isinstance(command, list): try: @@ -63,6 +86,8 @@ def git_operation(self, operation, *args, **kwargs): return command def config_get_value(self, section, name): + if not self._defined: + return if self._use_module: config = self.repo.config_reader() try: @@ -83,6 +108,8 @@ def config_get_value(self, section, name): return output.strip() def config_set_value(self, section, name, value): + if not self._defined: + return if self._use_module: with self.repo.config_writer() as writer: writer.set_value(section, name, value) diff --git a/CIME/status.py b/CIME/status.py index 23109b07645..54692395580 100644 --- a/CIME/status.py +++ b/CIME/status.py @@ -39,18 +39,20 @@ def append_case_status(phase, status, msg=None, caseroot=".", gitinterface=None) if gitinterface: filelist = gitinterface.git_operation( "ls-files", "--deleted", "--exclude-standard" - ).splitlines() + ) # First delete files that have been removed - for f in filelist: - logger.debug("removing file {}".format(f)) - gitinterface.git_operation("rm", f) + if filelist: + for f in filelist.splitlines(): + logger.debug("removing file {}".format(f)) + gitinterface.git_operation("rm", f) filelist = gitinterface.git_operation( "ls-files", "--others", "--modified", "--exclude-standard" - ).splitlines() + ) # Files that should not be added should have been excluded by the .gitignore file - for f in filelist: - logger.debug("adding file {}".format(f)) - gitinterface.git_operation("add", f) + if filelist: + for f in filelist.splitlines(): + logger.debug("adding file {}".format(f)) + gitinterface.git_operation("add", f) msg = msg if msg else " no message provided" gitinterface.git_operation("commit", "-m", '"' + msg + '"') remote = gitinterface.git_operation("remote")