mirror of
https://github.com/hilman2/easy-ocpp.git
synced 2026-10-20 08:46:49 +02:00
Migrations-Prüfsummen: Zeilenenden fixieren (v0.3.1)
Bestehende Installationen brachen beim Start mit dem Windows-Release-Binary ab: "migration 1 was previously applied but has been modified" – obwohl die Migration inhaltlich seit v0.2.0 unverändert ist. Ursache: .gitattributes enthielt nur "* text=auto". Zusammen mit core.autocrlf=true (Standard auf windows-latest-Runnern) checkt actions/checkout die .sql-Dateien als CRLF aus. sqlx::migrate! bettet den Dateiinhalt zur Compile-Zeit ein und bildet darüber eine SHA-384-Summe, die beim Start gegen _sqlx_migrations geprüft wird: 0001_initial.sql mit LF -> 0651a39f... 0001_initial.sql mit CRLF -> 90093a9a... Die GitHub-Windows-Builds v0.2.0 und v0.3.0 tragen die CRLF-Variante, lokal gebaute Exes und der Linux-Build die LF-Variante. Datenbanken, die mit einem LF-Binary angelegt wurden, kollidieren daher mit dem Windows-Release-ZIP. Zwei Änderungen: 1. .gitattributes erzwingt "*.sql text eol=lf". Ab jetzt erzeugen Windows- und Linux-Runner identische Prüfsummen. 2. db::repair_line_ending_checksums() hebt eine gespeicherte Prüfsumme vor dem Migrationslauf an – aber nur, wenn sie exakt der Zeilenenden-Variante desselben SQL entspricht, in beide Richtungen. Ohne diesen Schritt würde Punkt 1 jede Installation brechen, die mit dem CRLF-Binary aus dem GitHub-ZIP von v0.2.0/v0.3.0 angelegt wurde. Echte inhaltliche Abweichungen führen weiterhin zum Abbruch durch sqlx. sha2 wird dafür direkte Dependency (war bereits transitiv gelockt, die Auflösung ändert sich nicht). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1,8 @@
|
||||
* text=auto
|
||||
|
||||
# Migrationen MÜSSEN LF behalten: sqlx::migrate! bildet eine SHA-384-Prüfsumme
|
||||
# über den Dateiinhalt und vergleicht sie mit der in _sqlx_migrations
|
||||
# gespeicherten. Ein CRLF-Checkout (Windows-Buildrunner) erzeugt sonst eine
|
||||
# andere Prüfsumme als ein LF-Checkout (Linux) -> "migration 1 was previously
|
||||
# applied but has been modified" beim Start gegen eine bestehende Datenbank.
|
||||
*.sql text eol=lf
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# easy-occp v0.3.0 – Installation & Erststart (Windows)
|
||||
# easy-occp v0.3.1 – Installation & Erststart (Windows)
|
||||
|
||||
🌐 [English](INSTALL.md) · [Deutsch](ANLEITUNG.md) · [Français](INSTALL.fr.md) · [Español](INSTALL.es.md)
|
||||
|
||||
@@ -171,4 +171,4 @@ Dienst/Aufgabe entfernen, Ordner löschen — es gibt keine Registry-Einträge u
|
||||
|
||||
---
|
||||
|
||||
Version 0.3.0 · Lizenz: MIT
|
||||
Version 0.3.1 · Lizenz: MIT
|
||||
|
||||
Generated
+2
-1
@@ -578,7 +578,7 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "easy-occp"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -596,6 +596,7 @@ dependencies = [
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "easy-occp"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2021"
|
||||
rust-version = "1.80"
|
||||
description = "Einfaches Management-Tool für Wallboxen (OCPP 1.5/1.6/2.0.1) für KMUs"
|
||||
@@ -30,6 +30,7 @@ clap = { version = "4", features = ["derive"] }
|
||||
futures-util = "0.3"
|
||||
parking_lot = "0.12"
|
||||
base64 = "0.22"
|
||||
sha2 = "0.10"
|
||||
dashmap = "6"
|
||||
printpdf = "0.7"
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# easy-occp v0.3.0 – Instalación y primer arranque (Windows)
|
||||
# easy-occp v0.3.1 – Instalación y primer arranque (Windows)
|
||||
|
||||
🌐 [English](INSTALL.md) · [Deutsch](ANLEITUNG.md) · [Français](INSTALL.fr.md) · [Español](INSTALL.es.md)
|
||||
|
||||
@@ -175,4 +175,4 @@ Elimine el servicio/la tarea y borre la carpeta — no hay entradas en el regist
|
||||
|
||||
---
|
||||
|
||||
Versión 0.3.0 · Licencia: MIT
|
||||
Versión 0.3.1 · Licencia: MIT
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# easy-occp v0.3.0 – Installation & premier démarrage (Windows)
|
||||
# easy-occp v0.3.1 – Installation & premier démarrage (Windows)
|
||||
|
||||
🌐 [English](INSTALL.md) · [Deutsch](ANLEITUNG.md) · [Français](INSTALL.fr.md) · [Español](INSTALL.es.md)
|
||||
|
||||
@@ -174,4 +174,4 @@ Supprimez le service/la tâche, supprimez le dossier — il n'y a ni entrées de
|
||||
|
||||
---
|
||||
|
||||
Version 0.3.0 · Licence : MIT
|
||||
Version 0.3.1 · Licence : MIT
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# easy-occp v0.3.0 – Installation & First Start (Windows)
|
||||
# easy-occp v0.3.1 – Installation & First Start (Windows)
|
||||
|
||||
🌐 [English](INSTALL.md) · [Deutsch](ANLEITUNG.md) · [Français](INSTALL.fr.md) · [Español](INSTALL.es.md)
|
||||
|
||||
@@ -172,4 +172,4 @@ Remove the service/task, delete the folder — there are no registry entries and
|
||||
|
||||
---
|
||||
|
||||
Version 0.3.0 · License: MIT
|
||||
Version 0.3.1 · License: MIT
|
||||
|
||||
@@ -85,3 +85,80 @@ pub async fn setting_set(db: &SqlitePool, key: &str, value: &str) -> Result<()>
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Repariert Prüfsummen in `_sqlx_migrations`, die sich nur durch die
|
||||
/// Zeilenenden der Migrationsdatei unterscheiden.
|
||||
///
|
||||
/// Hintergrund: `sqlx::migrate!` bettet den Dateiinhalt zur Compile-Zeit ein und
|
||||
/// prüft beim Start eine SHA-384-Summe darüber. Wird dieselbe Migration einmal
|
||||
/// aus einem LF- und einmal aus einem CRLF-Checkout gebaut (Windows-Buildrunner
|
||||
/// ohne `eol=lf`), unterscheiden sich die Summen und sqlx bricht mit
|
||||
/// "migration N was previously applied but has been modified" ab, obwohl das
|
||||
/// SQL identisch ist. In diesem – und nur in diesem – Fall wird die gespeicherte
|
||||
/// Prüfsumme auf den aktuellen Wert gehoben.
|
||||
pub async fn repair_line_ending_checksums(
|
||||
db: &SqlitePool,
|
||||
migrator: &sqlx::migrate::Migrator,
|
||||
) -> Result<()> {
|
||||
let table: Option<(String,)> = sqlx::query_as(
|
||||
"SELECT name FROM sqlite_master WHERE type = 'table' AND name = '_sqlx_migrations'",
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
.context("Migrationstabelle konnte nicht gelesen werden")?;
|
||||
if table.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let applied: Vec<(i64, Vec<u8>)> =
|
||||
sqlx::query_as("SELECT version, checksum FROM _sqlx_migrations")
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.context("Angewandte Migrationen konnten nicht gelesen werden")?;
|
||||
|
||||
for migration in migrator.iter() {
|
||||
let Some((_, stored)) = applied.iter().find(|(v, _)| *v == migration.version) else {
|
||||
continue;
|
||||
};
|
||||
if stored.as_slice() == migration.checksum.as_ref() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Gegenstück mit umgedrehten Zeilenenden bilden und prüfen.
|
||||
let normalized = migration.sql.replace("\r\n", "\n");
|
||||
let variant = if migration.sql.contains("\r\n") {
|
||||
normalized
|
||||
} else {
|
||||
normalized.replace('\n', "\r\n")
|
||||
};
|
||||
if stored.as_slice() != sha384(variant.as_bytes()).as_slice() {
|
||||
continue; // Echte inhaltliche Abweichung – sqlx soll abbrechen.
|
||||
}
|
||||
|
||||
sqlx::query("UPDATE _sqlx_migrations SET checksum = ?1 WHERE version = ?2")
|
||||
.bind(migration.checksum.as_ref())
|
||||
.bind(migration.version)
|
||||
.execute(db)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Prüfsumme der Migration {} konnte nicht aktualisiert werden",
|
||||
migration.version
|
||||
)
|
||||
})?;
|
||||
tracing::warn!(
|
||||
"Migration {} ({}): Prüfsumme wich nur in den Zeilenenden ab und wurde korrigiert.",
|
||||
migration.version,
|
||||
migration.description
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sha384(data: &[u8]) -> Vec<u8> {
|
||||
use sha2::{Digest, Sha384};
|
||||
let mut hasher = Sha384::new();
|
||||
hasher.update(data);
|
||||
hasher.finalize().to_vec()
|
||||
}
|
||||
|
||||
+3
-1
@@ -65,7 +65,9 @@ async fn main() -> Result<()> {
|
||||
.await
|
||||
.context("SQLite-Pool konnte nicht geöffnet werden")?;
|
||||
|
||||
sqlx::migrate!("./migrations")
|
||||
let migrator = sqlx::migrate!("./migrations");
|
||||
db::repair_line_ending_checksums(&db, &migrator).await?;
|
||||
migrator
|
||||
.run(&db)
|
||||
.await
|
||||
.context("Migrationen fehlgeschlagen")?;
|
||||
|
||||
Reference in New Issue
Block a user