Completed
Pull Request — master (#17)
by Tobias
02:00
created

ComposeManager   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 316
Duplicated Lines 12.03 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 6
Bugs 0 Features 2
Metric Value
wmc 33
c 6
b 0
f 2
lcom 1
cbo 6
dl 38
loc 316
rs 9.3999

15 Methods

Rating   Name   Duplication   Size   Complexity  
A start() 0 8 1
A stop() 0 8 1
A remove() 0 14 2
A kill() 14 14 2
B build() 0 22 4
A pull() 0 10 1
A restart() 14 14 2
A run() 0 13 3
A ps() 0 8 1
A config() 0 8 1
A ips() 10 10 1
B processResult() 0 20 5
A createComposeFileCollection() 0 12 3
B formatCommand() 0 26 4
A execute() 0 13 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
     * @var array environment variables for command
21
     */
22
    public $env = [];
23
24
    /**
25
     * Start service containers
26
     *
27
     * @param mixed $composeFiles The compose files names
28
     */
29
    public function start($composeFiles = array())
30
    {
31
        return $this->processResult(
32
            $this->execute(
33
                $this->formatCommand('up -d', $this->createComposeFileCollection($composeFiles))
34
            )
35
        );
36
    }
37
38
    /**
39
     * Stop service containers
40
     *
41
     * @param mixed $composeFiles The compose files names
42
     */
43
    public function stop($composeFiles = array())
44
    {
45
        return $this->processResult(
46
            $this->execute(
47
                $this->formatCommand('stop', $this->createComposeFileCollection($composeFiles))
48
            )
49
        );
50
    }
51
52
    /**
53
     * Stop service containers
54
     *
55
     * @param mixed   $composeFiles  The compose files names
56
     * @param boolean $force         If the remove need to be force (default=false)
57
     * @param boolean $removeVolumes If we need to remove the volumes (default=false)
58
     */
59
    public function remove($composeFiles = array(), $force = false, $removeVolumes = false)
0 ignored issues
show
Unused Code introduced by
The parameter $force is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
60
    {
61
        $command = 'rm --force';
62
63
        if ($removeVolumes) {
64
            $command .= ' -v';
65
        }
66
67
        return $this->processResult(
68
            $this->execute(
69
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
70
            )
71
        );
72
    }
73
74
     /**
75
     * Stop service containers
76
     *
77
     * @param mixed   $composeFiles  The compose files names
78
     * @param string  $signal        Optionnal to precise SIGNAL to send to the container for SIGKILL replacement.
79
     */
80 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...
81
    {
82
        $command = 'kill';
83
84
        if ($signal !== 'SIGKILL') {
85
            $command .= ' -s ' . $signal;
86
        }
87
88
        return $this->processResult(
89
            $this->execute(
90
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
91
            )
92
        );
93
    }
94
95
    /**
96
     * Build service images
97
     *
98
     * @param mixed   $composeFiles  The compose files names
99
     * @param boolean $pull          If we want attempt to pull a newer version of the from image
100
     * @param boolean $forceRemove   If we want remove the intermediate containers
101
     * @param bollean $cache         If we can use the cache when building the image
102
     */
103
    public function build($composeFiles = array(), $pull = true, $forceRemove = false, $cache = true)
104
    {
105
        $command = 'build';
106
107
        if ($pull) {
108
            $command .= ' --pull';
109
        }
110
111
        if ($forceRemove) {
112
            $command .= ' --force-rm';
113
        }
114
115
        if (!$cache) {
116
            $command .= ' --no-cache';
117
        }
118
119
        return $this->processResult(
120
            $this->execute(
121
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
122
            )
123
        );
124
    }
125
126
    /**
127
     * Pull service images
128
     *
129
     * @param mixed   $composeFiles  The compose files names
130
     */
131
    public function pull($composeFiles = array())
132
    {
133
        $command = 'pull';
134
135
        return $this->processResult(
136
            $this->execute(
137
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
138
            )
139
        );
140
    }
141
142
143
    /**
144
     * Restart running containers
145
     *
146
     * @param mixed   $composeFiles  The compose files names
147
     * @param integer $timeout       If we want attempt to pull a newer version of the from image
148
     */
149 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...
150
    {
151
        $command = 'restart';
152
153
        if ($timeout != 10) {
154
            $command .= ' --timeout='.$timeout;
155
        }
156
157
        return $this->processResult(
158
            $this->execute(
159
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
160
            )
161
        );
162
    }
163
164
    /**
165
     * Run service with command
166
     *
167
     * @param string $service Service name
168
     * @param string $command Command to pass to service
169
     * @param mixed   $composeFiles  The compose files names
170
     */
171
    public function run($service, $command, $composeFiles = array())
172
    {
173
        $command = 'run --rm ' . $service . ' ' . $command;
174
        $result = $this->execute(
175
            $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
176
        );
177
178
        if ($result['code'] == 1 && strpos($result['output'], 'service') != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($result['output'], '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...
179
            throw new NoSuchServiceException($result['output']);
180
        }
181
182
        return $this->processResult($result);
183
    }
184
185
    /**
186
     * List containers
187
     *
188
     * @param mixed $composeFiles The compose files names
189
     */
190
    public function ps($composeFiles = array())
191
    {
192
        return $this->processResult(
193
            $this->execute(
194
                $this->formatCommand('ps', $this->createComposeFileCollection($composeFiles))
195
            )
196
        );
197
    }
198
199
    /**
200
     * Show configuration (yaml)
201
     *
202
     * @param mixed $composeFiles The compose files names
203
     */
204
    public function config($composeFiles = array())
205
    {
206
        return $this->processResult(
207
            $this->execute(
208
                $this->formatCommand('config', $this->createComposeFileCollection($composeFiles))
209
            )
210
        );
211
    }
212
213
    /**
214
     * List IP containers
215
     *
216
     * @param mixed $composeFiles The compose files names
217
     */
218 View Code Duplication
    public function ips($composeFiles = array())
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...
219
    {
220
        $command = $this->formatCommand('ps', $this->createComposeFileCollection($composeFiles));
221
222
        $command = 'for CONTAINER in $(' . $command . ' -q); ';
223
        $command .= 'do echo "$(docker inspect --format \' {{ .Name }} \' $CONTAINER)\t';
224
        $command .= '$(docker inspect --format \' {{ .NetworkSettings.IPAddress }} \' $CONTAINER)"; done';
225
226
        return $this->processResult($this->execute($command));
0 ignored issues
show
Documentation introduced by
$command is of type string, but the function expects a object<mikehaertl\shellcommand\Command>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
227
    }
228
229
    /**
230
     * Process result with returned code and output
231
     *
232
     * @param array $result The result of command with output and returnCode
233
     *
234
     * @throws DockerInstallationMissingException When returned code is 127
235
     * @throws ComposeFileNotFoundException When no compose file precise and docker-compose.yml not found
236
     * @throws DockerHostConnexionErrorException When we can't connect to docker host
237
     * @throws \Exception When an unknown error is returned
238
     */
239
    private function processResult($result)
240
    {
241
        if ($result['code'] === 127) {
242
            throw new DockerInstallationMissingException();
243
        }
244
245
        if ($result['code'] === 1) {
246
            if (!strpos($result['output'], 'DOCKER_HOST')) {
247
                if (!strpos($result['output'], 'docker-compose.yml')) {
248
                    throw new Exception($result['output']);
249
                } else {
250
                    throw new ComposeFileNotFoundException();
251
                }
252
            } else {
253
                throw new DockerHostConnexionErrorException();
254
            }
255
        }
256
257
        return $result['output'];
258
    }
259
260
    /**
261
     * Create the composeFileCollection from the type of value given
262
     *
263
     * @param mixed $composeFiles The docker-compose files (can be array, string or ComposeFile)
264
     *
265
     * @return ComposeFileCollection
266
     */
267
    private function createComposeFileCollection($composeFiles)
268
    {
269
        if (!$composeFiles instanceof ComposeFileCollection) {
270
            if (!is_array($composeFiles)) {
271
                return new ComposeFileCollection([$composeFiles]);
272
            } else {
273
                return new ComposeFileCollection($composeFiles);
274
            }
275
        } else {
276
            return $composeFiles;
277
        }
278
    }
279
280
    /**
281
     * Format the command to execute
282
     *
283
     * @param string                $subcommand   The subcommand to pass to docker-compose command
284
     * @param ComposeFileCollection $composeFiles The compose files to precise in the command
285
     */
286
    private function formatCommand($subcommand, ComposeFileCollection $composeFiles)
287
    {
288
        $command = new Command("docker-compose");
289
290
        if (!empty($this->env)) {
291
            $command->procEnv = $this->env;
292
        }
293
        $project = '';
0 ignored issues
show
Unused Code introduced by
$project is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
294
295
        # Add files names
296
        $preciseFiles = '';
0 ignored issues
show
Unused Code introduced by
$preciseFiles is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
297
        foreach ($composeFiles->getAll() as $composeFile) {
298
            $command->addArg('-f', $composeFile->getFileName());
299
            #$preciseFiles .= ' -f ' . $composeFile->getFileName();
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
300
        }
301
302
        # Add project name
303
        if ($composeFiles->getProjectName() != null) {
304
            $command->addArg('--project-name', $composeFiles->getProjectName());
305
            #$project = ' --project-name ' . $composeFiles->getProjectName();
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
306
        }
307
308
        $command->addArg($subcommand);
309
310
        return $command;
311
    }
312
313
    /**
314
     * Execute docker-compose commande
315
     * @codeCoverageIgnore
316
     * @param Command $command The command to execute.
317
     */
318
    protected function execute($command)
319
    {
320
        if ($command->execute()) {
321
            $output = $command->getOutput();
322
        } else {
323
            $output = $command->getError();
324
        }
325
326
        return array(
327
            'output' => $output,
328
            'code' => $command->getExitCode()
329
        );
330
    }
331
}
332