TraefikCreator::dotEnvProdSubstitution()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 0
dl 0
loc 21
rs 9.8666
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Cocotte\Template\Traefik;
4
5
use Cocotte\Console\Style;
6
use Cocotte\Filesystem\Filesystem;
7
use Cocotte\Shell\BasicAuth;
8
use Cocotte\Shell\EnvironmentSubstitution\EnvironmentSubstitution;
9
use Cocotte\Shell\EnvironmentSubstitution\SubstitutionFactory;
10
use Cocotte\Shell\ProcessRunner;
11
use Symfony\Component\Process\Process;
12
13
final class TraefikCreator
14
{
15
16
    /**
17
     * @var Style
18
     */
19
    private $style;
20
21
    /**
22
     * @var ProcessRunner
23
     */
24
    private $processRunner;
25
26
    /**
27
     * @var Filesystem
28
     */
29
    private $filesystem;
30
31
    /**
32
     * @var SubstitutionFactory
33
     */
34
    private $substitutionFactory;
35
36
    /**
37
     * @var TraefikHostname
38
     */
39
    private $traefikHostname;
40
41
    /**
42
     * @var TraefikPassword
43
     */
44
    private $traefikPassword;
45
46
    /**
47
     * @var TraefikUsername
48
     */
49
    private $traefikUsername;
50
51
    /**
52
     * @var BasicAuth
53
     */
54
    private $basicAuth;
55
56
    /**
57
     * @var string
58
     */
59
    private $tmpTemplatePath;
60
61
    public function __construct(
62
        Style $style,
63
        ProcessRunner $processRunner,
64
        Filesystem $filesystem,
65
        SubstitutionFactory $substitutionFactory,
66
        TraefikHostname $traefikHostname,
67
        TraefikPassword $traefikPassword,
68
        TraefikUsername $traefikUsername,
69
        BasicAuth $basicAuth
70
    ) {
71
        $this->style = $style;
72
        $this->processRunner = $processRunner;
73
        $this->filesystem = $filesystem;
74
        $this->substitutionFactory = $substitutionFactory;
75
        $this->traefikHostname = $traefikHostname;
76
        $this->traefikPassword = $traefikPassword;
77
        $this->traefikUsername = $traefikUsername;
78
        $this->basicAuth = $basicAuth;
79
        $this->tmpTemplatePath = "/tmp/".uniqid('traefik-');
80
    }
81
82
    public function create()
83
    {
84
        $this->backup();
85
        $this->copyTemplateToTmp();
86
        $this->removeIgnoredFiles();
87
        $this->createDockerComposeOverride();
88
        $this->createDotEnv();
89
        $this->copyTmpToHost();
90
    }
91
92
    public function hostAppPath(): string
93
    {
94
        return "/host/traefik";
95
    }
96
97
    private function backup(): void
98
    {
99
        $this->style->verbose('Backup');
100
        if ($this->filesystem->exists($this->hostAppPath())) {
101
            $this->style->note("Backing up old 'traefik' folder on host filesystem");
102
            $this->mustRun(
103
                [
104
                    'mv',
105
                    '-v',
106
                    $this->hostAppPath(),
107
                    $this->hostAppPath().'.'.date("YmdHis"),
108
                ]
109
            );
110
        } else {
111
            $this->style->veryVerbose('No backup was necessary');
112
        }
113
    }
114
115
    private function copyTemplateToTmp(): void
116
    {
117
        $this->style->verbose('Copy template to tmp directory');
118
        $this->cleanUpTmp();
119
        $this->mustRun(
120
            [
121
                'rsync',
122
                '-rv',
123
                $this->installerTemplatePath().'/',
124
                $this->tmpTemplatePath(),
125
            ]
126
        );
127
        $this->mustRun(['mv', '-v', $this->tmpTemplatePath(), $this->tmpAppPath()]);
128
    }
129
130
    private function removeIgnoredFiles(): void
131
    {
132
        $this->style->verbose('Remove ignored files (needed when developing only)');
133
        $this->mustRun(
134
            [
135
                'rm',
136
                '-fv',
137
                $this->tmpAppPath()."/.env",
138
                $this->tmpAppPath()."/.env-override",
139
                $this->tmpAppPath()."/docker-compose.override.yml",
140
            ]
141
        );
142
    }
143
144
    private function createDockerComposeOverride(): void
145
    {
146
        $this->style->verbose('Create ignored docker-compose.override.yml from dist');
147
        $this->mustRun(
148
            [
149
                'cp',
150
                '-v',
151
                $this->tmpAppPath()."/docker-compose.override.yml.dist",
152
                $this->tmpAppPath()."/docker-compose.override.yml",
153
            ]
154
        );
155
    }
156
157
    private function createDotEnv(): void
158
    {
159
        $this->style->verbose("Create '.env' and '.env-override' from command options + env");
160
161
        $this->createDotEnvProd();
162
        $this->createDotEnvDev();
163
    }
164
165
    private function copyTmpToHost(): void
166
    {
167
        $this->style->verbose('Copy tmp to host filesystem');
168
        $this->mustRun(
169
            [
170
                'rsync',
171
                '-rv',
172
                $this->tmpAppPath(),
173
                '/host',
174
            ]
175
        );
176
        $this->cleanUpTmp();
177
    }
178
179
    private function mustRun($command)
180
    {
181
        $this->processRunner->mustRun(new Process($command));
182
    }
183
184
    private function cleanUpTmp(): void
185
    {
186
        $this->mustRun(['rm', '-rfv', $this->tmpAppPath()]);
187
        $this->mustRun(['rm', '-rfv', $this->tmpTemplatePath()]);
188
    }
189
190
    private function tmpAppPath(): string
191
    {
192
        return "/tmp/traefik";
193
    }
194
195
    private function tmpTemplatePath(): string
196
    {
197
        return $this->tmpTemplatePath;
198
    }
199
200
    private function installerTemplatePath(): string
201
    {
202
        return "/installer/template/traefik";
203
    }
204
205
    private function createDotEnvProd(): void
206
    {
207
        EnvironmentSubstitution::withDefaults()
208
            ->restrict(
209
                [
210
                    'TRAEFIK_UI_HOSTNAME',
211
                    'TRAEFIK_ACME_EMAIL',
212
                    'MACHINE_NAME',
213
                    'MACHINE_STORAGE_PATH',
214
                ]
215
            )
216
            ->substitute($this->dotEnvProdSubstitution());
217
    }
218
219
    private function createDotEnvDev(): void
220
    {
221
        EnvironmentSubstitution::withDefaults()
222
            ->export(
223
                [
224
                    'APP_HOSTS' => $this->traefikHostname->toLocal()->toString(),
225
                ]
226
            )->substitute(
227
                $this->substitutionFactory->dumpFile(
228
                    $this->tmpAppPath().'/.env-override',
229
                    EnvironmentSubstitution::formatEnvFile(
230
                        [
231
                            'APP_HOSTS="${APP_HOSTS}"',
232
                        ]
233
                    )
234
                )
235
            );
236
    }
237
238
    /**
239
     * @return \Cocotte\Shell\EnvironmentSubstitution\DumpFileSubstitution
240
     */
241
    private function dotEnvProdSubstitution(): \Cocotte\Shell\EnvironmentSubstitution\DumpFileSubstitution
242
    {
243
        $basicAuth = $this->basicAuth->generate(
244
            $this->traefikUsername->toString(),
245
            $this->traefikPassword->toString()
246
        );
247
248
        $substitutionStrategy = $this->substitutionFactory->dumpFile(
249
            $this->tmpAppPath().'/.env',
250
            EnvironmentSubstitution::formatEnvFile(
251
                [
252
                    'APP_HOSTS="${TRAEFIK_UI_HOSTNAME}"',
253
                    "APP_AUTH_BASIC='{$basicAuth}'",
254
                    'ACME_EMAIL="${TRAEFIK_ACME_EMAIL}"',
255
                    'MACHINE_NAME="${MACHINE_NAME}"',
256
                    'MACHINE_STORAGE_PATH="${MACHINE_STORAGE_PATH}"',
257
                ]
258
            )
259
        );
260
261
        return $substitutionStrategy;
262
    }
263
}