From 39ddf71e037cdb4ed0056fa8a26f621ca93d97f8 Mon Sep 17 00:00:00 2001 From: Andrey Kutejko Date: Sun, 9 Nov 2014 10:32:27 +0200 Subject: [PATCH] simple assets compiler --- composer.lock | 32 +++++++++---------- ipf/application.php | 10 ++++++ ipf/assets.php | 54 +++++++++++++++++++++++++++++++++ ipf/cli.php | 29 ++++++++++++------ ipf/command/collectstatic.php | 8 +++++ ipf/http/response/file.php | 8 +++-- ipf/middleware/common.php | 2 +- ipf/middleware/serve_static.php | 45 +++++++++++++++++++++++++++ 8 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 ipf/assets.php create mode 100644 ipf/middleware/serve_static.php diff --git a/composer.lock b/composer.lock index 2e72559..5f82efd 100644 --- a/composer.lock +++ b/composer.lock @@ -74,7 +74,7 @@ "source": { "type": "git", "url": "git://git.andy128k.net/missing-tools.git", - "reference": "b415e5cacd202b096112c9f4690dcc4f1cb16643" + "reference": "7d22f1cd70189d7b13d1cc30b846f9086abfc545" }, "require": { "andy128k/pegp": "0.1.*@dev", @@ -99,7 +99,7 @@ } ], "description": "Miscellaneous utilities", - "time": "2014-09-14 13:43:45" + "time": "2014-11-09 08:28:31" }, { "name": "andy128k/pegp", @@ -204,12 +204,12 @@ "source": { "type": "git", "url": "https://github.com/lichtner/fluentpdo.git", - "reference": "80ab91b942439b50cf8d436d9826336a8fbe7d49" + "reference": "82801a7bd227c0224635433acdceff96d201b062" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lichtner/fluentpdo/zipball/80ab91b942439b50cf8d436d9826336a8fbe7d49", - "reference": "80ab91b942439b50cf8d436d9826336a8fbe7d49", + "url": "https://api.github.com/repos/lichtner/fluentpdo/zipball/82801a7bd227c0224635433acdceff96d201b062", + "reference": "82801a7bd227c0224635433acdceff96d201b062", "shasum": "" }, "type": "library", @@ -236,7 +236,7 @@ "dbal", "pdo" ], - "time": "2014-09-06 19:01:53" + "time": "2014-11-07 19:35:13" }, { "name": "pear/archive_tar", @@ -536,16 +536,16 @@ }, { "name": "phpunit/phpunit", - "version": "3.7.37", + "version": "3.7.38", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc" + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", - "reference": "ae6cefd7cc84586a5ef27e04bae11ee940ec63dc", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/38709dc22d519a3d1be46849868aa2ddf822bcf6", + "reference": "38709dc22d519a3d1be46849868aa2ddf822bcf6", "shasum": "" }, "require": { @@ -605,7 +605,7 @@ "testing", "xunit" ], - "time": "2014-04-30 12:24:19" + "time": "2014-10-17 09:04:17" }, { "name": "phpunit/phpunit-mock-objects", @@ -658,17 +658,17 @@ }, { "name": "symfony/yaml", - "version": "v2.5.4", + "version": "v2.5.6", "target-dir": "Symfony/Component/Yaml", "source": { "type": "git", "url": "https://github.com/symfony/Yaml.git", - "reference": "01a7695bcfb013d0a15c6757e15aae120342986f" + "reference": "2d9f527449cabfa8543dd7fa3a466d6ae83d6726" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/01a7695bcfb013d0a15c6757e15aae120342986f", - "reference": "01a7695bcfb013d0a15c6757e15aae120342986f", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/2d9f527449cabfa8543dd7fa3a466d6ae83d6726", + "reference": "2d9f527449cabfa8543dd7fa3a466d6ae83d6726", "shasum": "" }, "require": { @@ -701,7 +701,7 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com", - "time": "2014-08-31 03:22:04" + "time": "2014-10-01 05:50:18" } ], "aliases": [], diff --git a/ipf/application.php b/ipf/application.php index 911ed62..1ff21de 100644 --- a/ipf/application.php +++ b/ipf/application.php @@ -59,5 +59,15 @@ abstract class IPF_Application { return array(); } + + /** + * Returns Dictionary of assets + * + * @return array Dictionary of asset entry points mapped to output file + */ + public function assets() + { + return array(); + } } diff --git a/ipf/assets.php b/ipf/assets.php new file mode 100644 index 0000000..bdde475 --- /dev/null +++ b/ipf/assets.php @@ -0,0 +1,54 @@ + ', $data)); + + $dump = array(); + foreach ($data as $path) { + $dump[] = $compiler->files[$path]; + } + return implode("\n", $dump); + } + + function following($path) + { + if (!array_key_exists($path, $this->files)) + $this->files[$path] = file_get_contents($path); + $content = $this->files[$path]; + + if (!preg_match_all('#^(//=\\s*require\\s*(\\S+)|/\\*=\\s*require\\s*(\\S+)\\s*\\*/)\\s*$#m', $content, $matches, PREG_SET_ORDER)) + return array(); + + $dir = dirname($path); + $result = array(); + foreach ($matches as $m) { + $result[] = self::joinPath($dir, @$m[2].@$m[3]); + } + + return $result; + } + + private static function joinPath($base, $file) + { + if (mb_substr($file, 0, 1) === '/') + $path = realpath($file); + else + $path = realpath($base . '/' . $file); + + if (!$path) + throw new Exception("File '$file' not found in '$base'."); + + return $path; + } +} + diff --git a/ipf/cli.php b/ipf/cli.php index e9bc85f..ab2b75c 100644 --- a/ipf/cli.php +++ b/ipf/cli.php @@ -46,6 +46,15 @@ class IPF_Cli $this->commands['Project'] = $project; } + private function getCommand($commandName) + { + foreach ($this->commands as $group => $commands) + foreach ($commands as $command) + if ($command->command === $commandName) + return $command; + return null; + } + protected function usage() { print "Usage: php index.php [options] [args]\n"; @@ -85,17 +94,19 @@ class IPF_Cli return; } - foreach ($this->commands as $group => $commands) { - foreach ($commands as $command) { - if ($command->command === $args[1]) { - $command->run(array_slice($args, 2)); - return; - } - } + $command = $this->getCommand($args[1]); + if (!$command) { + print "Unknown command: '".$args[1]."'\n\n"; + $this->usage(); + return; } - print "Unknown command: '".$args[1]."'\n\n"; - $this->usage(); + try { + $command->run(array_slice($args, 2)); + } catch (Exception $e) { + $m = $e->getMessage(); + print "\n\033[1;31m$m\033[0m\n"; + } } } diff --git a/ipf/command/collectstatic.php b/ipf/command/collectstatic.php index c107b5f..dcb9862 100644 --- a/ipf/command/collectstatic.php +++ b/ipf/command/collectstatic.php @@ -16,6 +16,14 @@ class IPF_Command_CollectStatic $source = $app->getPath() . 'static'; if (is_dir($source)) IPF_Utils::copyDirectory($source, $destination); + + foreach ($app->assets() as $asset => $output) { + $content = IPF_Assets::compile($app->getPath(), $asset); + + $dest = $destination . $output; + IPF_Utils::makeDirectories(dirname($dest)); + file_put_contents($dest, $content); + } } } } diff --git a/ipf/http/response/file.php b/ipf/http/response/file.php index 0d5e6c6..1c9895a 100644 --- a/ipf/http/response/file.php +++ b/ipf/http/response/file.php @@ -4,12 +4,14 @@ class IPF_HTTP_Response_File extends IPF_HTTP_Response { private $filename; - function __construct($filename, $downloadName, $mimetype='application/octet-stream') + function __construct($filename, $downloadName=null, $mimetype='application/octet-stream') { parent::__construct('', $mimetype); $this->filename = $filename; - $this->headers['Content-Description'] = 'File Transfer'; - $this->headers['Content-Disposition'] = 'attachment; filename='.basename($downloadName); + if ($downloadName) { + $this->headers['Content-Description'] = 'File Transfer'; + $this->headers['Content-Disposition'] = 'attachment; filename='.basename($downloadName); + } $this->headers['Content-Transfer-Encoding'] = 'binary'; $this->headers['Content-Length'] = filesize($filename); } diff --git a/ipf/middleware/common.php b/ipf/middleware/common.php index 7115d3d..1b16bea 100644 --- a/ipf/middleware/common.php +++ b/ipf/middleware/common.php @@ -2,7 +2,7 @@ class IPF_Middleware_Common { - function processRequest(&$request) + function processRequest($request) { if (IPF::get('append_slash', true)) { $url = $request->absoluteUrl(); diff --git a/ipf/middleware/serve_static.php b/ipf/middleware/serve_static.php new file mode 100644 index 0000000..916ec8a --- /dev/null +++ b/ipf/middleware/serve_static.php @@ -0,0 +1,45 @@ +query, $matches)) + return false; + + $query = $matches[1]; + + foreach (IPF_Project::getInstance()->appList() as $app) { + $static = $app->getPath() . $staticUrl . $query; + if (is_file($static)) + return new IPF_HTTP_Response_File($static, null, $this->mimetype($query)); + + $asset = array_search($query, $app->assets()); + if ($asset !== false) { + $content = IPF_Assets::compile($app->getPath(), $asset); + return new IPF_HTTP_Response($content, $this->mimetype($query)); + } + } + + return false; + } + + private function mimetype($filename) + { + switch (strtolower(pathinfo($filename, PATHINFO_EXTENSION))) { + case 'jpg': + case 'jpeg': return 'image/jpeg'; + case 'png': return 'image/png'; + case 'gif': return 'image/gif'; + case 'svg': return 'image/svg+xml'; + case 'js': return 'application/javascript'; + case 'css': return 'text/css'; + case 'htm': + case 'html': return 'text/html'; + default: return 'application/octet-stream'; + } + } +} + -- 2.49.0