2022-02-14 10:19:20 +01:00
|
|
|
/**
|
|
|
|
* Utility to download/update the dictionaries used for translations within the app.
|
|
|
|
*/
|
2023-04-20 17:14:30 +02:00
|
|
|
import path from "node:path"
|
2023-04-19 13:58:49 +02:00
|
|
|
import { exitOnFail, getDefaultDistDirectory } from "./buildUtils.js"
|
2022-12-27 15:37:40 +01:00
|
|
|
import { program } from "commander"
|
2023-04-20 17:14:30 +02:00
|
|
|
import { spawnSync } from "node:child_process"
|
|
|
|
import { fileURLToPath } from "node:url"
|
2022-02-14 10:19:20 +01:00
|
|
|
import fs from "fs-extra"
|
2022-05-10 12:07:23 +02:00
|
|
|
import "zx/globals"
|
2023-04-19 13:58:49 +02:00
|
|
|
import { getElectronVersion } from "./getInstalledModuleVersion.js"
|
2022-02-14 10:19:20 +01:00
|
|
|
|
|
|
|
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
|
2022-02-14 10:19:20 +01:00
|
|
|
|
2024-07-05 19:02:03 +02:00
|
|
|
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-02-14 10:19:20 +01:00
|
|
|
})
|
2022-04-28 14:36:24 +02:00
|
|
|
.parse(process.argv)
|
2022-02-14 10:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param outDir
|
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2023-11-27 17:08:01 +01:00
|
|
|
async function getDictionaries(outDir) {
|
2022-05-02 17:17:33 +02:00
|
|
|
const electronVersion = await getElectronVersion()
|
2023-11-27 17:08:01 +01:00
|
|
|
const targetPath = path.join(outDir, "dictionaries")
|
|
|
|
return fetchDictionaries(electronVersion, targetPath)
|
2022-02-14 10:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
2022-02-14 10:19:20 +01:00
|
|
|
const deb = `tutanota-desktop-dicts_${electronVersion}_amd64.deb`
|
|
|
|
|
2022-05-18 16:30:38 +02:00
|
|
|
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],
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2022-02-14 10:19:20 +01:00
|
|
|
|
|
|
|
// 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],
|
|
|
|
}),
|
|
|
|
)
|
2022-02-14 10:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get the electron spell check dictionaries from the github release page.
|
|
|
|
* @param electronVersion {string} which dictionaries to fetch
|
2023-11-27 17:08:01 +01:00
|
|
|
* @param target the target folder for the dictionaries
|
2022-02-14 10:19:20 +01:00
|
|
|
* @returns {Promise<*>}
|
|
|
|
*/
|
2023-11-27 17:08:01 +01:00
|
|
|
export async function fetchDictionaries(electronVersion, target) {
|
|
|
|
console.log("downloading dictionaries into:", target)
|
2022-02-14 10:19:20 +01:00
|
|
|
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")
|
2023-11-27 17:08:01 +01:00
|
|
|
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)
|
|
|
|
}
|
2022-02-14 10:19:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
async function fetch(url) {
|
2023-04-20 17:14:30 +02:00
|
|
|
const https = await import("node:https")
|
2022-02-14 10:19:20 +01:00
|
|
|
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 {
|
2022-02-14 10:19:20 +01:00
|
|
|
clearTimeout(to)
|
2022-12-27 15:37:40 +01:00
|
|
|
reject("Couldn't fetch: " + url + ", got " + response.statusCode)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.on("error", (err) => {
|
2022-02-14 10:19:20 +01:00
|
|
|
clearTimeout(to)
|
2022-12-27 15:37:40 +01:00
|
|
|
reject(err.message)
|
|
|
|
})
|
2022-02-14 10:19:20 +01:00
|
|
|
})
|
|
|
|
}
|