first tool supported: xmllint
authorChristian Weiske <cweiske@cweiske.de>
Fri, 13 Apr 2012 17:56:24 +0000 (19:56 +0200)
committerChristian Weiske <cweiske@cweiske.de>
Fri, 13 Apr 2012 17:56:24 +0000 (19:56 +0200)
15 files changed:
data/config.default.php
data/templates/display-file.htm [new file with mode: 0644]
data/templates/display-foot.htm [new file with mode: 0644]
data/templates/display-head.htm [new file with mode: 0644]
data/templates/display.htm
data/templates/tool.htm [new file with mode: 0644]
src/phorkie/File.php
src/phorkie/Tool/Info.php [new file with mode: 0644]
src/phorkie/Tool/Manager.php [new file with mode: 0644]
src/phorkie/Tool/Result.php [new file with mode: 0644]
src/phorkie/Tool/Result/Line.php [new file with mode: 0644]
src/phorkie/Tool/Xmllint.php [new file with mode: 0644]
www/.htaccess
www/phorkie.css
www/tool.php [new file with mode: 0644]

index 804ff5e..443328d 100644 (file)
@@ -6,6 +6,9 @@ $GLOBALS['phorkie']['cfg'] = array(
     'tpl'     => __DIR__ . '/templates/',
     'css'     => 'http://twitter.github.com/bootstrap/assets/css/bootstrap.css',
 );
