dweb 0.5: handlers, fixes, tidying.
authorJacob Parker <j3parker@csclub.uwaterloo.ca>
Wed, 22 Feb 2012 22:11:10 +0000 (17:11 -0500)
committerJacob Parker <j3parker@csclub.uwaterloo.ca>
Wed, 22 Feb 2012 22:11:10 +0000 (17:11 -0500)
bin/changelog [deleted file]
bin/changelog.sh [new file with mode: 0755]
pub/style/style.css
src/config.d
src/web.d
srv/.dweb [deleted file]
srv/@changelog [new file with mode: 0644]
srv/@dweb.md [new file with mode: 0644]

diff --git a/bin/changelog b/bin/changelog
deleted file mode 100755 (executable)
index 27e81c4..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-echo "<ul>"
-git log --pretty=format:'<li>%s - %aN (%ae) <b>(%cr)</b></li>' --abbrev-commit --date=relative
-echo "</ul>"
diff --git a/bin/changelog.sh b/bin/changelog.sh
new file mode 100755 (executable)
index 0000000..27e81c4
--- /dev/null
@@ -0,0 +1,3 @@
+echo "<ul>"
+git log --pretty=format:'<li>%s - %aN (%ae) <b>(%cr)</b></li>' --abbrev-commit --date=relative
+echo "</ul>"
index e0e60f7..150f43a 100644 (file)
@@ -95,7 +95,6 @@ a:hover { text-decoration: underline; }
 /* # Horiz-side # */\r
 #horiz-side-bar {\r
   width:100%;\r
 /* # Horiz-side # */\r
 #horiz-side-bar {\r
   width:100%;\r
-  float left;\r
   clear: both;\r
   border: 0;\r
   margin: 0;\r
   clear: both;\r
   border: 0;\r
   margin: 0;\r
index f6813c3..a133c26 100644 (file)
@@ -1,6 +1,4 @@
 const string url_root = "/~j3parker/";
 const string url_root = "/~j3parker/";
-const string dweb_root = "/users/j3parker/www/";
-const string site_root = dweb_root ~ "srv/";
 
 const string site_title = "This is a Title";
 const string site_subtitle = "but this is a subtitle";
 
 const string site_title = "This is a Title";
 const string site_subtitle = "but this is a subtitle";
@@ -8,3 +6,10 @@ const string site_subtitle = "but this is a subtitle";
 const bool nav_tree_vert = true;
 const bool nav_tree_chev = true;
 const bool page_container = false;
 const bool nav_tree_vert = true;
 const bool nav_tree_chev = true;
 const bool page_container = false;
+
+string[string] handlers;
+
+void init_handlers() {
+  handlers["*.md"] = "contrib/Markdown.pl";
+  handlers["changelog"] = "changelog.sh";
+}
index 7e17553..5013d7d 100755 (executable)
--- a/src/web.d
+++ b/src/web.d
 //#!/usr/bin/rdmd
 //#!/usr/bin/rdmd
-import std.stdio;
-import std.process;
-import std.file;
-import std.array;
-import std.string;
-import std.algorithm;
+import std.stdio, std.path, std.process, std.file, std.array, std.string, std.algorithm, std.datetime;
 import config;
 
 import config;
 
+string dweb_root;
+
 string indent = "";
 void html(string s) { writeln(indent ~ s); }
 void html_pop(string s) { indent = indent[0..max(0, $-4)]; html(s); }
 void html_push(string s) { html(s); indent ~= "    "; }
 
 string indent = "";
 void html(string s) { writeln(indent ~ s); }
 void html_pop(string s) { indent = indent[0..max(0, $-4)]; html(s); }
 void html_push(string s) { html(s); indent ~= "    "; }
 
