@leverege/build-tools 2.4.9 → 2.5.0-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/lib/server/build-tools.js +144 -0
- package/lib/server/getfbcfg.js +25 -0
- package/lib/server/getjson.js +74 -0
- package/lib/server/npm-scripts/postinstall.js +19 -0
- package/lib/server/overwhelm.js +373 -0
- package/lib/server/repo-init/Config.js +45 -0
- package/lib/server/repo-init/RepoInit.js +176 -0
- package/lib/server/repo-init/config.tgz +0 -0
- package/lib/server/repo-init/gitter/Gitter.js +241 -0
- package/lib/server/repo-init/gitter/RepoHosting.js +106 -0
- package/lib/server/repo-init/gitter/index.js +9 -0
- package/lib/server/repo-init/index.js +6 -0
- package/lib/server/repo-init/templates/Templates.js +279 -0
- package/lib/server/repo-init/templates/ToBuildSpec.js +95 -0
- package/lib/server/repo-init/templates/index.js +9 -0
- package/lib/server/repo-init/utils/Shell.js +102 -0
- package/lib/server/repo-init/utils/VersionCheck.js +82 -0
- package/lib/server/repo-init/utils/index.js +67 -0
- package/lib/web/build-tools.js +144 -0
- package/lib/web/getfbcfg.js +25 -0
- package/lib/web/getjson.js +74 -0
- package/lib/web/npm-scripts/postinstall.js +19 -0
- package/lib/web/overwhelm.js +373 -0
- package/package.json +30 -29
- package/src/bash-funcs +61 -0
- package/src/build-tools.js +137 -0
- package/src/{getfbcfg → getfbcfg.js} +7 -6
- package/src/getjson.js +74 -0
- package/src/helmdn +1 -1
- package/src/npm-scripts/postinstall.js +17 -0
- package/src/{overwhelm → overwhelm.js} +83 -83
- package/lib/server/packleate/Packleator.js +0 -280
- package/lib/server/packleate/index.js +0 -98
- package/lib/server/packleate/logo-ansi.js +0 -17
- package/lib/web/packleate/Packleator.js +0 -623
- package/lib/web/packleate/index.js +0 -163
- package/lib/web/packleate/logo-ansi.js +0 -3
- package/src/getjson +0 -48
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
|
+
|
|
3
5
|
const chalk = require( 'chalk' )
|
|
4
6
|
const cliArgs = require( 'command-line-args' )
|
|
5
|
-
const cliHelp = require( 'command-line-usage' )
|
|
7
|
+
// const cliHelp = require( 'command-line-usage' )
|
|
6
8
|
const exec = require( 'child_process' ).execSync
|
|
7
9
|
const fs = require( 'fs' )
|
|
8
10
|
const glob = require( 'glob' )
|
|
@@ -11,6 +13,7 @@ const ask = require( 'readline-sync' )
|
|
|
11
13
|
const YAML = require( 'js-yaml' )
|
|
12
14
|
|
|
13
15
|
const optionsDefinitions = [
|
|
16
|
+
/* eslint-disable no-multi-spaces */
|
|
14
17
|
{ name : 'context', alias : 'x', type : String, default : '' },
|
|
15
18
|
{ name : 'section', alias : 's', type : String, default : 'default' },
|
|
16
19
|
{ name : 'key', alias : 'k', type : String },
|
|
@@ -19,14 +22,16 @@ const optionsDefinitions = [
|
|
|
19
22
|
{ name : 'checkctx', alias : 't', type : Boolean, default : false },
|
|
20
23
|
{ name : 'fetchctx', alias : 'f', type : Boolean, default : false },
|
|
21
24
|
{ name : 'verbose', alias : 'v', type : Boolean, default : false },
|
|
25
|
+
/* eslint-enable no-multi-spaces */
|
|
22
26
|
]
|
|
23
27
|
const args = cliArgs( optionsDefinitions )
|
|
24
28
|
|
|
25
29
|
// The kubernetes context is equal to the git branch name.
|
|
26
30
|
const gitBranch = require( 'git-branch' ).sync()
|
|
27
|
-
const context = args.context || gitBranch
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
const context = args.context || gitBranch
|
|
33
|
+
|
|
34
|
+
if ( context === 'master' ) {
|
|
30
35
|
console.log( '***ERROR: master context is forbidden; change to a different branch\n\n' )
|
|
31
36
|
process.exit( 1 )
|
|
32
37
|
}
|
|
@@ -46,8 +51,7 @@ if ( context == 'master' ) {
|
|
|
46
51
|
//
|
|
47
52
|
const yaml = YAML.safeLoad( fs.readFileSync( 'overwhelm.yaml', 'utf-8' ) )
|
|
48
53
|
const over = yaml.default
|
|
49
|
-
let
|
|
50
|
-
let wtfs = cfgs
|
|
54
|
+
let cfgs = yaml[context]
|
|
51
55
|
|
|
52
56
|
// If we just need to check context return 0 if cfgs exists, else error.
|
|
53
57
|
if ( args.checkctx ) { process.exit( !cfgs ) }
|
|
@@ -68,9 +72,9 @@ if ( cfgs['PROJECT_BASE'] ) {
|
|
|
68
72
|
const tempCfgs = cfgs
|
|
69
73
|
cfgs = yaml[baseName]
|
|
70
74
|
Object.keys( tempCfgs ).forEach( ( key ) => { cfgs[key] = tempCfgs[key] } )
|
|
71
|
-
console.log(
|
|
72
|
-
console.log(
|
|
73
|
-
process.exit( 1 ) //XXX HERE
|
|
75
|
+
console.log( 'PROJECT_BASE still under evaluation' )
|
|
76
|
+
console.log( '\n cfgs=', cfgs )
|
|
77
|
+
process.exit( 1 ) // XXX HERE
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
Object.keys( cfgs ).forEach( ( key ) => { over[key] = cfgs[key] || over[key] } )
|
|
@@ -115,7 +119,7 @@ if ( varErrors.length > 0 ) {
|
|
|
115
119
|
varErrors.forEach( ( error ) => {
|
|
116
120
|
console.log( ` ${error}` )
|
|
117
121
|
} )
|
|
118
|
-
console.log('' )
|
|
122
|
+
console.log( '' )
|
|
119
123
|
process.exit( 1 )
|
|
120
124
|
}
|
|
121
125
|
|
|
@@ -139,9 +143,9 @@ const doReplacements = ( yamls, replacements ) => {
|
|
|
139
143
|
if ( missed ) {
|
|
140
144
|
console.log( '\n***ERROR: missing replacements in overwhelm.yaml for these tags:\n' )
|
|
141
145
|
missed.forEach( ( miss ) => {
|
|
142
|
-
console.log( ` TAG: ${miss.match( /OVH:<(.*)>/)[1]}` )
|
|
146
|
+
console.log( ` TAG: ${miss.match( /OVH:<(.*)>/ )[1]}` )
|
|
143
147
|
} )
|
|
144
|
-
console.log('' )
|
|
148
|
+
console.log( '' )
|
|
145
149
|
process.exit( 1 )
|
|
146
150
|
}
|
|
147
151
|
|
|
@@ -187,11 +191,10 @@ if ( args.key ) {
|
|
|
187
191
|
}
|
|
188
192
|
if ( args.export ) {
|
|
189
193
|
console.log( `export ${args.key}=${keys[args.key]}` )
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
194
|
+
} else {
|
|
192
195
|
console.log( keys[args.key] )
|
|
193
196
|
}
|
|
194
|
-
if ( !
|
|
197
|
+
if ( !args.continue ) process.exit()
|
|
195
198
|
}
|
|
196
199
|
|
|
197
200
|
// Find all of the potential target dirs. Utilize .gitignore to ignore files
|
|
@@ -206,9 +209,8 @@ const ahoy = glob.sync( '*/', opt )
|
|
|
206
209
|
ahoy.forEach( ( dir ) => {
|
|
207
210
|
if ( fs.existsSync( `${dir}/.noahoy` ) ) {
|
|
208
211
|
!args.fetchctx && console.log( chalk.yellow( `***WARNING: .noahoy detected, not regenerating ${dir}values.yaml` ) )
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
args.verbose && console.log( `Generating values in ${dir}` )
|
|
212
|
+
} else if ( !fs.existsSync( `${dir}/.nohelm` ) ) {
|
|
213
|
+
args.verbose && console.log( `Generating values in ${dir}` ) // eslint-disable-line no-unused-expressions
|
|
212
214
|
|
|
213
215
|
let valuesOut = [] // An accumulator for all of the output values.
|
|
214
216
|
|
|
@@ -216,25 +218,24 @@ ahoy.forEach( ( dir ) => {
|
|
|
216
218
|
const valuesLocal = `${dir}values-local.yaml`
|
|
217
219
|
|
|
218
220
|
if ( fs.existsSync( valuesLocal ) ) {
|
|
219
|
-
args.verbose && console.log( ` Local values in ${valuesLocal}` )
|
|
220
|
-
valuesOut +=
|
|
221
|
+
args.verbose && console.log( ` Local values in ${valuesLocal}` ) // eslint-disable-line no-unused-expressions
|
|
222
|
+
valuesOut += '\n# AHOY => values-local.yaml\n\n'
|
|
221
223
|
valuesOut += fs.readFileSync( valuesLocal, { encoding : 'utf-8' } )
|
|
222
224
|
}
|
|
223
225
|
valuesOut += `\n${values}`
|
|
224
|
-
valuesOut
|
|
226
|
+
valuesOut = doReplacements( valuesOut, over )
|
|
225
227
|
|
|
226
228
|
fs.writeFileSync( `${dir}/values.yaml`, valuesOut )
|
|
227
229
|
}
|
|
228
230
|
} )
|
|
229
231
|
|
|
230
|
-
|
|
231
232
|
// Set the GCP context for safety!
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
const clusterName = over.CLUSTER_NAME
|
|
234
|
+
const projectId = over.PROJECT_ID
|
|
235
|
+
let zone = over['GCE_REGION'] + ( over['GCE_ZONE'] ? `-${over['GCE_ZONE']}` : '' )
|
|
235
236
|
|
|
236
|
-
|
|
237
|
-
|
|
237
|
+
if ( !clusterName ) {
|
|
238
|
+
console.log( chalk.yellow(
|
|
238
239
|
`
|
|
239
240
|
|
|
240
241
|
The overwhelm.yaml file in this branch is missing a CLUSTER_NAME setting,
|
|
@@ -246,80 +247,79 @@ ahoy.forEach( ( dir ) => {
|
|
|
246
247
|
${chalk.bold.green( `CLUSTER_NAME : "\${PROJECT_NAME}"` )}
|
|
247
248
|
|
|
248
249
|
However, if the CLUSTER_NAME is not the same as the PROJECT_NAME then go
|
|
249
|
-
ahead and add the CLUSTER_NAME setting to the ${chalk.bold.green(projectId)} section of the
|
|
250
|
+
ahead and add the CLUSTER_NAME setting to the ${chalk.bold.green( projectId )} section of the
|
|
250
251
|
overwhelm.yaml file.
|
|
251
252
|
|
|
252
253
|
` ) )
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
process.exit( 1 )
|
|
255
|
+
}
|
|
255
256
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
let kubeout = '_no_current_context_'
|
|
258
|
+
try {
|
|
259
|
+
kubeout = exec( 'kubectl config current-context', { stdio : [ undefined ] } )
|
|
260
|
+
} catch ( err ) {
|
|
261
|
+
// err && console.log( `Caught Error =>[${err}]` )
|
|
262
|
+
}
|
|
262
263
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
const currentCtx = kubeout.toString().trim()
|
|
265
|
+
let desiredCtx = `gke_${projectId}_${zone}_${clusterName}`
|
|
266
|
+
let cmd = `gcloud container clusters get-credentials ${clusterName} --zone ${zone} --project ${projectId}`
|
|
266
267
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
// Check if we are using AWS
|
|
269
|
+
if ( cfgs.CLOUD === 'aws' ) {
|
|
270
|
+
const awsAcctId = cfgs['AWS_ACCT_ID']
|
|
271
|
+
zone = over['AWS_REGION']
|
|
272
|
+
desiredCtx = `arn:aws:eks:${zone}:${awsAcctId}:cluster/${clusterName}`
|
|
273
|
+
cmd = `aws eks --region ${zone} update-kubeconfig --name ${clusterName}`
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// TODO - FETCH AWS CLUSTER CREDENTIALS
|
|
274
277
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
} catch (err) {
|
|
285
|
-
process.exit( 61 ) // ECONNREFUSED
|
|
286
|
-
}
|
|
278
|
+
const matchedCtx = ( currentCtx === desiredCtx )
|
|
279
|
+
|
|
280
|
+
// just fetch the context and exit if -f is specified
|
|
281
|
+
if ( args.fetchctx ) {
|
|
282
|
+
if ( !matchedCtx ) {
|
|
283
|
+
try {
|
|
284
|
+
exec( `${cmd}`, { stdio : [ undefined ] } )
|
|
285
|
+
} catch ( err ) {
|
|
286
|
+
process.exit( 61 ) // ECONNREFUSED
|
|
287
287
|
}
|
|
288
|
-
process.exit( 0 )
|
|
289
288
|
}
|
|
289
|
+
process.exit( 0 )
|
|
290
|
+
}
|
|
290
291
|
|
|
291
|
-
|
|
292
|
-
|
|
292
|
+
if ( matchedCtx ) {
|
|
293
|
+
console.log( `
|
|
293
294
|
|
|
294
|
-
Current context matches => ${chalk.bold.green(currentCtx)}
|
|
295
|
+
Current context matches => ${chalk.bold.green( currentCtx )}
|
|
295
296
|
|
|
296
297
|
` )
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
console.log( `
|
|
298
|
+
} else {
|
|
299
|
+
console.log( `
|
|
300
300
|
You are about to change your Kubernetes context to:
|
|
301
|
-
CLUSTER_NAME => ${chalk.bold.green(clusterName)}
|
|
302
|
-
PROJECT_ID => ${chalk.bold.green(projectId)}
|
|
303
|
-
REGION => ${chalk.bold.green(zone)}
|
|
301
|
+
CLUSTER_NAME => ${chalk.bold.green( clusterName )}
|
|
302
|
+
PROJECT_ID => ${chalk.bold.green( projectId )}
|
|
303
|
+
REGION => ${chalk.bold.green( zone )}
|
|
304
304
|
|
|
305
305
|
` )
|
|
306
|
+
}
|
|
307
|
+
const operation = matchedCtx ? 'refetch the credentials' : 'switch your context'
|
|
308
|
+
const ans = ask.question( `Enter "${chalk.bold.green( 'yes' )}" if you wish to ${operation} => ` )
|
|
309
|
+
if ( ans !== 'yes' ) {
|
|
310
|
+
if ( matchedCtx ) {
|
|
311
|
+
console.log( chalk.bold.yellow( '\n\nSkipping a refetch of your Kubernetes context and credentials\n\n' ) )
|
|
312
|
+
process.exit( 0 )
|
|
306
313
|
}
|
|
307
|
-
const operation = matchedCtx ? 'refetch the credentials' : 'switch your context'
|
|
308
|
-
const ans = ask.question( `Enter "${chalk.bold.green( 'yes' )}" if you wish to ${operation} => ` )
|
|
309
|
-
if ( ans !== 'yes' ) {
|
|
310
|
-
if ( matchedCtx ) {
|
|
311
|
-
console.log( chalk.bold.yellow( `\n\nSkipping a refetch of your Kubernetes context and credentials\n\n` ) )
|
|
312
|
-
process.exit( 0 )
|
|
313
|
-
}
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
console.log( chalk.bold.red( '\n\nYour Kubernetes context and credentials do NOT match - this could be bad!\n\n' ) )
|
|
316
|
+
process.exit( 1 )
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
console.log( `\n\nExecuting: ${chalk.bold.yellow( cmd )}\n\n` )
|
|
320
|
+
exec( `${cmd}`, ( error, out ) => {
|
|
321
|
+
if ( error ) {
|
|
322
|
+
console.log( `\n\n***ERROR ${error}\n\n` )
|
|
316
323
|
process.exit( 1 )
|
|
317
324
|
}
|
|
318
|
-
|
|
319
|
-
console.log( `\n\nExecuting: ${chalk.bold.yellow(cmd)}\n\n` )
|
|
320
|
-
exec( `${cmd}`, ( error, out ) => {
|
|
321
|
-
if ( error ) {
|
|
322
|
-
console.log( `\n\n***ERROR ${error}\n\n` )
|
|
323
|
-
process.exit( 1 )
|
|
324
|
-
}
|
|
325
|
-
} )
|
|
325
|
+
} )
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
4
|
-
|
|
5
|
-
const exec = require('child_process').exec;
|
|
6
|
-
|
|
7
|
-
const fs = require('fs-extra');
|
|
8
|
-
|
|
9
|
-
const path = require('path');
|
|
10
|
-
|
|
11
|
-
const async = require('async');
|
|
12
|
-
|
|
13
|
-
const copy = require('recursive-copy');
|
|
14
|
-
|
|
15
|
-
const ora = require('ora');
|
|
16
|
-
|
|
17
|
-
const tar = require('tar');
|
|
18
|
-
|
|
19
|
-
const semver = require('semver');
|
|
20
|
-
|
|
21
|
-
class Packleator {
|
|
22
|
-
constructor(options) {
|
|
23
|
-
const {
|
|
24
|
-
args
|
|
25
|
-
} = options;
|
|
26
|
-
this.privatePackages = new Set();
|
|
27
|
-
this.args = args ? { ...args,
|
|
28
|
-
output: args.output.substr(-1) === '/' ? args.output.substr(0, args.output.length) : args.output
|
|
29
|
-
} : {}; // args || {}
|
|
30
|
-
|
|
31
|
-
this.spinner = ora({
|
|
32
|
-
text: 'Installing NPM dependencies...',
|
|
33
|
-
spinner: 'monkey'
|
|
34
|
-
});
|
|
35
|
-
this.stderr = '';
|
|
36
|
-
this.tarredVersions = {};
|
|
37
|
-
this.outputPackageJson = {};
|
|
38
|
-
this.outputPackageLockJson = {};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async run() {
|
|
42
|
-
try {
|
|
43
|
-
this.spinner.start();
|
|
44
|
-
await this.npmInstall();
|
|
45
|
-
this.spinner.text = 'Copying files...';
|
|
46
|
-
await this.copyFiles();
|
|
47
|
-
process.chdir(this.args.output);
|
|
48
|
-
this.outputPackageJson = await this.getPackageJson();
|
|
49
|
-
this.outputPackageLockJson = await this.getPackageJson(undefined, true);
|
|
50
|
-
this.spinner.text = 'Parsing private dependencies...';
|
|
51
|
-
const deps = await this.getPrivateDeps();
|
|
52
|
-
this.spinner.text = 'Packaging modules...';
|
|
53
|
-
async.eachOfSeries(deps, (item, key, callback) => {
|
|
54
|
-
if (this.args.verbose) {
|
|
55
|
-
console.log(item);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
this.getPackageJson(item).then(packageJson => {
|
|
59
|
-
const {
|
|
60
|
-
name,
|
|
61
|
-
version
|
|
62
|
-
} = packageJson;
|
|
63
|
-
this.pack(name, version, item).then(() => {
|
|
64
|
-
callback();
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}, async err => {
|
|
68
|
-
await this.rebuildPackageJson();
|
|
69
|
-
await this.rebuildPackageLockJson();
|
|
70
|
-
await fs.writeFile('package.json', JSON.stringify(this.outputPackageJson, null, 2));
|
|
71
|
-
await fs.writeFile('package-lock.json', JSON.stringify(this.outputPackageLockJson, null, 2));
|
|
72
|
-
await fs.remove('node_modules');
|
|
73
|
-
const {
|
|
74
|
-
name,
|
|
75
|
-
version
|
|
76
|
-
} = this.outputPackageJson;
|
|
77
|
-
const fileName = `${name.replace('@', '').replace('/', '-')}-${version}.tgz`;
|
|
78
|
-
process.chdir('..');
|
|
79
|
-
this.spinner.text = 'Packaging results...';
|
|
80
|
-
await tar.c({
|
|
81
|
-
file: fileName,
|
|
82
|
-
strict: true,
|
|
83
|
-
prefix: 'package/',
|
|
84
|
-
C: this.args.output
|
|
85
|
-
}, ['.']);
|
|
86
|
-
this.spinner.text = 'Cleaning up...';
|
|
87
|
-
await this.cleanup();
|
|
88
|
-
this.spinner.stop();
|
|
89
|
-
});
|
|
90
|
-
} catch (ex) {
|
|
91
|
-
this.spinner.stop();
|
|
92
|
-
throw ex;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
async rebuildPackageJson() {
|
|
97
|
-
const packageJson = this.outputPackageJson;
|
|
98
|
-
const tarredPackages = Object.keys(this.tarredVersions);
|
|
99
|
-
const {
|
|
100
|
-
dependencies = {},
|
|
101
|
-
devDependencies = {}
|
|
102
|
-
} = packageJson;
|
|
103
|
-
tarredPackages.forEach(tarredPackage => {
|
|
104
|
-
if (dependencies[tarredPackage]) {
|
|
105
|
-
const version = semver.maxSatisfying(this.tarredVersions[tarredPackage], dependencies[tarredPackage]);
|
|
106
|
-
|
|
107
|
-
if (version != null) {
|
|
108
|
-
packageJson.dependencies[tarredPackage] = `file:${Packleator.PRIVATE_PACKAGES_DIRECTORY}${path.sep}${tarredPackage.replace('@', '').replace('/', '-')}-${version}.tgz`;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (devDependencies[tarredPackage]) {
|
|
113
|
-
const version = semver.maxSatisfying(this.tarredVersions[tarredPackage], devDependencies[tarredPackage]);
|
|
114
|
-
|
|
115
|
-
if (version != null) {
|
|
116
|
-
packageJson.devDependencies[tarredPackage] = `file:${Packleator.PRIVATE_PACKAGES_DIRECTORY}${path.sep}${tarredPackage.replace('@', '').replace('/', '-')}-${version}.tgz`;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async rebuildPackageLockJson() {
|
|
123
|
-
const packageLockJson = this.outputPackageLockJson;
|
|
124
|
-
const tarredPackages = Object.keys(this.tarredVersions);
|
|
125
|
-
|
|
126
|
-
const recurseDeps = deps => {
|
|
127
|
-
Object.keys(deps).forEach(key => {
|
|
128
|
-
const dep = deps[key];
|
|
129
|
-
tarredPackages.forEach(tarredPackage => {
|
|
130
|
-
if (key === tarredPackage) {
|
|
131
|
-
dep.version = `file:${Packleator.PRIVATE_PACKAGES_DIRECTORY}${path.sep}${key.replace('@', '').replace('/', '-')}-${dep.version}.tgz`;
|
|
132
|
-
delete dep.resolved;
|
|
133
|
-
delete dep.integrity;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (dep.requires && dep.requires[tarredPackage]) {
|
|
137
|
-
delete dep.requires[tarredPackage];
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (dep.dependencies) {
|
|
142
|
-
recurseDeps(dep.dependencies);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
recurseDeps(packageLockJson.dependencies);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async copyFiles() {
|
|
151
|
-
const startsWith = new RegExp(`^(dist|lib|image|package|${this.args.output})`);
|
|
152
|
-
const endsWith = /\.tgz$/;
|
|
153
|
-
await fs.remove(this.args.output);
|
|
154
|
-
await fs.mkdirp(this.args.output);
|
|
155
|
-
await copy('.', this.args.output, {
|
|
156
|
-
overwrite: true,
|
|
157
|
-
dot: true,
|
|
158
|
-
filter: item => {
|
|
159
|
-
if (item === 'package.json' || item === 'package-lock.json') {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (startsWith.test(item) || endsWith.test(item)) {
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (item.startsWith('.') && item.indexOf('.babelrc') === -1) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (this.args.ignore.length > 0) {
|
|
172
|
-
return this.args.ignore.indexOf(item) === -1;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async pack(name, version, dir) {
|
|
181
|
-
const fileName = `${name.replace('@', '').replace('/', '-')}-${version}.tgz`;
|
|
182
|
-
await tar.c({
|
|
183
|
-
file: fileName,
|
|
184
|
-
C: dir,
|
|
185
|
-
strict: true,
|
|
186
|
-
prefix: 'package/'
|
|
187
|
-
}, ['.']);
|
|
188
|
-
await fs.move(path.join(process.cwd(), fileName), path.join(process.cwd(), Packleator.PRIVATE_PACKAGES_DIRECTORY, fileName), {
|
|
189
|
-
overwrite: true
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
if (this.tarredVersions[name]) {
|
|
193
|
-
this.tarredVersions[name].push(version);
|
|
194
|
-
} else {
|
|
195
|
-
this.tarredVersions[name] = [version];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (this.args.verbose) {
|
|
199
|
-
console.log(fileName);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return fileName;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async cleanup() {
|
|
206
|
-
await copy(this.args.output, process.cwd(), {
|
|
207
|
-
overwrite: true,
|
|
208
|
-
filter: '*.tgz'
|
|
209
|
-
});
|
|
210
|
-
await fs.remove(this.args.output);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
async npmInstall(dir = process.cwd()) {
|
|
214
|
-
const currentDir = process.cwd();
|
|
215
|
-
return new Promise((resolve, reject) => {
|
|
216
|
-
if (currentDir !== dir) {
|
|
217
|
-
process.chdir(dir);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const npmInstall = exec('npm install');
|
|
221
|
-
npmInstall.stderr.on('data', data => {
|
|
222
|
-
this.stderr += data.toString();
|
|
223
|
-
});
|
|
224
|
-
npmInstall.on('exit', code => {
|
|
225
|
-
if (currentDir !== dir) {
|
|
226
|
-
process.chdir(currentDir);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
resolve();
|
|
230
|
-
});
|
|
231
|
-
npmInstall.on('error', err => {
|
|
232
|
-
if (currentDir !== dir) {
|
|
233
|
-
process.chdir(currentDir);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
reject(err);
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async getPrivateDeps(depth) {
|
|
242
|
-
return new Promise((resolve, reject) => {
|
|
243
|
-
const depthArg = depth != null ? ` --depth ${depth}` : '';
|
|
244
|
-
exec(`npm ls --parseable --silent${depthArg}`, (err, stdout, stderr) => {
|
|
245
|
-
if (err && !stdout) {
|
|
246
|
-
reject(err);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const dependencies = stdout.split('\n');
|
|
251
|
-
|
|
252
|
-
if (dependencies) {
|
|
253
|
-
resolve(dependencies.filter(item => {
|
|
254
|
-
const parts = item.split(path.sep);
|
|
255
|
-
return this.args.namespaces.indexOf(parts[parts.length - 2]) !== -1;
|
|
256
|
-
}));
|
|
257
|
-
} else {
|
|
258
|
-
reject(new Error('Unable to resolve package.json dependencies'));
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
async getPackageJson(dir = process.cwd(), lock = false) {
|
|
265
|
-
const lockModifier = lock ? '-lock' : '';
|
|
266
|
-
|
|
267
|
-
try {
|
|
268
|
-
const file = await fs.readFile(path.join(dir, `package${lockModifier}.json`), 'utf-8');
|
|
269
|
-
const json = JSON.parse(file);
|
|
270
|
-
return json;
|
|
271
|
-
} catch (ex) {
|
|
272
|
-
throw new Error('Error getting package.json. Make sure the current directory contains a valid package.json file');
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
_defineProperty(Packleator, "PRIVATE_PACKAGES_DIRECTORY", 'private_packages');
|
|
279
|
-
|
|
280
|
-
module.exports = Packleator;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
const commandLineArgs = require('command-line-args');
|
|
5
|
-
|
|
6
|
-
const commandLineUsage = require('command-line-usage');
|
|
7
|
-
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
const Packleator = require('./Packleator');
|
|
11
|
-
|
|
12
|
-
const ansiLogo = require('./logo-ansi');
|
|
13
|
-
|
|
14
|
-
const defaultConfig = {
|
|
15
|
-
namespaces: ['@leverege'],
|
|
16
|
-
output: 'lev_dest'
|
|
17
|
-
};
|
|
18
|
-
const sections = [{
|
|
19
|
-
content: ansiLogo,
|
|
20
|
-
raw: true
|
|
21
|
-
}, {
|
|
22
|
-
content: 'Bundles private/proprietary npm packages and source code into a tarball for distribution'
|
|
23
|
-
}, {
|
|
24
|
-
header: 'Options',
|
|
25
|
-
optionList: [{
|
|
26
|
-
name: 'output',
|
|
27
|
-
alias: 'o',
|
|
28
|
-
description: 'The destination folder (optional)',
|
|
29
|
-
defaultValue: 'lev_dest'
|
|
30
|
-
}, {
|
|
31
|
-
name: 'ignore',
|
|
32
|
-
alias: 'i',
|
|
33
|
-
description: 'List of files or folders to ignore. Uses glob pattern matching (optional)',
|
|
34
|
-
multiple: true
|
|
35
|
-
}, {
|
|
36
|
-
name: 'namespaces',
|
|
37
|
-
alias: 'n',
|
|
38
|
-
description: 'List of npm namespaces to be considered private/proprietary (optional)',
|
|
39
|
-
multiple: true
|
|
40
|
-
}, {
|
|
41
|
-
name: 'verbose',
|
|
42
|
-
alias: 'v',
|
|
43
|
-
description: 'Log a little bit louder now'
|
|
44
|
-
}, {
|
|
45
|
-
name: 'help',
|
|
46
|
-
description: 'Print this usage guide.'
|
|
47
|
-
}]
|
|
48
|
-
}];
|
|
49
|
-
const usage = commandLineUsage(sections);
|
|
50
|
-
const optionDefinitions = [{
|
|
51
|
-
name: 'output',
|
|
52
|
-
alias: 'o',
|
|
53
|
-
type: String,
|
|
54
|
-
defaultValue: defaultConfig.output
|
|
55
|
-
}, {
|
|
56
|
-
name: 'ignore',
|
|
57
|
-
alias: 'i',
|
|
58
|
-
type: String,
|
|
59
|
-
multiple: true,
|
|
60
|
-
defaultValue: []
|
|
61
|
-
}, {
|
|
62
|
-
name: 'namespaces',
|
|
63
|
-
alias: 'n',
|
|
64
|
-
type: String,
|
|
65
|
-
defaultValue: defaultConfig.namespaces
|
|
66
|
-
}, {
|
|
67
|
-
name: 'verbose',
|
|
68
|
-
alias: 'v',
|
|
69
|
-
type: Boolean,
|
|
70
|
-
defaultValue: false
|
|
71
|
-
}, {
|
|
72
|
-
name: 'help',
|
|
73
|
-
type: Boolean
|
|
74
|
-
}];
|
|
75
|
-
const args = commandLineArgs(optionDefinitions);
|
|
76
|
-
|
|
77
|
-
async function main() {
|
|
78
|
-
if (args.help) {
|
|
79
|
-
console.log(usage);
|
|
80
|
-
} else {
|
|
81
|
-
const packleator = new Packleator({ ...defaultConfig,
|
|
82
|
-
args
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
if (args.verbose) {
|
|
86
|
-
console.log(packleator.args);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
await packleator.getPackageJson();
|
|
91
|
-
await packleator.run();
|
|
92
|
-
} catch (ex) {
|
|
93
|
-
console.error(ex.message);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
main();
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
module.exports = `[0;5;37;47m . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . [0m
|
|
4
|
-
[0;5;37;47m . . S% . . . . . . . . . . . . . . . . . . [0m
|
|
5
|
-
[0;5;37;47m . .:[0;1;30;47m%[0;1;37;47m [0;5;37;47m: . . . .. . . . . . ...... . ... .. . . . .. .. . ..... . .... . .. . ..... . ... . ..... . .. . . ..... . . . . [0m
|
|
6
|
-
[0;5;37;47m . :[0;1;34;46m8[0;1;30;47m8[0;5;37;47m:.. . . .8: . [0;1;37;47m.[0;5;37;40m8[0;1;30;47m.[0;5;37;47m . .. [0;1;37;47m@[0;5;37;40m8[0;1;30;47mX@@@@@@8%[0;5;37;47m [0;1;37;47m@[0;1;30;47m88[0;5;37;47mX . . t[0;1;30;47mX8[0;1;37;47m%[0;5;37;47m 8[0;1;30;47m88@@@@@@@@[0;5;37;47mt. [0;1;37;47mt[0;5;37;40m8[0;1;30;47m@@@@@%[0;1;37;47m;[0;5;37;47m% . . [0;1;37;47m@[0;5;37;40m8[0;1;30;47m@@@@@@@8%[0;5;37;47m. .. ;[0;1;37;47mt[0;1;30;47m%88t[0;1;37;47m@[0;5;37;47m. .:[0;1;30;47mX8@@@@@@@8[0;1;37;47m8[0;5;37;47m . . .[0m
|
|
7
|
-
[0;5;37;47m . .. 8[0;5;34;44m8[0;1;30;46m8[0;5;37;47m8:. . .[0;1;37;47mX[0;1;31;47m8[0;5;37;47mS . . [0;5;37;40mS[0;34;40m%[0;5;35;40m [0;5;37;47m . . [0;1;30;47m:[0;34;40mS[0;5;30;40m@[0;5;35;40m;[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;35;40m%[0;5;36;40m.[0;5;37;47m S[0;5;35;40mt[0;34;40m%[0;5;37;40m8[0;5;37;47m.. . [0;1;30;47m@[0;34;40mS[0;5;35;40m;[0;5;37;47m@ [0;1;37;47mX[0;1;30;40mX[0;5;30;40m8[0;5;34;40mS[0;5;35;40m:[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;37;47m@ [0;1;30;47m8[0;34;40mS[0;5;30;40mS[0;5;35;40m;[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;34;40mS[0;1;30;40m8[0;5;30;40m8[0;5;35;40m [0;5;37;47mX.. [0;1;30;47m;[0;34;40mS[0;5;30;40mX[0;5;36;40m;[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;36;40m%[0;5;35;40m [0;5;37;47m. ..[0;1;37;47mt[0;5;36;40m [0;5;34;40m@[0;1;30;40m8[0;5;35;40mt[0;5;36;40mt[0;5;35;40mt[0;5;30;40mX8[0;5;34;40m8[0;5;33;40m [0;5;37;47mt. t[0;5;34;40m@[0;1;30;40m@[0;5;34;40mS[0;5;33;40m:[0;5;35;40mt[0;5;36;40m%[0;5;35;40m%[0;5;36;40mt[0;5;35;40mt[0;5;34;40mS[0;1;37;47mt[0;5;37;47m . . [0m
|
|
8
|
-
[0;5;37;47m . . @[0;5;36;44m8[0;34;46m8[0;1;30;47m8[0;5;37;47m8;. :[0;1;37;47mt[0;5;33;41m [0;5;37;43m@[0;5;37;47m8;. . [0;5;37;40m@[0;1;30;40m@[0;5;35;40m [0;5;37;47m . [0;1;30;47m.[0;1;30;40m8[0;5;34;40mS[0;5;37;47mS:;:;:: . [0;1;37;47m8[0;5;32;40mS[0;34;40mS[0;1;30;47m.[0;5;37;47m . . [0;1;37;47m;[0;5;30;40m8@[0;1;37;47m@[0;5;37;47m. [0;1;37;47mX[0;1;30;40m8[0;5;30;40m8[0;1;37;47m@[0;5;37;47m.;:;:;. . [0;1;30;47mX[0;1;30;40m@[0;5;36;40m:[0;5;37;47m;::;.;[0;1;30;47mX[0;1;30;40m8[0;5;35;40mt[0;5;37;47m%. [0;1;30;47m.[0;1;30;40m8[0;5;34;40mS[0;5;37;47mX:;:;:: .%[0;5;35;40m [0;1;30;40m8[0;5;35;40m:[0;1;37;47m:[0;5;37;47mt;:: S[0;1;30;47m [0;1;37;47mS[0;5;37;47m . t[0;5;30;40mS[0;1;30;40mX[0;1;30;47mt[0;5;37;47m.;;:;:. . [0m
|
|
9
|
-
[0;5;37;47m . [0;1;37;47m [0;5;34;44m8[0;1;34;46m8[0;36;44m8[0;1;37;47m;[0;5;37;47m .t[0;5;37;41m8[0;5;33;41m [0;5;33;43m.[0;1;35;47mX[0;5;37;47m:. . [0;5;37;40mX[0;34;40mS[0;5;37;40m@[0;5;37;47m . . [0;1;30;47m:[0;1;30;40mX[0;5;30;40mS[0;5;37;47mt . . . [0;1;30;47mS[0;1;30;40m8[0;5;34;40mS[0;5;37;47mS . :[0;5;36;40m.[0;34;40m%[0;1;30;47mX[0;5;37;47m : [0;1;37;47m@[0;1;30;40m@[0;5;30;40m8[0;1;37;47m8[0;5;37;47m . . . [0;1;30;47m@[0;34;40mS[0;5;35;40m [0;5;37;47m. . [0;1;37;47m8[0;5;30;40m88[0;5;37;47m8 [0;1;30;47m:[0;1;30;40mX[0;5;30;40mS[0;5;37;47m; . .. [0;1;30;47m@[0;1;30;40m@[0;5;34;40m@[0;5;37;47m8.. .... t[0;5;34;40m%[0;1;30;40mS[0;1;30;47m:[0;5;37;47m.. . . . . [0m
|
|
10
|
-
[0;5;37;47m . . . ..[0;1;30;47m8[0;5;36;44m8[0;1;30;46m8[0;5;34;44mS[0;1;30;47mt[0;5;37;47mS[0;1;37;47m [0;5;1;33;41m8[0;5;33;41m:[0;1;37;47m [0;5;37;47m... . . [0;5;37;40m@[0;1;30;40m@[0;5;35;40m [0;5;37;47m .. [0;1;30;47m:[0;1;30;40mX[0;5;30;40m@[0;5;36;40m [0;5;35;40m [0;5;36;40m [0;5;37;47mt ..%[0;5;35;40m;[0;32;40mt[0;1;30;47m@[0;5;37;47m.. [0;1;30;47m;[0;1;30;40m@[0;5;35;40m.[0;5;37;47mS . [0;1;37;47mX[0;1;30;40m8[0;5;34;40m8[0;5;33;40m;[0;5;35;40m.[0;5;36;40m [0;5;35;40m .[0;1;37;47m8[0;5;37;47m : [0;1;30;47mX[0;1;30;40m@[0;5;35;40m.[0;5;37;47m: ...t[0;1;30;47m8[0;34;40mX[0;5;36;40m.[0;5;37;47mt. [0;1;30;47m:[0;1;30;40m@[0;5;30;40m@[0;5;35;40m [0;5;37;47mS .[0;5;35;40m.[0;34;40mS[0;5;37;40m8[0;5;37;47m.. . %X; t[0;5;30;40mX[0;1;30;40m8[0;5;36;40m;[0;5;35;40m.[0;5;36;40m .[0;1;30;47m [0;5;37;47m . . . [0m
|
|
11
|
-
[0;5;37;47m . . t[0;36;47m8[0;5;34;44m8[0;1;30;46m8[0;5;36;44m8[0;5;36;40mX[0;1;37;47m [0;5;37;47m%8t . .. [0;5;37;40m@[0;34;40mS[0;5;37;40mX[0;5;37;47m . . [0;1;30;47m:[0;1;30;40mX[0;5;34;40mX[0;1;30;47m [0;1;37;47m;;;;:t[0;5;37;47m: ..[0;1;37;47m8[0;5;34;40mS[0;1;30;40m@[0;1;37;47m:[0;5;37;47m.[0;1;37;47mX[0;5;30;40m88[0;1;37;47m8[0;5;37;47m .. [0;1;37;47mX[0;1;30;40m88[0;1;30;47mS[0;1;37;47m::;;;.[0;5;37;47m% . [0;1;30;47m@[0;1;30;40mX[0;5;34;40m@[0;5;33;40m%[0;5;34;40mS[0;5;33;40m;[0;5;35;40m%[0;5;36;40mX[0;1;30;40m8[0;5;30;40mX[0;5;37;40m@[0;5;37;47mX . [0;1;30;47m:[0;34;40m@[0;5;33;40mt[0;1;30;47m;[0;1;37;47m;;;;:;[0;5;37;47m;. [0;5;37;40m%[0;1;30;40m@[0;5;33;40m [0;5;37;47m.. .. [0;5;36;40m [0;34;40m%[0;1;37;47mt[0;5;37;47m. t[0;5;34;40m%[0;1;30;40mX[0;5;37;40m8[0;1;37;47m;:;;; [0;5;37;47m8.. . [0m
|
|
12
|
-
[0;5;37;47m . . . .:8[0;1;30;46m8[0;5;34;44mX[0;5;36;40mt[0;5;34;44mt[0;34;46m8[0;1;30;47m8[0;5;37;47m . . [0;5;37;40m@[0;1;30;40mX[0;5;35;40m [0;5;37;47m ..... [0;1;30;47m:[0;1;30;40mX[0;5;34;40mS[0;5;37;47mS..:..:.. . [0;1;30;47m@[0;1;30;40mX[0;5;35;40m;[0;5;37;47m:[0;5;35;40m [0;34;40mS[0;1;30;47mS[0;5;37;47m . . [0;1;37;47mX[0;1;30;40m8[0;5;30;40m8[0;1;37;47m@[0;5;37;47m ::.:.. . [0;1;30;47m@[0;1;30;40mX[0;5;30;40mX[0;1;30;47m@X@@[0;5;30;40mS[0;1;30;40m@[0;1;30;47mt[0;5;37;47m ... [0;1;30;47m.[0;1;30;40m@[0;5;34;40m@[0;5;37;47mS ::..:.. [0;1;37;47m;[0;1;30;40m88[0;1;30;47mt[0;5;37;47m ..... [0;5;37;40mS[0;1;30;40mX[0;1;37;47m:[0;5;37;47m t[0;5;30;40mS[0;1;30;40mX[0;1;30;47m;[0;5;37;47m ::.:... . [0m
|
|
13
|
-
[0;5;37;47m . . [0;1;37;47m:[0;1;34;46m8[0;1;30;46m8[0;1;34;46m8[0;1;30;45m8[0;5;37;47m% . . [0;5;37;40m@[0;1;30;40mX[0;5;35;40m [0;5;37;47mS8@@8@: [0;1;30;47m:[0;1;30;40mX[0;5;30;40mS[0;1;37;47m8[0;5;37;47mX@X@X@X: . %[0;5;35;40m;[0;1;30;40m8[0;5;36;40m [0;5;34;40m@[0;5;33;40m%[0;5;37;47mX . . [0;1;37;47m@[0;1;30;40m8[0;5;34;40m8[0;1;37;47m:[0;5;37;47mS@X@X@@;. [0;1;30;47m@[0;34;40mX[0;5;36;40m [0;5;37;47m. ..[0;1;37;47m8[0;5;34;40mX[0;1;30;40m8[0;1;30;47m;[0;5;37;47m .. [0;1;30;47m:[0;1;30;40mX[0;5;30;40mS[0;1;37;47m8[0;5;37;47mS@X@X@@: [0;1;30;47mt[0;5;30;40m88[0;5;36;40m [0;1;37;47mt[0;5;37;47m8%S[0;1;37;47m8:[0;5;36;40m;[0;34;40mt[0;1;37;47m:[0;5;37;47m t[0;5;34;40m%[0;1;30;40mX[0;1;30;47mS[0;5;37;47mX@@X@X@% . . [0m
|
|
14
|
-
[0;5;37;47m . . . . . [0;1;37;47m:[0;5;34;44mX[0;1;30;47m8[0;5;37;47m@.: . . [0;5;37;40m8[0;5;30;40m8[0;5;34;40mX[0;5;30;40m8@8[0;5;34;40m8[0;5;30;40m8S[0;5;37;47mS [0;1;30;47m.[0;5;30;40m8[0;5;34;40m@[0;5;30;40m@88[0;5;34;40m8[0;5;30;40m8@[0;5;34;40m8[0;5;30;40m8[0;5;37;47m8.. ..[0;1;37;47m8[0;5;34;40mS[0;5;30;40m@X[0;1;37;47m8[0;5;37;47m . . [0;1;37;47m@[0;5;30;40m8@@[0;5;34;40m8[0;5;30;40m88[0;5;34;40m8[0;5;30;40m8[0;5;34;40m@[0;1;30;40m8[0;1;37;47m;[0;5;37;47m [0;1;30;47mS[0;5;30;40m8[0;5;36;40m [0;5;37;47m. . .@[0;5;35;40m.[0;5;30;40m8[0;5;37;40mS[0;5;37;47mt. [0;1;30;47m.[0;5;30;40m8[0;5;34;40m@[0;5;30;40m88[0;5;34;40m8[0;5;30;40m88[0;5;34;40m8[0;5;30;40m88[0;5;37;47m8...%[0;1;37;47m [0;5;37;40mS[0;5;36;40m%[0;5;30;40m888[0;5;34;40mX[0;5;33;40mt[0;5;37;40m@[0;1;37;47mt[0;5;37;47m; .;[0;5;33;40m%[0;5;30;40m8[0;5;34;40m8[0;5;30;40m88[0;5;34;40m8[0;5;30;40m88[0;5;34;40m@[0;1;30;40m@[0;1;30;47m8[0;5;37;47m . . .[0m
|
|
15
|
-
[0;5;37;47m . [0;36;47m8[0;1;37;47m [0;5;37;47m:.. .;;:::;::. :;;::::;:;:. .:;. .;:;::;::::. .;: . .:;: :;:::::::::: . ..:t;:: . :%;;:::::::. . [0m
|
|
16
|
-
[0;5;37;47m . . . . . X% . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . .. . . . [0m
|
|
17
|
-
[0;5;37;47m . .. . . . . . . . . . . . . . . . . . . . . . . . .[0m`;
|