Completed
Push — master ( 14e513...25505d )
by ophelie
02:44
created

ComposeManager   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 19
Bugs 2 Features 13
Metric Value
wmc 27
c 19
b 2
f 13
lcom 1
cbo 6
dl 0
loc 214
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A start() 0 8 1
A stop() 0 8 1
A remove() 0 17 3
B build() 0 22 4
A run() 0 13 3
B processResult() 0 20 5
A createComposeFileCollection() 0 12 3
B formatCommand() 0 27 5
A execute() 0 15 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
     * Build service images
74
     *
75
     * @param mixed   $composeFiles  The compose files names
76
     * @param boolean $pull          If we want attempt to pull a newer version of the from image
77
     * @param boolean $forceRemove   If we want remove the intermediate containers
78
     * @param bollean $cache         If we can use the cache when building the image
79
     */
80
    public function build($composeFiles = array(), $pull = true, $forceRemove = false, $cache = true)
81
    {
82
        $command = 'build';
83
84
        if ($pull) {
85
            $command .= ' --pull';
86
        }
87
88
        if ($forceRemove) {
89
            $command .= ' --force-rm';
90
        }
91
92
        if (!$cache) {
93
            $command .= ' --no-cache';
94
        }
95
96
        return $this->processResult(
97
            $this->execute(
98
                $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
99
            )
100
        );
101
    }
102
103
    /**
104
     * Run service with command
105
     *
106
     * @param string $service Service name
107
     * @param string $command Command to pass to service
108
     * @param mixed   $composeFiles  The compose files names
109
     */
110
    public function run($service, $command, $composeFiles = array())
111
    {
112
        $command = 'run --rm ' . $service . ' ' . $command;
113
        $result = $this->execute(
114
            $this->formatCommand($command, $this->createComposeFileCollection($composeFiles))
115
        );
116
117
        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...
118
            throw new NoSuchServiceException($result['output']);
119
        }
120
121
        return $this->processResult($result);
122
    }
123
124
    /**
125
     * Process result with returned code and output
126
     *
127
     * @param array $result The result of command with output and returnCode
128
     *
129
     * @throws DockerInstallationMissingException When returned code is 127
130
     * @throws ComposeFileNotFoundException When no compose file precise and docker-compose.yml not found
131
     * @throws DockerHostConnexionErrorException When we can't connect to docker host
132
     * @throws \Exception When an unknown error is returned
133
     */
134
    private function processResult($result)
135
    {
136
        if ($result['code'] === 127) {
137
            throw new DockerInstallationMissingException();
138
        }
139
140
        if ($result['code'] === 1) {
141
            if (!strpos($result['output'], 'DOCKER_HOST')) {
142
                if (!strpos($result['output'], 'docker-compose.yml')) {
143
                    throw new Exception($result['output']);
144
                } else {
145
                    throw new ComposeFileNotFoundException();
146
                }
147
            } else {
148
                throw new DockerHostConnexionErrorException();
149
            }
150
        }
151
152
        return $result['output'];
153
    }
154
155
    /**
156
     * Create the composeFileCollection from the type of value given
157
     *
158
     * @param mixed $composeFiles The docker-compose files (can be array, string or ComposeFile)
159
     *
160
     * @return ComposeFileCollection
161
     */
162
    private function createComposeFileCollection($composeFiles)
163
    {
164
        if (!$composeFiles instanceof ComposeFileCollection) {
165
            if (!is_array($composeFiles)) {
166
                return new ComposeFileCollection([$composeFiles]);
167
            } else {
168
                return new ComposeFileCollection($composeFiles);
169
            }
170
        } else {
171
            return $composeFiles;
172
        }
173
    }
174
175
    /**
176
     * Format the command to execute
177
     *
178
     * @param string                $subcommand   The subcommand to pass to docker-compose command
179
     * @param ComposeFileCollection $composeFiles The compose files to precise in the command
180
     */
181
    private function formatCommand($subcommand, ComposeFileCollection $composeFiles)
182
    {
183
        $project = '';
184
        $networking = '';
185
        $networkDriver = '';
186
187
        # Add project name, and network options
188
        if ($composeFiles->getProjectName() != null) {
189
            $project = ' --project-name ' . $composeFiles->getProjectName();
190
            if ($composeFiles->isNetworking()) {
191
                $networking = ' --x-networking';
192
                if ($composeFiles->getNetworkDriver() != null) {
193
                    $networkDriver = ' --x-network-driver ' . $composeFiles->getNetworkDriver();
194
                }
195
            }
196
        }
197
198
        # Add files names
199
        $preciseFiles = '';
200
        foreach ($composeFiles->getAll() as $composeFile) {
201
            $preciseFiles .= ' -f ' . $composeFile->getFileName();
202
        }
203
204
        $command = 'docker-compose' . $preciseFiles . $networking . $networkDriver . $project . ' ' . $subcommand;
205
206
        return $command;
207
    }
208
209
    /**
210
     * Execute docker-compose commande
211
     * @codeCoverageIgnore
212
     * @param string                $command      The command to execute
213
     */
214
    protected function execute($command)
215
    {
216
        $exec = new Command($command);
217
218
        if ($exec->execute()) {
219
            $output = $exec->getOutput();
220
        } else {
221
            $output = $exec->getError();
222
        }
223
224
        return array(
225
            'output' => $output,
226
            'code' => $exec->getExitCode()
227
        );
228
    }
229
}
230