« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gen-thumbs.js139
-rwxr-xr-xsrc/upd8.js115
-rw-r--r--src/web-routes.js1
3 files changed, 232 insertions, 23 deletions
diff --git a/src/gen-thumbs.js b/src/gen-thumbs.js
index 8a582693..c5c5ee4f 100644
--- a/src/gen-thumbs.js
+++ b/src/gen-thumbs.js
@@ -610,8 +610,11 @@ async function generateImageThumbnail(imagePath, thumbtack, {
 
 export async function determineMediaCachePath({
   mediaPath,
+  wikiCachePath,
   providedMediaCachePath,
+
   disallowDoubling = false,
+  regenerateMissingThumbnailCache = false,
 }) {
   if (!mediaPath) {
     return {
@@ -643,45 +646,147 @@ export async function determineMediaCachePath({
     };
   }
 
-  const inferredPath =
+  // Two inferred paths are possible - "adjacent" and "contained".
+  // "Contained" is the preferred format and we'll create it if
+  // wikiCachePath is provided, but if it *isn't* we won't know
+  // where to create it. Since "adjacent" isn't preferred we don't
+  // ever generate it, and we'd prefer not to *newly* generate
+  // thumbs in-place with mediaPath, so give up - we've already
+  // determined mediaPath doesn't include in-place thumbs.
+
+  const adjacentInferredPath =
     path.join(
       path.dirname(mediaPath),
       path.basename(mediaPath) + '-cache');
 
-  let inferredIncludesThumbnailCache;
+  const containedInferredPath =
+    (wikiCachePath
+      ? path.join(wikiCachePath, 'media-cache')
+      : null);
+
+  let adjacentIncludesThumbnailCache;
+  let containedIncludesThumbnailCache;
 
   try {
-    const files = await readdir(inferredPath);
-    inferredIncludesThumbnailCache = files.includes(CACHE_FILE);
+    const files = await readdir(adjacentInferredPath);
+    adjacentIncludesThumbnailCache = files.includes(CACHE_FILE);
   } catch (error) {
     if (error.code === 'ENOENT') {
-      inferredIncludesThumbnailCache = null;
+      adjacentIncludesThumbnailCache = null;
     } else {
-      inferredIncludesThumbnailCache = undefined;
+      adjacentIncludesThumbnailCache = undefined;
+    }
+  }
+
+  if (wikiCachePath) {
+    try {
+      const files = await readdir(containedInferredPath);
+      containedIncludesThumbnailCache = files.includes(CACHE_FILE);
+    } catch (error) {
+      if (error.code === 'ENOENT') {
+        containedIncludesThumbnailCache = null;
+      } else {
+        containedIncludesThumbnailCache = undefined;
+      }
     }
   }
 
-  if (inferredIncludesThumbnailCache === true) {
+  // Go ahead with the contained path if it exists and contains a cache -
+  // no other conditions matter.
+  if (containedIncludesThumbnailCache === true) {
     return {
-      annotation: 'inferred path has cache',
-      mediaCachePath: inferredPath,
+      annotation: `contained path has cache`,
+      mediaCachePath: containedInferredPath,
     };
-  } else if (inferredIncludesThumbnailCache === false) {
+  }
+
+  // Reuse an existing adjacent cache before figuring out what to do
+  // if there's no extant cache at all.
+  if (adjacentIncludesThumbnailCache === true) {
     return {
-      annotation: 'inferred path does not have cache',
-      mediaCachePath: null,
+      annotation: `adjacent path has cache`,
+      mediaCachePath: adjacentInferredPath,
     };
-  } else if (inferredIncludesThumbnailCache === null) {
+  }
+
+  // Throw a very high-priority tantrum if the contained cache exists but
+  // isn't readable. It's the preferred cache and we can't tell if it's
+  // available for use or not!
+  if (wikiCachePath && containedIncludesThumbnailCache === undefined) {
     return {
-      annotation: 'inferred path will be created',
-      mediaCachePath: inferredPath,
+      annotation: `contained path not readable`,
+      mediaCachePath: null,
     };
-  } else {
+  }
+
+  // Throw a secondary tantrum if the adjacent cache exists but
+  // isn't readable. This is just as big of a problem, but if for
+  // some reason both the contained and adjacent caches exist,
+  // the contained one is the one we'd rather have addressed.
+  if (adjacentIncludesThumbnailCache === undefined) {
     return {
-      annotation: 'inferred path not readable',
+      annotation: `adjacent path not readable`,
       mediaCachePath: null,
     };
   }
+
+  // Throw a high-priority tantrum if the contained cache exists but is
+  // missing its cache file, again because it's the more preferred cache.
+  // Unless we're indicated to regenerate such a missing cache file!
+  if (containedIncludesThumbnailCache === false) {
+    if (regenerateMissingThumbnailCache) {
+      return {
+        annotation: `contained path will regenerate missing cache`,
+        mediaCachePath: containedInferredPath,
+      };
+    } else {
+      return {
+        annotation: `contained path does not have cache`,
+        mediaCachePath: null,
+      };
+    }
+  }
+
+  // Throw a secondary tantrum if the adjacent cache exists but is
+  // missing its cache file, because it's the less preferred cache.
+  // Unless we're indicated to regenerate a missing cache file!
+  if (adjacentIncludesThumbnailCache === false) {
+    if (regenerateMissingThumbnailCache) {
+      return {
+        annotation: `adjacent path will regenerate missing cache`,
+        mediaCachePath: adjacentInferredPath,
+      };
+    } else {
+      return {
+        annotation: `adjacent path does not have cache`,
+        mediaCachePath: null,
+      };
+    }
+  }
+
+  // If wikiCachePath was provided and the contained cache just doesn't
+  // exist yet, we'll create it during this run.
+  if (wikiCachePath && containedIncludesThumbnailCache === null) {
+    return {
+      annotation: `contained path will be created`,
+      mediaCachePath: containedInferredPath,
+    };
+  }
+
+  // If the adjacent cache doesn't exist, too dang bad!
+  // We aren't interested in newly creating it, so
+  // don't count it as an option.
+
+  // Similarly, we've already established mediaPath isn't
+  // currently doubling as the thumbnail cache, and we won't
+  // newly start generating thumbnails here either.
+
+  // All options aside struck out, there's no way to continue.
+
+  return {
+    annotation: `missing wiki cache to create media cache inside`,
+    mediaCachePath: null,
+  };
 }
 
 export async function migrateThumbsIntoDedicatedCacheDirectory({
diff --git a/src/upd8.js b/src/upd8.js
index 4b5064a6..e2b65b75 100755
--- a/src/upd8.js
+++ b/src/upd8.js
@@ -240,7 +240,12 @@ async function main() {
     },
 
     'media-cache-path': {
-      help: `Specify path to media cache directory, including automatically generated thumbnails\n\nThis usually doesn't need to be provided, and will be inferred by adding "-cache" to the end of the media directory`,
+      help: `Specify path to media cache directory, including automatically generated thumbnails\n\nThis usually doesn't need to be provided, and will be inferred either by loading "media-cache" from --cache-path, or by adding "-cache" to the end of the media directory\n\nAlso may be provided via the HSMUSIC_MEDIA_CACHE environment variable`,
+      type: 'value',
+    },
+
+    'cache-path': {
+      help: `Specify path to general cache directory, usually containing generated thumbnails and assorted files reused between builds\n\nRequired for some features and may always be required if you're starting a new workspace\n\nAlso may be provided via the HSMUSIC_CACHE environment varaible`,
       type: 'value',
     },
 
@@ -284,6 +289,11 @@ async function main() {
       type: 'flag',
     },
 
+    'new-thumbs': {
+      help: `Repair a media cache that's completely missing its index file by starting clean and not reusing any existing thumbnails`,
+      type: 'flag',
+    },
+
     'skip-file-sizes': {
       help: `Skips preloading file sizes for images and additional files, which will be left blank in the build`,
       type: 'flag',
@@ -473,6 +483,7 @@ async function main() {
 
   const dataPath = cliOptions['data-path'] || process.env.HSMUSIC_DATA;
   const mediaPath = cliOptions['media-path'] || process.env.HSMUSIC_MEDIA;
+  const wikiCachePath = cliOptions['cache-path'] || process.env.HSMUSIC_CACHE;
   const langPath = cliOptions['lang-path'] || process.env.HSMUSIC_LANG; // Can 8e left unset!
 
   const thumbsOnly = cliOptions['thumbs-only'] ?? false;
@@ -500,6 +511,10 @@ async function main() {
     logError`${`Expected --media-path option or HSMUSIC_MEDIA to be set`}`;
   }
 
+  if (!wikiCachePath) {
+    logWarn`No --cache-path option nor HSMUSIC_CACHE set; provide for more features`;
+  }
+
   if (!dataPath || !mediaPath) {
     return false;
   }
@@ -761,31 +776,118 @@ async function main() {
     timeStart: Date.now(),
   });
 
+  const regenerateMissingThumbnailCache =
+    cliOptions['new-thumbs'] ?? false;
+
   const {mediaCachePath, annotation: mediaCachePathAnnotation} =
     await determineMediaCachePath({
       mediaPath,
+      wikiCachePath,
+
       providedMediaCachePath:
         cliOptions['media-cache-path'] || process.env.HSMUSIC_MEDIA_CACHE,
+
+      regenerateMissingThumbnailCache,
+
       disallowDoubling:
         stepStatusSummary.migrateThumbnails.status === STATUS_NOT_STARTED,
     });
 
+  if (regenerateMissingThumbnailCache) {
+    if (
+      mediaCachePathAnnotation !== `contained path will regenerate missing cache` &&
+      mediaCachePathAnnotation !== `adjacent path will regenerate missing cache`
+    ) {
+      if (mediaCachePath) {
+        logError`Determined a media cache path. (${mediaCachePathAnnotation})`;
+        console.error('');
+        logWarn`By using ${'--new-thumbs'}, you requested to generate completely`;
+        logWarn`new thumbnails, but there's already a ${'thumbnail-cache.json'}`;
+        logWarn`file where it's expected, within this media cache:`;
+        logWarn`${path.resolve(mediaCachePath)}`;
+        console.error('');
+        logWarn`If you really do want to completely regenerate all thumbnails`;
+        logWarn`and not reuse any existing ones, move aside ${'thumbnail-cache.json'}`;
+        logWarn`and run with ${'--new-thumbs'} again.`;
+
+        Object.assign(stepStatusSummary.determineMediaCachePath, {
+          status: STATUS_FATAL_ERROR,
+          annotation: `--new-thumbs provided but regeneration not needed`,
+          timeEnd: Date.now(),
+        });
+
+        return false;
+      } else {
+        logError`Couldn't determine a media cache path. (${mediaCachePathAnnotation})`;
+        console.error('');
+        logWarn`You requested to generate completely new thumbnails, but`;
+        logWarn`the media cache wasn't readable or just couldn't be found.`;
+        logWarn`Run again without ${'--new-thumbs'} - you should investigate`;
+        logWarn`what's going on before continuing.`;
+
+        Object.assign(stepStatusSummary.determineMediaCachePath, {
+          status: STATUS_FATAL_ERROR,
+          annotation: mediaCachePathAnnotation,
+          timeEnd: Date.now(),
+        });
+
+        return false;
+      }
+    }
+  }
+
   if (!mediaCachePath) {
     logError`Couldn't determine a media cache path. (${mediaCachePathAnnotation})`;
 
     switch (mediaCachePathAnnotation) {
-      case 'inferred path does not have cache':
-        logError`If you're certain this is the right path, you can provide it via`;
-        logError`${'--media-cache-path'} or ${'HSMUSIC_MEDIA_CACHE'}, and it should work.`;
+      case `contained path does not have cache`:
+        console.error('');
+        logError`You've provided a ${'--cache-path'} or ${'HSMUSIC_CACHE_PATH'},`;
+        logError`${path.resolve(wikiCachePath)}`;
+        console.error('');
+        logError`It contains a ${'media-cache'} folder, but this folder is`;
+        logError`missing its ${'thumbnail-cache.json'} file. This means there's`;
+        logError`no information available to reuse. If you use this cache,`;
+        logError`hsmusic will generate any existing thumbnails over again.`;
+        console.error('');
+        logError`* Try to see if you can recover or locate a copy of your`;
+        logError`  ${'thumbnail-cache.json'} file and put it back in place;`;
+        logError`* Or, generate all-new thumbnails with ${'--new-thumbs'}.`;
         break;
 
-      case 'inferred path not readable':
+      case 'adjacent path does not have cache':
+        console.error('');
+        logError`You have an existing ${'media-cache'} folder next to your media path,`;
+        logError`${path.resolve(mediaPath)}`;
+        console.error('');
+        logError`The ${'media-cache'} folder is missing its ${'thumbnail-cache.json'}`;
+        logError`file. This means there's no information available to reuse,`;
+        logError`and if you use this cache, hsmusic will generate any existing`;
+        logError`thumbnails over again.`;
+        console.error('');
+        logError`* Try to see if you can recover or locate a copy of your`;
+        logError`  ${'thumbnail-cache.json'} file and put it back in place;`;
+        logError`* Or, generate all-new thumbnails with ${'--new-thumbs'}.`;
+        break;
+
+      case `contained path not readable`:
+      case `adjacent path not readable`:
+        console.error('');
         logError`The folder couldn't be read, which usually indicates`;
         logError`a permissions error. Try to resolve this, or provide`;
         logError`a new path with ${'--media-cache-path'} or ${'HSMUSIC_MEDIA_CACHE'}.`;
         break;
 
-      case 'media path not provided': /* unreachable */
+      case `missing wiki cache to create media cache inside`:
+        console.error('');
+        logError`It looks like you're starting totally fresh, so please`;
+        logError`create a ${'cache'} folder and provide it with ${'--cache-path'}`;
+        logError`or ${'HSMUSIC_CACHE'}. The media cache will automatically be`;
+        logError`generated inside of this folder!`;
+        break;
+
+      case `media path not provided`: /* unreachable */
+        console.error('');
         logError`It seems a ${'--media-path'} (or ${'HSMUSIC_MEDIA'}) wasn't provided.`;
         logError`Make sure one of these is actually pointing to a path that exists.`;
         break;
@@ -1794,6 +1896,7 @@ async function main() {
       const webRouteSources = await identifyAllWebRoutes({
         mediaCachePath,
         mediaPath,
+        wikiCachePath,
       });
 
       const {aggregate, result} =
diff --git a/src/web-routes.js b/src/web-routes.js
index ab9633b8..efd86ca1 100644
--- a/src/web-routes.js
+++ b/src/web-routes.js
@@ -36,6 +36,7 @@ export const allStaticWebRoutes = [
 export async function identifyDynamicWebRoutes({
   mediaPath,
   mediaCachePath,
+  wikiCachePath,
 }) {
   const routeFunctions = [
     () => Promise.resolve([