forked from ESCOMP/CTSM
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a1702a7
commit db8a989
Showing
1 changed file
with
89 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import argparse | |
sys.path.append(os.path.join(os.path.dirname(__file__),"..","lib","python","site-packages")) | ||
|
||
import textwrap | ||
from pathlib import Path | ||
from fleximod import utils | ||
from fleximod.gitinterface import GitInterface | ||
from fleximod.gitmodules import GitModules | ||
|
@@ -16,7 +17,17 @@ from configparser import NoOptionError | |
# logger variable is global | ||
logger = None | ||
|
||
def commandline_arguments(args=None): | ||
def find_root_dir(filename=".git"): | ||
d = Path.cwd() | ||
root = Path(d.root) | ||
while d != root: | ||
attempt = d / filename | ||
if attempt.is_dir(): | ||
return attempt | ||
d = d.parent | ||
return None | ||
|
||
def get_parser(): | ||
description = """ | ||
%(prog)s manages checking out groups of gitsubmodules with addtional support for Earth System Models | ||
""" | ||
|
@@ -32,7 +43,7 @@ def commandline_arguments(args=None): | |
"action", | ||
choices=choices, | ||
default="checkout", | ||
help=f"Subcommand of fleximod, choices are {choices}", | ||
help=f"Subcommand of fleximod, choices are {choices[:-1]}", | ||
) | ||
|
||
parser.add_argument( | ||
|
@@ -45,8 +56,8 @@ def commandline_arguments(args=None): | |
parser.add_argument( | ||
"-C", | ||
"--path", | ||
default=os.getcwd(), | ||
help="Toplevel repository directory. Defaults to current directory.", | ||
default=find_root_dir(), | ||
help="Toplevel repository directory. Defaults to top git directory relative to current.", | ||
) | ||
|
||
parser.add_argument( | ||
|
@@ -63,6 +74,13 @@ def commandline_arguments(args=None): | |
nargs="*", | ||
help="Component(s) listed in the gitmodules file which should be ignored.", | ||
) | ||
parser.add_argument( | ||
"-f", | ||
"--force", | ||
action="store_true", | ||
default=False, | ||
help="Override cautions and update or checkout over locally modified repository." | ||
) | ||
|
||
parser.add_argument( | ||
"-o", | ||
|
@@ -111,6 +129,11 @@ def commandline_arguments(args=None): | |
"information to the screen and log file.", | ||
) | ||
|
||
return parser | ||
|
||
def commandline_arguments(args=None): | ||
parser = get_parser() | ||
|
||
if args: | ||
options = parser.parse_args(args) | ||
else: | ||
|
@@ -125,9 +148,15 @@ def commandline_arguments(args=None): | |
action = options.action | ||
if not action: | ||
action = "checkout" | ||
handlers=[logging.StreamHandler()] | ||
|
||
if options.debug: | ||
try: | ||
open("fleximod.log","w") | ||
except PermissionError: | ||
sys.exit("ABORT: Could not write file fleximod.log") | ||
level = logging.DEBUG | ||
handlers.append(logging.FileHandler("fleximod.log")) | ||
elif options.verbose: | ||
level = logging.INFO | ||
else: | ||
|
@@ -136,8 +165,9 @@ def commandline_arguments(args=None): | |
logging.basicConfig( | ||
level=level, | ||
format="%(name)s - %(levelname)s - %(message)s", | ||
handlers=[logging.FileHandler("fleximod.log"), logging.StreamHandler()], | ||
handlers=handlers | ||
) | ||
|
||
if hasattr(options, 'version'): | ||
exit() | ||
|
||
|
@@ -148,6 +178,7 @@ def commandline_arguments(args=None): | |
options.components, | ||
options.exclude, | ||
options.verbose, | ||
options.force, | ||
action, | ||
) | ||
|
||
|
@@ -231,8 +262,29 @@ def submodule_checkout(root, name, path, url=None, tag=None): | |
if url.startswith("git@"): | ||
tmpurl = url | ||
url = url.replace("[email protected]:", "https://github.com") | ||
git.git_operation("clone", "-b", tag, url, path) | ||
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",path)) | ||
print(f"root is {root} rootdotgit is {rootdotgit} newpath is {newpath}") | ||
if not os.path.isdir(os.path.join(newpath,os.pardir)): | ||
os.makedirs(os.path.abspath(os.path.join(newpath,os.pardir))) | ||
|
||
shutil.move(os.path.join(repodir,".git"), newpath) | ||
with open(os.path.join(repodir,".git"), "w") as f: | ||
f.write("gitdir: "+newpath) | ||
|
||
|
||
|
||
|
||
if not tmpurl: | ||
|
@@ -256,6 +308,7 @@ def submodule_checkout(root, name, path, url=None, tag=None): | |
|
||
def submodules_status(gitmodules, root_dir): | ||
testfails = 0 | ||
localmods = 0 | ||
for name in gitmodules.sections(): | ||
path = gitmodules.get(name, "path") | ||
tag = gitmodules.get(name, "fxtag") | ||
|
@@ -275,32 +328,38 @@ def submodules_status(gitmodules, root_dir): | |
atag = (htag.split()[1])[10:] | ||
break | ||
if tag == atag: | ||
print(f"Submodule {name} not checked out, aligned at tag {tag}") | ||
print(f"e {name:>20} not checked out, aligned at tag {tag}") | ||
else: | ||
print(f"Submodule {name} not checked out, out of sync at tag {atag}, expected tag is {tag}") | ||
print(f"e {name:>20} not checked out, out of sync at tag {atag}, expected tag is {tag}") | ||
testfails += 1 | ||
else: | ||
with utils.pushd(newpath): | ||
git = GitInterface(newpath, logger) | ||
atag = git.git_operation("describe", "--tags", "--always").rstrip() | ||
if tag and atag != tag: | ||
print(f"Submodule {name} {atag} is out of sync with .gitmodules {tag}") | ||
print(f"s {name:>20} {atag} is out of sync with .gitmodules {tag}") | ||
testfails += 1 | ||
elif tag: | ||
print(f"Submodule {name} at tag {tag}") | ||
print(f" {name:>20} at tag {tag}") | ||
else: | ||
print( | ||
f"Submodule {name} has no tag defined in .gitmodules, module at {atag}" | ||
f"e {name:>20} has no tag defined in .gitmodules, module at {atag}" | ||
) | ||
testfails += 1 | ||
|
||
status = git.git_operation("status","--ignore-submodules") | ||
if "nothing to commit" not in status: | ||
print(textwrap.indent(status,' ')) | ||
localmods = localmods+1 | ||
print('M'+textwrap.indent(status,' ')) | ||
|
||
return testfails | ||
return testfails, localmods | ||
|
||
def submodules_update(gitmodules, root_dir): | ||
def submodules_update(gitmodules, root_dir, force): | ||
_,localmods = submodules_status(gitmodules, root_dir) | ||
print("") | ||
if localmods and not force: | ||
print(f"Repository has local mods, cowardly refusing to continue, fix issues or use --force to override") | ||
return | ||
for name in gitmodules.sections(): | ||
fxtag = gitmodules.get(name, "fxtag") | ||
path = gitmodules.get(name, "path") | ||
|
@@ -333,15 +392,20 @@ def submodules_update(gitmodules, root_dir): | |
git.git_operation("fetch", newremote, "--tags") | ||
atag = git.git_operation("describe", "--tags", "--always").rstrip() | ||
if fxtag and fxtag != atag: | ||
print(f"Updating {name} to {fxtag}") | ||
print(f"{name:>20} updated to {fxtag}") | ||
git.git_operation("checkout", fxtag) | ||
elif not fxtag: | ||
print(f"No fxtag found for submodule {name}") | ||
print(f"No fxtag found for submodule {name:>20}") | ||
else: | ||
print(f"submodule {name} up to date.") | ||
print(f"{name:>20} up to date.") | ||
|
||
|
||
def submodules_checkout(gitmodules, root_dir, requiredlist): | ||
def submodules_checkout(gitmodules, root_dir, requiredlist, force): | ||
_,localmods = submodules_status(gitmodules, root_dir) | ||
print("") | ||
if localmods and not force: | ||
print(f"Repository has local mods, cowardly refusing to continue, fix issues or use --force to override") | ||
return | ||
for name in gitmodules.sections(): | ||
fxrequired = gitmodules.get(name, "fxrequired") | ||
fxsparse = gitmodules.get(name, "fxsparse") | ||
|
@@ -368,7 +432,7 @@ def submodules_checkout(gitmodules, root_dir, requiredlist): | |
|
||
def submodules_test(gitmodules, root_dir): | ||
# First check that fxtags are present and in sync with submodule hashes | ||
testfails = submodules_status(gitmodules, root_dir) | ||
testfails,localmods = submodules_status(gitmodules, root_dir) | ||
# Then make sure that urls are consistant with fxurls (not forks and not ssh) | ||
# and that sparse checkout files exist | ||
for name in gitmodules.sections(): | ||
|
@@ -382,7 +446,8 @@ def submodules_test(gitmodules, root_dir): | |
if fxsparse and not os.path.isfile(os.path.join(root_dir, path, fxsparse)): | ||
print(f"sparse submodule {name} sparse checkout file {fxsparse} not found") | ||
testfails += 1 | ||
return testfails | ||
return testfails+localmods | ||
|
||
|
||
|
||
|
||
|
@@ -394,6 +459,7 @@ def _main_func(): | |
includelist, | ||
excludelist, | ||
verbose, | ||
force, | ||
action, | ||
) = commandline_arguments() | ||
# Get a logger for the package | ||
|
@@ -409,6 +475,7 @@ def _main_func(): | |
utils.fatal_error( | ||
"No {} found in {} or any of it's parents".format(file_name, root_dir) | ||
) | ||
|
||
root_dir = os.path.dirname(file_path) | ||
logger.info(f"root_dir is {root_dir}") | ||
gitmodules = GitModules( | ||
|
@@ -420,9 +487,9 @@ def _main_func(): | |
) | ||
retval = 0 | ||
if action == "update": | ||
submodules_update(gitmodules, root_dir) | ||
submodules_update(gitmodules, root_dir, force) | ||
elif action == "checkout": | ||
submodules_checkout(gitmodules, root_dir, fxrequired) | ||
submodules_checkout(gitmodules, root_dir, fxrequired, force) | ||
elif action == "status": | ||
submodules_status(gitmodules, root_dir) | ||
elif action == "test": | ||
|