Passed
Push — master ( 2227df...4fbc87 )
by Robin
02:09
created

PorterLibrary::createDirectoryStructure()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 0
crap 3
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 122
    public function __construct(FilePublisher $filePublisher, Mechanic $mechanic, $path)
42
    {
43 122
        $this->filePublisher = $filePublisher;
44 122
        $this->files = $filePublisher->getFilesystem();
45 122
        $this->path = $path;
46 122
        $this->mechanic = $mechanic;
47 122
    }
48
49
    /**
50
     * Return the path for storing container config files.
51
     *
52
     * @return string
53
     */
54 122
    public function configPath()
55
    {
56 122
        return $this->path.'/config';
57
    }
58
59
    /**
60
     * Return the path of the database file.
61
     *
62
     * @return string
63
     */
64 122
    public function databaseFile()
65
    {
66 122
        return $this->path.'/database.sqlite';
67
    }
68
69
    /**
70
     * Return the path of the docker-compose file.
71
     *
72
     * @return string
73
     */
74 16
    public function dockerComposeFile()
75
    {
76 16
        return $this->path.'/docker-compose.yaml';
77
    }
78
79
    /**
80
     * Return the path of additional docker images.
81
     *
82
     * @return string
83
     */
84 122
    public function dockerImagesPath()
85
    {
86 122
        return $this->path.'/image-sets';
87
    }
88
89
    /**
90
     * Return the path where our generated SSL certs live.
91
     *
92
     * @return string
93
     */
94 122
    public function sslPath()
95
    {
96 122
        return $this->path.'/ssl';
97
    }
98
99
    /**
100
     * Return the library path.
101
     *
102
     * @return string
103
     */
104 7
    public function path()
105
    {
106 7
        return $this->path;
107
    }
108
109
    /**
110
     * Return the path for our additional/customised views
111
     * For example NGiNX config/ docker-compose views
112
     * for alternative container structures.
113
     *
114
     * @return string
115
     */
116 122
    public function viewsPath()
117
    {
118 122
        return $this->path.'/views';
119
    }
120
121
    /**
122
     * Check if the library has previously been set up.
123
     *
124
     * @return bool
125
     */
126 122
    public function alreadySetUp()
127
    {
128 122
        return $this->path && $this->files->exists($this->path);
129
    }
130
131
    /**
132
     * Set up the library, by creating files, storing the path in .env
133
     * creating the sqlite database and updating the app config.
134
     *
135
     * @param Application $app
136
     * @param bool        $force
137
     *
138
     * @throws PorterSetupFailed
139
     */
140 122
    public function setUp(Application $app, $force = false)
141
    {
142 122
        if ($this->alreadySetUp() && !$force) {
143
            throw new PorterSetupFailed(
144
                "The porter library already exists at '{$this->path}'. ".
145
                'You can use the --force flag to continue.'
146
            );
147
        }
148
149 122
        if (!$this->path) {
150 1
            $this->path = $this->mechanic->getUserHomePath().'/.porter';
151
152 1
            $this->moveExistingConfig();
153 1
            $this->publishEnv();
154 1
            $this->updateEnv();
155
        }
156
157 122
        if (!$this->path) {
158
            throw new PorterSetupFailed('Failed detecting and setting the library path for Porter.');
159
        }
160
161 122
        $this->publishConfigFiles();
162 122
        $this->createDirectoryStructure();
163 122
        $this->createDatabase();
164 122
        $this->updateAppConfig($app);
165
166 122
        if ($this->shouldMigrateAndSeedDatabase) {
167 1
            Artisan::call('migrate:fresh');
168 1
            Artisan::call('db:seed');
169
        }
170
171 122
        $app->instance(self::class, $this);
172 122
    }
173
174
    /**
175
     * Publish the .env.example file to .env.
176
     *
177
     * @throws PorterSetupFailed
178
     */
179 1
    protected function publishEnv()
180
    {
181
        try {
182 1
            $this->filePublisher->publish(base_path('.env.example'), base_path('.env'));
183
        } catch (\Exception $e) {
184
            throw new PorterSetupFailed('Failed publishing the .env file');
185
        }
186 1
    }
187
188
    /**
189
     * Move any existing config at the path to a backup directory
190
     * So we can avoid wiping out data/settings completely.
191
     */
192 1
    protected function moveExistingConfig()
193
    {
194 1
        if (!$this->alreadySetUp()) {
195
            return;
196
        }
197
198 1
        $this->files->moveDirectory($this->path, $this->path.'_'.now()->format('YmdHis'));
199 1
    }
200
201
    /**
202
     * Create the sqlite database.
203
     */
204 122
    protected function createDatabase()
205
    {
206 122
        $this->files->put($this->databaseFile(), '');
207 122
    }
208
209
    /**
210
     * Update the .env file values with the new library path.
211
     *
212
     * @throws PorterSetupFailed
213
     */
214 1
    protected function updateEnv()
215
    {
216
        try {
217 1
            $envContent = $this->files->get(base_path('.env'));
218 1
            $envContent = preg_replace('/LIBRARY_PATH=.*\n/', "LIBRARY_PATH=\"{$this->path}\"\n", $envContent);
219 1
            $this->files->put(base_path('.env'), $envContent);
220
        } catch (\Exception $e) {
221
            throw new PorterSetupFailed('Failed changing library path in the .env file', 0, $e);
222
        }
223 1
    }
224
225
    /**
226
     * Update core parts of the app config.
227
     *
228
     * @param Application $app
229
     */
230 122
    protected function updateAppConfig(Application $app)
231
    {
232 122
        $app['config']->set('database.connections.default.database', $this->databaseFile());
233 122
        $app['config']->set('porter.library_path', $this->path);
234 122
    }
235
236
    /**
237
     * Publish the container config files to the library config dir.
238
     *
239
     * @throws PorterSetupFailed
240
     */
241 122
    protected function publishConfigFiles()
242
    {
243
        try {
244 122
            $this->filePublisher->publish(resource_path('stubs/config'), $this->configPath());
245
        } catch (\Exception $e) {
246
            throw new PorterSetupFailed('Failed publishing the container configuration files');
247
        }
248 122
    }
249
250
    /**
251
     * Make sure we don't try to seed and migrate (usually in tests).
252
     *
253
     * @return $this
254
     */
255 122
    public function dontMigrateAndSeedDatabase()
256
    {
257 122
        $this->shouldMigrateAndSeedDatabase = false;
258
259 122
        return $this;
260
    }
261
262
    /**
263
     * Create the directory structure in the library path.
264
     */
265 122
    protected function createDirectoryStructure()
266
    {
267 122
        $directories = [$this->sslPath(), $this->viewsPath().'/nginx'];
268
269 122
        foreach ($directories as $directory) {
270 122
            if (!$this->files->isDirectory($directory)) {
271 122
                $this->files->makeDirectory($directory, 0755, true);
272
            }
273
        }
274 122
    }
275
}
276