Passed
Push — stable ( 4bc356...4bd7f3 )
by Nuno
04:37 queued 02:22
created

src/Commands/BuildCommand.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * This file is part of Laravel Zero.
7
 *
8
 * (c) Nuno Maduro <[email protected]>
9
 *
10
 *  For the full copyright and license information, please view the LICENSE
11
 *  file that was distributed with this source code.
12
 */
13
14
namespace LaravelZero\Framework\Commands;
15
16
use Illuminate\Support\Facades\File;
17
use Symfony\Component\Process\Process;
18
use Illuminate\Console\Application as Artisan;
19
use Symfony\Component\Console\Output\NullOutput;
20
use Symfony\Component\Console\Helper\ProgressBar;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Output\OutputInterface;
23
24
final class BuildCommand extends Command
25
{
26
    /**
27
     * {@inheritdoc}
28
     */
29
    protected $signature = 'app:build {name? : The build name}';
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    protected $description = 'Build a single file executable';
35
36
    /**
37
     * Holds the configuration on is original state.
38
     *
39
     * @var string|null
40
     */
41
    private static $config;
42
43
    /**
44
     * Holds the command original output.
45
     *
46
     * @var \Symfony\Component\Console\Output\OutputInterface
47
     */
48
    private $originalOutput;
49
50
    /**
51
     * {@inheritdoc}
52
     */
53 2
    public function handle()
54
    {
55 2
        $this->title('Building process');
56
57 2
        $this->build($this->input->getArgument('name') ?? $this->getBinary());
58 1
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 2
    public function run(InputInterface $input, OutputInterface $output)
64
    {
65 2
        parent::run($input, $this->originalOutput = $output);
66 1
    }
67
68
    /**
69
     * Builds the application into a single file.
70
     */
71 2
    private function build(string $name): BuildCommand
72
    {
73
        /*
74
         * We prepare the application for a build, moving it to production. Then,
75
         * after compile all the code to a single file, we move the built file
76
         * to the builds folder with the correct permissions.
77
         */
78 2
        $this->prepare()
79 2
            ->compile($name)
80 1
            ->clear();
81
82 1
        $this->output->writeln(
83 1
            sprintf('    Compiled successfully: <fg=green>%s</>', $this->app->buildsPath($name))
84
        );
85
86 1
        return $this;
87
    }
88
89 2
    private function compile(string $name): BuildCommand
90
    {
91 2
        if (! File::exists($this->app->buildsPath())) {
92 2
            File::makeDirectory($this->app->buildsPath());
93
        }
94
95 2
        $process = new Process(
96 2
            './box compile'.' --working-dir='.base_path().' --config='.base_path('box.json'),
0 ignored issues
show
'./box compile' . ' --wo.... base_path('box.json') of type string is incompatible with the type array expected by parameter $command of Symfony\Component\Process\Process::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
            /** @scrutinizer ignore-type */ './box compile'.' --working-dir='.base_path().' --config='.base_path('box.json'),
Loading history...
97 2
            dirname(dirname(__DIR__)).'/bin'
98
        );
99
100 2
        $section = tap($this->originalOutput->section())->write('');
101
102 2
        $progressBar = tap(
103 2
            new ProgressBar(
104 2
                $this->output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL ? new NullOutput() : $section, 25
105
            )
106 2
        )->setProgressCharacter("\xF0\x9F\x8D\xBA");
107
108 2
        foreach (tap($process)->start() as $type => $data) {
109 2
            $progressBar->advance();
110
111 2
            if ($this->output->getVerbosity() > OutputInterface::VERBOSITY_NORMAL) {
112 2
                $process::OUT === $type ? $this->info("$data") : $this->error("$data");
113
            }
114
        }
115
116 2
        $progressBar->finish();
117
118 2
        $section->clear();
119
120 1
        $this->task('   2. <fg=yellow>Compile</> into a single file');
121
122 1
        $this->output->newLine();
123
124 1
        File::move($this->app->basePath($this->getBinary()).'.phar', $this->app->buildsPath($name));
125
126 1
        return $this;
127
    }
128
129 2
    private function prepare(): BuildCommand
130
    {
131 2
        $file = $this->app->configPath('app.php');
132 2
        static::$config = File::get($file);
133 2
        $config = include $file;
134
135 2
        $config['production'] = true;
136
137 2
        $this->task(
138 2
            '   1. Moving application to <fg=yellow>production mode</>',
139
            function () use ($file, $config) {
140 2
                File::put($file, '<?php return '.var_export($config, true).';'.PHP_EOL);
141 2
            }
142
        );
143
144 2
        return $this;
145
    }
146
147 2
    private function clear(): BuildCommand
148
    {
149 2
        File::put($this->app->configPath('app.php'), static::$config);
150
151 2
        static::$config = null;
152
153 2
        return $this;
154
    }
155
156
    /**
157
     * Returns the artisan binary.
158
     */
159 2
    private function getBinary(): string
160
    {
161 2
        return str_replace("'", '', Artisan::artisanBinary());
162
    }
163
164
    /**
165
     * Makes sure that the `clear` is performed even
166
     * if the command fails.
167
     *
168
     * @return void
169
     */
170 30
    public function __destruct()
171
    {
172 30
        if (static::$config !== null) {
173 1
            $this->clear();
174
        }
175 30
    }
176
}
177