[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