-
-
Save kmafeni04/9f18504821fe7743eebb1b274529c631 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # NOTE: rewritten in lua, https://gist.github.com/kmafeni04/7c5a40443a9f5fd9d31e73a4bc7c47b0 | |
| echo "What would you like to name the project?:" | |
| read -r project_name | |
| mkdir "$project_name" | |
| cd "$project_name" || return | |
| luarocks install lapis --lua-version=5.1 | |
| luarocks install etlua --lua-version=5.1 | |
| lapis new --rockspec | |
| mkdir -p static/css static/assets static/js | |
| mkdir -p views/pages | |
| gitignore='logs/ | |
| nginx.conf.compiled | |
| *.sqlite | |
| *_temp/ | |
| ' | |
| echo "$gitignore" > .gitignore | |
| dockerfile='FROM openresty/openresty:jammy | |
| WORKDIR /app | |
| RUN apt update | |
| RUN apt install -y sqlite3 | |
| RUN apt install -y libssl-dev | |
| RUN apt install -y libsqlite3-dev | |
| RUN luarocks install luasec | |
| RUN luarocks install lapis | |
| RUN luarocks install etlua | |
| RUN luarocks install lsqlite3 | |
| RUN luarocks install tableshape | |
| COPY . . | |
| RUN lapis migrate production | |
| RUN chmod a+rw /app /app/* | |
| EXPOSE 8080 | |
| CMD ["lapis", "server", "production"] | |
| ' | |
| echo "$dockerfile" > Dockerfile | |
| index_etlua='<main> | |
| <h1> | |
| Welcome to | |
| <a href="https://leafo.net/lapis/" target="_blank">Lapis <%= require("lapis.version")%></a> | |
| </h1> | |
| <p>Edit the index.etlua file in views/pages to begin</p> | |
| </main> | |
| ' | |
| echo "$index_etlua" > views/pages/index.etlua | |
| reset_css=':root { | |
| --font-color-light: black; | |
| --font-color-dark: white; | |
| } | |
| @media (prefers-color-scheme: light) { | |
| :root { | |
| --font-color: var(--font-color-light); | |
| } | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| :root { | |
| --font-color: var(--font-color-dark); | |
| } | |
| } | |
| * { | |
| font-family: | |
| system-ui, | |
| -apple-system, | |
| BlinkMacSystemFont, | |
| "Segoe UI", | |
| Roboto, | |
| Oxygen, | |
| Ubuntu, | |
| Cantarell, | |
| "Open Sans", | |
| "Helvetica Neue", | |
| sans-serif; | |
| padding: 0; | |
| margin: 0; | |
| color: inherit; | |
| box-sizing: inherit; | |
| } | |
| *, | |
| *::after, | |
| *::before { | |
| box-sizing: inherit; | |
| } | |
| html { | |
| color-scheme: dark light; | |
| box-sizing: border-box; | |
| } | |
| @media (prefers-reduced-motion: no-preference) { | |
| html { | |
| scroll-padding-top: 4rem; | |
| scroll-behavior: smooth; | |
| } | |
| } | |
| body { | |
| color: var(--font-color); | |
| min-height: 100svh; | |
| } | |
| img, | |
| video, | |
| svg, | |
| picture { | |
| display: block; | |
| width: 100%; | |
| } | |
| input, | |
| textarea, | |
| button, | |
| select { | |
| font: inherit; | |
| } | |
| button { | |
| cursor: pointer; | |
| } | |
| ' | |
| echo "$reset_css" > static/css/reset.css | |
| live_js='/* | |
| Live.js - One script closer to Designing in the Browser | |
| Written for Handcraft.com by Martin Kool (@mrtnkl). | |
| Version 4. | |
| Recent change: Made stylesheet and mimetype checks case insensitive. | |
| http://livejs.com | |
| http://livejs.com/license (MIT) | |
| @livejs | |
| Include live.js#css to monitor css changes only. | |
| Include live.js#js to monitor js changes only. | |
| Include live.js#html to monitor html changes only. | |
| Mix and match to monitor a preferred combination such as live.js#html,css | |
| By default, just include live.js to monitor all css, js and html changes. | |
| Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then, | |
| as a page reload due to a change in html or css would not re-include the bookmarklet. | |
| To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify | |
| */ | |
| (function () { | |
| var headers = { "Etag": 1, "Last-Modified": 1, "Content-Length": 1, "Content-Type": 1 }, | |
| resources = {}, | |
| pendingRequests = {}, | |
| currentLinkElements = {}, | |
| oldLinkElements = {}, | |
| interval = 1000, | |
| loaded = false, | |
| active = { "html": 1, "css": 1, "js": 1 }; | |
| var Live = { | |
| // performs a cycle per interval | |
| heartbeat: function () { | |
| if (document.body) { | |
| // make sure all resources are loaded on first activation | |
| if (!loaded) Live.loadresources(); | |
| Live.checkForChanges(); | |
| } | |
| setTimeout(Live.heartbeat, interval); | |
| }, | |
| // loads all local css and js resources upon first activation | |
| loadresources: function () { | |
| // helper method to assert if a given url is local | |
| function isLocal(url) { | |
| var loc = document.location, | |
| reg = new RegExp("^\\.|^\/(?!\/)|^[\\w]((?!://).)*$|" + loc.protocol + "//" + loc.host); | |
| return url.match(reg); | |
| } | |
| // gather all resources | |
| var scripts = document.getElementsByTagName("script"), | |
| links = document.getElementsByTagName("link"), | |
| uris = []; | |
| // track local js urls | |
| for (var i = 0; i < scripts.length; i++) { | |
| var script = scripts[i], src = script.getAttribute("src"); | |
| if (src && isLocal(src)) | |
| uris.push(src); | |
| if (src && src.match(/\blive.js#/)) { | |
| for (var type in active) | |
| active[type] = src.match("[#,|]" + type) != null | |
| if (src.match("notify")) | |
| alert("Live.js is loaded."); | |
| } | |
| } | |
| if (!active.js) uris = []; | |
| if (active.html) uris.push(document.location.href); | |
| // track local css urls | |
| for (var i = 0; i < links.length && active.css; i++) { | |
| var link = links[i], rel = link.getAttribute("rel"), href = link.getAttribute("href", 2); | |
| if (href && rel && rel.match(new RegExp("stylesheet", "i")) && isLocal(href)) { | |
| uris.push(href); | |
| currentLinkElements[href] = link; | |
| } | |
| } | |
| // initialize the resources info | |
| for (var i = 0; i < uris.length; i++) { | |
| var url = uris[i]; | |
| Live.getHead(url, function (url, info) { | |
| resources[url] = info; | |
| }); | |
| } | |
| // add rule for morphing between old and new css files | |
| var head = document.getElementsByTagName("head")[0], | |
| style = document.createElement("style"), | |
| rule = "transition: all .3s ease-out;" | |
| css = [".livejs-loading * { ", rule, " -webkit-", rule, "-moz-", rule, "-o-", rule, "}"].join(''); | |
| style.setAttribute("type", "text/css"); | |
| head.appendChild(style); | |
| style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(document.createTextNode(css)); | |
| // yep | |
| loaded = true; | |
| }, | |
| // check all tracking resources for changes | |
| checkForChanges: function () { | |
| for (var url in resources) { | |
| if (pendingRequests[url]) | |
| continue; | |
| Live.getHead(url, function (url, newInfo) { | |
| var oldInfo = resources[url], | |
| hasChanged = false; | |
| resources[url] = newInfo; | |
| for (var header in oldInfo) { | |
| // do verification based on the header type | |
| var oldValue = oldInfo[header], | |
| newValue = newInfo[header], | |
| contentType = newInfo["Content-Type"]; | |
| switch (header.toLowerCase()) { | |
| case "etag": | |
| if (!newValue) break; | |
| // fall through to default | |
| default: | |
| hasChanged = oldValue != newValue; | |
| break; | |
| } | |
| // if changed, act | |
| if (hasChanged) { | |
| Live.refreshResource(url, contentType); | |
| break; | |
| } | |
| } | |
| }); | |
| } | |
| }, | |
| // act upon a changed url of certain content type | |
| refreshResource: function (url, type) { | |
| switch (type.toLowerCase()) { | |
| // css files can be reloaded dynamically by replacing the link element | |
| case "text/css": | |
| var link = currentLinkElements[url], | |
| html = document.body.parentNode, | |
| head = link.parentNode, | |
| next = link.nextSibling, | |
| newLink = document.createElement("link"); | |
| html.className = html.className.replace(/\s*livejs\-loading/gi, '') + " livejs-loading"; | |
| newLink.setAttribute("type", "text/css"); | |
| newLink.setAttribute("rel", "stylesheet"); | |
| newLink.setAttribute("href", url + "?now=" + new Date() * 1); | |
| next ? head.insertBefore(newLink, next) : head.appendChild(newLink); | |
| currentLinkElements[url] = newLink; | |
| oldLinkElements[url] = link; | |
| // schedule removal of the old link | |
| Live.removeoldLinkElements(); | |
| break; | |
| // check if an html resource is our current url, then reload | |
| case "text/html": | |
| if (url != document.location.href) | |
| return; | |
| // local javascript changes cause a reload as well | |
| case "text/javascript": | |
| case "application/javascript": | |
| case "application/x-javascript": | |
| document.location.reload(); | |
| } | |
| }, | |
| // removes the old stylesheet rules only once the new one has finished loading | |
| removeoldLinkElements: function () { | |
| var pending = 0; | |
| for (var url in oldLinkElements) { | |
| // if this sheet has any cssRules, delete the old link | |
| try { | |
| var link = currentLinkElements[url], | |
| oldLink = oldLinkElements[url], | |
| html = document.body.parentNode, | |
| sheet = link.sheet || link.styleSheet, | |
| rules = sheet.rules || sheet.cssRules; | |
| if (rules.length >= 0) { | |
| oldLink.parentNode.removeChild(oldLink); | |
| delete oldLinkElements[url]; | |
| setTimeout(function () { | |
| html.className = html.className.replace(/\s*livejs\-loading/gi, ''); | |
| }, 100); | |
| } | |
| } catch (e) { | |
| pending++; | |
| } | |
| if (pending) setTimeout(Live.removeoldLinkElements, 50); | |
| } | |
| }, | |
| // performs a HEAD request and passes the header info to the given callback | |
| getHead: function (url, callback) { | |
| pendingRequests[url] = true; | |
| var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp"); | |
| xhr.open("HEAD", url, true); | |
| xhr.onreadystatechange = function () { | |
| delete pendingRequests[url]; | |
| if (xhr.readyState == 4 && xhr.status != 304) { | |
| xhr.getAllResponseHeaders(); | |
| var info = {}; | |
| for (var h in headers) { | |
| var value = xhr.getResponseHeader(h); | |
| // adjust the simple Etag variant to match on its significant part | |
| if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, ''); | |
| if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1"); | |
| info[h] = value; | |
| } | |
| callback(url, info); | |
| } | |
| } | |
| xhr.send(); | |
| } | |
| }; | |
| // start listening | |
| if (document.location.protocol != "file:") { | |
| if (!window.liveJsLoaded) | |
| Live.heartbeat(); | |
| window.liveJsLoaded = true; | |
| } | |
| else if (window.console) | |
| console.log("Live.js does not support the file protocol. It needs http."); | |
| })(); | |
| ' | |
| echo "$live_js" > static/js/live.js | |
| app_lua='local lapis = require("lapis") | |
| local app = lapis.Application() | |
| app:enable("etlua") | |
| app.layout = require "views.layout" | |
| app:get("/", function() | |
| return {render = "pages.index"} | |
| end) | |
| return app | |
| ' | |
| echo "$app_lua" > app.lua | |
| layout='<!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title><%= Page_title or "Lapis Page" %></title> | |
| <link rel="stylesheet" href="/static/css/reset.css" /> | |
| <script src="/static/js/live.js"></script> | |
| </head> | |
| <body> | |
| <% content_for("inner") %> | |
| </body> | |
| </html> | |
| ' | |
| echo "$layout" > views/layout.etlua | |
| git init | |
| git add . | |
| eval "$(luarocks path)" | |
| echo "To start the server:" | |
| echo "" | |
| echo "cd $project_name/" | |
| echo "lapis server" | |
| echo "Open your browser at http://localhost:8080" |
This looks nice. I would use this for sure! I think it would be nice if there can be a choice between using strictly the api or using the api and etlua.
granted this looks great already!
There
- In line 11: Bash wouldn't recognize that command if it's not in
PATH, unless you have./lua_modules/bin/lapisinstead.
Do you have a recommended solution cause the only way I can think about this is to add the path to the .bashrc
- In line 14-17: You can simply remove the mkdir static and add -p to the rests of mkdir args, it will create a directory recursively.
Never knew about this, thanks
In test.sh line 37:
index_etlua='
^-- SC2089 (warning): Quotes/backslashes will be treated literally. Use an array.
Will probably just ignore this honestly
This looks nice. I would use this for sure! I think it would be nice if there can be a choice between using strictly the api or using the api and etlua.
granted this looks great already!
I'll try and implement that
Do you have a recommended solution cause the only way I can think about this is to add the path to the .bashrc
You can replace that with function that fallbacks to ~/lua_modules/bin/lapis
lapis() {
declare cmd=./lua_modules/bin/lapis
if command -v lapis >/dev/null; then
cmd=lapis
fi
command "$cmd" "$@"
}But this might be not the rightest answer, it all depends on how you set up your shell and etc. I usually use direnv for project-wide PATH and Luarocks settings.
I usually use direnv for project-wide
PATHand Luarocks settings.
I have all my rocks installed in $HOME/.luarocks. I believe it would be pretty hard to accommodate everyone's specific use case. Maybe an environment variable for the luarocks bin could work?
PATH, unless you have./lua_modules/bin/lapisinstead.mkdir staticand add-pto the rests ofmkdirargs, it will create a directory recursively.mkdir viewsand add-pflag formkdir views/pages.For the rest of it, I'll let Shellcheck do the job instead:
Shellcheck output