230 lines
6.1 KiB
PHP
230 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace Questionnaire\Command;
|
|
|
|
use Knp\Command\Command;
|
|
|
|
use Symfony\Component\Console\Input\InputArgument;
|
|
use Symfony\Component\Console\Input\InputInterface;
|
|
use Symfony\Component\Console\Output\OutputInterface;
|
|
use Symfony\Component\Console\Output\StreamOutput;
|
|
|
|
use Questionnaire\Parser\ReadmeParser;
|
|
|
|
class GenerateReadmeCommand extends Command
|
|
{
|
|
/**
|
|
* @var mixed
|
|
*/
|
|
protected $in;
|
|
|
|
/**
|
|
* @var OutputInterface
|
|
*/
|
|
protected $out;
|
|
|
|
/**
|
|
* @var boolean
|
|
*/
|
|
protected $closeOut;
|
|
|
|
protected function configure()
|
|
{
|
|
$this
|
|
->setName('generate:readme')
|
|
->setDescription(
|
|
'Generate the HTML readme from Markdown with tags replacement.'
|
|
)
|
|
;
|
|
|
|
|
|
$this->addArgument(
|
|
'in',
|
|
InputArgument::OPTIONAL,
|
|
'Markdown file to process, <info>README.*.md</info> by default, stdin if <info>-</info>.'
|
|
);
|
|
|
|
$outDefault = '<info>web/views/Questionnaire/readme.*.html.twig</info>';
|
|
|
|
$this->addArgument(
|
|
'out',
|
|
InputArgument::OPTIONAL,
|
|
'Output HTML file, '.$outDefault.' by default, stdout if <info>-</info>.'
|
|
);
|
|
}
|
|
|
|
protected function execute(InputInterface $input, OutputInterface $output)
|
|
{
|
|
if (empty($input->getArgument('in')) && empty($input->getArgument('out'))) {
|
|
$this->handleDefault($input, $output);
|
|
return;
|
|
}
|
|
|
|
$this->before($input, $output);
|
|
|
|
$app = $this->getSilexApplication();
|
|
$markdownParser = $app['markdown'];
|
|
$readmeParser = $app['readme.parser'];
|
|
|
|
$md = stream_get_contents($this->in);
|
|
$html = $markdownParser->transformMarkdown($md);
|
|
|
|
$html = sprintf(
|
|
'
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
</head>
|
|
<body>
|
|
%s
|
|
</body>
|
|
</html>
|
|
',
|
|
$html
|
|
);
|
|
|
|
$readmeParser->load($html);
|
|
$readmeParser->stream($this->out);
|
|
|
|
$this->after();
|
|
}
|
|
|
|
protected function before(InputInterface $input, OutputInterface $output)
|
|
{
|
|
$in = $input->getArgument('in');
|
|
$out = $input->getArgument('out');
|
|
|
|
if (empty($in) || empty($out)) {
|
|
throw new \InvalidArgumentException('The `in` and `out` parameters must be provided together.');
|
|
}
|
|
|
|
if ($in === '-') {
|
|
$this->in = fopen('php://stdin', 'rb');
|
|
} else {
|
|
$this->validateFile($in, 'rb');
|
|
$this->in = fopen($in, 'rb');
|
|
}
|
|
|
|
if ($out === '-') {
|
|
$this->out = $output;
|
|
$this->closeOut = false;
|
|
} else {
|
|
try {
|
|
$this->validateFile($out, 'wb');
|
|
} catch (Exception $e) {
|
|
$this->clean();
|
|
throw $e;
|
|
}
|
|
|
|
$this->out = new StreamOutput(fopen($out, 'wb'));
|
|
$this->closeOut = true;
|
|
}
|
|
}
|
|
|
|
protected function after()
|
|
{
|
|
$this->clean();
|
|
}
|
|
|
|
protected function clean()
|
|
{
|
|
if (is_resource($this->in)) {
|
|
fclose($this->in);
|
|
}
|
|
|
|
if ($this->closeOut && is_resource($this->out->getStream())) {
|
|
fclose($this->out->getStream());
|
|
}
|
|
}
|
|
|
|
protected function handleDefault(InputInterface $input, OutputInterface $output)
|
|
{
|
|
$app = $this->getSilexApplication();
|
|
$dir = $this->getProjectDirectory();
|
|
|
|
$files = glob($dir.'/README.*.md');
|
|
|
|
if (empty($files)) {
|
|
throw new \InvalidArgumentException('No file was found matching `README.*.md`.');
|
|
}
|
|
|
|
foreach ($files as $file) {
|
|
/**
|
|
* Find the penultimate dot in string (assuming it ends with `\..{2}`).
|
|
*
|
|
* strrpos($input, '.', -4);
|
|
*
|
|
* Cut the filename from the penultimate dot plus 1 (don't include
|
|
* the dot in the final string) until the end of the string minus 3
|
|
* (don't take the last 3 characters).
|
|
*
|
|
* So, for `README.en.md`, this will extract `en`.
|
|
*
|
|
* For `README.en.markdown`, this will extract `markd` (stripping
|
|
* final `own`), because this will find the last dot instead of
|
|
* the penultimate dot.
|
|
*/
|
|
$lang = substr($file, strrpos($file, '.', -4) + 1, -3);
|
|
|
|
// Compote output file from input lang
|
|
$targets[] = $app['twig.path'].'/Questionnaire/readme.'.$lang.'.html.twig';
|
|
}
|
|
|
|
foreach ($files as $i => $file) {
|
|
$input->setArgument('in', $file);
|
|
$input->setArgument('out', $targets[$i]);
|
|
|
|
// Recursive execution for each file
|
|
$this->execute($input, $output);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param string $file
|
|
* @param string $mode
|
|
* @see fopen()
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
protected function validateFile($file, $mode)
|
|
{
|
|
$read = 'r' === $mode[0];
|
|
$write = in_array($mode[0], array('w', 'a', 'c'), true);
|
|
$create = $write;
|
|
|
|
if ($mode[1] === '+') {
|
|
if ($read) {
|
|
$write = true;
|
|
} elseif ($write) {
|
|
$read = true;
|
|
}
|
|
}
|
|
|
|
if (!is_file($file)) {
|
|
if ($create) {
|
|
// Let the file be created
|
|
return;
|
|
}
|
|
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'Given file "%s" does not exists.',
|
|
$file
|
|
));
|
|
}
|
|
|
|
if ($read && !is_readable($file)) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'Given file "%s" is not readable.',
|
|
$file
|
|
));
|
|
}
|
|
|
|
if ($write && !is_writable($file)) {
|
|
throw new \InvalidArgumentException(sprintf(
|
|
'Given file "%s" is not writable.',
|
|
$file
|
|
));
|
|
}
|
|
}
|
|
}
|