linux-questionnaire/src/Questionnaire/Command/GenerateReadmeCommand.php
2015-03-02 20:07:17 +01:00

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
));
}
}
}