summaryrefslogtreecommitdiff
path: root/extras/appengine/sqlformat
diff options
context:
space:
mode:
Diffstat (limited to 'extras/appengine/sqlformat')
-rw-r--r--extras/appengine/sqlformat/__init__.py24
-rw-r--r--extras/appengine/sqlformat/legacy.py158
-rw-r--r--extras/appengine/sqlformat/templates/about.html46
-rw-r--r--extras/appengine/sqlformat/templates/api.html52
-rw-r--r--extras/appengine/sqlformat/templates/index.html120
-rw-r--r--extras/appengine/sqlformat/templates/master.html103
-rw-r--r--extras/appengine/sqlformat/templates/python-client-example.html17
-rw-r--r--extras/appengine/sqlformat/templates/source.html60
-rw-r--r--extras/appengine/sqlformat/urls.py11
-rw-r--r--extras/appengine/sqlformat/views.py225
10 files changed, 580 insertions, 236 deletions
diff --git a/extras/appengine/sqlformat/__init__.py b/extras/appengine/sqlformat/__init__.py
index e69de29..db9c132 100644
--- a/extras/appengine/sqlformat/__init__.py
+++ b/extras/appengine/sqlformat/__init__.py
@@ -0,0 +1,24 @@
+from flask import Flask, make_response
+
+from sqlformat.legacy import legacy
+
+
+app = Flask('sqlformat')
+
+
+@app.route('/ping')
+def ping():
+ return make_response('pong')
+
+@app.route('/_ah/warmup')
+def warmup():
+ return make_response('polishing chrome')
+
+@app.route('/fail')
+def fail():
+ # test URL for failure handling
+ raise AssertionError('You shouldn\'t be here!')
+
+
+# Register legacy URLs last so that newer URLs replace them.
+app.register_blueprint(legacy)
diff --git a/extras/appengine/sqlformat/legacy.py b/extras/appengine/sqlformat/legacy.py
new file mode 100644
index 0000000..6d3aaf8
--- /dev/null
+++ b/extras/appengine/sqlformat/legacy.py
@@ -0,0 +1,158 @@
+"""Legacy URLs."""
+
+import logging
+import os
+import time
+
+from google.appengine.api import memcache
+
+from flask import Blueprint, make_response, render_template, Response, request
+
+from pygments import highlight
+from pygments.formatters import HtmlFormatter
+from pygments.lexers import SqlLexer, PythonLexer, PhpLexer
+
+import simplejson as json
+
+import sqlparse
+
+
+legacy = Blueprint('', 'legacy')
+
+
+EXAMPLES_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../examples'))
+
+
+@legacy.route('/', methods=['POST', 'GET'])
+def index():
+ data = {'examples': _get_examples()}
+ extra = {'highlight': True, 'comments': False,
+ 'keywords': 'upper', 'idcase': '',
+ 'n_indents': '2',
+ 'lang': 'sql'}
+ sql_orig = 'select * from foo join bar on val1 = val2 where id = 123;'
+ if request.method == 'POST':
+ oformat = request.form.get('format', 'html')
+ extra['highlight'] = 'highlight' in request.form
+ extra['comments'] = 'remove_comments' in request.form
+ extra['keywords'] = request.form.get('keyword_case', '')
+ extra['idcase'] = request.form.get('identifier_case', '')
+ extra['n_indents'] = request.form.get('n_indents', '2')
+ extra['lang'] = request.form.get('output_format', 'sql')
+ sql = _get_sql(request.form, request.files)
+ sql_orig = sql
+ start = time.time()
+ data['output'] = _format_sql(sql, request.form, format=oformat)
+ data['proc_time'] = '%.3f' % (time.time()-start)
+ if oformat == 'json':
+ data['errors'] = ''
+ return make_response(Response(json.dumps(data),
+ content_type='text/x-json'))
+ elif oformat == 'text':
+ return make_response(Response(data['output'], content_type='text/plain'))
+ data['sql_orig'] = sql_orig
+ data['extra'] = extra
+ return render_template('index.html', **data)
+
+
+@legacy.route('/source/')
+def source():
+ return render_template('source.html')
+
+
+@legacy.route('/about/')
+def about():
+ return render_template('about.html')
+
+@legacy.route('/api/')
+def api():
+ return render_template('api.html')
+
+
+@legacy.route('/format/', methods=['GET', 'POST'])
+def format_():
+ if request.method == 'POST':
+ sql = _get_sql(request.form, request.files)
+ data = request.form
+ else:
+ sql = _get_sql(request.args)
+ data = request.args
+ formatted = _format_sql(sql, data, format='text')
+ return make_response(Response(formatted, content_type='text/plain'))
+
+
+@legacy.route('/load_example', methods=['GET', 'POST'])
+def load_example():
+ fname = request.form.get('fname')
+ if fname is None:
+ answer = 'Uups, I\'ve got no filename...'
+ elif fname not in _get_examples():
+ answer = 'Hmm, I think you don\'t want to do that.'
+ else:
+ answer = open(os.path.join(EXAMPLES_DIR, fname)).read()
+ data = json.dumps({'answer': answer})
+ return make_response(Response(data, content_type='text/x-json'))
+
+
+def _get_examples():
+ examples = memcache.get('legacy_examples')
+ if examples is None:
+ examples = os.listdir(EXAMPLES_DIR)
+ memcache.set('legacy_examples', examples)
+ return examples
+
+
+def _get_sql(data, files=None):
+ sql = None
+ if files is not None and 'datafile' in files:
+ raw = files['datafile'].read()
+ try:
+ sql = raw.decode('utf-8')
+ except UnicodeDecodeError, err:
+ logging.error(err)
+ logging.debug(repr(raw))
+ sql = (u'-- UnicodeDecodeError: %s\n'
+ u'-- Please make sure to upload UTF-8 encoded data for now.\n'
+ u'-- If you want to help improving this part of the application\n'
+ u'-- please file a bug with some demo data at:\n'
+ u'-- http://code.google.com/p/python-sqlparse/issues/entry\n'
+ u'-- Thanks!\n' % err)
+ if not sql:
+ sql = data.get('data')
+ return sql or ''
+
+
+def _format_sql(sql, data, format='html'):
+ popts = {}
+ if data.get('remove_comments'):
+ popts['strip_comments'] = True
+ if data.get('keyword_case', 'undefined') not in ('undefined', ''):
+ popts['keyword_case'] = data.get('keyword_case')
+ if data.get('identifier_case', 'undefined') not in ('undefined', ''):
+ popts['identifier_case'] = data.get('identifier_case')
+ if data.get('n_indents', None) is not None:
+ val = data.get('n_indents')
+ try:
+ popts['indent_width'] = max(1, min(1000, int(val)))
+ popts['reindent'] = True
+ except (ValueError, TypeError):
+ pass
+ if data.get('output_format', None) is not None:
+ popts['output_format'] = data.get('output_format')
+ logging.debug('Format: %s, POPTS: %r', format, popts)
+ logging.debug(sql)
+ sql = sqlparse.format(sql, **popts)
+ if format in ('html', 'json'):
+ if data.get('highlight', False):
+ if popts['output_format'] == 'python':
+ lexer = PythonLexer()
+ elif popts['output_format'] == 'php':
+ lexer = PhpLexer()
+ else:
+ lexer = SqlLexer()
+ sql = highlight(sql, lexer, HtmlFormatter())
+ else:
+ sql = ('<textarea class="resizable" '
+ 'style="height: 350px; margin-top: 1em;">%s</textarea>'
+ % sql)
+ return sql
diff --git a/extras/appengine/sqlformat/templates/about.html b/extras/appengine/sqlformat/templates/about.html
new file mode 100644
index 0000000..2d4e03e
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/about.html
@@ -0,0 +1,46 @@
+{% extends "master.html" %}
+
+{% block title %}About{% endblock %}
+
+{% block main %}
+<h1>About this Application</h1>
+<p>
+ This application is a online SQL formatting tool.
+</p>
+<p>
+ Basically it's a playground for a Python module to parse and format
+ SQL statements. Sometimes it's easier to combine the available
+ options and to see the resulting output using a web front-end than
+ on the command line ;-)
+</p>
+<p>
+ To get started, enter a SQL statement in the text box on the top,
+ choose some options and click on &quot;Format SQL&quot; (Ctrl+F)
+ to see the result.
+</p>
+<p>
+ <em>Note:</em> The SQL formatter and parser is in an early stage
+ of development. If you're looking for a mature tool, try one of
+ <a href="http://www.google.com/search?q=online+sql+formatter">these</a>.
+</p>
+<h2>Using it from the Command Line</h2>
+<p>
+ There are three ways to use this SQL formatter from the command line:
+</p>
+<ol>
+ <li>Grab the <a href="/source/">sources</a> and use the module in your
+ Python scripts.</li>
+ <li>
+ Write a little script in your favorite language that sends a POST
+ request to this application.<br/>
+ Read the <a href="/api/">API Documentation</a> for more information.
+ </li>
+ <li>Use
+ <a href="/static/lynx_screenshot.png"
+ alt="Lynx Screenshot" target="_blank"
+ title="Screenshot: sqlformat.appspot.com on Lynx">Lynx
+ </a>
+ </li>
+</ol>
+
+{% endblock %}
diff --git a/extras/appengine/sqlformat/templates/api.html b/extras/appengine/sqlformat/templates/api.html
new file mode 100644
index 0000000..79bf118
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/api.html
@@ -0,0 +1,52 @@
+{% extends "master.html" %}
+
+{% block title %}API{% endblock %}
+
+{% block main %}
+<h1>API Documentation</h1>
+
+<p>
+ Using the API for this application is pretty simple. Just send a
+ <code>POST</code> request to
+</p>
+<p>
+ <code>http://sqlformat.appspot.com/format/</code>
+</p>
+
+<h2>Options</h2>
+<p>
+ The <code>POST</code> request accepts various options to control
+ formatting. Only the <em>data</em> option is required. All others
+ are optional.
+</p>
+
+<dl>
+ <dt>data</dt>
+ <dd>The SQL statement to format.</dd>
+ <dt>remove_comments</dt>
+ <dd>Set to 1 to remove comments.</dd>
+ <dt>keyword_case</dt>
+ <dd>How to convert keywords. Allowed values are 'lower', 'upper',
+ 'capitalize'.</dd>
+ <dt>identifier_case</dt>
+ <dd>How to convert identifiers. Allowed values are 'lower', 'upper',
+ 'capitalize'.</dd>
+ <dt>n_indents</dt>
+ <dd>An integer indicating the indendation depth.</dd>
+ <dt>right_margin</dt>
+ <dd>An integer indicating the maximum line length.</dd>
+ <dt>output_format</dt>
+ <dd>Transfer the statement into another programming language.
+ Allowed values are 'python', 'php'</dd>
+</dl>
+
+<h2>Example</h2>
+<p>
+ Here's a example in Python:
+</p>
+{% include "python-client-example.html" %}
+<p>
+ <a href="/static/sqlformat_client_example.py">Download sqlformat_example_client.py</a>
+</p>
+
+{% endblock %}
diff --git a/extras/appengine/sqlformat/templates/index.html b/extras/appengine/sqlformat/templates/index.html
new file mode 100644
index 0000000..22d6fdb
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/index.html
@@ -0,0 +1,120 @@
+{% extends "master.html" %}
+
+{% block main %}
+
+{% if output %}
+ <a href="#output" class="skip">Jump to formatted query</a>
+{% endif %}
+
+<form method="post" action="" id="form_options" enctype="multipart/form-data">
+ <div id="input">
+ <div>
+ <strong>Type your SQL here:</strong><br />
+ <textarea id="id_data" rows="10" cols="40" name="data" class="resizable">{{ sql_orig }}</textarea>
+ </div>
+ <div style="margin-top: .5em;">
+ <strong>...or upload a file:</strong>
+ <input type="file" name="datafile" id="id_datafile" />
+ </div>
+ <div id="examples" style="margin-top: .5em;"></div>
+ <div id="actions" style="margin-top: .5em;">
+ <input type="submit" value="Format SQL" id="btn_format" />
+ </div>
+ {% if output %}<a name="output"></a>
+ <div id="response">{{output|safe}}</div>
+ {% else %}
+ <div id="response"></div>
+ {% endif %}
+ <div id="proc_time">
+ {% if proc_time %}Processed in {{proc_time}} seconds.{% endif %}
+ </div>
+ <div style="margin-top: 1em;">
+ <script type="text/javascript">
+ <!--
+ google_ad_client = "pub-8870624642249726";
+ /* 468x60, Erstellt 07.03.09 */
+ google_ad_slot = "9840041509";
+ google_ad_width = 468;
+ google_ad_height = 60;
+ //-->
+ </script>
+ <script type="text/javascript"
+ src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
+ </script>
+ </div>
+
+ </div>
+ <div id="options">
+ <h1 class="skip">Options</h1>
+ <fieldset><legend id="general"><strong>General Options</strong></legend>
+ <div id="general_content" class="content">
+ <input type="checkbox" id="id_remove_comments" name="remove_comments" value="1" {% if extra.comments %}checked="checked"{% endif %}/>
+ <label for="id_remove_comments">Remove comments</label>
+ <br />
+ <input type="checkbox" id="id_highlight" name="highlight" value="1" {% if extra.highlight %}checked="checked"{% endif %} />
+ <label for="id_highlight">Enable syntax highlighting</label>
+ </div>
+ </fieldset>
+ <fieldset><legend id="kwcase">
+ <strong>Keywords &amp; Identifiers</strong></legend>
+ <div>
+ Keywords: <select id="id_keyword_case" name="keyword_case">
+ <option value="">Unchanged</option>
+ <option value="lower" {% if extra.keywords == 'lower' %}selected="selected"{% endif %}>Lower case</option>
+ <option value="upper" {% if extra.keywords == 'upper' %}selected="selected"{% endif %}>Upper case</option>
+ <option value="capitalize" {% if extra.keywords == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option>
+ </select>
+ </div>
+ <div>
+ Identifiers: <select name="identifier_case" id="id_identifier_case">
+ <option value="">Unchanged</option>
+ <option value="lower" {% if extra.idcase == 'lower' %}selected="selected"{% endif %}>Lower case</option>
+ <option value="upper" {% if extra.idcase == 'upper' %}selected="selected"{% endif %}>Upper case</option>
+ <option value="capitalize" {% if extra.idcase == 'capitalize' %}selected="selected"{% endif %}>Capitalize</option>
+ </select>
+ </div>
+ </fieldset>
+ <fieldset><legend id="indent"><strong>Indentation &amp; Margins</strong>
+ </legend>
+ <div id="indent_content" class="content">
+ <label for="id_n_indents">Indentation: </label>
+ <input name="n_indents" value="{{extra.n_indents}}" maxlength="2" type="text" id="id_n_indents" size="2" /> spaces
+ <div class="help">Empty field means leave indentation unchanged.</div>
+ </div>
+ </fieldset>
+ <fieldset><legend id="output"><strong>Output Format</strong></legend>
+ <label for="id_output_format">Language: </label>
+ <select name="output_format" id="id_output_format">
+ <option value="sql" {% if extra.lang == 'sql' %}selected="selected"{% endif %}>SQL</option>
+ <option value="python" {% if extra.lang == 'python' %}selected="selected"{% endif %}>Python</option>
+ <option value="php" {% if extra.lang == 'php' %}selected="selected"{% endif %}>PHP</option>
+ </select>
+ </fieldset>
+
+ <div class="dev">This software is in development.</div>
+
+ <div>
+ <g:plusone size="medium"></g:plusone>
+ <a href="http://flattr.com/thing/350724/SQLFormat-Online-SQL-formatting-service" target="_blank">
+ <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" />
+ </a>
+ </div>
+ <div style="padding-top: 15px;">
+ <a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="andialbrecht">Tweet</a><script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
+ </div>
+ </div>
+ <div class="clearfix"></div>
+</form>
+
+<script language="javascript">
+html = '<strong>...or select an example:</strong> ';
+html = html + '<select onchange="load_example();" id="sel_example">';
+html = html + '<option value="">-- Choose Example --</option>';
+{% for ex in examples %}
+ html = html + '<option value="{{ex}}">{{ex}}</option>';
+{% endfor %}
+html = html + '</select>';
+$('#examples').html(html);
+</script>
+{% endblock %}
+
diff --git a/extras/appengine/sqlformat/templates/master.html b/extras/appengine/sqlformat/templates/master.html
new file mode 100644
index 0000000..88a9d36
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/master.html
@@ -0,0 +1,103 @@
+<html>
+ <head>
+ <title>{% block title %}SQLFormat - Online SQL Formatter{% endblock %}</title>
+ <meta name="keywords" content="SQL, format, parse, python, beautify, pretty, online, formatting, formatter" />
+ <meta name="description" content="Easy to use web service to format SQL statements." />
+ <link rel="stylesheet" href="/static/pygments.css" />
+ <link rel="stylesheet" href="/static/styles.css" />
+ <script src="http://www.google.com/jsapi"></script>
+ <script>
+ google.load("jquery", "1.2.6");
+ </script>
+ <script src="/static/hotkeys.js"></script>
+ <script src="/static/script.js"></script>
+ </head>
+ <body>
+
+ <div id="help">
+ <p>Keyboard Shortcuts</p>
+ <p>
+ <span class="shortcut">H</span> - Show / hide this help window<br/>
+ <span class="shortcut">Ctrl+F</span> - Format SQL and display result<br/>
+ <span class="shortcut">O</span> - Show / hide options<br/>
+ <span class="shortcut">T</span> - Set focus on SQL input<br/>
+ </p>
+ </div>
+
+ <div id="header">
+ <div id="header-inner">
+ {% if user %}<img src="{{userimg}}" border="0" align="right" style="padding-top:.4em;"/>{% endif %}
+ <h1>
+ <a href="/">
+ <span class="q">S<span class="q2">Q</span>L</span>Format
+ </a>
+ </h1>
+ <div id="slogan">Online SQL formatting service</div>
+ <div id="topmenu">
+ <a href="/">Home</a>
+ |
+ <a href="/about/">About</a>
+ |
+ <a href="/source/">Source Code</a>
+ |
+ <a href="/api/">API</a>
+<!--
+ |
+ {% if user %}
+ <a href="{{logout_url}}">Sign out</a>
+ {% else %}
+ <a href="{{login_url}}">Sign in</a>
+ <span style="color: #babdb6;">with your Google account
+ to save preferred settings.</span>
+ {% endif %}
+-->
+ </div>
+ </div>
+ </div>
+
+ <div id="main">
+ <div id="main-inner">
+ {% block main %}MAIN CONTENT GOES HERE{% endblock %}
+ </div>
+ </div>
+
+ <div id="footer">
+ <div id="footer-inner">
+ <div style="float: left; font-size: .85em;">
+ <div>&copy; 2011 Andi Albrecht&nbsp;&nbsp;
+ <code>&lt;albrecht dot andi gmail&gt;</code>
+ </div>
+ <div>
+ <a href="/">Home</a>
+ |
+ <a href="/about/">About</a>
+ |
+ <a href="/source/">Source Code</a>
+ |
+ <a href="/api/">API</a>
+ |
+ <a href="http://andialbrecht.wordpress.com/">Blog</a>
+ </div>
+ </div>
+ <div style="float: right;">
+ <img src="http://code.google.com/appengine/images/appengine-silver-120x30.gif"
+ alt="Powered by Google App Engine" />
+ </div>
+ <div class="clearfix"></div>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script>
+ <script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker("UA-3535525-2");
+ pageTracker._trackPageview();
+ } catch(err) {}</script>
+ <script>init();</script>
+ <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
+
+ </body>
+</html>
diff --git a/extras/appengine/sqlformat/templates/python-client-example.html b/extras/appengine/sqlformat/templates/python-client-example.html
new file mode 100644
index 0000000..68bf820
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/python-client-example.html
@@ -0,0 +1,17 @@
+<div class="highlight example"><pre><span class="c">#!/usr/bin/env python</span>
+
+<span class="k">import</span> <span class="nn">urllib</span>
+<span class="k">import</span> <span class="nn">urllib2</span>
+
+<span class="n">payload</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="p">(</span><span class="s">&#39;data&#39;</span><span class="p">,</span> <span class="s">&#39;select * from foo join bar on val1 = val2 where id = 123;&#39;</span><span class="p">),</span>
+ <span class="p">(</span><span class="s">&#39;format&#39;</span><span class="p">,</span> <span class="s">&#39;text&#39;</span><span class="p">),</span>
+ <span class="p">(</span><span class="s">&#39;keyword_case&#39;</span><span class="p">,</span> <span class="s">&#39;upper&#39;</span><span class="p">),</span>
+ <span class="p">(</span><span class="s">&#39;reindent&#39;</span><span class="p">,</span> <span class="bp">True</span><span class="p">),</span>
+ <span class="p">(</span><span class="s">&#39;n_indents&#39;</span><span class="p">,</span> <span class="mf">2</span><span class="p">),</span>
+ <span class="p">)</span>
+
+<span class="n">response</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">&#39;http://sqlformat.appspot.com/format/&#39;</span><span class="p">,</span>
+ <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">payload</span><span class="p">))</span>
+<span class="k">print</span> <span class="n">response</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
+</pre></div>
diff --git a/extras/appengine/sqlformat/templates/source.html b/extras/appengine/sqlformat/templates/source.html
new file mode 100644
index 0000000..a0ed89d
--- /dev/null
+++ b/extras/appengine/sqlformat/templates/source.html
@@ -0,0 +1,60 @@
+{% extends "master.html" %}
+
+{% block title %}Source code{% endblock %}
+
+{% block main %}
+<div id="response">
+ <h1>Source Code</h1>
+
+ <h2>Python Module</h2>
+ <p>
+ The sources for the SQL parser and formatter module are
+ hosted on Google Code.
+ To clone the repository run:
+ <p>
+ <code class="pre"> hg clone http://python-sqlparse.googlecode.com/hg/ python-sqlparse</code>
+ </p>
+ <p>
+ <a href="http://python-sqlparse.googlecode.com">Visit the project page</a>
+ |
+ <a href="http://code.google.com/p/python-sqlparse/source/browse/">Browse the sources online</a>
+ |
+ <a href="http://python-sqlparse.googlecode.com/svn/docs/api/index.html"> API Documentation</a>
+ </p>
+ <p>
+ Some relevant parts of the Python module contain code from the
+ <a href="http://pygments.org/">pygments</a> syntax highlighter.
+ The underlying Python module uses a non-validating SQL parser.
+ This approach makes it possible to parse even syntactically incorrect
+ SQL statements.
+ </p>
+
+ <p>
+ Currently the parser module is used by
+ <a href="http://crunchyfrog.googlecode.com/">CrunchyFrog</a> - a
+ database front-end for Gnome.
+ </p>
+
+ <p>
+ The <code>sqlparse</code> module is released under the terms of the
+ <a href="http://www.opensource.org/licenses/bsd-license.php">New BSD License</a>.
+ </p>
+
+ <h2>App Engine Application</h2>
+ <p>
+ The source code for this App Engine application is available in the
+ <code>examples</code> directory of the Python module
+ (but it's really nothing special ;-).
+ </p>
+
+ <h2>Contributing</h2>
+ <p>
+ Please file bug reports and feature requests on the project site at
+ <a href="http://code.google.com/p/python-sqlparse/issues/entry">http://code.google.com/p/python-sqlparse/issues/entry</a>
+ or if you have code to contribute upload it to
+ <a href="http://codereview.appspot.com">http://codereview.appspot.com</a>
+ and add albrecht.andi@googlemail.com as reviewer.
+ </p>
+
+</div>
+{% endblock %}
diff --git a/extras/appengine/sqlformat/urls.py b/extras/appengine/sqlformat/urls.py
deleted file mode 100644
index c83290e..0000000
--- a/extras/appengine/sqlformat/urls.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from django.conf.urls.defaults import *
-
-urlpatterns = patterns(
- 'sqlformat.views',
- (r'^$', 'index'),
- (r'^source/$', 'source'),
- (r'^about/$', 'about'),
- (r'^api/$', 'api'),
- (r'^format/$', 'format'),
- (r'^load_example', 'load_example'),
-)
diff --git a/extras/appengine/sqlformat/views.py b/extras/appengine/sqlformat/views.py
deleted file mode 100644
index 806496f..0000000
--- a/extras/appengine/sqlformat/views.py
+++ /dev/null
@@ -1,225 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import logging
-import md5
-import os
-import sys
-import time
-
-from django import forms
-from django.http import HttpResponse
-from django.template import loader
-from django.utils import simplejson as json
-
-from google.appengine.api import users
-
-from pygments import highlight
-from pygments.formatters import HtmlFormatter
-from pygments.lexers import SqlLexer, PythonLexer, PhpLexer
-
-import sqlparse
-
-
-INITIAL_SQL = "select * from foo join bar on val1 = val2 where id = 123;"
-EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), '../examples')
-
-
-# Custom render_to_response() function to avoid loading django.shortcuts
-# since django.shortcuts depends on a lot of Django modules we don't need
-# here, e.g. lots of modules from django.db.
-def render_to_response(template, params=None):
- if params is None:
- params = {}
- return HttpResponse(loader.render_to_string(template, params))
-
-
-def _get_user_image(user):
- if user is None:
- return None
- digest = md5.new(user.email().lower()).hexdigest()
- if os.environ['SERVER_SOFTWARE'].startswith('Dev'):
- host = 'localhost%3A8080'
- else:
- host = 'sqlformat.appspot.com'
- default = 'http%3A%2F%2F'+host+'%2Fstatic%2Fblank.gif'
- return 'http://gravatar.com/avatar/%s?s=32&d=%s' % (digest, default)
-
-def _get_examples():
- fnames = os.listdir(EXAMPLES_DIR)
- fnames.sort()
- return fnames
-
-
-class FormOptions(forms.Form):
- data = forms.CharField(widget=forms.Textarea({'class': 'resizable'}),
- initial=INITIAL_SQL, required=False)
- datafile = forms.FileField(required=False)
- highlight = forms.BooleanField(initial=True, required=False,
- widget=forms.CheckboxInput(),
- label='Enable syntax highlighting')
- remove_comments = forms.BooleanField(initial=False, required=False,
- widget=forms.CheckboxInput(),
- label='Remove comments')
- keyword_case = forms.CharField(
- widget=forms.Select(choices=(('', 'Unchanged'),
- ('lower', 'Lower case'),
- ('upper', 'Upper case'),
- ('capitalize', 'Capitalize'))),
- required=False, initial='upper', label='Keywords')
- identifier_case = forms.CharField(
- widget=forms.Select(choices=(('', 'Unchanged'),
- ('lower', 'Lower case'),
- ('upper', 'Upper case'),
- ('capitalize', 'Capitalize'))),
- required=False, initial='', label='Identifiers')
- n_indents = forms.IntegerField(min_value=1, max_value=30,
- initial=2, required=False,
- label='spaces',
- widget=forms.TextInput({'size': 2,
- 'maxlength': 2}))
-# right_margin = forms.IntegerField(min_value=10, max_value=500,
-# initial=60, required=False,
-# label='characters',
-# widget=forms.TextInput({'size': 3,
-# 'maxlength': 3}))
- output_format = forms.CharField(
- widget=forms.Select(choices=(('sql', 'SQL'),
- ('python', 'Python'),
- ('php', 'PHP'),
- )),
- required=False, initial='sql', label='Language')
-
- def clean(self):
- super(FormOptions, self).clean()
- data = self.cleaned_data.get('data')
- logging.info(self.files)
- if 'datafile' in self.files:
- self._datafile = self.files['datafile'].read()
- else:
- self._datafile = None
- if not data and not self._datafile:
- raise forms.ValidationError('Whoops, I need a file or text!')
- elif data and self._datafile:
- raise forms.ValidationError('Whoops, I need a file OR text!')
- return self.cleaned_data
-
- def clean_output_format(self):
- frmt = self.cleaned_data.get('output_format')
- if not frmt:
- frmt = 'sql'
- return frmt.lower()
-
- def get_data(self):
- data = self.cleaned_data.get('data')
- if self._datafile:
- return self._datafile
- else:
- return data
-
-
-def format_sql(form, format='html'):
- data = form.cleaned_data
- popts = {}
- sql = form.get_data()
- if data.get('remove_comments'):
- popts['strip_comments'] = True
- if data.get('keyword_case'):
- popts['keyword_case'] = data.get('keyword_case')
- if data.get('identifier_case'):
- popts['identifier_case'] = data.get('identifier_case')
- if data.get('n_indents', None) is not None:
- popts['reindent'] = True
- popts['indent_width'] = data.get('n_indents')
- if data.get('right_margin', None) is not None:
- popts['right_margin'] = data.get('right_margin')
- if data.get('output_format', None) is not None:
- popts['output_format'] = data.get('output_format')
- sql = sqlparse.format(sql, **popts)
- if format in ('html', 'json'):
- if data.get('highlight', False):
- if popts['output_format'] == 'python':
- lexer = PythonLexer()
- elif popts['output_format'] == 'php':
- lexer = PhpLexer()
- else:
- lexer = SqlLexer()
- sql = highlight(sql, lexer, HtmlFormatter())
- else:
- sql = ('<textarea class="resizable" '
- 'style="height: 350px; margin-top: 1em;">%s</textarea>'
- % sql)
- return sql
-
-
-def index(request):
- output = None
- data = {}
- proc_time = None
- if request.method == 'POST':
- logging.debug(request.POST)
- form = FormOptions(request.POST, request.FILES)
- if form.is_valid():
- start = time.time()
- output = format_sql(form,
- format=request.POST.get('format', 'html'))
- proc_time = time.time()-start
- else:
- form = FormOptions()
- if request.POST.get('format', None) == 'json':
- logging.warning(form.errors)
- data['errors'] = str(form.errors)
- data['output'] = output
- logging.info('%r', proc_time)
- data['proc_time'] = '%.3f' % (proc_time or 0.0)
- data = json.dumps(data)
- return HttpResponse(data, content_type='text/x-json')
- elif request.POST.get('format', None) == 'text':
- if not form.is_valid():
- data = str(form.errors) # XXX convert to plain text
- else:
- data = output
- return HttpResponse(data, content_type='text/plain')
- return render_to_response('index.html',
- {'form': form, 'output': output,
- 'proc_time': proc_time and '%.3f' % proc_time or None,
- 'user': users.get_current_user(),
- 'login_url': users.create_login_url('/'),
- 'logout_url': users.create_logout_url('/'),
- 'userimg': _get_user_image(users.get_current_user()),
- 'examples': _get_examples()})
-
-
-def format(request):
- if request.method == 'POST':
- form = FormOptions(request.POST)
- if form.is_valid():
- try:
- response = format_sql(form, format='text')
- except:
- err = sys.exc_info()[1]
- response = 'ERROR: Parsing failed. %s' % str(err)
- else:
- response = 'ERROR: %s' % str(form.errors)
- else:
- response = 'POST request required'
- return HttpResponse(response, content_type='text/plain')
-
-def source(request):
- return render_to_response('source.html')
-
-def about(request):
- return render_to_response('about.html')
-
-def api(request):
- return render_to_response('api.html')
-
-def load_example(request):
- fname = request.POST.get('fname')
- if fname is None:
- answer = 'Uups, I\'ve got no filename...'
- elif fname not in _get_examples():
- answer = 'Hmm, I think you don\'t want to do that.'
- else:
- answer = open(os.path.join(EXAMPLES_DIR, fname)).read()
- data = json.dumps({'answer': answer})
- return HttpResponse(data, content_type='text/x-json')