Verified Commit 359fffaa authored by Aral Balkan's avatar Aral Balkan
Browse files

Add new naming/directory placement conventions for archival cascade

(And deprecate the old convention.)
parent 9d582b05
......@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Changed
- Naming and directory placement conventions for archival cascades. Existing conventions will work but have been deprecated. Please see the README file for further details.
- Improved log output.
- Improved test output.
......
......@@ -533,22 +533,30 @@ When you `serve` a site at `@hostname` or use the `enable` command, globally-tru
What if links never died? What if we never broke the Web? What if it didn’t involve any extra work? It’s possible. And, with Site.js, it’s effortless.
### Native cascading archives support
### The Archival Cascade
If you have a static archive of the previous version of your site, you can have Site.js automatically serve it for you. For example, if your site is being served from the `my-site` folder, just put the archive of your site into a folder named `my-site-archive-1`:
__(As of version 12.11.0)__ If you have static archives of previous versions of your site, you can have Site.js automatically serve them for you.
Just put them into folder named `.archive-1`, `.archive-2`, etc.
If a path cannot be found in your current site, Site.js will search for it first in `.archive-2` and, if it cannot find it there either, in `.archive-1`.
Paths in your current site will override those in `.archive-2` and those in `.archive-2` will, similarly, override those in `.archive-1`.
Use the archival old links will never die but if you do replace them with never content in never versions, those will take precedence.
#### Legacy method (pre version 12.11.0)
In older versions, the convention for specifying the archival cascade was as follows:
```
|- my-site
|- my-site-archive-1
|- my-site-archive-2
|- etc.
```
If a path cannot be found in `my-site`, it will be served from `my-site-archive-1`.
And you’re not limited to a single archive (and hence the “cascade” bit in the name of the feature). As you have multiple older versions of your site, just add them to new folders and increment the archive index in the name. e.g., `my-site-archive-2`, `my-site-archive-3`, etc.
Paths in `my-site` will override those in `my-site-archive-3` and those in `my-site-archive-3` will, similarly, override those in `my-site-archive-2` and so on.
What this means that your old links will never die but if you do replace them with never content in never versions, those will take precedence.
This legacy method of specifying the archival cascade is still supported but may be removed in a future release. Please use the recommended method outlined above instead.
### Native 404 → 302 support
......
......@@ -423,7 +423,7 @@ class Site {
this.appAddTest500ErrorPage()
this.appAddDynamicRoutes()
this.appAddStaticRoutes()
this.appAddArchiveCascade()
this.appAddArchivalCascade()
}
......@@ -840,7 +840,8 @@ class Site {
//
// 1. Advanced _routes.js_-based advanced routing.
//
// 2. Separate folders for _.https_ and _.wss_ routes routing (the _.http_ folder itself will apply precedence rules 3 and 4 internally).
// 2. Separate folders for _.https_ and _.wss_ routes routing (the _.http_ folder itself will apply
// precedence rules 3 and 4 internally).
//
// 3. Separate folders for _.get_ and _.post_ routes in HTTPS-only routing.
//
......@@ -1014,58 +1015,97 @@ class Site {
}
// Check if we should implement an archive cascade.
// e.g., given the following folder structure:
// Check if we should implement an archival cascade.
//
// |-site
// |- site-archive-2
// |- site-archive-1
// As of 12.11.0, the preferred method of setting up an archival
// cascade is to include the archives in the root directory of your
// site while conforming to the following naming convention:
//
// .archive-1, .archive-2, etc.
//
// If we are asked to serve site, we would try and serve any 404s
// first from site-archive-2 and then from site-archive-1. The idea
// is that site-archive-\d+ are static archives of older versions of
// The routes in the archives will be served in the order indicated
// by their index.
//
// To illustrate: In the above example, if we get a 404, we will
// try to find the path in .archive-2 and then in .archive-1. The idea
// is that .archive-\d+ are static archives of older versions of
// the site and they are being served in order to maintain an
// evergreen web where we try not to break existing links. If site
// has a path, it will override site-archive-2 and site-archive-1. If
// site-archive-2 has a path, it will override site-archive-1 and so
// evergreen web where we try not to break existing links. If the
// current site has a path, it will override .archive-2 and .archive-1.
// If .archive-2 has a path, it will override .archive-1 and so
// on. In terms of latest version to oldest version, the order is
// site, site-archive-2, site-archive-1.
// the current site, site-archive-2, site-archive-1.
//
// Legacy usage (pre Site.js version 12.11.0) [Deprecated.]
//
// The archives would be specified according to the following folder structure:
//
// The archive cascade is automatically created by naming and location
// |-site
// |- site-archive-2
// |- site-archive-1
//
// The archive cascade was automatically created by naming and location
// convention. If the folder that is being served is called
// my-lovely-site, then the archive folders we would look for are
// my-lovely-site-archive-1, etc.
appAddArchiveCascade () {
const archiveCascade = []
//
// Note: this legacy method is still supported by deprecated. Please migrate
// ===== your sites to use the new method as this method will be removed
// in a future release.
appAddArchivalCascade () {
const archivalCascade = []
const absolutePathToServe = this.absolutePathToServe
// (Windows uses forward slashes in paths so write the RegExp accordingly for that platform.)
const pathName = process.platform === 'win32' ? absolutePathToServe.match(/.*\\(.*?)$/)[1] : absolutePathToServe.match(/.*\/(.*?)$/)[1]
if (pathName !== '') {
let archiveLevel = 0
do {
archiveLevel++
const archiveDirectory = path.resolve(absolutePathToServe, '..', `${pathName}-archive-${archiveLevel}`)
if (fs.existsSync(archiveDirectory)) {
// Archive exists, add it to the archive cascade.
archiveCascade.push(archiveDirectory)
} else {
// Archive does not exist.
break
}
} while (true)
// New method. Check for folders called .archive-\d+ in the folder being
// served. This is a simpler method in general and, practically, easier
// to deploy and projects feel better encapsulated.
const fileNames = fs.readdirSync(absolutePathToServe)
// We will implement the cascade in reverse (from highest archive number to the
// lowest, with latter versions overriding earlier ones), so reverse the list.
archiveCascade.reverse()
// Filter directories that match the naming convention.
const archivalCascade = fileNames.filter(fileName => {
const matchesNamingConvention = fileName.match(/^.archive-\d+$/)
if (matchesNamingConvention) {
const fileStats = fs.statSync(path.join(absolutePathToServe, fileName))
return fileStats.isDirectory()
} else {
return false
}
})
if (archivalCascade.length === 0) {
//
// No archives found; try the legacy method.
//
// (Windows uses forward slashes in paths so write the RegExp accordingly for that platform.)
const pathName = process.platform === 'win32' ? absolutePathToServe.match(/.*\\(.*?)$/)[1] : absolutePathToServe.match(/.*\/(.*?)$/)[1]
if (pathName !== '') {
let archiveLevel = 0
do {
archiveLevel++
const archiveDirectory = path.resolve(absolutePathToServe, '..', `${pathName}-archive-${archiveLevel}`)
if (fs.existsSync(archiveDirectory)) {
// Archive exists, add it to the archive cascade.
archivalCascade.push(archiveDirectory)
} else {
// Archive does not exist.
break
}
} while (true)
// We will implement the cascade in reverse (from highest archive number to the
// lowest, with latter versions overriding earlier ones), so reverse the list.
archivalCascade.reverse()
}
}
// Serve the archive cascade (if there is one).
// Note: for the archive cascade, we use express.static instead of instant as, by the
// ===== nature of it being an archive, live reload should not be a requirement.
let archiveNumber = 0
archiveCascade.forEach(archivePath => {
archivalCascade.forEach(archivePath => {
archiveNumber++
this.log(` 🌱 ❨Site.js❩ Evergreen web: serving archive #${archiveNumber}`)
this.app.use(express.static(archivePath))
......@@ -1077,4 +1117,3 @@ Site.appNameAndVersionAlreadyLogged = false
Site._versionNumber = null
module.exports = Site
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment