#!/usr/bin/env python3
# -*-coding:utf-8 -*
"""
cmd = 'git clone -b <branch> --sparse https://drf-gitlab.cea.fr/svom/ECLAIRs.git'
"""
import os.path as osp
import os
import argparse
import sys
from pathlib import Path
from distutils.version import LooseVersion as l_ver
import git
from git.repo import Repo
from git import RemoteProgress
# We assume ECPI_TOKEN and ECPI_USER are well defined
# TODO: Discuss if this information must be protected in 0600 mode files
ECPI_TOKEN = os.getenv('ECPI_TOKEN')
ECPI_USER = os.getenv('ECPI_USER')
ecpi_repo_url = f'https://{ECPI_USER}:{ECPI_TOKEN}@drf-gitlab.cea.fr/svom/ECLAIRs.git'
# NOTE: git configuration uses posix paths!! The following lines do not work in windows:
# ECPI_MODULES = {
# 'dpco': osp.join("src", "ecpi", "process", "dpco"),
# 'cali': osp.join("src", "ecpi", "process", "cali"),
# 'bube': osp.join("src", "ecpi", "process", "bube"),
# 'imag': osp.join("src", "ecpi", "process", "imag"),
# 'mosa': osp.join("src", "ecpi", "process", "mosa"),
# 'spex': osp.join("src", "ecpi", "process", "spex"),
# 'simu': osp.join("src", "ecpi", "simu")
# }
ECPI_MODULES = {
'dpco': ["src/ecpi/process/dpco"],
'cali': ["src/ecpi/process/cali"],
'bube': ["src/ecpi/process/bube"],
'imag': ["src/ecpi/process/imag"],
'mosa': ["src/ecpi/process/mosa"],
'spex': ["src/ecpi/process/spex"],
'simu': ["src/ecpi/simu", "src/ecpi/extras/simu"]
}
# We implement update method
[docs]class EcpiProgress(RemoteProgress):
[docs] def update(self, op_code, cur_count, max_count=None, message=''):
if message:
print(message)
[docs]def add_args():
"""Retrieve command line options."""
parser = argparse.ArgumentParser(
add_help=True,
usage="ecpi_co ecpi_module git_branch",
description="Retrieves a ECLAIRs submodule for local development in CWD (default ECPI_HOME).",
)
parser.add_argument(
"ecpi_mod",
help="Submodule tto be retrieved from the eclairs-gp gitlab repository.",
)
parser.add_argument(
"ecpi_branch",
help="Existing branch into the eclairs-gp gitlab repository."
)
return parser.parse_args()
[docs]def check_args(args):
if args.ecpi_mod not in ECPI_MODULES:
print(f"Module [{args.ecpi_mod}] is not a retrievable module in *eclair-gp*!")
return False
if args.ecpi_branch.find('dev') != 0:
print("By convention ECPI development branches must start with 'dev[_-][0-9]{3,}'!")
return False
if args.ecpi_branch.lower() == 'dev':
print("You cannot clone [dev] branch. This branch is protected!")
return False
return True
[docs]def check_env_var(env_var, lines):
ecpi_dir_val = None
for line in lines:
# We avoid commented lines
line = line.strip()
if len(line) == 0 or line[0] in ['#', '!', ';']:
continue
if line.find(env_var) >= 0:
print(f"Found variable [{env_var}] in line [{line}]")
fields = line.split('=')
if len(fields) > 1:
ecpi_dir_val = fields[1]
# print(ecpi_root_val, lines)
ecpi_dir_val = ecpi_dir_val.replace('\n', '')
if ecpi_dir_val is None:
print('Corrupted ecpi configuration file!')
return False
env_ecpi_dir = os.getenv(env_var)
if env_ecpi_dir is None:
print('Inactive ECPI environment variables. Run "source .ect/ecpirc" in your ECPI_HOME dir!')
return False
if ecpi_dir_val.find(env_ecpi_dir) < 0:
err_msg = f"""Your environment variables do not match your ECPI configuration!
-->>> Environment variable {env_var} is [{env_ecpi_dir}]
-->>> Local configuration for {env_var} is [{ecpi_dir_val}]
"""
print(err_msg)
return False
return True
[docs]def search_config_dir_in_parents(dir_name):
pth_dir = Path(os.getcwd())
exist_dir = False
local_dir = ''
for path in pth_dir.parents:
print(f"Looking for {dir_name} in directory: {path} ...", end="")
local_dir = osp.join(path, dir_name)
if osp.isdir(local_dir):
print("Found!")
exist_dir = True
break
print("Not found!")
print("\nParsing parent folders... Done!\n")
if not exist_dir:
return None
return local_dir
[docs]def check_ecpi_config():
config_file = osp.join('.ect', 'ecpirc')
lines = []
abs_path_file = osp.join(os.getcwd(), config_file)
if osp.isfile(abs_path_file):
with open(abs_path_file, 'r') as f:
lines = f.readlines()
else:
abs_path_file = osp.join(search_config_dir_in_parents('.ect'), config_file)
if osp.isfile(abs_path_file):
with open(abs_path_file, 'r') as f:
lines = f.readlines()
if not lines:
print('It looks current working directory in not an ECPI_HOME subtree!')
return False
print("Checking environment variables to match with local ecpi configuration...")
return check_env_var('ECPI_ROOT', lines) and check_env_var('ECPI_HOME', lines)
[docs]def has_git_dir():
has_git = False
cwd = os.getcwd()
if osp.isdir(osp.join(cwd, 'local')) or osp.isdir(osp.join(cwd, '.git')):
print(f'Current directory has already a git directory. Skipping!')
has_git = True
elif search_config_dir_in_parents('.git') is not None:
print(f'Current directory is in a git subtree directory. Skipping!')
has_git = True
return has_git
[docs]def update_ecpi_module_path(args, loc_dir):
assert isinstance(loc_dir, str)
ecpi_root = os.getenv('ECPI_ROOT')
root_mod_dir = osp.dirname(
osp.join(ecpi_root, loc_dir.replace('src'+osp.sep, ''))
)
home_mod_dir = osp.dirname(osp.join(args.local_root, loc_dir))
path_string = f"""
__path__ = [
'{home_mod_dir}',
'{root_mod_dir}'
]
"""
try:
with open(osp.join(root_mod_dir, '__init__.py'), 'a') as f:
f.writelines(path_string)
except:
print(f'Error updating module file in {root_mod_dir}!')
return False
return True
# main function for an entry-point must be without arguments
# arguments must be added with the add_args function
[docs]def main():
args = add_args()
if not check_args(args):
print('Bad arguments!')
sys.exit(1)
if not check_ecpi_config():
print('Current working directory is not configured or has a wrong configuration!')
sys.exit(2)
if has_git_dir():
print('A git repository already exists in this subtree. Skipping!')
sys.exit(3)
# Checking for git version >= 2.33
git_cmd = git.Git()
git_ver = git_cmd.execute(['git', '--version'])
git_ver = git_ver.replace('git', '').replace('version', '').strip()
if l_ver(git_ver) < l_ver('2.33'):
print(f'git version is {git_ver}. You need to install at least *git 2.33.0*. Skipping!')
sys.exit(4)
print('Everything looks ok. Trying to clone git repository!\n')
try:
repo = Repo.clone_from(ecpi_repo_url,
'local',
sparse=True,
branch=args.ecpi_branch,
progress=EcpiProgress()
)
except:
print(f"Error cloning branch [{args.ecpi_branch}] into local repository. Maybe wrong name!")
sys.exit(3)
# Adding module access path to local git configuration (.git/info/sparse-checkout)
git_root = osp.dirname(repo._get_config_path('repository'))
args.__setattr__('local_root', osp.dirname(git_root))
info_file = osp.join(git_root, "info", "sparse-checkout")
if osp.isfile(info_file):
with open(info_file, 'a') as f:
for line in ECPI_MODULES[args.ecpi_mod]:
f.write(line+'\n')
else:
print(f"Error adding the submodule [{args.ecpi_mod}] into your sparse configuration file:")
print(f"--->>> {args.ecpi_branch}")
sys.exit(4)
repo.git.execute(['git', 'sparse-checkout', 'reapply'])
# Adding local module's path into global module's __path__ variable
print(f"Adding [{args.ecpi_mod}]-subdirs into your sparse configuration file")
rev = True
for loc_dir in ECPI_MODULES[args.ecpi_mod]:
print(f'Configuring {loc_dir} module')
rev = rev and update_ecpi_module_path(args, loc_dir)
if not rev:
print(f"Error adding the submodule [{args.ecpi_mod}] into __path__ variable")
sys.exit(5)
sys.exit(0)
if __name__ == '__main__':
main()