Clean command
This commit is contained in:
+32
-1
@@ -9,7 +9,7 @@ les parcours alternatifs.
|
||||
- [[file:Readme.org][Guide de démarrage]]
|
||||
- [[file:Architecture.org][Architecture et conventions de développement]]
|
||||
|
||||
* Étapes et Script
|
||||
* Étapes
|
||||
|
||||
Utiliser `python -m copienator gui` ou `python -m copienator gui Interro` pour lancer un GUI
|
||||
qui suit automatiquement les étapes décrites ci-dessous.
|
||||
@@ -314,6 +314,37 @@ OU
|
||||
+ update the copies from =miqmacs.fr/admin=.
|
||||
6. (gestion perso) Impression d'une copie. Via Evince » print to pdf.
|
||||
|
||||
** Archivage et nettoyage
|
||||
|
||||
Une fois l'évaluation terminée, =python -m copienator clean Interro=
|
||||
supprime les fichiers intermédiaires et régénérables. La commande ne
|
||||
conserve que :
|
||||
|
||||
+ les PDF =Copies/*.pdf= produits après le découpage des pages ;
|
||||
+ les sources et sorties textuelles du prétraitement de l'énoncé :
|
||||
=enonce.tex=, =correction.tex=, =labels=, =label_groups=, =Text=,
|
||||
=Sol=, =Persp=, les fichiers TeX de =Text2= et =Sol2=, =Cache= et
|
||||
=Tmp= ;
|
||||
+ le résultat final =correction.json= ;
|
||||
+ les journaux de =.copienator/logs= et les journaux placés à la
|
||||
racine, comme =correction_log= ;
|
||||
+ les images et fichiers =score.json= présents dans =A Rendre=.
|
||||
|
||||
Les liens symboliques conservés dans =A Rendre= sont remplacés par de
|
||||
véritables fichiers avant la suppression de leurs cibles. La commande
|
||||
refuse de démarrer si les copies traitées, =correction.json= ou une
|
||||
image/un score d'élève sont absents. Elle affiche d'abord un résumé et
|
||||
demande de saisir le nom de l'évaluation pour confirmer.
|
||||
|
||||
Dans le GUI, cette commande apparaît comme dernière étape facultative
|
||||
dans la section =Archivage=. Un avertissement rappelle que la
|
||||
progression du GUI et les données binaires permettant de reprendre les
|
||||
étapes seront définitivement perdues.
|
||||
|
||||
Utiliser =python -m copienator clean Interro --dry-run= pour afficher
|
||||
le plan sans rien supprimer, et =--yes= pour omettre la confirmation
|
||||
interactive.
|
||||
|
||||
* Autres
|
||||
** Recorrection d'une seule copie (peu testé)
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ COMMANDS: dict[str, Command] = {
|
||||
"giving-names": Command("giving_names", "Name copies and prepare A Rendre"),
|
||||
"update-ods": Command("update_ods", "Update the configured score spreadsheet"),
|
||||
"add-final-score": Command("add_final_score", "Stamp final scores on copies"),
|
||||
"clean": Command("clean", "Delete intermediate files from a finished evaluation"),
|
||||
"gui": Command("@gui", "Launch the graphical workflow assistant"),
|
||||
}
|
||||
|
||||
|
||||
+23
-2
@@ -802,8 +802,9 @@ class CopienatorApp(tk.Tk):
|
||||
variant = self._current_variant()
|
||||
command = self._make_command()
|
||||
if variant.dangerous and not messagebox.askyesno(
|
||||
"Confirmation requise",
|
||||
"Cette commande réinitialise ou supprime des résultats de correction. Continuer ?",
|
||||
"Nettoyage irréversible" if step.id == "clean" else "Confirmation requise",
|
||||
variant.danger_warning
|
||||
or "Cette commande réinitialise ou supprime des résultats de correction. Continuer ?",
|
||||
icon="warning",
|
||||
):
|
||||
return
|
||||
@@ -893,6 +894,26 @@ class CopienatorApp(tk.Tk):
|
||||
if not step_id:
|
||||
return
|
||||
status = process_status(return_code, interrupted)
|
||||
if step_id == "clean" and status == "success":
|
||||
self._append_console(
|
||||
f"\n[Terminé — code {return_code} — {STATUS_LABELS[status]}]\n"
|
||||
)
|
||||
self.info_var.set(
|
||||
"Nettoyage terminé : la progression précédente a été supprimée."
|
||||
)
|
||||
self.active_step_id = None
|
||||
# Do not recreate .copienator-gui.json after clean removed it.
|
||||
self.state_store = StateStore()
|
||||
self._populate_tree()
|
||||
self._update_controls()
|
||||
messagebox.showinfo(
|
||||
"Nettoyage terminé",
|
||||
"Les fichiers intermédiaires et la progression du GUI ont été "
|
||||
"supprimés. Les copies traitées, les fichiers textuels de l’énoncé, "
|
||||
"correction.json, les journaux et les livrables de A Rendre ont "
|
||||
"été conservés.",
|
||||
)
|
||||
return
|
||||
self.state_store.update_step(step_id, status=status, return_code=return_code)
|
||||
self.state_store.add_history(
|
||||
{
|
||||
|
||||
@@ -27,12 +27,15 @@ class ProcessRunner:
|
||||
command: list[str],
|
||||
cwd: Path,
|
||||
environment: dict[str, str],
|
||||
log_path: Path,
|
||||
log_path: Path | None,
|
||||
) -> None:
|
||||
if self.running:
|
||||
raise RuntimeError("Un processus est déjà en cours")
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._log_file = log_path.open("wb")
|
||||
if log_path is not None:
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._log_file = log_path.open("wb")
|
||||
else:
|
||||
self._log_file = None
|
||||
self._interrupted = False
|
||||
|
||||
kwargs: dict[str, Any] = {}
|
||||
|
||||
@@ -32,6 +32,7 @@ class CommandVariant:
|
||||
fixed_args: tuple[str, ...] = ()
|
||||
fixed_args_before_positionals: bool = False
|
||||
dangerous: bool = False
|
||||
danger_warning: str | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -473,6 +474,36 @@ def build_workflow(show_personal_steps: bool) -> list[StepDefinition]:
|
||||
personal=True,
|
||||
optional=True,
|
||||
),
|
||||
StepDefinition(
|
||||
"clean",
|
||||
"Archivage",
|
||||
"Nettoyer les fichiers intermédiaires",
|
||||
"Supprime définitivement les fichiers permettant de reprendre le parcours. "
|
||||
"Conserve les PDF traités, les fichiers textuels de l’énoncé, correction.json, "
|
||||
"les journaux, ainsi que les images et score.json de A Rendre.",
|
||||
(
|
||||
python(
|
||||
"default",
|
||||
"Nettoyage définitif",
|
||||
"clean",
|
||||
fixed_args=("--yes",),
|
||||
dangerous=True,
|
||||
danger_warning=(
|
||||
"Le nettoyage est irréversible.\n\n"
|
||||
"Toute la progression du GUI et les fichiers intermédiaires "
|
||||
"seront supprimés. Il ne sera plus possible de reprendre une "
|
||||
"étape sans régénérer ses données.\n\n"
|
||||
"Les PDF traités, les fichiers textuels de l’énoncé, "
|
||||
"correction.json, les journaux, ainsi que les images et "
|
||||
"score.json de A Rendre seront conservés.\n\n"
|
||||
"Continuer ?"
|
||||
),
|
||||
),
|
||||
),
|
||||
arguments=(arg_target("Dossier de l’évaluation"),),
|
||||
optional=True,
|
||||
requires=("Copies", "correction.json", "A Rendre"),
|
||||
),
|
||||
]
|
||||
return [step for step in steps if show_personal_steps or not step.personal]
|
||||
|
||||
|
||||
@@ -1652,6 +1652,20 @@ class WorkflowTests(unittest.TestCase):
|
||||
self.assertEqual(rotate[2:], ["-m", "copienator", "copies", "rotate", self.evaluation])
|
||||
self.assertEqual(rename[2:], ["-m", "copienator", "copies", "rename", self.evaluation])
|
||||
|
||||
def test_clean_is_the_last_dangerous_gui_step(self) -> None:
|
||||
ordered_steps = build_workflow(True)
|
||||
clean = ordered_steps[-1]
|
||||
self.assertEqual(clean.id, "clean")
|
||||
self.assertTrue(clean.optional)
|
||||
self.assertTrue(clean.variants[0].dangerous)
|
||||
self.assertIn("progression", clean.variants[0].danger_warning)
|
||||
self.assertEqual(
|
||||
command_arguments(
|
||||
self.command("clean", "default", {"target": self.evaluation})
|
||||
),
|
||||
[self.evaluation, "--yes"],
|
||||
)
|
||||
|
||||
|
||||
class CrossPlatformFileTests(unittest.TestCase):
|
||||
def test_rotate_all_skips_statement(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user