-void write_link(string root, string file, bool expand) {
-  bool isdir = dirExists(file);
+void write_link(string to, bool expand) {
+  bool isdir = dirExists(dweb_root ~ "/srv/" ~ to[url_root.length..$]);
   string flair = nav_tree_chev? (expand? "&raquo; " : "&rsaquo; ") : "";
   html_push("<li" ~ (expand? " class=\"thisPage\" " : "") ~ ">");
   string flair = nav_tree_chev? (expand? "&raquo; " : "&rsaquo; ") : "";
   html_push("<li" ~ (expand? " class=\"thisPage\" " : "") ~ ">");
-  html("<a href=\"" ~ construct_rel_link(root, file) ~ "\">"
-        ~ flair ~last_in_path(file) ~ (isdir ? "/" : "")
-        ~ "</a>");
+  html("<a href=\"" ~ to ~ (isdir ? "/" : "") ~ "\">"
+        ~ flair ~ baseName(to) ~ (isdir ? "/" : "") ~ "</a>");
   html_pop("</li>");
 }
 
   html_pop("</li>");
 }
 
-void nav_tree_r(string root, string cur_loc, string[] subdirs) {
-  string[] dirs = dir(cur_loc);
+void nav_tree_r(string url, string cur_loc, string[] subdirs) {
+  string[] dirs = array(map!"a.name"(dirEntries(dweb_root ~ "/srv/" ~ cur_loc, SpanMode.shallow)));
+  sort(dirs);
   if (dirs.length == 0) return;
   if (dirs.length == 0) return;
-  html_push("<ul>");
+  bool inserted_ul = false;
   bool next = false;
   string next_loc;
   foreach(string s; dirs) {
   bool next = false;
   string next_loc;
   foreach(string s; dirs) {
-    bool hidden = last_in_path(s).length > 0 && last_in_path(s)[0] == '.';
-    bool expand = s[cur_loc.length..$] == (subdirs.length == 0 ? "" : subdirs[0]);
-    if (hidden && !expand) continue;
-    write_link(root, s, expand);
-    if (expand && isDir(cur_loc ~ subdirs[0])) {
+    s= s[(dweb_root ~ "/srv/").length..$];
+    string name = stripExtension(baseName(s));
+    if (name.length == 0) continue; // e.g. ".md", should we do something else with these files?
+    if (name == "index") continue; // "index" will never appear in the nav_tree.
+    if (name[0] == '@') continue; // hidden file
+    if (!inserted_ul) { html_push("<ul>"); inserted_ul = true; }
+    bool expand = subdirs.length > 0 && name == subdirs[0];
+    write_link(url_root ~ stripExtension(s), expand);
+
+    if (expand && isDir(dweb_root ~ "/srv/" ~ s)) {
       if (nav_tree_vert) {
         html_push("<li>");
       if (nav_tree_vert) {
         html_push("<li>");
-        nav_tree_r(root, cur_loc ~ subdirs[0] ~ "/", subdirs[1..$]);
+        nav_tree_r(url, (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0], subdirs[1..$]);
         html_pop("</li>");
       } else {
         next = true;
         html_pop("</li>");
       } else {
         next = true;
-        next_loc = cur_loc ~ subdirs[0] ~ "/";
+        next_loc = (cur_loc == "" ? "" : cur_loc ~ "/") ~ subdirs[0];
       }
     }
   }
       }
     }
   }
-  html_pop("</ul>");
-  if (next) nav_tree_r(root, next_loc, subdirs[1..$]);
-}
 
 
-// this could be better
-string[] dir(string path) {
-  string[] files;
-  foreach(string s; dirEntries(path, SpanMode.shallow)) {
-    if (s[max(0,$-8)..$] != "index.md") files ~= s;
-  }
-  sort(files);
-  return files;
+  if (inserted_ul) html_pop("</ul>");
+  if (next) nav_tree_r(url, next_loc, subdirs[1..$]);
 }
 
 }
 
-void do_nav_tree(string path) {
-  try { if (isDir(path) && path[path.length - 1] != '/') { path = site_root; } }
-  catch (Exception e) { path = site_root; }
-
+void do_nav_tree(string url) {
   html_push("<div id=\"" ~ (nav_tree_vert ? "" : "horiz-") ~ "side-bar\">");
   html_push("<div id=\"" ~ (nav_tree_vert ? "" : "horiz-") ~ "side-bar\">");
-
-  string root = get_root_dir(path);
-  string[] subdirs = explode_slashes(path[site_root.length..$]);
-  nav_tree_r(root, site_root, subdirs);
-
+  nav_tree_r(url, "", cast(string[])array(pathSplitter(url)));
   html_pop("</div>\n");
 }
 
   html_pop("</div>\n");
 }
 
