diff --git a/git_fleximod/git_fleximod.py b/git_fleximod/git_fleximod.py index 505d7222f0..e3adddb855 100755 --- a/git_fleximod/git_fleximod.py +++ b/git_fleximod/git_fleximod.py @@ -175,97 +175,6 @@ def submodule_sparse_checkout(root_dir, name, url, path, sparsefile, tag="master rgit.config_set_value(f'submodule "{name}"', "active", "true") rgit.config_set_value(f'submodule "{name}"', "url", url) - -def single_submodule_checkout( - root, name, path, url=None, tag=None, force=False, optional=False -): - """ - This function checks out a single git submodule. - - Parameters: - root (str): The root directory for the git operation. - name (str): The name of the submodule. - path (str): The path to the submodule. - url (str, optional): The URL of the submodule. Defaults to None. - tag (str, optional): The tag to checkout. Defaults to None. - force (bool, optional): If set to True, forces the checkout operation. Defaults to False. - optional (bool, optional): If set to True, the submodule is considered optional. Defaults to False. - - Returns: - None - """ - # function implementation... - git = GitInterface(root, logger) - repodir = os.path.join(root, path) - logger.info("Checkout {} into {}/{}".format(name, root, path)) - # if url is provided update to the new url - tmpurl = None - repo_exists = False -# if os.path.exists(os.path.join(repodir, ".git")): -# logger.info("Submodule {} already checked out".format(name)) -# repo_exists = True - # Look for a .gitmodules file in the newly checkedout repo - if not repo_exists and url: - # ssh urls cause problems for those who dont have git accounts with ssh keys defined - # but cime has one since e3sm prefers ssh to https, because the .gitmodules file was - # opened with a GitModules object we don't need to worry about restoring the file here - # it will be done by the GitModules class - if url.startswith("git@"): - tmpurl = url - url = url.replace("git@github.com:", "https://github.com/") - git.git_operation("clone", url, path) - smgit = GitInterface(repodir, logger) - if not tag: - tag = smgit.git_operation("describe", "--tags", "--always").rstrip() - smgit.git_operation("checkout", tag) - # Now need to move the .git dir to the submodule location - rootdotgit = os.path.join(root, ".git") - if os.path.isfile(rootdotgit): - with open(rootdotgit) as f: - line = f.readline() - if line.startswith("gitdir: "): - rootdotgit = line[8:].rstrip() - - newpath = os.path.abspath(os.path.join(root, rootdotgit, "modules", name)) - if os.path.exists(newpath): - shutil.rmtree(os.path.join(repodir, ".git")) - else: - shutil.move(os.path.join(repodir, ".git"), newpath) - - with open(os.path.join(repodir, ".git"), "w") as f: - f.write("gitdir: " + os.path.relpath(newpath, start=repodir)) - - if not os.path.exists(repodir): - parent = os.path.dirname(repodir) - if not os.path.isdir(parent): - os.makedirs(parent) - git.git_operation("submodule", "add", "--name", name, "--", url, path) - - if not repo_exists or not tmpurl: - git.git_operation("submodule", "update", "--init", "--", path) - if tag and not optional: - smgit = GitInterface(repodir, logger) - smgit.git_operation("checkout", tag) - - if os.path.exists(os.path.join(repodir, ".gitmodules")): - # recursively handle this checkout - print(f"Recursively checking out submodules of {name} {optional}") - gitmodules = GitModules(logger, confpath=repodir) - requiredlist = ["AlwaysRequired"] - if optional: - requiredlist.append("AlwaysOptional") - submodules_checkout(gitmodules, repodir, requiredlist, force=force) - if not os.path.exists(os.path.join(repodir, ".git")): - utils.fatal_error( - f"Failed to checkout {name} {repo_exists} {tmpurl} {repodir} {path}" - ) - - if tmpurl: - print(git.git_operation("restore", ".gitmodules")) - - return - - def init_submodule_from_gitmodules(gitmodules, name, root_dir, logger): path = gitmodules.get(name, "path") url = gitmodules.get(name, "url") @@ -280,7 +189,7 @@ def submodules_status(gitmodules, root_dir, toplevel=False, depth=0): localmods = 0 needsupdate = 0 submodules = {} - wrapper = textwrap.TextWrapper(initial_indent=' '*depth, width=120,subsequent_indent=' '*(depth+20)) + wrapper = textwrap.TextWrapper(initial_indent=' '*(depth*10), width=120,subsequent_indent=' '*(depth*20)) for name in gitmodules.sections(): if not submodules or name not in submodules: submodules[name] = init_submodule_from_gitmodules(gitmodules, name, root_dir, logger) @@ -306,23 +215,15 @@ def git_toplevelroot(root_dir, logger): superroot = rgit.git_operation("rev-parse", "--show-superproject-working-tree") return superroot - def submodules_update(gitmodules, root_dir, requiredlist, force): -# _, localmods, needsupdate = submodules_status(gitmodules, root_dir) -# if localmods and not force: -# local_mods_output() -# return -# if needsupdate == 0: -# return submodules = {} for name in gitmodules.sections(): if not submodules or name not in submodules: submodules[name] = init_submodule_from_gitmodules(gitmodules, name, root_dir, logger) _, needsupdate, localmods, testfails = submodules[name].status() - fxrequired = submodules[name].fxrequired - if not fxrequired: - fxrequired = "AlwaysRequired" - + if not submodules[name].fxrequired: + submodules[name].fxrequired = "AlwaysRequired" + fxrequired = submodules[name].fxrequired allowedvalues = fxrequired_allowed_values() assert fxrequired in allowedvalues @@ -334,32 +235,24 @@ def submodules_update(gitmodules, root_dir, requiredlist, force): or fxrequired not in requiredlist) ): if "Optional" in fxrequired and "Optional" not in requiredlist: + print(f"Skipping optional component {name:>20}") if fxrequired.startswith("Always"): print(f"Skipping optional component {name:>20}") continue - -# if fxsparse: -# logger.debug( -# "Callng submodule_sparse_checkout({}, {}, {}, {}, {}, {}".format( -# root_dir, name, url, path, fxsparse, fxtag -# ) -# ) -# submodule_sparse_checkout(root_dir, name, url, path, fxsparse, tag=fxtag) -# else: - print(f"fxrequired {fxrequired} requiredlist {requiredlist}") - submodules[name].update(optional="AlwaysOptional") - -# single_submodule_checkout( -# root_dir, -# name, -# path, -# url=url, -# tag=fxtag, -# force=force, -# optional="AlwaysOptional" in requiredlist -# ) - - + optional = "AlwaysOptional" in requiredlist + print(f"1 Required list is {requiredlist} optional is {optional}") + if fxrequired in requiredlist: + submodules[name].update() + repodir = os.path.join(root_dir, submodules[name].path) + if os.path.exists(os.path.join(repodir, ".gitmodules")): + # recursively handle this checkout + print(f"Recursively checking out submodules of {name}") + gitmodules = GitModules(submodules[name].logger, confpath=repodir) + requiredlist = ["AlwaysRequired"] + if optional: + requiredlist.append("AlwaysOptional") + print(f"2 Required list is {requiredlist}") + submodules_update(gitmodules, repodir, requiredlist, force=force) def local_mods_output(): @@ -375,65 +268,6 @@ def local_mods_output(): """ print(text) -# checkout is done by update if required so this function may be depricated -def submodules_checkout(gitmodules, root_dir, requiredlist, force=False): - """ - This function checks out all git submodules based on the provided parameters. - - Parameters: - gitmodules (ConfigParser): The gitmodules configuration. - root_dir (str): The root directory for the git operation. - requiredlist (list): The list of required modules. - force (bool, optional): If set to True, forces the checkout operation. Defaults to False. - - Returns: - None - """ - # function implementation... - print("") - _, localmods, needsupdate = submodules_status(gitmodules, root_dir) - if localmods and not force: - local_mods_output() - return - if not needsupdate: - return - for name in gitmodules.sections(): - fxrequired = gitmodules.get(name, "fxrequired") - fxsparse = gitmodules.get(name, "fxsparse") - fxtag = gitmodules.get(name, "fxtag") - path = gitmodules.get(name, "path") - url = gitmodules.get(name, "url") - superroot = git_toplevelroot(root_dir, logger) - if fxrequired and fxrequired not in requiredlist: - if fxrequired == "AlwaysOptional" or (superroot == root_dir): - print(f"Skipping optional component {name:>20} {requiredlist}") - continue - - - if fxsparse: - logger.debug( - "Callng submodule_sparse_checkout({}, {}, {}, {}, {}, {}".format( - root_dir, name, url, path, fxsparse, fxtag - ) - ) - submodule_sparse_checkout(root_dir, name, url, path, fxsparse, tag=fxtag) - else: - logger.debug( - "Calling submodule_checkout({},{},{})".format(root_dir, name, path) - ) - single_submodule_checkout( - root_dir, - name, - path, - url=url, - tag=fxtag, - force=force, - optional="AlwaysOptional" == fxrequired \ - or "ToplevelOptional" == fxrequired \ - or "TopLevelOptional" == fxrequired - ) - - def submodules_test(gitmodules, root_dir): """ This function tests the git submodules based on the provided parameters. diff --git a/git_fleximod/submodule.py b/git_fleximod/submodule.py index dc27c3d00a..a3e5624e54 100644 --- a/git_fleximod/submodule.py +++ b/git_fleximod/submodule.py @@ -32,23 +32,28 @@ def __init__(self, root_dir, name, path, url, fxtag=None, fxurl=None, fxsparse=N self.fxurl = fxurl self.fxtag = fxtag self.fxsparse = fxsparse - self.fxrequired = fxrequired + if fxrequired: + self.fxrequired = fxrequired + else: + self.fxrequired = "AlwaysRequired" self.logger = logger def status(self): """ Checks the status of the submodule and returns 4 parameters: - result (str): The status of the submodule. - - needsupdate (int): An indicator if the submodule needs to be updated. - - localmods (int): An indicator if the submodule has local modifications. - - testfails (int): An indicator if the submodule has failed a test, this is used for testing purposes. + - needsupdate (bool): An indicator if the submodule needs to be updated. + - localmods (bool): An indicator if the submodule has local modifications. + - testfails (bool): An indicator if the submodule has failed a test, this is used for testing purposes. """ smpath = os.path.join(self.root_dir, self.path) - testfails = 0 - localmods = 0 - needsupdate = 0 + testfails = False + localmods = False + needsupdate = False ahash = None - optional = " (optional)" if "Optional" in self.fxrequired else None + optional = "" + if "Optional" in self.fxrequired: + optional = " (optional)" required = None level = None if not os.path.exists(os.path.join(smpath, ".git")): @@ -71,7 +76,8 @@ def status(self): if hhash and atag: break if self.fxtag and (ahash == hhash or atag == self.fxtag): - result = f"e {self.name:>20} not checked out, aligned at tag {self.fxtag}{optional} {level} {required}" + result = f"e {self.name:>20} not checked out, aligned at tag {self.fxtag}{optional}" + needsupdate = True elif self.fxtag: ahash = rootgit.git_operation( "submodule", "status", "{}".format(self.path) @@ -81,18 +87,19 @@ def status(self): result = f"e {self.name:>20} not checked out, aligned at hash {ahash}{optional}" else: result = f"e {self.name:>20} not checked out, out of sync at tag {atag}, expected tag is {self.fxtag}{optional}" - testfails += 1 + testfails = True + needsupdate = True else: result = f"e {self.name:>20} has no fxtag defined in .gitmodules{optional}" - testfails += 1 + testfails = True else: with utils.pushd(smpath): git = GitInterface(smpath, self.logger) remote = git.git_operation("remote").rstrip() if remote == '': result = f"e {self.name:>20} has no associated remote" - testfails += 1 - needsupdate += 1 + testfails = True + needsupdate = True return result, needsupdate, localmods, testfails rurl = git.git_operation("ls-remote","--get-url").rstrip() atag = git.git_operation("describe", "--tags", "--always").rstrip() @@ -113,15 +120,15 @@ def status(self): recurse = True elif self.fxtag: result = f"s {self.name:>20} {atag} {ahash} is out of sync with .gitmodules {self.fxtag}" - testfails += 1 - needsupdate += 1 + testfails = True + needsupdate = True else: result = f"e {self.name:>20} has no fxtag defined in .gitmodules, module at {atag}" - testfails += 1 + testfails = True status = git.git_operation("status", "--ignore-submodules", "-uno") if "nothing to commit" not in status: - localmods = localmods + 1 + localmods = True result = "M" + textwrap.indent(status, " ") return result, needsupdate, localmods, testfails @@ -161,13 +168,6 @@ def _add_remote(self, git): git.git_operation("remote", "add", newremote, self.url) return newremote - def toplevel(self): - """ - Checks if the submodule is a top-level submodule (ie not a submodule of a submodule). - """ - if self.fxrequired: - return True if self.fxrequired.startswith("Top") else False - def sparse_checkout(self): """ Performs a sparse checkout of the submodule. @@ -267,7 +267,7 @@ def sparse_checkout(self): rgit.config_set_value(f'submodule "{self.name}"', "active", "true") rgit.config_set_value(f'submodule "{self.name}"', "url", self.url) - def update(self, optional=None): + def update(self): """ Updates the submodule to the latest or specified version. @@ -282,10 +282,8 @@ def update(self, optional=None): 4. If the root `.git` is a file (indicating a submodule or a worktree), additional steps are taken to integrate the submodule properly. Args: - optional (bool): Indicates if the submodule is optional. This parameter is currently unused in the function but can be implemented for conditional updates based on the submodule's importance. - + None Note: - - The method currently does not use the `optional` parameter, but it is designed for future use where updates can be conditional based on the submodule's importance. - SSH URLs are automatically converted to HTTPS to accommodate users without SSH keys. Returns: @@ -339,23 +337,15 @@ def update(self, optional=None): parent = os.path.dirname(repodir) if not os.path.isdir(parent): os.makedirs(parent) - git.git_operation("submodule", "add", "--name", self.name, "--", url, self.path) + git.git_operation("submodule", "add", "--name", self.name, "--", self.url, self.path) if not repo_exists or not tmpurl: git.git_operation("submodule", "update", "--init", "--", self.path) - if self.fxtag and not optional: + if self.fxtag: smgit = GitInterface(repodir, self.logger) smgit.git_operation("checkout", self.fxtag) - if os.path.exists(os.path.join(repodir, ".gitmodules")): - # recursively handle this checkout - print(f"Recursively checking out submodules of {self.name} {optional}") - gitmodules = GitModules(self.logger, confpath=repodir) - requiredlist = ["AlwaysRequired"] - if optional: - requiredlist.append("AlwaysOptional") - submodules_checkout(gitmodules, repodir, requiredlist, force=force) if not os.path.exists(os.path.join(repodir, ".git")): utils.fatal_error( f"Failed to checkout {self.name} {repo_exists} {tmpurl} {repodir} {self.path}" @@ -368,10 +358,7 @@ def update(self, optional=None): with utils.pushd(submoddir): git = GitInterface(submoddir, self.logger) # first make sure the url is correct - print("3calling ls-remote") - newremote = self._add_remote(git) - tags = git.git_operation("tag", "-l") fxtag = self.fxtag if fxtag and fxtag not in tags: