From: Michael D. Lowis Date: Sat, 23 May 2020 02:20:09 +0000 (-0400) Subject: initial commit X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=3f6317aefe79b39cfcdd1d6f35e64c7fde1b1f0c;p=projs%2Fawiki.git initial commit --- 3f6317aefe79b39cfcdd1d6f35e64c7fde1b1f0c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a0f3d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +html/ +pages/sitemap.md diff --git a/awiki.rb b/awiki.rb new file mode 100755 index 0000000..6128e9e --- /dev/null +++ b/awiki.rb @@ -0,0 +1,192 @@ +#!/usr/bin/env ruby +require 'open3' +require 'fileutils' +require 'webrick' +require 'redcarpet' + +# TODO: +# * Copy auxiliary files over +# * Add page attachment mechanism +# * Add edit shortcut +# * Add save shortcut +# * Add a create method +# * Add a delete method +# * Add a move/rename method +# * Add git revisioning for pages + +SITE_TITLE = "awiki" +SERVER_PORT = (ARGV[0] || 8080) +HTML_DIR = "./html/" +PAGES_DIR = "./pages/" +VIEW_TEMPLATE = "config/page.html.erb" +EDIT_TEMPLATE = "config/editor.html.erb" +PLANTUML_JAR = "config/plantuml.jar" +PLANTUML_CMD = "java -jar #{PLANTUML_JAR} -tsvg -pipe" + +class Page + def initialize(src) + @markdown = (File.exist?(src) ? File.read(src) : "") + @sanitized = @markdown.gsub(//,">") + @site_title = SITE_TITLE + @page_path = src.gsub(%r{/+},'/') + @gendate = Time.now.to_s + @page_title = (@markdown.match(/#\s*(.*)$/) || [])[1] + end + + def generate_graph(graph) + $plantuml_in.puts graph + data = "" + while not $plantuml_out.eof? + data += $plantuml_out.read_nonblock(32768) + break if data =~ /<\/svg>/ + end + "

"+data.sub(/<\?[^?]*\?>/,'')+"

" + end + + def parse_graphs + graph = nil + text = [] + @markdown.split("\n").each do |ln| + if graph.nil? and ln =~ /^@startuml/ then + graph = [ln] + elsif graph and ln =~ /^@enduml/ then + graph << ln + text << generate_graph(graph.join("\n")) + graph = nil + elsif graph + graph << ln + else + text << ln + end + end + text.join("\n") + end + + def view() + if not @article + @markdown = parse_graphs() + @article = $markdown.render(@markdown) + end + ERB.new(File.read(VIEW_TEMPLATE)).result(binding) + end + + def edit() + @article = ERB.new(File.read(EDIT_TEMPLATE)).result(binding) + view() + end +end + +def genallpages() + FileUtils.rm_rf(HTML_DIR) + Dir.glob("#{PAGES_DIR}/**/*.md").each do |f| + genpage(nil, f, true) + end + FileUtils.cp_r(Dir.glob("files/*"), HTML_DIR) +end + +def gensitemap() + links = [] + Dir.glob("#{PAGES_DIR}/**/*.md").each do |f| + path = f.sub(/\.([^.]*)$/, '.html').sub(/^#{PAGES_DIR}/, "") + title = (File.read(f).match(/#\s*(.*)$/) || [])[1] || path + links << { path: path, title: title } + end + File.open("#{PAGES_DIR}/sitemap.md", "w") do |f| + f.puts "" + f.puts "# Sitemap\n\n" + links.sort_by{|h| h[:title] }.each {|l| f.puts "[#{l[:title]}](#{l[:path]})
" } + end +end + +def genpage(path, src, force=false) + html = "" + htmlfile = src.sub(/\.([^.]*)$/, '.html').sub(/^#{PAGES_DIR}/, HTML_DIR) + puts "#{src} -> #{htmlfile}" + if not FileUtils.uptodate?(htmlfile, [src, VIEW_TEMPLATE]) or force + FileUtils.mkdir_p(File.dirname(htmlfile)) + html = Page.new(src).view() + File.open(htmlfile, "w") { |f| f.puts html } + else + html = File.read(htmlfile) + end + gensitemap() + html.sub("", + "[edit]") +end + +def do_post(req, res, path) + page_path = (PAGES_DIR + req.path).sub(/\.html$/, '.md') + FileUtils.mkdir_p(File.dirname(page_path)) + markup = req.query["markup"].gsub(//,"\n").gsub("\r\n","\n").gsub(/</,"<").gsub(/>/,">") + File.open(page_path, "wb") {|f| f.write(markup) } + res.status = 302 + res["Location"] = req.path +end + +def do_edit(req, resp, path, src) + html = Page.new(src).edit() + resp.body = html.sub("", + "[save]") +end + +def do_get(req, res, path) + if path.end_with?(".html") + page_path = PAGES_DIR + path.sub(/^\/html\//,'').sub(/\.html$/, ".md") + if (req.query["edit"] == "true") || (not File.exist?(page_path)) + do_edit(req, res, path, page_path) + else + res.body = genpage(path, page_path) + end + elsif File.exist?(HTML_DIR + path) + res.body = File.read(HTML_DIR + path) + else + res.status = 404 + res.body = "404 - file not found" + end +end + +#------------------------------------------------------------------------------- + +$plantuml_in, $plantuml_out, _ = Open3.popen2(PLANTUML_CMD) + +$markdown = Redcarpet::Markdown.new( + Redcarpet::Render::HTML.new( + escape_html: false, + with_toc_data: true + ), + no_intra_emphasis: true, + tables: true, + fenced_code_blocks: true, + autolink: true, + footnotes: true, + quotes: true, + highlights: true, + underline: true +) + +# Generate all pages from scratch +genallpages() + +$server = WEBrick::HTTPServer.new( + :Port => SERVER_PORT, + :SSLEnable => false, + :DocumentRoot => HTML_DIR, + :ServerAlias => 'localhost' +) + +$server.mount_proc '/' do |req, res| + rqtype = req.request_method + path = (req.path.end_with?("/") ? req.path + "index.html" : req.path) + if rqtype == "GET" + do_get(req, res, path) + elsif rqtype == "POST" + do_post(req, res, path) + end +end + +trap 'INT' do + $server.shutdown + genallpages() +end +$server.start + diff --git a/config/editor.html.erb b/config/editor.html.erb new file mode 100644 index 0000000..d4b4e54 --- /dev/null +++ b/config/editor.html.erb @@ -0,0 +1,27 @@ +

