[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
|
|
"""Dupliquer une base, et la neutraliser si on le demande.
|
|
|
|
|
|
|
|
|
|
|
|
Pourquoi passer par Odoo plutôt que par `CREATE DATABASE … TEMPLATE`
|
|
|
|
|
|
-------------------------------------------------------------------
|
|
|
|
|
|
La commande PostgreSQL copie les tables, et RIEN d'autre. Odoo, lui, fait
|
|
|
|
|
|
quatre choses de plus que `exp_duplicate_database` réunit :
|
|
|
|
|
|
|
|
|
|
|
|
1. Il coupe les connexions ouvertes sur la source. Sans cela PostgreSQL
|
|
|
|
|
|
refuse : « is being accessed by other users » — un shell Odoo laissé
|
|
|
|
|
|
ouvert suffit à faire échouer la copie.
|
|
|
|
|
|
2. Il RÉGÉNÈRE le `database.uuid`. Deux bases qui partagent le leur se
|
|
|
|
|
|
présentent comme la même instance au service de garantie d'Odoo.
|
|
|
|
|
|
3. Il copie le FILESTORE. Sans lui, chaque pièce jointe de la copie
|
|
|
|
|
|
pointe vers un fichier qui n'existe pas — 57 Mo perdus en silence sur
|
|
|
|
|
|
la base qui a servi à écrire ceci.
|
|
|
|
|
|
4. Il neutralise pour de bon, quand on le demande.
|
|
|
|
|
|
|
|
|
|
|
|
Ce que « neutraliser » veut dire, mesuré
|
|
|
|
|
|
----------------------------------------
|
|
|
|
|
|
Le dépôt a trois modules maison — `disable_mail_server`,
|
|
|
|
|
|
`disable_auto_backup`, `disable_payment_provider` — qui font trois gestes.
|
|
|
|
|
|
Aucun ne pose le drapeau, et l'un d'eux ouvre une porte : supprimer tous
|
|
|
|
|
|
les `ir.mail_server` fait retomber Odoo sur le `smtp_server` du fichier
|
|
|
|
|
|
de configuration.
|
|
|
|
|
|
|
|
|
|
|
|
`neutralize_database` d'Odoo exécute les 73 fichiers `neutralize.sql`
|
|
|
|
|
|
livrés par les modules INSTALLÉS. Mesuré sur une base migrée 12 → 18 :
|
|
|
|
|
|
|
|
|
|
|
|
database.is_neutralized ABSENT → true
|
|
|
|
|
|
crons actifs 33 → 1 (l'autovacuum, voulu)
|
|
|
|
|
|
serveurs de courriel 0 → 1 le bouchon « invalid »
|
|
|
|
|
|
clé Stripe présente 1 → 0
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
Deux techniques, selon la version
|
|
|
|
|
|
---------------------------------
|
|
|
|
|
|
`neutralize.py` n'existe qu'à partir d'Odoo 16 ; avant,
|
|
|
|
|
|
`exp_duplicate_database` ne prend que deux arguments. De 12 à 15 on
|
|
|
|
|
|
retombe donc sur la technique du dépôt : `update_prod_to_dev.sh`, qui
|
|
|
|
|
|
installe puis désinstalle `user_test`, `disable_mail_server`,
|
|
|
|
|
|
`disable_auto_backup` et `disable_payment_provider`.
|
|
|
|
|
|
|
|
|
|
|
|
Les deux n'obtiennent PAS la même chose, et il faut le savoir :
|
|
|
|
|
|
|
|
|
|
|
|
Odoo ≥ 16 script 12→15
|
|
|
|
|
|
database.is_neutralized posé non posé
|
|
|
|
|
|
crons désactivés oui non
|
|
|
|
|
|
serveur de courriel bouchon supprimés (*)
|
|
|
|
|
|
clés de paiement mises à laissées
|
|
|
|
|
|
NULL en place
|
|
|
|
|
|
compte test/test non oui
|
|
|
|
|
|
|
|
|
|
|
|
(*) supprimer tous les `ir.mail_server` fait retomber Odoo sur le
|
|
|
|
|
|
`smtp_server` du fichier de configuration ; le bouchon d'Odoo existe
|
|
|
|
|
|
précisément pour boucher ce trou-là.
|
|
|
|
|
|
|
|
|
|
|
|
La technique employée est ANNONCÉE à chaque exécution : une copie dont
|
|
|
|
|
|
on ignore par quel chemin elle est passée ne se juge pas.
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import argparse
|
|
|
|
|
|
import os
|
|
|
|
|
|
import subprocess
|
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
sys.path.append(
|
|
|
|
|
|
os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
from script.todo.todo_i18n import t
|
|
|
|
|
|
except Exception: # pragma: no cover - repli si i18n indisponible
|
|
|
|
|
|
|
|
|
|
|
|
def t(key: str) -> str:
|
|
|
|
|
|
return key
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
REPO_ROOT = os.path.normpath(
|
|
|
|
|
|
os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..")
|
|
|
|
|
|
)
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
# La neutralisation d'Odoo n'existe pas avant cette version.
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
PREMIERE_VERSION_NEUTRALISABLE = 16.0
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
# Comment on neutralise, selon ce que la version sait faire.
|
|
|
|
|
|
NEUTRALISATION_ODOO = "odoo"
|
|
|
|
|
|
NEUTRALISATION_SCRIPT = "script"
|
|
|
|
|
|
SCRIPT_PROD_TO_DEV = "./script/addons/update_prod_to_dev.sh"
|
|
|
|
|
|
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
|
|
|
|
|
|
def lire_version(nom):
|
|
|
|
|
|
"""Le contenu d'un fichier `.xxx-version`, ou None."""
|
|
|
|
|
|
chemin = os.path.join(REPO_ROOT, nom)
|
|
|
|
|
|
try:
|
|
|
|
|
|
with open(chemin, "r", encoding="utf-8") as handle:
|
|
|
|
|
|
return handle.read().strip() or None
|
|
|
|
|
|
except OSError:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def chemins_odoo():
|
|
|
|
|
|
"""(python du venv, racine d'Odoo) — résolus comme odoo_bin.sh le fait.
|
|
|
|
|
|
|
|
|
|
|
|
Le nom du venv porte les DEUX versions, Odoo et Python : le composer
|
|
|
|
|
|
de tête revient à se tromper un jour sur l'une des deux.
|
|
|
|
|
|
"""
|
|
|
|
|
|
erplibre = lire_version(".erplibre-version")
|
|
|
|
|
|
odoo = lire_version(".odoo-version")
|
|
|
|
|
|
if not erplibre or not odoo:
|
|
|
|
|
|
return None, None
|
|
|
|
|
|
python = os.path.join(REPO_ROOT, f".venv.{erplibre}", "bin", "python")
|
|
|
|
|
|
racine = os.path.join(REPO_ROOT, f"odoo{odoo}", "odoo")
|
|
|
|
|
|
return python, racine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# « rien n'a été passé » et « on m'a passé une version illisible » sont
|
|
|
|
|
|
# deux questions différentes, et un `None` ne doit pas se faire prendre
|
|
|
|
|
|
# pour l'autre : l'appelant dont la lecture a échoué se verrait répondre
|
|
|
|
|
|
# sur la version du checkout, c'est-à-dire sur autre chose.
|
|
|
|
|
|
_NON_FOURNI = object()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def supporte_neutralisation(version=_NON_FOURNI):
|
|
|
|
|
|
"""La version sait-elle neutraliser ? Sans argument : celle du checkout."""
|
|
|
|
|
|
if version is _NON_FOURNI:
|
|
|
|
|
|
version = lire_version(".odoo-version")
|
|
|
|
|
|
try:
|
|
|
|
|
|
return float(version) >= PREMIERE_VERSION_NEUTRALISABLE
|
|
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
def technique_neutralisation(version=_NON_FOURNI):
|
|
|
|
|
|
"""Par quel chemin neutraliser, pour cette version.
|
|
|
|
|
|
|
|
|
|
|
|
On ne REFUSE plus sous 12→15 : le dépôt a sa technique, et une copie
|
|
|
|
|
|
imparfaitement neutralisée vaut mieux qu'une copie brute. Ce qui
|
|
|
|
|
|
compte est de dire laquelle a servi.
|
|
|
|
|
|
"""
|
|
|
|
|
|
if supporte_neutralisation(version):
|
|
|
|
|
|
return NEUTRALISATION_ODOO
|
|
|
|
|
|
return NEUTRALISATION_SCRIPT
|
|
|
|
|
|
|
|
|
|
|
|
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
def nom_valide(nom):
|
|
|
|
|
|
"""Un nom de base acceptable — c'est aussi ce qui entre dans du SQL."""
|
|
|
|
|
|
if not nom or len(nom) > 63:
|
|
|
|
|
|
return False
|
|
|
|
|
|
if not (nom[0].isalpha() or nom[0] == "_"):
|
|
|
|
|
|
return False
|
|
|
|
|
|
return all(c.isalnum() or c in "_-$" for c in nom)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def script_python(source, cible, neutraliser, config):
|
|
|
|
|
|
"""Le programme qu'on remet à l'interpréteur d'Odoo.
|
|
|
|
|
|
|
|
|
|
|
|
`parse_config` est indispensable : sans lui, `Registry.new` ne sait ni
|
|
|
|
|
|
où se connecter ni où sont les addons, et la duplication échoue après
|
|
|
|
|
|
avoir DÉJÀ créé la base.
|
|
|
|
|
|
"""
|
|
|
|
|
|
return (
|
|
|
|
|
|
"import sys\n"
|
|
|
|
|
|
"sys.path.insert(0, %r)\n"
|
|
|
|
|
|
"import odoo\n"
|
|
|
|
|
|
"odoo.tools.config.parse_config(['-c', %r])\n"
|
|
|
|
|
|
"from odoo.service.db import exp_duplicate_database\n"
|
|
|
|
|
|
"exp_duplicate_database(%r, %r%s)\n"
|
|
|
|
|
|
% (
|
|
|
|
|
|
chemins_odoo()[1],
|
|
|
|
|
|
config,
|
|
|
|
|
|
source,
|
|
|
|
|
|
cible,
|
|
|
|
|
|
", True" if neutraliser else "",
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def bases_existantes():
|
|
|
|
|
|
"""Les bases que PostgreSQL expose, ou None si on n'a pas pu demander."""
|
|
|
|
|
|
try:
|
|
|
|
|
|
fait = subprocess.run(
|
|
|
|
|
|
[
|
|
|
|
|
|
"psql",
|
|
|
|
|
|
"-X",
|
|
|
|
|
|
"-w",
|
|
|
|
|
|
"-tA",
|
|
|
|
|
|
"-d",
|
|
|
|
|
|
"postgres",
|
|
|
|
|
|
"-c",
|
|
|
|
|
|
"SELECT datname FROM pg_database WHERE NOT datistemplate",
|
|
|
|
|
|
],
|
|
|
|
|
|
capture_output=True,
|
|
|
|
|
|
text=True,
|
|
|
|
|
|
timeout=60,
|
|
|
|
|
|
)
|
|
|
|
|
|
except (OSError, subprocess.SubprocessError):
|
|
|
|
|
|
return None
|
|
|
|
|
|
if fait.returncode:
|
|
|
|
|
|
return None
|
|
|
|
|
|
return {
|
|
|
|
|
|
ligne.strip() for ligne in fait.stdout.splitlines() if ligne.strip()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verifier(source, cible, neutraliser):
|
|
|
|
|
|
"""Ce qui empêche de commencer. Rendre la liste des refus."""
|
|
|
|
|
|
refus = []
|
|
|
|
|
|
for nom, role in ((source, "source"), (cible, "cible")):
|
|
|
|
|
|
if not nom_valide(nom):
|
|
|
|
|
|
refus.append(f"{t('Invalid database name: ')}{nom!r} ({role})")
|
|
|
|
|
|
if source == cible:
|
|
|
|
|
|
refus.append(t("The source and the copy cannot share a name."))
|
|
|
|
|
|
bases = bases_existantes()
|
|
|
|
|
|
if bases is not None:
|
|
|
|
|
|
if source not in bases:
|
|
|
|
|
|
refus.append(f"{t('No such database: ')}{source}")
|
|
|
|
|
|
if cible in bases:
|
|
|
|
|
|
# Écraser une base sans le dire est la faute qu'on ne rattrape
|
|
|
|
|
|
# pas : le contenu d'avant n'existe plus nulle part.
|
|
|
|
|
|
refus.append(f"{t('This database already exists: ')}{cible}")
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
if neutraliser and technique_neutralisation() == NEUTRALISATION_SCRIPT:
|
|
|
|
|
|
# PAS un refus : de 12 à 15 on passe par update_prod_to_dev.sh.
|
|
|
|
|
|
# Le script doit exister, sinon la copie sortirait brute en se
|
|
|
|
|
|
# croyant neutralisée — le seul cas vraiment dangereux.
|
|
|
|
|
|
if not os.path.isfile(os.path.join(REPO_ROOT, SCRIPT_PROD_TO_DEV)):
|
|
|
|
|
|
refus.append(f"{t('Missing script: ')}{SCRIPT_PROD_TO_DEV}")
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
return refus
|
|
|
|
|
|
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
def neutraliser_par_script(cible, timeout=3600):
|
|
|
|
|
|
"""La technique du dépôt, pour Odoo 12 à 15. Rendre (code, sortie).
|
|
|
|
|
|
|
|
|
|
|
|
`update_prod_to_dev.sh` installe puis désinstalle quatre modules
|
|
|
|
|
|
maison. Il tourne depuis la racine du dépôt : les chemins qu'il
|
|
|
|
|
|
contient sont relatifs, et l'appeler d'ailleurs le fait échouer sur
|
|
|
|
|
|
`install_addons_dev.sh` introuvable.
|
|
|
|
|
|
"""
|
|
|
|
|
|
fait = subprocess.run(
|
|
|
|
|
|
["bash", SCRIPT_PROD_TO_DEV, cible],
|
|
|
|
|
|
cwd=REPO_ROOT,
|
|
|
|
|
|
capture_output=True,
|
|
|
|
|
|
text=True,
|
|
|
|
|
|
timeout=timeout,
|
|
|
|
|
|
)
|
|
|
|
|
|
if fait.returncode:
|
|
|
|
|
|
return fait.returncode, (fait.stderr or fait.stdout).strip()
|
|
|
|
|
|
return 0, (fait.stdout or "").strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
def dupliquer(
|
|
|
|
|
|
source, cible, neutraliser=False, config="config.conf", timeout=3600
|
|
|
|
|
|
):
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
"""Faire la copie, puis la neutraliser par le chemin de la version.
|
|
|
|
|
|
|
|
|
|
|
|
La copie d'abord, la neutralisation ensuite : si la seconde échoue,
|
|
|
|
|
|
la base existe et l'on sait qu'elle est BRUTE. L'inverse — une base
|
|
|
|
|
|
à moitié neutralisée — ne se distinguerait pas d'une base traitée.
|
|
|
|
|
|
"""
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
python, racine = chemins_odoo()
|
|
|
|
|
|
if not python or not os.path.isfile(python):
|
|
|
|
|
|
return 2, t("Cannot find the virtualenv for this checkout.")
|
|
|
|
|
|
if not racine or not os.path.isdir(racine):
|
|
|
|
|
|
return 2, t("Cannot find the Odoo source for this checkout.")
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
|
|
|
|
|
|
par_odoo = neutraliser and (
|
|
|
|
|
|
technique_neutralisation() == NEUTRALISATION_ODOO
|
|
|
|
|
|
)
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
fait = subprocess.run(
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
[python, "-c", script_python(source, cible, par_odoo, config)],
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
cwd=REPO_ROOT,
|
|
|
|
|
|
capture_output=True,
|
|
|
|
|
|
text=True,
|
|
|
|
|
|
timeout=timeout,
|
|
|
|
|
|
)
|
|
|
|
|
|
if fait.returncode:
|
|
|
|
|
|
return fait.returncode, (fait.stderr or fait.stdout).strip()
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
|
|
|
|
|
|
if neutraliser and not par_odoo:
|
|
|
|
|
|
code, sortie = neutraliser_par_script(cible, timeout=timeout)
|
|
|
|
|
|
if code:
|
|
|
|
|
|
return code, sortie
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
return 0, (fait.stdout or "").strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(argv=None):
|
|
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
|
|
description=t("Duplicate a database, filestore included."),
|
|
|
|
|
|
)
|
|
|
|
|
|
parser.add_argument("-s", "--source", required=True)
|
|
|
|
|
|
parser.add_argument("-d", "--database", required=True, help=t("the copy"))
|
|
|
|
|
|
parser.add_argument("-c", "--config", default="config.conf")
|
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
|
"--neutralize",
|
|
|
|
|
|
action="store_true",
|
|
|
|
|
|
help=t("disable crons, outgoing mail and payment providers"),
|
|
|
|
|
|
)
|
|
|
|
|
|
args = parser.parse_args(argv)
|
|
|
|
|
|
|
|
|
|
|
|
refus = verifier(args.source, args.database, args.neutralize)
|
|
|
|
|
|
if refus:
|
|
|
|
|
|
for ligne in refus:
|
|
|
|
|
|
print(f"❌ {ligne}", file=sys.stderr)
|
|
|
|
|
|
return 2
|
|
|
|
|
|
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
technique = technique_neutralisation()
|
|
|
|
|
|
if args.neutralize:
|
|
|
|
|
|
# DIRE par quel chemin : les deux ne posent pas les mêmes gestes,
|
|
|
|
|
|
# et une copie dont on ignore le traitement ne se juge pas.
|
|
|
|
|
|
comment = (
|
|
|
|
|
|
t("Odoo's own neutralisation")
|
|
|
|
|
|
if technique == NEUTRALISATION_ODOO
|
|
|
|
|
|
else f"{SCRIPT_PROD_TO_DEV} ({t('Odoo')}"
|
|
|
|
|
|
f" {lire_version('.odoo-version')})"
|
|
|
|
|
|
)
|
|
|
|
|
|
print(f"🧬 {args.source} → {args.database} — {comment}")
|
|
|
|
|
|
else:
|
|
|
|
|
|
print(f"🧬 {args.source} → {args.database}")
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
code, sortie = dupliquer(
|
|
|
|
|
|
args.source, args.database, args.neutralize, args.config
|
|
|
|
|
|
)
|
|
|
|
|
|
if code:
|
|
|
|
|
|
print(f"❌ {t('The duplication failed.')}", file=sys.stderr)
|
|
|
|
|
|
if sortie:
|
|
|
|
|
|
print(sortie[-2000:], file=sys.stderr)
|
|
|
|
|
|
return 2
|
|
|
|
|
|
print(f"✅ {t('Done:')} {args.database}")
|
[FIX] database: de 12 à 15, neutraliser par le script plutôt que refuser
De 12 à 15 la neutralisation d'Odoo n'existe pas et la demande était refusée ;
le dépôt a pourtant sa technique de longue date, update_prod_to_dev.sh, et une
copie imparfaitement neutralisée vaut mieux qu'une copie brute. Le chemin suivi
est ANNONCÉ à l'exécution, car les deux ne posent pas les mêmes gestes : le
script ne pose pas is_neutralized, ne désactive pas les crons et laisse les
clés de paiement, là où il supprime les serveurs de courriel et pose un compte
de développement. Un seul cas reste refusé, le script introuvable, et son échec
fait échouer la copie : elle sortirait brute en s'annonçant neutralisée.
--- EN ---
From 12 to 15 Odoo's neutralisation does not exist and the request was refused;
yet the repository has long had its own technique, update_prod_to_dev.sh, and
an imperfectly neutralised copy beats a raw one. The route taken is ANNOUNCED
at run time, because the two do not make the same gestures: the script does not
set is_neutralized, does not disable crons and leaves the payment keys, where
it deletes the mail servers and sets up a development account. One case is
still refused, a missing script, and its failure fails the copy: it would come
out raw while announcing itself neutralised.
Assisted-by: Claude Opus 5
(cherry picked from commit bd7b648305a09c37adfe4b280e7479f1f178f20e)
2026-08-25 04:12:04 -04:00
|
|
|
|
if args.neutralize and technique == NEUTRALISATION_SCRIPT:
|
|
|
|
|
|
print(
|
|
|
|
|
|
f"ℹ️ {t('This route does not set database.is_neutralized, does')}"
|
|
|
|
|
|
f" {t('not disable crons, and leaves payment keys in place.')}"
|
|
|
|
|
|
)
|
|
|
|
|
|
print(f"ℹ️ {t('You can log in with test / test.')}")
|
[ADD] database: dupliquer une base, et la neutraliser pour de bon
La duplication passe par exp_duplicate_database d'Odoo plutôt que par CREATE
DATABASE ... TEMPLATE : lui seul coupe les connexions de la source, régénère
database.uuid, copie le filestore et neutralise. Les trois modules maison du
dépôt n'obtenaient aucun des quatre.
Sous Odoo 15 et avant la neutralisation n'existe pas : la demande est REFUSÉE,
jamais ignorée — une copie qu'on croit neutralisée est pire qu'une brute.
Vérifié sur la copie d'une base migrée 12 → 18 : is_neutralized posé, crons
réduits au seul autovacuum, clé de paiement effacée, filestore copié.
--- EN ---
Duplication goes through Odoo's exp_duplicate_database rather than CREATE
DATABASE ... TEMPLATE: only it drops the source's connections, regenerates
database.uuid, copies the filestore and neutralises. The repository's three
in-house modules obtained none of the four.
Under Odoo 15 and earlier neutralisation does not exist: the request is
REFUSED, never ignored — a copy believed neutralised is worse than a raw one.
Checked on the copy of a 12 → 18 migrated database: is_neutralized set, crons
reduced to autovacuum alone, payment key cleared, filestore copied.
Assisted-by: Claude Opus 5
(cherry picked from commit af99d450c12e70a891d01d0ccf556c1d560e943b)
2026-08-25 03:55:46 -04:00
|
|
|
|
if not args.neutralize:
|
|
|
|
|
|
print(
|
|
|
|
|
|
f"⚠️ {t('NOT neutralised: its crons run, its mail leaves and')}"
|
|
|
|
|
|
f" {t('its payment providers can charge.')}"
|
|
|
|
|
|
)
|
|
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
sys.exit(main())
|