diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-01-25 12:57:36 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-01-25 12:57:36 +0000 |
| commit | 2b91c3d0af33099f7b260a41efac252655104c50 (patch) | |
| tree | 4636152e118d90381a584f2636da34efbe8dd568 /build | |
| parent | correction in portfolio (diff) | |
| parent | update README.md (diff) | |
| download | mmm-2b91c3d0af33099f7b260a41efac252655104c50.tar.gz mmm-2b91c3d0af33099f7b260a41efac252655104c50.zip | |
Merge branch 'ba'
Diffstat (limited to 'build')
| -rw-r--r-- | build/bundle_fileder.moon | 155 | ||||
| -rw-r--r-- | build/fsck.moon | 37 | ||||
| -rw-r--r-- | build/import.moon | 53 | ||||
| -rw-r--r-- | build/layout.moon | 109 | ||||
| -rw-r--r-- | build/render_all.moon | 32 | ||||
| -rw-r--r-- | build/render_fileder.moon | 93 | ||||
| -rw-r--r-- | build/server.moon | 231 | ||||
| -rw-r--r-- | build/util.moon | 16 |
8 files changed, 353 insertions, 373 deletions
diff --git a/build/bundle_fileder.moon b/build/bundle_fileder.moon deleted file mode 100644 index c9f8c35..0000000 --- a/build/bundle_fileder.moon +++ /dev/null @@ -1,155 +0,0 @@ -require 'mmm' -import get_path from require 'build.util' -import Fileder, Key from require 'mmm.mmmfs.fileder' -import opairs from require 'mmm.ordered' -import to_lua from require 'moonscript.base' - --- usage: --- moon bundle_fileder.moon <path_to_root> <dirname> <facets>... -- <children>... -{ path_to_root, dirname } = arg - -assert path_to_root, "please specify the relative root path" -assert dirname, "please specify the fileder dirname" -path = get_path path_to_root - -facets = {} -children_bundles = {} - -do - addto = facets - for file in *arg[3,] - continue if file == 'Tupdefault.lua' - - if file == '--' - addto = children_bundles - continue - table.insert addto, file - --- load a fs file as a fileder facet -load_facet = (filename) -> - key = (filename\match '(.*)%.%w+') or filename - key = Key key\gsub '%$', '/' - key.filename = filename - - file = assert (io.open filename, 'r'), "couldn't open facet file '#{filename}'" - value = file\read '*all' - file\close! - - key, value - --- escape a string for lua aparser -escape = (str) -> string.format '%q', tostring str - --- dump a fileder subtree as Lua source -dump_fileder = do - _dump = (fileder, root=false) -> - code = "Fileder {" - - for key, val in pairs fileder.facets - if key.original - key = "fromcache(#{escape key}, #{escape key.original})" - else - key = escape key - code ..= "\n[#{key}] = #{escape val}," - - for child in *fileder.children - code ..= "\n#{_dump child}," - - code ..= "\n}" - code - - - (fileder) -> " -local mmmfs = require 'mmm.mmmfs' -local Key, Fileder = mmmfs.Key, mmmfs.Fileder -local function fromcache(str, orig) - local key = Key(str) - key.original = Key(orig) - return key -end - -return #{_dump fileder, true} - " - -renders = { - { - inp: '^text/moonscript %-> (.*)' - out: 'text/lua -> %1' - render: (val, fileder, old, new) -> - lua, err = to_lua val - - if not lua - error "Error compiling #{old}: #{err}" - - "-- this moonscript facet has been transpiled to --- '#{new}' for execution in the browser. --- refer to the original facet as the source. -#{lua}" - }, - { - inp: '^image/' - out: 'URL -> %0' - render: (val, fileder, old, new) -> "#{fileder.path}/#{old.filename}", "[binary removed]" - }, - { - inp: '^video/' - out: 'URL -> %0' - render: (val, fileder, old, new) -> "#{fileder.path}/#{old.filename}", "[binary removed]" - }, -} - -with io.open '$bundle.lua', 'w' - \write dump_fileder with fileder = Fileder 'name: alpha': dirname - \mount path, true - - order = nil - children = {} - - for facet in *facets - if facet == '$order' - order = [line for line in io.lines facet] - continue - key, value = load_facet facet - .facets[key] = value - - extra_facets = {} - for key, value in pairs .facets - for { :inp, :out, :render } in *renders - continue unless key.type\match inp - - built_key = Key key.name, key.type\gsub inp, out - built_key.original = key - - -- dont overwrite existing keys - continue if \has built_key - - rendered, replace = render value, fileder, key, built_key - - extra_facets[built_key] = rendered - .facets[key] = replace if replace - - break - - for k,v in pairs extra_facets - .facets[k] = v - - for child in *children_bundles - -- @BUG: child bundles are malformed due to Tup bug ($ symbol) - child = child\gsub '/%.lua$', '/$bundle.lua' - - dirname = assert child\match '^([%w-_%.]+)/%$bundle%.lua$' - children[dirname] = dofile child - - if order - -- order from order file - for i, name in pairs order - child = assert children[name], "child in $order but not fs: #{name}" - table.insert .children, child - children[name] = nil - - -- sort remainder alphabeticalally - for name, child in opairs children - table.insert .children, child - warn "child #{name} not in $order!" if order - - \close! diff --git a/build/fsck.moon b/build/fsck.moon new file mode 100644 index 0000000..df882a9 --- /dev/null +++ b/build/fsck.moon @@ -0,0 +1,37 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' + +import get_store from require 'mmm.mmmfs.stores' + +-- usage: +-- moon server.moon [FLAGS] [STORE] [host] [port] +-- * FLAGS - any of the following: +-- --[no-]rw - enable/disable POST?PUT/DELETE operations (default: on if local) +-- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local or --no-rw) +-- * STORE - see mmm/mmmfs/stores/init.moon:get_store +-- * host - interface to bind to (default localhost, set to 0.0.0.0 for public hosting) +-- * port - port to serve from, default 8000 + +flags = {} +arguments = for a in *arg + if flag = a\match '^%-%-no%-(.*)$' + flags[flag] = false + continue + elseif flag = a\match '^%-%-(.*)$' + flags[flag] = true + continue + else + a + +{ store, host, port } = arguments + +store = get_store store, verbose: true +store\fsck! diff --git a/build/import.moon b/build/import.moon new file mode 100644 index 0000000..92d4397 --- /dev/null +++ b/build/import.moon @@ -0,0 +1,53 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +require 'lfs' +import Key from require 'mmm.mmmfs.fileder' +import SQLStore from require 'mmm.mmmfs.stores.sql' + +-- usage: +-- moon import.moon <root> [output.sqlite3] +{ root, store } = arg + +assert root, "please specify the root directory" + +-- load a fs file as a fileder facet +load_facet = (filename, filepath) -> + key = (filename\match '(.*)%.%w+') or filename + key = Key key\gsub '%$', '/' + key.filename = filename + + file = assert (io.open filepath, 'rb'), "couldn't open facet file '#{filename}'" + value = file\read '*all' + file\close! + + key, value + +with SQLStore :file, verbose: true + import_fileder = (fileder, dirpath) -> + for file in lfs.dir dirpath + continue if '.' == file\sub 1, 1 + continue if file == 'Tupdefault.lua' + continue if file == 'index.html' + continue if file == '$order' + + filepath = "#{dirpath}/#{file}" + switch lfs.attributes filepath, 'mode' + when 'file' + key, value = load_facet file, filepath + \create_facet fileder, key.name, key.type, value + when 'directory' + next_fileder = \create_fileder fileder, file + -- \create_facet next_fileder, 'name', 'alpha', file + import_fileder next_fileder, filepath + else + warn "unknown entry type '#{attr.mode}'" + + import_fileder '', root diff --git a/build/layout.moon b/build/layout.moon deleted file mode 100644 index 7985371..0000000 --- a/build/layout.moon +++ /dev/null @@ -1,109 +0,0 @@ -import header, aside, footer, div, svg, script, g, circle, h1, span, b, a, img from require 'mmm.dom' -import navigate_to from (require 'mmm.mmmfs.util') require 'mmm.dom' - -pick = (...) -> - num = select '#', ... - i = math.ceil math.random! * num - select i, ... - -iconlink = (href, src, alt, style) -> a { - class: 'iconlink', - target: '_blank', - rel: 'me', - :href, - img :src, :alt, :style -} - -logo = svg { - class: 'sun' - viewBox: '-0.75 -1 1.5 2' - xmlns: 'http://www.w3.org/2000/svg' - baseProfile: 'full' - version: '1.1' - - g { - transform: 'translate(0 .18)' - - g { class: 'circle out', circle r: '.6', fill: 'none', 'stroke-width': '.12' } - g { class: 'circle in', circle r: '.2', stroke: 'none' } - } -} - -{ - header: header { - div { - h1 { - navigate_to '/', logo - span { - span 'mmm', class: 'bold' - '​' - '.s‑ol.nu' - } - } - span "fun stuff with code and wires" - -- pick 'fun', 'cool', 'weird', 'interesting', 'new' - -- pick 'stuff', 'things', 'projects', 'experiments', 'news' - -- "with" - -- pick 'mostly code', 'code and wires', 'silicon', 'electronics' - } - aside { - navigate_to '/about', 'about me' - navigate_to '/portfolio', 'portfolio' - navigate_to '/games', 'games' - navigate_to '/projects', 'other' - a { - href: 'mailto:s%20[removethis]%20[at]%20s-ol.nu' - 'contact' - script " - var l = document.currentScript.parentElement; - l.href = l.href.replace('%20[at]%20', '@'); - l.href = l.href.replace('%20[removethis]', '') + '?subject=Hey there :)'; - " - } - } - } - footer: footer { - span { - 'made with \xe2\x98\xbd by ' - a 's-ol', href: 'https://twitter.com/S0lll0s' - ", #{os.date '%Y'}" - } - div { - class: 'icons', - iconlink 'https://github.com/s-ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/github.svg', 'github' - iconlink 'https://merveilles.town/@s_ol', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/mastodon.svg', 'mastodon' - iconlink 'https://twitter.com/S0lll0s', 'https://cdn.jsdelivr.net/npm/simple-icons@latest/icons/twitter.svg', 'twitter' - iconlink 'https://webring.xxiivv.com/#random', 'https://webring.xxiivv.com/icon.black.svg', 'webring', - { height: '1.3em', 'margin-left': '.3em', 'margin-top': '-0.12em' } - } - } - get_meta: => - title = (@get 'title: text/plain') or @gett 'name: alpha' - - l = (str) -> - str = str\gsub '[%s\\n]+$', '' - str\gsub '\\n', ' ' - e = (str) -> string.format '%q', l str - - meta = " - <meta charset=\"UTF-8\"> - <title>#{l title}</title> - " - - if page_meta = @get '_meta: mmm/dom' - meta ..= page_meta - else - meta ..= " - <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"> - - <meta property=\"og:title\" content=#{e title} /> - <meta property=\"og:type\" content=\"website\" /> - <meta property=\"og:url\" content=\"https://mmm.s-ol.nu#{@path}/\" /> - <meta property=\"og:site_name\" content=\"mmm\" />" - - if desc = @get 'description: text/plain' - meta ..= " - <meta property=\"og:description\" content=#{e desc} />" - - meta -} diff --git a/build/render_all.moon b/build/render_all.moon new file mode 100644 index 0000000..b09957e --- /dev/null +++ b/build/render_all.moon @@ -0,0 +1,32 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' +import Fileder from require 'mmm.mmmfs.fileder' +import get_store from require 'mmm.mmmfs.stores' +import render from require 'mmm.mmmfs.layout' + +-- usage: +-- moon render_all.moon [STORE] [startpath] +{ store, startpath } = arg + +export STATIC +STATIC = true + +store = get_store store +tree = Fileder store +tree = tree\walk startpath if startpath + +for fileder in coroutine.wrap tree\iterate + print "rendering '#{fileder.path}'..." + os.execute "mkdir -p 'out/#{fileder.path}'" + + with io.open "out/#{fileder.path}/index.html", 'w' + \write render (fileder\get 'text/html'), fileder + \close! diff --git a/build/render_fileder.moon b/build/render_fileder.moon deleted file mode 100644 index 76c7856..0000000 --- a/build/render_fileder.moon +++ /dev/null @@ -1,93 +0,0 @@ -require 'mmm' -import get_path from require 'build.util' -import tohtml from require 'mmm.component' -import Browser from require 'mmm.mmmfs.browser' -import get_meta, header, footer from require 'build.layout' - -export BROWSER - --- usage: --- moon render.moon <path_to_root> -{ path_to_root } = arg - -assert path_to_root, "please specify the relative root path" -path = get_path path_to_root - -do - seed = (str) -> - len = #str - rnd = -> math.ceil math.random! * len - - math.randomseed len - - return if len == 0 - - upper, lower = 0, 0 - for i=1,4 - upper += str\byte rnd! - upper *= 0x100 - - lower += str\byte rnd! - lower *= 0x100 - - math.randomseed upper, lower - - seed path - -root = dofile '$bundle.lua' -assert root, "couldn't load $bundle.lua" -root\mount path, true - -BROWSER = Browser root, path - -with io.open 'index.html', 'w' - \write [[ -<!DOCTYPE html> -<html> - <head> - <link rel="stylesheet" type="text/css" href="/main.css" /> - <!-- - <link rel="preload" as="fetch" href="/mmm/dom/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/component/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/init.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/fileder.lua" /> - <link rel="preload" as="fetch" href="/mmm/mmmfs/browser.lua" /> - --> - - <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400" rel="stylesheet"> - ]] - \write " - #{get_meta root} - </head> - <body> - #{header} - - #{assert (tohtml BROWSER), "couldn't render BROWSER"} - - #{footer} - " - \write [[ - <script src="/highlight.pack.js"></script> - <script src="//cdnjs.cloudflare.com/ajax/libs/marked/0.5.1/marked.min.js"></script> - <script src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script> - <script src="//platform.twitter.com/widgets.js" charset="utf-8"></script> - <script src="/fengari-web.js"></script> - <script type="application/lua" src="/mmm.bundle.lua"></script> - <script type="application/lua">require 'mmm'</script> - ]] - \write " - <script type=\"application/lua\"> - on_load = on_load or {} - table.insert(on_load, function() - local path = #{string.format '%q', path} - local browser = require 'mmm.mmmfs.browser' - local root = dofile '/$bundle.lua' - root:mount('', true) - - BROWSER = browser.Browser(root, path, true) - end) - </script> - </body> -</html> - " - \close! diff --git a/build/server.moon b/build/server.moon new file mode 100644 index 0000000..7c0ff46 --- /dev/null +++ b/build/server.moon @@ -0,0 +1,231 @@ +add = (tmpl) -> + package.path ..= ";#{tmpl}.lua" + package.moonpath ..= ";#{tmpl}.moon" + +add '?' +add '?.server' +add '?/init' +add '?/init.server' + +require 'mmm' + +import dir_base, Key, Fileder from require 'mmm.mmmfs.fileder' +import convert, MermaidDebugger from require 'mmm.mmmfs.conversion' +import get_store from require 'mmm.mmmfs.stores' +import render from require 'mmm.mmmfs.layout' +import Browser from require 'mmm.mmmfs.browser' +import decodeURI from require 'http.util' + +lfs = require 'lfs' +server = require 'http.server' +headers = require 'http.headers' + +class Server + new: (@store, opts={}) => + opts = {k,v for k,v in pairs opts} + opts.host = 'localhost' unless opts.host + opts.port = 8000 unless opts.port + opts.onstream = @\stream + opts.onerror = @\error + + @server = server.listen opts + + @flags = opts.flags + + if @flags.rw == nil + @flags.rw = opts.host == 'localhost' or opts.host == '127.0.0.1' + + if @flags.unsafe == nil + @flags.unsafe = not @flags.rw or opts.host == 'localhost' or opts.host == '127.0.0.1' + + export UNSAFE + UNSAFE = @flags.unsafe + require 'mmm.mmmfs' + + listen: => + assert @server\listen! + + _, ip, port = @server\localname! + print "[#{@@__name}]", + "running at #{ip}:#{port}", + "[#{table.concat [flag for flag,on in pairs @flags when on], ', '}]" + + assert @server\loop! + + handle_interactive: (fileder, facet) => + root = Fileder @store + browser = Browser root, fileder.path, facet.name + + deps = [[ + <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/svg.js/2.6.6/svg.min.js"></script> + <script type="text/javascript" src="//unpkg.com/mermaid@8.4.0/dist/mermaid.min.js"></script> + <script type="text/javascript" src="//unpkg.com/marked@0.7.0/marked.min.js"></script> + <link rel="stylesheet" type="text/css" href="//unpkg.com/codemirror@5.49.2/lib/codemirror.css" /> + <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/lib/codemirror.js"></script> + <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/lua/lua.js"></script> + <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/mode/markdown/markdown.js"></script> + <script type="text/javascript" src="//unpkg.com/codemirror@5.49.2/addon/display/autorefresh.js"></script> + <script type="text/javascript" src="/static/fengari-web/:text/javascript"></script> + <script type="text/lua" src="/static/mmm/:text/lua"></script> + <script type="text/lua">require 'mmm'; require 'mmm.mmmfs'</script>]] + + render browser\todom!, fileder, noview: true, scripts: deps .. " + <script type=\"text/lua\"> + on_load = on_load or {} + table.insert(on_load, function() + local path = #{string.format '%q', fileder.path} + local facet = #{string.format '%q', facet.name} + local browser = require 'mmm.mmmfs.browser' + local fileder = require 'mmm.mmmfs.fileder' + local web = require 'mmm.mmmfs.stores.web' + + local store = web.WebStore({ verbose = true }) + local root = fileder.Fileder(store, store:get_index(nil, -1)) + + local err_and_trace = function (msg) return debug.traceback(msg, 2) end + local ok, browser = xpcall(browser.Browser, err_and_trace, root, path, facet, true) + if not ok then error(browser) end + end) + </script>" + + handle_debug: (fileder, facet) => + debugger = MermaidDebugger! + fileder\find facet, nil, nil, nil, debugger + convert 'text/mermaid-graph', 'text/html', debugger\render!, fileder, facet.name + + handle: (method, path, facet, value) => + if not @flags.rw and method != 'GET' and method != 'HEAD' + return 403, 'editing not allowed' + + switch method + when 'GET', 'HEAD' + root = Fileder @store + export BROWSER + BROWSER = :root + fileder = root\walk path -- Fileder @store, path + + if not fileder + -- fileder not found + return 404, "fileder '#{path}' not found" + + val = switch facet.name + when '?index', '?tree' + -- serve fileder index + -- '?index': one level deep + -- '?tree': recursively + depth = if facet.name == '?tree' then -1 else 1 + index = @store\get_index path, depth + convert 'table', facet.type, index, fileder, facet.name + else + if facet.type == 'text/html+interactive' + @handle_interactive fileder, facet + else if base = facet.type\match '^DEBUG %-> (.*)' + facet.type = base + @handle_debug fileder, facet + else if not fileder\has_facet facet.name + 404, "facet '#{facet.name}' not found in fileder '#{path}'" + else + fileder\get facet + + if val + 200, val + else + 406, "cant convert facet '#{facet.name}' to '#{facet.type}'" + when 'POST' + if facet + @store\create_facet path, facet.name, facet.type, value + 200, 'ok' + else + 200, @store\create_fileder dir_base path + when 'PUT' + if facet + @store\update_facet path, facet.name, facet.type, value + 200, 'ok' + else + cmd, args = value\match '^([^\n]+)\n(.*)' + switch cmd + when 'swap' + child_a, child_b = args\match '^([^\n]+)\n([^\n]+)$' + assert child_a and child_b, "invalid arguments" + + @store\swap_fileders path, child_a, child_b + 200, 'ok' + when nil + 400, "invalid request" + else + 501, "unknown command #{cmd}" + when 'DELETE' + if facet + @store\remove_facet path, facet.name, facet.type + else + @store\remove_fileder path + 200, 'ok' + else + 501, "not implemented" + + err_and_trace = (msg) -> debug.traceback msg, 2 + stream: (sv, stream) => + req = stream\get_headers! + method = req\get ':method' + path = req\get ':path' + path = decodeURI path + + path_facet, type = path\match '(.*):(.*)' + path_facet or= path + path, facet = path_facet\match '(.*)/([^/]*)' + + facet = if facet == '' and type == '' and method ~= 'GET' and method ~= 'HEAD' + nil + else + type or= 'text/html+interactive' + type = type\match '%s*(.*)' + Key facet, type + + value = stream\get_body_as_string! + ok, status, body = xpcall @.handle, err_and_trace, @, method, path, facet, value + if not ok + warn "Error handling request (#{method} #{path} #{facet}):\n#{status}" + body = "Internal Server Error:\n#{status}" + status = 500 + + res = headers.new! + response_type = if status > 299 then 'text/plain' + else if facet and facet.type == 'text/html+interactive' then 'text/html' + else if facet then facet.type + else 'text/plain' + res\append ':status', tostring status + res\append 'content-type', response_type + + stream\write_headers res, method == 'HEAD' + if method ~= 'HEAD' + stream\write_chunk body, true + + error: (sv, ctx, op, err, errno) => + msg = "#{op} on #{tostring ctx} failed" + msg = "#{msg}: #{err}" if err + +-- usage: +-- moon server.moon [FLAGS] [STORE] [host] [port] +-- * FLAGS - any of the following: +-- --[no-]rw - enable/disable POST?PUT/DELETE operations (default: on if local) +-- --[no-]unsafe - enable/disable server-side code execution when writable is on (default: on if local or --no-rw) +-- * STORE - see mmm/mmmfs/stores/init.moon:get_store +-- * host - interface to bind to (default localhost, set to 0.0.0.0 for public hosting) +-- * port - port to serve from, default 8000 + +flags = {} +arguments = for a in *arg + if flag = a\match '^%-%-no%-(.*)$' + flags[flag] = false + continue + elseif flag = a\match '^%-%-(.*)$' + flags[flag] = true + continue + else + a + +{ store, host, port } = arguments + +store = get_store store +server = Server store, :flags, :host, port: port and tonumber port +server\listen! diff --git a/build/util.moon b/build/util.moon deleted file mode 100644 index b9c9613..0000000 --- a/build/util.moon +++ /dev/null @@ -1,16 +0,0 @@ -require 'lfs' - -get_path = (root) -> - cwd = lfs.currentdir! - path = '' - - while root\find '^%.%./' - root = root\match '^%.%./(.*)' - cwd, trimmed = cwd\match '(.*)(/[^/]+)$' - path = trimmed .. path - - path - -{ - :get_path -} |