Edit - <%= @page_path %>


+ +
+ + +
<%= @sanitized %>
+
+ diff --git a/config/page.html.erb b/config/page.html.erb new file mode 100644 index 0000000..23f0893 --- /dev/null +++ b/config/page.html.erb @@ -0,0 +1,125 @@ + + + + + + <%= @site_title + (@page_title.nil? ? "" : " - #{@page_title}") %> + + + + + + + +
+ <%= @article %> +
+ + + + diff --git a/config/plantuml.jar b/config/plantuml.jar new file mode 100644 index 0000000..9ba86a7 Binary files /dev/null and b/config/plantuml.jar differ diff --git a/files/logo.png b/files/logo.png new file mode 100644 index 0000000..445b402 Binary files /dev/null and b/files/logo.png differ diff --git a/pages/index.md b/pages/index.md new file mode 100644 index 0000000..e8da45c --- /dev/null +++ b/pages/index.md @@ -0,0 +1,20 @@ +# Welcome! +Awiki is a tiny ruby script that implements a minimal wiki engine. The script is used for authoring the site and results in static HTML files that can then be published to your favorite hosting platform. + +## Features +* Markdown syntax +* PlantUML diagram generation +* Sitemap generation +* Browser-based page editor + +## Getting Started +To start a new wiki run the following commands: + +```` +git clone git://git.mdlowis.com/projs/awiki.git +cd awiki +./awiki.rb 8080 +```` + +This will run a local web server on port 8080. Navigate to http://localhost:8080 to see the home page. Every page will have an **[edit]** link or a **[save]** link in the upper right corner. These links are only available when served via the **awiki.rb** script. The raw generated HTML files will not have these links and can be published to any web server of your choosing. + diff --git a/pages/style.md b/pages/style.md new file mode 100644 index 0000000..f1bd61f --- /dev/null +++ b/pages/style.md @@ -0,0 +1,105 @@ +# Style +Simple showcase of styling and features available. + +# Heading 1 +## Heading 2 +### Heading 3 +#### Heading 4 +##### Heading 5 +###### Heading 6 + +--- + +[A link](https://www.example.com) + +https://www.example.com + +**Bold Text** + +*Italicized Text* + +_underlined text_ + +~~The world is flat.~~ + +"highlighted text" + +"quoted text" + +> This is a blockquote + +Here is some `code` inline. + + This is + a code block + +Unordered List: + +* item 1 +* item 2 +* item 3 + +Ordered List: + +1. item 1 +2. item 2 +3. item 3 + +dummy paragraph + +## Table Example + +
+ + + + + + + + + + + + +
Thisisatable
Thisisatable
+ +## Lorem Ipsum + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras eleifend purus non tempor finibus. Donec non turpis id magna egestas laoreet vel et erat. Mauris pulvinar fringilla nunc, quis sollicitudin arcu euismod ut. Phasellus eget gravida eros. Aenean aliquam purus vel semper facilisis. Nulla iaculis nec odio eget posuere. Nunc non justo sed justo ultrices ultrices. Maecenas ut aliquet tortor. Proin eu lectus a velit vestibulum posuere. Vivamus efficitur pulvinar volutpat. Vestibulum iaculis, lorem eget ultricies egestas, velit mi facilisis erat, ut congue sem orci eu metus. Nulla risus massa, suscipit id placerat at, molestie ac nulla. Nunc suscipit augue a risus porttitor egestas. In congue pretium faucibus. Sed porttitor, sapien ac consequat finibus, magna ante aliquet ipsum, quis luctus sem eros eget magna. Cras vitae ligula massa. + +Pellentesque mattis urna commodo dolor dictum eleifend. Phasellus ullamcorper venenatis diam eu finibus. Phasellus pellentesque eu leo et vehicula. Vivamus aliquam ante a tortor faucibus maximus ac eu urna. Maecenas et condimentum nisl. Vestibulum tristique lacus aliquet eros molestie, tincidunt ultrices quam porta. Morbi rhoncus ex in scelerisque rutrum. Fusce egestas dui nulla, nec tincidunt ante elementum volutpat. Nam mattis vehicula metus ac elementum. Aliquam erat volutpat. Mauris augue nibh, mollis at ligula nec, posuere tincidunt tortor. + +## UML Diagrams + +@startuml +actor Foo +actor Bar +Foo -> Bar : This is a label +@enduml + +## Flexbox Example + +
+
+
ONE
+
TWO
+
THREE
+
FOUR
+
FIVE
+
SIX
+
SEVEN
+
EIGHT
+
NINE
+
TEN
+
ELEVEN
+
TWELVE
+
+ +## Footnotes + +This references a footnote here [^1] and here[^2]; + +here are the references: +[^1]: Some reference... +[^2]: Some other reference...