[IMP] script update config from database and implement TODO configuration

- execute script remote endline from output
This commit is contained in:
Mathieu Benoit 2026-02-13 03:46:27 -05:00
parent c580493099
commit facd1c928e
8 changed files with 354 additions and 66 deletions

View file

@ -0,0 +1,66 @@
#!/usr/bin/env python3
# © 2021-2025 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import argparse
import logging
import os
import sys
new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
sys.path.append(new_path)
from script.execute import execute
from script.git.git_tool import GitTool
_logger = logging.getLogger(__name__)
def get_config():
"""Parse command line arguments, extracting the config file name,
returning the union of config file and command line arguments
:return: dict of config file settings and command line arguments
"""
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Will print list of installed module from database
""",
epilog="""\
""",
)
parser.add_argument(
"--database",
required=True,
help="The database name to extract",
)
args = parser.parse_args()
return args
def main():
config = get_config()
execute_cmd = execute.Execute()
if config.database:
cmd = f"cat ./script/odoo/util/show_installed_module.py | ./odoo_bin.sh shell -d {config.database}"
status, output = execute_cmd.exec_command_live(
cmd,
quiet=True,
source_erplibre=False,
single_source_erplibre=True,
return_status_and_output=True,
)
has_find = False
for line in output:
if has_find:
print(line.strip())
if line.strip() == "Installed modules:":
has_find = True
if __name__ == "__main__":
main()

View file

@ -68,27 +68,15 @@ def main():
json_manifest_file = json.load(manifest_file)
lst_module = set(json_manifest_file.get("modules").keys())
cmd = "parallel ::: " + " ".join(
[
f"'./script/addons/check_addons_exist.py --output_path -m \"{a}\"'"
for a in lst_module
]
)
str_module = ";".join(lst_module)
cmd = f'./script/database/get_repo_from_module.py --module "{str_module}"'
execute_cmd = execute.Execute()
status, output = execute_cmd.exec_command_live(
cmd,
quiet=not config.debug,
source_erplibre=False,
single_source_erplibre=True,
return_status_and_output=True,
)
set_path_repo = set()
for line_module_path in output:
line_repo = os.path.dirname(line_module_path)
set_path_repo.add(line_repo)
for path_repo in set_path_repo:
print(path_repo)
def die(cond, message, code=1):

View file

@ -0,0 +1,80 @@
#!/usr/bin/env python3
# © 2021-2025 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import argparse
import json
import logging
import os
import sys
import zipfile
new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
sys.path.append(new_path)
from script.execute import execute
logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
_logger = logging.getLogger(__name__)
def get_config():
"""Parse command line arguments, extracting the config file name,
returning the union of config file and command line arguments
:return: dict of config file settings and command line arguments
"""
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Extract all repo path from installed module into backup.
Use --backup_path or --backup_name
""",
epilog="""\
""",
)
parser.add_argument("--module", help="Module list separate by ;")
parser.add_argument("--debug", action="store_true")
args = parser.parse_args()
return args
def main():
config = get_config()
lst_module = set(config.module.split(";"))
cmd = "parallel ::: " + " ".join(
[
f"'./script/addons/check_addons_exist.py --output_path -m \"{a}\"'"
for a in lst_module
]
)
execute_cmd = execute.Execute()
status, output = execute_cmd.exec_command_live(
cmd,
quiet=not config.debug,
source_erplibre=False,
single_source_erplibre=True,
return_status_and_output=True,
)
set_path_repo = set()
for line_module_path in output:
line_repo = os.path.dirname(line_module_path)
set_path_repo.add(line_repo)
for path_repo in set_path_repo:
print(path_repo)
def die(cond, message, code=1):
if cond:
print(message, file=sys.stderr)
sys.exit(code)
if __name__ == "__main__":
main()

View file

@ -138,7 +138,12 @@ class Execute:
return_status_and_output
or return_status_and_output_and_command
):
lst_output.append(ligne)
# Remove last \n char
lst_output.append(
ligne.removesuffix("\r\n")
.removesuffix("\n")
.removesuffix("\r")
)
process.wait() # Attendre la fin du process
return_status = process.returncode

View file

