Completed
Push — master ( 8c5bee...33e30f )
by
unknown
06:57 queued 04:51
created

Bundle/SculpinBundle/Command/GenerateCommand.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is a part of Sculpin.
7
 *
8
 * (c) Dragonfly Development Inc.
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 Sculpin\Bundle\SculpinBundle\Command;
15
16
use Sculpin\Bundle\SculpinBundle\Console\Application;
17
use Sculpin\Bundle\SculpinBundle\HttpServer\HttpServer;
18
use Sculpin\Core\Io\ConsoleIo;
19
use Sculpin\Core\Io\IoInterface;
20
use Sculpin\Core\Sculpin;
21
use Sculpin\Core\Source\DataSourceInterface;
22
use Sculpin\Core\Source\SourceSet;
23
use Symfony\Component\Console\Helper\QuestionHelper;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\OutputInterface;
27
use Symfony\Component\Console\Question\ConfirmationQuestion;
28
use Symfony\Component\Filesystem\Exception\IOException;
29
use Twig\Error\LoaderError;
30
use Twig\Error\RuntimeError;
31
use Twig\Error\SyntaxError;
32
33
/**
34
 * Generate the site.
35
 *
36
 * @author Beau Simensen <[email protected]>
37
 */
38
class GenerateCommand extends AbstractCommand
39
{
40
    /**
41
     * @var bool
42
     */
43
    protected $throwExceptions;
44
45
    /**
46
     * {@inheritdoc}
47
     */
48
    protected function configure(): void
49
    {
50
        $prefix = $this->isStandaloneSculpin() ? '' : 'sculpin:';
51
52
        $this
53
            ->setName($prefix.'generate')
54
            ->setDescription('Generate a site from source.')
55
            ->setDefinition([
56
                new InputOption(
57
                    'clean',
58
                    null,
59
                    InputOption::VALUE_NONE,
60
                    'Cleans the output directory prior to generation.'
61
                ),
62
                new InputOption(
63
                    'watch',
64
                    null,
65
                    InputOption::VALUE_NONE,
66
                    'Watch source and regenerate site as changes are made.'
67
                ),
68
                new InputOption(
69
                    'server',
70
                    null,
71
                    InputOption::VALUE_NONE,
72
                    'Start an HTTP server to host your generated site'
73
                ),
74
                new InputOption('url', null, InputOption::VALUE_REQUIRED, 'Override URL.'),
75
                new InputOption('port', null, InputOption::VALUE_REQUIRED, 'Port'),
76
                new InputOption('output-dir', null, InputOption::VALUE_REQUIRED, 'Output Directory'),
77
                new InputOption('source-dir', null, InputOption::VALUE_REQUIRED, 'Source Directory'),
78
            ])
79
            ->setHelp(<<<EOT
80
The <info>generate</info> command generates a site.
81
82
EOT
83
            );
84
    }
85
86
    /**
87
     * {@inheritdoc}
88
     */
89
    protected function execute(InputInterface $input, OutputInterface $output): void
90
    {
91
        $application = $this->getApplication();
92
        if ($application instanceof Application) {
93
            foreach ($application->getMissingSculpinBundlesMessages() as $message) {
94
                $output->writeln($message);
95
            }
96
        }
97
98
        $writer  = $this->getContainer()->get('sculpin.writer');
99
        $docroot = $writer->getOutputDir();
100
        if ($input->getOption('clean')) {
101
            $this->clean($input, $output, $docroot);
102
        }
103
104
        $watch = $input->getOption('watch') ?: false;
105
        $sculpin = $this->getContainer()->get('sculpin');
106
        $dataSource = $this->getContainer()->get('sculpin.data_source');
107
        $sourceSet = new SourceSet();
108
109
        $config = $this->getContainer()->get('sculpin.site_configuration');
110
        if ($url = $input->getOption('url')) {
111
            $config->set('url', $url);
112
        }
113
114
        $consoleIo = new ConsoleIo($input, $output, $this->getApplication()->getHelperSet());
0 ignored issues
show
The call to ConsoleIo::__construct() has too many arguments starting with $this->getApplication()->getHelperSet().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
115
116
        if ($input->getOption('server')) {
117
            $this->throwExceptions = false;
118
            $output->isDebug();
119
            $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo);
120
121
            $kernel = $this->getContainer()->get('kernel');
122
123
            $httpServer = new HttpServer(
124
                $output,
125
                $docroot,
126
                $kernel->getEnvironment(),
127
                $kernel->isDebug(),
128
                (int) $input->getOption('port')
129
            );
130
131
            if ($watch) {
132
                $httpServer->addPeriodicTimer(1, function () use ($sculpin, $dataSource, $sourceSet, $consoleIo) {
133
                    clearstatcache();
134
                    $sourceSet->reset();
135
136
                    $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo);
137
                });
138
            }
139
140
            $httpServer->run();
141
        } else {
142
            $this->throwExceptions = !$watch;
143
            do {
144
                $this->runSculpin($sculpin, $dataSource, $sourceSet, $consoleIo);
145
146
                if ($watch) {
147
                    sleep(2);
148
                    clearstatcache();
149
                    $sourceSet->reset();
150
                }
151
            } while ($watch);
152
        }
