#! /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 = "FAIL") def __call__(self, caption = None): if caption in self.blocks.keys(): return style(self.blocks[caption]) else: tosend = "" for cap in self.order: tosend += "[%s]\n%s" %(cap, self.blocks[cap]) return style(tosend) def help(self, caption = None): return self.__call__(caption) # output engine colortags = { '': '\x1b[32;01m', '': '\x1b[33;01m', '': '\x1b[31;01m', '': '\x1b[34;01m', '': '\x1b[01m', '': '\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('').sub(lambda text: colortags[text.group()], text) def style(text): tags = re.findall('', 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 %s" %(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 = [" ", ">>> ", " * ", " * "] _icons_debug = ["INFO", "EXEC", "DONE", "FAIL"] _logfile = time.strftime('%Y-%m-%d %H:%M:%S')+".log"