+$GLOBALS['phorkie']['tools'] = array(
+    '\\phorkie\\Tool_Xmllint'
+);
 /**
  * Array of supported file types / languages.
  * Key is the file extension
diff --git a/data/templates/display-file.htm b/data/templates/display-file.htm
new file mode 100644 (file)
index 0000000..d06c365
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="file">
+ <div class="header">
+  <a class="btn btn-mini" href="{{file.getLink('raw')}}" style="float: right;">raw</a>
+  {% for toolinfo in file.getToolInfos %}
+  <a class="btn btn-mini" href="{{toolinfo.getLink(file)}}" style="float: right;">{{toolinfo.getTitle}}</a>
+  {% endfor %}
+  <h3 id="{{file.getFilename}}">{{file.getFilename}}<a class="anchorlink" href="#{{file.getFilename}}"></a></h3>
+ </div>
+ <div class="code">
+  {{file.getHighlightedContent|raw}}
+ </div>
+</div>
diff --git a/data/templates/display-foot.htm b/data/templates/display-foot.htm
new file mode 100644 (file)
index 0000000..9f2451f
--- /dev/null
@@ -0,0 +1,7 @@
+<div class="row-fluid" style="margin-top: 5ex">
+ <div class="span12" style="text-align: right;">
+  <a class="btn" href="{{repo.getLink('delete')}}">
+   <i class="icon-trash"></i> Delete
+  </a>
+ </div>
+</div>
diff --git a/data/templates/display-head.htm b/data/templates/display-head.htm
new file mode 100644 (file)
index 0000000..7ce5160
--- /dev/null
@@ -0,0 +1,35 @@
+<h1>{{repo.getDescription}}</h1>
+<div class="row-fluid repo-info">
+ <div class="span4">
+  <a class="btn" href="{{repo.getLink('edit')}}"><i class="icon-edit"></i> edit</a>
+ </div>
+ <div class="span4" style="text-align: center">
+  <h3>Paste #{{repo.id}}</h3>
+ </div>
+ <div class="span4" style="text-align: right">
+  <form method="post" action="{{repo.getLink('fork')}}">
+    <button type="submit" class="btn"><i class="icon-share"></i> fork</button>
+  </form>
+ </div>
+</div>
+
+{% if repo.getCloneURL(true) or repo.getCloneURL(false) %}
+<div class="well">
+ {% if repo.getCloneURL(true) %}
+ <div class="row-fluid">
+  <div class="span3">Public clone URL</div>
+  <div class="span9">
+   <a href="{{repo.getCloneURL(true)}}">{{repo.getCloneURL(true)}}</a>
+  </div>
+ </div>
+ {% endif %}
+ {% if repo.getCloneURL(false) %}
+ <div class="row-fluid">
+  <div class="span3">Private clone URL</div>
+  <div class="span9">
+   <a href="{{repo.getCloneURL(false)}}">{{repo.getCloneURL(false)}}</a>
+  </div>
+ </div>
+ {% endif %}
+</div>
+{% endif %}
index da75cd9..e021296 100644 (file)
@@ -8,61 +8,13 @@
 {% endblock %}
 
 {% block content %}
-<h1>{{repo.getDescription}}</h1>
-<div class="row-fluid">
- <div class="span4">
-  <a class="btn" href="{{repo.getLink('edit')}}"><i class="icon-edit"></i> edit</a>
- </div>
- <div class="span4" style="text-align: center">
-  <h3>Paste #{{repo.id}}</h3>
- </div>
- <div class="span4" style="text-align: right">
-  <form method="post" action="{{repo.getLink('fork')}}">
-    <button type="submit" class="btn"><i class="icon-share"></i> fork</button>
-  </form>
- </div>
-</div>
-
-{% if repo.getCloneURL(true) or repo.getCloneURL(false) %}
-<div class="well">
- {% if repo.getCloneURL(true) %}
- <div class="row-fluid">
-  <div class="span3">Public clone URL</div>
-  <div class="span9">
-   <a href="{{repo.getCloneURL(true)}}">{{repo.getCloneURL(true)}}</a>
-  </div>
- </div>
- {% endif %}
- {% if repo.getCloneURL(false) %}
- <div class="row-fluid">
-  <div class="span3">Private clone URL</div>
-  <div class="span9">
-   <a href="{{repo.getCloneURL(false)}}">{{repo.getCloneURL(false)}}</a>
-  </div>
- </div>
- {% endif %}
-</div>
-{% endif %}
+ {% include 'display-head.htm' %}
 
 {% for file in repo.getFiles %}
-<div class="file">
- <div class="header">
-  <a class="btn btn-mini" href="{{file.getLink('raw')}}" style="float: right;">raw</a>
-  <h3 id="{{file.getFilename}}">{{file.getFilename}}<a class="anchorlink" href="#{{file.getFilename}}"></a></h3>
- </div>
- <div class="code">
-  {{file.getHighlightedContent|raw}}
- </div>
-</div>
+ {% include 'display-file.htm' %}
 {% endfor %}
 
-<div class="row-fluid" style="margin-top: 5ex">
- <div class="span12" style="text-align: right;">
-  <a class="btn" href="{{repo.getLink('delete')}}">
-   <i class="icon-trash"></i> Delete
-  </a>
- </div>
-</div>
+ {% include 'display-foot.htm' %}
 {% endblock %}
 
 {% block sidebar %}
diff --git a/data/templates/tool.htm b/data/templates/tool.htm
new file mode 100644 (file)
index 0000000..ef8e5e0
--- /dev/null
@@ -0,0 +1,44 @@
+{% extends "base.htm" %}
+{% block title %}
+ Tool results: 
+ {%if repo.getDescription %}
+  {{repo.getDescription}}
+ {%else%}
+  {{repo.id}}
+ {%endif%}
+{% endblock %}
+
+{% block content %}
+<h1>Tool results:  {{repo.getDescription}}</h1>
+<div class="row-fluid repo-info">
+ <div class="span4">
+  <a class="btn" href="{{repo.getLink('edit')}}"><i class="icon-edit"></i> edit</a>
+  <a class="btn" href="{{repo.getLink('display')}}"><i class="icon-arrow-left"></i> back</a>
+ </div>
+ <div class="span4" style="text-align: center">
+  <h3>Paste #{{repo.id}}</h3>
+ </div>
+</div>
+
+ {% for line in toolres.annotations.general %}
+  <div class="alert {{line.getAlertLevel}}">
+   {{line.message}}
+  </div>
+ {% endfor %}
+
+ {% include 'display-file.htm' %}
+
+ {% for number,lineinfos in toolres.annotations if number != 'general' %}
+  {% for line in lineinfos %}
+   <div class="alert {{line.getAlertLevel}}">
+    Line #{{number}}: {{line.message}}
+   </div>
+  {% endfor %}
+ {% endfor %}
+
+ {% include 'display-foot.htm' %}
+{% endblock %}
+
+{% block sidebar %}
+sidebar FIXME
+{% endblock %}
index 87c3851..869aa80 100644 (file)
@@ -75,14 +75,17 @@ class File
      *
      * @param string $type Link type. Supported are:
      *                     - "raw"
-     *                     - "display"
+     *                     - "tool"
+     * @param string $option
      *
      * @return string
      */
