#!/usr/bin/env python3
# Copyright (C) 2016-2017 Florian Festi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import sys
import argparse
import cgi
import tempfile
import os.path
import threading
import time
import codecs
import mimetypes
import re
import markdown
# Python 2 vs Python 3 compat
try:
from urllib.parse import unquote_plus
except ImportError:
from urllib import unquote_plus
from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server
import wsgiref.util
try:
import boxes.generators
except ImportError:
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
import boxes.generators
class FileChecker(threading.Thread):
def __init__(self, files=[], checkmodules=True):
super(FileChecker, self).__init__()
self.checkmodules = checkmodules
self.timestamps = {}
for path in files:
self.timestamps[path] = os.stat(path).st_mtime
if checkmodules:
self._addModules()
def _addModules(self):
for name, module in sys.modules.items():
path = getattr(module, "__file__", None)
if not path:
continue
if path not in self.timestamps:
self.timestamps[path] = os.stat(path).st_mtime
def filesOK(self):
if self.checkmodules:
self._addModules()
for path, timestamp in self.timestamps.items():
try:
if os.stat(path).st_mtime != timestamp:
return False
except FileNotFoundError:
return False
return True
def run(self):
while True:
if not self.filesOK():
os.execv(__file__, sys.argv)
time.sleep(1)
class ArgumentParserError(Exception): pass
class ThrowingArgumentParser(argparse.ArgumentParser):
def error(self, message):
raise ArgumentParserError(message)
boxes.ArgumentParser = ThrowingArgumentParser # Evil hack
class BServer:
def __init__(self):
self.boxes = {b.__name__ : b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
self.boxes['TrayLayout2'] = boxes.generators.traylayout.TrayLayout2(self, webargs=True)
self.groups = boxes.generators.ui_groups
self.groups_by_name = boxes.generators.ui_groups_by_name
for name, box in self.boxes.items():
self.groups_by_name.get(box.ui_group,
self.groups_by_name["Misc"]).add(box)
self.staticdir = os.path.join(os.path.dirname(__file__), '../static/')
def arg2html(self, a, prefix, defaults={}):
name = a.option_strings[0].replace("-", "")
if isinstance(a, argparse._HelpAction):
return ""
viewname = name
if prefix and name.startswith(prefix + '_'):
viewname = name[len(prefix)+1:]
default = defaults.get(name, None)
row = """
%s
%%s
%s
\n""" % \
(viewname, a.help or "")
if (isinstance(a, argparse._StoreAction) and
hasattr(a.type, "html")):
input = a.type.html(name, default or a.default)
elif a.dest == "layout":
val = (default or a.default).split("\n")
input = """""" % \
(name, max((len(l) for l in val))+10, len(val)+1, default or a.default)
elif a.choices:
options = "\n".join(
("""""" %
(e, ' selected="selected"' if e == (default or a.default) else "",
e) for e in a.choices))
input = """\n""" % (name, options)
else:
input = """""" % \
(name, default or a.default)
return row % input
scripts = """
"""
def args2html(self, name, box, action="", defaults={}):
result = ["""
Boxes - """, name, """
""", self.scripts % (len(box.argparser._action_groups)-3), """
""")
if box.description:
result.append(markdown.markdown(box.description))
result.append("""
""" )
return (s.encode("utf-8") for s in result)
def menu(self):
result = ["""
Boxes.py
""", self.scripts % len(self.groups), """
Boxes.py
Create boxes and more with a laser cutter!
Boxes.py is an Open Source box generator written in Python. It features both finished parametrized generators as well as a Python API for writing your own. It features finger and (flat) dovetail joints, flex cuts, holes and slots for screws, hinges, gears, pulleys and much more.
""" ]
for nr, group in enumerate(self.groups):
result.append('''
\n""" % (group.name))
for box in group.generators:
name = box.__class__.__name__
if name in ("TrayLayout2", ):
continue
docs = ""
if box.__doc__:
docs = " - " + box.__doc__
result.append("""