UNPKG

node-talisman

Version:

A npm package for running Thoughtwork's Talisman tool

400 lines (354 loc) 11 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var path = _interopDefault(require('path')); var os = _interopDefault(require('os')); var fs = _interopDefault(require('fs')); var clogy = _interopDefault(require('clogy')); var request = _interopDefault(require('request')); var crypto = _interopDefault(require('crypto')); var mkdirp = _interopDefault(require('mkdirp')); var execSh = _interopDefault(require('exec-sh')); const getDirname = path.dirname; const CONSOLE_COLORS = { white: '\x1b[1m\x1b[30m\x1b[47m%s\x1b[0m', cyan: '\x1b[1m\x1b[37m\x1b[46m%s\x1b[0m', red: '\x1b[1m\x1b[37m\x1b[41m%s\x1b[0m', green: '\x1b[1m\x1b[37m\x1b[42m%s\x1b[0m' }; const CHECKSUMS = { talisman_linux_386: process.env.TALISMAN_LINUX_386_CHECKSUM || '8de2384ecd56fbf1d51b08db4670a067b3209244a1707ed941ec64ee3af0041f', talisman_linux_amd64: process.env.TALISMAN_LINUX_AMD64_CHECKSUM || '8e0ae8bb7b160bf10c4fa1448beb04a32a35e63505b3dddff74a092bccaaa7e4', talisman_linux_arm64: process.env.TALISMAN_LINUX_ARM64_CHECKSUM || 'ca706f428a45d7a4ed3cc5c3cf7b3e5b0dfce6f2f584000a117d0d602a0342b7', // NOTE: Checksum for darwin_386 not present in original checksum file. talisman_darwin_386: process.env.TALISMAN_DARWIN_386_CHECKSUM || '', talisman_darwin_amd64: process.env.TALISMAN_DARWIN_AMD64_CHECKSUM || '9a67e015d6c99650c45d653ce4a597f885bf661164c2671f08a3827013b277fb', talisman_darwin_arm64: process.env.TALISMAN_DARWIN_ARM64_CHECKSUM || '4806746b2ba0190941f0606853990b4da6eb7df2d64c261212a6aa66eb6b15c2', 'talisman_windows_386.exe': process.env.TALISMAN_WINDOWS_386_CHECKSUM || '06baa1703b9e50c67567aafc92aa699929a54069f0ca6df1cb6a99fe36c98538', 'talisman_windows_amd64.exe': process.env.TALISMAN_WINDOWS_AMD64_CHECKSUM || '64b4f61fadd254f0bf32b5411e678564a8f201bd61a811105e286495df644be1', 'talisman_windows_arm64.exe': process.env.TALISMAN_WINDOWS_ARM64_CHECKSUM || 'ce3649680a427fa1204b418c9e5b67c83f32737c1426993796cd9ee6cde1ebc9' }; const META_INFO = { version: process.env.TALISMAN_VERSION || 'v1.37.0' }; const PATHS = { // TODO: Replace __filename with require('url').fileURLToPath(import.meta.url); // Need some investigation here. Not working out of box. BINARY: path.resolve(getDirname(__filename), 'bin', META_INFO.version) }; const PLATFORMS = { macOS: { key: 'darwin', name: 'darwin' }, linux: { key: 'linux', name: 'linux' }, windows: { key: 'win', name: 'windows' } }; const ARCHITECTURES = { threeEightySix: { key: '32', name: '386' }, sixtyFour: { key: '64', name: 'amd64' } }; const isObject = value => { const type = typeof value; return value != null && (type === 'object' || type === 'function'); }; const replacePlaceholdersInTargetValue = value => { const replacePlaceholders = placeholders => { return Object.keys(placeholders).reduce((accum, placeholder) => accum.replace(new RegExp(`{${placeholder}}`, 'g'), placeholders[placeholder]), value); }; replacePlaceholders.toString = () => value; return replacePlaceholders; }; const createDeepProxy = obj => new Proxy(obj, { get(target, prop) { const value = target[prop] || prop; if (isObject(value)) { return createDeepProxy(value); } return replacePlaceholdersInTargetValue(value); } }); const defaultLanguage = 'en'; const messages = { [defaultLanguage]: { check: { inProgress: 'Checking source files....', succeed: 'Check passed!!!!', failed: 'Check failed!!!! There might be some security breaches or you might have changed parts of any file listed in ".talismanrc" or the binary itself has some unknown error. If you have changed parts of any file listed in ".talismanrc", Please update ".talismanrc" with latest checksum (https://github.com/thoughtworks/talisman#ignoring-files). For more details, Please check the above report.' }, download: { inProgress: 'Downloading {NAME}....', succeed: 'Successfully downloaded {NAME}!!!!', failed: 'Failed to download {NAME}!!!!' }, makeExecutable: { succeed: 'Made binary executable!!!!', failed: 'Failed to make binary executable!!!!' }, verifyChecksum: { succeed: 'Checksum verification passed!!!!', failed: 'Checksum verification failed!!!!' }, writeFile: { succeed: 'File written to disk!!!!', failed: 'Failed to write file on disk!!!!' }, binary: 'binary', keyNotPresentInList: '{KEY} not present in {LIST}' } }; var messages$1 = createDeepProxy(messages[process.env.TALISMAN_LANGUAGE || defaultLanguage] || messages[defaultLanguage]); const getMatchedName = (key, list) => { const listItemMatched = Object.keys(list).find(listItem => key.includes(list[listItem].key)); if (!listItemMatched) { throw new ReferenceError(messages$1.keyNotPresentInList({ KEY: key, LIST: JSON.stringify(list) })); } return list[listItemMatched].name; }; const getPlatform = () => getMatchedName(os.platform(), PLATFORMS); const getArchitecture = () => getMatchedName(os.arch(), ARCHITECTURES); const isWindows = () => os.platform() === 'win32'; const doesFileExists = filePath => fs.existsSync(filePath); clogy.setLevel(clogy.LEVELS.log); const logToConsoleForDebugging = message => { if (process.env.__TALISMAN__DEV__) { clogy.trace(CONSOLE_COLORS.white, JSON.stringify(message)); } }; const logToConsole = (...args) => { if (args.length < 2) { return clogy.log(); } const [{ color = CONSOLE_COLORS.white } = { color: CONSOLE_COLORS.white }, message] = args; return clogy.log(`${CONSOLE_COLORS.white} ${color}`, ' TALISMAN >>>> ', ` ${message} `); }; const download = ({ url, name }) => { logToConsoleForDebugging({ url, name }); return new Promise((resolve, reject) => { logToConsole({ color: CONSOLE_COLORS.cyan }, messages$1.download.inProgress({ NAME: name })); logToConsole(); request({ url, encoding: null }, (error, response, data) => { if (!error && response.statusCode === 200) { logToConsole({ color: CONSOLE_COLORS.green }, messages$1.download.succeed({ NAME: name })); logToConsole(); return resolve(data); } logToConsole({ color: CONSOLE_COLORS.red }, messages$1.download.failed({ NAME: name })); logToConsole(); return reject(error); }); }); }; const getChecksum = (data, algorithm = 'sha256', encoding = 'hex') => crypto.createHash(algorithm).update(data).digest(encoding); const verifyChecksum = ({ data, checksum }) => { logToConsoleForDebugging({ checksum }); return new Promise((resolve, reject) => { const isChecksumEqual = getChecksum(data) === checksum; logToConsoleForDebugging({ isChecksumEqual }); if (isChecksumEqual) { logToConsole({ color: CONSOLE_COLORS.green }, messages$1.verifyChecksum.succeed.toString()); logToConsole(); return resolve(isChecksumEqual); } const errorMessage = messages$1.verifyChecksum.failed.toString(); logToConsole({ color: CONSOLE_COLORS.red }, errorMessage); logToConsole(); return reject(new Error(errorMessage)); }); }; const writeFile = ({ fileBasePath, filePath, data }) => { logToConsoleForDebugging({ fileBasePath, filePath }); return new Promise((resolve, reject) => { try { if (!doesFileExists(fileBasePath)) { mkdirp.sync(fileBasePath); } fs.writeFileSync(filePath, data); logToConsole({ color: CONSOLE_COLORS.green }, messages$1.writeFile.succeed.toString()); logToConsole(); resolve(); } catch (error) { logToConsole({ color: CONSOLE_COLORS.red }, messages$1.writeFile.failed.toString()); logToConsole(); reject(error); } }); }; const wrapTextIfNotWindows = wrapper => text => isWindows() ? text : `${wrapper}${text}${wrapper}`; const wrapTextWithQuotesIfNotWindows = wrapTextIfNotWindows(`"`); const makeExecutable = ({ filePath }) => { logToConsoleForDebugging({ filePath }); return new Promise((resolve, reject) => { if (isWindows()) { return resolve(); } return execSh([`chmod +x ${wrapTextWithQuotesIfNotWindows(filePath)}`], error => { if (!error) { logToConsole({ color: CONSOLE_COLORS.green }, messages$1.makeExecutable.succeed.toString()); logToConsole(); return resolve(); } logToConsole({ color: CONSOLE_COLORS.red }, messages$1.makeExecutable.failed.toString()); logToConsole(); return reject(error); }); }); }; const install = ({ url, checksum, fileBasePath, fileName, filePath }) => { logToConsoleForDebugging({ url, checksum, fileBasePath, fileName, filePath }); return download({ url, name: messages$1.binary.toString() }).then(data => verifyChecksum({ data, checksum }).then(() => data)).then(data => writeFile({ fileBasePath, filePath, data }).then(() => data)).then(data => makeExecutable({ filePath }).then(() => data)); }; const getProcessArgs = args => args.slice(2).join(' '); const wrapTextWithQuotesIfNotWindows$1 = wrapTextIfNotWindows(`"`); const check = ({ filePath, args }) => { logToConsoleForDebugging({ filePath }); return new Promise((resolve, reject) => { logToConsole({ color: CONSOLE_COLORS.cyan }, messages$1.check.inProgress.toString()); logToConsole(); execSh([`${wrapTextWithQuotesIfNotWindows$1(filePath)} ${getProcessArgs(args)}`], error => { if (!error) { logToConsole({ color: CONSOLE_COLORS.green }, messages$1.check.succeed.toString()); logToConsole(); return resolve(); } logToConsole({ color: CONSOLE_COLORS.red }, messages$1.check.failed.toString()); logToConsole(); return reject(error); }); }); }; const fileName = `talisman_${getPlatform()}_${getArchitecture()}${isWindows() ? '.exe' : ''}`; const url = `https://github.com/thoughtworks/talisman/releases/download/${META_INFO.version}/${fileName}`; const checksum = CHECKSUMS[fileName]; const fileBasePath = PATHS.BINARY; const filePath = path.resolve(fileBasePath, fileName); const runner = args => { if (doesFileExists(filePath)) { return check({ filePath, args }); } return install({ url, checksum, fileBasePath, fileName, filePath }).then(() => check({ filePath, args })); }; var index = (args => runner(args).catch(error => { setImmediate(() => { throw error; }); })); exports.default = index; //# sourceMappingURL=index.js.map