parent
07330c1ca9
commit
d446e0db2e
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
|
namespace Icinga\Module\Doc;
|
||||||
|
|
||||||
|
use ArrayIterator;
|
||||||
|
use RunetimeException;
|
||||||
|
|
||||||
|
class FileLockingIterator extends ArrayIterator
|
||||||
|
{
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->current()->flock(LOCK_UN);
|
||||||
|
parent::next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
if (!parent::valid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$fileInfo = $this->current();
|
||||||
|
try {
|
||||||
|
$fileObject = $fileInfo->openFile();
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
throw new DocException($e->getMessage());
|
||||||
|
}
|
||||||
|
if ($fileObject->flock(LOCK_SH) === false) {
|
||||||
|
throw new DocException('Couldn\'t get the lock');
|
||||||
|
}
|
||||||
|
$this[$this->key()] = $fileObject;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use IteratorAggregate;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
|
||||||
|
class DocIterator implements IteratorAggregate
|
||||||
|
{
|
||||||
|
protected $fileInfos;
|
||||||
|
|
||||||
|
public function __construct($path)
|
||||||
|
{
|
||||||
|
$iter = new RecursiveIteratorIterator(
|
||||||
|
new MarkdownFileIterator(
|
||||||
|
new RecursiveDirectoryIterator($path)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$fileInfos = iterator_to_array($iter);
|
||||||
|
natcasesort($fileInfos);
|
||||||
|
$this->fileInfos = $fileInfos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIterator()
|
||||||
|
{
|
||||||
|
return new FileLockingIterator($this->fileInfos);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
// {{{ICINGA_LICENSE_HEADER}}}
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
// {{{ICINGA_LICENSE_HEADER}}
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
namespace Icinga\Module\Doc;
|
namespace Icinga\Module\Doc;
|
||||||
|
|
||||||
require_once 'vendor/Parsedown/Parsedown.php';
|
require_once 'vendor/Parsedown/Parsedown.php';
|
||||||
|
|
||||||
use ArrayIterator;
|
|
||||||
use RunetimeException;
|
|
||||||
|
|
||||||
class FileLockingIterator extends ArrayIterator
|
|
||||||
{
|
|
||||||
public function next()
|
|
||||||
{
|
|
||||||
$this->current()->flock(LOCK_UN);
|
|
||||||
parent::next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function valid()
|
|
||||||
{
|
|
||||||
if (!parent::valid()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$fileInfo = $this->current();
|
|
||||||
try {
|
|
||||||
$fileObject = $fileInfo->openFile();
|
|
||||||
} catch (RuntimeException $e) {
|
|
||||||
throw new DocException($e->getMessage());
|
|
||||||
}
|
|
||||||
if ($fileObject->flock(LOCK_SH) === false) {
|
|
||||||
throw new DocException('Couldn\'t get the lock');
|
|
||||||
}
|
|
||||||
$this[$this->key()] = $fileObject;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use IteratorAggregate;
|
|
||||||
use RecursiveIteratorIterator;
|
|
||||||
use RecursiveDirectoryIterator;
|
|
||||||
|
|
||||||
class DocIterator implements IteratorAggregate
|
|
||||||
{
|
|
||||||
protected $fileInfos;
|
|
||||||
|
|
||||||
public function __construct($path)
|
|
||||||
{
|
|
||||||
$iter = new RecursiveIteratorIterator(
|
|
||||||
new MarkdownFileIterator(
|
|
||||||
new RecursiveDirectoryIterator($path)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$fileInfos = iterator_to_array($iter);
|
|
||||||
natcasesort($fileInfos);
|
|
||||||
$this->fileInfos = $fileInfos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getIterator()
|
|
||||||
{
|
|
||||||
return new FileLockingIterator($this->fileInfos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use Parsedown;
|
use Parsedown;
|
||||||
|
use Icinga\Data\Tree\Node;
|
||||||
use Icinga\Exception\NotReadableError;
|
use Icinga\Exception\NotReadableError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,10 +33,10 @@ class DocParser
|
||||||
public function __construct($path)
|
public function __construct($path)
|
||||||
{
|
{
|
||||||
if (! is_dir($path)) {
|
if (! is_dir($path)) {
|
||||||
throw new DocException('Doc directory `' . $path .'\' does not exist');
|
throw new DocException('Doc directory `' . $path . '\' does not exist');
|
||||||
}
|
}
|
||||||
if (! is_readable($path)) {
|
if (! is_readable($path)) {
|
||||||
throw new NotReadableError('Doc directory `' . $path .'\' is not readable');
|
throw new NotReadableError('Doc directory `' . $path . '\' is not readable');
|
||||||
}
|
}
|
||||||
$this->path = $path;
|
$this->path = $path;
|
||||||
}
|
}
|
||||||
|
@ -99,16 +44,17 @@ class DocParser
|
||||||
/**
|
/**
|
||||||
* Retrieve the table of contents
|
* Retrieve the table of contents
|
||||||
*
|
*
|
||||||
* @return DocTocHtmlRenderer
|
* @return Node
|
||||||
*/
|
*/
|
||||||
public function getToc()
|
public function getToc()
|
||||||
{
|
{
|
||||||
$tocStack = array((object) array(
|
$tocStack = array((object) array(
|
||||||
'level' => 0,
|
'level' => 0,
|
||||||
'node' => new DocToc()
|
'node' => new Node()
|
||||||
));
|
));
|
||||||
foreach (new DocIterator($this->path) as $fileObject) {
|
foreach (new DocIterator($this->path) as $fileObject) {
|
||||||
$line = null;
|
$line = null;
|
||||||
|
$currentChapterName = null;
|
||||||
while (! $fileObject->eof()) {
|
while (! $fileObject->eof()) {
|
||||||
// Save last line for setext-style headers
|
// Save last line for setext-style headers
|
||||||
$lastLine = $line;
|
$lastLine = $line;
|
||||||
|
@ -129,11 +75,17 @@ class DocParser
|
||||||
$nofollow = true;
|
$nofollow = true;
|
||||||
}
|
}
|
||||||
$id = urlencode(str_replace('.', '.', strip_tags($id)));
|
$id = urlencode(str_replace('.', '.', strip_tags($id)));
|
||||||
|
if ($currentChapterName === null) {
|
||||||
|
// The first header is the chapter's name
|
||||||
|
$currentChapterName = $id;
|
||||||
|
$id = null;
|
||||||
|
}
|
||||||
$node = end($tocStack)->node->appendChild(
|
$node = end($tocStack)->node->appendChild(
|
||||||
(object) array(
|
(object) array(
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'title' => $header,
|
'title' => $header,
|
||||||
'nofollow' => $nofollow
|
'nofollow' => $nofollow,
|
||||||
|
'chapterName' => $currentChapterName
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$tocStack[] = (object) array(
|
$tocStack[] = (object) array(
|
||||||
|
@ -143,72 +95,77 @@ class DocParser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new DocTocHtmlRenderer($tocStack[0]->node);
|
return $tocStack[0]->node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve doc as HTML converted from markdown files sorted by filename and the table of contents
|
* Retrieve a chapter
|
||||||
*
|
*
|
||||||
* @return array
|
* @param string $chapterName
|
||||||
* @throws DocException
|
*
|
||||||
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getDocAndToc()
|
public function getChapter($chapterName)
|
||||||
{
|
{
|
||||||
$cat = array();
|
$cat = array();
|
||||||
$tocStack = array((object) array(
|
$tocStack = array((object) array(
|
||||||
'level' => 0,
|
'level' => 0,
|
||||||
'node' => new DocToc()
|
'node' => new Node()
|
||||||
));
|
));
|
||||||
|
$chapterFound = false;
|
||||||
foreach (new DocIterator($this->path) as $fileObject) {
|
foreach (new DocIterator($this->path) as $fileObject) {
|
||||||
$line = null;
|
$line = null;
|
||||||
$sectionTitle = null;
|
$currentChapterName = null;
|
||||||
|
$chapter = array();
|
||||||
while (! $fileObject->eof()) {
|
while (! $fileObject->eof()) {
|
||||||
// Save last line for setext-style headers
|
// Save last line for setext-style headers
|
||||||
$lastLine = $line;
|
$lastLine = $line;
|
||||||
$line = $fileObject->fgets();
|
$line = $fileObject->fgets();
|
||||||
$header = $this->extractHeader($line, $lastLine);
|
$header = $this->extractHeader($line, $lastLine);
|
||||||
if ($header !== null) {
|
if ($header !== null) {
|
||||||
list($header, $level) = $header;
|
list($header, $level) = $header;
|
||||||
if ($sectionTitle === null) {
|
$id = $this->extractHeaderId($header);
|
||||||
// The first header is the section's title
|
|
||||||
$sectionTitle = $header;
|
|
||||||
}
|
|
||||||
$id = $this->extractHeaderId($header);
|
|
||||||
$nofollow = false;
|
|
||||||
$this->reduceToc($tocStack, $level);
|
$this->reduceToc($tocStack, $level);
|
||||||
if ($id === null) {
|
if ($id === null) {
|
||||||
$path = array();
|
$path = array();
|
||||||
foreach (array_slice($tocStack, 1) as $entity) {
|
foreach (array_slice($tocStack, 1) as $entity) {
|
||||||
$path[] = $entity->node->getValue()->title;
|
$path[] = $entity->node->getValue()->title;
|
||||||
}
|
}
|
||||||
$path[] = $header;
|
$path[] = $header;
|
||||||
$id = implode('-', $path);
|
$id = implode('-', $path);
|
||||||
$nofollow = true;
|
|
||||||
}
|
}
|
||||||
$id = urlencode(str_replace('.', '.', strip_tags($id)));
|
$id = urlencode(str_replace('.', '.', strip_tags($id)));
|
||||||
$node = end($tocStack)->node->appendChild(
|
if ($currentChapterName === null) {
|
||||||
|
$currentChapterName = $id;
|
||||||
|
$id = null;
|
||||||
|
}
|
||||||
|
$node = end($tocStack)->node->appendChild(
|
||||||
(object) array(
|
(object) array(
|
||||||
'id' => $id,
|
'title' => $header
|
||||||
'title' => $header,
|
|
||||||
'nofollow' => $nofollow
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$tocStack[] = (object) array(
|
$tocStack[] = (object) array(
|
||||||
'level' => $level,
|
'level' => $level,
|
||||||
'node' => $node
|
'node' => $node
|
||||||
);
|
);
|
||||||
$line = '<a name="' . $id . '"></a>' . PHP_EOL . $line;
|
$line = '<a name="' . $id . '"></a>' . PHP_EOL . $line;
|
||||||
}
|
}
|
||||||
$cat[] = $line;
|
$chapter[] = $line;
|
||||||
|
}
|
||||||
|
if ($currentChapterName === $chapterName) {
|
||||||
|
$chapterFound = true;
|
||||||
|
$cat = $chapter;
|
||||||
|
}
|
||||||
|
if (! $chapterFound) {
|
||||||
|
$cat = array_merge($cat, $chapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$html = Parsedown::instance()->text(implode('', $cat));
|
|
||||||
$html = preg_replace_callback(
|
$html = preg_replace_callback(
|
||||||
'#<pre><code class="language-php">(.*?)\</code></pre>#s',
|
'#<pre><code class="language-php">(.*?)\</code></pre>#s',
|
||||||
array($this, 'highlight'),
|
array($this, 'highlight'),
|
||||||
$html
|
Parsedown::instance()->text(implode('', $cat))
|
||||||
);
|
);
|
||||||
return array($html, new DocTocHtmlRenderer($tocStack[0]->node));
|
return $html;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue