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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import psutil
from script.process.kill_process_by_port import ( from script.process.kill_process_by_port import (
PROTECTED_NAMES, PROTECTED_NAMES,
STOP_PARENT_KILL, WRAPPER_SCRIPT_NAMES,
choose_target, choose_target,
find_listeners, find_listeners,
get_ancestry, get_ancestry,
@ -241,10 +241,10 @@ class TestProtectedNames(unittest.TestCase):
class TestStopParentKill(unittest.TestCase): class TestStopParentKill(unittest.TestCase):
def test_contains_run_sh(self): 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): 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__": if __name__ == "__main__":

View file

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

View file

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