366 lines
9.8 KiB
Python
Executable file
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"
|