Completed
Push — master ( 1f0a28...847154 )
by ophelie
02:07
created

ComposeManager::kill()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 14
Ratio 100 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 14
loc 14
rs 9.4285
cc 2
eloc 7
nc 2
nop 2
1
<?php
2
3
namespace DockerCompose\Manager;
4
5
use DockerCompose\Exception\ComposeFileNotFoundException;
6
use DockerCompose\Exception\DockerHostConnexionErrorException;
7
use DockerCompose\Exception\DockerInstallationMissingException;
8
use DockerCompose\Exception\NoSuchServiceException;
9
use DockerCompose\ComposeFileCollection;
10
use mikehaertl\shellcommand\Command;
11
use Exception;
12
13
/**
14
 * DockerCompose\Manager\ComposeManager
15
 */
16
class ComposeManager
17
{
18
19
    /**
20
     * Start service containers
21
     *
22
     * @param mixed $composeFiles The compose files names
23
     */
24
    public function start($composeFiles = array())
25
    {
26
        return $this->processResult(
27
            $this->execute(
28
                $this->formatCommand('up -d', $this->createComposeFileCollection($composeFiles))
29
            )
30
        );
31
    }
32
33
    /**
34
     * Stop service containers
35
     *
36
     * @param mixed $composeFiles The compose files names
37
     */
38
    public function stop($composeFiles = array())
39
    {
40
        return $this->processResult(
41
            $this->execute(
42
                $this->formatCommand('stop', $this->createComposeFileCollection($composeFiles))
43
            )
44
        );
45
    }
46
47
    /**
48
     * Stop service containers
49
     *
50
     * @param mixed   $composeFiles  The compose files names
51
     * @param boolean $force         If the remove need to be force (default=false)
52
     * @param boolean $removeVolumes If we need to remove the volumes (default=false)
53
     */
54
    public function remove($composeFiles = array(), $force = false, $removeVolumes = false)
55
    {
56
        $command = 'rm';
57
        if ($force) {
58
            $command .= ' --force';
59
        }
60
61
        if ($removeVolumes) {
62
            $command .= ' -v';
63
        }
64
65
        return $this->processResult(
66
            $this->execute(
67
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
68
            )
69
        );
70
    }
71
72
     /**
73
     * Stop service containers
74
     *
75
     * @param mixed   $composeFiles  The compose files names
76
     * @param string  $signal        Optionnal to precise SIGNAL to send to the container for SIGKILL replacement.
77
     */
78 View Code Duplication
    public function kill($composeFiles = array(), $signal = 'SIGKILL')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
79
    {
80
        $command = 'kill';
81
82
        if ($signal !== 'SIGKILL') {
83
            $command .= ' -s ' . $signal;
84
        }
85
86
        return $this->processResult(
87
            $this->execute(
88
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
89
            )
90
        );
91
    }
92
93
    /**
94
     * Build service images
95
     *
96
     * @param mixed   $composeFiles  The compose files names
97
     * @param boolean $pull          If we want attempt to pull a newer version of the from image
98
     * @param boolean $forceRemove   If we want remove the intermediate containers
99
     * @param bollean $cache         If we can use the cache when building the image
100
     */
101
    public function build($composeFiles = array(), $pull = true, $forceRemove = false, $cache = true)
102
    {
103
        $command = 'build';
104
105
        if ($pull) {
106
            $command .= ' --pull';
107
        }
108
109
        if ($forceRemove) {
110
            $command .= ' --force-rm';
111
        }
112
113
        if (!$cache) {
114
            $command .= ' --no-cache';
115
        }
116
117
        return $this->processResult(
118
            $this->execute(
119
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
120
            )
121
        );
122
    }
123
124
125
    /**
126
     * Restart running containers
127
     *
128
     * @param mixed   $composeFiles  The compose files names
129
     * @param integer $timeout       If we want attempt to pull a newer version of the from image
130
     */
131 View Code Duplication
    public function restart($composeFiles = array(), $timeout = 10)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
    {
133
        $command = 'restart';
134
135
        if ($timeout != 10) {
136
            $command .= ' --timeout='.$timeout;
137
        }
138
139
        return $this->processResult(
140
            $this->execute(
141
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
142
            )
143
        );
144
    }
145
146
    /**
147
     * Run service with command
148
     *
149
     * @param string $service Service name
150
     * @param string $command Command to pass to service
151
     * @param mixed   $composeFiles  The compose files names
152
     */
153
    public function run($service, $command, $composeFiles = array())
154
    {
155
        $command = 'run --rm ' . $service . ' ' . $command;
156
        $result = $this->execute(
157
            $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
158
        );
159
160
        if ($result['code'] == 1 && strpos($result['output'], 'No such service') != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($result['output'], 'No such service') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
161
            throw new NoSuchServiceException($result['output']);
162
        }
163
164
        return $this->processResult($result);
165
    }
166
167
    /**
168
     * List containers
169
     *
170
     * @param mixed $composeFiles The compose files names
171
     */
172
    public function ps($composeFiles = array())
173
    {
174
        return $this->processResult(
175
            $this->execute(
176
                $this->formatCommand('ps', $this->createComposeFileCollection($composeFiles))
177
            )
178
        );
179
    }
180
181
    /**
182
     * Process result with returned code and output
183
     *
184
     * @param array $result The result of command with output and returnCode
185
     *
186
     * @throws DockerInstallationMissingException When returned code is 127
187
     * @throws ComposeFileNotFoundException When no compose file precise and docker-compose.yml not found
188
     * @throws DockerHostConnexionErrorException When we can't connect to docker host
189
     * @throws \Exception When an unknown error is returned
190
     */
191
    private function processResult($result)
192
    {
193
        if ($result['code'] === 127) {
194
            throw new DockerInstallationMissingException();
195
        }
196
197
        if ($result['code'] === 1) {
198
            if (!strpos($result['output'], 'DOCKER_HOST')) {
199
                if (!strpos($result['output'], 'docker-compose.yml')) {
200
                    throw new Exception($result['output']);
201
                } else {
202
                    throw new ComposeFileNotFoundException();
203
                }
204
            } else {
205
                throw new DockerHostConnexionErrorException();
206
            }
207
        }
208
209
        return $result['output'];
210
    }
211
212
    /**
213
     * Create the composeFileCollection from the type of value given
214
     *
215
     * @param mixed $composeFiles The docker-compose files (can be array, string or ComposeFile)
216
     *
217
     * @return ComposeFileCollection
218
     */
219
    private function createComposeFileCollection($composeFiles)
220
    {
221
        if (!$composeFiles instanceof ComposeFileCollection) {
222
            if (!is_array($composeFiles)) {
223
                return new ComposeFileCollection([$composeFiles]);
224
            } else {
225
                return new ComposeFileCollection($composeFiles);
226
            }
227
        } else {
228
            return $composeFiles;
229
        }
230
    }
231
232
    /**
233
     * Format the command to execute
234
     *
235
     * @param string                $subcommand   The subcommand to pass to docker-compose command
236
     * @param ComposeFileCollection $composeFiles The compose files to precise in the command
237
     */
238
    private function formatCommand($subcommand, ComposeFileCollection $composeFiles)
239
    {
240
        $project = '';
241
        $networking = '';
242
        $networkDriver = '';
243
244
        # Add project name, and network options
245
        if ($composeFiles->getProjectName() != null) {
246
            $project = ' --project-name ' . $composeFiles->getProjectName();
247
            if ($composeFiles->isNetworking()) {
248
                $networking = ' --x-networking';
249
                if ($composeFiles->getNetworkDriver() != null) {
250
                    $networkDriver = ' --x-network-driver ' . $composeFiles->getNetworkDriver();
251
                }
252
            }
253
        }
254
255
        # Add files names
256
        $preciseFiles = '';
257
        foreach ($composeFiles->getAll() as $composeFile) {
258
            $preciseFiles .= ' -f ' . $composeFile->getFileName();
259
        }
260
261
        $command = 'docker-compose' . $preciseFiles . $networking . $networkDriver . $project . ' ' . $subcommand;
262
263
        return $command;
264
    }
265
266
    /**
267
     * Execute docker-compose commande
268
     * @codeCoverageIgnore
269
     * @param string                $command      The command to execute
270
     */
271
    protected function execute($command)
272
    {
273
        $exec = new Command($command);
274
275
        if ($exec->execute()) {
276
            $output = $exec->getOutput();
277
        } else {
278
            $output = $exec->getError();
279
        }
280
281
        return array(
282
            'output' => $output,
283
            'code' => $exec->getExitCode()
284
        );
285
    }
286
}
287