Passed
Pull Request — master (#31)
by Keoghan
03:18
created

Porter::buildImages()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
namespace App;
4
5
use App\Models\PhpVersion;
6
use App\Models\Setting;
7
use App\Support\Console\DockerCompose\CliCommandFactory;
8
use App\Support\Console\DockerCompose\YamlBuilder;
9
use App\Support\Contracts\Cli;
10
use App\Support\Contracts\ImageRepository;
11
use App\Support\Contracts\ImageSetRepository;
12
use App\Support\Images\Image;
13
14
class Porter
15
{
16
    /**
17
     * The docker images sets used by Porter to serve sites.
18
     *
19
     * @var ImageSetRepository
20
     */
21
    protected $imageSets;
22
23
    /**
24
     * The CLI class that executes commands.
25
     *
26
     * @var Cli
27
     */
28
    protected $cli;
29
30
    /**
31
     * The Docker composer command factory.
32
     *
33
     * @var CliCommandFactory
34
     */
35
    protected $dockerCompose;
36
37
    /**
38
     * The DockerCompose YAML file builder.
39
     *
40
     * @var YamlBuilder
41
     */
42
    protected $yamlBuilder;
43
44
    /**
45
     * Porter constructor.
46
     *
47
     * @param ImageSetRepository $imageSets
48
     * @param Cli                $cli
49
     * @param CliCommandFactory  $commandFactory
50
     * @param YamlBuilder        $yamlBuilder
51
     */
52 73
    public function __construct(
53
        ImageSetRepository $imageSets,
54
        Cli $cli,
55
        CliCommandFactory $commandFactory,
56
        YamlBuilder $yamlBuilder
57
    ) {
58 73
        $this->imageSets = $imageSets;
59 73
        $this->cli = $cli;
60 73
        $this->dockerCompose = $commandFactory;
61 73
        $this->yamlBuilder = $yamlBuilder;
62 73
    }
63
64
    /**
65
     * Check if the Porter containers are running.
66
     *
67
     * @param string|null $service
68
     *
69
     * @return bool
70
     */
71 5
    public function isUp($service = null)
72
    {
73 5
        return (bool) stristr($this->dockerCompose->command('ps')->perform(), "porter_{$service}");
74
    }
75
76
    /**
77
     * Create the docker-compose.yaml file.
78
     */
79 4
    public function compose()
80
    {
81 4
        $this->yamlBuilder->build($this->getDockerImageSet());
82 4
    }
83
84
    /**
85
     * Start Porter containers, optionally start a specific service, and force them to be recreated.
86
     *
87
     * @param string|null $service
88
     * @param bool        $recreate
89
     */
90 4
    public function start($service = null, $recreate = false)
91
    {
92 4
        $recreate = $recreate ? '--force-recreate ' : '';
93
94 4
        $this->dockerCompose->command("up -d {$recreate}--remove-orphans {$service}")->realTime()->perform();
95 4
    }
96
97
    /**
98
     * Stop Porter containers.
99
     *
100
     * @param string|null $service
101
     */
102 2
    public function stop($service = null)
103
    {
104 2
        if ($service) {
105 1
            $this->dockerCompose->command("stop {$service}")->realTime()->perform();
106
107 1
            return;
108
        }
109
110 1
        $this->dockerCompose->command('down --remove-orphans')->realTime()->perform();
111 1
    }
112
113
    /**
114
     * Restart Porter containers.
115
     *
116
     * @param string|null $service
117
     */
118 2
    public function restart($service = null)
119
    {
120 2
        if ($this->isUp($service)) {
121
            $this->stop($service);
122
        }
123
124
        // If we're restarting something it's probably because config changed - so force recreation
125 2
        $this->start($service, true);
126 2
    }
127
128
    /**
129
     * Restart serving, picking up changes in used PHP versions and NGiNX.
130
     */
131 1
    public function restartServing()
132
    {
133
        // Build up docker-compose again - so we pick up any new PHP containers to be used
134 1
        $this->compose();
135
136 1
        if (!$this->isUp()) {
137
            return;
138
        }
139
140 1
        PhpVersion::active()
141 1
            ->get()
142
            ->reject(function ($phpVersion) {
143 1
                return $this->isUp($phpVersion->fpm_name);
144 1
            })
145
            ->each(function ($phpVersion) {
146 1
                $this->start($phpVersion->fpm_name);
147 1
                $this->start($phpVersion->cli_name);
148 1
            });
149
150 1
        $this->restart('nginx');
151 1
    }
152
153
    /**
154
     * Turn a service on.
155
     *
156
     * @param string $service
157
     */
158 2
    public function turnOnService($service)
159
    {
160 2
        if (setting("use_{$service}") == 'on') {
161 1
            return;
162
        }
163
164 1
        Setting::updateOrCreate("use_{$service}", 'on');
165
166 1
        $this->compose();
167
168 1
        if ($this->isUp()) {
169 1
            $this->start($service);
170
        }
171 1
    }
172
173
    /**
174
     * Turn a service off.
175
     *
176
     * @param string $service
177
     */
178 2
    public function turnOffService($service)
179
    {
180 2
        if (in_array(setting("use_{$service}"), [null, 'off'])) {
181 1
            return;
182
        }
183
184 1
        Setting::updateOrCreate("use_{$service}", 'off');
185
186 1
        if ($this->isUp()) {
187 1
            $this->stop($service);
188
        }
189 1
        $this->compose();
190 1
    }
191
192
    /**
193
     * (Re)build Porter containers.
194
     */
195 1
    public function build()
196
    {
197 1
        $this->dockerCompose->command('build')->perform();
198 1
    }
199
200
    /**
201
     * Build the current images.
202
     *
203
     * @param string|null $service
204
     */
205 3
    public function buildImages($service = null)
206
    {
207 3
        foreach ($this->getDockerImageSet()->findByServiceName($service, $firstPartyOnly = true) as $image) {
208
            /* @var Image $image */
209 2
            $this->cli->passthru("docker build -t {$image->getName()} --rm {$image->getLocalPath()} --");
210
        }
211 3
    }
212
213
    /**
214
     * Push the current images.
215
     *
216
     * @param string|null $service
217
     */
218 3
    public function pushImages($service = null)
219
    {
220 3
        foreach ($this->getDockerImageSet()->findByServiceName($service, $firstPartyOnly = true) as $image) {
221
            /* @var Image $image */
222 2
            $this->cli->passthru("docker push {$image->getName()}");
223
        }
224 3
    }
225
226
    /**
227
     * Pull our docker images.
228
     *
229
     * @param string|null $service
230
     */
231 3
    public function pullImages($service = null)
232
    {
233 3
        foreach ($this->getDockerImageSet()->findByServiceName($service) as $image) {
234
            /** @var Image $image */
235 3
            if (running_tests() && $this->hasImage($image)) {
236
                continue;
237
            }
238
239 3
            $this->cli->passthru("docker pull {$image->getName()}");
240
        }
241 3
    }
242
243
    /**
244
     * Check if we already have the image.
245
     *
246
     * @param Image $image
247
     *
248
     * @return bool
249
     */
250 3
    public function hasImage(Image $image)
251
    {
252 3
        $output = $this->cli->exec("docker image inspect {$image->getName()}");
253
254 3
        return strpos($output, "Error: No such image: {$image->getName()}") === false;
255
    }
256
257
    /**
258
     * Get the current image set to use.
259
     *
260
     * @return ImageRepository
261
     */
262 13
    public function getDockerImageSet()
263
    {
264 13
        return $this->imageSets->getImageRepository(
265 13
            setting('docker_image_set', config('porter.default-docker-image-set'))
266
        );
267
    }
268
269
    /**
270
     * Show container status.
271
     */
272 1
    public function status()
273
    {
274 1
        echo $this->dockerCompose->command('ps')->perform();
275 1
    }
276
277
    /**
278
     * Show container logs.
279
     *
280
     * @param string|null $service
281
     */
282 1
    public function logs($service = null)
283
    {
284 1
        echo $this->dockerCompose->command("logs {$service}")->perform();
285 1
    }
286
}
287