@ -7,9 +7,6 @@ import logging
import os
import sys
import git
from git import Repo
new_path = os.path.normpath(
os.path.join(os.path.dirname(__file__), "..", "..")
)
@ -27,9 +24,6 @@ def get_config():
:return: dict of config file settings and command line arguments
"""
config = GitTool.get_project_config()
# TODO update description
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
@ -65,6 +59,10 @@ def get_config():
"--add_repo",
help="Add repo, separate by ; for list",
)
parser.add_argument(
"--database",
help="Add repo from module found into database.",
)
args = parser.parse_args()
return args
@ -72,12 +70,13 @@ def get_config():
def main():
config = get_config()
git_tool = GitTool()
execute_cmd = execute.Execute()
index_to_remove = len(os.getcwd()) + 1
filter_group = config.group if config.group else None
lst_whitelist = []
if config.from_backup_path or config.from_backup_name:
execute_cmd = execute.Execute()
# script/database/get_repo_from_backup.py
# --backup_name bpir_prod_5_dec_2025_2026-02-04_14h27m54s.zip
if config.from_backup_path:
@ -91,7 +90,28 @@ def main():
single_source_erplibre=True,
return_status_and_output=True,
)
index_to_remove = len(os.getcwd()) + 1
for line in output:
repo_name = line[index_to_remove:].strip()
lst_whitelist.append(repo_name)
if config.database:
cmd = f"./script/database/get_module_list_from_database.py --database {config.database}"
status, output = execute_cmd.exec_command_live(
cmd,
quiet=True,
source_erplibre=False,
single_source_erplibre=True,
return_status_and_output=True,
)
str_module = ";".join(output)
cmd = f'./script/database/get_repo_from_module.py --module "{str_module}"'
status, output = execute_cmd.exec_command_live(
cmd,
quiet=True,
source_erplibre=False,
single_source_erplibre=True,
return_status_and_output=True,
)
for line in output:
repo_name = line[index_to_remove:].strip()
lst_whitelist.append(repo_name)

View file

@ -457,7 +457,9 @@ class GitTool:
continue
# groups = repo.get("group")
# Use variable instead of hardcoded path
if update_repo.startswith(os.path.join(filter_group, "addons")):
if update_repo.startswith(
os.path.join(self.odoo_version_long, "addons")
):
lst_path = update_repo.split("/", 1)
update_repo = f"${{EL_HOME_ODOO_PROJECT}}/" + lst_path[1]
# str_repo = (

View file

@ -3,7 +3,7 @@
Run this script when doing database migration. Example :
```bash
source ./.venv.odoo15.0_python3.8.20/bin/activate && cat ./script/migration/fix_migration_odoo140_to_odoo150.py | ./odoo15.0/odoo/odoo-bin shell -d DATABASE
source ./.venv.odoo15.0_python3.8.20/bin/activate && cat ./script/odoo/migration/fix_migration_odoo140_to_odoo150.py | ./odoo15.0/odoo/odoo-bin shell -d DATABASE
```
Check [uninstall_module_list_odoo140_to_odoo150.txt](uninstall_module_list_odoo140_to_odoo150.txt)

View file

@ -206,6 +206,7 @@ class TODO:
[5] Doc - Recherche de documentation
[6] Database - Outils sur les bases de données
[7] Process - Outils sur les exécutions
[8] Config - Traitement du fichier de configuration
[0] Retour
"""
while True:
@ -241,6 +242,10 @@ class TODO:
status = self.prompt_execute_process()
if status is not False:
return
elif status == "8":
status = self.prompt_execute_config()
if status is not False:
return
else:
print("Commande non trouvée 🤖!")
@ -436,10 +441,10 @@ class TODO:
if callback:
callback(dct_instance)
def fill_help_info(self, lst_instance):
def fill_help_info(self, lst_choice):
help_info = "Commande :\n"
help_end = "[0] Retour\n"
for i, dct_instance in enumerate(lst_instance):
for i, dct_instance in enumerate(lst_choice):
help_info += (
f"[{i + 1}] " + dct_instance["prompt_description"] + "\n"
)
@ -450,16 +455,16 @@ class TODO:
# TODO proposer le déploiement à distance
# TODO proposer l'exécution de docker
# TODO proposer la création de docker
lst_instance = self.config_file.get_config("instance")
init_len = len(lst_instance)
lst_choice = self.config_file.get_config("instance")
init_len = len(lst_choice)
if os.path.exists(MOBILE_HOME_PATH):
dct_upgrade_odoo_database = {
"prompt_description": "Mobile - Compile and run software",
"callback": self.callback_make_mobile_home,
}
lst_instance.append(dct_upgrade_odoo_database)
help_info = self.fill_help_info(lst_instance)
lst_choice.append(dct_upgrade_odoo_database)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
@ -475,15 +480,15 @@ class TODO:
status = click.confirm(
"Voulez-vous une nouvelle instance?"
)
dct_instance = lst_instance[int_cmd - 1]
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(
dct_instance,
exec_run_db=True,
ignore_makefile=not bool(status),
)
elif int_cmd <= len(lst_instance):
elif int_cmd <= len(lst_choice):
# Execute dynamic instance
dct_instance = lst_instance[int_cmd - 1]
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(
dct_instance,
)
@ -493,8 +498,8 @@ class TODO:
print("Commande non trouvée 🤖!")
def prompt_execute_fonction(self):
lst_instance = self.config_file.get_config("function")
help_info = self.fill_help_info(lst_instance)
lst_choice = self.config_file.get_config("function")
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
@ -505,9 +510,9 @@ class TODO:
cmd_no_found = True
try:
int_cmd = int(status)
if 0 < int_cmd <= len(lst_instance):
if 0 < int_cmd <= len(lst_choice):
cmd_no_found = False
dct_instance = lst_instance[int_cmd - 1]
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
except ValueError:
pass
@ -525,34 +530,34 @@ class TODO:
# TODO faire la mise à jour de ERPLibre
# TODO faire l'upgrade d'un odoo vers un autre
lst_instance = self.config_file.get_config("update_from_makefile")
lst_choice = self.config_file.get_config("update_from_makefile")
dct_upgrade_odoo_database = {
"prompt_description": "Upgrade Odoo - Migration Database",
}
lst_instance.append(dct_upgrade_odoo_database)
lst_choice.append(dct_upgrade_odoo_database)
dct_upgrade_poetry = {
"prompt_description": "Upgrade Poetry - Dependency of Odoo",
}
lst_instance.append(dct_upgrade_poetry)
help_info = self.fill_help_info(lst_instance)
lst_choice.append(dct_upgrade_poetry)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == str(len(lst_instance) - 1):
elif status == str(len(lst_choice) - 1):
upgrade = todo_upgrade.TodoUpgrade(self)
upgrade.execute_odoo_upgrade()
elif status == str(len(lst_instance)):
elif status == str(len(lst_choice)):
self.upgrade_poetry()
else:
cmd_no_found = True
try:
int_cmd = int(status) - 1
if 0 < int_cmd <= len(lst_instance):
if 0 < int_cmd <= len(lst_choice):
cmd_no_found = False
dct_instance = lst_instance[int_cmd - 1]
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
except ValueError:
pass
@ -573,27 +578,27 @@ class TODO:
# [0] Retour
# """
lst_instance = self.config_file.get_config("code_from_makefile")
lst_choice = self.config_file.get_config("code_from_makefile")
dct_upgrade_odoo_database = {
"prompt_description": "Upgrade Module",
}
lst_instance.append(dct_upgrade_odoo_database)
help_info = self.fill_help_info(lst_instance)
lst_choice.append(dct_upgrade_odoo_database)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == str(len(lst_instance)):
elif status == str(len(lst_choice)):
self.upgrade_module()
else:
cmd_no_found = True
try:
int_cmd = int(status)
if 0 < int_cmd <= len(lst_instance):
if 0 < int_cmd <= len(lst_choice):
cmd_no_found = False
dct_instance = lst_instance[int_cmd - 1]
dct_instance = lst_choice[int_cmd - 1]
self.execute_from_configuration(dct_instance)
except ValueError:
pass
@ -602,13 +607,13 @@ class TODO:
def prompt_execute_doc(self):
print("🤖 Vous cherchez de la documentation?")
lst_instance = [
lst_choice = [
{"prompt_description": "Migration module coverage"},
{"prompt_description": "What change between version"},
{"prompt_description": "OCA guidelines"},
{"prompt_description": "OCA migration Odoo 19 milestone"},
]
help_info = self.fill_help_info(lst_instance)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
@ -651,13 +656,13 @@ class TODO:
def prompt_execute_database(self):
print("🤖 Faites des modifications sur les bases de données!")
lst_instance = [
lst_choice = [
{
"prompt_description": "Download database to create backup (.zip)"
},
{"prompt_description": "Restore from backup (.zip)"},
]
help_info = self.fill_help_info(lst_instance)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
@ -673,10 +678,10 @@ class TODO:
def prompt_execute_process(self):
print("🤖 Manipuler les processus d'exécution!")
lst_instance = [
lst_choice = [
{"prompt_description": "Kill process from actual port"},
]
help_info = self.fill_help_info(lst_instance)
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
@ -688,6 +693,122 @@ class TODO:
else:
print("Commande non trouvée 🤖!")
def prompt_execute_config(self):
print("🤖 Manipuler la configuration ERPLibre et Odoo!")
lst_choice = [
{"prompt_description": "Generate all configuration"},
{"prompt_description": "Generate from pre-configuration"},
{"prompt_description": "Generate from backup file"},
{"prompt_description": "Generate from database"},
]
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == "1":
self.generate_config()
elif status == "2":
self.generate_config_from_preconfiguration()
elif status == "3":
self.generate_config_from_backup()
elif status == "4":
self.generate_config_from_database()
else:
print("Commande non trouvée 🤖!")
def generate_config(self, add_arg=None):
# Repeating to get all item before get group
cmd = (
f"./script/git/git_repo_update_group.py;"
f"./script/generate_config.sh"
)
if add_arg:
cmd += (
f";./script/git/git_repo_update_group.py {add_arg};"
f"./script/generate_config.sh"
)
self.execute.exec_command_live(
cmd,
source_erplibre=False,
single_source_erplibre=True,
)
def generate_config_from_preconfiguration(self):
lst_choice = [
{"prompt_description": "base"},
{"prompt_description": "base + code_generator"},
{"prompt_description": "base + image_db"},
{"prompt_description": "all"},
# {"prompt_description": "base + migration"},
]
help_info = self.fill_help_info(lst_choice)
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status == "1":
group = "base"
str_group = f"--group {group}"
self.generate_config(add_arg=str_group)
elif status == "2":
group = "base,code_generator"
str_group = f"--group {group}"
self.generate_config(add_arg=str_group)
elif status == "3":
group = "base,image_db"
str_group = f"--group {group}"
self.generate_config(add_arg=str_group)
elif status == "4":
self.generate_config()
# elif status == "5":
# group = "base,migration"
# str_group = f"--group {group}"
# self.generate_config(add_arg=str_group)
else:
print("Commande non trouvée 🤖!")
def generate_config_from_backup(self):
file_name = self.open_file_image_db()
add_arg = f"--from_backup_name {file_name} --add_repo odoo18.0/addons/MathBenTech_development"
self.generate_config(add_arg=add_arg)
def generate_config_from_database(self):
cmd_server = f"./odoo_bin.sh db --list"
status, output = 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 output]
help_info = self.fill_help_info(lst_choice)
lst_str_choice = [str(a) for a in range(len(lst_choice) + 1) if a]
while True:
status = click.prompt(help_info)
print()
if status == "0":
return False
elif status in lst_str_choice:
database_name = output[int(status) - 1].strip()
print(database_name)
str_arg = f"--database {database_name}"
self.generate_config(add_arg=str_arg)
return False
else:
print("Commande non trouvée 🤖!")
# file_name = self.open_file_image_db()
# add_arg = f"--from_backup_name {file_name} --add_repo odoo18.0/addons/MathBenTech_development"
#
# self.generate_config(add_arg=add_arg)
def get_odoo_version(self):
with open(VERSION_DATA_FILE) as txt:
data_version = json.load(txt)
@ -899,14 +1020,7 @@ class TODO:
if status == "1":
file_name = status
else:
self.dir_path = ""
file_browser = todo_file_browser.FileBrowser(
path_image_db, self.on_dir_selected
)
file_browser.run_main_frame()
file_name = os.path.basename(self.dir_path)
print(file_name)
file_name = self.open_file_image_db
database_name = input("💬 Database name : ")
if not database_name:
@ -943,6 +1057,19 @@ class TODO:
source_erplibre=False,
)
def open_file_image_db(self):
self.dir_path = ""
path_image_db = os.path.join(os.getcwd(), "image_db")
# self.dir_path is over-write into on_dir_selected
file_browser = todo_file_browser.FileBrowser(
path_image_db, self.on_dir_selected
)
file_browser.run_main_frame()
file_name = os.path.basename(self.dir_path)
print(file_name)
return file_name
def process_kill_from_port(self):
cfg = configparser.ConfigParser()
cfg.read("./config.conf")