-string last_in_path(string path) {
-  auto i = max(path.length,1) - 1;
-  while (i-- > 0) if (path[i] == '/') return path[min(i+1,$)..$];
-  return path;
-}
-
-string chomp_slashes(string path) { return chompPrefix(chomp(path, "/"), "/"); }
-string[] explode_slashes(string path) { return split(chomp_slashes(path), "/"); }
-
-string get_root_dir(string path) {
-  if (path == "") return "";
-  if (isDir(path)) return path[path.length - 1] == '/' ? path : path ~ "/";
-  auto i = path.length - 1;
-  while (--i > 0) if (path[i] == '/') return path[0..i];
-  return "/";
-}
-
-string construct_rel_link(string src, string dst) {
-  string rel = "";
-  string[] srcs = explode_slashes(src);
-  string[] dsts = explode_slashes(dst);
-  ulong i = 0;
-  while(i < srcs.length && i < dsts.length && srcs[i] == dsts[i]) i++;
-  if (i == srcs.length && i == dsts.length) return ".";
-  foreach (ulong j; 0..(srcs.length - i)) rel ~= "../";
-  foreach (string s; dsts[i..$]) rel ~= s ~ "/"; 
-  return isDir(dst) ? rel : rel[0..$-1];
-}
-
 void not_found(string path) {
   html("The page <code>" ~ path ~ "</code> does not exist. (404)");
 }
 void not_found(string path) {
   html("The page <code>" ~ path ~ "</code> does not exist. (404)");
 }
@@ -111,7 +68,6 @@ void do_header() {
   html_push("<div class=\"right\">");
   html("<a href=\"" ~ url_root ~ "changelog\">changelog</a>");
   html_pop("</div>");
   html_push("<div class=\"right\">");
   html("<a href=\"" ~ url_root ~ "changelog\">changelog</a>");
   html_pop("</div>");
-  
   html_pop("</div>");
 
   html_push("<div class=\"midHeader\">");
   html_pop("</div>");
 
   html_push("<div class=\"midHeader\">");
@@ -127,37 +83,33 @@ void do_header() {
   html_pop("</div>\n");
 }
 
   html_pop("</div>\n");
 }
 
-void do_markdown(string file) {
-  // sanity check file first?!?!?
-  html(shell("cat " ~ file ~ "|" ~ dweb_root ~ "bin/contrib/Markdown.pl"));
-}
-
-bool fileExists(string path) { try { if (isFile(path)) return true; else return false; } catch (Exception e) { return false; } }
 bool dirExists(string path)  { try { if (isDir(path))  return true; else return false; } catch (Exception e) { return false; } }
 
 bool dirExists(string path)  { try { if (isDir(path))  return true; else return false; } catch (Exception e) { return false; } }
 
