def storeKernel(self, fileName, bootCode=""): Console.info("Storing kernel...") Console.indent() # Export all field data for the kernel classes = [] fieldSetupClasses = self.__session.getFieldSetupClasses() for fieldName in fieldSetupClasses: classes.append(fieldSetupClasses[fieldName]) # Transfer all hard-wired fields into a permutation self.__session.setStaticPermutation() # Sort and compress sortedClasses = self.__buildClassList(classes, bootCode, inlineTranslations=True) Console.info("Compressing %s classes...", len(sortedClasses)) compressedCode = self.__compressClasses(sortedClasses) # Write file to disk self.__fileManager.writeFile(fileName, compressedCode) # Remember kernel level classes self.__kernelClasses = sortedClasses Console.outdent()
def compute(tree): Console.info("Resolving variables...") Console.indent() __computeRecurser(tree, None, {}) Console.outdent()
def __generateFeed(self): if not self.__posts: return Console.info("Generating feed...") Console.indent() itemsInFeed = self.config["blog"]["itemsInFeed"] destinationPath = self.__profile.getDestinationPath() for language in self.__languages: sortedPosts = self.__getSortedPosts(language) # Feed Render Model renderModel = { 'config' : self.config, 'site' : { 'name' : self.__siteName, 'url' : self.__siteUrl }, "current" : { "lang" : language }, "feedUrl" : self.__feedUrl, "now" : datetime.datetime.now(tz=dateutil.tz.tzlocal()).replace(microsecond=0).isoformat(), "posts" : sortedPosts[0:itemsInFeed] } template = self.__templates["%s.Feed" % self.__theme] outputContent = template.render(renderModel) outputFilename = os.path.join(destinationPath, self.__feedUrl) self.__fileManager.writeFile(outputFilename, outputContent) Console.outdent()
def checkSingleInstallation(keys, versions, packageName, minVersion, installPath, updatePath): Console.info('%s:' % packageName) Console.indent() if packageName.lower() in keys: Console.info(Console.colorize('Found installation', "green")) if LooseVersion(minVersion) > LooseVersion("0.0"): if LooseVersion(versions[packageName.lower()]) >= LooseVersion( minVersion): Console.info( Console.colorize( 'Version is OK (needed: %s installed: %s)' % (minVersion, versions[packageName.lower()]), "green")) else: Console.info( Console.colorize( Console.colorize( '- Version is NOT OK (needed: %s installed: %s)' % (minVersion, versions[packageName.lower()]), "red"), "bold")) Console.info( 'Update to the newest version of %s using %s' % (packageName, updatePath)) else: Console.info( Console.colorize( Console.colorize('Did NOT find installation', "red"), "bold")) Console.info('Install the newest version of %s using %s' % (packageName, installPath)) Console.outdent()
def __addDir(self, directory, regex, type, package): check = re.compile(regex) path = os.path.join(self.__path, directory) if not os.path.exists(path): return Console.debug("Scanning directory: %s" % directory) Console.indent() for dirPath, dirNames, fileNames in os.walk(path): for dirName in dirNames: # Filter dotted directories like .git, .bzr, .hg, .svn, etc. if dirName.startswith("."): dirNames.remove(dirName) relDirPath = os.path.relpath(dirPath, path) for fileName in fileNames: if fileName[0] == ".": continue relPath = os.path.normpath(os.path.join(relDirPath, fileName)).replace(os.sep, "/") if not check.match(os.path.join(directory, relPath).replace(os.sep, "/")): continue fullPath = os.path.join(dirPath, fileName) self.addFile(relPath, fullPath, type, package) Console.outdent()
def __getOptimizedTree(self, permutation=None, context=None): """Returns an optimized tree with permutations applied""" field = "opt-tree[%s]-%s" % (self.id, permutation) tree = self.project.getCache().read(field, self.mtime) if not tree: tree = copy.deepcopy(self.__getTree("%s:plain" % context)) # Logging msg = "Processing class %s" % Console.colorize(self.id, "bold") if permutation: msg += Console.colorize(" (%s)" % permutation, "grey") if context: msg += Console.colorize(" [%s]" % context, "cyan") Console.info("%s..." % msg) Console.indent() # Apply permutation if permutation: Console.debug("Patching tree with permutation: %s", permutation) Console.indent() jasy.js.clean.Permutate.patch(tree, permutation) Console.outdent() # Cleanups jasy.js.clean.DeadCode.cleanup(tree) ScopeScanner.scan(tree) jasy.js.clean.Unused.cleanup(tree) self.project.getCache().store(field, tree, self.mtime, True) Console.outdent() return tree
def __resolve(project): name = project.getName() # List of required projects Console.info("Getting requirements of %s...", Console.colorize(name, "bold")) Console.indent() requires = project.getRequires(checkoutDirectory, updateRepositories) Console.outdent() if not requires: return Console.debug("Processing %s requirements...", len(requires)) Console.indent() # Adding all project in reverse order. # Adding all local ones first before going down to their requirements for requiredProject in reversed(requires): requiredName = requiredProject.getName() if not requiredName in names: Console.debug("Adding: %s %s (via %s)", requiredName, requiredProject.version, project.getName()) names[requiredName] = True result.append(requiredProject) else: Console.debug("Blocking: %s %s (via %s)", requiredName, requiredProject.version, project.getName()) # Process all requirements of added projects for requiredProject in requires: if requiredProject.hasRequires(): __resolve(requiredProject) Console.outdent()
def __addContent(self, content): Console.info("Adding manual content") Console.indent() for fileId in content: entry = content[fileId] if not isinstance(entry, dict): raise UserError("Invalid manual content section for file %s. Requires a dict with type and source definition!" % fileId) itemType = entry["type"] fileContent = entry["source"] if len(fileContent) == 0: raise UserError("Empty content!") # Support for joining text content if len(fileContent) == 1: filePath = os.path.join(self.__path, fileContent[0]) else: filePath = [os.path.join(self.__path, filePart) for filePart in fileContent] name, construct = self.__resolveConstructor(itemType) item = construct(self, fileId).attach(filePath) Console.debug("Registering %s %s" % (item.kind, fileId)) if not itemType in self.items: self.items[itemType] = {} # Check for duplication if fileId in self.items[itemType]: raise UserError("Item ID was registered before: %s" % fileId) self.items[itemType][fileId] = item Console.outdent()
def cleanup(node): """ """ if not hasattr(node, "variables"): ScopeScanner.scan(node) # Re cleanup until nothing to remove is found iteration = 0 cleaned = False Console.info("Removing unused variables...") Console.indent() while True: iteration += 1 modified = __cleanup(node) if modified > 0: Console.info("Removed %s unused variables", modified) ScopeScanner.scan(node) cleaned = True else: break Console.outdent() return cleaned
def cleanup(node): """""" if not hasattr(node, "variables"): ScopeScanner.scan(node) # Re cleanup until nothing to remove is found x = 0 cleaned = False Console.debug("Removing unused variables...") while True: x = x + 1 #debug("Removing unused variables [Iteration: %s]...", x) Console.indent() if __cleanup(node): ScopeScanner.scan(node) cleaned = True Console.outdent() else: Console.outdent() break return cleaned
def attach(self, path): # Call AbstractItem's attach method first super().attach(path) Console.debug("Loading translation file: %s", path) Console.indent() # Flat data strucuture where the keys are unique table = {} path = self.getPath() # Decide infrastructure/parser to use based on file name po = polib.pofile(path) Console.debug("Translated messages: %s=%s%%", self.language, po.percent_translated()) for entry in po.translated_entries(): entryId = generateMessageId(entry.msgid, entry.msgid_plural, entry.msgctxt) if entryId not in table: if entry.msgstr != "": table[entryId] = entry.msgstr elif entry.msgstr_plural: # This field contains all different plural cases (type=dict) table[entryId] = entry.msgstr_plural Console.debug("Translation of %s entries ready" % len(table)) Console.outdent() self.table = table return self
def getTranslationBundle(self, language=None): """Returns a translation object for the given language containing all relevant translation files for the current project set.""" if language is None: return None if language in self.__translationBundles: return self.__translationBundles[language] Console.info("Creating translation bundle: %s", language) Console.indent() # Initialize new Translation object with no project assigned # This object is used to merge all seperate translation instances later on. combined = jasy.item.Translation.TranslationItem(None, id=language) relevantLanguages = self.__expandLanguage(language) # Loop structure is build to prefer finer language matching over project priority for currentLanguage in reversed(relevantLanguages): for project in self.__projects: for translation in project.getTranslations().values(): if translation.getLanguage() == currentLanguage: Console.debug("Adding %s entries from %s @ %s...", len(translation.getTable()), currentLanguage, project.getName()) combined += translation Console.info("Combined number of translations: %s", len(combined.getTable())) Console.outdent() self.__translationBundles[language] = combined return combined
def init(self, autoInitialize=True, updateRepositories=True, scriptEnvironment=None): """ Initialize the actual session with projects :param autoInitialize: Whether the projects should be automatically added when the current folder contains a valid Jasy project. :param updateRepositories: Whether to update repositories of all project dependencies. :param scriptEnvironment: API object as being used for loadLibrary to add Python features offered by projects. """ self.__scriptEnvironment = scriptEnvironment self.__updateRepositories = updateRepositories if autoInitialize and jasy.core.Config.findConfig("jasyproject"): try: self.addProject(jasy.core.Project.getProjectFromPath(".")) except UserError as err: Console.outdent(True) Console.error(err) raise UserError("Critical: Could not initialize session!") Console.info("Active projects (%s):", len(self.__projects)) Console.indent() for project in self.__projects: if project.version: Console.info("%s @ %s", Console.colorize(project.getName(), "bold"), Console.colorize(project.version, "magenta")) else: Console.info(Console.colorize(project.getName(), "bold")) Console.outdent()
def __generateTranslationBundle(self): """ Returns a translation object for the given language containing all relevant translation files for the current project set. """ language = self.getCurrentPermutation().get("locale") if language is None: return None if language in self.__translationBundles: return self.__translationBundles[language] Console.info("Creating translation bundle: %s", language) Console.indent() # Initialize new Translation object with no project assigned # This object is used to merge all seperate translation instances later on. combined = jasy.item.Translation.TranslationItem(None, id=language) relevantLanguages = self.__expandLanguage(language) # Loop structure is build to prefer finer language matching over project priority for currentLanguage in reversed(relevantLanguages): for project in self.__projects: for translation in project.getTranslations().values(): if translation.getLanguage() == currentLanguage: Console.debug("Adding %s entries from %s @ %s...", len(translation.getTable()), currentLanguage, project.getName()) combined += translation Console.debug("Combined number of translations: %s", len(combined.getTable())) Console.outdent() self.__translationBundles[language] = combined return combined
def getApi(self, highlight=True): field = "api[%s]-%s" % (self.id, highlight) apidata = self.project.getCache().read(field, self.mtime, inMemory=False) if apidata is None: apidata = jasy.js.api.Data.ApiData(self.id, highlight) tree = self.__getTree(context="api") Console.indent() apidata.scanTree(tree) Console.outdent() metaData = self.getMetaData() apidata.addAssets(metaData.assets) for require in metaData.requires: apidata.addUses(require) for optional in metaData.optionals: apidata.removeUses(optional) apidata.addSize(self.getSize()) apidata.addFields(self.getFields()) self.project.getCache().store(field, apidata, self.mtime, inMemory=False) return apidata
def __addDir(self, directory, distname): Console.debug("Scanning directory: %s" % directory) Console.indent() path = os.path.join(self.__path, directory) if not os.path.exists(path): return for dirPath, dirNames, fileNames in os.walk(path): for dirName in dirNames: # Filter dotted directories like .git, .bzr, .hg, .svn, etc. if dirName.startswith("."): dirNames.remove(dirName) # Filter sub projects if os.path.exists(os.path.join(dirPath, dirName, "jasyproject.json")): dirNames.remove(dirName) relDirPath = os.path.relpath(dirPath, path) for fileName in fileNames: if fileName[0] == ".": continue relPath = os.path.normpath(os.path.join(relDirPath, fileName)).replace(os.sep, "/") fullPath = os.path.join(dirPath, fileName) self.addFile(relPath, fullPath, distname) Console.outdent()
def __addDir(self, directory, distname): Console.debug("Scanning directory: %s" % directory) Console.indent() path = os.path.join(self.__path, directory) if not os.path.exists(path): return for dirPath, dirNames, fileNames in os.walk(path): for dirName in dirNames: # Filter dotted directories like .git, .bzr, .hg, .svn, etc. if dirName.startswith("."): dirNames.remove(dirName) # Filter sub projects if os.path.exists( os.path.join(dirPath, dirName, "jasyproject.json")): dirNames.remove(dirName) relDirPath = os.path.relpath(dirPath, path) for fileName in fileNames: if fileName[0] == ".": continue relPath = os.path.normpath(os.path.join(relDirPath, fileName)).replace( os.sep, "/") fullPath = os.path.join(dirPath, fileName) self.addFile(relPath, fullPath, distname) Console.outdent()
def generate(self, path='', autorotate=False, debug=False): """Generate sheets/variants""" Console.info('Generating sprite sheet variants...') Console.indent() sheets, count = self.packBest(autorotate) # Write PNG files data = {} for pos, sheet in enumerate(sheets): Console.info('Writing image (%dx%dpx) with %d images' % (sheet.width, sheet.height, len(sheet))) name = 'jasysprite_%d.png' % pos # Export sheet.write(os.path.join(self.base, path, name), debug) data[name] = sheet.export() Console.outdent() # Generate JSON/YAML Console.info('Exporting data...') script = os.path.join(self.base, path, 'jasysprite.%s' % self.dataFormat) writeConfig(data, script)
def cleanup(node): """""" if not hasattr(node, "variables"): ScopeScanner.scan(node) # Re cleanup until nothing to remove is found iteration = 0 cleaned = False Console.debug("Removing unused variables...") Console.indent() while True: iteration += 1 modified = __cleanup(node) if modified > 0: Console.debug("Removed %s unused variables", modified) ScopeScanner.scan(node) cleaned = True else: break Console.outdent() return cleaned
def __init__(self, session, assetManager=None, compressionLevel=1, formattingLevel=0): Console.info("Initializing OutputManager...") Console.indent() Console.info("Formatting Level: %s", formattingLevel) Console.info("Compression Level: %s", compressionLevel) self.__session = session self.__assetManager = assetManager self.__fileManager = FileManager(session) self.__scriptOptimization = Optimization() self.__compressGeneratedCode = False self.__kernelClasses = [] if compressionLevel > 0: self.__scriptOptimization.enable("variables") self.__scriptOptimization.enable("declarations") self.__compressGeneratedCode = True if compressionLevel > 1: self.__scriptOptimization.enable("blocks") self.__scriptOptimization.enable("privates") self.__scriptFormatting = Formatting() if formattingLevel > 0: self.__scriptFormatting.enable("semicolon") self.__scriptFormatting.enable("comma") Console.outdent()
def __init__(self, locale): Console.info("Parsing CLDR files for %s..." % locale) Console.indent() splits = locale.split("_") # Store for internal usage self.__locale = locale self.__language = splits[0] self.__territory = splits[1] if len(splits) > 1 else None # This will hold all data extracted data self.__data = {} # Add info section self.__data["info"] = {"LOCALE": self.__locale, "LANGUAGE": self.__language, "TERRITORY": self.__territory} # Add keys (fallback to C-default locale) path = "%s.xml" % os.path.join(CLDR_DIR, "keys", self.__language) try: Console.info("Processing %s..." % os.path.relpath(path, CLDR_DIR)) tree = xml.etree.ElementTree.parse(path) except IOError: path = "%s.xml" % os.path.join(CLDR_DIR, "keys", "C") Console.info("Processing %s..." % os.path.relpath(path, CLDR_DIR)) tree = xml.etree.ElementTree.parse(path) self.__data["key"] = { "Short": {key.get("type"): key.text for key in tree.findall("./keys/short/key")}, "Full": {key.get("type"): key.text for key in tree.findall("./keys/full/key")}, } # Add main CLDR data: Fallback chain for locales main = os.path.join(CLDR_DIR, "main") files = [] while True: files.append("%s.xml" % os.path.join(main, locale)) if "_" in locale: locale = locale[: locale.rindex("_")] else: break # Extend data with root data files.append(os.path.join(main, "root.xml")) # Finally import all these files in order for path in reversed(files): Console.info("Processing %s..." % os.path.relpath(path, CLDR_DIR)) tree = xml.etree.ElementTree.parse(path) self.__addDisplayNames(tree) self.__addDelimiters(tree) self.__addCalendars(tree) self.__addNumbers(tree) # Add supplemental CLDR data self.__addSupplementals(self.__territory) Console.outdent()
def generate(self, path='', debug=False): """Generate sheets/variants.""" Console.info('Generating sprite sheet variants...') Console.indent() sheets, count = self.packBest() # Write PNG files data = {} for pos, sheet in enumerate(sheets): Console.info('Writing image (%dx%dpx) with %d images' % (sheet.width, sheet.height, len(sheet))) name = 'jasysprite_%d.png' % pos # Export sheet.write(os.path.join(self.base, path, name), debug) data[name] = sheet.export() Console.outdent() # Generate config file Console.info('Exporting data...') script = os.path.join(self.base, path, 'jasysprite.%s' % self.dataFormat) writeConfig(data, script)
def __addDir(self, directory, regex, type, package): check = re.compile(regex) path = os.path.join(self.__path, directory) if not os.path.exists(path): return Console.debug("Scanning directory: %s" % directory) Console.indent() for dirPath, dirNames, fileNames in os.walk(path): for dirName in dirNames: # Filter dotted directories like .git, .bzr, .hg, .svn, etc. if dirName.startswith("."): dirNames.remove(dirName) relDirPath = os.path.relpath(dirPath, path) for fileName in fileNames: if fileName[0] == ".": continue relPath = os.path.normpath(os.path.join(relDirPath, fileName)).replace( os.sep, "/") if not check.match( os.path.join(directory, relPath).replace(os.sep, "/")): continue fullPath = os.path.join(dirPath, fileName) self.addFile(relPath, fullPath, type, package) Console.outdent()
def processSprites(self): """Processes jasysprite files to merge sprite data into asset registry.""" assets = self.__assets configs = [fileId for fileId in assets if assets[fileId].isImageSpriteConfig()] if configs: Console.info("Processing %s...", Console.colorize("%s sprites", "magenta") % len(configs)) sprites = [] Console.indent() for fileId in configs: Console.debug("Processing %s...", fileId) asset = assets[fileId] spriteBase = os.path.dirname(fileId) try: spriteConfig = asset.getParsedObject() except ValueError as err: raise UserError("Could not parse jasysprite at %s: %s" % (fileId, err)) Console.indent() for spriteImage in spriteConfig: spriteImageId = "%s/%s" % (spriteBase, spriteImage) singleRelPaths = spriteConfig[spriteImage] Console.debug("Image %s combines %s images", spriteImageId, len(singleRelPaths)) for singleRelPath in singleRelPaths: singleId = "%s/%s" % (spriteBase, singleRelPath) singleData = singleRelPaths[singleRelPath] singleItem = assets[singleId] # Verify that sprite sheet is up-to-date fileChecksum = singleItem.getChecksum() storedChecksum = singleData["checksum"] Console.debug("Checksum Compare: %s <=> %s", fileChecksum, storedChecksum) if storedChecksum != fileChecksum: raise UserError("Sprite Sheet is not up-to-date. Checksum of %s differs." % singleId) if spriteImageId not in sprites: spriteImageIndex = len(sprites) sprites.append(spriteImageId) else: spriteImageIndex = sprites.index(spriteImageId) # Add relevant data to find image on sprite sheet singleItem.addImageSpriteData(spriteImageIndex, singleData["left"], singleData["top"]) Console.outdent() # The config file does not make any sense on the client side Console.debug("Deleting sprite config from assets: %s", fileId) del assets[fileId] Console.outdent() self.__sprites = sprites
def executeCommand(args, failMessage=None, path=None, wrapOutput=True): """ Executes the given process and outputs failMessage when errors happen. :param args: :type args: str or list :param failMessage: Message for exception when command fails :type failMessage: str :param path: Directory path where the command should be executed :type path: str :raise Exception: Raises an exception whenever the shell command fails in execution :type wrapOutput: bool :param wrapOutput: Whether shell output should be wrapped and returned (and passed through to Console.debug()) """ if isinstance(args, str): args = shlex.split(args) prevpath = os.getcwd() # Execute in custom directory if path: path = os.path.abspath(os.path.expanduser(path)) os.chdir(path) Console.debug("Executing command: %s", " ".join(args)) Console.indent() # Using shell on Windows to resolve binaries like "git" if not wrapOutput: returnValue = subprocess.call(args, shell=sys.platform == "win32") result = returnValue else: output = tempfile.TemporaryFile(mode="w+t") returnValue = subprocess.call(args, stdout=output, stderr=output, shell=sys.platform == "win32") output.seek(0) result = output.read().strip("\n\r") output.close() # Change back to previous path os.chdir(prevpath) if returnValue != 0 and failMessage: raise Exception("Error during executing shell command: %s (%s)" % (failMessage, result)) if wrapOutput: for line in result.splitlines(): Console.debug(line) Console.outdent() return result
def storeKernel(self, fileName, classes=None, debug=False): """ Writes a so-called kernel script to the given location. This script contains data about possible permutations based on current session values. It optionally might include asset data (useful when boot phase requires some assets) and localization data (if only one locale is built). Optimization of the script is auto-enabled when no other information is given. This method returns the classes which are included by the script so you can exclude it from the real other generated output files. """ Console.info("Storing kernel...") Console.indent() # Use a new permutation based on debug settings and statically configured fields self.__session.setStaticPermutation(debug=debug) # Build resolver # We need the permutation here because the field configuration might rely on detection classes resolver = Resolver(self.__session) detectionClasses = self.__session.getFieldDetectionClasses() for className in detectionClasses: resolver.addClassName(className) # Jasy client side classes to hold data resolver.addClassName("jasy.Env") resolver.addClassName("jasy.Asset") resolver.addClassName("jasy.Translate") # Allow kernel level mass loading of scripts (required for source, useful for build) resolver.addClassName("core.io.Script") resolver.addClassName("core.io.Queue") if classes: for className in classes: resolver.addClassName(className) # Generate boot code bootCode = "jasy.Env.setFields(%s);" % self.__session.exportFields() if self.__compressGeneratedCode: bootCode = packCode(bootCode) # Sort resulting class list sortedClasses = resolver.getSortedClasses() self.storeCompressed(sortedClasses, fileName, bootCode) # Remember classes for filtering in storeLoader/storeCompressed self.__kernelClasses = set(sortedClasses) # Reset static permutation self.__session.resetCurrentPermutation() Console.outdent()
def export(self, path): Console.info("Writing result...") Console.info("Target directory: %s", path) Console.indent() jasy.core.File.write(os.path.join(path, "jasyproject.yaml"), 'name: locale\npackage: ""\n') count = self.__exportRecurser(self.__data, "locale", path) Console.info("Created %s classes", count) Console.outdent()
def processSelectors(tree): """Processes all mixin includes inside selectors.""" Console.info("Merging mixins into selectors") Console.indent() modified = __process(tree, scanMixins=False) Console.debug("Merged %s mixins", modified) Console.outdent() return modified
def processMixins(tree): """Processes all mixin includes inside mixins.""" Console.info("Merging mixins with each other...") Console.indent() modified = __process(tree, scanMixins=True) Console.debug("Merged %s mixins", modified) Console.outdent() return modified
def processExtends(tree): """Processes all requests for mixin extends.""" Console.info("Processing extend requests...") Console.indent() modified = __extend(tree) Console.debug("Processed %s selectors", modified) Console.outdent() return modified
def cleanup(node): """Reprocesses JavaScript to remove dead paths.""" Console.debug("Removing dead code branches...") Console.indent() result = __cleanup(node) Console.outdent() return result
def storeCompressedScript(self, items, fileName, bootCode=""): Console.info("Generating compressed script...") Console.indent() sortedScripts = self.__sortScriptItems(items, bootCode, filterBy=self.__kernelScripts, inlineTranslations=True) compressedCode = self.__compressScripts(sortedScripts) self.__fileManager.writeFile(os.path.join(self.__outputPath, fileName), compressedCode) Console.outdent()
def storeLoaderScript(self, items, fileName, bootCode=""): Console.info("Generating loader script...") Console.indent() sortedScripts = self.__sortScriptItems(items, bootCode, filterBy=self.__kernelScripts) loaderCode = self.__generateScriptLoader(sortedScripts) self.__fileManager.writeFile(os.path.join(self.__outputPath, fileName), loaderCode) Console.outdent()
def clean(self): """Clears all caches of all registered projects""" Console.info("Cleaning session...") Console.indent() for project in self.__projects: project.clean() Console.outdent()
def __processAnimations(self): """Processes jasyanimation.json files to merge animation data into asset registry""" assets = self.__assets configs = [fileId for fileId in assets if assets[fileId].isImageAnimationConfig()] if configs: Console.info("Processing %s image animation configs...", len(configs)) Console.indent() for fileId in configs: Console.debug("Processing %s...", fileId) asset = assets[fileId] base = os.path.dirname(fileId) try: config = json.loads(asset.getText()) except ValueError as err: raise UserError("Could not parse jasyanimation.json at %s: %s" % (fileId, err)) for relPath in config: imageId = "%s/%s" % (base, relPath) data = config[relPath] if not imageId in assets: raise UserError("Unknown asset %s in %s" % (imageId, fileId)) animationAsset = assets[imageId] if "rows" in data or "columns" in data: rows = Util.getKey(data, "rows", 1) columns = Util.getKey(data, "columns", 1) frames = Util.getKey(data, "frames") animationAsset.addImageAnimationData(columns, rows, frames) if frames is None: frames = rows * columns elif "layout" in data: layout = data["layout"] animationAsset.addImageAnimationData(None, None, layout=layout) frames = len(layout) else: raise UserError("Invalid image frame data for: %s" % imageId) Console.debug(" - Animation %s has %s frames", imageId, frames) Console.debug(" - Deleting animation config from assets: %s", fileId) del assets[fileId] Console.outdent()
def buildPart(self, partId, fileId): if not fileId: return Console.info("Generating style (%s)...", fileId) Console.indent() self.__profile.setWorkingPath(self.getWorkingPath()) styleItems = StyleResolver.Resolver(self.__profile).add(fileId).getSorted() self.storeCompressedStylesheet(styleItems, "%s-{{id}}.css" % partId) Console.outdent()
def __outputContent(self): """Output processed content to HTML.""" Console.info("Generating public files...") Console.indent() # self.__generatePosts() # self.__generateArchives() self.__generatePages() # self.__generateFeed() Console.outdent()
def close(self): """Closes the session and stores cache to the harddrive.""" Console.debug("Closing session...") Console.indent() for project in self.__projects: project.close() self.__projects = None Console.outdent()
def cleanup(node): """ Reprocesses JavaScript to remove dead paths """ Console.debug("Removing dead code branches...") Console.indent() result = __cleanup(node) Console.outdent() return result
def storeCompressedStylesheet(self, styles, fileName): Console.info("Generating compressed stylesheet...") Console.indent() # Resolve placeholders first fileName = self.__profile.expandFileName(fileName) relativeToMain = self.__session.getMain().toRelativeUrl(fileName) compressedCode = self.__compressStyles(styles) self.__fileManager.writeFile(os.path.join(self.__outputPath, fileName), compressedCode) Console.outdent()
def clean(self): """Clears all caches of all registered projects""" if not self.__projects: return Console.info("Cleaning session...") Console.indent() for project in self.__projects: project.clean() Console.outdent()
def executeCommand(args, failmsg=None, path=None): """ Executes the given process and outputs failmsg when errors happen. Returns the combined shell output (stdout and strerr combined). :param args: :type args: str or list :param failmsg: Message for exception when command fails :type failmsg: str :param path: Directory path where the command should be executed :type path: str :raise Exception: Raises an exception whenever the shell command fails in execution """ if type(args) == str: args = shlex.split(args) prevpath = os.getcwd() # Execute in custom directory if path: path = os.path.abspath(os.path.expanduser(path)) os.chdir(path) Console.debug("Executing command: %s", " ".join(args)) Console.indent() # Using shell on Windows to resolve binaries like "git" output = tempfile.TemporaryFile(mode="w+t") returnValue = subprocess.call(args, stdout=output, stderr=output, shell=sys.platform == "win32") output.seek(0) result = output.read().strip("\n\r") output.close() # Change back to previous path os.chdir(prevpath) if returnValue != 0: raise Exception("Error during executing shell command: %s (%s)" % (failmsg, result)) for line in result.splitlines(): Console.debug(line) Console.outdent() return result
def clear(self): """Removes all generated sprite files found in the base directory.""" Console.info("Cleaning sprite files...") Console.indent() for dirPath, dirNames, fileNames in os.walk(self.base): for fileName in fileNames: if fileName.startswith("jasysprite"): filePath = os.path.join(dirPath, fileName) Console.debug("Removing file: %s", filePath) os.remove(filePath) Console.outdent()
def __init__(self, port=8080, host="127.0.0.1", mimeTypes=None): Console.info("Initializing server...") Console.indent() # Shared configuration (global/app) self.__config = { "global": { "environment": "production", "log.screen": False, "server.socket_port": port, "server.socket_host": host, "engine.autoreload.on": False, "tools.encode.on": True, "tools.encode.encoding": "utf-8" }, "/": { "log.screen": False } } self.__port = port # Build dict of content types to override native mimetype detection combinedTypes = {} combinedTypes.update(additionalContentTypes) if mimeTypes: combinedTypes.update(mimeTypes) # Update global config cherrypy.config.update(self.__config) # Somehow this screen disabling does not work # This hack to disable all access/error logging works def empty(*param, **args): pass def inspect(*param, **args): if args["severity"] > 20: Console.error("Critical error occoured:") Console.error(param[0]) cherrypy.log.access = empty cherrypy.log.error = inspect cherrypy.log.screen = False # Basic routing self.__root = Static("/", {}, mimeTypes=combinedTypes) Console.outdent()
def packDir(self, path='', recursive=True, autorotate=False, debug=False): """Pack images inside a dir into sprite sheets""" Console.info('Packing sprites in: %s' % os.path.join(self.base, path)) Console.indent() self.files = [] self.addDir(path, recursive=recursive) Console.info('Found %d images' % len(self.files)) if len(self.files) > 0: self.generate(path, autorotate, debug) Console.outdent()
def addProject(self, project): """ Adds the given project to the list of known projects. Projects should be added in order of their priority. This adds the field configuration of each project to the session fields. Fields must not conflict between different projects (same name). :param project: Instance of Project to append to the list :type project: object """ result = Project.getProjectDependencies(project, "external", self.__updateRepositories) for project in result: Console.info("Adding %s...", Console.colorize(project.getName(), "bold")) Console.indent() # Append to session list self.__projects.append(project) # Import library methods libraryPath = os.path.join(project.getPath(), "jasylibrary.py") if os.path.exists(libraryPath): self.loadLibrary(project.getName(), libraryPath, doc="Library of project %s" % project.getName()) # Import command methods commandPath = os.path.join(project.getPath(), "jasycommand.py") if os.path.exists(commandPath): self.loadCommands(project.getName(), commandPath) # Import project defined fields which might be configured using "activateField()" fields = project.getFields() for name in fields: entry = fields[name] if name in self.__fields: raise UserError("Field '%s' was already defined!" % (name)) if "check" in entry: check = entry["check"] if check in ["Boolean", "String", "Number"] or isinstance(check, list): pass else: raise UserError("Unsupported check: '%s' for field '%s'" % (check, name)) self.__fields[name] = entry Console.outdent()
def close(self): """Closes the session and stores cache to the harddrive.""" if not self.__projects: return Console.debug("Closing session...") Console.indent() for project in self.__projects: project.close() self.__projects = None Console.outdent()
def __addContent(self, content): Console.debug("Adding manual content") Console.indent() for fileId in content: fileContent = content[fileId] if len(fileContent) == 0: raise UserError("Empty content!") # If the user defines a file extension for JS public idenfiers # (which is not required) we filter them out if fileId.endswith(".js"): raise UserError( "JavaScript files should define the exported name, not a file name: %s" % fileId) fileExtension = os.path.splitext(fileContent[0])[1] # Support for joining text content if len(fileContent) == 1: filePath = os.path.join(self.__path, fileContent[0]) else: filePath = [ os.path.join(self.__path, filePart) for filePart in fileContent ] # Structure files if fileExtension in classExtensions: construct = jasy.item.Class.ClassItem dist = self.classes elif fileExtension in translationExtensions: construct = jasy.item.Translation.TranslationItem dist = self.translations else: construct = jasy.item.Asset.AssetItem dist = self.assets # Check for duplication if fileId in dist: raise UserError("Item ID was registered before: %s" % fileId) # Create instance item = construct(self, fileId).attach(filePath) Console.debug("Registering %s %s" % (item.kind, fileId)) dist[fileId] = item Console.outdent()
def __getTree(self): """Returns the abstract syntax tree of the stylesheet.""" field = "style:tree[%s]" % self.id tree = self.project.getCache().read(field, self.mtime) if not tree: Console.info("Parsing stylesheet %s...", Console.colorize(self.id, "bold")) Console.indent() tree = Engine.getTree(self.getText(), self.id) Console.outdent() self.project.getCache().store(field, tree, self.mtime, True) return tree