This repository has been archived by the owner on Nov 14, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
compile.ts
103 lines (94 loc) · 3.99 KB
/
compile.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import {flags} from '@oclif/command'
import {existsSync, readFileSync} from 'fs'
import {Credential} from 'mesg-js/lib/api'
import {hash} from 'mesg-js/lib/api/types'
import {dirname, join} from 'path'
import {WithCredential as Command} from '../../credential-command'
import * as compile from '../../utils/compiler'
import {IsAlreadyExistsError} from '../../utils/error'
import ServiceCompile from '../service/compile'
export default class ProcessCompile extends Command {
static description = 'Compile a process'
static flags = {
...Command.flags,
dev: flags.boolean({description: 'compile the process and automatically deploy and start all the services'}),
env: flags.string({
description: 'Set environment variables',
multiple: true,
helpValue: 'FOO=BAR'
})
}
static args = [{
name: 'PROCESS_FILE',
description: 'Path of a process file'
}]
private _credentials: Credential | null = null
async run(): Promise<any> {
const {args, flags} = this.parse(ProcessCompile)
const definition = await compile.process(readFileSync(args.PROCESS_FILE), async (instanceObject: any) => {
if (instanceObject.instanceHash) {
return instanceObject.instanceHash
}
if (!flags.dev) {
throw new Error('"instanceHash" should be present in your process. Use `--dev` to be able to use the "instance" attributes.')
}
if (!instanceObject.instance) {
throw new Error('"instanceHash" or "instance" not found in the process\'s definition')
}
const {service, src, env} = instanceObject.instance
if (service) {
return this.serviceToInstance(service, env)
}
if (src) {
return this.sourceToInstance(args.PROCESS_FILE, src, env, flags)
}
throw new Error('at least one of the following parameter should be set: "instanceHash", "service" or "src"')
}, (flags.env || []).reduce((prev, env) => ({
...prev,
[env.split('=')[0]]: env.split('=')[1],
}), {}))
this.styledJSON(definition)
this.spinner.stop()
return definition
}
async sourceToInstance(dir: string, src: string, env: string[], flags: any): Promise<hash> {
const directory = join(dirname(dir), src)
const definition = await ServiceCompile.run([existsSync(directory) ? directory : src, '--silent', ...this.flagsAsArgs(flags)])
const {hash} = await this.api.service.hash(definition)
if (!hash) throw new Error('invalid hash')
const {exists} = await this.api.service.exists({hash})
if (!exists) {
const resp = await this.api.service.create(definition, await this.credentials())
if (!resp.hash) throw new Error('invalid hash')
if (resp.hash.toString() !== hash.toString()) throw new Error('invalid hash')
}
return this.serviceToInstance(hash, env)
}
async serviceToInstance(sidOrHash: hash | string, env: string[]): Promise<hash> {
const {services} = await this.api.service.list({})
if (!services) throw new Error('no services deployed, please deploy your service first')
const sidOrHashStr = sidOrHash.toString()
const match = services.filter(x => x.hash && x.hash.toString() === sidOrHashStr || x.sid && x.sid.toString() === sidOrHashStr)
if (!match || match.length === 0) throw new Error(`cannot find any service with the following: ${sidOrHashStr}`)
if (match.length > 1) throw new Error(`multiple services match the following sid: ${sidOrHashStr}, provide a service's hash instead`)
const service = match[0]
if (!service.hash) throw new Error('invalid service')
try {
const resp = await this.api.instance.create({
serviceHash: service.hash,
env,
})
if (!resp.hash) throw new Error('invalid hash')
return resp.hash
} catch (e) {
if (!IsAlreadyExistsError.match(e)) throw e
return new IsAlreadyExistsError(e).hash
}
}
private async credentials(): Promise<Credential> {
if (!this._credentials) {
this._credentials = await this.getCredential()
}
return this._credentials
}
}