Skip to content
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

refine the git interface to handle no git and old git #4684

Merged
merged 4 commits into from
Sep 27, 2024
Merged
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
44 changes: 17 additions & 27 deletions CIME/case/case_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
)
33 changes: 30 additions & 3 deletions CIME/gitinterface.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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)
Expand Down
18 changes: 10 additions & 8 deletions CIME/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading