« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/write
diff options
context:
space:
mode:
Diffstat (limited to 'src/write')
-rw-r--r--src/write/bind-utilities.js27
-rw-r--r--src/write/build-modes/live-dev-server.js55
-rw-r--r--src/write/build-modes/static-build.js61
3 files changed, 86 insertions, 57 deletions
diff --git a/src/write/bind-utilities.js b/src/write/bind-utilities.js
index 8e2adea7..3d4ecc7a 100644
--- a/src/write/bind-utilities.js
+++ b/src/write/bind-utilities.js
@@ -10,15 +10,24 @@ import * as html from '#html';
 import {bindOpts} from '#sugar';
 import {thumb} from '#urls';
 
+import {
+  checkIfImagePathHasCachedThumbnails,
+  getDimensionsOfImagePath,
+  getThumbnailEqualOrSmaller,
+  getThumbnailsAvailableForDimensions,
+} from '#thumbs';
+
 export function bindUtilities({
   absoluteTo,
   cachebust,
   defaultLanguage,
   getSizeOfAdditionalFile,
-  getSizeOfImageFile,
+  getSizeOfImagePath,
   language,
   languages,
+  missingImagePaths,
   pagePath,
+  thumbsCache,
   to,
   urls,
   wikiData,
@@ -30,10 +39,12 @@ export function bindUtilities({
     cachebust,
     defaultLanguage,
     getSizeOfAdditionalFile,
-    getSizeOfImageFile,
+    getSizeOfImagePath,
+    getThumbnailsAvailableForDimensions,
     html,
     language,
     languages,
+    missingImagePaths,
     pagePath,
     thumb,
     to,
@@ -46,5 +57,17 @@ export function bindUtilities({
 
   bound.find = bindFind(wikiData, {mode: 'warn'});
 
+  bound.checkIfImagePathHasCachedThumbnails =
+    (imagePath) =>
+      checkIfImagePathHasCachedThumbnails(imagePath, thumbsCache);
+
+  bound.getDimensionsOfImagePath =
+    (imagePath) =>
+      getDimensionsOfImagePath(imagePath, thumbsCache);
+
+  bound.getThumbnailEqualOrSmaller =
+    (preferred, imagePath) =>
+      getThumbnailEqualOrSmaller(preferred, imagePath, thumbsCache);
+
   return bound;
 }
diff --git a/src/write/build-modes/live-dev-server.js b/src/write/build-modes/live-dev-server.js
index 2767a02f..1339c322 100644
--- a/src/write/build-modes/live-dev-server.js
+++ b/src/write/build-modes/live-dev-server.js
@@ -1,8 +1,6 @@
 import * as http from 'node:http';
-import {createReadStream} from 'node:fs';
-import {stat} from 'node:fs/promises';
+import {readFile, stat} from 'node:fs/promises';
 import * as path from 'node:path';
-import {pipeline} from 'node:stream/promises'
 
 import {logInfo, logWarn, progressCallAll} from '#cli';
 import {watchContentDependencies} from '#content-dependencies';
@@ -10,11 +8,9 @@ import {quickEvaluate} from '#content-function';
 import * as html from '#html';
 import * as pageSpecs from '#page-specs';
 import {serializeThings} from '#serialize';
-import {empty} from '#sugar';
 
 import {
   getPagePathname,
-  getPagePathnameAcrossLanguages,
   getURLsFrom,
   getURLsFromRoot,
 } from '#urls';
@@ -44,8 +40,8 @@ export function getCLIOptions() {
       },
     },
 
-    'quiet-responses': {
-      help: `Disables outputting [200] and [404] responses in the server log`,
+    'loud-responses': {
+      help: `Enables outputting [200] and [404] responses in the server log, which are suppressed by default`,
       type: 'flag',
     },
   };
@@ -58,14 +54,16 @@ export async function go({
 
   defaultLanguage,
   languages,
+  missingImagePaths,
   srcRootPath,
+  thumbsCache,
   urls,
   wikiData,
 
   cachebust,
   developersComment,
   getSizeOfAdditionalFile,
-  getSizeOfImageFile,
+  getSizeOfImagePath,
   niceShowAggregate,
 }) {
   const showError = (error) => {
@@ -78,7 +76,7 @@ export async function go({
 
   const host = cliOptions['host'] ?? defaultHost;
   const port = parseInt(cliOptions['port'] ?? defaultPort);
-  const quietResponses = cliOptions['quiet-responses'] ?? false;
+  const loudResponses = cliOptions['loud-responses'] ?? false;
 
   const contentDependenciesWatcher = await watchContentDependencies();
   const {contentDependencies} = contentDependenciesWatcher;
@@ -160,10 +158,10 @@ export async function go({
         });
         response.writeHead(200, contentTypeJSON);
         response.end(json);
-        if (!quietResponses) console.log(`${requestHead} [200] /data.json`);
+        if (loudResponses) console.log(`${requestHead} [200] /data.json`);
       } catch (error) {
         response.writeHead(500, contentTypeJSON);
-        response.end({error: `Internal error serializing wiki JSON`});
+        response.end(`Internal error serializing wiki JSON`);
         console.error(`${requestHead} [500] /data.json`);
         showError(error);
       }
@@ -224,7 +222,7 @@ export async function go({
         'gif': 'image/gif',
         'ico': 'image/vnd.microsoft.icon',
         'jpg': 'image/jpeg',
-        'jpeg:': 'image/jpeg',
+        'jpeg': 'image/jpeg',
         'js': 'text/javascript',
         'mjs': 'text/javascript',
         'mp3': 'audio/mpeg',
@@ -249,14 +247,13 @@ export async function go({
 
       try {
         const {size} = await stat(filePath);
+        const buffer = await readFile(filePath)
         response.writeHead(200, contentType ? {
           'Content-Type': contentType,
           'Content-Length': size,
         } : {});
-        await pipeline(
-          createReadStream(filePath),
-          response);
-        if (!quietResponses) console.log(`${requestHead} [200] ${pathname}`);
+        response.end(buffer);
+        if (loudResponses) console.log(`${requestHead} [200] ${pathname}`);
       } catch (error) {
         response.writeHead(500, contentTypePlain);
         response.end(`Failed during file-to-response pipeline`);
@@ -274,7 +271,7 @@ export async function go({
     if (!Object.hasOwn(urlToPageMap, pathnameKey)) {
       response.writeHead(404, contentTypePlain);
       response.end(`No page found for: ${pathnameKey}\n`);
-      if (!quietResponses) console.log(`${requestHead} [404] ${pathname}`);
+      if (loudResponses) console.log(`${requestHead} [404] ${pathname}`);
       return;
     }
 
@@ -331,22 +328,17 @@ export async function go({
         return;
       }
 
-      const localizedPathnames = getPagePathnameAcrossLanguages({
-        defaultLanguage,
-        languages,
-        pagePath: servePath,
-        urls,
-      });
-
       const bound = bindUtilities({
         absoluteTo,
         cachebust,
         defaultLanguage,
         getSizeOfAdditionalFile,
-        getSizeOfImageFile,
+        getSizeOfImagePath,
         language,
         languages,
+        missingImagePaths,
         pagePath: servePath,
+        thumbsCache,
         to,
         urls,
         wikiData,
@@ -363,14 +355,14 @@ export async function go({
 
       const {pageHTML} = html.resolve(topLevelResult);
 
-      if (!quietResponses) console.log(`${requestHead} [200] ${pathname}`);
+      if (loudResponses) console.log(`${requestHead} [200] ${pathname}`);
       response.writeHead(200, contentTypeHTML);
       response.end(pageHTML);
     } catch (error) {
-      response.writeHead(500, contentTypePlain);
-      response.end(`Error generating page, view server log for details\n`);
       console.error(`${requestHead} [500] ${pathname}`);
       showError(error);
+      response.writeHead(500, contentTypePlain);
+      response.end(`Error generating page, view server log for details\n`);
     }
   });
 
@@ -393,8 +385,11 @@ export async function go({
   server.on('listening', () => {
     logInfo`${'All done!'} Listening at: ${address}`;
     logInfo`Press ^C here (control+C) to stop the server and exit.`;
-    if (quietResponses) {
-      logInfo`Suppressing [200] and [404] response logging.`;
+    if (loudResponses) {
+      logInfo`Printing [200] and [404] responses.`
+    } else {
+      logInfo`Suppressing [200] and [404] response logging.`
+      logInfo`(Pass --loud-responses to show these.)`;
     }
   });
 
diff --git a/src/write/build-modes/static-build.js b/src/write/build-modes/static-build.js
index 2210dfe7..09316999 100644
--- a/src/write/build-modes/static-build.js
+++ b/src/write/build-modes/static-build.js
@@ -17,16 +17,15 @@ import {serializeThings} from '#serialize';
 import {empty, queue, withEntries} from '#sugar';
 
 import {
+  fileIssue,
   logError,
   logInfo,
   logWarn,
-  progressCallAll,
   progressPromiseAll,
 } from '#cli';
 
 import {
   getPagePathname,
-  getPagePathnameAcrossLanguages,
   getURLsFrom,
   getURLsFromRoot,
 } from '#urls';
@@ -89,15 +88,17 @@ export async function go({
 
   defaultLanguage,
   languages,
+  missingImagePaths,
   srcRootPath,
+  thumbsCache,
   urls,
-  urlSpec,
   wikiData,
 
   cachebust,
   developersComment,
   getSizeOfAdditionalFile,
-  getSizeOfImageFile,
+  getSizeOfImagePath,
+  niceShowAggregate,
 }) {
   const outputPath = cliOptions['out-path'] || process.env.HSMUSIC_OUT;
   const appendIndexHTML = cliOptions['append-index-html'] ?? false;
@@ -253,6 +254,8 @@ export async function go({
   ));
   */
 
+  let errored = false;
+
   const contentDependencies = await quickLoadContentDependencies();
 
   const perLanguageFn = async (language, i, entries) => {
@@ -265,13 +268,6 @@ export async function go({
       ...pageWrites.map(page => () => {
         const pagePath = page.path;
 
-        const localizedPathnames = getPagePathnameAcrossLanguages({
-          defaultLanguage,
-          languages,
-          pagePath,
-          urls,
-        });
-
         const pathname = getPagePathname({
           baseDirectory,
           pagePath,
@@ -294,23 +290,33 @@ export async function go({
           cachebust,
           defaultLanguage,
           getSizeOfAdditionalFile,
-          getSizeOfImageFile,
+          getSizeOfImagePath,
           language,
           languages,
+          missingImagePaths,
           pagePath,
+          thumbsCache,
           to,
           urls,
           wikiData,
         });
 
-        const topLevelResult =
-          quickEvaluate({
-            contentDependencies,
-            extraDependencies: {...bound, appendIndexHTML},
-
-            name: page.contentFunction.name,
-            args: page.contentFunction.args ?? [],
-          });
+        let topLevelResult;
+        try {
+          topLevelResult =
+            quickEvaluate({
+              contentDependencies,
+              extraDependencies: {...bound, appendIndexHTML},
+
+              name: page.contentFunction.name,
+              args: page.contentFunction.args ?? [],
+            });
+        } catch (error) {
+          logError`\rError generating page: ${pathname}`;
+          niceShowAggregate(error);
+          errored = true;
+          return;
+        }
 
         const {pageHTML, oEmbedJSON} = html.resolve(topLevelResult);
 
@@ -358,6 +364,16 @@ export async function go({
 
   // The single most important step.
   logInfo`Written!`;
+
+  if (errored) {
+    logWarn`The code generating content for some pages ended up erroring.`;
+    logWarn`These pages were skipped, so if you ran a build previously and`;
+    logWarn`they didn't error that time, then the old version is still`;
+    logWarn`available - albeit possibly outdated! Please scroll up and send`;
+    logWarn`the HSMusic developers a copy of the errors:`;
+    fileIssue({topMessage: null});
+  }
+
   return true;
 }
 
@@ -454,14 +470,9 @@ async function writeFavicon({
 }
 
 async function writeSharedFilesAndPages({
-  language,
   outputPath,
-  urls,
-  wikiData,
   wikiDataJSON,
 }) {
-  const {groupData, wikiInfo} = wikiData;
-
   return progressPromiseAll(`Writing files & pages shared across languages.`, [
     wikiDataJSON &&
       writeFile(