-
Notifications
You must be signed in to change notification settings - Fork 13
/
stop.ts
113 lines (99 loc) · 3.46 KB
/
stop.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
104
105
106
107
108
109
110
111
112
113
import { CliUx } from '@oclif/core';
import chalk from 'chalk';
import fs from 'fs-extra';
import inquirer from 'inquirer';
import net from 'net';
import path from 'path';
import { socketPath } from '.';
import { ArchitectError } from '../..';
import BaseCommand from '../../base-command';
import { DockerComposeUtils } from '../../common/docker-compose';
import { RequiresDocker } from '../../common/docker/helper';
import LocalPaths from '../../paths';
export default class DevStop extends BaseCommand {
async auth_required(): Promise<boolean> {
return false;
}
static description = 'Stop a local deployment';
static examples = [
'architect dev:stop <local-environment-name>',
];
static flags = {
...BaseCommand.flags,
};
static args = [{
sensitive: false,
name: 'name',
description: 'Name of local environment',
required: false,
}];
async waitForEnviromentToStop(environment: string): Promise<boolean> {
let attempts = 0;
// Essentially add a 3 mintue timeout
while (attempts < 180) {
const environments = await DockerComposeUtils.getLocalEnvironments();
if (environments.includes(environment)) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
} else {
return true;
}
attempts++;
}
return false;
}
async runComposeStop(project: string): Promise<void> {
const compose_file = DockerComposeUtils.buildComposeFilepath(this.app.config.getConfigDir(), project);
await DockerComposeUtils.dockerCompose(['-p', project, '-f', compose_file, 'stop']);
fs.removeSync(compose_file); // remove compose file if dev was started in detached mode
}
@RequiresDocker({ compose: true })
async run(): Promise<void> {
const { args } = await this.parse(DevStop);
const env_names = await DockerComposeUtils.getLocalEnvironments();
if (env_names.length === 0) {
throw new Error(chalk.red(`No local deployment found.`));
}
const answers: { name: string } = await inquirer.prompt([
{
type: 'list',
name: 'name',
when: !args.name,
message: 'Select a local environment',
choices: env_names,
},
]);
const name = args.name || answers.name;
if (!env_names.includes(name as string)) {
throw new Error(chalk.red(`No local deployment named '${name}'. Use command 'architect dev:list' to list local deployments.`));
}
CliUx.ux.action.start(chalk.blue(`Waiting for ${name} to stop...`));
const socket_path = socketPath(path.join(this.app.config.getConfigDir(), LocalPaths.LOCAL_DEPLOY_PATH, name));
if (fs.existsSync(socket_path)) {
const socket = net.createConnection(socket_path);
socket.on('error', async (e: any) => {
if (e.code === 'ECONNREFUSED') {
socket.end();
await this.runComposeStop(name);
} else {
throw e;
}
});
socket.write('stop', () => {
socket.end();
});
} else {
// If there's no socket at all, dev is running in detached mode and we can stop it with docker compose without
// worrying about the health check restarting anything.
await this.runComposeStop(name);
}
const did_stop = await this.waitForEnviromentToStop(name);
CliUx.ux.action.stop();
if (did_stop) {
this.log(chalk.green(`Successfully stopped local deployment '${name}'.`));
} else {
this.error(new ArchitectError(`Unable to stop ${name}`));
}
}
}