mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
163 lines
4.8 KiB
JavaScript
163 lines
4.8 KiB
JavaScript
const { writeFile, copy, mkdirp, remove } = require('fs-extra');
|
|
const glob = require('glob');
|
|
const { resolve } = require('path');
|
|
const { dirname } = require('@joplin/tools/gulp/utils');
|
|
|
|
const rootDir = resolve(__dirname, '../../..');
|
|
const nodeModulesDir = resolve(__dirname, '../node_modules');
|
|
|
|
function stripOffRootDir(path) {
|
|
if (path.startsWith(rootDir)) return path.substr(rootDir.length + 1);
|
|
return path;
|
|
}
|
|
|
|
const msleep = async (ms) => {
|
|
return new Promise((resolve) => {
|
|
setTimeout(() => {
|
|
resolve();
|
|
}, ms);
|
|
});
|
|
};
|
|
|
|
// Running this script on CI is very unreliable. It fails with errors that don't
|
|
// make much sense, such as:
|
|
//
|
|
// [Error: ENOENT: no such file or directory, copyfile
|
|
// '/home/runner/work/joplin/joplin/Assets/TinyMCE/langs/ro_RO.js' ->
|
|
// '/home/runner/work/joplin/joplin/packages/app-desktop/vendor/lib/tinymce/langs/ro_RO.js']
|
|
//
|
|
// (but "Assets/TinyMCE/langs/ro_RO.js" exists, since it's in the repo, and it's
|
|
// normal that "tinymce/langs/ro_RO.js" doesn't exist since we want to create
|
|
// it...)
|
|
//
|
|
// Another one, when trying to delete a directory:
|
|
//
|
|
// ENOTEMPTY: directory not empty
|
|
//
|
|
// (also makes no sense since the point of calling `remove()` is to remove a
|
|
// directory that is not empty)
|
|
//
|
|
// Those errors are random - they may or may not happen on a CI run, and always
|
|
// on different files. Since they don't make sense and are seemingly impossible
|
|
// to fix, we instead implement a retry mechanism with exponential backoff. The
|
|
// failures are relatively rare so 5 attempts should be enough to ensure all CI
|
|
// runs succeed.
|
|
//
|
|
// It's possible the same technique should be added to copyPluginAssets too.
|
|
|
|
const withRetry = async (fn) => {
|
|
for (let i = 0; i < 5; i++) {
|
|
try {
|
|
await fn();
|
|
return;
|
|
} catch (error) {
|
|
console.warn(`withRetry: Failed calling function - will retry (${i})`, error);
|
|
await msleep(1000 + i * 1000);
|
|
}
|
|
}
|
|
|
|
throw new Error('withRetry: Could not run function after multiple attempts');
|
|
};
|
|
|
|
async function main() {
|
|
const langSourceDir = resolve(__dirname, '../../../Assets/TinyMCE/langs');
|
|
const buildLibDir = resolve(__dirname, '../vendor/lib');
|
|
const buildDir = resolve(__dirname, '../build');
|
|
|
|
const dirs = [
|
|
'tinymce',
|
|
'@fortawesome/fontawesome-free/webfonts',
|
|
'roboto-fontface/fonts',
|
|
'codemirror/theme',
|
|
{
|
|
src: langSourceDir,
|
|
dest: `${buildLibDir}/tinymce/langs`,
|
|
},
|
|
{
|
|
src: `${nodeModulesDir}/tesseract.js-core`,
|
|
dest: `${buildDir}/tesseract.js-core`,
|
|
},
|
|
];
|
|
|
|
const files = [
|
|
'@fortawesome/fontawesome-free/css/all.min.css',
|
|
'@joeattardi/emoji-button/dist/index.js',
|
|
'codemirror/addon/dialog/dialog.css',
|
|
'codemirror/lib/codemirror.css',
|
|
'mark.js/dist/mark.min.js',
|
|
'react-datetime/css/react-datetime.css',
|
|
'roboto-fontface/css/roboto/roboto-fontface.css',
|
|
'smalltalk/css/smalltalk.css',
|
|
'smalltalk/img/IDR_CLOSE_DIALOG_H.png',
|
|
'smalltalk/img/IDR_CLOSE_DIALOG.png',
|
|
{
|
|
src: resolve(__dirname, '../../lib/services/plugins/sandboxProxy.js'),
|
|
dest: `${buildLibDir}/@joplin/lib/services/plugins/sandboxProxy.js`,
|
|
},
|
|
{
|
|
src: `${nodeModulesDir}/pdfjs-dist/build/pdf.worker.min.js`,
|
|
dest: `${buildDir}/pdf.worker.min.js`,
|
|
},
|
|
{
|
|
src: `${nodeModulesDir}/tesseract.js/dist/worker.min.js`,
|
|
dest: `${buildDir}/tesseract.js/worker.min.js`,
|
|
},
|
|
];
|
|
|
|
// First we delete all the destination directories, then we copy the files.
|
|
// It seems there's a race condition if we delete then copy right away.
|
|
for (const action of ['delete', 'copy']) {
|
|
for (const dir of dirs) {
|
|
let sourceDir, destDir;
|
|
|
|
if (typeof dir !== 'string') {
|
|
sourceDir = dir.src;
|
|
destDir = dir.dest;
|
|
} else {
|
|
sourceDir = `${nodeModulesDir}/${dir}`;
|
|
destDir = `${buildLibDir}/${dir}`;
|
|
}
|
|
|
|
if (action === 'delete') {
|
|
await withRetry(() => remove(destDir));
|
|
} else {
|
|
console.info(`Copying ${stripOffRootDir(sourceDir)} => ${stripOffRootDir(destDir)}`);
|
|
await withRetry(() => mkdirp(destDir));
|
|
await withRetry(() => copy(sourceDir, destDir, { overwrite: true }));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const file of files) {
|
|
let sourceFile, destFile;
|
|
|
|
if (typeof file !== 'string') {
|
|
sourceFile = file.src;
|
|
destFile = file.dest;
|
|
} else {
|
|
sourceFile = `${nodeModulesDir}/${file}`;
|
|
destFile = `${buildLibDir}/${file}`;
|
|
}
|
|
|
|
await withRetry(() => mkdirp(dirname(destFile)));
|
|
|
|
console.info(`Copying ${stripOffRootDir(sourceFile)} => ${stripOffRootDir(destFile)}`);
|
|
await withRetry(() => copy(sourceFile, destFile, { overwrite: true }));
|
|
}
|
|
|
|
const supportedLocales = glob.sync(`${langSourceDir}/*.js`).map(s => {
|
|
s = s.split('/');
|
|
s = s[s.length - 1];
|
|
s = s.split('.');
|
|
return s[0];
|
|
});
|
|
|
|
supportedLocales.sort();
|
|
|
|
const content = `module.exports = ${JSON.stringify(supportedLocales, null, 2)}`;
|
|
|
|
await writeFile(`${__dirname}/../gui/NoteEditor/NoteBody/TinyMCE/supportedLocales.js`, content, 'utf8');
|
|
}
|
|
|
|
module.exports = main;
|