Test Failed
Pull Request — stable (#106)
by Nuno
01:47
created

Builder::compile()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 4
nop 1
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
namespace LaravelZero\Framework\Commands\App;
4
5
use Phar;
6
use FilesystemIterator;
7
use UnexpectedValueException;
8
use LaravelZero\Framework\Commands\Command;
9
10
/**
11
 * This is the Laravel Zero Framework builder command class.
12
 *
13
 * @author Nuno Maduro <[email protected]>
14
 */
15
class Builder extends Command
16
{
17
    /**
18
     * The directory that contains your application builds.
19
     */
20
    const BUILD_PATH = BASE_PATH.DIRECTORY_SEPARATOR.'builds';
21
22
    /**
23
     * Contains the default app structure.
24
     *
25
     * @var []string
26
     */
27
    protected $structure = [
28
        'app'.DIRECTORY_SEPARATOR,
29
        'bootstrap'.DIRECTORY_SEPARATOR,
30
        'vendor'.DIRECTORY_SEPARATOR,
31
        'config'.DIRECTORY_SEPARATOR,
32
    ];
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    protected $signature = 'app:build {name=application : The build name}';
38
39
    /**
40
     * {@inheritdoc}
41
     */
42
    protected $description = 'Perform an application build';
43
44
    /**
45
     * Holds the configuration on is original state.
46
     *
47
     * @var string
48
     */
49
    protected static $config;
50
51
    /**
52
     * {@inheritdoc}
53
     */
54
    public function handle(): void
55
    {
56
        $this->alert('Building the application...');
57
58
        if (Phar::canWrite()) {
59
            $this->build($this->input->getArgument('name') ?: self::BUILD_NAME);
60
        } else {
61
            $this->error(
62
                'Unable to compile a phar because of php\'s security settings. '.'phar.readonly must be disabled in php.ini. '.PHP_EOL.PHP_EOL.'You will need to edit '.php_ini_loaded_file(
63
                ).' and add or set'.PHP_EOL.PHP_EOL.'    phar.readonly = Off'.PHP_EOL.PHP_EOL.'to continue. Details here: http://php.net/manual/en/phar.configuration.php'
64
            );
65
        }
66
    }
67
68
    /**
69
     * Builds the application.
70
     *
71
     * @param string $name
72
     *
73
     * @return $this
74
     */
75
    protected function build(string $name): Builder
76
    {
77
        $this->prepare()
78
            ->compile($name)
79
            ->cleanUp($name)
80
            ->setPermissions($name)
81
            ->finish();
82
83
        $this->info('Standalone application compiled into: builds'.DIRECTORY_SEPARATOR.$name);
84
85
        return $this;
86
    }
87
88
    /**
89
     * Compiles the standalone application.
90
     *
91
     * @param string $name
92
     *
93
     * @return $this
94
     */
95
    protected function compile(string $name): Builder
96
    {
97
        $this->info('Compiling code...');
98
99
        $compiler = $this->makeFolder()
100
            ->getCompiler($name);
101
102
        $structure = config('app.structure') ?: $this->structure;
103
        
104
        $regex = '#'.implode('|', $structure).'#';
105
106
        if (stristr(PHP_OS, 'WINNT') !== false) {
107
            $compiler->buildFromDirectory(BASE_PATH, str_replace('\\', '/', $regex));
108
        } else {
109
            // Linux, OS X
110
            $compiler->buildFromDirectory(BASE_PATH, $regex);
111
        }
112
        $compiler->setStub(
113
            "#!/usr/bin/env php \n".$compiler->createDefaultStub('bootstrap'.DIRECTORY_SEPARATOR.'init.php')
114
        );
115
116
        return $this;
117
    }
118
119
    /**
120
     * Gets a new instance of the compiler.
121
     *
122
     * @param string $name
123
     *
124
     * @return \Phar
125
     */
126
    protected function getCompiler(string $name): \Phar
127
    {
128
        try {
129
            return new Phar(
130
                self::BUILD_PATH.DIRECTORY_SEPARATOR.$name.'.phar',
131
                FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::KEY_AS_FILENAME,
132
                $name
133
            );
134
        } catch (UnexpectedValueException $e) {
135
            $this->error("You can't perform a build.");
136
            exit(0);
137
        }
138
    }
139
140
    /**
141
     * Creates the folder for the builds.
142
     *
143
     * @return $this
144
     */
145
    protected function makeFolder(): Builder
146
    {
147
        if (! file_exists(self::BUILD_PATH)) {
148
            mkdir(self::BUILD_PATH);
149
        }
150
151
        return $this;
152
    }
153
154
    /**
155
     * Moves the compiled files to the builds folder.
156
     *
157
     * @param string $name
158
     *
159
     * @return $this
160
     */
161
    protected function cleanUp(string $name): Builder
162
    {
163
        $file = self::BUILD_PATH.DIRECTORY_SEPARATOR.$name;
164
        rename("$file.phar", $file);
165
166
        return $this;
167
    }
168
169
    /**
170
     * Sets the executable mode on the standalone application file.
171
     *
172
     * @param string $name
173
     *
174
     * @return $this
175
     */
176
    protected function setPermissions($name): Builder
177
    {
178
        $file = self::BUILD_PATH.DIRECTORY_SEPARATOR.$name;
179
        chmod($file, 0755);
180
181
        return $this;
182
    }
183
184
    /**
185
     * Prepares the application for build.
186
     *
187
     * @return $this
188
     */
189
    protected function prepare(): Builder
190
    {
191
        $file = BASE_PATH.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'app.php';
192
        static::$config = file_get_contents($file);
193
        $config = include $file;
194
195
        $config['production'] = true;
196
197
        $this->info('Moving configuration to production mode...');
198
199
        file_put_contents($file, '<?php return '.var_export($config, true).';'.PHP_EOL);
200
201
        return $this;
202
    }
203
204
    /**
205
     * Prepares the application for build.
206
     *
207
     * @return $this
208
     */
209
    protected function finish(): Builder
210
    {
211
        file_put_contents(BASE_PATH.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'app.php', static::$config);
212
213
        static::$config = null;
214
215
        return $this;
216
    }
217
218
    /**
219
     * Makes sure that the finish is performed even
220
     * if the command fails.
221
     */
222
    public function __destruct()
223
    {
224
        if (static::$config !== null) {
225
            file_put_contents(BASE_PATH.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'app.php', static::$config);
226
        }
227
    }
228
}
229