@wocker/ws 1.0.2 → 1.0.3

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.
Files changed (100) hide show
  1. package/README.md +1 -1
  2. package/lib/App.d.ts +4 -3
  3. package/lib/App.js +98 -77
  4. package/lib/controllers/ImageController.d.ts +2 -2
  5. package/lib/controllers/ImageController.js +27 -27
  6. package/lib/controllers/PluginController.d.ts +2 -2
  7. package/lib/controllers/PluginController.js +78 -56
  8. package/lib/controllers/PresetController.d.ts +3 -1
  9. package/lib/controllers/PresetController.js +155 -136
  10. package/lib/controllers/ProjectController.d.ts +5 -5
  11. package/lib/controllers/ProjectController.js +653 -603
  12. package/lib/controllers/ProxyController.d.ts +4 -1
  13. package/lib/controllers/ProxyController.js +269 -245
  14. package/lib/controllers/index.js +19 -58
  15. package/lib/env.js +33 -15
  16. package/lib/index.d.ts +2 -0
  17. package/lib/index.js +30 -16
  18. package/lib/makes/Controller.js +4 -8
  19. package/lib/makes/DI.d.ts +7 -0
  20. package/lib/makes/DI.js +27 -0
  21. package/lib/makes/Docker.js +298 -382
  22. package/lib/makes/FS.js +328 -304
  23. package/lib/makes/LineConvertStream.js +37 -40
  24. package/lib/makes/Logger.d.ts +9 -1
  25. package/lib/makes/Logger.js +22 -11
  26. package/lib/makes/Model.js +8 -12
  27. package/lib/makes/MySQL.js +6 -27
  28. package/lib/makes/Plugin.d.ts +1 -1
  29. package/lib/makes/Plugin.js +55 -37
  30. package/lib/makes/Preset.d.ts +46 -0
  31. package/lib/makes/Preset.js +33 -0
  32. package/lib/makes/Project.d.ts +45 -0
  33. package/lib/makes/Project.js +127 -0
  34. package/lib/makes/Repository.js +18 -21
  35. package/lib/makes/index.d.ts +3 -0
  36. package/lib/makes/index.js +23 -69
  37. package/lib/plugins/ElasticSearchPlugin.d.ts +3 -1
  38. package/lib/plugins/ElasticSearchPlugin.js +66 -66
  39. package/lib/plugins/LocaltunnelPlugin.d.ts +2 -2
  40. package/lib/plugins/LocaltunnelPlugin.js +256 -257
  41. package/lib/plugins/MaildevPlugin.d.ts +2 -2
  42. package/lib/plugins/MaildevPlugin.js +45 -44
  43. package/lib/plugins/MongodbPlugin.d.ts +2 -2
  44. package/lib/plugins/MongodbPlugin.js +303 -248
  45. package/lib/plugins/NgrokPlugin.d.ts +2 -2
  46. package/lib/plugins/NgrokPlugin.js +221 -231
  47. package/lib/plugins/PageKitePlugin.d.ts +2 -2
  48. package/lib/plugins/PageKitePlugin.js +150 -149
  49. package/lib/plugins/PostgresPlugin.d.ts +1 -1
  50. package/lib/plugins/PostgresPlugin.js +115 -89
  51. package/lib/plugins/ProxmoxPlugin.d.ts +1 -1
  52. package/lib/plugins/ProxmoxPlugin.js +50 -38
  53. package/lib/plugins/RedisPlugin.d.ts +3 -1
  54. package/lib/plugins/RedisPlugin.js +73 -72
  55. package/lib/plugins/index.js +25 -103
  56. package/lib/services/AppConfigService.d.ts +3 -3
  57. package/lib/services/AppConfigService.js +162 -157
  58. package/lib/services/AppEventsService.js +26 -24
  59. package/lib/services/DockerService.d.ts +37 -2
  60. package/lib/services/DockerService.js +185 -205
  61. package/lib/services/LogService.d.ts +3 -2
  62. package/lib/services/LogService.js +33 -34
  63. package/lib/services/PluginService.d.ts +2 -1
  64. package/lib/services/PluginService.js +11 -14
  65. package/lib/services/PresetService.d.ts +8 -3
  66. package/lib/services/PresetService.js +60 -59
  67. package/lib/services/ProjectService.d.ts +11 -4
  68. package/lib/services/ProjectService.js +140 -129
  69. package/lib/services/index.js +21 -80
  70. package/lib/types/Config.d.ts +4 -3
  71. package/lib/types/Config.js +1 -4
  72. package/lib/types/EnvConfig.js +1 -4
  73. package/lib/types/index.js +16 -25
  74. package/lib/utils/buildOptions.js +5 -8
  75. package/lib/utils/demuxOutput.js +16 -20
  76. package/lib/utils/escapeRegExp.js +4 -7
  77. package/lib/utils/exec.js +38 -39
  78. package/lib/utils/fetch.js +46 -30
  79. package/lib/utils/followProgress.js +66 -77
  80. package/lib/utils/format-size-units.js +16 -16
  81. package/lib/utils/get-config.d.ts +1 -1
  82. package/lib/utils/get-config.js +13 -16
  83. package/lib/utils/get-cursor-position.js +22 -29
  84. package/lib/utils/image-build.js +35 -23
  85. package/lib/utils/index.js +32 -191
  86. package/lib/utils/injectVariables.js +10 -13
  87. package/lib/utils/parse-table.js +20 -23
  88. package/lib/utils/set-config.d.ts +1 -1
  89. package/lib/utils/set-config.js +12 -15
  90. package/lib/utils/spawn.js +17 -20
  91. package/lib/utils/tty.js +2 -6
  92. package/lib/utils/volumeFormat.js +5 -12
  93. package/lib/utils/volumeParse.js +10 -13
  94. package/package.json +13 -39
  95. package/presets/bun/Dockerfile +11 -0
  96. package/presets/bun/config.json +3 -0
  97. package/presets/node/Dockerfile +4 -2
  98. package/presets/php-apache/Dockerfile +3 -2
  99. package/.github/workflows/publish.yml +0 -31
  100. package/plugins/mariadb/admin/conf/config.user.inc.php +0 -9