153
    }
154
155
    /**
156
     * Cleanup an output directory by deleting it.
157
     *
158
     * @param string $dir The directory to remove
159
     */
160
    private function clean(InputInterface $input, OutputInterface $output, string $dir): void
161
    {
162
        $fileSystem = $this->getContainer()->get('filesystem');
163
164
        if ($fileSystem->exists($dir)) {
165
            if ($input->isInteractive()) {
166
                // Prompt the user for confirmation.
167
                /** @var QuestionHelper $helper */
168
                $helper = $this->getHelper('question');
169
                $question = new ConfirmationQuestion(sprintf(
170
                    'Are you sure you want to delete all the contents of the %s directory?',
171
                    $dir
172
                ), false);
173
174
                if (!$helper->ask($input, $output, $question)) {
175
                    return;
176
                }
177
            }
178
179
            $output->writeln(sprintf('Deleting %s', $dir));
180
            $fileSystem->remove($dir);
181
        }
182
    }
183
184
    /**
185
     * @throws \Throwable
186
     */
187
    protected function runSculpin(
188
        Sculpin $sculpin,
189
        DataSourceInterface $dataSource,
190
        SourceSet $sourceSet,
191
        IoInterface $io
192
    ) {
193
        $messages = [];
194
        $errPrint = function (\Exception $e) {
195
            return $e->getMessage().PHP_EOL.' at '.str_replace(getcwd().DIRECTORY_SEPARATOR, '', $e->getFile());
196
        };
197
198
        try {
199
            $sculpin->run($dataSource, $sourceSet, $io);
200
201
            return;
202
        } catch (LoaderError | RuntimeError | SyntaxError $e) {
203
            $messages[] = '<error>Twig exception: ' . $errPrint($e) . '</error>';
204
        } catch (IOException $e) {
205
            $messages[] = '<error>Filesystem exception: ' . $errPrint($e) . '</error>';
206
        } catch (\Throwable $e) {
207
            $messages[] = '<error>Exception: ' . $errPrint($e) . '</error>';
208
        }
209
210
        if ($this->throwExceptions) {
211
            throw $e;
212
        }
213
214
        if ($io->isDebug()) {
215
            $messages[] = '<comment>Exception trace:</comment>';
216
217
            foreach ($e->getTrace() as $trace) {
218
                $messages[] = sprintf(
219
                    '<comment>  %s at %s:%s</comment>',
220
                    isset($trace['class']) ? $trace['class'] . '->' . $trace['function'] : $trace['function'],
221
                    $trace['file'],
222
                    $trace['line']
223
                );
224
            }
225
        }
226
227
        $io->write('<error>[FAILED]</error>');
228
        foreach ($messages as $message) {
229
            $io->write($message);
230
        }
231
        $io->write('');
232
    }
233
}
234