tutanota/buildSrc/fetchDictionaries.js

143 lines
4.3 KiB
JavaScript
Raw Normal View History

/**
* Utility to download/update the dictionaries used for translations within the app.
*/
import path from "node:path"
import { exitOnFail, getDefaultDistDirectory } from "./buildUtils.js"
2022-12-27 15:37:40 +01:00
import { program } from "commander"
import { spawnSync } from "node:child_process"
import { fileURLToPath } from "node:url"
import fs from "fs-extra"
2022-05-10 12:07:23 +02:00
import "zx/globals"
import { getElectronVersion } from "./getInstalledModuleVersion.js"
if (process.argv[1] === fileURLToPath(import.meta.url)) {
2022-04-28 14:36:24 +02:00
program
2022-12-27 15:37:40 +01:00
.usage("[options]")
.description("Utility to update the app dictionaries")
.option("--out-dir <outDir>", "Base dir of client build")
.option("--publish", "Build and publish .deb package for dictionaries.")
.action(async (options) => {
const outDir = typeof options.outDir !== "undefined" ? options.outDir : getDefaultDistDirectory()
const publishDictionaries = typeof options.publish !== "undefined" ? options.publish : false
await getDictionaries(outDir)
2022-12-27 15:37:40 +01:00
.then(async (v) => {
2022-04-28 14:36:24 +02:00
console.log("Dictionaries updated successfully")
if (publishDictionaries) {
await publishDebPackage()
}
process.exit()
})
2022-12-27 15:37:40 +01:00
.catch((e) => {
console.log("Fetching dictionaries failed: ", e)
process.exit(1)
})
})
2022-04-28 14:36:24 +02:00
.parse(process.argv)
}
/**
*
* @param outDir
* @returns {Promise<*>}
*/
async function getDictionaries(outDir) {
2022-05-02 17:17:33 +02:00
const electronVersion = await getElectronVersion()
const targetPath = path.join(outDir, "dictionaries")
return fetchDictionaries(electronVersion, targetPath)
}
async function publishDebPackage() {
const commonArgs = `-f -s dir -t deb --deb-user tutadb --deb-group tutadb`
const target = `/opt/tutanota`
2022-05-02 17:17:33 +02:00
const electronVersion = await getElectronVersion()
const deb = `tutanota-desktop-dicts_${electronVersion}_amd64.deb`
console.log("create", deb)
2022-12-27 15:37:40 +01:00
exitOnFail(
spawnSync(
"/usr/local/bin/fpm",
`${commonArgs} -n tutanota-desktop-dicts -v ${electronVersion} dictionaries/=${target}-desktop/dictionaries`.split(" "),
{
cwd: "build",
stdio: [process.stdin, process.stdout, process.stderr],
},
),
)
// copy spell checker dictionaries.
console.log("copying dictionaries")
2022-12-27 15:37:40 +01:00
exitOnFail(
spawnSync("/bin/cp", `-f build/${deb} /opt/repository/tutanota/`.split(" "), {
stdio: [process.stdin, process.stdout, process.stderr],
}),
)
exitOnFail(
spawnSync("/bin/chmod", `o+r /opt/repository/tutanota/${deb}`.split(" "), {
stdio: [process.stdin, process.stdout, process.stderr],
}),
)
}
/**
* get the electron spell check dictionaries from the github release page.
* @param electronVersion {string} which dictionaries to fetch
* @param target the target folder for the dictionaries
* @returns {Promise<*>}
*/
export async function fetchDictionaries(electronVersion, target) {
console.log("downloading dictionaries into:", target)
const url = `https://github.com/electron/electron/releases/download/v${electronVersion}/hunspell_dictionaries.zip`
2022-12-27 15:37:40 +01:00
const jszip = await import("jszip")
await fs.promises.mkdir(target, { recursive: true })
const zipArchive = await fetch(url).then(jszip.default.loadAsync)
for (const name of Object.keys(zipArchive.files)) {
const contents = await zipArchive.files[name].async("nodebuffer")
await fs.promises.writeFile(path.join(target, name.toLowerCase()), contents)
}
}
async function fetch(url) {
const https = await import("node:https")
return new Promise((resolve, reject) => {
const data = []
// using setTimeout because .on('timeout', handler) is
// a connection timeout, once the connection stands it
// can take as long as it wants.
const to = setTimeout(() => {
request.abort()
reject(`download of ${url} timed out`)
}, 60000)
2022-12-27 15:37:40 +01:00
const request = https
.get(url, (response) => {
if (response.statusCode === 302) {
fetch(response.headers.location)
.then((...args) => {
clearTimeout(to)
resolve(...args)
})
.catch((...args) => {
clearTimeout(to)
reject(...args)
})
} else if (response.statusCode === 200) {
response
.on("data", (c) => data.push(c))
.on("end", () => {
clearTimeout(to)
resolve(Buffer.concat(data))
})
} else {
clearTimeout(to)
2022-12-27 15:37:40 +01:00
reject("Couldn't fetch: " + url + ", got " + response.statusCode)
}
})
.on("error", (err) => {
clearTimeout(to)
2022-12-27 15:37:40 +01:00
reject(err.message)
})
})
}