...
 
Commits (3)
...@@ -16,3 +16,12 @@ Install ...@@ -16,3 +16,12 @@ Install
To do To do
-------------------------- --------------------------
* (websockets-based) view to monitor output of make command * (websockets-based) view to monitor output of make command
* add --js option to mixin custom javascript plugins (a la greasemonkey)
* add --saveable option to mixin saveable javascript
makewiki (aka cookbook)
--------------------------
Curated set of deployable makefiles
For instance to convert AVI to webm
avi=$(shell ls *.AVI)
aviwebm=$(avi:%.AVI=%.webm)
all: $(aviwebm)
%.webm: %.AVI
ffmpeg -i $< -s 360x270 -c:a libvorbis -c:v libvpx $@
# find all .md files in the directory
# mdsrc=$(shell ls *.md)
mdsrc=$(shell find . -iname "*.md")
# mdsrc=$(wildcard *.md */*.md **/*.md )
# map *.mp => *.html for mdsrc
html_from_md=$(mdsrc:%.md=%.html)
all: $(html_from_md)
fixnames:
rename "s/ /_/g" *
today:
touch `date +"%Y-%m-%d.md"`
now_folder:
mkdir `date +"%Y-%m-%d-%H%M%S"`
# Implicit rule to know how to make .html from .md
%.html: %.md
include.py $< | \
pandoc --from markdown \
--to html \
--standalone \
--smart \
--section-divs \
--css styles.css | \
html5tidy \
--alternate /$<?edit "Edit source" "text/html" \
--script /__makeserver__/links.js > $@
# special rule for debugging variables
print-%:
@echo '$*=$($*)'
...@@ -3,7 +3,8 @@ import sys, os, asyncio, json ...@@ -3,7 +3,8 @@ import sys, os, asyncio, json
from asyncio import create_subprocess_exec from asyncio import create_subprocess_exec
from urllib.parse import urlparse, unquote as urlunquote, quote as urlquote from urllib.parse import urlparse, unquote as urlunquote, quote as urlquote
import argparse import argparse
from asyncio.subprocess import DEVNULL from asyncio.subprocess import DEVNULL, STDOUT
import aiohttp
""" """
Todo: use proper http error responses for errors, see aiohttp/http_exceptions.py Todo: use proper http error responses for errors, see aiohttp/http_exceptions.py
...@@ -14,14 +15,19 @@ async def is_makeable (path, cwd=".", makefile="makefile"): ...@@ -14,14 +15,19 @@ async def is_makeable (path, cwd=".", makefile="makefile"):
p = await create_subprocess_exec("make", "--question", "-f", makefile, rpath, cwd = cwd, stdout=DEVNULL, stderr=DEVNULL) p = await create_subprocess_exec("make", "--question", "-f", makefile, rpath, cwd = cwd, stdout=DEVNULL, stderr=DEVNULL)
# retcode 0=file is up to date, 1=file needs remaking, 2=file is not makeable # retcode 0=file is up to date, 1=file needs remaking, 2=file is not makeable
ret = await p.wait() == 1 ret = await p.wait() == 1
# print (f"is_makeable {path}: {ret}", file=sys.stderr) print (f"is_makeable {path}: {ret}", file=sys.stderr)
await log(f"is_makeable {path}: {ret}")
return ret return ret
async def make (path, cwd=".", makefile="makefile"): async def make (path, cwd=".", makefile="makefile"):
rpath = os.path.relpath(path, cwd) rpath = os.path.relpath(path, cwd)
p = await create_subprocess_exec("make", "-f", makefile, rpath, cwd = cwd) p = await create_subprocess_exec("make", "-f", makefile, rpath, stderr = STDOUT, cwd = cwd)
while True:
line = await p.stdout.readline()
log(line)
ret = await p.wait() == 0 ret = await p.wait() == 0
# print (f"make {path}: {ret}", file=sys.stderr) print (f"make {path}: {ret}", file=sys.stderr)
await log(f"make {path}: {ret}")
return ret return ret
textchars = bytearray({7,8,9,10,12,13,27} | set(range(0x20, 0x100)) - {0x7f}) textchars = bytearray({7,8,9,10,12,13,27} | set(range(0x20, 0x100)) - {0x7f})
...@@ -38,7 +44,7 @@ def editable (path): ...@@ -38,7 +44,7 @@ def editable (path):
_, ext = os.path.splitext(path) _, ext = os.path.splitext(path)
ext = ext.lower()[1:] ext = ext.lower()[1:]
# print (f"editable? ext {ext}", file=sys.stderr) # print (f"editable? ext {ext}", file=sys.stderr)
return ((ext not in ("html", "htm")) and not is_binary_file(path)) return ((ext not in ("html", "htm")) and not os.path.isdir(path) and not is_binary_file(path))
# From aiohttp/web_urldispatcher.py # From aiohttp/web_urldispatcher.py
def directory_as_html(filepath, directory, prefix, editor_url=None): def directory_as_html(filepath, directory, prefix, editor_url=None):
...@@ -84,7 +90,7 @@ def directory_as_html(filepath, directory, prefix, editor_url=None): ...@@ -84,7 +90,7 @@ def directory_as_html(filepath, directory, prefix, editor_url=None):
ul = "<ul>\n{}\n</ul>".format('\n'.join(index_list)) ul = "<ul>\n{}\n</ul>".format('\n'.join(index_list))
body = "<body>\n{}\n{}\n</body>".format(h1, ul) body = "<body>\n{}\n{}\n</body>".format(h1, ul)
head_str = "<head>\n<title>{}</title>\n</head>".format(index_of) head_str = "<head>\n<title>{}</title>\n<link rel=\"stylesheet\" href=\"/include/index.css\"></script>\n<script src=\"/include/index.js\"></script>\n</head>".format(index_of)
html = "<html>\n{}\n{}\n</html>".format(head_str, body) html = "<html>\n{}\n{}\n</html>".format(head_str, body)
return html return html
...@@ -111,17 +117,56 @@ async def route_post (request): ...@@ -111,17 +117,56 @@ async def route_post (request):
print ("POST", path, file=sys.stderr) print ("POST", path, file=sys.stderr)
if os.path.exists(path) and os.path.isfile(path): if os.path.exists(path) and os.path.isfile(path):
data = await request.post() data = await request.post()
resp = {}
# SAVE
if 'text' in data: if 'text' in data:
text = data['text'] text = data['text']
# doing file io inline here is not strictly speaking very async ;) # doing file io inline here is not strictly speaking very async ;)
with open(path, "w") as f: with open(path, "w") as f:
f.write(text) f.write(text)
return web.Response(text=json.dumps({"response": "ok"}), content_type="application/json") resp['text'] = 'ok'
else: # RENAME
return web.Response(text="no text") if 'name' in data:
newpath = os.path.join(os.path.split(path)[0], data['name'])
if path != newpath:
os.rename(path, newpath)
resp['name'] = 'ok'
# DELETE
if 'delete' in data:
os.remove(path)
resp['delete'] = 'ok'
return web.Response(text=json.dumps(resp), content_type="application/json")
else: else:
return web.Response(text="post not allowed on {0}".format(path)) return web.Response(text="post not allowed on {0}".format(path))
active_sockets = []
async def log (msg):
for ws in active_sockets:
await ws.send_str(msg)
async def websocket_handler(request):
print('Websocket connection starting')
ws = web.WebSocketResponse()
await ws.prepare(request)
print('Websocket connection ready')
active_sockets.append(ws)
async for msg in ws:
print(msg)
if msg.type == aiohttp.WSMsgType.TEXT:
print(msg.data)
if msg.data == 'close':
await ws.close()
else:
await ws.send_str(msg.data + '/answer')
active_sockets.remove(ws)
print('Websocket connection closed')
return ws
def main (): def main ():
ap = argparse.ArgumentParser("make & serve") ap = argparse.ArgumentParser("make & serve")
ap.add_argument("--makefile", default="makefile") ap.add_argument("--makefile", default="makefile")
...@@ -136,6 +181,7 @@ def main (): ...@@ -136,6 +181,7 @@ def main ():
app = web.Application() app = web.Application()
app['makefile'] = args.makefile app['makefile'] = args.makefile
app['editor'] = args.editor app['editor'] = args.editor
app.router.add_route('GET', '/ws', websocket_handler)
app.add_routes([web.get('/{make:.*}', route_get)]) app.add_routes([web.get('/{make:.*}', route_get)])
app.add_routes([web.post('/{make:.*}', route_post)]) app.add_routes([web.post('/{make:.*}', route_post)])
web.run_app(app) web.run_app(app)
......