@@ -1,628 +1,678 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
5
17
  });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.ProjectController = void 0;
7
- var _core = require("@wocker/core");
8
- var _utils = require("@wocker/utils");
9
- var _cliTable = _interopRequireDefault(require("cli-table3"));
10
- var _chalk = _interopRequireDefault(require("chalk"));
11
- var Path = _interopRequireWildcard(require("path"));
12
- var _asyncMutex = require("async-mutex");
13
- var _env = require("../env");
14
- var _makes = require("../makes");
15
- var _utils2 = require("../utils");
16
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
17
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
- class ProjectController extends _makes.Controller {
20
- constructor(di) {
21
- super();
22
- this.di = di;
23
- this.appConfigService = this.di.resolveService(_core.AppConfigService);
24
- this.appEventsService = this.di.resolveService(_core.AppEventsService);
25
- this.projectService = this.di.resolveService(_core.ProjectService);
26
- this.dockerService = this.di.resolveService(_core.DockerService);
27
- }
28
- install(cli) {
29
- super.install(cli);
30
- cli.command("init").help({
31
- description: "Init project"
32
- }).option("name", {
33
- type: "string",
34
- description: "Ім'я контейнеру",
35
- alias: "n"
36
- }).option("type", {
37
- type: "string",
38
- description: "Тип запуску контейнеру"
39
- }).completion("type", () => {
40
- return [];
41
- }).option("preset", {
42
- type: "string",
43
- description: "Preset",
44
- default: ""
45
- }).action(options => this.init(options));
46
- cli.command("ps").option("all", {
47
- type: "boolean",
48
- alias: "a",
49
- description: "All projects"
50
- }).action(options => this.projectList(options));
51
- cli.command("start").help({
52
- description: "Run project"
53
- }).option("name", {
54
- type: "string",
55
- alias: "n"
56
- }).completion("name", () => this.getProjectNames()).option("rebuild", {
57
- type: "boolean",
58
- alias: "r"
59
- }).option("detach", {
60
- type: "boolean",
61
- alias: "d"
62
- }).action(options => this.start(options));
63
- cli.command("stop").option("name", {
64
- type: "string",
65
- alias: "n"
66
- }).completion("name", () => this.getProjectNames()).action(options => this.stop(options));
67
- cli.command("run <script>").completion("script", options => this.getScripts()).action((options, script) => this.run(script));
68
- cli.command("attach").option("name", {
69
- type: "string",
70
- alias: "n"
71
- }).completion("name", () => this.getProjectNames()).action(options => this.attach(options));
72
- cli.command("config").option("name", {
73
- type: "string",
74
- alias: "n"
75
- }).completion("name", () => this.getProjectNames()).option("global", {
76
- type: "boolean",
77
- alias: "g"
78
- }).action(options => this.configList(options));
79
- cli.command("config:get <key>").help({
80
- description: "Get project env variable"
81
- }).option("global", {
82
- alias: "g",
83
- description: "Global"
84
- }).option("name", {
85
- type: "string",
86
- alias: "n"
87
- }).completion("name", () => this.getProjectNames()).action((options, key) => this.configGet(options, key));
88
- cli.command("config:set [...configs]").option("name", {
89
- type: "string",
90
- alias: "n"
91
- }).option("global", {
92
- type: "boolean",
93
- alias: "g"
94
- }).completion("name", () => this.getProjectNames()).action((options, configs) => this.configSet(options, configs));
95
- cli.command("config:unset [...configs]").option("name", {
96
- type: "string",
97
- alias: "n"
98
- }).completion("name", () => this.getProjectNames()).option("global", {
99
- type: "boolean",
100
- alias: "g"
101
- }).action((options, configs) => this.configUnset(options, configs));
102
- cli.command("build-args").option("name", {
103
- type: "string",
104
- alias: "n"
105
- }).completion("name", () => this.getProjectNames()).action(options => this.buildArgsList(options));
106
- cli.command("build-args:get [...buildArgs]").option("name", {
107
- type: "string",
108
- alias: "n"
109
- }).completion("name", () => this.getProjectNames()).action((options, buildArgs) => this.buildArgsGet(options, buildArgs));
110
- cli.command("build-args:set [...buildArgs]").option("name", {
111
- type: "string",
112
- alias: "n"
113
- }).completion("name", () => this.getProjectNames()).action((options, buildArgs) => this.buildArgsSet(options, buildArgs));
114
- cli.command("build-args:unset [...buildArgs]").option("name", {
115
- type: "string",
116
- alias: "n"
117
- }).completion("name", () => this.getProjectNames()).action((options, buildArgs) => this.buildArgsUnset(options, buildArgs));
118
- cli.command("volumes").option("name", {
119
- type: "string",
120
- alias: "n"
121
- }).completion("name", () => this.getProjectNames()).action(options => this.volumeList(options));
122
- cli.command("volume:mount <...volumes>").option("name", {
123
- type: "string",
124
- alias: "n"
125
- }).completion("name", () => this.getProjectNames()).action((options, volumes) => this.volumeMount(options, volumes));
126
- cli.command("volume:unmount <...volumes>").option("name", {
127
- type: "string",
128
- alias: "n"
129
- }).completion("name", () => this.getProjectNames()).action((options, volumes) => this.volumeUnmount(options, volumes));
130
- cli.command("logs").help({
131
- description: "Logs"
132
- }).option("name", {
133
- type: "boolean",
134
- alias: "n"
135
- }).option("global", {
136
- type: "boolean",
137
- alias: "g"
138
- }).option("follow", {
139
- type: "boolean",
140
- alias: "f"
141
- }).option("detach", {
142
- type: "boolean",
143
- alias: "d"
144
- }).completion("name", () => this.getProjectNames()).action(options => this.logs(options));
145
- cli.command("exec [...command]").option("name", {
146
- type: "string",
147
- alias: "n"
148
- }).completion("name", () => this.getProjectNames()).action((options, command) => this.exec(options, command));
149
- }
150
- async getProjectNames() {
151
- const projects = await _core.Project.search();
152
- return projects.map(project => {
153
- return project.name;
154
- });
155
- }
156
- async getScripts() {
157
- try {
158
- const project = await this.projectService.get();
159
- return Object.keys(project.scripts || {});
160
- } catch (ignore) {
161
- return [];
162
- }
163
- }
164
- async init(options) {
165
- let project = await _core.Project.searchOne({
166
- path: this.appConfigService.getPWD()
167
- });
168
- if (!project) {
169
- project = new _core.Project({});
170
- }
171
- if (options.name) {
172
- project.name = options.name;
173
- }
174
- if (!options.name || !project.name) {
175
- project.name = await (0, _utils.promptText)({
176
- type: "string",
177
- required: true,
178
- message: "Project name",
179
- default: project.name
180
- });
181
- }
182
- if (options.type) {
183
- project.type = options.type;
30
+ const utils_1 = require("@wocker/utils");
31
+ const cli_table3_1 = __importDefault(require("cli-table3"));
32
+ const chalk_1 = __importDefault(require("chalk"));
33
+ const Path = __importStar(require("path"));
34
+ const async_mutex_1 = require("async-mutex");
35
+ const env_1 = require("../env");
36
+ const makes_1 = require("../makes");
37
+ const makes_2 = require("../makes");
38
+ const services_1 = require("../services");
39
+ const utils_2 = require("../utils");
40
+ class ProjectController extends makes_1.Controller {
41
+ constructor(di) {
42
+ super();
43
+ this.di = di;
44
+ this.appConfigService = this.di.resolveService(services_1.AppConfigService);
45
+ this.appEventsService = this.di.resolveService(services_1.AppEventsService);
46
+ this.projectService = this.di.resolveService(services_1.ProjectService);
47
+ this.dockerService = this.di.resolveService(services_1.DockerService);
48
+ }
49
+ install(cli) {
50
+ super.install(cli);
51
+ cli.command("init")
52
+ .help({
53
+ description: "Init project"
54
+ })
55
+ .option("name", {
56
+ type: "string",
57
+ description: "Ім'я контейнеру",
58
+ alias: "n"
59
+ })
60
+ .option("type", {
61
+ type: "string",
62
+ description: "Тип запуску контейнеру"
63
+ })
64
+ .completion("type", () => {
65
+ return [];
66
+ })
67
+ .option("preset", {
68
+ type: "string",
69
+ description: "Preset",
70
+ default: ""
71
+ })
72
+ .action((options) => this.init(options));
73
+ cli.command("ps")
74
+ .option("all", {
75
+ type: "boolean",
76
+ alias: "a",
77
+ description: "All projects"
78
+ })
79
+ .action((options) => this.projectList(options));
80
+ cli.command("start")
81
+ .help({
82
+ description: "Run project"
83
+ })
84
+ .option("name", {
85
+ type: "string",
86
+ alias: "n"
87
+ })
88
+ .completion("name", () => this.getProjectNames())
89
+ .option("rebuild", {
90
+ type: "boolean",
91
+ alias: "r"
92
+ })
93
+ .option("detach", {
94
+ type: "boolean",
95
+ alias: "d"
96
+ })
97
+ .action((options) => this.start(options));
98
+ cli.command("stop")
99
+ .option("name", {
100
+ type: "string",
101
+ alias: "n"
102
+ })
103
+ .completion("name", () => this.getProjectNames())
104
+ .action((options) => this.stop(options));
105
+ cli.command("run <script>")
106
+ .completion("script", (options) => this.getScripts())
107
+ .action((options, script) => this.run(script));
108
+ cli.command("attach")
109
+ .option("name", {
110
+ type: "string",
111
+ alias: "n"
112
+ })
113
+ .completion("name", () => this.getProjectNames())
114
+ .action((options) => this.attach(options));
115
+ cli.command("config")
116
+ .option("name", {
117
+ type: "string",
118
+ alias: "n"
119
+ })
120
+ .completion("name", () => this.getProjectNames())
121
+ .option("global", {
122
+ type: "boolean",
123
+ alias: "g"
124
+ })
125
+ .action((options) => this.configList(options));
126
+ cli.command("config:get <key>")
127
+ .help({
128
+ description: "Get project env variable"
129
+ })
130
+ .option("global", {
131
+ alias: "g",
132
+ description: "Global"
133
+ })
134
+ .option("name", {
135
+ type: "string",
136
+ alias: "n"
137
+ })
138
+ .completion("name", () => this.getProjectNames())
139
+ .action((options, key) => this.configGet(options, key));
140
+ cli.command("config:set [...configs]")
141
+ .option("name", {
142
+ type: "string",
143
+ alias: "n"
144
+ })
145
+ .option("global", {
146
+ type: "boolean",
147
+ alias: "g"
148
+ })
149
+ .completion("name", () => this.getProjectNames())
150
+ .action((options, configs) => this.configSet(options, configs));
151
+ cli.command("config:unset [...configs]")
152
+ .option("name", {
153
+ type: "string",
154
+ alias: "n"
155
+ })
156
+ .completion("name", () => this.getProjectNames())
157
+ .option("global", {
158
+ type: "boolean",
159
+ alias: "g"
160
+ })
161
+ .action((options, configs) => this.configUnset(options, configs));
162
+ cli.command("build-args")
163
+ .option("name", {
164
+ type: "string",
165
+ alias: "n"
166
+ })
167
+ .completion("name", () => this.getProjectNames())
168
+ .action((options) => this.buildArgsList(options));
169
+ cli.command("build-args:get [...buildArgs]")
170
+ .option("name", {
171
+ type: "string",
172
+ alias: "n"
173
+ })
174
+ .completion("name", () => this.getProjectNames())
175
+ .action((options, buildArgs) => this.buildArgsGet(options, buildArgs));
176
+ cli.command("build-args:set [...buildArgs]")
177
+ .option("name", {
178
+ type: "string",
179
+ alias: "n"
180
+ })
181
+ .completion("name", () => this.getProjectNames())
182
+ .action((options, buildArgs) => this.buildArgsSet(options, buildArgs));
183
+ cli.command("build-args:unset [...buildArgs]")
184
+ .option("name", {
185
+ type: "string",
186
+ alias: "n"
187
+ })
188
+ .completion("name", () => this.getProjectNames())
189
+ .action((options, buildArgs) => this.buildArgsUnset(options, buildArgs));
190
+ cli.command("volumes")
191
+ .option("name", {
192
+ type: "string",
193
+ alias: "n"
194
+ })
195
+ .completion("name", () => this.getProjectNames())
196
+ .action((options) => this.volumeList(options));
197
+ cli.command("volume:mount [...volumes]")
198
+ .option("name", {
199
+ type: "string",
200
+ alias: "n"
201
+ })
202
+ .completion("name", () => this.getProjectNames())
203
+ .action((options, volumes) => this.volumeMount(options, volumes));
204
+ cli.command("volume:unmount [...volumes]")
205
+ .option("name", {
206
+ type: "string",
207
+ alias: "n"
208
+ })
209
+ .completion("name", () => this.getProjectNames())
210
+ .action((options, volumes) => this.volumeUnmount(options, volumes));
211
+ cli.command("logs")
212
+ .help({
213
+ description: "Logs"
214
+ })
215
+ .option("name", {
216
+ type: "boolean",
217
+ alias: "n"
218
+ })
219
+ .option("global", {
220
+ type: "boolean",
221
+ alias: "g"
222
+ })
223
+ .option("follow", {
224
+ type: "boolean",
225
+ alias: "f"
226
+ })
227
+ .option("detach", {
228
+ type: "boolean",
229
+ alias: "d"
230
+ })
231
+ .completion("name", () => this.getProjectNames())
232
+ .action((options) => this.logs(options));
233
+ cli.command("exec [...command]")
234
+ .option("name", {
235
+ type: "string",
236
+ alias: "n"
237
+ })
238
+ .completion("name", () => this.getProjectNames())
239
+ .action((options, command) => this.exec(options, command));
240
+ }
241
+ async getProjectNames() {
242
+ const projects = await makes_2.Project.search();
243
+ return projects.map((project) => {
244
+ return project.name;
245
+ });
184
246
  }
185
- const mapTypes = this.appConfigService.getProjectTypes();
186
- if (!options.type || !project.type || !mapTypes[project.type]) {
187
- project.type = await (0, _utils.promptSelect)({
188
- message: "Project type",
189
- options: mapTypes,
190
- default: project.type
191
- });
247
+ async getScripts() {
248
+ try {
249
+ const project = await this.projectService.get();
250
+ return Object.keys(project.scripts || {});
251
+ }
252
+ catch (ignore) {
253
+ return [];
254
+ }
192
255
  }
193
- switch (project.type) {
194
- case _core.PROJECT_TYPE_DOCKERFILE:
195
- {
196
- const files = await _makes.FS.readdirFiles(this.appConfigService.getPWD());
197
- const dockerfiles = files.filter(fileName => {
198
- if (new RegExp("^(.*)\\.dockerfile$").test(fileName)) {
199
- return true;
256
+ async init(options) {
257
+ let project = await makes_2.Project.searchOne({
258
+ path: this.appConfigService.getPWD()
259
+ });
260
+ if (!project) {
261
+ project = new makes_2.Project({});
262
+ }
263
+ if (options.name) {
264
+ project.name = options.name;
265
+ }
266
+ if (!options.name || !project.name) {
267
+ project.name = await (0, utils_1.promptText)({
268
+ type: "string",
269
+ required: true,
270
+ message: "Project name",
271
+ default: project.name
272
+ });
273
+ }
274
+ if (options.type) {
275
+ project.type = options.type;
276
+ }
277
+ const mapTypes = this.appConfigService.getProjectTypes();
278
+ if (!options.type || !project.type || !mapTypes[project.type]) {
279
+ project.type = await (0, utils_1.promptSelect)({
280
+ message: "Project type",
281
+ options: mapTypes,
282
+ default: project.type
283
+ });
284
+ }
285
+ switch (project.type) {
286
+ case makes_2.PROJECT_TYPE_DOCKERFILE: {
287
+ const files = await makes_1.FS.readdirFiles(this.appConfigService.getPWD());
288
+ const dockerfiles = files.filter((fileName) => {
289
+ if (new RegExp("^(.*)\\.dockerfile$").test(fileName)) {
290
+ return true;
291
+ }
292
+ return new RegExp("^Dockerfile(\\..*)?").test(fileName);
293
+ });
294
+ project.dockerfile = await (0, utils_1.promptSelect)({
295
+ options: dockerfiles.map((dockerfile) => {
296
+ return {
297
+ value: dockerfile
298
+ };
299
+ }),
300
+ message: "Dockerfile",
301
+ default: project.dockerfile
302
+ });
303
+ break;
200
304
  }
201
- return new RegExp("^Dockerfile(\\..*)?").test(fileName);
202
- });
203
- project.dockerfile = await (0, _utils.promptSelect)({
204
- options: dockerfiles.map(dockerfile => {
205
- return {
206
- value: dockerfile
207
- };
208
- }),
209
- message: "Dockerfile",
210
- default: project.dockerfile
211
- });
212
- break;
213
- }
214
- case _core.PROJECT_TYPE_IMAGE:
215
- {
216
- project.imageName = await (0, _utils.promptText)({
217
- message: "Image Name",
218
- default: project.imageName
219
- });
220
- break;
221
- }
222
- default:
223
- break;
224
- }
225
- await this.appEventsService.emit("project:init", project);
226
- project.path = this.appConfigService.getPWD();
227
- await project.save();
228
- }
229
- async projectList(options) {
230
- const {
231
- all
232
- } = options;
233
- const table = new _cliTable.default({
234
- head: ["Name", "Type", "Status"],
235
- colAligns: ["left", "center", "center"]
236
- });
237
- const projects = await this.projectService.search({});
238
- for (const project of projects) {
239
- const container = await this.dockerService.getContainer(`${project.name}.workspace`);
240
- if (!container) {
241
- if (all) {
242
- table.push([project.name, project.type, "-"]);
243
- }
244
- continue;
245
- }
246
- const {
247
- State: {
248
- Status = "stopped"
249
- } = {}
250
- } = await container.inspect();
251
- table.push([project.name, project.type, Status]);
252
- }
253
- return table.toString() + "\n";
254
- }
255
- async start(options) {
256
- const {
257
- name,
258
- rebuild,
259
- detach
260
- } = options;
261
- if (name) {
262
- await this.projectService.cdProject(name);
263
- }
264
- const project = await this.projectService.get();
265
- if (rebuild) {
266
- await this.appEventsService.emit("project:rebuild", project);
267
- }
268
- await this.projectService.start(project);
269
- if (!detach) {
270
- const project = await this.projectService.get();
271
- const containerName = `${project.name}.workspace`;
272
- const container = await _makes.Docker.getContainer(containerName);
273
- await container.resize({
274
- w: process.stdout.columns,
275
- h: process.stdout.rows
276
- });
277
- await _makes.Docker.attach(containerName);
278
- }
279
- }
280
- async stop(options) {
281
- const {
282
- name
283
- } = options;
284
- if (name) {
285
- await this.projectService.cdProject(name);
286
- }
287
- const project = await this.projectService.get();
288
- await this.projectService.stop(project);
289
- }
290
- async run(script) {
291
- const project = await this.projectService.get();
292
- if (!project.scripts || !project.scripts[script]) {
293
- throw new Error(`Script ${script} not found`);
294
- }
295
- const container = await this.dockerService.getContainer(`${project.name}.workspace`);
296
- if (!container) {
297
- throw new Error("The project is not started");
298
- }
299
- const exec = await container.exec({
300
- Cmd: ["bash", "-i", "-c", project.scripts[script]],
301
- AttachStdin: true,
302
- AttachStdout: true,
303
- AttachStderr: true,
304
- Tty: process.stdin.isTTY
305
- });
306
- const stream = await exec.start({
307
- hijack: true,
308
- stdin: true,
309
- Tty: process.stdin.isTTY
310
- });
311
- await this.dockerService.attachStream(stream);
312
- }
313
- async attach(options) {
314
- const {
315
- name
316
- } = options;
317
- if (name) {
318
- await this.projectService.cdProject(name);
319
- }
320
- const containerName = `${name}.workspace`;
321
- await _makes.Docker.attach(containerName);
322
- }
323
- async configList(options) {
324
- const {
325
- name,
326
- global
327
- } = options;
328
- if (name) {
329
- await this.projectService.cdProject(name);
330
- }
331
- let env = {};
332
- if (!global) {
333
- const project = await this.projectService.get();
334
- env = project.env || {};
335
- } else {
336
- const config = await (0, _utils2.getConfig)();
337
- env = config.env || {};
338
- }
339
- const table = new _cliTable.default({
340
- head: ["KEY", "VALUE"]
341
- });
342
- for (const i in env) {
343
- table.push([i, env[i]]);
344
- }
345
- return table.toString() + "\n";
346
- }
347
- async configGet(options, key) {
348
- const {
349
- name,
350
- global
351
- } = options;
352
- if (name) {
353
- await this.projectService.cdProject(name);
354
- }
355
- let value = "";
356
- if (global) {
357
- const config = await (0, _utils2.getConfig)();
358
- value = config[key] || "";
359
- } else {
360
- const project = await this.projectService.get();
361
- value = project.getEnv(key);
362
- }
363
- const table = new _cliTable.default({
364
- head: ["KEY", "VALUE"]
365
- });
366
- table.push([key, value]);
367
- return table.toString() + "\n";
368
- }
369
- async configSet(options, configs) {
370
- const {
371
- name,
372
- global
373
- } = options;
374
- const env = configs.reduce((env, config) => {
375
- const [key, value] = config.split("=");
376
- env[key.trim()] = value.trim();
377
- return env;
378
- }, {});
379
- if (global) {
380
- const config = await (0, _utils2.getConfig)();
381
- await (0, _utils2.setConfig)({
382
- ...config,
383
- env: {
384
- ...(config.env || {}),
385
- ...env
386
- }
387
- });
388
- return;
389
- }
390
- if (name) {
391
- await this.projectService.cdProject(name);
392
- }
393
- const project = await this.projectService.get();
394
- for (const i in env) {
395
- project.setEnv(i, env[i]);
396
- }
397
- await project.save();
398
- }
399
- async configUnset(options, configs) {
400
- const {
401
- name,
402
- global
403
- } = options;
404
- const env = configs.reduce((env, config) => {
405
- const [key] = config.split("=");
406
- env[key.trim()] = null;
407
- return env;
408
- }, {});
409
- if (global) {
410
- return;
305
+ case makes_2.PROJECT_TYPE_IMAGE: {
306
+ project.imageName = await (0, utils_1.promptText)({
307
+ message: "Image Name",
308
+ default: project.imageName
309
+ });
310
+ break;
311
+ }
312
+ default:
313
+ break;
314
+ }
315
+ await this.appEventsService.emit("project:init", project);
316
+ project.path = this.appConfigService.getPWD();
317
+ await project.save();
318
+ }
319
+ async projectList(options) {
320
+ const { all } = options;
321
+ const table = new cli_table3_1.default({
322
+ head: ["Name", "Type", "Status"],
323
+ colAligns: ["left", "center", "center"]
324
+ });
325
+ const projects = await this.projectService.search({});
326
+ for (const project of projects) {
327
+ const container = await this.dockerService.getContainer(`${project.name}.workspace`);
328
+ if (!container) {
329
+ if (all) {
330
+ table.push([project.name, project.type, "-"]);
331
+ }
332
+ continue;
333
+ }
334
+ const { State: { Status = "stopped" } = {} } = await container.inspect();
335
+ table.push([project.name, project.type, Status]);
336
+ }
337
+ return table.toString() + "\n";
411
338
  }
412
- if (name) {
413
- await this.projectService.cdProject(name);
339
+ async start(options) {
340
+ const { name, rebuild, detach } = options;
341
+ if (name) {
342
+ await this.projectService.cdProject(name);
343
+ }
344
+ const project = await this.projectService.get();
345
+ if (rebuild) {
346
+ await this.appEventsService.emit("project:rebuild", project);
347
+ }
348
+ await this.projectService.start();
349
+ if (!detach) {
350
+ const project = await this.projectService.get();
351
+ const containerName = `${project.name}.workspace`;
352
+ const container = await makes_1.Docker.getContainer(containerName);
353
+ await container.resize({
354
+ w: process.stdout.columns,
355
+ h: process.stdout.rows
356
+ });
357
+ await makes_1.Docker.attach(containerName);
358
+ }
414
359
  }
415
- const project = await this.projectService.get();
416
- for (const i in env) {
417
- project.unsetEnv(i);
360
+ async stop(options) {
361
+ const { name } = options;
362
+ if (name) {
363
+ await this.projectService.cdProject(name);
364
+ }
365
+ await this.projectService.stop();
418
366
  }
419
- await project.save();
420
- }
421
- async buildArgsList(options) {
422
- const {
423
- name
424
- } = options;
425
- if (name) {
426
- await this.projectService.cdProject(name);
367
+ async run(script) {
368
+ const project = await this.projectService.get();
369
+ if (!project.scripts || !project.scripts[script]) {
370
+ throw new Error(`Script ${script} not found`);
371
+ }
372
+ const container = await this.dockerService.getContainer(`${project.name}.workspace`);
373
+ if (!container) {
374
+ throw new Error("The project is not started");
375
+ }
376
+ const exec = await container.exec({
377
+ Cmd: ["bash", "-i", "-c", project.scripts[script]],
378
+ AttachStdin: true,
379
+ AttachStdout: true,
380
+ AttachStderr: true,
381
+ Tty: process.stdin.isTTY
382
+ });
383
+ const stream = await exec.start({
384
+ hijack: true,
385
+ stdin: true,
386
+ Tty: process.stdin.isTTY
387
+ });
388
+ await this.dockerService.attachStream(stream);
427
389
  }
428
- const project = await this.projectService.get();
429
- const table = new _cliTable.default({
430
- head: ["KEY", "VALUE"]
431
- });
432
- const buildArgs = project.buildArgs || {};
433
- for (const i in buildArgs) {
434
- table.push([i, typeof buildArgs[i] === "string" ? buildArgs[i] : JSON.stringify(buildArgs[i])]);
390
+ async attach(options) {
391
+ const { name } = options;
392
+ if (name) {
393
+ await this.projectService.cdProject(name);
394
+ }
395
+ const containerName = `${name}.workspace`;
396
+ await makes_1.Docker.attach(containerName);
435
397
  }
436
- return table.toString() + "\n";
437
- }
438
- async buildArgsGet(options, args) {
439
- const {
440
- name
441
- } = options;
442
- if (name) {
443
- await this.projectService.cdProject(name);
398
+ async configList(options) {
399
+ const { name, global } = options;
400
+ if (name) {
401
+ await this.projectService.cdProject(name);
402
+ }
403
+ let env = {};
404
+ if (!global) {
405
+ const project = await this.projectService.get();
406
+ env = project.env || {};
407
+ }
408
+ else {
409
+ const config = await (0, utils_2.getConfig)();
410
+ env = config.env || {};
411
+ }
412
+ const table = new cli_table3_1.default({
413
+ head: ["KEY", "VALUE"]
414
+ });
415
+ for (const i in env) {
416
+ table.push([i, env[i]]);
417
+ }
418
+ return table.toString() + "\n";
444
419
  }
445
- const project = await this.projectService.get();
446
- const table = new _cliTable.default({
447
- head: ["KEY", "VALUE"]
448
- });
449
- _makes.Logger.info("...");
450
- for (const key of args) {
451
- if (project.buildArgs && typeof project.buildArgs[key] !== "undefined") {
452
- const value = project.buildArgs[key] || "";
420
+ async configGet(options, key) {
421
+ const { name, global } = options;
422
+ if (name) {
423
+ await this.projectService.cdProject(name);
424
+ }
425
+ let value = "";
426
+ if (global) {
427
+ const config = await (0, utils_2.getConfig)();
428
+ value = config[key] || "";
429
+ }
430
+ else {
431
+ const project = await this.projectService.get();
432
+ value = project.getEnv(key);
433
+ }
434
+ const table = new cli_table3_1.default({
435
+ head: ["KEY", "VALUE"]
436
+ });
453
437
  table.push([key, value]);
454
- }
455
- }
456
- return table.toString() + "\n";
457
- }
458
- async buildArgsSet(options, args) {
459
- const {
460
- name
461
- } = options;
462
- if (name) {
463
- await this.projectService.cdProject(name);
438
+ return table.toString() + "\n";
439
+ }
440
+ async configSet(options, configs) {
441
+ const { name, global } = options;
442
+ const env = configs.reduce((env, config) => {
443
+ const [key, value] = config.split("=");
444
+ env[key.trim()] = value.trim();
445
+ return env;
446
+ }, {});
447
+ if (global) {
448
+ const config = await (0, utils_2.getConfig)();
449
+ await (0, utils_2.setConfig)({
450
+ ...config,
451
+ env: {
452
+ ...config.env || {},
453
+ ...env
454
+ }
455
+ });
456
+ return;
457
+ }
458
+ if (name) {
459
+ await this.projectService.cdProject(name);
460
+ }
461
+ const project = await this.projectService.get();
462
+ for (const i in env) {
463
+ project.setEnv(i, env[i]);
464
+ }
465
+ await project.save();
466
+ }
467
+ async configUnset(options, configs) {
468
+ const { name, global } = options;
469
+ const env = configs.reduce((env, config) => {
470
+ const [key] = config.split("=");
471
+ env[key.trim()] = null;
472
+ return env;
473
+ }, {});
474
+ if (global) {
475
+ return;
476
+ }
477
+ if (name) {
478
+ await this.projectService.cdProject(name);
479
+ }
480
+ const project = await this.projectService.get();
481
+ for (const i in env) {
482
+ project.unsetEnv(i);
483
+ }
484
+ await project.save();
464
485
  }
465
- const project = await this.projectService.get();
466
- const buildArgs = args.reduce((env, config) => {
467
- const [key, value] = config.split("=");
468
- env[key.trim()] = value.trim();
469
- return env;
470
- }, {});
471
- for (const key in buildArgs) {
472
- if (!project.buildArgs) {
473
- project.buildArgs = {};
474
- }
475
- project.buildArgs[key] = buildArgs[key];
486
+ async buildArgsList(options) {
487
+ const { name } = options;
488
+ if (name) {
489
+ await this.projectService.cdProject(name);
490
+ }
491
+ const project = await this.projectService.get();
492
+ const table = new cli_table3_1.default({
493
+ head: ["KEY", "VALUE"]
494
+ });
495
+ const buildArgs = project.buildArgs || {};
496
+ for (const i in buildArgs) {
497
+ table.push([i, typeof buildArgs[i] === "string" ? buildArgs[i] : JSON.stringify(buildArgs[i])]);
498
+ }
499
+ return table.toString() + "\n";
476
500
  }
477
- await project.save();
478
- }
479
- async buildArgsUnset(options, args) {
480
- const {
481
- name
482
- } = options;
483
- if (name) {
484
- await this.projectService.cdProject(name);
501
+ async buildArgsGet(options, args) {
502
+ const { name } = options;
503
+ if (name) {
504
+ await this.projectService.cdProject(name);
505
+ }
506
+ const project = await this.projectService.get();
507
+ const table = new cli_table3_1.default({
508
+ head: ["KEY", "VALUE"]
509
+ });
510
+ makes_1.Logger.info("...");
511
+ for (const key of args) {
512
+ if (project.buildArgs && typeof project.buildArgs[key] !== "undefined") {
513
+ const value = project.buildArgs[key] || "";
514
+ table.push([key, value]);
515
+ }
516
+ }
517
+ return table.toString() + "\n";
485
518
  }
486
- const project = await this.projectService.get();
487
- const buildArgs = args.reduce((env, config) => {
488
- const [key, value] = config.split("=");
489
- env[key.trim()] = value.trim();
490
- return env;
491
- }, {});
492
- for (const key in buildArgs) {
493
- if (!project.buildArgs) {
494
- break;
495
- }
496
- if (typeof project.buildArgs[key] !== "undefined") {
497
- delete project.buildArgs[key];
498
- }
519
+ async buildArgsSet(options, args) {
520
+ const { name } = options;
521
+ if (name) {
522
+ await this.projectService.cdProject(name);
523
+ }
524
+ const project = await this.projectService.get();
525
+ const buildArgs = args.reduce((env, config) => {
526
+ const [key, value] = config.split("=");
527
+ env[key.trim()] = value.trim();
528
+ return env;
529
+ }, {});
530
+ for (const key in buildArgs) {
531
+ if (!project.buildArgs) {
532
+ project.buildArgs = {};
533
+ }
534
+ project.buildArgs[key] = buildArgs[key];
535
+ }
536
+ await project.save();
499
537
  }
500
- await project.save();
501
- }
502
- async volumeList(options) {
503
- const {
504
- name
505
- } = options;
506
- if (name) {
507
- await this.projectService.cdProject(name);
538
+ async buildArgsUnset(options, args) {
539
+ const { name } = options;
540
+ if (name) {
541
+ await this.projectService.cdProject(name);
542
+ }
543
+ const project = await this.projectService.get();
544
+ const buildArgs = args.reduce((env, config) => {
545
+ const [key, value] = config.split("=");
546
+ env[key.trim()] = value.trim();
547
+ return env;
548
+ }, {});
549
+ for (const key in buildArgs) {
550
+ if (!project.buildArgs) {
551
+ break;
552
+ }
553
+ if (typeof project.buildArgs[key] !== "undefined") {
554
+ delete project.buildArgs[key];
555
+ }
556
+ }
557
+ await project.save();
508
558
  }
509
- const project = await this.projectService.get();
510
- const table = new _cliTable.default({
511
- head: ["Volume"]
512
- });
513
- const volumes = project.volumes || [];
514
- for (const volume of volumes) {
515
- table.push([volume]);
559
+ async volumeList(options) {
560
+ const { name } = options;
561
+ if (name) {
562
+ await this.projectService.cdProject(name);
563
+ }
564
+ const project = await this.projectService.get();
565
+ const table = new cli_table3_1.default({
566
+ head: ["Volume"]
567
+ });
568
+ const volumes = project.volumes || [];
569
+ for (const volume of volumes) {
570
+ table.push([volume]);
571
+ }
572
+ return table.toString() + "\n";
516
573
  }
517
- return table.toString() + "\n";
518
- }
519
- async volumeMount(options, volumes) {
520
- const {
521
- name
522
- } = options;
523
- if (name) {
524
- await this.projectService.cdProject(name);
574
+ async volumeMount(options, volumes) {
575
+ const { name } = options;
576
+ if (name) {
577
+ await this.projectService.cdProject(name);
578
+ }
579
+ const project = await this.projectService.get();
580
+ if (Array.isArray(volumes) && volumes.length > 0) {
581
+ project.volumeMount(...volumes);
582
+ await project.save();
583
+ }
525
584
  }
526
- const project = await this.projectService.get();
527
- console.log(volumes);
528
- project.volumeMount(...volumes);
529
- await project.save();
530
- }
531
- async volumeUnmount(options, volumes) {
532
- const {
533
- name
534
- } = options;
535
- if (name) {
536
- await this.projectService.cdProject(name);
585
+ async volumeUnmount(options, volumes) {
586
+ const { name } = options;
587
+ if (name) {
588
+ await this.projectService.cdProject(name);
589
+ }
590
+ const project = await this.projectService.get();
591
+ if (Array.isArray(volumes) && volumes.length > 0) {
592
+ project.volumeUnmount(...volumes);
593
+ await project.save();
594
+ }
537
595
  }
538
- const project = await this.projectService.get();
539
- project.volumeUnmount(...volumes);
540
- await project.save();
541
- }
542
- async logs(options) {
543
- const {
544
- name,
545
- global,
546
- detach,
547
- follow
548
- } = options;
549
- if (global) {
550
- const logFilepath = Path.join(_env.DATA_DIR, "ws.log");
551
- const prepareLog = str => {
552
- return str.replace(/^\[.*]\s([^:]+):\s.*$/gm, (substring, type) => {
553
- switch (type) {
554
- case "info":
555
- return _chalk.default.green(substring);
556
- case "warning":
557
- return _chalk.default.yellow(substring);
558
- case "error":
559
- return _chalk.default.red(substring);
560
- default:
561
- return substring;
562
- }
563
- });
564
- };
565
- const stream = _makes.FS.createReadLinesStream(logFilepath, follow ? -10 : undefined);
566
- stream.on("data", data => {
567
- process.stdout.write(prepareLog(data.toString()));
568
- process.stdout.write("\n");
569
- });
570
- if (follow) {
571
- const stats = await _makes.FS.stat(logFilepath);
572
- const watcher = _makes.FS.watch(logFilepath);
573
- const mutex = new _asyncMutex.Mutex();
574
- let position = BigInt(stats.size);
575
- watcher.on("change", async () => {
576
- await mutex.acquire();
577
- try {
578
- const stats = await _makes.FS.stat(logFilepath);
579
- if (BigInt(stats.size) < position) {
580
- console.log("file truncated");
581
- position = 0n;
596
+ async logs(options) {
597
+ const { name, global, detach, follow } = options;
598
+ if (global) {
599
+ const logFilepath = Path.join(env_1.DATA_DIR, "ws.log");
600
+ const prepareLog = (str) => {
601
+ return str.replace(/^\[.*]\s([^:]+):\s.*$/gm, (substring, type) => {
602
+ switch (type) {
603
+ case "info":
604
+ return chalk_1.default.green(substring);
605
+ case "warn":
606
+ case "warning":
607
+ return chalk_1.default.yellow(substring);
608
+ case "error":
609
+ return chalk_1.default.red(substring);
610
+ default:
611
+ return substring;
612
+ }
613
+ });
614
+ };
615
+ const stream = makes_1.FS.createReadLinesStream(logFilepath, follow ? -10 : undefined);
616
+ stream.on("data", (data) => {
617
+ process.stdout.write(prepareLog(data.toString()));
618
+ process.stdout.write("\n");
619
+ });
620
+ if (follow) {
621
+ const stats = await makes_1.FS.stat(logFilepath);
622
+ const watcher = makes_1.FS.watch(logFilepath);
623
+ const mutex = new async_mutex_1.Mutex();
624
+ let position = BigInt(stats.size);
625
+ watcher.on("change", async () => {
626
+ await mutex.acquire();
627
+ try {
628
+ const stats = await makes_1.FS.stat(logFilepath);
629
+ if (BigInt(stats.size) < position) {
630
+ console.log("file truncated");
631
+ position = 0n;
632
+ }
633
+ const buffer = await makes_1.FS.readBytes(logFilepath, position);
634
+ position += BigInt(buffer.length);
635
+ process.stdout.write(prepareLog(buffer.toString("utf-8")));
636
+ }
637
+ finally {
638
+ mutex.release();
639
+ }
640
+ });
582
641
  }
583
- const buffer = await _makes.FS.readBytes(logFilepath, position);
584
- position += BigInt(buffer.length);
585
- process.stdout.write(prepareLog(buffer.toString("utf-8")));
586
- } finally {
587
- mutex.release();
588
- }
589
- });
590
- }
591
- return;
592
- }
593
- if (name) {
594
- await this.projectService.cdProject(name);
595
- }
596
- const project = await this.projectService.get();
597
- const container = await _makes.Docker.getContainer(`${project.name}.workspace`);
598
- if (!detach) {
599
- const stream = await container.logs({
600
- stdout: true,
601
- stderr: true,
602
- follow: true
603
- });
604
- stream.on("data", data => {
605
- process.stdout.write((0, _utils2.demuxOutput)(data));
606
- });
607
- } else {
608
- const buffer = await container.logs({
609
- stdout: true,
610
- stderr: true,
611
- follow: false
612
- });
613
- process.stdout.write((0, _utils2.demuxOutput)(buffer));
642
+ return;
643
+ }
644
+ if (name) {
645
+ await this.projectService.cdProject(name);
646
+ }
647
+ const project = await this.projectService.get();
648
+ const container = await makes_1.Docker.getContainer(`${project.name}.workspace`);
649
+ if (!detach) {
650
+ const stream = await container.logs({
651
+ stdout: true,
652
+ stderr: true,
653
+ follow: true
654
+ });
655
+ stream.on("data", (data) => {
656
+ process.stdout.write((0, utils_2.demuxOutput)(data));
657
+ });
658
+ }
659
+ else {
660
+ const buffer = await container.logs({
661
+ stdout: true,
662
+ stderr: true,
663
+ follow: false
664
+ });
665
+ process.stdout.write((0, utils_2.demuxOutput)(buffer));
666
+ }
614
667
  }
615
- }
616
- async exec(options, command) {
617
- const {
618
- name
619
- } = options;
620
- if (name) {
621
- await this.projectService.cdProject(name);
668
+ async exec(options, command) {
669
+ const { name } = options;
670
+ if (name) {
671
+ await this.projectService.cdProject(name);
672
+ }
673
+ const project = await this.projectService.get();
674
+ const containerName = `${project.name}.workspace`;
675
+ await makes_1.Docker.exec(containerName, command);
622
676
  }
623
- const project = await this.projectService.get();
624
- const containerName = `${project.name}.workspace`;
625
- await _makes.Docker.exec(containerName, command);
626
- }
627
677
  }
628
- exports.ProjectController = ProjectController;
678
+ exports.ProjectController = ProjectController;