From d8d242fdbfef1a88d8f572234f41653765aa976d Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Sat, 30 Sep 2023 22:53:35 +0300 Subject: [PATCH 1/4] refactor to more generic code --- .gitignore | 1 + common.js | 123 ++++++++++++++++++++++++++++++++++++ latest-linker.js | 158 ++++++----------------------------------------- package.json | 5 +- test.js | 20 ++++++ 5 files changed, 164 insertions(+), 143 deletions(-) create mode 100755 common.js diff --git a/.gitignore b/.gitignore index 131da0f..180a766 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .nyc_output +.tap node_modules package-lock.json diff --git a/common.js b/common.js new file mode 100755 index 0000000..a9baf37 --- /dev/null +++ b/common.js @@ -0,0 +1,123 @@ +'use strict' + +const path = require('path') +const semver = require('semver') + +const ltsNames = { + 4: 'argon', + 6: 'boron', + 8: 'carbon', + 10: 'dubnium', + 12: 'erbium', + 14: 'fermium', + 16: 'gallium', + 18: 'hydrogen' +} + +class Linker { + #links = new Map() + #dirs = [] + #baseDir + #docsDir + constructor ({ baseDir, docsDir }) { + this.#baseDir = baseDir + this.#docsDir = docsDir + } + + async getLinks (allDirectories, readDir) { + const allDirs = allDirectories + .map((d) => path.basename(d)) + .map((d) => { + try { + return semver.parse(d) + /* c8 ignore next 3 */ + } catch (e) { + return null + } + }) + .filter(Boolean) + + this.#makeDocsLinks(allDirs.map((d) => d.raw)) + + this.#dirs = allDirs.filter((d) => semver.satisfies(d, '~0.10 || ~0.12 || >= 1.0')).map((d) => d.raw) + this.#dirs.sort((d1, d2) => semver.compare(d1, d2)) + + this.#link('0.10') + this.#link(0.12) + + for (let i = 1; ; i++) { + if (!this.#link(i) && i >= 4) { + break + } + } + + const max = this.#link(null) + const tbreg = new RegExp(`(\\w+)-${max}.tar.gz`) + const latestDir = path.join(this.#baseDir, 'latest') + + let tarball = (await readDir(this.#links.get(latestDir) || latestDir)).filter((f) => tbreg.test(f)) + + /* c8 ignore next 3 */ + if (tarball.length !== 1) { + throw new Error('Could not find latest.tar.gz') + } + + tarball = tarball[0] + const name = tarball.match(tbreg)[1] + const dst = path.join(this.#baseDir, `${name}-latest.tar.gz`) + this.#links.set(dst, path.join(this.#baseDir, 'latest', tarball)) + return this.#links + } + + #makeDocsLinks (versions) { + if (!this.#docsDir) { + return + } + + for (const version of versions) { + const src = path.join(this.#baseDir, version, 'docs') + const dst = path.join(this.#docsDir, version) + this.#links.set(dst, src) + } + } + + #link (version) { + const line = version && `${version}.x` + const range = version ? `${Number(version) < 1 ? '~' : '^'}${line}` : '*' + const max = semver.maxSatisfying(this.#dirs, range) + + if (!max) { + return false + } + + const symlink = (name) => { + const dst = path.join(this.#baseDir, name) + const src = path.join(this.#baseDir, max) + + this.#links.set(dst, src) + + if (!this.#docsDir) { + return + } + + const dsrc = path.join(this.#baseDir, max, 'docs') + const ddst = path.join(this.#docsDir, name) + this.#links.set(ddst, dsrc) + } + + if (line) { + symlink(`latest-v${line}`) + if (ltsNames[version]) { + symlink(`latest-${ltsNames[version]}`) + } + } else { + symlink('latest') + } + + return max + } +} + +module.exports = { + Linker +} diff --git a/latest-linker.js b/latest-linker.js index 946d21b..ebecd66 100755 --- a/latest-linker.js +++ b/latest-linker.js @@ -2,156 +2,34 @@ 'use strict' -const fs = require('fs') +const fs = require('fs/promises') const path = require('path') -const semver = require('semver') -const map = require('map-async') - -const ltsNames = { - 4: 'argon', - 6: 'boron', - 8: 'carbon', - 10: 'dubnium', - 12: 'erbium', - 14: 'fermium', - 16: 'gallium', - 18: 'hydrogen' -} +const { Linker } = require('./common.js') +/* c8 ignore next 3 */ if (process.argv.length < 3) { throw new Error('Usage: latest-linker.js [docs directory]') } const dir = path.resolve(process.argv[2]) -const docsDir = process.argv[3] && path.resolve(process.argv[3]) - -if (!fs.statSync(dir).isDirectory()) { - throw new Error('Usage: latest-linker.js [docs directory]') -} +const docsDir = process.argv[3] && path.resolve(process.argv[3]); -if (docsDir && !fs.statSync(docsDir).isDirectory()) { - throw new Error('Usage: latest-linker.js [docs directory]') -} - -map( - fs.readdirSync(dir).map((d) => path.join(dir, d)), - (d, callback) => fs.stat(d, (_, stat) => callback(null, { d, stat })), - afterMap -) - -function afterMap (err, allDirs) { - if (err) { - throw err +(async function main () { + /* c8 ignore next 3 */ + if (!(await fs.stat(dir)).isDirectory()) { + throw new Error('Usage: latest-linker.js [docs directory]') } - allDirs = allDirs.filter((d) => d.stat && d.stat.isDirectory()) - .map((d) => path.basename(d.d)) - .map((d) => { - try { - return semver.parse(d) - } catch (e) {} - }) - .filter(Boolean) - - makeDocsLinks(allDirs.map((v) => v.raw)) - - const dirs = allDirs.filter((d) => semver.satisfies(d, '~0.10 || ~0.12 || >= 1.0')) - .map((d) => d.raw) - - dirs.sort((d1, d2) => semver.compare(d1, d2)) - - link('0.10', dirs) - link(0.12, dirs) - - for (let i = 1; ; i++) { - if (!link(i, dirs) && i >= 4) { - break - } + /* c8 ignore next 3 */ + if (docsDir && !(await fs.stat(docsDir)).isDirectory()) { + throw new Error('Usage: latest-linker.js [docs directory]') } - const max = link(null, dirs) - const tbreg = new RegExp(`(\\w+)-${max}.tar.gz`) - - let tarball = fs.readdirSync(path.join(dir, 'latest')) - .filter((f) => tbreg.test(f)) - - if (tarball.length !== 1) { - throw new Error('Could not find latest.tar.gz') + const allDirs = (await fs.readdir(dir, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name) + const linker = new Linker({ baseDir: dir, docsDir }) + const links = await linker.getLinks(allDirs, fs.readdir) + for (const [dest, src] of links) { + await fs.unlink(dest).catch(() => {}) + await fs.symlink(src, dest) } - - tarball = tarball[0] - const name = tarball.match(tbreg)[1] - const dst = path.join(dir, `${name}-latest.tar.gz`) - try { - fs.unlinkSync(dst) - } catch (e) {} - fs.symlinkSync(path.join(dir, 'latest', tarball), dst) -} - -function makeDocsLinks (versions) { - if (!docsDir) { - return - } - - versions.forEach((version) => { - const src = path.join(dir, version, 'docs') - const dst = path.join(docsDir, version) - - fs.stat(src, (err, stat) => { - if (err || !stat.isDirectory()) { - return - } - - fs.unlink(dst, () => { - fs.symlink(src, dst, (err) => { - if (err) { - throw err - } - }) - }) - }) - }) -} - -function link (version, dirs) { - const line = version && `${version}.x` - const range = version ? `${Number(version) < 1 ? '~' : '^'}${line}` : '*' - const max = semver.maxSatisfying(dirs, range) - - if (!max) { - return false - } - - function symlink (name) { - const dst = path.join(dir, name) - const src = path.join(dir, max) - - try { - fs.unlinkSync(dst) - } catch (e) {} - fs.symlinkSync(src, dst) - - if (!docsDir) { - return - } - - const dsrc = path.join(dir, max, 'docs') - const ddst = path.join(docsDir, name) - - try { - fs.unlinkSync(ddst) - } catch (e) {} - fs.symlinkSync(dsrc, ddst) - } - - if (line) { - symlink(`latest-v${line}`) - if (ltsNames[version]) { - symlink(`latest-${ltsNames[version]}`) - } - } else { - symlink('latest') - } - - return max -} +})() diff --git a/package.json b/package.json index e13e54d..f434e5f 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "author": "Rod (http://r.va.gg/)", "license": "MIT", "dependencies": { - "map-async": "^0.1.1", "semver": "^7.3.2" }, "bin": { @@ -22,7 +21,7 @@ }, "preferGlobal": true, "devDependencies": { - "tap": "^14.10.8", - "standard": "^14.3.4" + "standard": "^17.1.0", + "tap": "^18.4.0" } } diff --git a/test.js b/test.js index 73799a3..9adfb07 100644 --- a/test.js +++ b/test.js @@ -4,6 +4,26 @@ const { execFileSync } = require('child_process') const fs = require('fs') const path = require('path') const tap = require('tap') +const { Linker } = require('./common.js') + +tap.test('Linker', async t => { + const linker = new Linker({ baseDir: 'base', docsDir: 'docs' }) + const links = await linker.getLinks( + ['v19.8.0/', 'v19.8.1/', 'v19.9.0/', 'v20.7.0/', 'v20.8.0/'], + async () => ['docs/', 'win-x64/', 'node-v20.8.0-aix-ppc64.tar.gz', 'node-v20.8.0-arm64.msi', 'node-v20.8.0-headers.tar.gz', 'node-v20.8.0.tar.gz'] + ) + t.same(links, new Map([ + ['docs/v19.8.0', 'base/v19.8.0/docs'], + ['docs/v19.8.1', 'base/v19.8.1/docs'], + ['docs/v19.9.0', 'base/v19.9.0/docs'], + ['docs/v20.7.0', 'base/v20.7.0/docs'], + ['docs/v20.8.0', 'base/v20.8.0/docs'], + ['base/latest', 'base/v20.8.0'], + ['docs/latest', 'base/v20.8.0/docs'], + ['base/node-latest.tar.gz', 'base/latest/node-v20.8.0.tar.gz'] + ])) + t.end() +}) tap.test('basic test', t => { const dir = t.testdir({ From 9d49b445599060283d6ea054fcf8091b052cee0f Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Sat, 30 Sep 2023 22:57:59 +0300 Subject: [PATCH 2/4] use node 18 in ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7ef7b7..58b1970 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: master env: - NODE_VERSION: 12.x + NODE_VERSION: 18.x jobs: test: From bf9c4bb08fa9ce2854d35e410d42b89b69ffe2ab Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Sat, 30 Sep 2023 23:06:40 +0300 Subject: [PATCH 3/4] --allow-incomplete-coverage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f434e5f..1908c3e 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "latest-linker.js", "scripts": { "lint": "standard", - "test": "npm run lint && tap test.js" + "test": "npm run lint && tap --allow-incomplete-coverage test.js" }, "repository": { "type": "git", From 4f274d5f3d44e8b4706555fd92dbd29031864c35 Mon Sep 17 00:00:00 2001 From: Moshe Atlow Date: Mon, 2 Oct 2023 17:33:33 +0300 Subject: [PATCH 4/4] change to node 16 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 58b1970..be5ec89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,7 +5,7 @@ on: branches: master env: - NODE_VERSION: 18.x + NODE_VERSION: 16.x jobs: test: