]> git.andy128k.dev Git - ipf.git/commitdiff
simple assets compiler
authorAndrey Kutejko <andy128k@gmail.com>
Sun, 9 Nov 2014 08:32:27 +0000 (10:32 +0200)
committerAndrey Kutejko <andy128k@gmail.com>
Sun, 30 Nov 2014 04:18:35 +0000 (06:18 +0200)
composer.lock
ipf/application.php
ipf/assets.php [new file with mode: 0644]
ipf/cli.php
ipf/command/collectstatic.php
ipf/http/response/file.php
ipf/middleware/common.php
ipf/middleware/serve_static.php [new file with mode: 0644]

index 2e72559fbb6061659e21247dff9abbbabfb5fb8c..5f82efd25afd4574cd112daace1167ff94f7b650 100644 (file)
@@ -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",
             "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",
                 "dbal",
                 "pdo"
             ],
-            "time": "2014-09-06 19:01:53"
+            "time": "2014-11-07 19:35:13"
         },
         {
             "name": "pear/archive_tar",
         },
         {
             "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": {
                 "testing",
                 "xunit"
             ],
-            "time": "2014-04-30 12:24:19"
+            "time": "2014-10-17 09:04:17"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
         },
         {
             "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": {
             ],
             "description": "Symfony Yaml Component",
             "homepage": "http://symfony.com",
-            "time": "2014-08-31 03:22:04"
+            "time": "2014-10-01 05:50:18"
         }
     ],
     "aliases": [],
index 911ed62b5f9ddf1c1b420cc972e4e28798efab1f..1ff21deb19c8adc04ca938c32c192a90f803f77f 100644 (file)
@@ -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 (file)
index 0000000..bdde475
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+
+class IPF_Assets
+{
+    private $files = array();
+
+    public static function compile($dir, $path)
+    {
+        $compiler = new IPF_Assets;
+
+        $root = self::joinPath($dir, $path);
+        list($success, $data) = \PFF\TopSort::sort(array($root), array($compiler, 'following'));
+        if (!$success)
+            throw new Exception('Loop detected: '.implode(' -> ', $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;
+    }
+}
+
index e9bc85ff4bd426d3b0ff0f1818c2542946603c43..ab2b75c3b96fdd5a67ef22dd5eff3214f7e2fade 100644 (file)
@@ -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 <subcommand> [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";
+        }
     }
 }
 
index c107b5f0e04ca9e680fa9834fc219f4f0681a583..dcb98629ad08d0b8bdad7e1c49f684869ac612ab 100644 (file)
@@ -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);
+            }
         }
     }
 }
index 0d5e6c6937eb23a01415e036cbb5e5fbcb35f68b..1c9895a455bb63151a3de5748d3ff228ea3b6078 100644 (file)
@@ -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);
     }
index 7115d3d5d2154a9bbe47f6f03347c9afbbcbfc02..1b16bea1b7e123df488553fb414ee3fb9f259295 100644 (file)
@@ -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 (file)
index 0000000..916ec8a
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+class IPF_Serve_Static_Middleware
+{
+    function processRequest($request)
+    {
+        $staticUrl = IPF::get('static_url');
+
+        if (!preg_match('#^'.preg_quote($staticUrl).'(.*)$#', $request->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';
+        }
+    }
+}
+