Passed
Pull Request — master (#27)
by Keoghan
04:06 queued 01:19
created

PorterLibrary::setUp()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8.6881

Importance

Changes 0
Metric Value
eloc 18
dl 0
loc 31
ccs 11
cts 19
cp 0.5789
rs 9.0444
c 0
b 0
f 0
cc 6
nc 7
nop 2
crap 8.6881
1
<?php
2
3
namespace App;
4
5
use App\Exceptions\PorterSetupFailed;
6
use App\Support\FilePublisher;
7
use App\Support\Mechanics\ChooseMechanic;
8
use Illuminate\Contracts\Foundation\Application;
9
use Illuminate\Filesystem\Filesystem;
10
use Illuminate\Support\Facades\Artisan;
11
12
class PorterLibrary
13
{
14
    /** @var string */
15
    protected $path;
16
17
    /** @var Filesystem */
18
    protected $files;
19
20
    /** @var \App\Support\FilePublisher **/
21
    protected $filePublisher;
22
23
    protected $shouldMigrateAndSeedDatabase = true;
24
25 54
    public function __construct(FilePublisher $filePublisher, $path)
26
    {
27 54
        $this->filePublisher = $filePublisher;
28 54
        $this->files = $filePublisher->getFilesystem();
29 54
        $this->path = $path;
30 54
    }
31
32
    /**
33
     * Return the path for storing container config files
34
     *
35
     * @return string
36
     */
37 54
    public function configPath()
38
    {
39 54
        return $this->path.'/config';
40
    }
41
42
    /**
43
     * Return the path of the database file
44
     *
45
     * @return string
46
     */
47 54
    public function databaseFile()
48
    {
49 54
        return $this->path.'/database.sqlite';
50
    }
51
52
    /**
53
     * Return the path of the docker-compose file
54
     *
55
     * @return string
56
     */
57 16
    public function dockerComposeFile()
58
    {
59 16
        return $this->path.'/docker-compose.yaml';
60
    }
61
62
    /**
63
     * Return the path of additional docker images
64
     *
65
     * @return string
66
     */
67 54
    public function dockerImagesPath()
68
    {
69 54
        return $this->path.'/docker';
70
    }
71
72
    /**
73
     * Return the path where our generated SSL certs live
74
     *
75
     * @return string
76
     */
77 6
    public function sslPath()
78
    {
79 6
        return $this->path.'/ssl';
80
    }
81
82
    /**
83
     * Return the library path
84
     *
85
     * @return string
86
     */
87 5
    public function path()
88
    {
89 5
        return $this->path;
90
    }
91
92
    /**
93
     * Return the path for our additional/customised views
94
     * For example NGiNX config/ docker-compose views
95
     * for alternative container structures
96
     *
97
     * @return string
98
     */
99 54
    public function viewsPath()
100
    {
101 54
        return $this->path.'/views';
102
    }
103
104
    /**
105
     * Check if the library has previously been set up
106
     *
107
     * @return bool
108
     */
109 54
    public function alreadySetUp()
110
    {
111 54
        return $this->path && $this->files->exists($this->path);
112
    }
113
114
    /**
115
     * Set up the library, by creating files, storing the path in .env
116
     * creating the sqlite database and updating the app config
117
     *
118
     * @param Application $app
119
     * @param bool $force
120
     * @throws PorterSetupFailed
121
     */
122 54
    public function setUp(Application $app, $force = false)
123
    {
124 54
        if ($this->alreadySetUp() && ! $force) {
125
            throw new PorterSetupFailed(
126
                "The porter library already exists at '{$this->path}'. ".
127
                "You can use the --force flag to continue."
128
            );
129
        }
130
131 54
        if (! $this->path) {
132
            $this->path = ChooseMechanic::forOS()->getUserHomePath().'/.porter';
133
134
            $this->moveExistingConfig();
135
            $this->publishEnv();
136
            $this->updateEnv();
137
        }
138
139 54
        if (! $this->path) {
140
            throw new PorterSetupFailed('Failed detecting and setting the library path for Porter.');
141
        }
142
143 54
        $this->publishConfigFiles();
144 54
        $this->createDatabase();
145 54
        $this->updateAppConfig($app);
146
147 54
        if ($this->shouldMigrateAndSeedDatabase) {
148 1
            Artisan::call('migrate:fresh');
149 1
            Artisan::call('db:seed');
150
        }
151
152 54
        $app->instance(PorterLibrary::class, $this);
153 54
    }
154
155
    /**
156
     * Publish the .env.example file to .env
157
     *
158
     * @throws PorterSetupFailed
159
     */
160
    protected function publishEnv()
161
    {
162
        try {
163
            $this->filePublisher->publish(base_path('.env.example'), base_path('.env'));
164
        } catch (\Exception $e) {
165
            throw new PorterSetupFailed('Failed publishing the .env file');
166
        }
167
    }
168
169
    /**
170
     * Move any existing config at the path to a backup directory
171
     * So we can avoid wiping out data/settings completely
172
     */
173
    protected function moveExistingConfig()
174
    {
175
        if (! $this->alreadySetUp()) {
176
            return;
177
        }
178
179
        $this->files->moveDirectory($this->path, $this->path.'_'.now()->format('YmdHis'));
180
    }
181
182
    /**
183
     * Create the sqlite database
184
     */
185 54
    protected function createDatabase()
186
    {
187 54
        $this->files->put($this->databaseFile(), '');
188 54
    }
189
190
    /**
191
     * Update the .env file values with the new library path
192
     *
193
     * @throws PorterSetupFailed
194
     */
195
    protected function updateEnv()
196
    {
197
        try {
198
            $envContent = $this->files->get(base_path('.env'));
199
            $envContent = preg_replace('/LIBRARY_PATH=.*\n/', "LIBRARY_PATH=\"{$this->path}\"\n", $envContent);
200
            $this->files->put(base_path('.env'), $envContent);
201
        } catch (\Exception $e) {
202
            throw new PorterSetupFailed('Failed changing library path in the .env file');
203
        }
204
    }
205
206
    /**
207
     * Update core parts of the app config
208
     *
209
     * @param Application $app
210
     */
211 54
    protected function updateAppConfig(Application $app)
212
    {
213 54
        $app['config']->set('database.connections.default.database', $this->databaseFile());
214 54
        $app['config']->set('porter.library_path', $this->path);
215 54
    }
216
217
    /**
218
     * Publish the container config files to the library config dir
219
     *
220
     * @throws PorterSetupFailed
221
     */
222 54
    protected function publishConfigFiles()
223
    {
224
        try {
225 54
            $this->filePublisher->publish(resource_path('stubs/config'), $this->configPath());
226
        } catch (\Exception $e) {
227
            throw new PorterSetupFailed('Failed publishing the container configuration files');
228
        }
229 54
    }
230
231
    /**
232
     * Make sure we don't try to seed and migrate (usually in tests)
233
     *
234
     * @return $this
235
     */
236 54
    public function dontMigrateAndSeedDatabase()
237
    {
238 54
        $this->shouldMigrateAndSeedDatabase = false;
239
240 54
        return $this;
241
    }
242
}
243