diff --git a/src/StackFormation/PreProcessor/Stage/AbstractTreePreProcessorStage.php b/src/StackFormation/PreProcessor/Stage/AbstractTreePreProcessorStage.php index 8d38f76..b68fb9a 100644 --- a/src/StackFormation/PreProcessor/Stage/AbstractTreePreProcessorStage.php +++ b/src/StackFormation/PreProcessor/Stage/AbstractTreePreProcessorStage.php @@ -7,30 +7,33 @@ abstract class AbstractTreePreProcessorStage { protected $treePreProcessor; // reference to parent + protected $template; /** * @param \StackFormation\PreProcessor\TreePreProcessor $treePreProcessor + * @param Template $template */ - public function __construct(\StackFormation\PreProcessor\TreePreProcessor $treePreProcessor) { + public function __construct(\StackFormation\PreProcessor\TreePreProcessor $treePreProcessor, Template $template) { $this->treePreProcessor = $treePreProcessor; + $this->template = $template; } /** - * @param Template $template - * @return Template $template * @throws \StackFormation\Exception\TreePreProcessorException */ - public function __invoke(Template $template) + public function __invoke() { try { - return $this->invoke($template); + $tree = $this->template->getTree(); + $this->invoke($tree); + $this->template->setTree($tree); } catch (\Exception $e) { - throw new \StackFormation\Exception\TreePreProcessorException($template, $e); + throw new \StackFormation\Exception\TreePreProcessorException($this->template, $e); } } /** - * @param Template $template + * @param $tree */ - abstract function invoke(Template $template); + abstract function invoke(array &$tree); } diff --git a/src/StackFormation/PreProcessor/Stage/Tree/ExpandPort.php b/src/StackFormation/PreProcessor/Stage/Tree/ExpandPort.php index 8b66ff4..b733f3f 100644 --- a/src/StackFormation/PreProcessor/Stage/Tree/ExpandPort.php +++ b/src/StackFormation/PreProcessor/Stage/Tree/ExpandPort.php @@ -3,24 +3,18 @@ namespace StackFormation\PreProcessor\Stage\Tree; use StackFormation\PreProcessor\Stage\AbstractTreePreProcessorStage; -use StackFormation\Template; class ExpandPort extends AbstractTreePreProcessorStage { /** - * @param Template $template - * @return Template $template + * @param array $tree */ - public function invoke(Template $template) + public function invoke(array &$tree) { - $tree = $template->getTree(); - $this->treePreProcessor->searchTreeByExpression('/^Port$/', $tree, function (&$tree, $key, $value) { + $this->treePreProcessor->searchTreeByExpression('/^Port$/', $tree, function (&$tree, $key, $value, $matches) { unset($tree[$key]); $tree['FromPort'] = $value; $tree['ToPort'] = $value; - }, 'key'); - $template->setTree($tree); - - return $template; + }, true); } } diff --git a/src/StackFormation/PreProcessor/Stage/Tree/InjectFilecontent.php b/src/StackFormation/PreProcessor/Stage/Tree/InjectFilecontent.php new file mode 100644 index 0000000..466b346 --- /dev/null +++ b/src/StackFormation/PreProcessor/Stage/Tree/InjectFilecontent.php @@ -0,0 +1,86 @@ +treePreProcessor->searchTreeByExpression('/^Fn::FileContent(|Unpretty|TrimLines|Minify)$/', $tree, function (array &$tree, $key, $value, $matches) { + unset($tree[$key]); + $lines = $this->renderFileContent($value, $matches[1]); + $tree['Fn::Join'] = [ '', [implode('', $lines)]]; + }, true); + + // Search in values (content) + $this->treePreProcessor->searchTreeByExpression('/Fn::FileContent(|Unpretty|TrimLines|Minify)(:)(.*)/', $tree, function (array &$tree, $key, $value, $matches) { + unset($tree[$key]); + $lines = $this->renderFileContent(trim(end($matches)), $matches[1]); + $tree[$key] = ['Fn::Join' => [ '', [implode('', $lines)]]]; + }); + } + + /** + * @param string $file + * @param string $modus + * @return array + * @throws \Exception + */ + protected function renderFileContent($file, $modus) + { + $file = $this->template->getBasePath() . '/' . $file; + if (!is_file($file)) { + throw new FileNotFoundException("File '$file' not found"); + } + + $ext = pathinfo($file, PATHINFO_EXTENSION); + if ($modus == 'Minify' && $ext != 'js') { + throw new \Exception('Fn::FileContentMinify is only supported for *.js files. (File: ' . $file . ')'); + } + + $fileContent = file_get_contents($file); + + # TODO in own stage ? + #$fileContent = $this->injectInclude($fileContent, dirname(realpath($file))); + + if ($ext === 'js') { + if ($modus == 'Minify') { + $fileContent = \JShrink\Minifier::minify($fileContent, ['flaggedComments' => false]); + } + + $size = strlen($fileContent); + if ($size > self::MAX_JS_FILE_INCLUDE_SIZE) { + // this is assuming you are uploading an inline JS file to AWS Lambda + throw new \Exception(sprintf("JS file is larger than %s bytes (actual size: %s bytes)", self::MAX_JS_FILE_INCLUDE_SIZE, $size)); + } + } + + // TODO: this isn't optimal. Why are we processing this here in between? + #$fileContent = $this->base64encodedJson($fileContent); + + $lines = explode("\n", $fileContent); + foreach ($lines as $lineKey => &$line) { + if ($modus == 'TrimLines') { + $line = trim($line); + if (empty($line)) { + unset($lines[$lineKey]); + } + } + $line .= "\n"; + } + + #$whitespace = trim($matches[1], "\n"); + #$result = str_replace("\n", "\n" . $whitespace, $result); + + return $lines; + } +} diff --git a/src/StackFormation/PreProcessor/TreePreProcessor.php b/src/StackFormation/PreProcessor/TreePreProcessor.php index ded63ab..2e7425c 100644 --- a/src/StackFormation/PreProcessor/TreePreProcessor.php +++ b/src/StackFormation/PreProcessor/TreePreProcessor.php @@ -15,10 +15,10 @@ public function process(Template $template) { $stageClasses = [ '\StackFormation\PreProcessor\Stage\Tree\ExpandPort', + '\StackFormation\PreProcessor\Stage\Tree\InjectFilecontent', # TODO, check also if we still need that #'\StackFormation\PreProcessor\Stage\Tree\ParseRefInDoubleQuotedStrings', - #'\StackFormation\PreProcessor\Stage\Tree\InjectFilecontent', #'\StackFormation\PreProcessor\Stage\Tree\Base64encodedJson', #'\StackFormation\PreProcessor\Stage\Tree\Split', #'\StackFormation\PreProcessor\Stage\Tree\ReplaceFnGetAttr', @@ -28,30 +28,32 @@ public function process(Template $template) $pipeline = new Pipeline(); foreach ($stageClasses as $stageClass) { - $pipeline->addStage(new $stageClass($this)); + $pipeline->addStage(new $stageClass($this, $template)); } - return $pipeline->process($template); + $pipeline->process(''); } /** * @param string $expression * @param array $tree * @param callable $callback - * @param string $mode + * @param bool $expressionUsedOnKey */ - public function searchTreeByExpression($expression, array &$tree, callable $callback, $mode = '') + public function searchTreeByExpression($expression, array &$tree, callable $callback, $expressionUsedOnKey = false) { + #print_r($tree);die(); + foreach ($tree as $key => &$leaf) { if (is_array($leaf)) { - $this->searchTreeByExpression($expression, $leaf, $callback, $mode); + $this->searchTreeByExpression($expression, $leaf, $callback, $expressionUsedOnKey); continue; } - $subject = ($mode == 'key' ? $key : $leaf); - if (preg_match($expression, $subject)) { - $callback($tree, $key, $leaf); - } + $subject = ($expressionUsedOnKey === true ? $key : $leaf); + preg_replace_callback($expression, function(array $matches) use ($callback, &$tree, $key, $leaf) { + $callback($tree, $key, $leaf, $matches); + }, $subject); } } } diff --git a/src/StackFormation/PrefixedTemplate.php b/src/StackFormation/PrefixedTemplate.php index ebb14e9..3a83896 100644 --- a/src/StackFormation/PrefixedTemplate.php +++ b/src/StackFormation/PrefixedTemplate.php @@ -37,6 +37,13 @@ public function getProcessedTemplate() if ($this->prefix) { if (!$this->cache->has(__METHOD__)) { $content = parent::getProcessedTemplate(); + + + + + # TODO $content is now an Template object + + $content = $this->updateRef($this->prefix, $content); $content = $this->updateDependsOn($this->prefix, $content); $content = $this->updateDependsOnMultiple($this->prefix, $content); @@ -47,6 +54,14 @@ public function getProcessedTemplate() return $this->cache->get(__METHOD__); } else { + + + + + # TODO return $this instead of + + + return parent::getProcessedTemplate(); } } diff --git a/src/StackFormation/Template.php b/src/StackFormation/Template.php index b96540f..e143b65 100644 --- a/src/StackFormation/Template.php +++ b/src/StackFormation/Template.php @@ -60,7 +60,8 @@ public function getProcessedTemplate() return $this->cache->get( __METHOD__, function () { - return $this->treePreProcessor->process($this); + $this->treePreProcessor->process($this); + return $this; } ); } @@ -78,16 +79,16 @@ public function getData() $yamlParser = new \Symfony\Component\Yaml\Parser(); $this->tree = $yamlParser->parse($fileContent); - $this->getProcessedTemplate(); + $template = $this->getProcessedTemplate(); - if (!is_array($this->tree)) { - throw new TemplateDecodeException($this->getFilePath(), sprintf("Error decoding file '%s'", $this->getFilePath())); + if (!is_array($template->getTree())) { + throw new TemplateDecodeException($template->getFilePath(), sprintf("Error decoding file '%s'", $template->getFilePath())); } - if ($this->tree['AWSTemplateFormatVersion'] != '2010-09-09') { - throw new TemplateInvalidException($this->getFilePath(), 'Invalid AWSTemplateFormatVersion'); + if ($template->tree['AWSTemplateFormatVersion'] != '2010-09-09') { + throw new TemplateInvalidException($template->getFilePath(), 'Invalid AWSTemplateFormatVersion'); } - $this->cache->set(__METHOD__, $this->tree); + $this->cache->set(__METHOD__, $template->tree); } return $this->cache->get(__METHOD__); diff --git a/src/StackFormation/TemplateMerger.php b/src/StackFormation/TemplateMerger.php index d66ff0d..ff6cb8d 100644 --- a/src/StackFormation/TemplateMerger.php +++ b/src/StackFormation/TemplateMerger.php @@ -64,8 +64,7 @@ public function merge(array $templates, $description = null, array $additionalDa if (Div::isProgramInstalled('jq')) { $tmpfile = tempnam(sys_get_temp_dir(), 'json_validate_'); $yaml = new \Symfony\Component\Yaml\Yaml(); - $output = $yaml->dump($template->getProcessedTemplate()); - file_put_contents($tmpfile, $output); + file_put_contents($tmpfile, $yaml->dump($data)); passthru('jq . ' . $tmpfile); unlink($tmpfile); } diff --git a/tests/StackFormation/PreprocessorTest.php b/tests/StackFormation/PreprocessorTest.php index 010a50e..3d179b5 100644 --- a/tests/StackFormation/PreprocessorTest.php +++ b/tests/StackFormation/PreprocessorTest.php @@ -12,6 +12,19 @@ class PreprocessorTest extends \PHPUnit_Framework_TestCase public function setUp() { parent::setUp(); + + + + # + # + # TODO switch Preprocessor and rewrite/add tests + # + # + # + # + + + $this->preprocessor = new \StackFormation\Preprocessor(); }