-    public function getLink($type)
+    public function getLink($type, $option = null)
     {
         if ($type == 'raw') {
             return '/' . $this->repo->id . '/raw/' . $this->getFilename();
+        } else if ($type == 'tool') {
+            return '/' . $this->repo->id . '/tool/' . $option . '/' . $this->getFilename();
         }
         throw new Exception('Unknown type');
     }
@@ -95,6 +98,15 @@ class File
         }
         return $GLOBALS['phorkie']['languages'][$ext]['mime'];
     }
+
+    /**
+     * @return array Array of Tool_Info objects
+     */
+    public function getToolInfos()
+    {
+        $tm = new Tool_Manager();
+        return $tm->getSuitable($this);
+    }
 }
 
 ?>
\ No newline at end of file
diff --git a/src/phorkie/Tool/Info.php b/src/phorkie/Tool/Info.php
new file mode 100644 (file)
index 0000000..c1c3c69
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+namespace phorkie;
+
+class Tool_Info
+{
+    public $class;
+
+    public function __construct($class)
+    {
+        $this->class = $class;
+    }
+
+    public function getLink(File $file)
+    {
+        return $file->getLink('tool', $this->stripPrefix($this->class));
+    }
+
+    public function getTitle()
+    {
+        return $this->stripPrefix($this->class);
+    }
+
+    protected function stripPrefix($class)
+    {
+        $prefix = '\\phorkie\\Tool_';
+        if (substr($class, 0, strlen($prefix)) === $prefix) {
+            return substr($class, strlen($prefix));
+        }
+        return $class;
+    }
+}
+
+?>
diff --git a/src/phorkie/Tool/Manager.php b/src/phorkie/Tool/Manager.php
new file mode 100644 (file)
index 0000000..3bcf750
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+namespace phorkie;
+
+
+class Tool_Manager
+{
+    public function getSuitable(File $file)
+    {
+        $ext = $file->getExt();
+        $suitables = array();
+        foreach ($GLOBALS['phorkie']['tools'] as $class) {
+            if (array_search($ext, $class::$arSupportedExtensions) !== false) {
+                $suitables[] = new Tool_Info($class);
+            }
+        }
+        return $suitables;
+    }
+
+    /**
+     * Returns the class name from a tool name
+     *
+     * @param string $name Full class name or short name without
+     *                     'phorkie\\Tool_' prefix
+     *
+     * @return string Class name or NULL if not found
+     */
+    public function getClass($name)
+    {
+        if (strpos($name, '\\') === false && strpos($name, '_') === false) {
+            return '\\phorkie\\Tool_' . $name;
+        }
+        return $name;
+    }
+
+    public function loadTool($name)
+    {
+        $class = $this->getClass($name);
+        if (!class_exists($class, true)) {
+            throw new Exception('Tool does not exist: ' . $class);
+        }
+        
+        return new $class();
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/src/phorkie/Tool/Result.php b/src/phorkie/Tool/Result.php
new file mode 100644 (file)
index 0000000..22ea273
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+namespace phorkie;
+
+class Tool_Result
+{
+    public $annotations;
+}
+
+?>
\ No newline at end of file
diff --git a/src/phorkie/Tool/Result/Line.php b/src/phorkie/Tool/Result/Line.php
new file mode 100644 (file)
index 0000000..a788db6
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+namespace phorkie;
+
+class Tool_Result_Line
+{
+    public $message;
+    public $level;
+
+    public function __construct($message, $level = 'ok')
+    {
+        $this->message = $message;
+        $this->setLevel($level);
+    }
+
+    public function setLevel($level)
+    {
+        if ($level !== 'ok' && $level !== 'error' && $level !== 'warning') {
+            throw new Exception('Invalid result line level: ' . $level);
+        }
+        $this->level = $level;
+    }
+
+    public function getAlertLevel()
+    {
+        static $map = array(
+            'error'   => 'alert-error',
+            'ok'      => 'alert-success',
+            'warning' => '',
+        );
+        return $map[$this->level];
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/src/phorkie/Tool/Xmllint.php b/src/phorkie/Tool/Xmllint.php
new file mode 100644 (file)
index 0000000..b9917f5
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+namespace phorkie;
+
+class Tool_Xmllint
+{
+    public static $arSupportedExtensions = array(
+        'htm', 'html', 'xml'
+    );
+
+    public function run(File $file)
+    {
+        $fpath = $file->getPath();
+        $fpathlen = strlen($fpath);
+
+        $res = new Tool_Result();
+        $cmd = 'xmllint --noout ' . escapeshellarg($fpath) . ' 2>&1';
+        exec($cmd, $output, $retval);
+        if ($retval == 0) {
+            $res->annotations['general'][] = new Tool_Result_Line(
+                'XML is well-formed', 'ok'
+            );
+            return $res;
+        }
+
+        for ($i = 0; $i < count($output); $i += 3) {
+            $line = $output[$i];
+            if (substr($line, 0, $fpathlen) != $fpath) {
+                throw new Exception('xmllint does not behave as expected: ' . $line);
+            }
+            list($line, $msg) = explode(':', substr($line, $fpathlen + 1), 2);
+            $res->annotations[$line][] = new Tool_Result_Line(
+                $msg, 'error'
+            );
+        }
+
+        $res->annotations['general'][] = new Tool_Result_Line(
+            'XML is not well-formed', 'error'
+        );
+
+        return $res;
+    }
+}
+
+?>
\ No newline at end of file
index 32701be..10833c7 100644 (file)
@@ -8,6 +8,7 @@ RewriteRule ^([0-9]+)/delete/confirm$ /delete.php?id=$1&confirm=1
 RewriteRule ^([0-9]+)/edit$ /edit.php?id=$1
 RewriteRule ^([0-9]+)/fork$ /fork.php?id=$1
 RewriteRule ^([0-9]+)/raw/(.+)$ /raw.php?id=$1&file=$2
+RewriteRule ^([0-9]+)/tool/([^/]+)/(.+)$ /tool.php?id=$1&tool=$2&file=$3
 
 RewriteRule ^list$ /list.php
 RewriteRule ^list/([0-9]+)$ /list.php?page=$1
index 882a2f7..3e4b061 100644 (file)
@@ -28,9 +28,12 @@ a.anchorlink {
     color: #FFA;
 }
 
-.file {
-    margin-top: 2em;
+h1 {
+    margin-bottom: 0.5ex;
+}
 
+.repo-info {
+    margin-bottom: 2em;
 }
 .file .header {
     padding: 1.0ex;
diff --git a/www/tool.php b/www/tool.php
new file mode 100644 (file)
index 0000000..d42954c
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Runs a tool on a file
+ */
+namespace phorkie;
+require_once 'www-header.php';
+$repo = new Repository();
+$repo->loadFromRequest();
+
+if (!isset($_GET['file']) || $_GET['file'] == '') {
+    throw new Exception_Input('File name missing');
+}
+$file = $repo->getFileByName($_GET['file']);
+
+if (!isset($_GET['tool']) || $_GET['tool'] == '') {
+    throw new Exception_Input('Tool name missing');
+}
+
+$tm = new Tool_Manager();
+$tool = $tm->loadTool($_GET['tool']);
+
+$res = $tool->run($file);
+
+render(
+    'tool',
+    array(
+        'repo' => $repo,
+        'file' => $file,
+        'toolres' => $res,
+    )
+);
+
+?>
\ No newline at end of file