Skip to content

Instantly share code, notes, and snippets.

@kingschnulli
Created August 8, 2018 11:28
Show Gist options
  • Save kingschnulli/f10c582c6a283578fc76a27908f6c17c to your computer and use it in GitHub Desktop.
Save kingschnulli/f10c582c6a283578fc76a27908f6c17c to your computer and use it in GitHub Desktop.
Grunt runner for gxid e-shop flow theme
<?php
/**
* Config - adjust as needed
*/
// Path to node download
$nodeUrl = 'https://nodejs.org/dist/v8.11.3/node-v8.11.3-linux-x64.tar.xz';
// Id of your child theme
$customTheme = 'aufkleber';
/**
* End of config
*/
$basePath = realpath(dirname(__FILE__)) . '/';
if(!file_exists('./nodejs/bin/node')){
// Download nodejs
mkdir('./nodejs');
$options = array(
CURLOPT_FILE => fopen('./nodejs/node.tar.xz', 'w'),
CURLOPT_TIMEOUT => 28800, // set this to 8 hours so we dont timeout on big files
CURLOPT_URL => $nodeUrl
);
$ch = curl_init();
curl_setopt_array($ch, $options);
curl_exec($ch);
curl_close($ch);
// Extract nodejs
exec('cd ./nodejs/ && tar -xf ./node.tar.xz');
// Delete zip
exec('rm ./nodejs/node.tar.xz');
// Move folder contents
exec('mv ./nodejs/node-v8.11.3-linux-x64/* ./nodejs/');
// Remove old folder
exec('rmdir ./nodejs/node-v8.11.3-linux-x64/');
// Secure folder
file_put_contents('./nodejs/.htaccess', 'deny from all');
}
if (!file_exists('./Application/views/__grunt__'.$customTheme.'/')) {
// Create grunt theme folder
exec('mkdir ./Application/views/__grunt__'.$customTheme.'/');
// Copy flow to custom
exec('cp -r ./Application/views/flow/* ./Application/views/__grunt__'.$customTheme.'/');
// Install grunt-cli locally
exec('cd ./Application/views/__grunt__'.$customTheme.'/ && ../../../nodejs/bin/node ../../../nodejs/bin/npm install grunt-cli --save-dev');
// install flow grunt plugins
exec('cd ./Application/views/__grunt__'.$customTheme.'/ && ../../../nodejs/bin/node ../../../nodejs/bin/npm install --save-dev');
// add grunt script to package.json
$packageJson = file_get_contents('./Application/views/__grunt__'.$customTheme.'/package.json');
$package = json_decode($packageJson);
$package->scripts->build = "grunt";
file_put_contents('./Application/views/__grunt__'.$customTheme.'/package.json', json_encode($package));
}
// Copy custom stuff to grunt theme folder
exec('cp -r ./Application/views/'.$customTheme.'/* ./Application/views/__grunt__'.$customTheme.'/');
// Run grunt
exec('export PATH="$PATH:'.$basePath.'nodejs/bin/" && cd '.$basePath.'Application/views/__grunt__'.$customTheme.'/ && npm run-script build', $out);
// Copy files
exec('cp -r ./Application/views/__grunt__'.$customTheme.'/out/flow/* ./out/'.$customTheme.'/');
// Join output - the rest is just ANSI to HTML stuff
$output = implode("\n", $out);
/**
* Converts an ANSI text to HTML5.
*/
class AnsiToHtmlConverter
{
protected $theme;
protected $charset;
protected $inlineStyles;
protected $inlineColors;
protected $colorNames;
public function __construct(Theme $theme = null, $inlineStyles = true, $charset = 'UTF-8')
{
$this->theme = null === $theme ? new Theme() : $theme;
$this->inlineStyles = $inlineStyles;
$this->charset = $charset;
$this->inlineColors = $this->theme->asArray();
$this->colorNames = array(
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white',
'', '',
'brblack', 'brred', 'brgreen', 'bryellow', 'brblue', 'brmagenta', 'brcyan', 'brwhite',
);
}
public function convert($text)
{
// remove cursor movement sequences
$text = preg_replace('#\e\[(K|s|u|2J|2K|\d+(A|B|C|D|E|F|G|J|K|S|T)|\d+;\d+(H|f))#', '', $text);
// remove character set sequences
$text = preg_replace('#\e(\(|\))(A|B|[0-2])#', '', $text);
$text = htmlspecialchars($text, PHP_VERSION_ID >= 50400 ? ENT_QUOTES | ENT_SUBSTITUTE : ENT_QUOTES, $this->charset);
// carriage return
$text = preg_replace('#^.*\r(?!\n)#m', '', $text);
$tokens = $this->tokenize($text);
// a backspace remove the previous character but only from a text token
foreach ($tokens as $i => $token) {
if ('backspace' == $token[0]) {
$j = $i;
while (--$j >= 0) {
if ('text' == $tokens[$j][0] && strlen($tokens[$j][1]) > 0) {
$tokens[$j][1] = substr($tokens[$j][1], 0, -1);
break;
}
}
}
}
$html = '';
foreach ($tokens as $token) {
if ('text' == $token[0]) {
$html .= $token[1];
} elseif ('color' == $token[0]) {
$html .= $this->convertAnsiToColor($token[1]);
}
}
if ($this->inlineStyles) {
$html = sprintf('<span style="background-color: %s; color: %s">%s</span>', $this->inlineColors['black'], $this->inlineColors['white'], $html);
} else {
$html = sprintf('<span class="ansi_color_bg_black ansi_color_fg_white">%s</span>', $html);
}
// remove empty span
$html = preg_replace('#<span[^>]*></span>#', '', $html);
return $html;
}
public function getTheme()
{
return $this->theme;
}
protected function convertAnsiToColor($ansi)
{
$bg = 0;
$fg = 7;
$as = '';
if ('0' != $ansi && '' != $ansi) {
$options = explode(';', $ansi);
foreach ($options as $option) {
if ($option >= 30 && $option < 38) {
$fg = $option - 30;
} elseif ($option >= 40 && $option < 48) {
$bg = $option - 40;
} elseif (39 == $option) {
$fg = 7;
} elseif (49 == $option) {
$bg = 0;
}
}
// options: bold => 1, underscore => 4, blink => 5, reverse => 7, conceal => 8
if (in_array(1, $options)) {
$fg += 10;
$bg += 10;
}
if (in_array(4, $options)) {
$as = '; text-decoration: underline';
}
if (in_array(7, $options)) {
$tmp = $fg;
$fg = $bg;
$bg = $tmp;
}
}
if ($this->inlineStyles) {
return sprintf('</span><span style="background-color: %s; color: %s%s">', $this->inlineColors[$this->colorNames[$bg]], $this->inlineColors[$this->colorNames[$fg]], $as);
} else {
return sprintf('</span><span class="ansi_color_bg_%s ansi_color_fg_%s">', $this->colorNames[$bg], $this->colorNames[$fg]);
}
}
protected function tokenize($text)
{
$tokens = array();
preg_match_all("/(?:\e\[(.*?)m|(\x08))/", $text, $matches, PREG_OFFSET_CAPTURE);
$offset = 0;
foreach ($matches[0] as $i => $match) {
if ($match[1] - $offset > 0) {
$tokens[] = array('text', substr($text, $offset, $match[1] - $offset));
}
$tokens[] = array("\x08" == $match[0] ? 'backspace' : 'color', $matches[1][$i][0]);
$offset = $match[1] + strlen($match[0]);
}
if ($offset < strlen($text)) {
$tokens[] = array('text', substr($text, $offset));
}
return $tokens;
}
}
class Theme
{
public function asCss($prefix = 'ansi_color')
{
$css = array();
foreach ($this->asArray() as $name => $color) {
$css[] = sprintf('.%s_fg_%s { color: %s }', $prefix, $name, $color);
$css[] = sprintf('.%s_bg_%s { background-color: %s }', $prefix, $name, $color);
}
return implode("\n", $css);
}
public function asArray()
{
return array(
'black' => 'black',
'red' => 'darkred',
'green' => 'green',
'yellow' => 'yellow',
'blue' => 'blue',
'magenta' => 'darkmagenta',
'cyan' => 'cyan',
'white' => 'white',
'brblack' => 'black',
'brred' => 'red',
'brgreen' => 'lightgreen',
'bryellow' => 'lightyellow',
'brblue' => 'lightblue',
'brmagenta' => 'magenta',
'brcyan' => 'lightcyan',
'brwhite' => 'white',
);
}
}
$converter = new AnsiToHtmlConverter();
$html = $converter->convert($output);
?>
<html>
<body style="background-color: black;">
<pre style="background-color: black; overflow: auto; padding: 10px 15px; font-family: monospace;"
><?php echo $html ?></pre>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment