PorterLibrary   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 286
Duplicated Lines 0 %

Test Coverage

Coverage 86.84%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 32
eloc 66
dl 0
loc 286
ccs 66
cts 76
cp 0.8684
rs 9.84
c 2
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A updateEnv() 0 8 2
A createDatabase() 0 3 1
A viewsPath() 0 3 1
A alreadySetUp() 0 3 2
A databaseFile() 0 3 1
A updateAppConfig() 0 4 1
A moveExistingConfig() 0 7 2
A dontMigrateAndSeedDatabase() 0 5 1
A configPath() 0 3 1
A dockerImagesPath() 0 3 1
A createDirectoryStructure() 0 7 3
A publishEnv() 0 6 2
A path() 0 3 1
A getMechanic() 0 3 1
A dockerComposeFile() 0 3 1
A sslPath() 0 3 1
A setMechanic() 0 5 1
A publishConfigFiles() 0 6 2
A setUp() 0 32 6
1
<?php
2
3
namespace App;
4
5
use App\Exceptions\PorterSetupFailed;
6
use App\Support\FilePublisher;
7
use App\Support\Mechanics\Mechanic;
8
use Illuminate\Contracts\Foundation\Application;
9
use Illuminate\Filesystem\Filesystem;
10
use Illuminate\Support\Facades\Artisan;
11
12
class PorterLibrary
13
{
14
    /**
15
     * The path of the Porter library directory (e.g. ~/.porter on Mac).
16
     *
17
     * @var string
18
     */
19
    protected $path;
20
21
    /**
22
     * The system's filesystem.
23
     *
24
     * @var Filesystem
25
     */
26
    protected $files;
27
28
    /**
29
     * The file publisher.
30
     *
31
     * @var \App\Support\FilePublisher
32
     */
33
    protected $filePublisher;
34
35
    protected $shouldMigrateAndSeedDatabase = true;
36
    /**
37
     * @var Mechanic
38
     */
39
    private $mechanic;
40
41 210
    public function __construct(FilePublisher $filePublisher, Mechanic $mechanic, $path)
42
    {
43 210
        $this->filePublisher = $filePublisher;
44 210
        $this->files = $filePublisher->getFilesystem();
45 210
        $this->path = $path;
46 210
        $this->mechanic = $mechanic;
47
    }
48
49
    /**
50
     * Set the Mechanic instance.
51
     *
52
     * @param Mechanic $mechanic
53
     *
54
     * @return $this
55
     */
56 8
    public function setMechanic(Mechanic $mechanic)
57
    {
58 8
        $this->mechanic = $mechanic;
59
60 8
        return $this;
61
    }
62
63
    /**
64
     * Return the path for storing container config files.
65
     *
66
     * @return string
67
     */
68 210
    public function configPath()
69
    {
70 210
        return $this->path.'/config';
71
    }
72
73
    /**
74
     * Return the path of the database file.
75
     *
76
     * @return string
77
     */
78 210
    public function databaseFile()
79
    {
80 210
        return $this->path.'/database.sqlite';
81
    }
82
83
    /**
84
     * Return the path of the docker-compose file.
85
     *
86
     * @return string
87
     */
88 18
    public function dockerComposeFile()
89
    {
90 18
        return $this->path.'/docker-compose.yaml';
91
    }
92
93
    /**
94
     * Return the path of additional docker images.
95
     *
96
     * @return string
97
     */
98 210
    public function dockerImagesPath()
99
    {
100 210
        return $this->path.'/image-sets';
101
    }
102
103
    /**
104
     * Return the path where our generated SSL certs live.
105
     *
106
     * @return string
107
     */
108 210
    public function sslPath()
109
    {
110 210
        return $this->path.'/ssl';
111
    }
112
113
    /**
114
     * Return the library path.
115
     *
116
     * @return string
117
     */
118 10
    public function path()
119
    {
120 10
        return $this->path;
121
    }
122
123
    /**
124
     * Return the path for our additional/customised views
125
     * For example NGiNX config/ docker-compose views
126
     * for alternative container structures.
127
     *
128
     * @return string
129
     */
130 210
    public function viewsPath()
131
    {
132 210
        return $this->path.'/views';
133
    }
134
135
    /**
136
     * Check if the library has previously been set up.
137
     *
138
     * @return bool
139
     */
140 210
    public function alreadySetUp()
141
    {
142 210
        return $this->path && $this->files->exists($this->path);
143
    }
144
145
    /**
146
     * Set up the library, by creating files, storing the path in .env
147
     * creating the sqlite database and updating the app config.
148
     *
149
     * @param Application $app
150
     * @param bool        $force
151
     *
152
     * @throws PorterSetupFailed
153
     */
154 210
    public function setUp(Application $app, $force = false)
155
    {
156 210
        if ($this->alreadySetUp() && !$force) {
157
            throw new PorterSetupFailed(
158
                "The porter library already exists at '{$this->path}'. ".
159
                'You can use the --force flag to continue.'
160
            );
161
        }
162
163 210
        if (!$this->path) {
164 1
            $this->path = $this->mechanic->getUserHomePath().'/.porter';
165
166 1
            $this->moveExistingConfig();
167 1
            $this->publishEnv();
168 1
            $this->updateEnv();
169
        }
170
171 210
        if (!$this->path) {
172
            throw new PorterSetupFailed('Failed detecting and setting the library path for Porter.');
173
        }
174
175 210
        $this->publishConfigFiles();
176 210
        $this->createDirectoryStructure();
177 210
        $this->createDatabase();
178 210
        $this->updateAppConfig($app);
179
180 210
        if ($this->shouldMigrateAndSeedDatabase) {
181 1
            Artisan::call('migrate:fresh');
182 1
            Artisan::call('db:seed');
183
        }
184
185 210
        $app->instance(self::class, $this);
186
    }
187
188
    /**
189
     * Publish the .env.example file to .env.
190
     *
191
     * @throws PorterSetupFailed
192
     */
193 1
    protected function publishEnv()
194
    {
195
        try {
196 1
            $this->filePublisher->publish(base_path('.env.example'), base_path('.env'));
197
        } catch (\Exception $e) {
198
            throw new PorterSetupFailed('Failed publishing the .env file');
199
        }
200
    }
201
202
    /**
203
     * Move any existing config at the path to a backup directory
204
     * So we can avoid wiping out data/settings completely.
205
     */
206 1
    protected function moveExistingConfig()
207
    {
208 1
        if (!$this->alreadySetUp()) {
209
            return;
210
        }
211
212 1
        $this->files->moveDirectory($this->path, $this->path.'_'.now()->format('YmdHis'));
213
    }
214
215
    /**
216
     * Create the sqlite database.
217
     */
218 210
    protected function createDatabase()
219
    {
220 210
        $this->files->put($this->databaseFile(), '');
221
    }
222
223
    /**
224
     * Update the .env file values with the new library path.
225
     *
226
     * @throws PorterSetupFailed
227
     */
228 1
    protected function updateEnv()
229
    {
230
        try {
231 1
            $envContent = $this->files->get(base_path('.env'));
232 1
            $envContent = preg_replace('/LIBRARY_PATH=.*\n/', "LIBRARY_PATH=\"{$this->path}\"\n", $envContent);
233 1
            $this->files->put(base_path('.env'), $envContent);
234
        } catch (\Exception $e) {
235
            throw new PorterSetupFailed('Failed changing library path in the .env file', 0, $e);
236
        }
237
    }
238
239
    /**
240
     * Update core parts of the app config.
241
     *
242
     * @param Application $app
243
     */
244 210
    protected function updateAppConfig(Application $app)
245
    {
246 210
        $app['config']->set('database.connections.sqlite.database', $this->databaseFile());
247 210
        $app['config']->set('porter.library_path', $this->path);
248
    }
249
250
    /**
251
     * Publish the container config files to the library config dir.
252
     *
253
     * @throws PorterSetupFailed
254
     */
255 210
    protected function publishConfigFiles()
256
    {
257
        try {
258 210
            $this->filePublisher->publish(resource_path('stubs/config'), $this->configPath());
259
        } catch (\Exception $e) {
260
            throw new PorterSetupFailed('Failed publishing the container configuration files');
261
        }
262
    }
263
264
    /**
265
     * Make sure we don't try to seed and migrate (usually in tests).
266
     *
267
     * @return $this
268
     */
269 210
    public function dontMigrateAndSeedDatabase()
270
    {
271 210
        $this->shouldMigrateAndSeedDatabase = false;
272
273 210
        return $this;
274
    }
275
276
    /**
277
     * Create the directory structure in the library path.
278
     */
279 210
    protected function createDirectoryStructure()
280
    {
281 210
        $directories = [$this->sslPath(), $this->viewsPath().'/nginx'];
282
283 210
        foreach ($directories as $directory) {
284 210
            if (!$this->files->isDirectory($directory)) {
285 210
                $this->files->makeDirectory($directory, 0755, true);
286
            }
287
        }
288
    }
289
290
    /**
291
     * Return the Mechanic instance.
292
     *
293
     * @return Mechanic
294
     */
295 9
    public function getMechanic()
296
    {
297 9
        return $this->mechanic;
298
    }
299
}
300