From 3c0abb8d8aeb6b334e52b766ca3f81f3db88fd6b Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Tue, 3 Jul 2018 11:39:30 +0200 Subject: [PATCH] Add support to regenerate nsl cache if corrupted. --- src/bootstrap-amd.js | 13 +- src/main.js | 124 +++++++++++------- .../electron-browser/issue/issueReporter.js | 13 +- .../processExplorer/processExplorer.js | 13 +- .../sharedProcess/sharedProcess.js | 13 +- .../electron-browser/bootstrap/index.js | 13 +- 6 files changed, 134 insertions(+), 55 deletions(-) diff --git a/src/bootstrap-amd.js b/src/bootstrap-amd.js index f0015d389d3..98bc02c22cd 100644 --- a/src/bootstrap-amd.js +++ b/src/bootstrap-amd.js @@ -29,6 +29,8 @@ function readFile(file) { }); } +const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + var rawNlsConfig = process.env['VSCODE_NLS_CONFIG']; var nlsConfig = rawNlsConfig ? JSON.parse(rawNlsConfig) : { availableLanguages: {} }; @@ -46,8 +48,15 @@ if (nlsConfig._resolvedLanguagePackCoreLocation) { let json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); - }) - .catch(cb); + }).catch((error) => { + try { + if (nlsConfig._corruptedFile) { + writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); }); + } + } finally { + cb(error, undefined); + } + }); }; } diff --git a/src/main.js b/src/main.js index 624bf52f0c1..5d30c39f692 100644 --- a/src/main.js +++ b/src/main.js @@ -123,6 +123,10 @@ const exists = file => new Promise(c => fs.exists(file, c)); const readFile = file => new Promise((c, e) => fs.readFile(file, 'utf8', (err, data) => err ? e(err) : c(data))); const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); const touch = file => new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); }); +const lstat = file => new Promise((c, e) => fs.lstat(file, (err, stats) => err ? e(err) : c(stats))); +const readdir = dir => new Promise((c, e) => fs.readdir(dir, (err, files) => err ? e(err) : c(files))); +const rmdir = dir => new Promise((c, e) => fs.rmdir(dir, err => err ? e(err) : c(undefined))); +const unlink = file => new Promise((c, e) => fs.unlink(file, err => err ? e(err) : c(undefined))); function mkdirp(dir) { return mkdir(dir).then(null, err => { @@ -138,6 +142,23 @@ function mkdirp(dir) { }); } +function rimraf(location) { + return lstat(location).then(stat => { + if (stat.isDirectory() && !stat.isSymbolicLink()) { + return readdir(location) + .then(children => Promise.all(children.map(child => rimraf(path.join(location, child))))) + .then(() => rmdir(location)); + } else { + return unlink(location); + } + }, (err) => { + if (err.code === 'ENOENT') { + return void 0; + } + throw err; + }); +} + function resolveJSFlags(...jsFlags) { if (args['js-flags']) { @@ -267,62 +288,75 @@ function getNLSConfiguration(locale) { let cacheRoot = path.join(userData, 'clp', packId); let coreLocation = path.join(cacheRoot, commit); let translationsConfigFile = path.join(cacheRoot, 'tcf.json'); + let corruptedFile = path.join(cacheRoot, 'corrupted.info'); let result = { locale: initialLocale, availableLanguages: { '*': locale }, _languagePackId: packId, _translationsConfigFile: translationsConfigFile, _cacheRoot: cacheRoot, - _resolvedLanguagePackCoreLocation: coreLocation + _resolvedLanguagePackCoreLocation: coreLocation, + _corruptedFile: corruptedFile }; - return exists(coreLocation).then((fileExists) => { - if (fileExists) { - // We don't wait for this. No big harm if we can't touch - touch(coreLocation).catch(() => { }); - perf.mark('nlsGeneration:end'); - return result; + return exists(corruptedFile).then((corrupted) => { + // The nls cache directory is corrupted. + let toDelete; + if (corrupted) { + toDelete = rimraf(cacheRoot); + } else { + toDelete = Promise.resolve(undefined); } - return mkdirp(coreLocation).then(() => { - return Promise.all([readFile(path.join(__dirname, 'nls.metadata.json')), readFile(mainPack)]); - }).then((values) => { - let metadata = JSON.parse(values[0]); - let packData = JSON.parse(values[1]).contents; - let bundles = Object.keys(metadata.bundles); - let writes = []; - for (let bundle of bundles) { - let modules = metadata.bundles[bundle]; - let target = Object.create(null); - for (let module of modules) { - let keys = metadata.keys[module]; - let defaultMessages = metadata.messages[module]; - let translations = packData[module]; - let targetStrings; - if (translations) { - targetStrings = []; - for (let i = 0; i < keys.length; i++) { - let elem = keys[i]; - let key = typeof elem === 'string' ? elem : elem.key; - let translatedMessage = translations[key]; - if (translatedMessage === undefined) { - translatedMessage = defaultMessages[i]; + return toDelete.then(() => { + return exists(coreLocation).then((fileExists) => { + if (fileExists) { + // We don't wait for this. No big harm if we can't touch + touch(coreLocation).catch(() => { }); + perf.mark('nlsGeneration:end'); + return result; + } + return mkdirp(coreLocation).then(() => { + return Promise.all([readFile(path.join(__dirname, 'nls.metadata.json')), readFile(mainPack)]); + }).then((values) => { + let metadata = JSON.parse(values[0]); + let packData = JSON.parse(values[1]).contents; + let bundles = Object.keys(metadata.bundles); + let writes = []; + for (let bundle of bundles) { + let modules = metadata.bundles[bundle]; + let target = Object.create(null); + for (let module of modules) { + let keys = metadata.keys[module]; + let defaultMessages = metadata.messages[module]; + let translations = packData[module]; + let targetStrings; + if (translations) { + targetStrings = []; + for (let i = 0; i < keys.length; i++) { + let elem = keys[i]; + let key = typeof elem === 'string' ? elem : elem.key; + let translatedMessage = translations[key]; + if (translatedMessage === undefined) { + translatedMessage = defaultMessages[i]; + } + targetStrings.push(translatedMessage); + } + } else { + targetStrings = defaultMessages; } - targetStrings.push(translatedMessage); + target[module] = targetStrings; } - } else { - targetStrings = defaultMessages; + writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); } - target[module] = targetStrings; - } - writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); - } - writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); - return Promise.all(writes); - }).then(() => { - perf.mark('nlsGeneration:end'); - return result; - }).catch((err) => { - console.error('Generating translation files failed.', err); - return defaultResult(locale); + writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); + return Promise.all(writes); + }).then(() => { + perf.mark('nlsGeneration:end'); + return result; + }).catch((err) => { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + }); + }); }); }); }); diff --git a/src/vs/code/electron-browser/issue/issueReporter.js b/src/vs/code/electron-browser/issue/issueReporter.js index 5b246f9491b..53abd748d7b 100644 --- a/src/vs/code/electron-browser/issue/issueReporter.js +++ b/src/vs/code/electron-browser/issue/issueReporter.js @@ -45,6 +45,8 @@ function readFile(file) { }); } +const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + function main() { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; @@ -127,8 +129,15 @@ function main() { let json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); - }) - .catch(cb); + }).catch((error) => { + try { + if (nlsConfig._corruptedFile) { + writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); }); + } + } finally { + cb(error, undefined); + } + }); }; } diff --git a/src/vs/code/electron-browser/processExplorer/processExplorer.js b/src/vs/code/electron-browser/processExplorer/processExplorer.js index 1fdb4bb8296..0a798fb876d 100644 --- a/src/vs/code/electron-browser/processExplorer/processExplorer.js +++ b/src/vs/code/electron-browser/processExplorer/processExplorer.js @@ -45,6 +45,8 @@ function readFile(file) { }); } +const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + function main() { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; @@ -102,8 +104,15 @@ function main() { let json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); - }) - .catch(cb); + }).catch((error) => { + try { + if (nlsConfig._corruptedFile) { + writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); }); + } + } finally { + cb(error, undefined); + } + }); }; } diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js index 98d6e852940..d7dd08b4e3d 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcess.js +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcess.js @@ -53,6 +53,8 @@ function readFile(file) { }); } +const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + function main() { const args = parseURLQueryArgs(); const configuration = JSON.parse(args['config'] || '{}') || {}; @@ -111,8 +113,15 @@ function main() { let json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); - }) - .catch(cb); + }).catch((error) => { + try { + if (nlsConfig._corruptedFile) { + writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); }); + } + } finally { + cb(error, undefined); + } + }); }; } diff --git a/src/vs/workbench/electron-browser/bootstrap/index.js b/src/vs/workbench/electron-browser/bootstrap/index.js index 75f6dc4d7f6..692122631e7 100644 --- a/src/vs/workbench/electron-browser/bootstrap/index.js +++ b/src/vs/workbench/electron-browser/bootstrap/index.js @@ -81,6 +81,8 @@ function readFile(file) { }); } +const writeFile = (file, content) => new Promise((c, e) => fs.writeFile(file, content, 'utf8', err => err ? e(err) : c())); + function registerListeners(enableDeveloperTools) { // Devtools & reload support @@ -180,8 +182,15 @@ function main() { let json = JSON.parse(content); bundles[bundle] = json; cb(undefined, json); - }) - .catch(cb); + }).catch((error) => { + try { + if (nlsConfig._corruptedFile) { + writeFile(nlsConfig._corruptedFile, 'corrupted').catch(function (error) { console.error(error); }); + } + } finally { + cb(error, undefined); + } + }); }; } -- GitLab