over-video/doc/ellib.py
Martinez 5ffb173513 fix interpreter path
update to current over
2015-06-09 20:58:30 +02:00

366 lines
9.8 KiB
Python
Executable file

#! /usr/bin/env python2
# -*- coding: utf-8 -*-
import os, pickle, re, sys, time, traceback
__version = '1.9.2'
class CmdParser:
class config:
pass
def __init__(self, mapping, source = sys.argv[1:]):
# pools for variable quadruples
p_long = []
p_short = []
p_type = []
p_plural = {}
p_default = {}
# Legacy checks for pre-1.7 or pre-1.9 programs -- it's a CRAP, so i had them neutered :]
#l_mapping = len(mapping)
#if l_mapping%3 == 0 and l_mapping%4 != 0:
#maptype = 3
#say("ellib.CmdParser: Pre-1.7 or 1.9 program detected, running in legacy mode", timestamp = True, icon = "DBG")
#else:
#maptype = 5
maptype = 5
for i in range(0, len(mapping), maptype):
p_long.append(mapping[i])
p_short.append(mapping[i+1])
p_type.append(mapping[i+2])
p_plural[mapping[i]] = mapping[i+3]
p_default[mapping[i]] = mapping[i+4]
# Switches and targets arrays.
self.switches = {}
for name in p_long:
if p_plural[name]:
self.switches[name] = []
else:
self.switches[name] = None
self.targets = []
self.errors = []
# Behold, the Parser !!!
delka = len(source)
mapa = range(delka)
for i in range(delka):
if i in mapa:
arg = source[i]
if arg[:2] == '--' and arg[:5] != '--no-':
if arg[2:] in p_long:
if p_type[p_long.index(arg[2:])] == 0:
if p_plural[arg[2:]]:
self.switches[arg[2:]].append(True)
else:
self.switches[arg[2:]] = True
else:
try:
if p_plural[arg[2:]]:
self.switches[arg[2:]].append(source[i+1])
else:
self.switches[arg[2:]] = source[i+1]
mapa.remove(i+1)
except:
self.errors.append(arg)
else:
self.errors.append(arg)
elif arg[:5] == '--no-':
if arg[5:] in p_long:
if p_type[p_long.index(arg[5:])] == 0:
if p_plural[arg[5:]]:
self.switches[arg[5:]].append(False)
else:
self.switches[arg[5:]] = False
else:
self.errors.append(arg)
elif arg[0] in ['-', '+']:
for x in arg[1:]:
if x in p_short:
longname = p_long[p_short.index(x)]
if p_type[p_short.index(x)] == 0:
if arg[0] == '-':
value = False
else:
value = True
if p_plural[longname]:
self.switches[longname].append(value)
else:
self.switches[longname] = value
else:
try:
if p_plural[longname]:
self.switches[longname].append(source[i+1])
else:
self.switches[longname] = source[i+1]
mapa.remove(i+1)
except:
self.errors.append(arg[0]+x)
else:
self.errors.append(arg[0]+x)
else:
self.targets.append(arg)
# Look for empty fields and fill them with default values if possible
for name in self.switches:
if name in p_default.keys() and p_default[name] != None and self.switches[name] in [[], None]:
if type(p_default[name]) == list:
self.switches[name] = p_default[name]
else:
if p_plural[name]:
self.switches[name] = [p_default[name]]
else:
self.switches[name] = p_default[name]
# Fill the self.switches dictionary into self.config variables for easier access
name2 = name.replace(' ', '_').replace('-', '_').replace('+', '_')
setattr(self.config, name2, self.switches[name])
# if there's a "--debug" somewhere on the line, run a command dump
if '--debug' in source:
_debug = True
say("Command dump", 1)
for name in self.switches:
say("%s: %s" %(name, self.switches[name]))
say("Command dump", 2)
class Db:
"""Třída velmi špatné databáze:
* při inicializaci se vytvoří databáze se jménem name, pokud neexistuje. Otevře databázi.
* metoda read() - přečte databázi
* metoda write() - zapíše (přepíše) databázi
* metoda remove() - odstraní řádek
"""
def __init__(self, filename):
"""Otevře databázi, pokud neexistuje, vytvoří ji."""
self.filename = filename
if os.path.isfile(self.filename):
try: file = open(self.filename, 'r+')
except IOError: file = open(self.filename, 'r')
else:
say("Vytvářím databázi %s \r" %(self.filename), 1, 1)
file = open(self.filename, 'w')
file.write('None')
say("Databáze %s vytvořena." %(self.filename), 2)
file.close()
try: file = open(self.filename, 'r+')
except IOError: file = open(self.filename, 'r')
self.file = file
def read(self):
"""Low level funkce; vrátí databázi"""
self.file.seek(0)
try: return pickle.load(self.file)
except:
return []
def write(self, object):
"""Low level funkce; zapíše databázi"""
self.file.seek(0)
retval = pickle.dump(object, self.file)
self.file.flush()
return retval
def remove(self, ID):
"""Odstraní řádek z databáze."""
database = self.read()
del database[ID]
return self.write(database)
def add(self, line):
"""Zapíše řádek do databáze"""
database = self.read()
database.append(line)
return self.write(database)
class Help:
def __init__(self, rawtext):
self.rawtext = rawtext+'\n[[' # a kinky workaround indeed :)
self.blocks = {}
self.order = []
self.mkindex()
def mkindex(self):
chunk = re.findall('\[\[(.+?)\]\]\n(.+?)(?=\[\[)', self.rawtext, re.S)
for section in chunk:
if len(section) == 2: # caption and text
self.order.append(section[0])
self.blocks[section[0]] = section[1]
else:
say("Help section is of wrong lenght, please report a bug (provide the original help text if possible)", timestamp = True, icon = "<Cr>FAIL<C/>")
def __call__(self, caption = None):
if caption in self.blocks.keys():
return style(self.blocks[caption])
else:
tosend = ""
for cap in self.order:
tosend += "[<CB>%s<C/>]\n%s" %(cap, self.blocks[cap])
return style(tosend)
def help(self, caption = None):
return self.__call__(caption)
# output engine
colortags = {
'<Cg>': '\x1b[32;01m',
'<Cy>': '\x1b[33;01m',
'<Cr>': '\x1b[31;01m',
'<Cb>': '\x1b[34;01m',
'<CB>': '\x1b[01m',
'<C/>': '\x1b[39;49;00m'
}
badchars = {
'\"': '\\"',
'\x00': '',
'/': '-'
}
def charfilter(text, sada = badchars):
for badchar in sada.keys():
text = text.replace(badchar, sada[badchar])
return text
# R.I.P, you served us well. May this line make us remember you for ages.
# Eram, non sum, non misero...
#def style(text):
#return re.compile('<C.>').sub(lambda text: colortags[text.group()], text)
def style(text):
tags = re.findall('<C.>', text)
for tag in tags:
try:
text = text.replace(tag, colortags[tag])
except KeyError:
pass
return text
def say(text, mode = 0, breakline = True, timestamp = False, icon = ""):
if isinstance(text, unicode) and sys.stdout.encoding:
text = text.encode(sys.stdout.encoding)
text = str(text)
if _debug:
timestamp = True
icons = _icons_debug
else:
icons = _icons
if mode in range(1, len(icons)) and not icon:
icon = icons[mode]
elif not icon:
icon = icons[0]
if breakline == 1:
br = '\n'
else:
br = ''
if timestamp:
text = style(time.strftime('%Y-%m-%d %H:%M:%S ')+icon+' -- '+text)+br
else:
text = style(icon+' '+text)+br
if _log: log(text)
sys.stdout.write(text)
sys.stdout.flush()
def countdown(units, text = "", secs = 1):
ticks = range(units)
ticks.reverse()
try:
for i in ticks:
say(text+str(i+1)+' \r', 1, 0)
time.sleep(secs)
say(text+'0 ', 2)
return True
except (EOFError, KeyboardInterrupt):
say(text+'0 ', 3)
return False
def log(text, logfile = None):
if not logfile:
logfile = _logfile
if not text:
return False
if text[-1] != '\n':
text += '\n'
fd = open(logfile, 'a')
fd.write(text)
fd.close()
def join(array, separator=' '):
return separator.join(array)
def logger(status, prefix = '.'):
global _log, _logfile
_prefix = prefix
if status:
_log = True
# Check if prefix is a directory: if it's a file, log into ".", if it doesn't exist, create it.
if not os.path.isdir(_prefix) and os.path.exists(_prefix):
_prefix = '.'
elif not os.path.exists(_prefix):
os.mkdir(_prefix)
_logfile = _prefix + '/' + time.strftime('%Y-%m-%d %H:%M:%S')+'.log'
if prefix != _prefix: say("%s exists, but is not a directory." %(prefix), 3)
say("Logging into %s" %(_logfile), 1)
else:
say("Logging into %s" %(_logfile), 2)
_log = False
class File:
def __init__(self, name, mode = 'r'):
self.name = name
self.mode = mode
self.fd = open(name, mode)
self.data = ''
def read(self):
self.data = self.fd.read()
def write(self):
self.fd.write(self.data)
def close(self):
self.fd.close()
def coredump(loc):
import code
c = code.InteractiveConsole(loc)
c.interact()
class Autoloader:
def __init__(self):
self.original_handler = sys.excepthook
def register(self, deact=False):
if not deact:
sys.excepthook = self
else:
sys.excepthook = self.original_handler
def __call__(self, exctype, value, trace):
if exctype == NameError:
module_name = charfilter(value.args[0], {"name '": "", "' is not defined": ""})
#retval = _exec("import %s" % module_name, trace)
command_locals = trace.tb_frame.f_locals
command_globals = trace.tb_frame.f_globals
try: # retval relates to import success only
exec "import %s" % module_name in command_locals, command_globals
retval = True
say("Autoloaded module <Cg>%s<C/>" %(module_name), timestamp=True, icon="INFO")
exec trace.tb_frame.f_code in command_locals, command_globals
retval = True
except ImportError:
retval = False
except:
traceback.print_exc()
if exctype != NameError or not retval:
traceback.print_exception(exctype, value, trace)
autoloader = Autoloader()
# Ellib setup
_debug = False
_log = False
_icons = [" ", ">>> ", "<Cg> * <C/>", "<Cr> * <C/>"]
_icons_debug = ["INFO", "<CB>EXEC<C/>", "<Cg>DONE<C/>", "<Cr>FAIL<C/>"]
_logfile = time.strftime('%Y-%m-%d %H:%M:%S')+".log"