Passed
Pull Request — master (#52)
by Robin
04:04
created

PorterLibrary::dockerComposeFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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