[REF] script: improve naming and translate to English

Continue variable renaming to remove Hungarian notation
prefixes (dct_, lst_) and adopt descriptive names. Translate
remaining French comments and user-facing strings to English
for consistency across the codebase.

Generated by Claude Code 2.1.72 model claude-opus-4-6

Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
This commit is contained in:
Mathieu Benoit 2026-03-10 03:45:11 -04:00
parent e27c544f02
commit 666f285fca
12 changed files with 400 additions and 414 deletions

View file

@ -25,7 +25,6 @@ _logger = logging.getLogger(__name__)
class ConfigFile:
def get_config(self, key_param: str):
# Open file and update dct_data
config_base = {}
config_override = {}
config_private = {}
@ -45,18 +44,18 @@ class ConfigFile:
merged_base_private = self.deep_merge_with_lists(
config_base, config_private, list_strategy="extend"
)
dct_data = self.deep_merge_with_lists(
merged_config = self.deep_merge_with_lists(
merged_base_private, config_override, list_strategy="extend"
)
return dct_data.get(key_param)
return merged_config.get(key_param)
def get_config_value(self, lst_params: list):
dct_data = self.get_config(lst_params[0])
for param in lst_params[1:]:
if param in dct_data.keys():
dct_data = dct_data.get(param)
return dct_data
def get_config_value(self, params: list):
config_data = self.get_config(params[0])
for param in params[1:]:
if param in config_data:
config_data = config_data.get(param)
return config_data
def get_logo_ascii_file_path(self):
return LOGO_ASCII_FILE
@ -86,7 +85,7 @@ class ConfigFile:
and isinstance(v, list)
and list_strategy == "extend"
):
# on étend : dest_list + src_list
# Extend: dest_list + src_list
result[k] = result[k] + v
elif k in result and isinstance(result[k], str):
if v:

View file

@ -74,10 +74,10 @@ class Execute:
return_status_and_output_and_command=False,
):
"""
Exécute une command et affiche la sortie en direct.
Execute a command and display its output live.
Args:
command (str): La command à exécuter (sous forme de chaîne de caractères).
command (str): The command to execute.
"""
my_env = os.environ.copy()
@ -126,8 +126,8 @@ class Execute:
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1, # Désactive la mise en tampon pour la sortie en direct
universal_newlines=True, # Pour traiter les sauts de lines correctement
bufsize=1, # Disable buffering for live output
universal_newlines=True, # Handle line breaks correctly
env=my_env,
)
@ -148,11 +148,11 @@ class Execute:
.removesuffix("\r")
)
process.wait() # Attendre la fin du process
process.wait()
exit_code = process.returncode
if process.returncode != 0 and not quiet:
print(
"La command a retourné un code d'erreur :"
"Command returned error code:"
f" {process.returncode}"
)
@ -160,23 +160,23 @@ class Execute:
if not quiet:
if "password" in command:
print(
f"Erreur : La command '{command.split(' ')[0]}'[...] n'a"
" pas été trouvée."
f"Error: Command '{command.split(' ')[0]}'[...]"
" not found."
)
else:
print(
f"Erreur : La command '{command}' n'a pas été trouvée."
f"Error: Command '{command}' not found."
)
except Exception as e:
if not quiet:
print(f"Une erreur s'est produite : {e}")
print(f"An error occurred: {e}")
process_end_time = time.time()
duration_sec = process_end_time - process_start_time
if humanize:
duration_delta = datetime.timedelta(seconds=duration_sec)
humain_time = humanize.precisedelta(duration_delta)
human_time = humanize.precisedelta(duration_delta)
if not quiet:
print(f"🏠 ⬆ Executed ({humain_time}) :")
print(f"🏠 ⬆ Executed ({human_time}) :")
else:
if not quiet:
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :")

View file

@ -184,8 +184,8 @@ def main():
dct_remote_total[key] = copy.deepcopy(value)
git_tool.generate_repo_manifest(
dct_remote=dct_remote_total,
dct_project=dct_project_total,
remotes_config=dct_remote_total,
projects_config=dct_project_total,
output=config.output,
default_remote=default_remote_total,
)

View file

@ -97,8 +97,8 @@ def main():
git_tool.generate_repo_manifest(
lst_repo_organization,
output=f"{config.dir}{config.manifest}",
dct_remote=dct_remote,
dct_project=dct_project,
remotes_config=dct_remote,
projects_config=dct_project,
keep_original=config.keep_origin,
**kwargs,
)

View file

@ -125,8 +125,8 @@ def main():
filter_group=filter_group,
extra_path=config.extra_addons_path,
ignore_odoo_path=config.ignore_odoo_path,
lst_add_repo=lst_add_repo,
lst_whitelist=lst_whitelist,
add_repos=lst_add_repo,
whitelist=lst_whitelist,
)

View file

