Premiere commit - Omika
This commit is contained in:
@@ -0,0 +1,525 @@
|
||||
# ============================================================
|
||||
# Omika - Generation / verification du manifeste des packs de langue
|
||||
# (manifest.json de Omika.Langues.Api)
|
||||
# ============================================================
|
||||
# Le manifeste decrit les packs ONNX telechargeables par le mobile. Ce n'est PAS
|
||||
# un fichier de publication : il decrit les fichiers REELLEMENT presents sous
|
||||
# Langues__RootPath. Il se genere donc la ou sont les modeles, pas dans le depot.
|
||||
#
|
||||
# Arborescence attendue : <racine>\<code>\<sens>\<fichier>, ou <sens> vaut
|
||||
# versFrancais, depuisFrancais, ou commun (poids partages par les deux sens d'un
|
||||
# modele familial ; le mobile ne les telecharge qu'une fois).
|
||||
#
|
||||
# Deux champs ne peuvent pas etre saisis a la main sans risque :
|
||||
# - tailleOctets : taille reelle (progression du telechargement mobile) ;
|
||||
# - sha256 : empreinte d'integrite, reverifiee par le mobile APRES
|
||||
# telechargement. Une empreinte fausse ou absente ne se voit
|
||||
# QUE sur le telephone : le pack est refuse et pack.json
|
||||
# n'est jamais ecrit (aucune erreur ne remonte au serveur).
|
||||
# Ce script les calcule depuis les fichiers. Aucune valeur n'est inventee.
|
||||
#
|
||||
# Usage :
|
||||
# .\New-OmikaLanguesManifeste.ps1 # genere sous RootPath
|
||||
# .\New-OmikaLanguesManifeste.ps1 -WhatIf # simulation, affiche
|
||||
# .\New-OmikaLanguesManifeste.ps1 -RootPathLangues D:\Modeles
|
||||
# .\New-OmikaLanguesManifeste.ps1 -Verifier # controle d'integrite
|
||||
# .\New-OmikaLanguesManifeste.ps1 -Libelles @{ es = 'Espagnol (Espagne)' }
|
||||
#
|
||||
# -Verifier compare le manifeste EXISTANT aux fichiers du disque et sort en
|
||||
# erreur (code 1) au moindre ecart. Aucun droit administrateur n'est requis :
|
||||
# c'est le controle a passer apres chaque ajout ou remplacement de modele.
|
||||
#
|
||||
# La racine par defaut est lue dans Langues__RootPath (MACHINE), donc la meme
|
||||
# source de verite que le service : le manifeste est ecrit la ou l'API le lit.
|
||||
# ============================================================
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||
param(
|
||||
# Dossier racine des modeles. Par defaut : variable MACHINE Langues__RootPath,
|
||||
# puis C:\Omika\Data\Langues (recommandation du DEPLOIEMENT_API_LANGUES.md §6).
|
||||
[string]$RootPathLangues,
|
||||
|
||||
# Fichier manifeste. Par defaut : <RootPathLangues>\manifest.json.
|
||||
[string]$Sortie,
|
||||
|
||||
# Version ecrite dans chaque pack (le mobile la compare a celle installee).
|
||||
[string]$Version = '1.0.0',
|
||||
|
||||
# Libelles affiches, par code de langue. Complete/ecrase la table par defaut.
|
||||
[hashtable]$Libelles = @{},
|
||||
|
||||
# Autorise l'ecriture d'un manifeste SANS aucun pack (deconseille : le mobile
|
||||
# affiche alors « Aucun modele de langue n'est disponible sur le serveur »).
|
||||
[switch]$AutoriserVide,
|
||||
|
||||
# Controle le manifeste existant au lieu de le regenerer.
|
||||
[switch]$Verifier
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Sens canoniques : le mobile compare ces valeurs de facon SENSIBLE A LA CASSE.
|
||||
# « commun » porte les poids PARTAGES par les deux sens d'un modele familial
|
||||
# (opus-mt-tc-big-itc-itc) : le telephone les telecharge une seule fois, et
|
||||
# chaque sens ne contient que son modele.json (jeton de cible).
|
||||
$SensCanoniques = @('versFrancais', 'depuisFrancais', 'commun')
|
||||
|
||||
# Noms de vocabulaire reconnus par l'application (OnnxTranslationService) :
|
||||
# vocab.spm = vocabulaire commun, source.spm / target.spm = vocabulaire par
|
||||
# langue d'un modele Marian/OPUS-MT. Tout autre nom .spm n'est qu'un repli.
|
||||
$NomsVocabulaire = @('vocab.spm', 'source.spm', 'target.spm')
|
||||
|
||||
$LibellesParDefaut = @{
|
||||
'ar' = 'Arabe'
|
||||
'bg' = 'Bulgare'
|
||||
'ca' = 'Catalan'
|
||||
'cs' = 'Tchèque'
|
||||
'da' = 'Danois'
|
||||
'de' = 'Allemand'
|
||||
'el' = 'Grec'
|
||||
'en' = 'Anglais'
|
||||
'es' = 'Espagnol'
|
||||
'et' = 'Estonien'
|
||||
'fi' = 'Finnois'
|
||||
'gl' = 'Galicien'
|
||||
'hr' = 'Croate'
|
||||
'hu' = 'Hongrois'
|
||||
'is' = 'Islandais'
|
||||
'it' = 'Italien'
|
||||
'lt' = 'Lituanien'
|
||||
'lv' = 'Letton'
|
||||
'mk' = 'Macédonien'
|
||||
'mt' = 'Maltais'
|
||||
'nl' = 'Néerlandais'
|
||||
'no' = 'Norvégien'
|
||||
'pl' = 'Polonais'
|
||||
'pt' = 'Portugais'
|
||||
'ro' = 'Roumain'
|
||||
'ru' = 'Russe'
|
||||
'sk' = 'Slovaque'
|
||||
'sl' = 'Slovène'
|
||||
'sv' = 'Suédois'
|
||||
'tr' = 'Turc'
|
||||
'uk' = 'Ukrainien'
|
||||
'zh' = 'Chinois'
|
||||
}
|
||||
|
||||
function Write-ManifesteInfo([string]$message) { Write-Host (' ' + $message) }
|
||||
function Write-ManifesteOk([string]$message) { Write-Host ('[OK] ' + $message) -ForegroundColor Green }
|
||||
function Write-ManifesteAlerte([string]$message) { Write-Host ('[ALERTE] ' + $message) -ForegroundColor Yellow }
|
||||
function Write-ManifesteEchec([string]$message) { Write-Host ('[ECHEC] ' + $message) -ForegroundColor Red }
|
||||
|
||||
function Format-ManifesteTaille([long]$octets) {
|
||||
if ($octets -ge 1073741824) { return ('{0:N2} Gio' -f ($octets / 1073741824)) }
|
||||
if ($octets -ge 1048576) { return ('{0:N1} Mio' -f ($octets / 1048576)) }
|
||||
if ($octets -ge 1024) { return ('{0:N0} Kio' -f ($octets / 1024)) }
|
||||
return ('{0} octets' -f $octets)
|
||||
}
|
||||
|
||||
# Code de langue : memes regles que LanguagePaths.EstCodeValide cote application
|
||||
# (2 a 10 caracteres, minuscules ASCII, chiffres, tiret). Un code invalide fait
|
||||
# IGNORER le pack SILENCIEUSEMENT par le mobile : on refuse de l'ecrire.
|
||||
function Test-ManifesteCodeValide([string]$code) {
|
||||
if ([string]::IsNullOrWhiteSpace($code)) { return $false }
|
||||
|
||||
$valeur = $code.Trim()
|
||||
if ($valeur.Length -lt 2 -or $valeur.Length -gt 10) { return $false }
|
||||
if ($valeur[0] -eq '-' -or $valeur[-1] -eq '-') { return $false }
|
||||
|
||||
foreach ($c in $valeur.ToCharArray()) {
|
||||
$autorise = (($c -ge 'a' -and $c -le 'z') -or ($c -ge '0' -and $c -le '9') -or $c -eq '-')
|
||||
if (-not $autorise) { return $false }
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
# Retourne le sens canonique, ou $null si le dossier n'est pas un sens connu.
|
||||
function Resolve-ManifesteSens([string]$nomDossier) {
|
||||
foreach ($canonique in $SensCanoniques) {
|
||||
if ([string]::Equals($nomDossier, $canonique, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
return $canonique
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Resolve-ManifesteLibelle([string]$code, [hashtable]$surcharge) {
|
||||
if ($surcharge -and $surcharge.ContainsKey($code)) { return [string]$surcharge[$code] }
|
||||
if ($LibellesParDefaut.ContainsKey($code)) { return [string]$LibellesParDefaut[$code] }
|
||||
return $code.ToUpperInvariant()
|
||||
}
|
||||
|
||||
# SHA-256 hexadecimal minuscule : exactement ce que le mobile recalcule.
|
||||
function Get-ManifesteEmpreinte([string]$chemin) {
|
||||
return (Get-FileHash -LiteralPath $chemin -Algorithm SHA256).Hash.ToLowerInvariant()
|
||||
}
|
||||
|
||||
# Echappe une chaine pour du JSON (guillemets, antislash, caracteres de controle).
|
||||
function ConvertTo-ManifesteJsonChaine([string]$valeur) {
|
||||
$sb = New-Object System.Text.StringBuilder
|
||||
[void]$sb.Append('"')
|
||||
foreach ($c in $valeur.ToCharArray()) {
|
||||
$code = [int]$c
|
||||
if ($c -eq '"') { [void]$sb.Append('\"') }
|
||||
elseif ($c -eq '\') { [void]$sb.Append('\\') }
|
||||
elseif ($code -lt 32) { [void]$sb.Append(('\u{0:x4}' -f $code)) }
|
||||
else { [void]$sb.Append($c) }
|
||||
}
|
||||
[void]$sb.Append('"')
|
||||
return $sb.ToString()
|
||||
}
|
||||
|
||||
function New-ManifesteBlocFichier([string]$sens, [string]$nomFichier, [long]$taille, [string]$sha256) {
|
||||
$lignes = @(
|
||||
' {'
|
||||
(' "sens": ' + (ConvertTo-ManifesteJsonChaine $sens) + ',')
|
||||
(' "nomFichier": ' + (ConvertTo-ManifesteJsonChaine $nomFichier) + ',')
|
||||
(' "tailleOctets": ' + $taille + ',')
|
||||
(' "sha256": ' + (ConvertTo-ManifesteJsonChaine $sha256))
|
||||
' }'
|
||||
)
|
||||
return ($lignes -join "`r`n")
|
||||
}
|
||||
|
||||
function New-ManifesteBlocPack([string]$code, [string]$libelle, [string]$version, $blocsFichiers) {
|
||||
$lignes = @(
|
||||
' {'
|
||||
(' "code": ' + (ConvertTo-ManifesteJsonChaine $code) + ',')
|
||||
(' "libelle": ' + (ConvertTo-ManifesteJsonChaine $libelle) + ',')
|
||||
(' "version": ' + (ConvertTo-ManifesteJsonChaine $version) + ',')
|
||||
' "fichiers": ['
|
||||
($blocsFichiers -join (",`r`n"))
|
||||
' ]'
|
||||
' }'
|
||||
)
|
||||
return ($lignes -join "`r`n")
|
||||
}
|
||||
|
||||
function New-ManifesteJsonText($blocsPacks) {
|
||||
# Tableau vide ecrit « [] » et non « [\n\n] » : lisible et sans ligne blanche.
|
||||
$corps = if ($blocsPacks.Count -eq 0) {
|
||||
@(' "packs": []')
|
||||
}
|
||||
else {
|
||||
@(
|
||||
' "packs": ['
|
||||
($blocsPacks -join (",`r`n"))
|
||||
' ]'
|
||||
)
|
||||
}
|
||||
|
||||
$lignes = @('{') + $corps + @('}')
|
||||
return (($lignes -join "`r`n") + "`r`n")
|
||||
}
|
||||
|
||||
# JSON ecrit en UTF-8 SANS BOM : un manifeste est un fichier de donnees lu par
|
||||
# l'API et par des outils externes, jamais un script.
|
||||
function Write-ManifesteFichier([string]$chemin, [string]$contenu) {
|
||||
$encodage = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($chemin, $contenu, $encodage)
|
||||
}
|
||||
|
||||
function Write-ManifesteBilan($echecs, $alertes) {
|
||||
foreach ($alerte in $alertes) { Write-ManifesteAlerte $alerte }
|
||||
foreach ($echec in $echecs) { Write-ManifesteEchec $echec }
|
||||
Write-Host ''
|
||||
if ($echecs.Count -gt 0) {
|
||||
Write-Host ("=== RESULTAT : {0} ecart(s), {1} alerte(s) ===" -f $echecs.Count, $alertes.Count) -ForegroundColor Red
|
||||
return $false
|
||||
}
|
||||
Write-Host ("=== RESULTAT : conforme ({0} alerte(s)) ===" -f $alertes.Count) -ForegroundColor Green
|
||||
return $true
|
||||
}
|
||||
|
||||
# --- Racine effective --------------------------------------------------------
|
||||
if (-not $RootPathLangues) {
|
||||
$RootPathLangues = [Environment]::GetEnvironmentVariable('Langues__RootPath', 'Machine')
|
||||
}
|
||||
if (-not $RootPathLangues) {
|
||||
$RootPathLangues = [Environment]::GetEnvironmentVariable('Langues__RootPath', 'Process')
|
||||
}
|
||||
if (-not $RootPathLangues) {
|
||||
$RootPathLangues = 'C:\Omika\Data\Langues'
|
||||
}
|
||||
$racine = $RootPathLangues.Trim().TrimEnd([char[]]@('\', '/'))
|
||||
if (-not $Sortie) { $Sortie = Join-Path $racine 'manifest.json' }
|
||||
|
||||
Write-Host '=== Manifeste des packs de langue (Omika Langues API) ==='
|
||||
Write-ManifesteInfo ("Racine des modeles : {0}" -f $racine)
|
||||
Write-ManifesteInfo ("Manifeste : {0}" -f $Sortie)
|
||||
if ($Verifier) { Write-ManifesteInfo 'Mode : VERIFICATION (aucune ecriture)' }
|
||||
Write-Host ''
|
||||
|
||||
if (-not (Test-Path -LiteralPath $racine -PathType Container)) {
|
||||
Write-ManifesteEchec ("Racine introuvable : {0}" -f $racine)
|
||||
Write-ManifesteInfo 'Verifier Langues__RootPath (MACHINE), ou passer -RootPathLangues.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$echecs = New-Object 'System.Collections.Generic.List[string]'
|
||||
$alertes = New-Object 'System.Collections.Generic.List[string]'
|
||||
|
||||
# ============================================================================
|
||||
# MODE VERIFICATION
|
||||
# ============================================================================
|
||||
if ($Verifier) {
|
||||
if (-not (Test-Path -LiteralPath $Sortie -PathType Leaf)) {
|
||||
Write-ManifesteEchec ("Manifeste ABSENT : {0}" -f $Sortie)
|
||||
Write-ManifesteInfo 'Sans ce fichier, GET /api/langues repond 404 (et le mobile n''a aucune langue).'
|
||||
Write-ManifesteInfo 'Generer avec : .\New-OmikaLanguesManifeste.ps1'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$manifeste = $null
|
||||
try {
|
||||
$manifeste = (Get-Content -LiteralPath $Sortie -Raw -Encoding UTF8 | ConvertFrom-Json)
|
||||
}
|
||||
catch {
|
||||
Write-ManifesteEchec ("Manifeste illisible (JSON invalide) : {0}" -f $_.Exception.Message)
|
||||
Write-ManifesteInfo 'Cote service : « Manifeste des langues illisible » puis 404.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$packs = @($manifeste.packs)
|
||||
if ($packs.Count -eq 0) {
|
||||
$echecs.Add('Le manifeste ne declare aucun pack : le mobile affichera « Aucun modele de langue n''est disponible sur le serveur ».')
|
||||
}
|
||||
|
||||
$declare = New-Object 'System.Collections.Generic.List[string]'
|
||||
$nbFichiers = 0
|
||||
$octetsTotal = [long]0
|
||||
|
||||
foreach ($pack in $packs) {
|
||||
$code = ([string]$pack.code).Trim().ToLowerInvariant()
|
||||
if (-not (Test-ManifesteCodeValide $code)) {
|
||||
$echecs.Add(("Pack « {0} » : code de langue invalide -> IGNORE SILENCIEUSEMENT par le mobile." -f $pack.code))
|
||||
continue
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace([string]$pack.libelle)) {
|
||||
$alertes.Add(("Pack « {0} » : libelle vide (le code s'affichera a la place)." -f $code))
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace([string]$pack.version)) {
|
||||
$alertes.Add(("Pack « {0} » : version vide (comparaison d'installation impossible)." -f $code))
|
||||
}
|
||||
|
||||
$fichiers = @($pack.fichiers)
|
||||
if ($fichiers.Count -eq 0) {
|
||||
$echecs.Add(("Pack « {0} » : aucun fichier declare." -f $code))
|
||||
continue
|
||||
}
|
||||
|
||||
foreach ($fichier in $fichiers) {
|
||||
$sensManifeste = [string]$fichier.sens
|
||||
$sens = Resolve-ManifesteSens $sensManifeste
|
||||
if (-not $sens) {
|
||||
$echecs.Add(("Pack « {0} » : sens inconnu « {1} » (attendu versFrancais, depuisFrancais ou commun)." -f $code, $sensManifeste))
|
||||
continue
|
||||
}
|
||||
if ($sensManifeste -cne $sens) {
|
||||
$echecs.Add(("Pack « {0} » : sens « {1} » a la mauvaise casse -> REFUSE par le mobile (comparaison sensible a la casse)." -f $code, $sensManifeste))
|
||||
continue
|
||||
}
|
||||
|
||||
$nomFichier = [string]$fichier.nomFichier
|
||||
if ([string]::IsNullOrWhiteSpace($nomFichier)) {
|
||||
$echecs.Add(("Pack « {0} » : nomFichier vide." -f $code))
|
||||
continue
|
||||
}
|
||||
if ($nomFichier -ne [System.IO.Path]::GetFileName($nomFichier)) {
|
||||
$echecs.Add(("Pack « {0} » : nomFichier « {1} » contient un chemin (interdit)." -f $code, $nomFichier))
|
||||
continue
|
||||
}
|
||||
|
||||
$chemin = Join-Path (Join-Path (Join-Path $racine $code) $sens) $nomFichier
|
||||
$declare.Add($chemin.ToLowerInvariant())
|
||||
$relatif = ('{0}/{1}/{2}' -f $code, $sens, $nomFichier)
|
||||
|
||||
# Un fichier declare est un fichier TELECHARGE par chaque telephone :
|
||||
# signaler ceux qui ne servent a rien.
|
||||
if ($nomFichier.EndsWith('.onnx', [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
-and $nomFichier -match 'past') {
|
||||
$alertes.Add(("{0} : decodeur a cache (past_key_values) IGNORE par l'application, mais declare donc TELECHARGE pour rien." -f $relatif))
|
||||
}
|
||||
elseif ($nomFichier.EndsWith('.spm', [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
-and $NomsVocabulaire -notcontains $nomFichier) {
|
||||
$alertes.Add(("{0} : nom de vocabulaire non reconnu (attendu vocab.spm, source.spm ou target.spm) : pris comme repli « premier .spm »." -f $relatif))
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $chemin -PathType Leaf)) {
|
||||
$echecs.Add(("Fichier ABSENT sur le disque : {0} -> le mobile recevra 404." -f $relatif))
|
||||
continue
|
||||
}
|
||||
|
||||
$info = Get-Item -LiteralPath $chemin
|
||||
$taille = [long]$fichier.tailleOctets
|
||||
if ($taille -le 0) {
|
||||
$alertes.Add(("{0} : tailleOctets non renseignee (0) -> pas de controle de taille ni de progression." -f $relatif))
|
||||
}
|
||||
elseif ($taille -ne $info.Length) {
|
||||
$echecs.Add(("{0} : taille differente -> manifeste {1} octet(s), disque {2}." -f $relatif, $taille, $info.Length))
|
||||
}
|
||||
|
||||
$sha = ([string]$fichier.sha256).Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($sha)) {
|
||||
$echecs.Add(("{0} : empreinte SHA-256 absente -> le pack sera REFUSE par le mobile." -f $relatif))
|
||||
continue
|
||||
}
|
||||
|
||||
$reel = Get-ManifesteEmpreinte $chemin
|
||||
if (-not [string]::Equals($sha, $reel, [System.StringComparison]::OrdinalIgnoreCase)) {
|
||||
$echecs.Add(("{0} : empreinte differente ->`r`n manifeste {1}`r`n disque {2}" -f $relatif, $sha, $reel))
|
||||
}
|
||||
|
||||
$nbFichiers++
|
||||
$octetsTotal += $info.Length
|
||||
}
|
||||
}
|
||||
|
||||
# Fichiers presents mais non declares : jamais telecharges, poids mort.
|
||||
foreach ($fichierDisque in @(Get-ChildItem -LiteralPath $racine -Recurse -File)) {
|
||||
if ($fichierDisque.FullName.ToLowerInvariant() -eq $Sortie.ToLowerInvariant()) { continue }
|
||||
# La sauvegarde du manifeste ecrite par ce script n'est evidemment pas un
|
||||
# fichier de modele : la signaler serait un faux positif a chaque controle.
|
||||
if ($fichierDisque.FullName.ToLowerInvariant() -eq ($Sortie + '.bak').ToLowerInvariant()) { continue }
|
||||
|
||||
$relatifDisque = $fichierDisque.FullName.Substring($racine.Length).TrimStart('\', '/')
|
||||
# Dossiers techniques (ex. .hf-cache du script d'export, .tmp-*) : ce ne
|
||||
# sont pas des modeles, et un cache peut contenir des milliers de fichiers.
|
||||
if ($relatifDisque -match '(^|\\)\.[^\\]') { continue }
|
||||
|
||||
if (-not $declare.Contains($fichierDisque.FullName.ToLowerInvariant())) {
|
||||
$alertes.Add(("Fichier non declare dans le manifeste (jamais telecharge) : {0}" -f $relatifDisque))
|
||||
}
|
||||
}
|
||||
|
||||
Write-ManifesteInfo ("{0} pack(s), {1} fichier(s) verifie(s), {2}" -f $packs.Count, $nbFichiers, (Format-ManifesteTaille $octetsTotal))
|
||||
Write-Host ''
|
||||
|
||||
if (Write-ManifesteBilan $echecs $alertes) { exit 0 } else { exit 1 }
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# MODE GENERATION
|
||||
# ============================================================================
|
||||
$dossiersPacks = @(Get-ChildItem -LiteralPath $racine -Directory |
|
||||
Where-Object { -not $_.Name.StartsWith('.') } |
|
||||
Sort-Object -Property Name)
|
||||
if ($dossiersPacks.Count -eq 0) {
|
||||
$message = ("Aucun sous-dossier de langue sous {0} (attendu : {0}\es\versFrancais\encoder.onnx)." -f $racine)
|
||||
# -AutoriserVide couvre les DEUX causes de manifeste vide : racine sans
|
||||
# dossier de langue, et dossiers sans aucun fichier exploitable.
|
||||
if ($AutoriserVide) { $alertes.Add($message) } else { $echecs.Add($message) }
|
||||
}
|
||||
|
||||
$blocsPacks = New-Object 'System.Collections.Generic.List[string]'
|
||||
$recap = New-Object 'System.Collections.Generic.List[string]'
|
||||
|
||||
foreach ($dossierPack in $dossiersPacks) {
|
||||
$nomDossier = $dossierPack.Name
|
||||
$code = $nomDossier.Trim().ToLowerInvariant()
|
||||
|
||||
if (-not (Test-ManifesteCodeValide $code)) {
|
||||
$alertes.Add(("Dossier ignore « {0} » : code de langue invalide (2 a 10 caracteres, minuscules a-z, chiffres, tiret)." -f $nomDossier))
|
||||
continue
|
||||
}
|
||||
# -cne : comparaison SENSIBLE A LA CASSE. « -ne » considererait « ru » et
|
||||
# « RU » comme egaux et ne signalerait rien.
|
||||
if ($code -cne $nomDossier) {
|
||||
$alertes.Add(("Dossier « {0} » : le manifeste ecrit « {1} ». Renommer le dossier si le volume peut etre sensible a la casse." -f $nomDossier, $code))
|
||||
}
|
||||
|
||||
$libelle = Resolve-ManifesteLibelle $code $Libelles
|
||||
$blocsFichiers = New-Object 'System.Collections.Generic.List[string]'
|
||||
$nbFichiersPack = 0
|
||||
$octetsPack = [long]0
|
||||
|
||||
foreach ($dossierSens in @(Get-ChildItem -LiteralPath $dossierPack.FullName -Directory | Sort-Object -Property Name)) {
|
||||
$sens = Resolve-ManifesteSens $dossierSens.Name
|
||||
if (-not $sens) {
|
||||
$alertes.Add(("Dossier ignore {0}\{1} : sens inconnu (attendu versFrancais, depuisFrancais ou commun)." -f $nomDossier, $dossierSens.Name))
|
||||
continue
|
||||
}
|
||||
if ($sens -cne $dossierSens.Name) {
|
||||
$alertes.Add(("Dossier {0}\{1} : le manifeste ecrit « {2} » (casse canonique exigee par le mobile)." -f $nomDossier, $dossierSens.Name, $sens))
|
||||
}
|
||||
|
||||
# L'API ne sert que {code}/{sens}/{fichier} : un sous-dossier n'est jamais atteignable.
|
||||
foreach ($sousDossier in @(Get-ChildItem -LiteralPath $dossierSens.FullName -Directory)) {
|
||||
$alertes.Add(("Dossier ignore {0}\{1}\{2} : l'API ne sert que {{code}}/{{sens}}/{{fichier}}." -f $nomDossier, $dossierSens.Name, $sousDossier.Name))
|
||||
}
|
||||
|
||||
foreach ($fichier in @(Get-ChildItem -LiteralPath $dossierSens.FullName -File | Sort-Object -Property Name)) {
|
||||
# Deux fichiers inutiles qu'il ne faut PAS livrer : declares ici, ils
|
||||
# seraient telecharges par chaque telephone pour rien.
|
||||
if ($fichier.Name.EndsWith('.onnx', [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
-and $fichier.Name -match 'past') {
|
||||
$alertes.Add(("{0}\{1}\{2} (~{3}) : decodeur a cache (past_key_values) IGNORE par l'application, mais il serait TELECHARGE. Ne pas livrer ce fichier." -f $nomDossier, $dossierSens.Name, $fichier.Name, (Format-ManifesteTaille $fichier.Length)))
|
||||
}
|
||||
elseif ($fichier.Name.EndsWith('.spm', [System.StringComparison]::OrdinalIgnoreCase) `
|
||||
-and $NomsVocabulaire -notcontains $fichier.Name) {
|
||||
$alertes.Add(("{0}\{1}\{2} : nom de vocabulaire non reconnu (attendu vocab.spm, source.spm ou target.spm). L'application le prendrait comme repli « premier .spm » : verifier qu'il est bien le bon." -f $nomDossier, $dossierSens.Name, $fichier.Name))
|
||||
}
|
||||
|
||||
$sha = Get-ManifesteEmpreinte $fichier.FullName
|
||||
$blocsFichiers.Add((New-ManifesteBlocFichier -sens $sens -nomFichier $fichier.Name -taille $fichier.Length -sha256 $sha))
|
||||
$nbFichiersPack++
|
||||
$octetsPack += $fichier.Length
|
||||
}
|
||||
}
|
||||
|
||||
if ($nbFichiersPack -eq 0) {
|
||||
$alertes.Add(("Pack « {0} » ignore : aucun fichier utilisable." -f $code))
|
||||
continue
|
||||
}
|
||||
|
||||
$blocsPacks.Add((New-ManifesteBlocPack -code $code -libelle $libelle -version $Version -blocsFichiers $blocsFichiers))
|
||||
$recap.Add((' {0,-6} {1,-16} {2,3} fichier(s) {3,12}' -f $code, $libelle, $nbFichiersPack, (Format-ManifesteTaille $octetsPack)))
|
||||
}
|
||||
|
||||
if ($blocsPacks.Count -eq 0 -and -not $AutoriserVide) {
|
||||
$echecs.Add('Aucun pack exploitable : manifeste NON ecrit (un manifeste vide ferait afficher au mobile « Aucun modele de langue n''est disponible sur le serveur »).')
|
||||
$echecs.Add('Corriger l''arborescence, ou forcer avec -AutoriserVide si c''est volontaire.')
|
||||
}
|
||||
|
||||
if ($echecs.Count -gt 0) {
|
||||
Write-ManifesteBilan $echecs $alertes | Out-Null
|
||||
exit 1
|
||||
}
|
||||
|
||||
$json = New-ManifesteJsonText $blocsPacks
|
||||
|
||||
foreach ($ligne in $recap) { Write-ManifesteInfo $ligne }
|
||||
Write-Host ''
|
||||
|
||||
if (-not $PSCmdlet.ShouldProcess($Sortie, 'Ecriture du manifeste des packs de langue')) {
|
||||
Write-ManifesteInfo 'Simulation (-WhatIf) : aucun fichier ecrit. Contenu qui aurait ete ecrit :'
|
||||
Write-Host ''
|
||||
Write-Host $json
|
||||
Write-Host ''
|
||||
Write-ManifesteBilan $echecs $alertes | Out-Null
|
||||
exit 0
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $Sortie -PathType Leaf) {
|
||||
$sauvegarde = $Sortie + '.bak'
|
||||
Copy-Item -LiteralPath $Sortie -Destination $sauvegarde -Force
|
||||
Write-ManifesteInfo ("Manifeste precedent conserve : {0}" -f $sauvegarde)
|
||||
}
|
||||
|
||||
Write-ManifesteFichier -chemin $Sortie -contenu $json
|
||||
Write-ManifesteOk ("Manifeste ecrit : {0}" -f $Sortie)
|
||||
Write-Host ''
|
||||
|
||||
foreach ($alerte in $alertes) { Write-ManifesteAlerte $alerte }
|
||||
Write-Host ''
|
||||
Write-ManifesteInfo 'Aucun demarrage/redemarrage de service n''est necessaire : l''API relit le'
|
||||
Write-ManifesteInfo 'manifeste a CHAQUE appel de GET /api/langues.'
|
||||
Write-ManifesteInfo 'Le mobile, lui, garde son index memorise : il faut un rafraichissement'
|
||||
Write-ManifesteInfo '(liste des langues -> actualiser) pour voir la nouvelle liste.'
|
||||
Write-Host ''
|
||||
Write-ManifesteInfo 'Controles a enchainer :'
|
||||
Write-ManifesteInfo (' 1. .\New-OmikaLanguesManifeste.ps1 -Verifier')
|
||||
Write-ManifesteInfo ' 2. Invoke-RestMethod https://<URL_SRV_LANGUES>/api/langues | ConvertTo-Json -Depth 6'
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user