UNPKG

@tangelo/tangelo-configuration-toolkit

Version:

Tangelo Configuration Toolkit is a command-line toolkit which offers support for developing a Tangelo configuration.

135 lines (109 loc) 6.35 kB
const fs = require('fs-extra'); const objMerge = require('object-assign-deep'); const path = require('path'); function getRemotePath (...arr) { const fp = path.join(this.server.remotedir, ...arr); return this.server.remotedir.includes(':') ? fp : fp.toFws; } function setServer (searchString) { if (!searchString) _error('No server was passed.'); const stringsToArrays = stringOrArray => [stringOrArray].flat(); const filterDomains = domain => domain[0].startsWith(searchString) || domain.slice(1).includes(searchString); const filterServerConfigs = (arr, cfg) => { if (cfg.domains) cfg.domains = cfg.domains.map(stringsToArrays).filter(filterDomains); if (cfg.name === searchString || cfg.domains?.[0]) arr.push(cfg); return arr; }; // find server in local config and filter domains let serverConfigs = _appconfig.servers?.reduce(filterServerConfigs, []); // if nothing found, find server in shared config and filter domains if (!serverConfigs?.[0]) serverConfigs = _appconfig.shared.servers?.reduce(filterServerConfigs, []); // abort if no config is found, or if multiple configs or domains are found for server if (!serverConfigs?.[0]) _error(`No config found for "${searchString}".`); if (serverConfigs.length > 1 || serverConfigs[0].domains?.length > 1) { const matches = serverConfigs.map(obj => obj.name === searchString ? obj.name : obj.domains); const matchesFlatten = matches.flat().map(stringsToArrays).map(m => m[0] + (m[1] ? ` [${m.slice(1).join(', ')}]` : '')).join(', '); _error(`Passed server name "${searchString}" gives multiple results:\n${matchesFlatten}`); } // complement serverconfig with defaults const serverConfig = objMerge( {config: {}, domains: [[]]}, // make sure keys are present _appconfig.shared.serverDefaults, // override with shared defaults _appconfig.serverDefaults, // override with local defaults serverConfigs[0] ); // compose final server config in usable format const {config, domains: [[host]], mode} = serverConfig; this.server = {remotedir: config.remotedir}; if (host) { const {parallel, port, username} = config; if (!(port && parallel && username)) _error('Config is incomplete!'); this.server.ftpConfig = { host, port, parallel, username, agent: process.env.SSH_AUTH_SOCK ?? process.platform === 'win32' ? '\\\\.\\pipe\\openssh-ssh-agent' : undefined, agentForward: true, readyTimeout: 15000, retries: 1 }; } if (mode === 'delivery-pack') { const dateStr = new Date().toISOString().replace(/(.*)T(\d+):(\d+):(\d+).*/g, '$1_$2$3$4'); this.deliveryPackName = `tangelo-config-delivery-pack_${_paths.repo.split(/[\\/]/).pop()}_${dateStr}`; this.server.remotedir += '/' + this.deliveryPackName; // output to temp folder this.deliveryPack = true; } this.envDev = !host && !this.deliveryPack || /\.dev\.tangelo\.nl$/.test(host); } function prepareForCopy (filter) { const {remotedir, ftpConfig} = this.server; if (!path.isAbsolute(remotedir)) _error('"remotedir" must contain an absolute path!'); this.giPatterns = !fs.existsSync('.gitignore') ? [] : fs.readFileSync('.gitignore').toString() .trim() .replace(/^#.+/gm, '') // remove comments .split(/\s+/) // split on lines .filter(p => !p.match(/(^database\/)|(\/tdi)|(\/fonto)/)) // filter paths that should be copied .map(p => '!' + (p.match(/^config/) ? p : '**/' + p.split('**/').pop()) + (p.match(/\/$/) ? '**' : '')) // negate expressions, remove base dir, suffix folders with ** ; let transferPattern = path.join(_paths.apply, filter).toFws; // test if 'cmscustom/tdi' would be included, then add specifically, because following symlinks doesnt work with glob stars const tdiIncRegex = /^(config\/)?((\{\w*,?)?cmscustom(,?\w*\})?\/|\*\/)?\*\*/; const tdiPattern = tdiIncRegex.test(transferPattern) ? transferPattern.replace(tdiIncRegex, `${this.deliveryPack ? 'config/' : ''}cmscustom/tdi/**`) : 'nomatch'; if (!transferPattern) _error('Invalid glob expression passed!'); else if (this.deliveryPack && transferPattern.startsWith('*')) transferPattern = `{config,database,${_paths.tdi}/src/database/tdi}/${transferPattern}`; else if (!this.deliveryPack) { // for normal deployment to server, set config-dir so no other files in repo are unintentionally transferred transferPattern = transferPattern.replace(/^config\/|^\//, ''); try { process.chdir('config'); } catch(e) { _error('No config dir present!'); } } this.transferPatterns = [transferPattern, tdiPattern, ...this.giPatterns, '!**/*.crdownload']; // ignore patterns must come last if (this.deliveryPack && transferPattern.includes(_paths.tdi)) this.transferPatterns.push(`${_paths.tdi}/src/database/create*.sql`); // create(_exists).sql is called by tdi install // add time parameters to all xopus requests to overcome cache const ts = new Date().toISOString().replace(/[-:]/g, '').substring(0, 15); this.replaceStrings = [ [/((xsd|xsl|src|iconsrc)="[^"?]+)"/g, `$1?_=${ts}"`, '**/xopus/xml/*'], [/(schemaLocation="[^"?]+)"/g, `$1?_=${ts}"`, '**/xopus/xsd/*'], [/(href="[^"?]+.xsl)"/g, `$1?_=${ts}"`, '**/xopus/xsl/*'] ]; // depending on env, enable debug mode and change track functionality if (this.envDev) { this.transferPatterns.push('!ldap.xml'); this.replaceStrings.push( ['debug.on=false', 'debug.on=true', '**/util.js'], ['debugMode>false', 'debugMode>true', '**/xopus/xml/*'], ['allowAccept>false', 'allowAccept>true', '**/xopus/xml/*'], ['allowReject>false', 'allowReject>true', '**/xopus/xml/*'], [/(id="generateSampleText" available=")false/, '$1true', '**/xopus/xml/*'] ); } else this.replaceStrings.push(['debugMode>true', 'debugMode>false', '**/xopus/xml/*']); _info(`Branch: ${_git.commitLocal().branch}`); _info(`Source: ${path.join(process.cwd(), transferPattern)}`); _info(`Server: ${ftpConfig ? `${ftpConfig.host}:${ftpConfig.port}` : 'local'}`); _info(`Target: ${this.getRemotePath(transferPattern)}`); _write(); } module.exports = {getRemotePath, setServer, prepareForCopy};