diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a1d1aa2..e031850 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -148,6 +148,8 @@ jobs: Get-ChildItem converter/*.dll | ForEach-Object { Write-Output "Bundled $($_.Name) ($($_.Length) bytes)" } - name: Build allfontsgen + env: + ALLFONTSGEN_FORCE_REBUILD: ${{ runner.os == 'Windows' && '1' || '0' }} run: bun scripts/build_allfontsgen.js - name: Install production dependencies diff --git a/scripts/build_allfontsgen.js b/scripts/build_allfontsgen.js index c49859f..3b6cdb4 100755 --- a/scripts/build_allfontsgen.js +++ b/scripts/build_allfontsgen.js @@ -25,12 +25,24 @@ const CORE_REPO = 'https://github.com/ONLYOFFICE/core.git'; const CORE_COMMIT = '82e281cf6bf89498e4de6018423b36576706c2b6'; const SRC = path.join(CORE_DIR, 'DesktopEditor', 'AllFontsGen', 'main.cpp'); const WINDOWS_COMPONENTS = ['graphics', 'kernel', 'UnicodeConverter']; +const FORCE_ALLFONTSGEN_REBUILD = process.env.ALLFONTSGEN_FORCE_REBUILD === '1'; +const ALLFONTSGEN_DIAGNOSTICS_PATCH = path.join( + ROOT, + 'scripts', + 'patches', + 'allfontsgen-control-diagnostics.patch' +); let cachedConverterArch = null; const platform = process.platform; // 'darwin', 'win32', 'linux' // Early return if allfontsgen binary already exists function checkExistingBinary() { + if (FORCE_ALLFONTSGEN_REBUILD) { + console.log('[build_allfontsgen] ALLFONTSGEN_FORCE_REBUILD=1, rebuilding binary'); + return false; + } + if (platform === 'darwin') { const output = path.join(CONVERTER_DIR, 'allfontsgen'); if (fs.existsSync(output)) { @@ -364,12 +376,25 @@ function ensureCoreSources() { console.log(`[build_allfontsgen] Checking out ONLYOFFICE/core commit ${CORE_COMMIT}...`); run('git', ['fetch', '--all'], { cwd: CORE_DIR }); - run('git', ['checkout', CORE_COMMIT], { cwd: CORE_DIR }); + run('git', ['checkout', '--force', CORE_COMMIT], { cwd: CORE_DIR }); console.log('[build_allfontsgen] Updating ONLYOFFICE/core submodules...'); run('git', ['submodule', 'update', '--init', '--recursive', '--force'], { cwd: CORE_DIR }); } +function applyAllFontsGenDiagnosticsPatch() { + if (!fs.existsSync(ALLFONTSGEN_DIAGNOSTICS_PATCH)) { + console.error('[build_allfontsgen] Missing diagnostics patch:', ALLFONTSGEN_DIAGNOSTICS_PATCH); + process.exit(1); + } + + console.log('[build_allfontsgen] Applying AllFontsGen diagnostics patch...'); + run('git', ['apply', '--unidiff-zero', '--whitespace=nowarn', ALLFONTSGEN_DIAGNOSTICS_PATCH], { + cwd: CORE_DIR, + }); +} + ensureCoreSources(); +applyAllFontsGenDiagnosticsPatch(); if (!fs.existsSync(SRC)) { console.error('[build_allfontsgen] main.cpp not found:', SRC); diff --git a/scripts/generate_office_fonts.js b/scripts/generate_office_fonts.js index 7d2fec5..6e6c714 100755 --- a/scripts/generate_office_fonts.js +++ b/scripts/generate_office_fonts.js @@ -63,6 +63,7 @@ function locateBinary() { const BIN = locateBinary(); const INPUT_DIR = path.join(OUTPUT_DIR, 'fonts'); +const DIAG_LOG = path.join(OUTPUT_DIR, 'allfontsgen-control.log'); fs.mkdirSync(OUTPUT_DIR, { recursive: true }); fs.mkdirSync(INPUT_DIR, { recursive: true }); @@ -78,18 +79,56 @@ const env = { ...process.env }; if (platform === 'darwin') { env.DYLD_FRAMEWORK_PATH = CONVERTER_DIR; } +if (platform === 'win32') { + env.ALLFONTSGEN_DIAG_LOG = DIAG_LOG; +} + +function readDiagnosticLog() { + if (platform !== 'win32' || !fs.existsSync(DIAG_LOG)) { + return ''; + } + + const text = fs.readFileSync(DIAG_LOG, 'utf8').trim(); + if (!text) { + return ''; + } + + const normalizedText = text.replaceAll('\r\n', '\n'); + return `\n[generate_office_fonts] allfontsgen diagnostic log:\n${normalizedText}`; +} + +function formatExitStatus(status) { + if (typeof status !== 'number') { + return String(status); + } + + return `${status} (0x${(status >>> 0).toString(16).toUpperCase()})`; +} const result = spawnSync(BIN, args, { stdio: 'inherit', env }); if (result.status !== 0) { - fail(`allfontsgen exited with code ${result.status || 1}`); + const details = [ + `allfontsgen exited with code ${formatExitStatus(result.status)}`, + result.signal ? `signal=${result.signal}` : null, + result.error ? `error=${result.error.message}` : null, + ].filter(Boolean).join(' '); + + fail(`${details}${readDiagnosticLog()}`); } const allFontsJs = path.join(OUTPUT_DIR, 'AllFonts.js'); const fontSelectionBin = path.join(OUTPUT_DIR, 'font_selection.bin'); if (!fs.existsSync(allFontsJs) || !fs.existsSync(fontSelectionBin)) { - fail('allfontsgen exited successfully but font metadata files were not created'); + const missing = [ + fs.existsSync(allFontsJs) ? null : allFontsJs, + fs.existsSync(fontSelectionBin) ? null : fontSelectionBin, + ].filter(Boolean); + + fail( + `allfontsgen exited successfully but font metadata files were not created; missing=${missing.join(', ')}${readDiagnosticLog()}` + ); } console.log('[generate_office_fonts] Font metadata updated.'); diff --git a/scripts/patches/allfontsgen-control-diagnostics.patch b/scripts/patches/allfontsgen-control-diagnostics.patch new file mode 100644 index 0000000..2fd0b35 --- /dev/null +++ b/scripts/patches/allfontsgen-control-diagnostics.patch @@ -0,0 +1,65 @@ +diff --git a/DesktopEditor/AllFontsGen/main.cpp b/DesktopEditor/AllFontsGen/main.cpp +--- a/DesktopEditor/AllFontsGen/main.cpp ++++ b/DesktopEditor/AllFontsGen/main.cpp +@@ -33,0 +34,2 @@ ++#include ++#include +@@ -42,0 +45,49 @@ ++ ++#ifdef _WIN32 ++#include ++ ++static std::wstring g_allFontsGenDiagLogPath; ++static std::wstring g_allFontsGenOutputDir; ++ ++static void AppendAllFontsGenDiagLine(const wchar_t* stage, DWORD eventType = MAXDWORD) ++{ ++ if (g_allFontsGenDiagLogPath.empty()) ++ return; ++ ++ std::wofstream file(g_allFontsGenDiagLogPath.c_str(), std::ios::app); ++ if (!file.is_open()) ++ return; ++ ++ SYSTEMTIME now; ++ GetSystemTime(&now); ++ file << L"utc=" ++ << now.wYear << L"-" << now.wMonth << L"-" << now.wDay ++ << L"T" << now.wHour << L":" << now.wMinute << L":" << now.wSecond ++ << L"." << now.wMilliseconds << L"Z" ++ << L" stage=" << stage ++ << L" pid=" << GetCurrentProcessId(); ++ ++ if (eventType != MAXDWORD) ++ file << L" eventCode=" << eventType; ++ ++ file << L" outputDir=\"" << g_allFontsGenOutputDir << L"\"" << std::endl; ++} ++ ++static BOOL WINAPI AllFontsGenConsoleCtrlHandler(DWORD eventType) ++{ ++ AppendAllFontsGenDiagLine(L"console-control", eventType); ++ return FALSE; ++} ++ ++static void InitAllFontsGenDiagnostics(const std::wstring& outputDir) ++{ ++ const wchar_t* logPath = _wgetenv(L"ALLFONTSGEN_DIAG_LOG"); ++ if (!logPath || !logPath[0]) ++ return; ++ ++ g_allFontsGenDiagLogPath = logPath; ++ g_allFontsGenOutputDir = outputDir; ++ SetConsoleCtrlHandler(AllFontsGenConsoleCtrlHandler, TRUE); ++ AppendAllFontsGenDiagLine(L"start"); ++} ++#endif +@@ -209,0 +261,4 @@ ++#ifdef _WIN32 ++ InitAllFontsGenDiagnostics(oWorker.m_sDirectory); ++#endif ++ +@@ -225,0 +281,3 @@ ++#ifdef _WIN32 ++ AppendAllFontsGenDiagLine(pApplicationFonts ? L"after-check-non-null" : L"after-check-null"); ++#endif