-void do_content(string path) {
+void do_content(string url) {
   html_push("<div id=\"main-copy\"" ~ (nav_tree_vert? " class=\"main-copy-side-bar\"" : "")  ~ ">");
   html_push("<div id=\"main-copy\"" ~ (nav_tree_vert? " class=\"main-copy-side-bar\"" : "")  ~ ">");
-  string url = path[site_root.length..$];
-  switch (url) {
-    case "changelog":
-      html(shell(dweb_root ~ "bin/changelog"));
-      break;
-    default:
-      try {
-        if (isDir(path) && fileExists(path ~ "index.md")) path ~= "index.md";
-        if (fileExists(path)) do_markdown(path);
-      } catch (Exception e) {
-        not_found(path);
+  if (url == "" ? false : url[$-1] == '/') url ~= "index";
+  foreach (f; array(map!"a.name"(dirEntries(dirName(dweb_root ~ "/srv/" ~ url), SpanMode.shallow)))) {
+    if (isDir(f)) continue;
+    string name = baseName(f); name = name[0] == '@' ? name[1..$] : name;
+    if (stripExtension(name) == baseName(url)) {
+      foreach (string glob, string h; handlers) { 
+        if (globMatch(name, glob)) {
+          html(shell(dweb_root ~ "/bin/" ~ h ~ " " ~ f));
+          html_pop("</div>");
+          return;
+        }
       }
       }
+    }
   }
   }
-  html_pop("</div>\n");
+  if (baseName(url) != "index") not_found(url);
+  html_pop("</div>");
 }
 
 void do_footer() {
   html_push("<div id=\"footer\">");
 
   html_push("<div class=\"left\">");
 }
 
 void do_footer() {
   html_push("<div id=\"footer\">");
 
   html_push("<div class=\"left\">");
-  html("<a href=\"" ~ url_root ~ ".dweb\">Powered by dweb</a>");
+  html("<a href=\"" ~ url_root ~ "dweb\">Powered by dweb</a>");
   html_pop("</div>");
 
   html_push("<div class=\"right\">");
   html_pop("</div>");
 
   html_push("<div class=\"right\">");
@@ -168,21 +120,22 @@ void do_footer() {
 }
 
 void main(string[] args) {
 }
 
 void main(string[] args) {
+  init_handlers();
+  dweb_root = getcwd()[0..$-4]; // take out bin/
   html("Content-type: text/html\n");
   html("<!DOCTYPE html>");
   html_push("<html>\n");
 
   string url = getenv("SCRIPT_URL")[url_root.length..$];
   html("Content-type: text/html\n");
   html("<!DOCTYPE html>");
   html_push("<html>\n");
 
   string url = getenv("SCRIPT_URL")[url_root.length..$];
-  string path = site_root ~ url;
   
   
-  string pagename = last_in_path(url);
+  string pagename = baseName(url);
   if (pagename.length != 0) pagename = " - " ~ pagename;
   pagename = site_title ~ pagename;
   
   html_push("<head>");
   html("<title>" ~ pagename ~ "</title>");
   html("<link rel=\"stylesheet\" href=\"" ~ url_root ~ "pub/style/style.css\" type=\"text/css\" media=\"screen, handheld\" title=\"default\">");
   if (pagename.length != 0) pagename = " - " ~ pagename;
   pagename = site_title ~ pagename;
   
   html_push("<head>");
   html("<title>" ~ pagename ~ "</title>");
   html("<link rel=\"stylesheet\" href=\"" ~ url_root ~ "pub/style/style.css\" type=\"text/css\" media=\"screen, handheld\" title=\"default\">");
-  html("<link rel=\"shortcut\" href=\"" ~ url_root ~ "pub/favicon.ico\" type=\"image/vnd.microsoft.icon\">");
   html("<meta charset=\"UTF-8\">");
   html("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
   html_pop("</head>\n");
   html("<meta charset=\"UTF-8\">");
   html("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
   html_pop("</head>\n");
@@ -190,10 +143,10 @@ void main(string[] args) {
   html_push("<body" ~ (page_container? " style=\"text-align: center\"" : "")~ ">");
   if (page_container) html_push("<div id=\"container\">");
   do_header();
   html_push("<body" ~ (page_container? " style=\"text-align: center\"" : "")~ ">");
   if (page_container) html_push("<div id=\"container\">");
   do_header();
-  do_nav_tree(path);
-  do_content(path);
+  do_nav_tree(url);
+  do_content(url);
   do_footer();
   do_footer();
-  if (page_container) html_push("</div>");
+  if (page_container) html_pop("</div>");
   html_pop("</body>\n");
 
   html_pop("</html>");
   html_pop("</body>\n");
 
   html_pop("</html>");
diff --git a/srv/.dweb b/srv/.dweb
deleted file mode 100644 (file)
index 5a392e4..0000000
--- a/srv/.dweb
+++ /dev/null
@@ -1,53 +0,0 @@
-dweb - A simple website written in D
-=====
-dweb is a simple website framework based off the [werc][werc] software.
-
-Its principles are:
-
-- Database free, uses files and directories instead.
-- Written using the D programming language.
-- Minimize tedious work: eg., no need to ever write HTML, use markdown instead.
-- Very minimalist yet extensible codebase. Handlers for special things should be easy to add.
-
-It was created because werc was annoying to deploy on UW Computer Science Club's Apache setup and because [Not Invented Here](http://en.wikipedia.org/wiki/Not_Invented_Here).
-
-[werc]:http://werc.cat-v.org/
-[md]:http://daringfireball.net/projects/markdown
-
-Install Guide
-------
-You will need:
-- An HTTP server with CGI support.
-- The D compiler.
-
-Extract the contents into the location you want to serve webpages from. Edit the following files:
-
-- <code>$DWEB_ROOT/.htaccess</code>: make the paths work for your setup.
-- <code>$DWEB_ROOT/src/config.d</code>: change these strings as necessary.
-- <code>$DWEB_ROOT/src/web.d</code>: this is the main web code.
-- <code>$DWEB_ROOT/pub/</code>: static content goes here.
-- <code>$DWEB_ROOT/srv/</code>: directories, markdown webpages etc. go in here.
-- <code>$DWEB_ROOT/bin/</code>: custom handlers go here.
-
-Run <code>build</code> in <code>$DWEB_ROOT/src</code> to recompile the website software.
-
-Source
---------
-
-You can get the source code on [github](https://github.com/j3parker/dweb) or by running
-
-     git clone git://github.com/j3parker/dweb.git
-
-Contact
---------
-For questions, suggestions, bug reports and contributing patches email [j3parker](mailto:j3parker@csclub.uwaterloo.ca)
-
-License
--------
-Public domain.
-
-Credits
--------
-The idea and css stolen from [werc][werc]. This page itself also plagarised.
-
-Thanks to John Gruber for the [Markdown.pl][md] script.
diff --git a/srv/@changelog b/srv/@changelog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/srv/@dweb.md b/srv/@dweb.md
new file mode 100644 (file)
index 0000000..5a392e4
--- /dev/null
@@ -0,0 +1,53 @@
+dweb - A simple website written in D
+=====
+dweb is a simple website framework based off the [werc][werc] software.
+
+Its principles are:
+
+- Database free, uses files and directories instead.
+- Written using the D programming language.
+- Minimize tedious work: eg., no need to ever write HTML, use markdown instead.
+- Very minimalist yet extensible codebase. Handlers for special things should be easy to add.
+
+It was created because werc was annoying to deploy on UW Computer Science Club's Apache setup and because [Not Invented Here](http://en.wikipedia.org/wiki/Not_Invented_Here).
+
+[werc]:http://werc.cat-v.org/
+[md]:http://daringfireball.net/projects/markdown
+
+Install Guide
+------
+You will need:
+- An HTTP server with CGI support.
+- The D compiler.
+
+Extract the contents into the location you want to serve webpages from. Edit the following files:
+
+- <code>$DWEB_ROOT/.htaccess</code>: make the paths work for your setup.
+- <code>$DWEB_ROOT/src/config.d</code>: change these strings as necessary.
+- <code>$DWEB_ROOT/src/web.d</code>: this is the main web code.
+- <code>$DWEB_ROOT/pub/</code>: static content goes here.
+- <code>$DWEB_ROOT/srv/</code>: directories, markdown webpages etc. go in here.
+- <code>$DWEB_ROOT/bin/</code>: custom handlers go here.
+
+Run <code>build</code> in <code>$DWEB_ROOT/src</code> to recompile the website software.
+
+Source
+--------
+
+You can get the source code on [github](https://github.com/j3parker/dweb) or by running
+
+     git clone git://github.com/j3parker/dweb.git
+
+Contact
+--------
+For questions, suggestions, bug reports and contributing patches email [j3parker](mailto:j3parker@csclub.uwaterloo.ca)
+
+License
+-------
+Public domain.
+
+Credits
+-------
+The idea and css stolen from [werc][werc]. This page itself also plagarised.
+
+Thanks to John Gruber for the [Markdown.pl][md] script.