fix(ops): la sauvegarde des contrats archivait le mauvais repertoire
OBS-006. Trois racines etaient baties sur os.getcwd() : le magasin de documents, les journaux et les sauvegardes. La vague G a corrige la premiere, parce qu'elle bloquait aussi OPS-011, et a laisse les deux autres. C'est la lecon deja consignee deux fois : un motif fautif corrige dans une seule couche reste dans les autres. Le plus serieux n'est pas le motif, c'est l'ecart qu'il a ouvert. backup.py gardait sa propre constante DOCUMENTS_DIR sur os.getcwd(), donc il ignorait DOCUMENTS_ROOT -- la variable que la vague G a introduite et que docs/deployment.md dit maintenant de regler pour sortir les televersements des repertoires de version. Des qu'un exploitant suit cette consigne, le script archive un repertoire ou l'application n'a jamais rien ecrit. Et comme il repond a un repertoire absent par une ligne d'information et un code de sortie 0, une tache planifiee qui surveille le code de sortie voit vert indefiniment. Autrement dit : plus l'exploitant suivait correctement la documentation de deploiement, plus surement ses sauvegardes de contrats etaient vides. Les trois racines viennent desormais d'app/storage.py, resolues a l'appel et non a l'import, et la sauvegarde imprime la source qu'elle a utilisee. Le message d'absence nomme le chemin ou elle a cherche : "No documents directory found" se lisait comme "il n'y a pas de documents" plutot que comme "je regarde au mauvais endroit". Le test qui porte est celui qui ouvre l'archive : un zip vide est un fichier de taille non nulle, donc verifier qu'un fichier a ete produit ne prouvait rien. Verifie par mutation. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+52
-4
@@ -1,4 +1,13 @@
|
||||
"""Where uploaded documents live, and how the database refers to them.
|
||||
"""Where the application's files live, and how the database refers to them.
|
||||
|
||||
Three roots: the project itself, the document store, and the log directory.
|
||||
They are here together because they are the same defect three times over
|
||||
(OBS-006) — `os.path.join(os.getcwd(), …)`, evaluated at import or upload
|
||||
time, so every one of them moved with whatever directory the process was
|
||||
started from. The document store was fixed first, in wave G, because it was
|
||||
the one that also blocked OPS-011; the other two were left behind, which is
|
||||
the repeated lesson of this project: a faulty pattern corrected in one layer
|
||||
stays in the others.
|
||||
|
||||
Contracts were stored at `os.path.join(os.getcwd(), 'documents', …)`,
|
||||
evaluated at upload time, and the resulting absolute path was written into
|
||||
@@ -26,21 +35,60 @@ import os
|
||||
#: inside whichever one is current.
|
||||
DOCUMENTS_ROOT_ENV = 'DOCUMENTS_ROOT'
|
||||
|
||||
#: Environment override for the log directory. Same reasoning: a release
|
||||
#: directory that carries its own logs loses them at the next switch.
|
||||
LOG_DIR_ENV = 'LOG_DIR'
|
||||
|
||||
#: Environment override for the backup directory.
|
||||
BACKUP_DIR_ENV = 'BACKUP_DIR'
|
||||
|
||||
#: Sub-directory holding uploaded contracts, under the document root.
|
||||
CONTRACTS_DIR = 'contrats signés'
|
||||
|
||||
|
||||
def project_root():
|
||||
"""Absolute path of the project, derived from this file's location.
|
||||
|
||||
The anchor every other root falls back to. Not `os.getcwd()`: the
|
||||
process is started by Waitress under Pterodactyl, by pytest, by a task
|
||||
scheduler and by a person in a shell, and only one of those four is
|
||||
reliably in the project directory.
|
||||
"""
|
||||
package_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.dirname(package_dir)
|
||||
|
||||
|
||||
def documents_root():
|
||||
"""Absolute path of the document store.
|
||||
|
||||
Falls back to `documents/` beside this package — the project root
|
||||
wherever it is installed, rather than wherever the process was launched.
|
||||
"""
|
||||
configured = os.getenv(DOCUMENTS_ROOT_ENV)
|
||||
return _rooted(DOCUMENTS_ROOT_ENV, 'documents')
|
||||
|
||||
|
||||
def logs_root():
|
||||
"""Absolute path of the log directory.
|
||||
|
||||
Was `os.path.join(os.getcwd(), 'logs')`. Starting the server from
|
||||
another directory sent the logs somewhere new without a word, which is
|
||||
the worst possible failure mode for the one file you go and read when
|
||||
something else has gone wrong.
|
||||
"""
|
||||
return _rooted(LOG_DIR_ENV, 'logs')
|
||||
|
||||
|
||||
def backups_root():
|
||||
"""Absolute path of the backup directory."""
|
||||
return _rooted(BACKUP_DIR_ENV, 'backups')
|
||||
|
||||
|
||||
def _rooted(env_name, default_name):
|
||||
"""The configured path, or `default_name` under the project root."""
|
||||
configured = os.getenv(env_name)
|
||||
if configured:
|
||||
return os.path.abspath(configured)
|
||||
package_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.join(os.path.dirname(package_dir), 'documents')
|
||||
return os.path.join(project_root(), default_name)
|
||||
|
||||
|
||||
def discard_documents(stored_paths):
|
||||
|
||||
Reference in New Issue
Block a user