@ -128,7 +128,7 @@ class GitTool:
url, _, url_git = self.get_url(url_https)
url_https_organization = url_https[: url_https.rfind("/")]
d = {
repo_data = {
"url": url,
"url_git": url_git,
"url_https": url_https,
@ -146,8 +146,8 @@ class GitTool:
"sub_path": sub_path,
}
if get_obj:
return RepoAttrs(**d)
return d
return RepoAttrs(**repo_data)
return repo_data
def get_repo_info(
self,
@ -184,7 +184,7 @@ class GitTool:
}]
"""
filename = os.path.join(repo_path, ".gitmodules")
lst_repo = []
repos = []
with open(filename) as file:
txt = file.readlines()
@ -204,7 +204,7 @@ class GitTool:
"relative_path": os.path.join(repo_path, path),
"name": name,
}
lst_repo.append(data)
repos.append(data)
name = line[12:-3]
first_execution = False
continue
@ -229,7 +229,7 @@ class GitTool:
"relative_path": os.path.join(repo_path, path),
"name": name,
}
lst_repo.append(data)
repos.append(data)
if add_root:
repo_root = Repo(repo_path)
@ -243,10 +243,10 @@ class GitTool:
"path": repo_path,
"name": "",
}
lst_repo.insert(0, data)
repos.insert(0, data)
# Sort
lst_repo = sorted(lst_repo, key=lambda k: k.get("name"))
return lst_repo
repos = sorted(repos, key=lambda k: k.get("name"))
return repos
def get_repo_info_manifest_xml(
self, repo_path: str = ".", add_root: bool = False, filter_group=None
@ -266,7 +266,7 @@ class GitTool:
"name": name of the submodule
}]
"""
lst_filter_group = filter_group.split(",") if filter_group else []
filter_groups = filter_group.split(",") if filter_group else []
manifest_file = self.get_manifest_file(repo_path=repo_path)
if not manifest_file:
return []
@ -275,30 +275,29 @@ class GitTool:
filename = manifest_file
else:
filename = os.path.normpath(os.path.join(repo_path, manifest_file))
lst_repo = []
repos = []
with open(filename) as xml:
xml_as_string = xml.read()
xml_dict = xmltodict.parse(xml_as_string)
dct_manifest = xml_dict.get("manifest")
if not dct_manifest:
manifest_data = xml_dict.get("manifest")
if not manifest_data:
return []
if dct_manifest.get("default"):
default_remote = dct_manifest.get("default").get("@remote")
if manifest_data.get("default"):
default_remote = manifest_data.get("default").get("@remote")
else:
default_remote = None
lst_remote = dct_manifest.get("remote")
if type(lst_remote) is dict:
lst_remote = [lst_remote]
lst_project = dct_manifest.get("project")
if type(lst_project) is dict:
lst_project = [lst_project]
dct_remote = {a.get("@name"): a.get("@fetch") for a in lst_remote}
for project in lst_project:
remotes = manifest_data.get("remote")
if type(remotes) is dict:
remotes = [remotes]
projects = manifest_data.get("project")
if type(projects) is dict:
projects = [projects]
remotes_by_name = {a.get("@name"): a.get("@fetch") for a in remotes}
for project in projects:
groups = project.get("@groups")
lst_group = groups.split(",") if groups else []
# Continue if lst_filter exist and group in filter
for group in lst_group:
if lst_filter_group and group not in lst_filter_group:
project_groups = groups.split(",") if groups else []
for group in project_groups:
if filter_groups and group not in filter_groups:
continue
else:
break
@ -308,10 +307,10 @@ class GitTool:
# get name and remote .git
path = project.get("@path")
name = path
url_prefix = dct_remote.get(project.get("@remote"))
url_prefix = remotes_by_name.get(project.get("@remote"))
if not url_prefix:
# get default remote
url_prefix = dct_remote.get(default_remote)
url_prefix = remotes_by_name.get(default_remote)
url = f"{url_prefix}{project.get('@name')}"
url, url_https, url_git = self.get_url(url)
data = {
@ -323,7 +322,7 @@ class GitTool:
"name": name,
"group": groups,
}
lst_repo.append(data)
repos.append(data)
if add_root:
repo_root = Repo(repo_path)
@ -346,10 +345,10 @@ class GitTool:
"path": repo_path,
"name": "",
}
lst_repo.insert(0, data)
repos.insert(0, data)
# Sort
lst_repo = sorted(lst_repo, key=lambda k: k.get("name"))
return lst_repo
repos = sorted(repos, key=lambda k: k.get("name"))
return repos
def get_manifest_xml_info(
self, repo_path: str = ".", filename=None, add_root: bool = False
@ -368,25 +367,25 @@ class GitTool:
with open(filename) as xml:
xml_as_string = xml.read()
xml_dict = xmltodict.parse(xml_as_string)
dct_manifest = xml_dict.get("manifest")
if not dct_manifest:
manifest_data = xml_dict.get("manifest")
if not manifest_data:
return {}, {}, None
default_remote = dct_manifest.get("default")
lst_remote = dct_manifest.get("remote")
if type(lst_remote) is dict:
lst_remote = [lst_remote]
lst_project = dct_manifest.get("project")
if type(lst_project) is dict:
lst_project = [lst_project]
if lst_remote:
dct_remote = {a.get("@name"): a for a in lst_remote}
default_remote = manifest_data.get("default")
remotes = manifest_data.get("remote")
if type(remotes) is dict:
remotes = [remotes]
projects = manifest_data.get("project")
if type(projects) is dict:
projects = [projects]
if remotes:
remotes_by_name = {a.get("@name"): a for a in remotes}
else:
dct_remote = {}
if lst_project:
dct_project = {a.get("@name"): a for a in lst_project}
remotes_by_name = {}
if projects:
projects_by_name = {a.get("@name"): a for a in projects}
else:
dct_project = {}
return dct_remote, dct_project, default_remote
projects_by_name = {}
return remotes_by_name, projects_by_name, default_remote
@staticmethod
def get_project_config(repo_path="."):
@ -403,20 +402,20 @@ class GitTool:
txt = file.readlines()
txt = [a[:-1] for a in txt if "=" in a]
lst_filter = [EL_GITHUB_TOKEN]
dct_config = {}
filter_keys = [EL_GITHUB_TOKEN]
config = {}
# Take filtered value and get bash string values
for f in lst_filter:
for v in txt:
if f in v:
lst_v = v.split("=")
if len(lst_v) > 1:
dct_config[EL_GITHUB_TOKEN] = v.split("=")[1][1:-1]
return dct_config
for key in filter_keys:
for line in txt:
if key in line:
parts = line.split("=")
if len(parts) > 1:
config[EL_GITHUB_TOKEN] = line.split("=")[1][1:-1]
return config
@staticmethod
def open_repo_web_browser(dct_repo):
url = dct_repo.get("url_https")
def open_repo_web_browser(repo_info):
url = repo_info.get("url_https")
if url:
webbrowser.open_new_tab(url)
@ -426,31 +425,31 @@ class GitTool:
filter_group=None,
extra_path=None,
ignore_odoo_path=None,
lst_add_repo=None,
lst_whitelist=None,
add_repos=None,
whitelist=None,
):
filename_locally = os.path.join(repo_path, "script/generate_config.sh")
if not filter_group:
filter_group = self.odoo_version_long
lst_repo_origin = self.get_repo_info(
all_repos = self.get_repo_info(
repo_path=repo_path, filter_group=filter_group
)
if lst_whitelist:
lst_repo = []
for repo in lst_repo_origin:
if whitelist:
repos = []
for repo in all_repos:
if (
repo.get("path") in lst_whitelist
or repo.get("path") in lst_add_repo
repo.get("path") in whitelist
or repo.get("path") in add_repos
):
lst_repo.append(repo)
repos.append(repo)
else:
lst_repo = lst_repo_origin
lst_result = []
if not lst_repo:
repos = all_repos
results = []
if not repos:
print(
f"{Fore.YELLOW}WARNING{Style.RESET_ALL}: List of repo is empty when write generate_config."
)
for repo in lst_repo:
for repo in repos:
update_repo = repo.get("path")
# Exception, ignore addons/OCA_web and root
if update_repo in ["addons/OCA_web", "odoo", "image_db"]:
@ -472,14 +471,14 @@ class GitTool:
# Ignore repo if not starting by addons
# if update_repo.startswith("addons"):
# lst_result.append(str_repo)
lst_result.append(str_repo)
results.append(str_repo)
if extra_path:
for each_extra_path in extra_path.strip().split(","):
str_repo = (
f' printf "{each_extra_path}," >> '
'"${EL_CONFIG_FILE}"\n'
)
lst_result.append(str_repo)
results.append(str_repo)
with open(filename_locally) as file:
all_lines = file.readlines()
# search place to add/replace lines
@ -501,10 +500,10 @@ class GitTool:
and 'if [[ ${EL_MINIMAL_ADDONS} = "False" ]]; then\n' == line
):
index_find = index + 1
for insert_line in lst_result:
for insert_line in results:
all_lines.insert(index_find, insert_line)
index_find += 1
if not lst_result:
if not results:
all_lines.insert(index_find, '\tprintf ""\n')
index_find += 1
find_index = True
@ -531,37 +530,37 @@ class GitTool:
def generate_repo_manifest(
self,
lst_repo: List[RepoAttrs] = [],
repo_list: List[RepoAttrs] = [],
output: str = "",
dct_remote={},
dct_project={},
remotes_config={},
projects_config={},
default_remote=None,
keep_original=False,
default_branch=None,
):
"""
Generate repo manifest
:param lst_repo: optional, update manifest with list_repo
:param repo_list: optional, update manifest with list_repo
:param output: filename to write output
:param dct_remote: dict of remote information
:param dct_project: dict of project information
:param remotes_config: dict of remote information
:param projects_config: dict of project information
:param default_remote: dict of default remote
:param keep_original: if True, can manage multiple organization with same name,
but with different fetch url
:param default_branch: default branch name
:return:
"""
lst_remote = []
lst_remote_name = []
lst_project = []
lst_project_name = []
lst_default = []
remote_entries = []
remote_names = []
project_entries = []
project_names = []
default_entries = []
# Fill with configuration
for dct_value in dct_remote.values():
for dct_value in remotes_config.values():
remote_name = dct_value.get("@name")
if remote_name not in lst_remote_name:
lst_remote.append(
if remote_name not in remote_names:
remote_entries.append(
OrderedDict(
[
("@name", remote_name),
@ -569,45 +568,45 @@ class GitTool:
]
)
)
lst_remote_name.append(remote_name)
for dct_value in dct_project.values():
remote_names.append(remote_name)
for dct_value in projects_config.values():
lst_project_info = [
("@name", dct_value.get("@name")),
("@path", dct_value.get("@path")),
]
if "@remote" in dct_value.keys():
if "@remote" in dct_value:
lst_project_info.append(("@remote", dct_value.get("@remote")))
if "@revision" in dct_value.keys():
if "@revision" in dct_value:
lst_project_info.append(
("@revision", dct_value.get("@revision"))
)
if "@clone-depth" in dct_value.keys():
if "@clone-depth" in dct_value:
lst_project_info.append(
("@clone-depth", dct_value.get("@clone-depth"))
)
if "@groups" in dct_value.keys():
if "@groups" in dct_value:
lst_project_info.append(("@groups", dct_value.get("@groups")))
if "@upstream" in dct_value.keys():
if "@upstream" in dct_value:
lst_project_info.append(
("@upstream", dct_value.get("@upstream"))
)
if "@dest-branch" in dct_value.keys():
if "@dest-branch" in dct_value:
lst_project_info.append(
("@dest-branch", dct_value.get("@dest-branch"))
)
lst_project.append(OrderedDict(lst_project_info))
lst_project_name.append(dct_value.get("@name"))
project_entries.append(OrderedDict(lst_project_info))
project_names.append(dct_value.get("@name"))
for repo in lst_repo:
for repo in repo_list:
if not repo.is_submodule:
# Default
if lst_default:
if default_entries:
raise Exception(
"Cannot have many root repo. "
"Validate why 2 or more is not submodule."
)
lst_default.append(
default_entries.append(
OrderedDict(
[
("@remote", repo.original_organization),
@ -620,7 +619,7 @@ class GitTool:
else:
if (
keep_original
and repo.project_name not in dct_project.keys()
and repo.project_name not in projects_config
):
# Exception, create a new remote to keep tracking on original
original_organization = (
@ -629,8 +628,8 @@ class GitTool:
else:
original_organization = repo.original_organization
# Add remote, only unique remote
if original_organization not in lst_remote_name:
lst_remote.append(
if original_organization not in remote_names:
remote_entries.append(
OrderedDict(
[
("@name", original_organization),
@ -638,10 +637,10 @@ class GitTool:
]
)
)
lst_remote_name.append(repo.original_organization)
remote_names.append(repo.original_organization)
# Add project, only unique project
if repo.project_name not in lst_project_name:
lst_project_name.append(repo.project_name)
if repo.project_name not in project_names:
project_names.append(repo.project_name)
lst_project_info = [
("@name", repo.project_name),
("@path", repo.path),
@ -657,10 +656,10 @@ class GitTool:
lst_project_info.append(("@groups", "addons"))
else:
lst_project_info.append(("@groups", "odoo"))
lst_project.append(OrderedDict(lst_project_info))
project_entries.append(OrderedDict(lst_project_info))
if default_remote and not lst_default:
lst_default.append(
if default_remote and not default_entries:
default_entries.append(
OrderedDict(
[
("@remote", default_remote.get("@remote")),
@ -672,29 +671,29 @@ class GitTool:
)
# Order in alphabetic
lst_order_remote = sorted(lst_remote, key=lambda key: key.get("@name"))
lst_order_default = sorted(
lst_default, key=lambda key: key.get("@remote")
sorted_remotes = sorted(remote_entries, key=lambda key: key.get("@name"))
sorted_defaults = sorted(
default_entries, key=lambda key: key.get("@remote")
)
lst_order_project = sorted(
lst_project, key=lambda key: key.get("@name") + key.get("@path")
sorted_projects = sorted(
project_entries, key=lambda key: key.get("@name") + key.get("@path")
)
dct_repo = OrderedDict(
manifest_dict = OrderedDict(
[
(
"manifest",
OrderedDict(
[
("remote", lst_order_remote),
("default", lst_order_default),
("project", lst_order_project),
("remote", sorted_remotes),
("default", sorted_defaults),
("project", sorted_projects),
]
),
)
]
)
str_xml_text = xmltodict.unparse(dct_repo, pretty=True)
str_xml_text = xmltodict.unparse(manifest_dict, pretty=True)
pos_insert = str_xml_text.rfind("</remote>")
if pos_insert >= 0:
@ -730,12 +729,12 @@ class GitTool:
print(str_xml_text + "\n")
def generate_git_modules(
self, lst_repo: List[RepoAttrs], repo_path: str = "."
self, repo_list: List[RepoAttrs], repo_path: str = "."
):
lst_modules = []
for repo in lst_repo:
modules = []
for repo in repo_list:
if repo.is_submodule:
lst_modules.append(
modules.append(
f'[submodule "{repo.path}"]\n'
f"\turl = {repo.url_https}\n"
f"\tpath = {repo.path}\n"
@ -743,7 +742,7 @@ class GitTool:
# create file
with open(os.path.join(repo_path, ".gitmodules"), mode="w") as file:
file.writelines(lst_modules)
file.writelines(modules)
def get_source_repo_addons(self, repo_path=".", add_repo_root=False):
"""
@ -761,7 +760,7 @@ class GitTool:
}]
"""
file_name = os.path.join(repo_path, SOURCE_REPO_ADDONS_FILE)
lst_result = []
results = []
if add_repo_root:
# TODO what to do if origin not exist?
repo = Repo(repo_path)
@ -769,7 +768,7 @@ class GitTool:
repo_info = self.get_transformed_repo_info_from_url(
url, repo_path=repo_path, get_obj=False, is_submodule=False
)
lst_result.append(repo_info)
results.append(repo_info)
with open(file_name) as file:
all_lines = file.readlines()
if all_lines:
@ -812,8 +811,8 @@ class GitTool:
revision=revision,
clone_depth=clone_depth,
)
lst_result.append(repo_info)
return lst_result
results.append(repo_info)
return results
def get_manifest_file(self, repo_path: str = "."):
"""
@ -852,23 +851,20 @@ class GitTool:
:param sync_with_submodule: force use submodule with repo_compare_to
:return: (list of matches, list of missing, list of more)
"""
lst_repo_info_actual = self.get_repo_info_manifest_xml(actual_repo)
dct_repo_info_actual = {a.get("name"): a for a in lst_repo_info_actual}
# set_actual = set(dct_repo_info_actual.keys())
# set_actual_repo = set(
# [a[a.find("_") + 1:] for a in dct_repo_info_actual.keys()])
actual_repos = self.get_repo_info_manifest_xml(actual_repo)
actual_by_name = {a.get("name"): a for a in actual_repos}
dct_repo_info_actual_adapted = {
actual_adapted = {
key[key.find("_") + 1 :]: item
for key, item in dct_repo_info_actual.items()
for key, item in actual_by_name.items()
}
set_actual_repo = set(dct_repo_info_actual_adapted.keys())
set_actual_repo = set(actual_adapted.keys())
lst_repo_info_compare = self.get_repo_info(
compare_repos = self.get_repo_info(
repo_compare_to, is_manifest=not sync_with_submodule
)
if force_normalize_compare:
for repo_info in lst_repo_info_compare:
for repo_info in compare_repos:
url_https = repo_info.get("url_https")
url_split = url_https.split("/")
organization = url_split[3]
@ -879,59 +875,55 @@ class GitTool:
name = f"{repo_name}"
repo_info["name"] = name
dct_repo_info_compare = {
a.get("name"): a for a in lst_repo_info_compare
compare_by_name = {
a.get("name"): a for a in compare_repos
}
set_compare = set(dct_repo_info_compare.keys())
set_compare = set(compare_by_name.keys())
# TODO finish the match
# lst_same_name = set_actual.intersection(set_compare)
# lst_missing_name = set_compare.difference(set_actual)
lst_same_name_normalize = set_actual_repo.intersection(set_compare)
lst_missing_name_normalize = set_compare.difference(set_actual_repo)
lst_over_name_normalize = set_actual_repo.difference(set_compare)
same_names = set_actual_repo.intersection(set_compare)
missing_names = set_compare.difference(set_actual_repo)
extra_names = set_actual_repo.difference(set_compare)
print(
f"Has {len(lst_same_name_normalize)} sames, "
f"{len(lst_missing_name_normalize)} missing, "
f"{len(lst_over_name_normalize)} more."
f"Has {len(same_names)} sames, "
f"{len(missing_names)} missing, "
f"{len(extra_names)} more."
)
lst_match = []
for key in lst_same_name_normalize:
lst_match.append(
(dct_repo_info_actual_adapted[key], dct_repo_info_compare[key])
matches = []
for key in same_names:
matches.append(
(actual_adapted[key], compare_by_name[key])
)
return lst_match, lst_missing_name_normalize, lst_over_name_normalize
return matches, missing_names, extra_names
@staticmethod
def sync_to(result, checkout_when_diff=False):
lst_compare_repo_info, lst_missing_info, lst_over_info = result
total = len(lst_missing_info)
compared_repos, missing_repos, extra_repos = result
total = len(missing_repos)
if total:
print(f"\nList of missing : {total}")
i = 0
for info in lst_missing_info:
for info in missing_repos:
i += 1
print(f"Nb element {i}/{total}")
print(f"Missing '{info}'")
total = len(lst_over_info)
total = len(extra_repos)
if total:
print(f"\nList of over : {total}")
i = 0
for info in lst_over_info:
for info in extra_repos:
i += 1
print(f"Nb element {i}/{total}")
print(f"Missing '{info}'")
total = len(lst_compare_repo_info)
total = len(compared_repos)
print(f"\nList of normalize : {total}")
lst_same = []
lst_diff = []
same = []
diffs = []
i = 0
for original, compare_to in lst_compare_repo_info:
for original, compare_to in compared_repos:
i += 1
print(f"Nb element {i}/{total}")
repo_original = Repo(original.get("relative_path"))
@ -943,7 +935,7 @@ class GitTool:
f"DIFF - {original.get('name')} - O {commit_original} - "
f"R {commit_compare}"
)
lst_diff.append((original, compare_to))
diffs.append((original, compare_to))
if checkout_when_diff:
# Update all remote
for remote in repo_original.remotes:
@ -954,8 +946,8 @@ class GitTool:
repo_original.git.checkout(commit_compare)
else:
print(f"SAME - {original.get('name')}")
lst_same.append((original, compare_to))
print(f"finish same {len(lst_same)}, diff {len(lst_diff)}")
same.append((original, compare_to))
print(f"finish same {len(same)}, diff {len(diffs)}")
@staticmethod
def add_and_fetch_remote(

View file

@ -6,7 +6,7 @@ import sys
import psutil
STOP_PARENT_KILL = ["./odoo_bin.sh", "./run.sh"]
WRAPPER_SCRIPT_NAMES = ["./odoo_bin.sh", "./run.sh"]
# Processes that must never be killed — killing these
# can crash the desktop session or the system.
@ -77,12 +77,12 @@ def choose_target(chain, parent_depth):
if not chain:
return None
parent_chain = []
for pid in chain:
parent_chain.append(pid)
for str_to_stop in STOP_PARENT_KILL:
if str_to_stop in pid.cmdline():
return pid, parent_chain
ancestors = []
for proc in chain:
ancestors.append(proc)
for wrapper in WRAPPER_SCRIPT_NAMES:
if wrapper in proc.cmdline():
return proc, ancestors
return chain[parent_depth - 1], [chain[parent_depth - 1]]
@ -164,12 +164,12 @@ def main():
args = ap.parse_args()
if not (1 <= args.port <= 65535):
print("Port invalide (1-65535).", file=sys.stderr)
print("Invalid port (1-65535).", file=sys.stderr)
return 2
pids = find_listeners(args.port)
if not pids:
print(f"Aucun process en LISTEN sur {args.port}.")
print(f"No process listening on port {args.port}.")
return 1
for pid in pids:
@ -177,7 +177,7 @@ def main():
if not chain:
continue
target, lst_target = choose_target(chain, args.parent_depth)
target, target_chain = choose_target(chain, args.parent_depth)
print(f"\nListener PID {pid} ancestry:")
for i, p in enumerate(chain):
@ -189,14 +189,14 @@ def main():
if target.pid == 1:
print(
"Refus: la cible est PID 1 (systemd)."
" Utilise plutôt systemctl pour arrêter"
" le service.",
"Refused: target is PID 1 (systemd)."
" Use systemctl to stop the service"
" instead.",
)
continue
if target.name() in PROTECTED_NAMES:
print(
f"Refus: le process '{target.name()}' semble être protégé et dangereux à être arrêter.",
f"Refused: process '{target.name()}' is protected and dangerous to kill.",
)
continue
@ -208,9 +208,9 @@ def main():
while not has_response and not ignore_kill:
confirm = (
input(
f"Tuer ce processus index {args.parent_depth} (enter) ou mettre "
f"l'index [0 to {len(chain) - 1}] du "
f"process à tuer, (c/C) pour annuler : \n"
f"Kill process at index {args.parent_depth} (enter) or enter "
f"index [0 to {len(chain) - 1}] of "
f"process to kill, (c/C) to cancel: \n"
)
.strip()
.lower()
@ -234,7 +234,7 @@ def main():
alive = kill_tree(target, force=args.force)
if alive:
print(
"Toujours vivants:",
"Still alive:",
", ".join(str(p.pid) for p in alive),
)
else:
@ -244,7 +244,7 @@ def main():
kill_process(target, force=args.force)
except psutil.AccessDenied as e:
print(
f"AccessDenied: {e} (lance le script avec sudo).",
f"AccessDenied: {e} (run the script with sudo).",
file=sys.stderr,
)

View file

@ -84,7 +84,7 @@ class TODO:
def __init__(self):
self.dir_path = None
self.kdbx = None
self.file_path = None
self.selected_file_path = None
self.config_file = config_file.ConfigFile()
self.execute = execute.Execute()
@ -173,29 +173,29 @@ class TODO:
if self.kdbx:
return self.kdbx
# Open file
chemin_fichier_kdbx = self.config_file.get_config_value(
kdbx_file_path = self.config_file.get_config_value(
["kdbx", "path"]
)
if not chemin_fichier_kdbx:
if not kdbx_file_path:
root = tk.Tk()
root.withdraw() # Hide the main window
chemin_fichier_kdbx = filedialog.askopenfilename(
kdbx_file_path = filedialog.askopenfilename(
title="Select a File",
filetypes=(("KeepassX files", "*.kdbx"),),
)
if not chemin_fichier_kdbx:
if not kdbx_file_path:
_logger.error(
f"KDBX is not configured, please fill {self.config_file.CONFIG_FILE}"
)
return
mot_de_passe_kdbx = self.config_file.get_config_value(
kdbx_password = self.config_file.get_config_value(
["kdbx", "password"]
)
if not mot_de_passe_kdbx:
mot_de_passe_kdbx = getpass.getpass(prompt=t("enter_password"))
if not kdbx_password:
kdbx_password = getpass.getpass(prompt=t("enter_password"))
kp = PyKeePass(chemin_fichier_kdbx, password=mot_de_passe_kdbx)
kp = PyKeePass(kdbx_file_path, password=kdbx_password)
if kp:
self.kdbx = kp
@ -213,10 +213,10 @@ class TODO:
kp = self.get_kdbx()
if not kp:
return
nom_configuration = self.config_file.get_config_value(
config_name = self.config_file.get_config_value(
["kdbx_config", "openai", "kdbx_key"]
)
entry = kp.find_entries_by_title(nom_configuration, first=True)
entry = kp.find_entries_by_title(config_name, first=True)
client = openai.OpenAI(api_key=entry.password)
prompt_update = status
@ -256,7 +256,7 @@ class TODO:
if status is not False:
return
elif status == "2":
status = self.prompt_execute_fonction()
status = self.prompt_execute_function()
if status is not False:
return
elif status == "3":
@ -370,7 +370,7 @@ class TODO:
# TODO maybe update q to only install erplibre from install_locally
# TODO problem installing with q, the script depend on odoo
key_i = 0
dct_cmd_intern_begin = {
commands_begin = {
"q": (
"q",
"q: ERPLibre only with system python without Odoo",
@ -391,43 +391,43 @@ class TODO:
f"0: {t('menu_quit')}",
),
}
dct_final_cmd_intern = {}
lst_version, lst_version_installed, odoo_installed_version = (
commands_end = {}
versions, installed_versions, odoo_installed_version = (
self.get_odoo_version()
)
for dct_version in lst_version[::-1]:
for version_info in versions[::-1]:
key_i += 1
key_s = str(key_i)
label = f"{key_s}: Odoo {dct_version.get('odoo_version')}"
label = f"{key_s}: Odoo {version_info.get('odoo_version')}"
odoo_version = f"odoo{dct_version.get('odoo_version')}"
if odoo_version in lst_version_installed:
odoo_version = f"odoo{version_info.get('odoo_version')}"
if odoo_version in installed_versions:
label += " - Installed"
if odoo_version == odoo_installed_version:
label += " - Actual"
if dct_version.get("default"):
if version_info.get("default"):
label += " - Default"
if dct_version.get("is_deprecated"):
if version_info.get("is_deprecated"):
label += " - Deprecated"
erplibre_version = dct_version.get("erplibre_version")
dct_cmd_intern_begin[key_s] = (
erplibre_version = version_info.get("erplibre_version")
commands_begin[key_s] = (
key_s,
label,
f"./script/version/update_env_version.py --erplibre_version {erplibre_version} --install_dev",
)
# Add final command
dct_cmd_intern = {**dct_cmd_intern_begin, **dct_final_cmd_intern}
install_commands = {**commands_begin, **commands_end}
# Show command
odoo_version_input = ""
while odoo_version_input not in dct_cmd_intern.keys():
while odoo_version_input not in install_commands:
if odoo_version_input:
print(f"{t('error_value')} '{odoo_version_input}'")
str_input_dyn_odoo_version = (
f"💬 {t('choose_version')}\n\t"
+ "\n\t".join([a[1] for a in dct_cmd_intern.values()])
+ "\n\t".join([a[1] for a in install_commands.values()])
+ f"\n{t('selection')}"
)
odoo_version_input = (
@ -437,7 +437,7 @@ class TODO:
if odoo_version_input == "0":
return
cmd_intern = dct_cmd_intern.get(odoo_version_input)[2]
cmd_intern = install_commands.get(odoo_version_input)[2]
print(f"{t('will_execute')}\n{cmd_intern}")
# TODO use external script to detect terminal to use on system
@ -454,12 +454,12 @@ class TODO:
self.restart_script(str(e))
def execute_from_configuration(
self, dct_instance, exec_run_db=False, ignore_makefile=False
self, instance, exec_run_db=False, ignore_makefile=False
):
# exec_run_db need argument database
kdbx_key = dct_instance.get("kdbx_key")
odoo_user = dct_instance.get("user")
odoo_password = dct_instance.get("password")
kdbx_key = instance.get("kdbx_key")
odoo_user = instance.get("user")
odoo_password = instance.get("password")
if kdbx_key:
extra_cmd_web_login = self.kdbx_get_extra_command_user(kdbx_key)
@ -471,7 +471,7 @@ class TODO:
else:
extra_cmd_web_login = ""
makefile_cmd = dct_instance.get("makefile_cmd")
makefile_cmd = instance.get("makefile_cmd")
if makefile_cmd and not ignore_makefile:
status = self.execute.exec_command_live(
f"make {makefile_cmd}",
@ -485,30 +485,30 @@ class TODO:
return
if exec_run_db:
db_name = dct_instance.get("database")
db_name = instance.get("database")
self.prompt_execute_selenium_and_run_db(
db_name, extra_cmd_web_login=extra_cmd_web_login
)
command = dct_instance.get("command")
command = instance.get("command")
if command:
self.prompt_execute_selenium(
command=command, extra_cmd_web_login=extra_cmd_web_login
)
callback = dct_instance.get("callback")
callback = instance.get("callback")
if callback:
callback(dct_instance)
callback(instance)
def fill_help_info(self, lst_choice):
def fill_help_info(self, choices):
help_info = t("command") + "\n"
help_end = f"[0] {t('back')}\n"
for i, dct_instance in enumerate(lst_choice):
desc_key = dct_instance.get("prompt_description_key")
for i, instance in enumerate(choices):
desc_key = instance.get("prompt_description_key")
if desc_key:
desc = t(desc_key)
else:
desc = dct_instance["prompt_description"]
desc = instance["prompt_description"]
help_info += f"[{i + 1}] " + desc + "\n"
help_info += help_end
return help_info
@ -517,24 +517,24 @@ class TODO:
# TODO proposer le déploiement à distance
# TODO proposer l'exécution de docker
# TODO proposer la création de docker
lst_choice = self.config_file.get_config("instance")
init_len = len(lst_choice)
choices = self.config_file.get_config("instance")
init_len = len(choices)
# Support mobile ERPLibre
if os.path.exists(MOBILE_HOME_PATH):
dct_upgrade_odoo_database = {
menu_entry = {
"prompt_description": t("mobile_compile_run"),
"callback": self.callback_make_mobile_home,
}
lst_choice.append(dct_upgrade_odoo_database)
choices.append(menu_entry)
# Support custom database to execute
dct_upgrade_odoo_database = {
menu_entry = {
"prompt_description": t("choose_database"),
"callback": self.callback_execute_custom_database,
}
lst_choice.insert(0, dct_upgrade_odoo_database)
help_info = self.fill_help_info(lst_choice)
choices.insert(0, menu_entry)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -548,27 +548,27 @@ class TODO:
if 1 < int_cmd <= init_len:
cmd_no_found = False
status = click.confirm(t("new_instance_confirm"))
dct_instance = lst_choice[int_cmd - 1]
instance = choices[int_cmd - 1]
self.execute_from_configuration(
dct_instance,
instance,
exec_run_db=True,
ignore_makefile=not bool(status),
)
elif int_cmd <= len(lst_choice) or 1 == int_cmd:
elif int_cmd <= len(choices) or 1 == int_cmd:
cmd_no_found = False
# Execute dynamic instance
dct_instance = lst_choice[int_cmd - 1]
instance = choices[int_cmd - 1]
self.execute_from_configuration(
dct_instance,
instance,
)
except ValueError:
pass
if cmd_no_found:
print(t("cmd_not_found"))
def prompt_execute_fonction(self):
lst_choice = self.config_file.get_config("function")
help_info = self.fill_help_info(lst_choice)
def prompt_execute_function(self):
choices = self.config_file.get_config("function")
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -579,10 +579,10 @@ class TODO:
cmd_no_found = True
try:
int_cmd = int(status)
if 0 < int_cmd <= len(lst_choice):
if 0 < int_cmd <= len(choices):
cmd_no_found = False
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
instance = choices[int_cmd - 1]
self.execute_from_configuration(instance)
except ValueError:
pass
if cmd_no_found:
@ -599,35 +599,35 @@ class TODO:
# TODO faire la mise à jour de ERPLibre
# TODO faire l'upgrade d'un odoo vers un autre
lst_choice = self.config_file.get_config("update_from_makefile")
dct_upgrade_odoo_database = {
choices = self.config_file.get_config("update_from_makefile")
menu_entry = {
"prompt_description": t("upgrade_odoo_migration"),
}
lst_choice.append(dct_upgrade_odoo_database)
dct_upgrade_poetry = {
choices.append(menu_entry)
poetry_entry = {
"prompt_description": t("upgrade_poetry_dependency"),
}
lst_choice.append(dct_upgrade_poetry)
help_info = self.fill_help_info(lst_choice)
choices.append(poetry_entry)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == str(len(lst_choice) - 1):
elif status == str(len(choices) - 1):
upgrade = todo_upgrade.TodoUpgrade(self)
upgrade.execute_odoo_upgrade()
elif status == str(len(lst_choice)):
elif status == str(len(choices)):
self.upgrade_poetry()
else:
cmd_no_found = True
try:
int_cmd = int(status) - 1
if 0 < int_cmd <= len(lst_choice):
if 0 < int_cmd <= len(choices):
cmd_no_found = False
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
instance = choices[int_cmd - 1]
self.execute_from_configuration(instance)
except ValueError:
pass
if cmd_no_found:
@ -647,45 +647,45 @@ class TODO:
# [0] Retour
# """
lst_choice = self.config_file.get_config("code_from_makefile")
choices = self.config_file.get_config("code_from_makefile")
dct_upgrade_odoo_database = {
menu_entry = {
"prompt_description": t("open_shell"),
}
lst_choice.append(dct_upgrade_odoo_database)
choices.append(menu_entry)
dct_upgrade_odoo_database = {
menu_entry = {
"prompt_description": t("upgrade_module"),
}
lst_choice.append(dct_upgrade_odoo_database)
choices.append(menu_entry)
lst_choice.append(
choices.append(
{
"prompt_description": t("debug"),
}
)
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == str(len(lst_choice)):
elif status == str(len(choices)):
self.debug_ide()
elif status == str(len(lst_choice) - 1):
elif status == str(len(choices) - 1):
self.upgrade_module()
elif status == str(len(lst_choice) - 2):
elif status == str(len(choices) - 2):
self.open_shell_on_database()
else:
cmd_no_found = True
try:
int_cmd = int(status)
if 0 < int_cmd <= len(lst_choice):
if 0 < int_cmd <= len(choices):
cmd_no_found = False
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
instance = choices[int_cmd - 1]
self.execute_from_configuration(instance)
except ValueError:
pass
if cmd_no_found:
@ -693,16 +693,16 @@ class TODO:
def prompt_execute_git(self):
print(f"🤖 {t('git_manage')}")
lst_choice = [
choices = [
{"prompt_description": t("git_local_server")},
]
# Append config-driven entries
lst_config = self.config_file.get_config("git_from_makefile")
if lst_config:
lst_choice.extend(lst_config)
config_entries = self.config_file.get_config("git_from_makefile")
if config_entries:
choices.extend(config_entries)
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -715,10 +715,10 @@ class TODO:
cmd_no_found = True
try:
int_cmd = int(status)
if 0 < int_cmd <= len(lst_choice):
if 0 < int_cmd <= len(choices):
cmd_no_found = False
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
instance = choices[int_cmd - 1]
self.execute_from_configuration(instance)
except ValueError:
pass
if cmd_no_found:
@ -726,11 +726,11 @@ class TODO:
def prompt_execute_git_local_server(self):
print(f"🤖 {t('git_repo_manage')}")
lst_choice = [
choices = [
{"prompt_description": t("git_repo_deploy_local")},
{"prompt_description": t("git_repo_deploy_production")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -751,14 +751,14 @@ class TODO:
else t("git_mode_local")
)
print(f"🤖 {mode}")
lst_choice = [
choices = [
{"prompt_description": t("git_action_all")},
{"prompt_description": t("git_action_init")},
{"prompt_description": t("git_action_remote")},
{"prompt_description": t("git_action_push")},
{"prompt_description": t("git_action_serve")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -807,10 +807,10 @@ class TODO:
def prompt_execute_gpt_code(self):
print(f"🤖 {t('gpt_code_manage')}")
lst_choice = [
choices = [
{"prompt_description": t("gpt_code_claude_commit")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -863,13 +863,13 @@ class TODO:
def prompt_execute_doc(self):
print(f"🤖 {t('doc_search')}")
lst_choice = [
choices = [
{"prompt_description": t("migration_module_coverage")},
{"prompt_description": t("what_change_between_version")},
{"prompt_description": t("oca_guidelines")},
{"prompt_description": t("oca_migration_odoo_19")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -912,12 +912,12 @@ class TODO:
def prompt_execute_database(self):
print(f"🤖 {t('db_modify')}")
lst_choice = [
choices = [
{"prompt_description": t("download_db_backup")},
{"prompt_description": t("restore_from_backup")},
{"prompt_description": t("create_backup")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -935,11 +935,11 @@ class TODO:
def prompt_execute_process(self):
print(f"🤖 {t('process_manage')}")
lst_choice = [
choices = [
{"prompt_description": t("kill_process_port")},
{"prompt_description": t("kill_git_daemon")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -962,14 +962,14 @@ class TODO:
def prompt_execute_config(self):
print(f"🤖 {t('config_manage')}")
lst_choice = [
choices = [
{"prompt_description": t("generate_all_config")},
{"prompt_description": t("generate_from_preconfig")},
{"prompt_description": t("generate_from_backup")},
{"prompt_description": t("generate_from_database")},
{"prompt_description": t("setup_queue_job_for_parallelism")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -991,7 +991,7 @@ class TODO:
def prompt_execute_network(self):
print(f"🤖 {t('network_tools')}")
lst_choice = [
choices = [
{"prompt_description": t("ssh_port_forwarding")},
{
"prompt_description": t(
@ -999,7 +999,7 @@ class TODO:
)
},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -1039,10 +1039,10 @@ class TODO:
def prompt_execute_security(self):
print(f"🤖 {t('security_audit')}")
lst_choice = [
choices = [
{"prompt_description": t("pip_audit_desc")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -1056,12 +1056,12 @@ class TODO:
def prompt_execute_test(self):
print(f"🤖 {t('test_description')}")
lst_choice = [
choices = [
{"prompt_description": t("test_run_module")},
{"prompt_description": t("test_run_module_coverage")},
{"prompt_description": t("test_run_unit_tests")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -1180,18 +1180,18 @@ class TODO:
print(f"\n{t('test_unit_failed')}: {status_code}")
def execute_pip_audit(self):
lst_version, lst_version_installed, odoo_installed_version = (
versions, installed_versions, odoo_installed_version = (
self.get_odoo_version()
)
# Build list of installed environments
dct_env = {}
environments = {}
key_i = 0
for dct_version in lst_version[::-1]:
erplibre_version = dct_version.get("erplibre_version")
for version_info in versions[::-1]:
erplibre_version = version_info.get("erplibre_version")
venv_path = f".venv.{erplibre_version}"
req_path = f"requirement/requirements.{erplibre_version}.txt"
odoo_version = f"odoo{dct_version.get('odoo_version')}"
odoo_version = f"odoo{version_info.get('odoo_version')}"
if not os.path.isdir(venv_path):
continue
@ -1201,29 +1201,29 @@ class TODO:
label = f"{key_s}: {erplibre_version}"
if odoo_version == odoo_installed_version:
label += f" - {t('current')}"
if dct_version.get("default"):
if version_info.get("default"):
label += f" - {t('default')}"
dct_env[key_s] = {
environments[key_s] = {
"label": label,
"venv_path": venv_path,
"req_path": req_path,
"erplibre_version": erplibre_version,
}
if not dct_env:
if not environments:
print(t("no_env_installed"))
return
# Show selection menu
str_input = (
f"💬 {t('choose_env_audit')}\n\t"
+ "\n\t".join([v["label"] for v in dct_env.values()])
+ "\n\t".join([v["label"] for v in environments.values()])
+ f"\n\t0: {t('back')}"
+ f"\n{t('selection')}"
)
env_input = ""
while env_input not in dct_env.keys() and env_input != "0":
while env_input not in environments and env_input != "0":
if env_input:
print(f"{t('error_value')}" f" '{env_input}'")
env_input = input(str_input).strip()
@ -1231,7 +1231,7 @@ class TODO:
if env_input == "0":
return
selected = dct_env[env_input]
selected = environments[env_input]
venv_path = selected["venv_path"]
req_path = selected["req_path"]
@ -1267,14 +1267,14 @@ class TODO:
)
def generate_config_from_preconfiguration(self):
lst_choice = [
choices = [
{"prompt_description": t("preconfig_base")},
{"prompt_description": t("preconfig_base_code_generator")},
{"prompt_description": t("preconfig_base_image_db")},
{"prompt_description": t("preconfig_all")},
# {"prompt_description": "base + migration"},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -1303,10 +1303,10 @@ class TODO:
print(t("cmd_not_found"))
def debug_ide(self):
lst_choice = [
choices = [
{"prompt_description": t("debug_todo_py")},
]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
while True:
status = click.prompt(help_info)
@ -1342,25 +1342,25 @@ class TODO:
def select_database(self):
cmd_server = f"./odoo_bin.sh db --list"
status, lst_database = self.execute.exec_command_live(
status, databases = self.execute.exec_command_live(
cmd_server,
return_status_and_output=True,
source_erplibre=False,
single_source_erplibre=True,
)
lst_choice = [{"prompt_description": a.strip()} for a in lst_database]
choices = [{"prompt_description": a.strip()} for a in databases]
help_info = self.fill_help_info(lst_choice)
help_info = self.fill_help_info(choices)
lst_str_choice = [str(a) for a in range(len(lst_choice) + 1) if a]
valid_choices = [str(a) for a in range(len(choices) + 1) if a]
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status in lst_str_choice:
database_name = lst_database[int(status) - 1].strip()
elif status in valid_choices:
database_name = databases[int(status) - 1].strip()
print(database_name)
return database_name
else:
@ -1374,15 +1374,15 @@ class TODO:
raise Exception(
f"Internal error, no Odoo version is supported, please valide file '{VERSION_DATA_FILE}'"
)
lst_version_transform = []
version_entries = []
for key, value in data_version.items():
lst_version_transform.append(value)
version_entries.append(value)
value["erplibre_version"] = key
lst_version_installed = []
installed_versions = []
if os.path.exists(INSTALLED_ODOO_VERSION_FILE):
with open(INSTALLED_ODOO_VERSION_FILE) as txt:
lst_version_installed = sorted(txt.read().splitlines())
installed_versions = sorted(txt.read().splitlines())
odoo_installed_version = None
if os.path.exists(ODOO_VERSION_FILE):
@ -1390,23 +1390,23 @@ class TODO:
odoo_installed_version = f"odoo{txt.read().strip()}"
# Add odoo version installation on command
lst_version = sorted(
lst_version_transform, key=lambda k: k.get("erplibre_version")
versions = sorted(
version_entries, key=lambda k: k.get("erplibre_version")
)
return lst_version, lst_version_installed, odoo_installed_version
return versions, installed_versions, odoo_installed_version
def kdbx_get_extra_command_user(self, kdbx_key):
lst_value = []
values = []
if kdbx_key:
kp = self.get_kdbx()
if not kp:
return ""
if type(kdbx_key) is not list:
lst_kdbx_key = [kdbx_key]
kdbx_keys = [kdbx_key]
else:
lst_kdbx_key = kdbx_key
for key in lst_kdbx_key:
kdbx_keys = kdbx_key
for key in kdbx_keys:
entry = kp.find_entries_by_title(key, first=True)
try:
odoo_user = entry.username
@ -1416,23 +1416,18 @@ class TODO:
odoo_password = entry.password
except AttributeError:
_logger.error(f"Cannot find password from keys {key}")
lst_value.append(
values.append(
" --default_email_auth"
f" {odoo_user} --default_password_auth '{odoo_password}'"
)
if len(lst_value) == 0:
if len(values) == 0:
return ""
elif len(lst_value) == 1:
return lst_value[0]
return lst_value
elif len(values) == 1:
return values[0]
return values
def prompt_execute_selenium_and_run_db(self, bd, extra_cmd_web_login=""):
# cmd = (
# f'parallel ::: "./run.sh -d {bd}" "sleep'
# f' 3;./script/selenium/web_login.py{extra_cmd_web_login}"'
# )
# self.execute.exec_command_live(cmd)
cmd_server = f"./run.sh -d {bd};bash"
def prompt_execute_selenium_and_run_db(self, db_name, extra_cmd_web_login=""):
cmd_server = f"./run.sh -d {db_name};bash"
self.execute.exec_command_live(cmd_server)
cmd_client = (
f"sleep 3;./script/selenium/web_login.py{extra_cmd_web_login};bash"
@ -1440,7 +1435,7 @@ class TODO:
self.execute.exec_command_live(cmd_client)
def prompt_execute_selenium(self, command=None, extra_cmd_web_login=""):
lst_cmd = []
commands = []
if not command:
cmd = "./script/selenium/web_login.py"
else:
@ -1448,15 +1443,15 @@ class TODO:
if type(extra_cmd_web_login) is list:
for item in extra_cmd_web_login:
lst_cmd.append(cmd + item)
commands.append(cmd + item)
else:
lst_cmd.append(cmd + extra_cmd_web_login)
commands.append(cmd + extra_cmd_web_login)
if len(lst_cmd) == 1:
self.execute.exec_command_live(lst_cmd[0])
elif len(lst_cmd) > 1:
if len(commands) == 1:
self.execute.exec_command_live(commands[0])
elif len(commands) > 1:
new_cmd = "parallel ::: "
for i, cmd in enumerate(lst_cmd):
for i, cmd in enumerate(commands):
new_cmd += f' "sleep {1 * i};{cmd}"'
self.execute.exec_command_live(new_cmd)
@ -1525,7 +1520,7 @@ class TODO:
database = self.select_database()
if database:
cmd_server = f"./odoo_bin.sh shell -d {database}"
status, lst_database = self.execute.exec_command_live(
status, databases = self.execute.exec_command_live(
cmd_server,
return_status_and_output=True,
source_erplibre=False,
@ -1592,7 +1587,7 @@ class TODO:
if os.path.exists(poetry_lock):
shutil.copy2(poetry_lock, path_file_odoo_lock)
def callback_execute_custom_database(self, dct_config):
def callback_execute_custom_database(self, config):
database_name = self.select_database()
self.prompt_execute_selenium_and_run_db(database_name)
@ -1627,14 +1622,14 @@ class TODO:
more_arg = "--neutralize "
is_neutralize = True
database_name += "_neutralize"
status, lst_output = self.execute.exec_command_live(
status, output_lines = self.execute.exec_command_live(
f"python3 ./script/database/db_restore.py -d {database_name} {more_arg}--ignore_cache --image {file_name}",
return_status_and_output=True,
single_source_erplibre=True,
source_erplibre=False,
)
if is_neutralize:
status, lst_output = self.execute.exec_command_live(
status, output_lines = self.execute.exec_command_live(
f"./script/addons/update_prod_to_dev.sh {database_name}",
return_status_and_output=True,
single_source_erplibre=True,
@ -1646,7 +1641,7 @@ class TODO:
.lower()
)
if status == "y":
status, lst_output = self.execute.exec_command_live(
status, output_lines = self.execute.exec_command_live(
f"./script/addons/update_addons_all.sh {database_name}",
return_status_and_output=True,
single_source_erplibre=True,
@ -1672,7 +1667,7 @@ class TODO:
print(backup_name)
cmd = f"./odoo_bin.sh db --backup --database {database_name} --restore_image {backup_name}"
status, lst_output = self.execute.exec_command_live(
status, output_lines = self.execute.exec_command_live(
cmd,
return_status_and_output=True,
single_source_erplibre=True,
@ -1705,18 +1700,18 @@ class TODO:
def download_database_backup_cli(self, show_remote_list=True):
database_domain = input("Domain Odoo (ex. https://mondomain.com) : ")
if show_remote_list:
status, lst_output = self.execute.exec_command_live(
status, output_lines = self.execute.exec_command_live(
f"python3 ./script/database/list_remote.py --raw --odoo-url {database_domain}",
return_status_and_output=True,
single_source_erplibre=True,
source_erplibre=False,
)
if len(lst_output) > 1:
for index, output in enumerate(lst_output):
if len(output_lines) > 1:
for index, output in enumerate(output_lines):
print(f"{index + 1} - {output}")
database_name = input("Select id of database :").strip()
elif len(lst_output) == 1:
database_name = lst_output[0].strip()
elif len(output_lines) == 1:
database_name = output_lines[0].strip()
else:
database_name = input(
"Cannot read remote database, Database name :\n"

View file

@ -5,7 +5,7 @@
import os
import re
CONFIG_OVERRIDE_PRIVATE_FILE = "./env_var.sh"
ENV_VAR_FILE = "./env_var.sh"
_current_lang = None
@ -560,9 +560,9 @@ def get_lang():
return _current_lang
# 1. Check env_var.sh file
if os.path.exists(CONFIG_OVERRIDE_PRIVATE_FILE):
if os.path.exists(ENV_VAR_FILE):
try:
with open(CONFIG_OVERRIDE_PRIVATE_FILE) as f:
with open(ENV_VAR_FILE) as f:
content = f.read()
match = re.search(
r'^EL_LANG=["\']?(\w+)["\']?', content, re.MULTILINE
@ -591,9 +591,9 @@ def set_lang(lang):
_current_lang = lang
# Persist to env_var.sh
if os.path.exists(CONFIG_OVERRIDE_PRIVATE_FILE):
if os.path.exists(ENV_VAR_FILE):
try:
with open(CONFIG_OVERRIDE_PRIVATE_FILE) as f:
with open(ENV_VAR_FILE) as f:
content = f.read()
except OSError:
return
@ -610,15 +610,15 @@ def set_lang(lang):
else:
content = content.rstrip("\n") + "\n" + new_line + "\n"
with open(CONFIG_OVERRIDE_PRIVATE_FILE, "w") as f:
with open(ENV_VAR_FILE, "w") as f:
f.write(content)
def lang_is_configured():
"""Check if a language has been explicitly set."""
if os.path.exists(CONFIG_OVERRIDE_PRIVATE_FILE):
if os.path.exists(ENV_VAR_FILE):
try:
with open(CONFIG_OVERRIDE_PRIVATE_FILE) as f:
with open(ENV_VAR_FILE) as f:
content = f.read()
return bool(re.search(r"^EL_LANG=", content, re.MULTILINE))
except OSError:

View file

@ -9,7 +9,7 @@ import psutil
from script.process.kill_process_by_port import (
PROTECTED_NAMES,
STOP_PARENT_KILL,
WRAPPER_SCRIPT_NAMES,
choose_target,
find_listeners,
get_ancestry,
@ -241,10 +241,10 @@ class TestProtectedNames(unittest.TestCase):
class TestStopParentKill(unittest.TestCase):
def test_contains_run_sh(self):
self.assertIn("./run.sh", STOP_PARENT_KILL)
self.assertIn("./run.sh", WRAPPER_SCRIPT_NAMES)
def test_contains_odoo_bin_sh(self):
self.assertIn("./odoo_bin.sh", STOP_PARENT_KILL)
self.assertIn("./odoo_bin.sh", WRAPPER_SCRIPT_NAMES)
if __name__ == "__main__":

View file

@ -31,7 +31,7 @@ class TestTODOInit(unittest.TestCase):
todo = TODO()
self.assertIsNone(todo.dir_path)
self.assertIsNone(todo.kdbx)
self.assertIsNone(todo.file_path)
self.assertIsNone(todo.selected_file_path)
self.assertIsNotNone(todo.config_file)
self.assertIsNotNone(todo.execute)

View file

@ -82,7 +82,7 @@ class TestGetLang(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
result = todo_i18n.get_lang()
self.assertEqual(result, "en")
@ -97,7 +97,7 @@ class TestGetLang(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
result = todo_i18n.get_lang()
self.assertEqual(result, "fr")
@ -107,7 +107,7 @@ class TestGetLang(unittest.TestCase):
def test_env_variable_fallback(self):
with patch.object(
todo_i18n,
"CONFIG_OVERRIDE_PRIVATE_FILE",
"ENV_VAR_FILE",
"/nonexistent/path",
), patch.dict(os.environ, {"EL_LANG": "en"}):
result = todo_i18n.get_lang()
@ -116,7 +116,7 @@ class TestGetLang(unittest.TestCase):
def test_default_is_fr(self):
with patch.object(
todo_i18n,
"CONFIG_OVERRIDE_PRIVATE_FILE",
"ENV_VAR_FILE",
"/nonexistent/path",
), patch.dict(os.environ, {}, clear=True):
result = todo_i18n.get_lang()
@ -130,7 +130,7 @@ class TestGetLang(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
), patch.dict(os.environ, {}, clear=True):
result = todo_i18n.get_lang()
self.assertEqual(result, "fr")
@ -159,7 +159,7 @@ class TestSetLang(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
todo_i18n.set_lang("en")
with open(f.name) as rf:
@ -177,7 +177,7 @@ class TestSetLang(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
todo_i18n.set_lang("en")
with open(f.name) as rf:
@ -190,7 +190,7 @@ class TestSetLang(unittest.TestCase):
def test_nonexistent_file_no_crash(self):
with patch.object(
todo_i18n,
"CONFIG_OVERRIDE_PRIVATE_FILE",
"ENV_VAR_FILE",
"/nonexistent/path",
):
todo_i18n.set_lang("en")
@ -208,7 +208,7 @@ class TestLangIsConfigured(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
result = todo_i18n.lang_is_configured()
self.assertTrue(result)
@ -223,7 +223,7 @@ class TestLangIsConfigured(unittest.TestCase):
f.flush()
try:
with patch.object(
todo_i18n, "CONFIG_OVERRIDE_PRIVATE_FILE", f.name
todo_i18n, "ENV_VAR_FILE", f.name
):
result = todo_i18n.lang_is_configured()
self.assertFalse(result)
@ -233,7 +233,7 @@ class TestLangIsConfigured(unittest.TestCase):
def test_returns_false_when_file_missing(self):
with patch.object(
todo_i18n,
"CONFIG_OVERRIDE_PRIVATE_FILE",
"ENV_VAR_FILE",
"/nonexistent/path",
):
result = todo_i18n.lang_is_configured()