def readEvents(self): tokenHandlers = { DefineToken: self._handleDefineToken, EventToken: self._handleEventToken, ValueToken: self._handleValueToken, DurationToken: self._handleDurationToken, ApiToken: self._handleApiToken, BeginObjectToken: self._handleBeginObjectToken, EndObjectToken: self._handleEndObjectToken, } while 1: try: token = Token.read(self.file) except ValueError, e: Log.warn("Error reading token: %s" % e) break if not token: break event = tokenHandlers[token.__class__](token) if event: yield event
def GetAniDBTVDBMapCustom(media, movie): AniDBTVDBMapCustom = None lib, root, path = common.GetLibraryRootPath( common.GetMediaDir(media, movie)) dir = os.path.join(root, path) while dir: scudlee_filename_custom = os.path.join(dir, SCHUDLEE_CUSTOM) if os.path.exists(scudlee_filename_custom): try: AniDBTVDBMapCustom = XML.ElementFromString( Core.storage.load(scudlee_filename_custom)) Log.Info("Local custom mapping file loaded: {}".format( scudlee_filename_custom)) except: Log.Error("Failed to open: '%s', error: '%s'" % (scudlee_filename_custom, e)) else: break dir = os.path.dirname(dir) if len(dir) > len( root ) else '' # Clear variable if we've just finished processing down to (and including) root else: Log.Info("Local custom mapping file not present: {}".format( SCHUDLEE_CUSTOM)) return AniDBTVDBMapCustom
def repackageFrw(frwDir, bootClassFolder): """ Repackage the classes.dex into jar of frwDir. """ if OPTIONS.formatFrw == False : return # Keep the old directory, we will change back after some operations. oldDir = os.path.abspath(os.curdir) # Some dexFiles are parted, such as framework-classes2.dex regex = re.compile("(.*)-(classes\d?).dex") Log.i(TAG, "Repackage JARs of %s" %(frwDir)) os.chdir(frwDir) for dexFile in os.listdir(bootClassFolder): if dexFile.endswith(".dex"): jarFile = dexFile[0:-4] + ".jar" dexName = "classes.dex" if not os.path.exists(jarFile): # Match out the jar file with regex matcher = regex.match(dexFile) if matcher != None: jarFile = matcher.group(1) + ".jar" dexName = matcher.group(2) + ".dex" Log.d(TAG, "Repackage %s" %(jarFile)) # Put the dex and framework's jar in the same folder, and jar into the jarFile shutil.move(os.path.join(bootClassFolder, dexFile), os.path.join(frwDir, dexName)) Utils.runWithOutput(["jar", "uf", jarFile, dexName]) if os.path.exists(dexName): os.remove(dexName) os.chdir(oldDir)
def deoat(self): """ De-oat the OTA package. """ if self.mBootOAT == None: Log.i(TAG, "deoat(): boot.oat not found in %s, nothing need deoat" % self.mRoot) return self if os.path.exists(self.mBootClassFolder): Log.d(TAG, "Delete the already exists %s" %self.mBootClassFolder) shutil.rmtree(self.mBootClassFolder) # Phase 1: de-oat boot.oat OatZip.deoatBootOAT(self.mBootOAT) # Phase 2: de-oat all the other oat files, of which suffix is odex. # [Android 5.0]: All the oat jars are located in the same folder with boot.oat OatZip.deoatFrw(self.mBootOATDir) # Phase 3: de-oat app OatZip.deoatApp(self.mFrwDir, self.mBootClassFolder) OatZip.deoatApp(self.mAppDir, self.mBootClassFolder) OatZip.deoatApp(self.mPrivAppDir, self.mBootClassFolder) return self
def deoatApp(oatApkDir, bootClassFolder): """ De-oat app """ if OPTIONS.formatApp == False: return Log.i(TAG, "De-oat files of oat-format in %s, with BOOTCLASSFOLDER=%s" %(oatApkDir, bootClassFolder)) for (dirpath, dirnames, filenames) in os.walk(oatApkDir): dirnames = dirnames # no use, to avoid warning for filename in filenames: if filename.endswith(".odex"): # no need to de-oat if original apk does not exist apkFile = filename[0:-5] + ".apk" apkPath = os.path.dirname(dirpath) if not os.path.exists(os.path.join(apkPath, apkFile)): continue oatApk = os.path.join(dirpath, filename) deoatApk = oatApk[0:-5] + ".dex" if os.path.exists(deoatApk): Log.d(TAG, "Delete the already exists %s" % deoatApk) os.remove(deoatApk) Utils.runWithOutput([OatZip.OAT2DEX, oatApk, bootClassFolder])
def getZipType(self): """ Retrieve the OTA package type The property <persist.sys.dalvik.vm.lib> defines the VM type. If libart.so is used, it is an ART package; If libdvm.so is used, it is an DVM package. """ if self.mRoot is None: self.unzip() buildProp = os.path.join(self.mRoot, "system/build.prop") # Retrieve the <persist.sys.dalvik.vm.lib> in build.prop zipType = None if os.path.exists(buildProp): fileHandle = open(buildProp, "r") content = fileHandle.read() vmlib = re.compile("\n.*sys.dalvik.vm.lib.*=\s*(?P<lib>.*)\n") match = vmlib.search(content) if match is not None: libType = match.group("lib") Log.d(TAG, "sys.dalvik.vm.lib=%s" % libType) else: libType = "" fileHandle.close() else: raise Exception("Could not find %s, unknown ota type" % buildProp) if libType.find("art") >= 0: zipType = ZipModel.ART elif libType.find("dvm") >= 0: zipType = ZipModel.DVM return zipType
def process(self, fileName, includeMacros = False): """ Process the macro declarations present in a file and return the resulting string. @param fileName: Name of file to parse @param includeMacros: Pass True to include the preprocessor macros in the output """ cmd = [self.binary] if self.arguments: cmd.append(self.arguments) if includeMacros: cmd.append("-dD") # Don't include predefined macros cmd.append("-undef") for macro, value in self.config.get("macros", {}).items(): cmd.append("-D%s=%s" % (macro, value)) if self.platform.name in self.config: plat = self.config[self.platform.name] for lib in plat.get("includedirs", []): cmd.append("-I") cmd.append(lib) for macro, value in plat.get("macros", {}).items(): cmd.append("-D%s=%s" % (macro, value)) cmd.append(fileName) if self.options.verbose: Log.debug("Running preprocessor: " + " ".join(cmd)) p = subprocess.Popen(cmd, stdout = subprocess.PIPE) return p.stdout.read()
def _postprocessEvent(event, logDir): # Process the render surface if there is one if "render_surface_width" in event.sensorData and "render_surface_height" in event.sensorData: try: _processRenderSurface(logDir, event.sensorData) except Exception, e: Log.error("Unable to load render surface for event %s(%d): %s" % (event.name, event.seq, e))
def getZipType(self): """ Retrieve the OTA package type The property <persist.sys.dalvik.vm.lib> defines the VM type. If libart.so is used, it is an ART package; If libdvm.so is used, it is an DVM package. """ if self.mRoot is None: self.unzip() buildProp = os.path.join(self.mRoot, "system/build.prop") # Retrieve the <persist.sys.dalvik.vm.lib> in build.prop zipType = None if os.path.exists(buildProp): fileHandle = open(buildProp, "r") content = fileHandle.read() vmlib = re.compile("\n.*sys.dalvik.vm.lib.*=\s*(?P<lib>.*)\n") match = vmlib.search(content) if match is not None: libType = match.group("lib") Log.d(TAG, "sys.dalvik.vm.lib=%s" % libType) fileHandle.close() else: raise Exception("Could not find %s, unknown ota type" %buildProp) if libType.find("art") >= 0: zipType = ZipModel.ART elif libType.find("dvm") >= 0: zipType = ZipModel.DVM return zipType
def parseConfig(config, template=None): """ Parses the given tracer configuration and returns a tree of configuration symbols. @param config Config file text @param template Optional configuration to use a template. @return: A dictionary tree of configuration values """ if not template: template = Config.Config() items = template for itemName, item in configFile.parseString(config): if not item: Log.warn("Empty top-level item '%s'." % itemName) if itemName in items and isinstance(item, Config.Group): items[itemName].update(item) elif itemName in items and isinstance(item, Config.List): items[itemName] += item else: items[itemName] = item return items
def readEvents(self): tokenHandlers = { DefineToken: self._handleDefineToken, EventToken: self._handleEventToken, ValueToken: self._handleValueToken, DurationToken: self._handleDurationToken, ApiToken: self._handleApiToken, BeginObjectToken: self._handleBeginObjectToken, EndObjectToken: self._handleEndObjectToken, } while 1: try: token = Token.read(self.file) except ValueError, e: Log.warn("Error reading token: %s" % e) continue if not token: break try: event = tokenHandlers[token.__class__](token) except Exception, e: Log.warn("Error decoding token %s: %s" % (token.__class__.__name__, e)) continue
def generate(project, options, args): """Generate a target from a project. [target]""" if not args: fail("Generation target missing. Use one of %s" % ", ".join(project.targets.keys())) if not project.targets: fail("Project file name missing.") config = project.config for targetName in args: if not targetName in project.targets: fail("No such target. Use one of %s" % ", ".join(project.targets.keys())) # Generate the target target = project.targets[targetName] projectName = config.name.lower() + "-" + targetName targetPath = options.output and options.output or projectName Log.notice( heading("Generating '%s' from project '%s'" % (targetName, config.name))) target.generate(projectName, targetPath) Log.notice("Target '%s' created at '%s'." % (projectName, targetPath))
def deoatApp(oatApkDir, bootClassFolder): """ De-oat app """ if OPTIONS.formatApp == False: return Log.i( TAG, "De-oat files of oat-format in %s, with BOOTCLASSFOLDER=%s" % (oatApkDir, bootClassFolder)) for (dirpath, dirnames, filenames) in os.walk(oatApkDir): dirnames = dirnames # no use, to avoid warning for filename in filenames: if filename.endswith(".odex"): # no need to de-oat if original apk does not exist apkFile = filename[0:-5] + ".apk" apkPath = os.path.dirname(dirpath) if not os.path.exists(os.path.join(apkPath, apkFile)): continue oatApk = os.path.join(dirpath, filename) deoatApk = oatApk[0:-5] + ".dex" if os.path.exists(deoatApk): Log.d(TAG, "Delete the already exists %s" % deoatApk) os.remove(deoatApk) Utils.runWithOutput( [OatZip.OAT2DEX, oatApk, bootClassFolder])
def parseConfig(config, template = None): """ Parses the given tracer configuration and returns a tree of configuration symbols. @param config Config file text @param template Optional configuration to use a template. @return: A dictionary tree of configuration values """ if not template: template = Config.Config() items = template for itemName, item in configFile.parseString(config): if not item: Log.warn("Empty top-level item '%s'." % itemName) if itemName in items and isinstance(item, Config.Group): items[itemName].update(item) elif itemName in items and isinstance(item, Config.List): items[itemName] += item else: items[itemName] = item return items
def deoat(self): """ De-oat the OTA package. """ if self.mBootOAT == None: Log.i( TAG, "deoat(): boot.oat not found in %s, nothing need deoat" % self.mRoot) return self if os.path.exists(self.mBootClassFolder): Log.d(TAG, "Delete the already exists %s" % self.mBootClassFolder) shutil.rmtree(self.mBootClassFolder) # Phase 1: de-oat boot.oat OatZip.deoatBootOAT(self.mBootOAT) # Phase 2: de-oat all the other oat files, of which suffix is odex. # [Android 5.0]: All the oat jars are located in the same folder with boot.oat OatZip.deoatFrw(self.mBootOATDir) # Phase 3: de-oat app OatZip.deoatApp(self.mFrwDir, self.mBootClassFolder) OatZip.deoatApp(self.mAppDir, self.mBootClassFolder) OatZip.deoatApp(self.mPrivAppDir, self.mBootClassFolder) return self
def setValue(self, value, callback=None): from Msg import Msg Log.i( 'Device', "Set value for device" + self.unid + "|" + self.setid + " :" + value + ", isOnline:%s" % self.isOnline) if self.mySocketWrap != None and self.isOnline == True: Log.i('Device', "Sending expl now") self.setValueCallback = callback Log.d('DeviceSetVal', "[1.1]") msg = self.mySocketWrap.sendValue(self, value, self.callbackSetValue) Log.d('DeviceSetVal', "[1.2]") self.needSetValue = False elif (self.mySocketWrap == None and self.isOnline == True): DB.addAlert(self.unid, self.setid, 1008) if (callback != None): msg = Msg(cmd="device.val.set.error") msg.sendAttempt = -1 callback(msg, self) else: Log.i('Device', "Scheduled for when online") msg = Msg(cmd="device.val.set.scheduled") self.executeTriggerSeq(1) if (callback != None): callback(msg, self) self.needSetValue = True self.updateValueDb(value) if (self.isOnline == False): self.sendHeartBeat() #else: # self.setIsOnline(False) self.lastValue = value
def generate(self, projectName, targetPath): tempPath = tempfile.mkdtemp() try: # Create a build build = self.project.platform.createBuild(self.config, self.library, projectName, self.name) # If there is at least one C++ function, generate only C++ code if "c++" in self.getLanguages() or self.config.get("language", "c") == "c++": playerSourceName = "player_gen.cpp" else: playerSourceName = "player_gen.c" self.library.language = "c" # Generate the player playerSourcePath = os.path.join(tempPath, playerSourceName) g = Generator.CSourcePlayerGenerator(self.config, self.project.platform, [self.library], templatePath = Resource.getPath("templates")) output = open(playerSourcePath, "w") g.generate(outputFile = output) output.close() # Add the generated source file to the configuration self.addSourceFile(playerSourcePath) # Finalize the build build.compile(targetPath = targetPath) finally: try: shutil.rmtree(tempPath) except: Log.warn("Unable to clean up temporary directory '%s'" % tempPath)
def validate(self): lib = self.library # Validate the target for function in lib.functions.values(): if function.ordinal is None and function.staticLinkage and self.project.platform.requireOrdinals: Log.warn("Function '%s' does not have a valid ordinal." % function.name)
def __init__(self, project, options): Analyzer.__init__(self, project) self.commands = {} self.commandHelp = {} self.options = options self.parser = ScriptParser() self.done = False self.colorizer = Console.colorizer self.taskMonitor = Task.RateLimitedTaskMonitor(self) self.profiling = False self.plugins = [] self.traceFiles = {} self.customSyntaxCommands = set() if not self.project.targets: Log.warn("Using empty project file.") if not self.projectHasApiDescription(): Log.warn("Project file does not contain an API description.") # Register internal commands self.registerCommand("quit", self.quit) # Start receiving task notifications Task.setMonitor(self.taskMonitor) # Load all plugins self._loadPlugins()
def deoatAppWithArch(appsDir, frwDir, arch, arch2): """ De-oat app """ if OPTIONS.formatApp == False: return Log.i(TAG, "De-oat files of oat-format in %s" % (appsDir)) bootClassFolderArch = os.path.join(frwDir, arch, "odex") bootClassFolderArch2 = os.path.join(frwDir, arch2, "odex") #for app in $( ls $appdir ); do for app in os.listdir(appsDir): appPath = os.path.join(appsDir, app) apkFile = os.path.join(appPath, app + ".apk") archPath = os.path.join(appPath, "oat", arch) #if [[ -d "$appdir/$app/$arch" ]]; if os.path.exists(archPath): odexFile = os.path.join(archPath, app + ".odex") #java -Xmx512m -jar $oat2dex $appdir/$app/$arch/$app.odex $framedir/$arch/odex Utils.runWithOutput( [OatZip.OAT2DEX, odexFile, bootClassFolderArch]) else: # if exists arch2 if arch2.strip(): arch2Path = os.path.join(appPath, "oat", arch2) if os.path.exists(arch2Path): odexFile2 = os.path.join(arch2Path, app + ".odex") Utils.runWithOutput( [OatZip.OAT2DEX, odexFile2, bootClassFolderArch2])
def _processRenderSurface(logDir, attributes): def attr(name): return attributes[name] w, h = attr("render_surface_width"), attr("render_surface_height") redMask = attr("red_mask") greenMask = attr("green_mask") blueMask = attr("blue_mask") alphaMask = attr("alpha_mask") depthMask = attr("depth_mask") stencilMask = attr("stencil_mask") isLinear = attr("is_linear") isPremultiplied = attr("is_premultiplied") # Convert the color buffer if "color_buffer" in attributes: fileName = attr("color_buffer") if not os.path.exists(fileName): fileName = os.path.join(logDir, fileName) fileNameOut = fileName.rsplit(".", 1)[0] + ".png" # Only do the conversion if the image doesn't already exist # or if the source file is newer. if fileName.endswith(".dat") and \ (not os.path.exists(fileNameOut) or \ (os.path.exists(fileName) and os.path.getmtime(fileName) > os.path.getmtime(fileNameOut)) ): stride = attr("color_stride") f = open(fileName, "rb") data = f.read(stride * h) f.close() if len(data) != h * stride or not data: Log.error("Invalid color buffer data size: %d" % len(data)) return colorBuffer = Graphics.decodeImageData(data, (w, h), stride, redMask, greenMask, blueMask, alphaMask, isLinear, isPremultiplied) colorBuffer = colorBuffer.convert("RGBA") colorBuffer.save(fileNameOut) # We can remove the original file now os.unlink(fileName) # Replace the original file name with the decoded file attributes["color_buffer"] = fileNameOut # Eat the render surface attributes since they are of little use further down the road #for attrName in ["red_mask", "green_mask", "blue_mask", "alpha_mask", # "depth_mask", "stencil_mask", "color_stride", # "is_linear", "is_premultiplied", "color_data_type", # "depth_data_type", "stencil_data_type"]: # if attrName in attributes: # del attributes[attrName] for bufferName in ["depth_buffer", "stencil_buffer"]: if bufferName in attributes and not os.path.exists(attributes[bufferName]): # Fill in the full buffer file name attributes[bufferName] = os.path.join(logDir, attr(bufferName))
def execute(self): Log.i('Tasker',"Executing task %i NOW" % self.id) threading.Thread(target = Task.runUserScriptEnv, args=(self.script,)).start() #self.runUserScriptEnv(self.script) DB.registerEvent('','','Tasker','Executing task #%i' % (self.id ) ) now = datetime.now() self.lastTimeRun = datetime.strftime(now, "%Y.%m.%d %H:%M:%S") self.updateNextTime()
def testArch(frwDir, arch): """ Test whether arch exists """ bootOATPath = os.path.join(frwDir, arch, "boot.oat") Log.i(TAG, "testArch : " + bootOATPath) if os.path.exists(bootOATPath): return True return False
def checkVPN(): res = str(check_output("ifconfig".split(" ") )) Log.i("PortalConnect","Checking for VPN res:",res) if "ppp" not in res: res = os.system("sudo pon main updetach persist") print(res) if res != 0: Log.e("VPN Setup","Error connecting to VPN server(",res)
def heartbeatRes(self, msg): Log.i('Device', "Received heartbeat.res for device", self.unid, self.setid, "sendAttempt:", msg.sendAttempt) if (msg.sendAttempt < 0 and self.isOnline == True): self.setIsOnline(False) elif (self.isOnline == False): #else: self.setIsOnline(True)
def image_upload(cls, file, width=0, height=0, thumbnail=False): if not cls.allowed_file(file.filename): Log.warn("Filename's suffix was not allowed.") raise Exception("Filename's suffix was not allowed.") if file: filename, url = cls.generate_image_path_info(file.filename) file.save(filename) pillow_image = PillowImage.open(filename).convert('RGB') if width != 0 and height != 0: if width != pillow_image.width or height != pillow_image.height: Log.warn("Invalid image size.") os.remove(filename) raise Exception('Invalid image size.') if pillow_image: if thumbnail: # 生成缩略图 if pillow_image.height > pillow_image.width: # 竖图 pos = (pillow_image.height - pillow_image.width) // 2 crop_image = pillow_image.crop( (0, pos, pillow_image.width, pillow_image.height - pos)) thumb_img = crop_image.resize( (current_app.config['APP']['thumb_height'], current_app.config['APP']['thumb_width']), PillowImage.ANTIALIAS) elif pillow_image.height < pillow_image.width: # 横图 pos = (pillow_image.width - pillow_image.height) // 2 crop_image = pillow_image.crop( (pos, 0, pillow_image.width - pos, pillow_image.height)) thumb_img = crop_image.resize( (current_app.config['APP']['thumb_height'], current_app.config['APP']['thumb_width']), PillowImage.ANTIALIAS) else: thumb_img = pillow_image.resize( (current_app.config['APP']['thumb_height'], current_app.config['APP']['thumb_width']), PillowImage.ANTIALIAS) thumb_img.save(filename + '_thumb.jpg', format='jpeg', quality=80) image = Image(filename=filename, url=url, size=op.getsize(filename), height=pillow_image.height, width=pillow_image.width).save() Log.info('Success upload file: {}.'.format(filename)) return image else: Log.warn('Can not open image file.') raise Exception('Can not open image file.') else: Log.warn('Invalid file data.') raise Exception('Invalid file data.')
def deoatBootOAT(frwDir, arch): """ De-oat boot.oat """ bootClassFolder = os.path.join(frwDir, arch) bootOatPath = os.path.join(bootClassFolder, "boot.oat") bootClassFolderDex = os.path.join(frwDir, arch + "-dex") bootClassFolderOdex = os.path.join(frwDir, arch + "-odex") if os.path.exists(bootClassFolderDex): Log.d(TAG, "Delete the already exists %s" % bootClassFolderDex) shutil.rmtree(bootClassFolderDex) if os.path.exists(bootClassFolderOdex): Log.d(TAG, "Delete the already exists %s" % bootClassFolderOdex) shutil.rmtree(bootClassFolderOdex) Log.i(TAG, "De-oat %s" % bootClassFolder) if OPTIONS.use_baksmali: for item in os.listdir(bootClassFolder): if item.endswith(".oat"): oatPath = os.path.join(bootClassFolder, item) dexlist = Utils.runWithResult( [OatZip.BAKSMALI, "list", "dex", oatPath]) jarName = os.path.basename(dexlist[0].strip("\n")) jarOutDir = os.path.join(frwDir, arch + "-odex", jarName + ".out") dexDir = os.path.join(frwDir, arch + "-dex") if not os.path.exists(dexDir): os.makedirs(dexDir) for dex in dexlist: if dex.strip("\n").endswith(".jar"): dexName = "" smaliDir = "smali" dexSaveName = jarName[0:-4] + ".dex" else: dexName = dex.strip("\n").split(":")[1] smaliDir = "smali_" + dexName[0:-4] dexSaveName = jarName[0:-4] + "-" + dexName Log.d( TAG, "baksmali deodex -b %s %s -o %s" % (bootOatPath, os.path.join(oatPath, dexName), os.path.join(jarOutDir, smaliDir))) Utils.runWithOutput([ OatZip.BAKSMALI, "deodex", "-b", bootOatPath, os.path.join(oatPath, dexName), "-o", os.path.join(jarOutDir, smaliDir) ]) Log.d( TAG, "smali assemble %s -o %s" % (os.path.join(jarOutDir, smaliDir), os.path.join(dexDir, dexSaveName))) Utils.runWithOutput([ OatZip.SMALI, "assemble", os.path.join(jarOutDir, smaliDir), "-o", os.path.join(dexDir, dexSaveName) ]) else: Utils.runWithOutput([OatZip.OAT2DEX, "boot", bootClassFolder])
def onValueSetACK(msg, device): Log.i('API/OnValueACK',msg.toJSON()) if (API.socketAwaitACK != None): if(msg.cmd == "device.val.set.scheduled"): API.socketAwaitACK.send(json.dumps({"errcode": "0", "data": {"msg":"scheduled"}}).encode()) elif(msg.sendAttempt < 0): API.socketAwaitACK.send(json.dumps({"errcode": "2004","msg":"Too many attempts where made", "data": {}}).encode()) elif(msg.cmd == "ACK" or msg.cmd == "0"): API.socketAwaitACK.send(json.dumps({"errcode": "0", "data": {}}).encode()) API.socketAwaitACK = None
def sendValue(self, device, value, callback=None): msg = Msg(unid=device.unid, setid=device.setid, cmd="device.val.set", value=value, socket=self, callback=callback) Log.d('DeviceSetVal', "[1.1.1]") self.outgoingMSG.append(msg) return msg
def Update(metadata, media, lang, force, movie): from common import Log #Import here for startup logging to go to the plex pms log Log.Open(media=media, movie=movie, search=False) source = metadata.id.split('-', 1)[0] error_log = { 'AniDB summaries missing' :[], 'AniDB posters missing' :[], 'anime-list AniDBid missing':[], 'anime-list studio logos' :[], 'TVDB posters missing' :[], 'TVDB season posters missing':[], 'anime-list TVDBid missing' :[], 'Plex themes missing' :[], 'Missing Episodes' :[], 'Missing Specials' :[], 'Missing Episode Summaries' :[], 'Missing Special Summaries':[]} Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("id: {}, title: {}, lang: {}, force: {}, movie: {}".format(metadata.id, metadata.title, lang, force, movie)) Log.Info("start: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) dict_AnimeLists, AniDBid, TVDBid, TMDbid, IMDbid, mappingList = AnimeLists.GetMetadata(media, movie, error_log, metadata.id) dict_TheTVDB, IMDbid = TheTVDBv2.GetMetadata(media, movie, error_log, lang, source, AniDBid, TVDBid, IMDbid, mappingList, Dict(AniDB, 'movie')) dict_tvdb4 = common.GetMetadata(media, movie, source, TVDBid, mappingList) dict_AniDB, ANNid, MALid = AniDB.GetMetadata(media, movie, error_log, source, AniDBid, TVDBid, AnimeLists.AniDBMovieSets, mappingList) dict_TheMovieDb, TSDbid, TMDbid, IMDbid = TheMovieDb.GetMetadata(media, movie, TVDBid, TMDbid, IMDbid) dict_FanartTV = FanartTV.GetMetadata( movie, TVDBid, TMDbid, IMDbid) dict_Plex = Plex.GetMetadata(metadata, error_log, TVDBid, Dict(dict_TheTVDB, 'title')) dict_TVTunes = TVTunes.GetMetadata(metadata, Dict(dict_TheTVDB, 'title'), Dict(mappingList, AniDBid, 'name')) #Sources[m:eval('dict_'+m)] dict_OMDb = OMDb.GetMetadata(movie, IMDbid) #TVDBid=='hentai' dict_MyAnimeList = MyAnimeList.GetMetadata(movie, MALid ) dict_Local = Local.GetMetadata(media, movie) if common.AdjustMapping(source, mappingList, dict_AniDB, dict_TheTVDB): dict_AniDB, ANNid, MALid = AniDB.GetMetadata(media, movie, error_log, source, AniDBid, TVDBid, AnimeLists.AniDBMovieSets, mappingList) Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("AniDBid: '{}', TVDBid: '{}', TMDbid: '{}', IMDbid: '{}', ANNid:'{}', MALid: '{}'".format(AniDBid, TVDBid, TMDbid, IMDbid, ANNid, MALid)) common.write_logs(media, movie, error_log, source, AniDBid, TVDBid) common.UpdateMeta(metadata, media, movie, {'AnimeLists': dict_AnimeLists, 'AniDB': dict_AniDB, 'TheTVDB': dict_TheTVDB, 'TheMovieDb': dict_TheMovieDb, 'FanartTV': dict_FanartTV, 'tvdb4': dict_tvdb4, 'Plex': dict_Plex, 'TVTunes': dict_TVTunes, 'OMDb': dict_OMDb, 'MyAnimeList': dict_MyAnimeList, 'Local': dict_Local}, mappingList) Log.Info('=== Update() ==='.ljust(157, '=')) Log.Info("end: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Close()
def Search(results, media, lang, manual, movie): from common import Log #Import here for startup logging to go to the plex pms log orig_title = media.title if movie else media.show Log.Open(media=media, movie=movie, search=True) Log.Info('=== Search() ==='.ljust(157, '=')) Log.Info("title: '%s', name: '%s', filename: '%s', manual: '%s', year: '%s'" % (orig_title, media.name, media.filename, str(manual), media.year)) #if media.filename is not None: filename = String.Unquote(media.filename) #auto match only Log.Info("start: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Info("".ljust(157, '=')) if not orig_title: return #clear-cache directive if orig_title == "clear-cache": HTTP.ClearCache() results.Append(MetadataSearchResult(id='clear-cache', name='Plex web cache cleared', year=media.year, lang=lang, score=0)) return ### Check if a guid is specified "Show name [anidb-id]" ### match = re.search(r"(?P<show>.*?) ?\[(?P<source>([a-z0-9]*))-(tt)?(?P<guid>[0-9]{1,7})\]", orig_title, re.IGNORECASE) if ' [' in orig_title else None if match is not None: guid=match.group('source') + '-' + match.group('guid') if guid.startswith('anidb') and not movie and max(map(int, media.seasons.keys()))>1: Log.Info('[!] multiple seasons = tvdb numbering, BAKA!') results.Append(MetadataSearchResult(id=guid, name=match.group('show')+" ["+guid+']', year=media.year, lang=lang, score=100)) Log.Info("Forced ID - source: {}, id: {}, title: '{}'".format(match.group('source'), match.group('guid'), match.group('show'))) else: #if media.year is not None: orig_title = orig_title + " (" + str(media.year) + ")" ### Year - if present (manual search or from scanner but not mine), include in title ### maxi, n = 0, 0 if movie or max(map(int, media.seasons.keys()))<=1: maxi, n = AniDB.Search(results, media, lang, manual, movie) if maxi<50 and movie: maxi = TheMovieDb.Search(results, media, lang, manual, movie) if maxi<80 and not movie or n>1: maxi = max(TheTVDBv2.Search(results, media, lang, manual, movie), maxi) Log.Info("".ljust(157, '=')) Log.Info("end: {}".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f"))) Log.Close()
def rebuild(self): """ Rebuild the deoated zip """ if self.mBootOAT == None: Log.i(TAG, "rebuild(): boot.oat not found, nothing need rebuild") return # repackage app OatZip.repackageAppWithArch(self.mAppDir, self.arch) if self.arch2.strip(): OatZip.repackageAppWithArch(self.mAppDir, self.arch2) OatZip.repackageAppWithArch(self.mPrivAppDir, self.arch) if self.arch2.strip(): OatZip.repackageAppWithArch(self.mPrivAppDir, self.arch2) # repackage framework #$framedir/$arch #OatZip.repackageFrwWithArch(self.mFrwDir, os.path.join(self.mFrwDir, self.arch)) #$framedir/$arch/dex if os.path.exists(os.path.join(self.mFrwDir, self.arch + "-dex")): OatZip.repackageFrwWithArch( self.mFrwDir, os.path.join(self.mFrwDir, self.arch + "-dex")) #$framedir/oat/$arch if os.path.exists(os.path.join(self.mFrwDir, "oat", self.arch)): OatZip.repackageFrwWithArch( self.mFrwDir, os.path.join(self.mFrwDir, "oat", self.arch)) # deal with additional apks not in system/framework system/app system/priv-app OatZip.dealWithAdditionalApks(self.mSystemDir, self.mFrwDir, self.arch, self.arch2, self.mAllAppDirList) # Remove arch and arch2 dir os.chdir(self.mRoot) if os.path.exists(os.path.join(self.mFrwDir, self.arch)): shutil.rmtree(os.path.join(self.mFrwDir, self.arch)) if os.path.exists(os.path.join(self.mFrwDir, self.arch + "-dex")): shutil.rmtree(os.path.join(self.mFrwDir, self.arch + "-dex")) if os.path.exists(os.path.join(self.mFrwDir, self.arch + "-odex")): shutil.rmtree(os.path.join(self.mFrwDir, self.arch + "-odex")) if self.arch2.strip(): if os.path.exists(os.path.join(self.mFrwDir, self.arch2)): shutil.rmtree(os.path.join(self.mFrwDir, self.arch2)) if os.path.exists(os.path.join(self.mFrwDir, self.arch2 + "-dex")): shutil.rmtree(os.path.join(self.mFrwDir, self.arch2 + "-dex")) if os.path.exists(os.path.join(self.mFrwDir, self.arch2 + "-odex")): shutil.rmtree(os.path.join(self.mFrwDir, self.arch2 + "-odex")) if os.path.exists(os.path.join(self.mFrwDir, "oat")): shutil.rmtree(os.path.join(self.mFrwDir, "oat"))
def repackageFrwWithArch(frwDir, dexFolder): """ Repackage the classes.dex into jar of frwDir. """ if OPTIONS.formatFrw == False: return # Keep the old directory, we will change back after some operations. oldDir = os.path.abspath(os.curdir) Log.i(TAG, "Repackage JARs of %s - %s" % (frwDir, dexFolder)) os.chdir(dexFolder) for dexFile in os.listdir(dexFolder): if dexFile.endswith(".dex") and dexFile.find("classes") == -1: appName = dexFile[0:-4] jarFile = os.path.join(frwDir, appName + ".apk") if not os.path.exists(jarFile): jarFile = jarFile[0:-4] + ".jar" if not os.path.exists(jarFile): dexName = "classes.dex" shutil.move(os.path.join(dexFolder, dexFile), os.path.join(dexFolder, dexName)) Utils.runWithOutput(["jar", "cf", jarFile, dexName]) os.remove(os.path.join(dexFolder, dexName)) continue Log.d(TAG, "Repackage %s" % (jarFile)) if not OatZip.isDeodexed(jarFile): # Put the dex and framework's jar in the same folder, and jar into the jarFile dexName = "classes.dex" shutil.move(os.path.join(dexFolder, dexFile), os.path.join(dexFolder, dexName)) Utils.runWithOutput(["jar", "uf", jarFile, dexName]) os.remove(os.path.join(dexFolder, dexName)) dexName = "classes2.dex" dexFile = appName + "-" + dexName if os.path.exists(os.path.join(dexFolder, dexFile)): shutil.move(os.path.join(dexFolder, dexFile), os.path.join(dexFolder, dexName)) Utils.runWithOutput(["jar", "uf", jarFile, dexName]) os.remove(os.path.join(dexFolder, dexName)) dexName = "classes3.dex" dexFile = appName + "-" + dexName if os.path.exists(os.path.join(dexFolder, dexFile)): shutil.move(os.path.join(dexFolder, dexFile), os.path.join(dexFolder, dexName)) Utils.runWithOutput(["jar", "uf", jarFile, dexName]) os.remove(os.path.join(dexFolder, dexName)) os.chdir(oldDir)
def deoatFrw(oatJarDir): """ De-oat framework """ if not OPTIONS.formatFrw: return Log.i(TAG, "De-oat files of oat-format in %s" % oatJarDir) for item in os.listdir(oatJarDir): if item.endswith(".odex"): # COMMANDS: oat2dex boot <jar-of-oat-format> oatJar = os.path.join(oatJarDir, item) Utils.runWithOutput([OatZip.OAT2DEX, "boot", oatJar])
def getPath(*name, **args): """ Get a path to an existing resource. @param *name Resource path segments @param required If True, a warning is logged if the resource is not found. """ for path in paths: p = os.path.join(path, *name) if os.path.exists(p): return p if args.get("required", True) == True: Log.warn("Resource '%s' not found." % os.sep.join(name))
def validate(self): lib = self.library # Validate the target for function in lib.functions.values(): if function.ordinal is None and function.staticLinkage and self.project.platform.requireOrdinals: Log.warn("Function '%s' does not have a valid ordinal." % function.name) for parameter in function.parameters.values(): if lib.getNativeType(parameter.type) == "pointer" \ and not parameter.name in lib.functions[function.name].hooks \ and not parameter.metaType \ and lib.functions[function.name].generate: Log.warn("Saving naked pointer '%s' of type '%s' in function '%s'." % (parameter.name, parameter.type, function.name))
def load(self): # Determine the trace file size try: self.file.seek(0, 2) fileSize = self.file.tell() self.file.seek(0) except: fileSize = 0 task = Task.startTask("load", "Loading trace", steps = fileSize) # Read and verify version magic version = self.file.read(4) if version != FORMAT_VERSION: raise RuntimeError("Unsupported file format version: %s (%s)" % (version, binascii.hexlify(version))) # First pass: read all the events for i, event in enumerate(self.readEvents()): self.trace.events.append(event) if fileSize: task.updateProgress(self.file.tell()) elif (i & 0xff) == 0: task.step() task.finish() task = Task.startTask("resolve", "Resolving data", len(self.trace.events)) # Second pass: resolve any unknown phrases for event in self.trace.events: if isinstance(event.name, Trace.UnknownPhrase): Log.warn("Event %d name is undefined, trace is probably corrupted." % event.seq) self.trace.events.remove(event) continue for key, value in event.values.items(): if isinstance(key, Trace.UnknownPhrase): Log.warn("Event %d parameter name is undefined, trace is probably corrupted." % event.seq) self.trace.events.remove(event) continue if isinstance(value, Trace.UnknownPhrase): v2 = value value = self.decoder.getPhrase(value.id) if isinstance(value, Trace.UnknownPhrase): #Log.warn("Unable to resolve unknown phrase %s.%s = %s." % (event.name, key, value)) pass else: event.values[key] = value if not value in event.modifiedArrays: event.modifiedArrays.append(value) task.step()
def GetMetadata(metadata, error_log, TVDBid, title): Log.Info("=== Plex.GetMetadata() ===".ljust(157, '=')) url = THEME_URL.format(TVDBid) Plex_dict = {} Log.Info("Prefs['themes']: '{}', TVDBid: '{}'".format( Prefs['themes'], TVDBid)) Log.Info("--- themes ---".ljust(157, '-')) if 'Plex' in Prefs['themes'] and TVDBid.isdigit(): title = title or TVDBid result = '*' if url in metadata.themes else common.GetStatusCode(url) Log.Info("result code: '{plex}', url: '{url}'".format(plex=result, url=url)) if result in (200, "*"): Log.Info("[ ] theme: {}".format( SaveDict(("Plex/%s.mp3" % TVDBid, 2, None), Plex_dict, 'themes', url))) else: error_log['Plex themes missing'].append( "TVDBid: '{}' | Title: '{}' | {}".format( common.WEB_LINK % (common.TVDB_SERIE_URL + TVDBid, title), title, common.WEB_LINK % ("mailto:[email protected]?cc=&subject=Missing%%20theme%%20song%%20-%%20'%s%%20-%%20%s.mp3'" % (title, TVDBid), 'Upload'))) else: Log.Info( "Not pulling meta - 'Plex' in Prefs['themes']: '{}', TVDBid: '{}'". format('Plex' in Prefs['themes'], TVDBid)) Log.Info("--- return ---".ljust(157, '-')) Log.Info("Plex_dict: {}".format(DictString(Plex_dict, 1))) return Plex_dict
def collectItem(self, targetPath, item): Tools.makePath(targetPath) path = self.config.getRelativePath(item) if not os.path.exists(path): Log.error("Project file '%s' not found." % path) return if not int(item.attrs.get("copy", 1)): return path name = os.path.basename(path) shutil.copyfile(path, os.path.join(targetPath, name)) return name
def loadHooks(self): target = self.target config = self.target.config lib = self.target.library platform = self.target.project.platform # Collect hooks in various locations for fileName in config.get("hooks", []): Log.notice("Parsing hooks from '%s'." % fileName) source = self.readSource(fileName) functions = Parser.parseSource(source).functions.values() if not functions: Log.warn("No hooks found.") for f in functions: Log.debug("%s %s(%s)" % (f.type, f.name, ", ".join(["%s %s" % (t.type, p) for p, t in f.parameters.items()]))) for function in functions: if not function.body: Log.warn("Hook function '%s' has no body." % function.name) continue if function.name.startswith("@"): lib.hooks[function.name] = function.body continue else: try: name, hookName = function.name.split(".", 1) if not name in lib.functions: target.fail("Function '%s' referred by hook function '%s' does not exist." % (name, function.name)) if not hookName.startswith("@") and not hookName in lib.functions[name].parameters: target.fail("Parameter '%s' referred by hook function '%s' does not exist." % (hookName, function.name)) lib.functions[name].hooks[hookName] = function.body except ValueError: target.fail("Hook function name '%s' is not valid." % function.name)
def setPhrase(self, id, data): # Check that this definition is really necessary if verbose and name in self.phrasebook: oldData = self.phrasebook[name] if data == oldData: Log.warn("%d bytes of redundant phrase data for phrase 0x%x" % (len(data), name)) elif len(oldData) < len(data): for v1, v2 in zip(oldData, data): if v1 != v2: break else: Log.warn("%d bytes of partially redundant phrase data for phrase 0x%x" % (len(data), name)) self.phrasebook[id] = data
def connect(): connected = False while True: try: if(connected == False): Log.i("PortalConnect","Connecting to PORTAL",PortalConnect.IP, 4046) PortalConnect.checkVPN() server_address = (PortalConnect.IP, 4046 ) PortalConnect.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) PortalConnect.sock.connect(server_address) PortalConnect.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) PortalConnect.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1) PortalConnect.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1) PortalConnect.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5) Log.i("PortalConnect","Connected to PORTAL") PortalConnect.sock.settimeout(3) data = { 'cmd' : 'register.renew', 'locIP' : PortalConnect.get_lan_ip(), 'webVer' : PortalConnect.config ['PortalConnect']['webVer'], 'hubVer' : PortalConnect.getMaxVer(), 'id' : PortalConnect.config ['PortalConnect']['id'], } #PortalConnect.sock.setblocking(0) connected = True PortalConnect.sock.sendall(json.dumps({"data":data}).encode()) PortalConnect.thread() #data = PortalConnect.sock.recv(1024) #Log.i('PortalConnect', "ReReged: ", data) #PortalConnect.sock.sendall(b"") time.sleep(1) #if not data: #connected = False #break except ConnectionError as e: Log.e('PortalConnect/Connect',"While E: %s"%e) connected = False time.sleep(5) #break except ValueError as e: Log.e('PortalConnect/Connect',"While E: %s"%e) connected = False time.sleep(5) except socket.error as e: #if(e.errno != 11): Log.w('PortalConnect/Connect',"Retrying...\n%s"%e) connected = False time.sleep(5)
def getNativeType(self, library, type): """ Get the native equivalent of a Type instance. @param library: Library from which the type is searched @param type: Type instance to convert to native type @returns the name of the matching native type or None """ t = library.getNativeType(type) if not t: Log.warn("Type '%s' has no mapping to a native equivalent; defaulting to 'int'." % type.declaration) t = "int" return t
def GetAniDBTVDBMapCustom(media, movie): AniDBTVDBMapCustom = None lib, root, path = common.GetLibraryRootPath(common.GetMediaDir(media, movie)) dir = os.path.join(root, path) while dir and os.path.splitdrive(dir)[1] != os.sep: scudlee_filename_custom = os.path.join(dir, SCHUDLEE_CUSTOM) if os.path.exists( scudlee_filename_custom ): try: AniDBTVDBMapCustom = XML.ElementFromString(Core.storage.load(scudlee_filename_custom)) Log.Info("Local custom mapping file loaded: {}".format(scudlee_filename_custom)) except: Log.Error("Failed to open: '%s', error: '%s'" % (scudlee_filename_custom, e)) else: break dir = os.path.dirname(dir) else: Log.Info("Local custom mapping file not present: {}".format(SCHUDLEE_CUSTOM)) return AniDBTVDBMapCustom
def rebuild(self): """ Rebuild the deoated zip """ if self.mBootOAT == None: Log.i(TAG, "rebuild(): boot.oat not found, nothing need rebuild") return OatZip.repackageFrw(self.mFrwDir, self.mBootClassFolder) OatZip.repackageApp(self.mFrwDir) OatZip.repackageApp(self.mAppDir) OatZip.repackageApp(self.mPrivAppDir) # Remove the whole OAT directory if os.path.exists(self.mBootOATDir): shutil.rmtree(self.mBootOATDir)
def unzip(self): # Already unziped if self.mRoot is not None: return self.mRoot = tempfile.mkdtemp() Log.i(TAG, "unzip %s to %s" % (self.mInZip, self.mRoot)) cmd = "unzip -q -o %s -d %s" %(self.mInZip, self.mRoot) Log.d(TAG, commands.getoutput(cmd)) self.dedatIfNeeded() # Format path if os.path.exists(os.path.join(self.mRoot, "SYSTEM")): shutil.move(os.path.join(self.mRoot, "SYSTEM"), os.path.join(self.mRoot, "system")) return self
def create(options): """ Create a zip formatter for the incoming zip file """ zipModel = ZipModel(options.inZip, options.outZip) zipType = zipModel.getZipType() Log.i(TAG, "process(): Creating %s ZipFormatter..." %zipType) if zipType == ZipModel.ART: deoat.OPTIONS = options return Deoat(zipModel) elif zipType == ZipModel.DVM: deodex.OPTIONS = options return Deodex(zipModel) else: raise Exception("Unknown OTA package zip. Is it an ART or DALVIKVM package?")
def prepareTarget(targetName): if targetName in project.targets: return if not targetName in Target.targets: fail("Bad target name '%s'." % targetName) return targetClass = Target.targets[targetName] for dep in targetClass.dependencies: if not dep in project.targets: prepareTarget(dep) Log.notice("Preparing target %d of %d: %s." % (len(project.targets) + 1, len(targetNames), targetName)) target = targetClass(project) target.prepare() target.validate() project.targets[targetName] = target
def dedatIfNeeded(self): """ Android 5.0 zip structure: * META-INF (folder containing scripts) * system.new.dat (compressed /system partition) * system.patch.dat * system.transfer.list (see explanation below) """ if not os.path.exists(os.path.join(self.mRoot, "system.new.dat")): return if not os.path.exists(os.path.join(self.mRoot, "system.transfer.list")): return if os.geteuid() != 0: raise Exception("DEDAT should be executed as root.") cmd = "%s %s" % (commands.mkarg(ZipModel.DAT2IMG), commands.mkarg(self.mRoot)) Log.d(TAG, commands.getoutput(cmd))
def deodexFrw(odexJarDir): """ De-odex framework """ if OPTIONS.formatFrw == False: return coreOdex = os.path.join(odexJarDir, "core.odex") if os.path.exists(coreOdex): Log.i(TAG, "De-odex core.odex") deodexFile = os.path.join(odexJarDir, "core.jar") OdexZip.deodexOneFile(coreOdex, deodexFile) Log.i(TAG, "De-odex files of odex-format in %s" % odexJarDir) for item in os.listdir(odexJarDir): if item.endswith(".odex"): odexJar = os.path.join(odexJarDir, item) deodexJar = odexJar[0:-4] + ".jar" OdexZip.deodexOneFile(odexJar, deodexJar) break
def __init__(self, **cfg): self.log_obj = Log(cfg["log_file"]) self.meta_con = MySQLdb.connect( host=cfg["db_meta_host"], user=cfg["db_meta_user"], passwd=cfg["db_meta_pwd"], db=cfg["db_meta_name"], charset="utf8", use_unicode=True, cursorclass=MySQLdb.cursors.DictCursor, ) self.meta_cursor = self.meta_con.cursor()
def generate(templates, namespace, outputFile = sys.stdout): """ Process a list of templates and write the result to a file object. @param templates: A list of templates to process @param namespace: A dictionary of objects that the templates may access @param outputFile: Output file object. """ def processTemplate(inputFile, outputFile, searchList): t = Template(file = inputFile, searchList = searchList) outputFile.write(str(t)) def process(templateName): processTemplate(open(templateName), outputFile, namespace) for template in templates: try: process(template) except Exception, e: Log.error("Exception while processing template '%s': %s" % (template, e)) raise
def show(project, options, args): """Show information about a project target. [target]""" commands = [ "all", "config", "functions", "constants", "typedefs" ] if not args: fail("Show what? Use one of %s" % ", ".join(commands)) command, args = args[0], args[1:] if not command in commands: fail("Show what? Use one of %s" % ", ".join(commands)) if not project.targets: fail("Project file name missing.") config = project.config lib = project.library if "code" in project.targets: lib = project.targets["code"].library if args: config = project.targets[args[0]].config lib = project.targets[args[0]].library if command == "config" or command == "all": Log.notice("Configuration:") print config.save() if command == "functions" or command == "all": Log.notice("%d functions:" % len(lib.functions)) for name, function in lib.functions.items(): params = [] for paramName, param in sorted(function.parameters.items()): params.append("%s %s" % (param.type, param.name)) params = ", ".join(params) print "%s %s(%s)" % (function.type, function.name, params) if command == "constants" or command == "all": Log.notice("%d constants:" % len(lib.constants)) for constName, constValue in sorted(lib.constants.items()): print "%-40s %-8s (0x%x)" % (constName, constValue, constValue) if command == "typedefs" or command == "all": Log.notice("%d typedefs:" % len(lib.typeDefs)) for tdName, tdValue in sorted(lib.typeDefs.items()): print "%-40s %s" % (tdName, tdValue)