Completed
Push — master ( 1c72b8...2bd393 )
by ophelie
03:53
created

ComposeManager::createComposeFileCollection()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 12
rs 9.4286
cc 3
eloc 8
nc 3
nop 1
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 Exception;
11
12
/**
13
 * DockerCompose\Manager\ComposeManager
14
 */
15
class ComposeManager
16
{
17
18
    /**
19
     * Start service containers
20
     *
21
     * @param mixed $composeFiles The compose files names
22
     */
23 View Code Duplication
    public function start($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...
24
    {
25
        $composeFiles = $this->createComposeFileCollection($composeFiles);
26
        $result = $this->execute(
27
            $this->formatCommand('up -d', $composeFiles)
28
        );
29
30
        return $this->processResult($result);
31
    }
32
33
    /**
34
     * Stop service containers
35
     *
36
     * @param mixed $composeFiles The compose files names
37
     */
38 View Code Duplication
    public function stop($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...
39
    {
40
        $composeFiles = $this->createComposeFileCollection($composeFiles);
41
        $result = $this->execute(
42
            $this->formatCommand('stop', $composeFiles)
43
        );
44
45
        return $this->processResult($result);
46
    }
47
48
    /**
49
     * Stop service containers
50
     *
51
     * @param mixed   $composeFiles  The compose files names
52
     * @param boolean $force         If the remove need to be force (default=false)
53
     * @param boolean $removeVolumes If we need to remove the volumes (default=false)
54
     */
55
    public function remove($composeFiles = array(), $force = false, $removeVolumes = false)
56
    {
57
        $composeFiles = $this->createComposeFileCollection($composeFiles);
58
        $command = 'rm';
59
        if ($force) {
60
            $command .= ' --force';
61
        }
62
63
        if ($removeVolumes) {
64
            $command .= ' -v';
65
        }
66
67
        $result = $this->execute(
68
            $this->formatCommand($command, $composeFiles)
69
        );
70
71
        return $this->processResult($result);
72
    }
73
74
    /**
75
     * Run service with command
76
     *
77
     * @param string $service Service name
78
     * @param string $command Command to pass to service
79
     * @param mixed   $composeFiles  The compose files names
80
     */
81
    public function run($service, $command, $composeFiles = array())
82
    {
83
        $composeFiles = $this->createComposeFileCollection($composeFiles);
84
        $command = 'run --rm ' . $service . ' ' . $command;
85
        $result = $this->execute(
86
            $this->formatCommand($command, $composeFiles)
87
        );
88
89
        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...
90
            throw new NoSuchServiceException($result['output']);
91
        }
92
93
        return $this->processResult($result);
94
    }
95
96
    /**
97
     * Process result with returned code and output
98
     *
99
     * @param array $result The result of command with output and returnCode
100
     *
101
     * @throws DockerInstallationMissingException When returned code is 127
102
     * @throws ComposeFileNotFoundException When no compose file precise and docker-compose.yml not found
103
     * @throws DockerHostConnexionErrorException When we can't connect to docker host
104
     * @throws \Exception When an unknown error is returned
105
     */
106
    private function processResult($result)
107
    {
108
        if ($result['code'] === 127) {
109
            throw new DockerInstallationMissingException();
110
        }
111
112
        if ($result['code'] === 1) {
113
            if (!strpos($result['output'], 'DOCKER_HOST')) {
114
                if (!strpos($result['output'], 'docker-compose.yml')) {
115
                    throw new Exception($result['output']);
116
                } else {
117
                    throw new ComposeFileNotFoundException();
118
                }
119
            } else {
120
                throw new DockerHostConnexionErrorException();
121
            }
122
        }
123
124
        return $result['output'];
125
    }
126
127
    /**
128
     * Create the composeFileCollection from the type of value given
129
     *
130
     * @param mixed $composeFiles The docker-compose files (can be array, string or ComposeFile)
131
     *
132
     * @return ComposeFileCollection
133
     */
134
    private function createComposeFileCollection($composeFiles)
135
    {
136
        if (!$composeFiles instanceof ComposeFileCollection) {
137
            if (!is_array($composeFiles)) {
138
                return new ComposeFileCollection([$composeFiles]);
139
            } else {
140
                return new ComposeFileCollection($composeFiles);
141
            }
142
        } else {
143
            return $composeFiles;
144
        }
145
    }
146
147
    /**
148
     * Format the command to execute
149
     *
150
     * @param string                $subcommand   The subcommand to pass to docker-compose command
151
     * @param ComposeFileCollection $composeFiles The compose files to precise in the command
152
     */
153
    private function formatCommand($subcommand, ComposeFileCollection $composeFiles)
154
    {
155
        $project = '';
156
        $networking = '';
157
        $networkDriver = '';
158
        # Add project name, and network options
159
        if ($composeFiles->getProjectName() != null) {
160
            $project = ' --project-name ' . $composeFiles->getProjectName();
161
            if ($composeFiles->isNetworking()) {
162
                $networking = ' --x-networking';
163
                if ($composeFiles->getNetworkDriver() != null) {
164
                    $networkDriver = ' --x-network-driver ' . $composeFiles->getNetworkDriver();
165
                }
166
            }
167
        }
168
169
        # Add files names
170
        $preciseFiles = '';
171
        foreach ($composeFiles->getAll() as $composeFile) {
172
            $preciseFiles .= ' -f ' . $composeFile->getFileName();
173
        }
174
175
        $command = 'docker-compose' . $preciseFiles . $networking . $networkDriver . $project . ' ' . $subcommand;
176
177
        return $command;
178
    }
179
180
    /**
181
     * Execute docker-compose commande
182
     * @codeCoverageIgnore
183
     * @param string                $command      The command to execute
184
     */
185
    protected function execute($command)
186
    {
187
        $command = system($command . ' > output 2>&1', $retval);
0 ignored issues
show
Unused Code introduced by
$command 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...
188
189
        $output = fopen('output', 'r');
190
        $output = fread($output, filesize('output'));
191
        unlink('output');
192
193
        return array(
194
            'output' => $output,
195
            'code' => $retval
196
        );
197
    }
198
}
199