[cig-commits] r15381 - cs/plot-user-map/trunk
leif at geodynamics.org
leif at geodynamics.org
Wed Jun 24 16:48:47 PDT 2009
Author: leif
Date: 2009-06-24 16:48:47 -0700 (Wed, 24 Jun 2009)
New Revision: 15381
Added:
cs/plot-user-map/trunk/plot-user-map.spk
Log:
Translated the user map CGI script from Python to Spike. The "XXX"
comments highlight current shortcomings of the language.
http://crust.geodynamics.org/~leif/cgi-bin/plot-user-map.spk
Added: cs/plot-user-map/trunk/plot-user-map.spk
===================================================================
--- cs/plot-user-map/trunk/plot-user-map.spk (rev 0)
+++ cs/plot-user-map/trunk/plot-user-map.spk 2009-06-24 23:48:47 UTC (rev 15381)
@@ -0,0 +1,508 @@
+#!/home/leif/public_html/cgi-bin/spike-1
+
+// Written against Spike Maltipy r153.
+// svn export https://spike.svn.sourceforge.net/svnroot/spike/maltipy
+
+import cgi, cgitb, os, sys, tempfile;
+
+import stdout, open from spike.io;
+import sqlite = pysqlite2.dbapi2;
+import basename, join, isdir from os.path;
+
+// XXX: no builtins
+import dict, int, len, list, str from __builtin__;
+import __builtin__;
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// configuration
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+// XXX: no initializers, global or otherwise
+
+var database, statsDir,
+ outputDirRoot, outputURLRoot,
+ gmtRoot, netcdfRoot,
+ defaultDPI;
+
+config() {
+ // data
+ database = "/home/leif/projects/user-maps/geobytes-database";
+ statsDir = "/home/leif/projects/user-maps/stats";
+
+ // output
+ outputDirRoot = "/home/leif/public_html/maps"; // must be writable by 'www-data'
+ outputURLRoot = "http://crust.geodynamics.org/~leif/maps";
+
+ // software
+ gmtRoot = "/home/leif/opt/gmt";
+ netcdfRoot = "/home/leif/opt/netCDF";
+
+ // misc.
+ defaultDPI = 72;
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// constants
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+var queryFormat;
+
+initConstants() {
+ queryFormat = "SELECT c.latitude, c.longitude, c.city, r.region, co.country
+FROM cities AS c
+JOIN subnets AS s ON c.cityid=s.cityid
+JOIN regions AS r ON c.regionid=r.regionid
+JOIN countries AS co ON c.countryid=co.countryid
+WHERE s.subnetaddress IN %s";
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// utils
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+makeTuple(...args) {
+ // XXX: No easy way to construct a tuple. In Spike, ',' works as in C.
+ return args;
+}
+
+makeList(...args) {
+ // XXX: No easy way to construct a list.
+ var l;
+ l = list();
+ foreach (arg: args) {
+ l.append(arg);
+ }
+ return l;
+}
+
+assert(cond) {
+ // XXX: no 'assert' statement
+ if (!cond) {
+ // XXX: 'raise', but no try/except
+ raise __builtin__.AssertionError();
+ }
+}
+
+printf(format, ...args) {
+ // XXX: There should be a convenience function like this one.
+ stdout.printf(format, ...args);
+}
+
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// code
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+queryDatabase(ipList) {
+ var subnetList, subnet;
+
+ subnetList = list(); // XXX: no list literals
+ foreach (ip: ipList) {
+ subnet = ".".join(ip.split(".").__getslice__(0, 3)); // XXX: no slices
+ subnetList.append(subnet);
+ }
+
+ var subnets, query;
+
+ subnets = "(\"" + "\", \"".join(subnetList) + "\")";
+ query = queryFormat % subnets;
+
+ var con, cur;
+
+ con = sqlite.connect(database);
+ con.text_factory = str; // for conversion to UTF-8
+ cur = con.cursor();
+ cur.execute(query);
+
+ var table;
+
+ table = list();
+ foreach (row: cur) {
+ table.append(row);
+ }
+
+ return table;
+}
+
+
+plotMap(latLonList, dpi /*=72*/ ) { // XXX: no default arguments
+ var xyFile, xy, c;
+
+ os.putenv("LD_LIBRARY_PATH", join(netcdfRoot, "lib"));
+
+ xyFile = "user-map.xy";
+
+ // XXX: no keyword arguments
+ c = dict();
+ c["gmt_bin"] = join(gmtRoot, "bin");
+ c["xyFile"] = xyFile;
+ c["psFile"] = "user-map.ps";
+ c["dpi"] = dpi;
+ c["gifFile"] = "user-map.gif";
+
+ xy = open(xyFile, "w");
+ foreach (lat, lon: latLonList) {
+ xy.printf("%s %s\n", lon, lat);
+ }
+ xy.close();
+
+ os.system("%(gmt_bin)s/gmtset PAPER_MEDIA = letter+" % c);
+ os.system("%(gmt_bin)s/psbasemap -R-179/179/-60/70 -JM6i -Ba60/a30/wesn -P -K -V > %(psFile)s" % c);
+ os.system("%(gmt_bin)s/pscoast -R -JM -Dl -A10000 -G0/150/0 -S0/0/150 -K -O -V >> %(psFile)s" % c);
+ os.system("%(gmt_bin)s/psxy -R -JM -Sc0.17 -O -V -G255/255/0 -W1/0/0/0 %(xyFile)s >> %(psFile)s" % c);
+ os.system("convert -trim +repage -density %(dpi)d %(psFile)s %(gifFile)s" % c);
+}
+
+
+scanStats(rawStats, filter /*=null*/ ) {
+ var fileList, codeList, platformList, versionList, monthList;
+
+ fileList = list();
+
+ codeList = list();
+ platformList = list();
+ versionList = list();
+ monthList = list();
+
+ var operatingSystems;
+ operatingSystems = makeTuple("Lin", "Mac", "Win");
+
+ // XXX: no 'continue' inside 'foreach' loops
+ //foreach (name: rawStats)
+ var name, i;
+ for (i = 0; i < len(rawStats); ++i) {
+ name = rawStats[i];
+
+ var tokens;
+ var x, y, month, year;
+
+ tokens = name.split("_");
+ if (len(tokens) == 3) {
+ // XXX: no tuple unpacking
+ x = tokens[0];
+ month = tokens[1];
+ year = tokens[2];
+ } else if (len(tokens) == 4) {
+ // Seismic_CPML
+ x = tokens[0];
+ y = tokens[1];
+ month = tokens[2];
+ year = tokens[3];
+ x = x + "_" + y;
+ } else {
+ continue;
+ }
+ if (len(month) != 3 || len(year) != 4) {
+ continue;
+ }
+ month = "%s-%s" % makeTuple(year, month);
+
+ var code, platform, opSys, arch, version;
+ code = platform = version = null;
+ tokens = x.split("-");
+ // XXX: no 'switch' statement
+ if (len(tokens) == 2) {
+ code = tokens[0];
+ version = tokens[1];
+ } else if (len(tokens) == 3) {
+ if (tokens[1] == "Globe") {
+ code = tokens[0] + tokens[1];
+ version = tokens[2];
+ } else {
+ code = tokens[0];
+ platform = tokens[1];
+ version = tokens[2];
+ }
+ } else if (len(tokens) == 4) {
+ code = tokens[0];
+ opSys = tokens[1];
+ arch = tokens[2];
+ version = tokens[3];
+ // XXX: No "in" equivalent, but who cares?
+ if (!operatingSystems.__contains__(opSys.__getslice__(0, 3))) {
+ continue;
+ }
+ platform = "%s-%s" % makeTuple(opSys, arch);
+ } else {
+ continue;
+ }
+
+ if (code === null || version === null) {
+ continue;
+ }
+ if (code == "PyLith3d") {
+ code = "PyLith";
+ }
+ if (platform === null) {
+ platform = "(null)";
+ }
+
+ if (filter !== null) { // XXX: no automatic coercion to boolean
+ if (!filter[0].__contains__(code)) {
+ continue;
+ }
+ if (len(filter) > 1) {
+ if (!filter[1].__contains__(platform)) {
+ continue;
+ }
+ if (!filter[2].__contains__(version)) {
+ continue;
+ }
+ if (!filter[3].__contains__(month)) {
+ continue;
+ }
+ }
+ }
+
+ var pathname;
+ pathname = join(statsDir, name);
+ fileList.append(pathname);
+
+ codeList.append(code);
+ platformList.append(platform);
+ versionList.append(version);
+ monthList.append(month);
+ }
+
+ var filterChoices, lists;
+ filterChoices = list();
+ lists = makeList(
+ makeTuple("codeList", codeList),
+ makeTuple("platformList", platformList),
+ makeTuple("versionList", versionList),
+ makeTuple("monthList", monthList)
+ );
+
+ // sort and uniqify
+ foreach (name, l: lists) {
+ var u, last;
+
+ l.sort();
+ u = list();
+ last = null;
+ foreach (x: l) {
+ if (x != last) {
+ u.append(x);
+ }
+ last = x;
+ }
+ filterChoices.append(makeTuple(name, u));
+ }
+
+ return makeTuple(fileList, filterChoices);
+}
+
+
+console() {
+ // for debugging
+ var ipList, table, latLonList;
+
+ ipList = makeList("131.215.211.1",
+ "72.14.207.99",
+ "64.233.187.99",
+ "64.233.167.99");
+
+ table = queryDatabase(ipList);
+ latLonList = list();
+ stdout.puts("latitude longitude city region country\n");
+ foreach (latitude, longitude, city, region, country: table) {
+ latLonList.append(makeTuple(latitude, longitude));
+ printf("%s,%s,%s,%s,%s\n", latitude, longitude, city, region, country);
+ }
+ plotMap(latLonList, defaultDPI);
+ return;
+}
+
+
+web(method) {
+ cgitb.enable(); // for troubleshooting
+
+ // XXX: no '__file__'
+ var action;
+ action = basename("/home/leif/public_html/cgi-bin/plot-user-map.spk");
+
+ stdout.puts("Content-type: text/html\n"
+ "\n"
+ "<html>\n"
+ "<head><title>Plot User Map</title></head>\n"
+ "<body>\n"
+ "<h1>Plot User Map</h1>\n"
+ );
+
+ var rawStats, fileList, lists, codeList, tmp;
+ rawStats = os.listdir(statsDir);
+ tmp = scanStats(rawStats, null);
+ fileList = tmp[0];
+ lists = tmp[1];
+ codeList = lists[0][1];
+
+ if (method == "GET") {
+ // XXX: The escaped quotes look pretty bad. Spike should
+ // steal quotes from Perl or Python.
+ printf("<form method=\"post\" action=\"%s\">\n"
+ "<p>Select code: \n"
+ "<select name=code style=\"vertical-align: top\">\n",
+ action);
+ foreach (item: codeList) {
+ printf("<option>%s</option>\n", item);
+ }
+ printf("</select>\n"
+ "</p>\n"
+ "<p><input type=\"submit\" value=\"Next\"/></p>\n"
+ "</form>\n"
+ "<p>Powered by<br><a href=\"http://spike.sourceforge.net/\"><img src=\"http://spike.sourceforge.net/images/spikelanguage.gif\" border=0></a></p>\n"
+ );
+
+ } else if (method == "POST") {
+ var form;
+ form = cgi.FieldStorage();
+
+ var code;
+ code = form.getfirst("code", null);
+ assert(codeList.__contains__(code));
+ printf("<p>code: %s</p>\n", code);
+
+ var filter, emptyFilter;
+ filter = makeList(makeList(code)); // [[code]]
+ emptyFilter = false;
+ foreach (name, l: lists.__getslice__(1, sys.maxint)) {
+ var f;
+ f = form.getlist(name);
+ if (len(f) == 0) {
+ emptyFilter = true;
+ }
+ filter.append(f);
+ }
+
+ if (emptyFilter) {
+ tmp = scanStats(rawStats, makeList(makeList(code)));
+ fileList = tmp[0];
+ lists = tmp[1];
+ printf("<form method=\"post\" action=\"%s\">\n"
+ "<p>\n",
+ action);
+ foreach (name, l: lists.__getslice__(1, sys.maxint)) {
+ printf("<select name=%s multiple style=\"vertical-align: top\">\n", name);
+ foreach (item: l) {
+ printf("<option selected>%s</option>\n", item);
+ }
+ printf("</select>\n");
+ }
+ printf(
+ "</p>\n"
+ "<fieldset><legend>PostScript-to-GIF Conversion Options</legend>\n"
+ "<p><label for=dpi>DPI:</label> <input id=dpi type=\"text\" name=\"dpi\" value=\"%d\"/></p>\n"
+ "</fieldset>\n"
+ "<input type=\"hidden\" name=\"code\" value=\"%s\"/>\n"
+ "<p><input type=\"submit\" value=\"Generate Map\"/></p>\n"
+ "</form>\n",
+ defaultDPI, code
+ );
+
+ printf("<hr/>\n");
+ dumpFilenames(fileList);
+
+ } else {
+ tmp = scanStats(rawStats, filter);
+ fileList = tmp[0];
+ lists = tmp[1];
+
+ var remoteAddr, outputDir, outputURL;
+ remoteAddr = os.environ["REMOTE_ADDR"];
+ outputDir = join(outputDirRoot, remoteAddr);
+ outputURL = outputURLRoot + "/" + remoteAddr;
+ if (!isdir(outputDir)) {
+ os.makedirs(outputDir);
+ }
+ os.chdir(outputDir);
+
+ var dpi;
+ dpi = form.getfirst("dpi", str(defaultDPI));
+ dpi = int(dpi);
+
+ printf("<h2>Output</h2>\n"
+ "<ul>\n"
+ "<li><a href=\"%s/user-map.ps\">PostScript</a></li>\n"
+ "<li><a href=\"%s/user-map.gif\">GIF</a> (%d dpi)</li>\n"
+ "</ul>\n"
+ "<hr/>\n",
+ outputURL,
+ outputURL,
+ dpi
+ );
+
+ var ipList;
+ ipList = list();
+ foreach (pathname: fileList) {
+ var s, line;
+ s = open(pathname, "r");
+ while ((line = s.readline()) != "") { // XXX: file iteration
+ ipList.append(line.strip());
+ }
+ }
+
+ var table;
+ table = queryDatabase(ipList);
+
+ var latLonList;
+ latLonList = list();
+ printf("<h2>Cities</h2>\n"
+ "<table>\n"
+ "<tr>");
+ foreach (th: makeList("latitude", "longitude", "city", "region", "country")) {
+ printf("<th>%s</th>", th);
+ }
+ printf("</tr>\n");
+ foreach (row: table) {
+ latLonList.append(makeTuple(row[0], row[1]));
+ printf("<tr>");
+ foreach (td: row) {
+ printf("<td>%s</td>", td);
+ }
+ printf("</tr>\n");
+ }
+ printf("</table>\n");
+
+ plotMap(latLonList, dpi);
+
+ dumpFilenames(fileList);
+ }
+ } else {
+ assert(false);
+ }
+
+ printf("</body>\n"
+ "</html>\n");
+ return;
+}
+
+
+dumpFilenames(fileList) {
+ printf("<h2>Files</h2>\n"
+ "<pre>\n");
+ foreach (pathname: fileList) {
+ printf("%s\n", basename(pathname));
+ }
+ printf("</pre>\n");
+}
+
+
+main(argv) {
+ config();
+ initConstants();
+
+ var method;
+ method = os.environ.get("REQUEST_METHOD");
+ /* XXX: Shouldn't 'null' be 'None'? */
+ if (method === __builtin__.None) {
+ console();
+ } else {
+ web(method);
+ }
+
+ return 0;
+}
Property changes on: cs/plot-user-map/trunk/plot-user-map.spk
___________________________________________________________________
Name: svn:executable
+ *
More information about the CIG-COMMITS
mailing list