-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConfig.ts
More file actions
198 lines (150 loc) · 4.95 KB
/
Config.ts
File metadata and controls
198 lines (150 loc) · 4.95 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import merge from 'lodash.merge';
import Base from '../base/Base';
import Formatter from './Formatter';
export namespace ConfigSpace {
export type Config = {
formatter: Formatter;
sources: any[];
variables: { [key: string]: any };
};
export type Source = { [key: string]: any };
export type Options = { [key: string]: any };
export type Registry = {
username: string;
host: string;
path: string;
password: string;
};
export type Public = {
// tool to do publishing processing
// only nginx currently supported
tool: 'nginx';
// path to web site configuration file
// for nginx it is can be `/etc/nginx/sites`
directory: string;
// path to web site credentials file
// where to store .htaccess files
credentials: string;
// server name property
// domain or ip
name: string;
// listen to this port
// for passed server name
port: string;
// restart tool after successful configuration
restart: boolean;
};
export type Access = {
// whether to restrict access or not
// with the basic auth functionality
restrict: boolean;
// http basic auth credentials list to pass
credentials: { [key: string]: string };
};
export type Proxy = {
// location block match value
// by default it is '/'
location?: string;
// where to proxy requests from the internet
// for the configured web site
// for docker it should be localhost
name: string;
// port where to proxy requests
// usually `-p` property value from `docker run`
port: string;
};
export type Ssl = {
// restart publishing tool after successful configuration
restart: boolean;
};
export type Parsed = {
// deploy scenario
as: 'image' | 'source' | 'registry';
// credentials user
user: string;
// credentials password
password: string;
// path to custom config file
config?: string;
// remote server host as `user@your-domain.com`
host: string;
// base code to attach to the containers like `my-lovely-container`
code: string;
// release code to attach to the containers like commit hash or `latest`
release: string;
// composed tag from `code` and `release` like `my-lovely-container:latest`
tag: string;
// registry configuration
registry: Registry;
// docker image build `docker build` options
image: Options;
// docker image container `docker run` options
container: Options;
// certbot configuration to configure ssl generation tool
certbot: Options;
// public configuration to expose container to the internet
// via publishing tool like `nginx`
public: Public;
// internal configuration to proxy requests from the internet
// to the locally running docker container
proxy: Proxy | Proxy[];
// ssl configuration for the published site
ssl: Ssl;
// auth configuration for the published site
access: Access;
// source directory
source: string;
// database engine
engine: string;
// database name
database: string;
};
}
export default class Config<C = {}> extends Base<C & ConfigSpace.Config> {
private _parsed?: ConfigSpace.Parsed;
public get base() {
return {} as ConfigSpace.Parsed;
}
public get parsed(): ConfigSpace.Parsed {
if (!this._parsed) {
// merge configuration sources
this._parsed = this.processSources(this.config.sources);
// replace environment variables
this._parsed = this.processVariables(this._parsed, this.config.variables);
if (!this._parsed) {
throw new Error('Unable to parse the configuration file');
}
}
return this._parsed;
}
public processSources(sources: any[]): ConfigSpace.Parsed {
// merge configuration defaults
const convert = this.config.formatter.convertObjectPropertiesFromOptionToCamel.bind(this.config.formatter);
const parts = sources.map((source) => source ? convert(source) : {});
const merged = merge({}, this.base, ...parts);
// extract legacy configuration structure
const legacy = merge({}, (merged.default || {}), ...Object.values(merged.commands || {}));
delete merged.default;
delete merged.commands;
// merge brand new configuration structure with legacy one
return merge({}, merged, legacy);
}
public processVariables(value: any, variables: { [key: string]: any }) {
if (typeof value === 'object') {
const result: any = value instanceof Array ? [] : {};
for (const key in value) {
if (value.hasOwnProperty(key)) {
result[key] = this.processVariables(value[key], variables);
}
}
return result;
} else if (typeof value === 'string') {
return value.replace(/\${[a-z-_]+}/ig, (matched) => {
const name = matched.replace(/^\${(.*?)}$/, '$1');
const value = variables[name] || matched;
return value.replace(/\n/g, '\n');
});
}
return value;
}
};