Correct deployment #8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Compiler WASM et deployer sur GitHub Pages | |
| on: | |
| push: | |
| branches: ["main"] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| concurrency: | |
| group: "pages" | |
| cancel-in-progress: false | |
| jobs: | |
| build: | |
| name: Compiler le source francais -> WebAssembly | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Cloner le depot | |
| uses: actions/checkout@v4 | |
| - name: Configurer Python 3.12 | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Configurer Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - name: Installer multilingualprogramming[wasm] | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install "multilingualprogramming[wasm]" | |
| - name: Compiler le source francais vers WebAssembly | |
| shell: python | |
| run: | | |
| import io | |
| import sys | |
| from pathlib import Path | |
| from multilingualprogramming import ProgramExecutor | |
| from multilingualprogramming.codegen.runtime_builtins import RuntimeBuiltins | |
| racine = Path.cwd() | |
| script_ml = racine / "scripts" / "compile_wasm.ml" | |
| if not script_ml.exists(): | |
| raise RuntimeError(f"Script multilingual introuvable: {script_ml}") | |
| if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"): | |
| sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") | |
| if sys.stderr.encoding and sys.stderr.encoding.lower() not in ("utf-8", "utf8"): | |
| sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace") | |
| source_ml = script_ml.read_text(encoding="utf-8") | |
| code_python = ProgramExecutor(language="fr").transpile(source_ml) | |
| if not code_python or not code_python.strip(): | |
| raise RuntimeError("Transpilation vide pour scripts/compile_wasm.ml") | |
| espace_builtins = RuntimeBuiltins("fr").namespace() | |
| espace_execution = dict(espace_builtins) | |
| espace_execution.update({"__name__": "__compile_wasm_ml__", "__file__": str(script_ml)}) | |
| exec(code_python, espace_execution) | |
| point_entree = espace_execution.get("main") | |
| if not callable(point_entree): | |
| raise RuntimeError("Fonction main() introuvable dans scripts/compile_wasm.ml") | |
| point_entree() | |
| - name: Verifier la syntaxe JavaScript | |
| run: node --check public/ui.js | |
| - name: Valider le WASM ou basculer sur JavaScript | |
| run: | | |
| node -e " | |
| const fs = require('fs'); | |
| const wasmPath = 'public/cellcosmos.wasm'; | |
| const watPath = 'public/cellcosmos.wat'; | |
| const fallback = (message, detail) => { | |
| console.warn(message); | |
| if (detail) { | |
| console.warn(detail); | |
| } | |
| if (fs.existsSync(wasmPath)) fs.unlinkSync(wasmPath); | |
| if (fs.existsSync(watPath)) fs.unlinkSync(watPath); | |
| console.log('Publication en mode JavaScript uniquement.'); | |
| process.exit(0); | |
| }; | |
| if (!fs.existsSync(wasmPath)) { | |
| fallback('WASM absent apres compilation.'); | |
| } | |
| const bytes = fs.readFileSync(wasmPath); | |
| const module = new WebAssembly.Module(bytes); | |
| const importObject = {}; | |
| for (const entry of WebAssembly.Module.imports(module)) { | |
| if (!importObject[entry.module]) { | |
| importObject[entry.module] = {}; | |
| } | |
| if (entry.kind === 'function') { | |
| importObject[entry.module][entry.name] = () => 0; | |
| } else if (entry.kind === 'memory') { | |
| importObject[entry.module][entry.name] = new WebAssembly.Memory({ initial: 16 }); | |
| } else if (entry.kind === 'table') { | |
| importObject[entry.module][entry.name] = new WebAssembly.Table({ initial: 0, element: 'anyfunc' }); | |
| } else if (entry.kind === 'global') { | |
| importObject[entry.module][entry.name] = new WebAssembly.Global({ value: 'i32', mutable: true }, 0); | |
| } | |
| } | |
| if (!importObject.env) { | |
| importObject.env = {}; | |
| } | |
| WebAssembly.instantiate(module, importObject).then((instance) => { | |
| const exports = instance.exports; | |
| const required = ['cellule_suivante', 'classe_wolfram']; | |
| const missing = required.filter((name) => typeof exports[name] !== 'function'); | |
| if (missing.length) { | |
| fallback('Exports WASM manquants.', missing.join(', ')); | |
| } | |
| const transitionChecks = [ | |
| [90, 1, 0, 1, 0], | |
| [90, 1, 0, 0, 1], | |
| [30, 1, 1, 1, 0], | |
| [30, 0, 1, 0, 1], | |
| ]; | |
| for (const [rule, left, center, right, expected] of transitionChecks) { | |
| const actual = Number(exports.cellule_suivante(rule, left, center, right)); | |
| if (actual !== expected) { | |
| fallback('Transition WASM invalide.', JSON.stringify({ rule, left, center, right, expected, actual })); | |
| } | |
| } | |
| const classChecks = [ | |
| [30, 3], | |
| [110, 4], | |
| [255, 1], | |
| [73, 2], | |
| ]; | |
| for (const [rule, expected] of classChecks) { | |
| const actual = Number(exports.classe_wolfram(rule)); | |
| if (actual !== expected) { | |
| fallback('Classification WASM invalide.', JSON.stringify({ rule, expected, actual })); | |
| } | |
| } | |
| console.log('WASM smoke test OK'); | |
| }).catch((err) => { | |
| fallback('Instantiation WASM impossible.', err && err.stack ? err.stack : String(err)); | |
| }); | |
| " | |
| - name: Configurer GitHub Pages | |
| uses: actions/configure-pages@v5 | |
| - name: Preparer l'artefact Pages | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: "public" | |
| deploy: | |
| name: Deployer sur GitHub Pages | |
| runs-on: ubuntu-latest | |
| needs: build | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Deployer sur GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 |