def executeScript(self, fileName, autoDelete=True, optional=False, encoding="utf-8"): """ Executes the given script for configuration proposes and deletes the file afterwards (by default). Returns True when the file was found and processed. """ if not os.path.exists(fileName): if optional: return False else: raise UserError("Could not find configuration script: %s" % fileName) env = { "config" : self, "file" : File } code = open(fileName, "r", encoding=encoding).read() exec(compile(code, os.path.abspath(fileName), "exec"), globals(), env) if autoDelete: File.rm(fileName) return True
def executeScript(self, fileName, autoDelete=True, optional=False, encoding="utf-8"): """ Executes the given script for configuration proposes and deletes the file afterwards (by default). Returns True when the file was found and processed. """ if not os.path.exists(fileName): if optional: return False else: raise UserError("Could not find configuration script: %s" % fileName) env = {"config": self, "file": File} code = open(fileName, "r", encoding=encoding).read() exec(compile(code, os.path.abspath(fileName), "exec"), globals(), env) if autoDelete: File.rm(fileName) return True
def readQuestions(self, fileName, force=False, autoDelete=True, optional=False, encoding="utf-8"): """ Reads the given configuration file with questions and deletes the file afterwards (by default). Returns True when the file was found and processed. """ configFile = findConfig(fileName) if configFile is None: if optional: return False else: raise UserError("Could not find configuration file (questions): %s" % configFile) data = loadConfig(configFile, encoding=encoding) for entry in data: question = entry["question"] name = entry["name"] accept = getKey(entry, "accept", None) required = getKey(entry, "required", True) default = getKey(entry, "default", None) force = getKey(entry, "force", False) self.ask(question, name, accept=accept, required=required, default=default, force=force) if autoDelete: File.rm(configFile) return True
def __init__(self, path, config=None, version=None): """ Constructor call of the project. - First param is the path of the project relative to the current working directory. - Config can be read from jasyproject.json or using constructor parameter @config - Parent is used for structural debug messages (dependency trees) """ if not os.path.isdir(path): raise UserError("Invalid project path: %s" % path) # Only store and work with full path self.__path = os.path.abspath(os.path.expanduser(path)) # Store given params self.version = version # Intialize item registries self.classes = {} self.assets = {} self.docs = {} self.translations = {} # Load project configuration self.__config = Config.Config(config) self.__config.loadValues(os.path.join(self.__path, "jasyproject"), optional=True) # Initialize cache try: File.mkdir(os.path.join(self.__path, ".jasy")) self.__cache = jasy.core.Cache.Cache(self.__path, filename=".jasy/cache") except IOError as err: raise UserError( "Could not initialize project. Cache file in %s could not be initialized! %s" % (self.__path, err) ) # Detect version changes if version is None: self.__modified = True else: cachedVersion = self.__cache.read("project[version]") self.__modified = cachedVersion != version self.__cache.store("project[version]", version) # Read name from manifest or use the basename of the project's path self.__name = self.__config.get("name", getProjectNameFromPath(self.__path)) # Read requires self.__requires = self.__config.get("requires", {}) # Defined whenever no package is defined and classes/assets are not stored in the toplevel structure. self.__package = self.__config.get("package", self.__name if self.__config.has("name") else None) # Read fields (for injecting data into the project and build permutations) self.__fields = self.__config.get("fields", {}) # Read setup for running command pre-scan self.__setup = self.__config.get("setup")
def getPath(self): """Returns the exact position of the class file in the file system.""" # Automatically write file (from eventually processed text content) when it does not exist if self.__text is not None and not File.exists(self.__path): File.write(self.__path, self.getText()) return self.__path
def saveText(self, text, path, encoding="utf-8"): """ Saves the given text under the given path and stores both for future access This is mainly useful for "virtual" files which are not edited by the developer but which are created dynamically during runtime. """ self.__text = text self.__path = path if not File.exists(path) or File.read(path) != text: File.write(path, text) self.mtime = os.stat(path).st_mtime
def saveText(self, text, path, encoding="utf-8"): """ Saves the given text under the given path and stores both for future access. This is mainly useful for "virtual" files which are not edited by the developer but which are created dynamically during runtime. """ self.__text = text self.__path = path if not File.exists(path) or File.read(path) != text: File.write(path, text) self.mtime = os.stat(path).st_mtime
def readQuestions(self, fileName, force=False, autoDelete=True, optional=False, encoding="utf-8"): """ Reads the given configuration file with questions and deletes the file afterwards (by default). Returns True when the file was found and processed. """ configFile = findConfig(fileName) if configFile is None: if optional: return False else: raise UserError( "Could not find configuration file (questions): %s" % configFile) data = loadConfig(configFile, encoding=encoding) for entry in data: question = entry["question"] name = entry["name"] accept = getKey(entry, "accept", None) required = getKey(entry, "required", True) default = getKey(entry, "default", None) force = getKey(entry, "force", False) self.ask(question, name, accept=accept, required=required, default=default, force=force) if autoDelete: File.rm(configFile) return True
def copyAssets(self): """ Copies assets from their source folder to the configured destination folder. Does apply file name transformations during copying when requested. """ Console.info("Copying assets...") counter = 0 for assetItem in self.__copylist: srcFile = assetItem.getPath() dstFile = self.__computeDestinationPath(assetItem) if File.syncfile(srcFile, dstFile): counter += 1 Console.info("Copied %s assets.", counter)
def postProcess(self, parsed, filename, languages): for key, value in parsed.items(): if type(value) is str: parsed[key] = self.__fixJasyCommands(value) if "slug" in parsed: parsed["slug"] = Util.fixSlug(parsed["slug"]) else: parsed["slug"] = Util.fixSlug(parsed["title"]) parsed["content"] = Util.fixCoreTemplating(parsed["content"]) if not "status" in parsed: parsed["status"] = "published" if not "pos" in parsed: parsed["pos"] = 0 else: parsed["pos"] = int(parsed["pos"]) if not "lang" in parsed: parsed["lang"] = self.__defaultLanguage if parsed["lang"] not in languages: languages.append(parsed["lang"]) # Add modification time and short hash parsed["mtime"] = os.path.getmtime(filename) parsed["hash"] = File.sha1(filename)[0:8] # Create simple boolean flag for publish state check parsed["publish"] = parsed["status"] == "published" # Parse date if available if "date" in parsed: parsed["date"] = dateutil.parser.parse(parsed["date"]).replace(tzinfo=dateutil.tz.tzlocal()) return parsed
def write(self, distFolder, classFilter=None, callback="apiload", showInternals=False, showPrivates=False, printErrors=True, highlightCode=True): """ Writes API data generated from JavaScript into distFolder :param distFolder: Where to store the API data :param classFilter: Tuple of classes or method to use for filtering :param callback: Name of callback to use for loading or None if pure JSON should be used :param showInternals: Include internal methods inside API data :param showPrivates: Include private methods inside API data :param printErrors: Whether errors should be printed to the console :param highlightCode: Whether to enable code highlighting using Pygments :type distFolder: str :type classFilter: tuple or function :type callback: function :type showInternals: bool :type showPrivates: bool :type printErrors: bool :type highlightCode: bool """ # # Collecting # Console.info("Collecting API Data...") Console.indent() apiData = {} highlightedCode = {} for project in self.__session.getProjects(): classes = project.getClasses() Console.info("Loading API of project %s: %s...", Console.colorize(project.getName(), "bold"), Console.colorize("%s classes" % len(classes), "cyan")) Console.indent() for className in classes: if self.__isIncluded(className, classFilter): data = classes[className].getApi(highlightCode) if not data.isEmpty: apiData[className] = data highlightedCode[className] = classes[className].getHighlightedCode() else: Console.info("Skipping %s, class is empty." % className) Console.outdent() Console.outdent() # # Processing # Console.info("Processing API Data...") Console.indent() data, index, search = self.__process(apiData, classFilter=classFilter, internals=showInternals, privates=showPrivates, printErrors=printErrors, highlightCode=highlightCode) Console.outdent() # # Writing # Console.info("Storing API data...") Console.indent() writeCounter = 0 extension = "js" if callback else "json" compress = True class JsonEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, set): return list(obj) return json.JSONEncoder.default(self, obj) def encode(content, name): if compress: jsonContent = json.dumps(content, sort_keys=True, cls=JsonEncoder, separators=(',',':')) else: jsonContent = json.dumps(content, sort_keys=True, cls=JsonEncoder, indent=2) if callback: return "%s(%s,'%s');" % (callback, jsonContent, name) else: return jsonContent Console.info("Saving class data (%s files)...", len(data)) Console.indent() for className in data: try: classData = data[className] if type(classData) is dict: classExport = classData else: classExport = classData.export() File.write(self.__session.expandFileName(os.path.join(distFolder, "%s.%s" % (className, extension))), encode(classExport, className)) except TypeError as writeError: Console.error("Could not write API data of: %s: %s", className, writeError) continue Console.outdent() if highlightCode: Console.info("Saving highlighted code (%s files)...", len(highlightedCode)) Console.indent() for className in highlightedCode: try: File.write(self.__session.expandFileName(os.path.join(distFolder, "%s.html" % className)), highlightedCode[className]) except TypeError as writeError: Console.error("Could not write highlighted code of: %s: %s", className, writeError) continue Console.outdent() Console.info("Writing index...") Console.indent() File.write(self.__session.expandFileName(os.path.join(distFolder, "meta-index.%s" % extension)), encode(index, "meta-index")) File.write(self.__session.expandFileName(os.path.join(distFolder, "meta-search.%s" % extension)), encode(search, "meta-search")) Console.outdent() Console.outdent()
def getChecksum(self, mode="rb"): """Returns the SHA1 checksum of the item""" return File.sha1(open(self.getPath(), mode))
def write(self, distFolder, classFilter=None, callback="apiload", showInternals=False, showPrivates=False, printErrors=True, highlightCode=True): """ Writes API data generated from JavaScript into distFolder. :param distFolder: Where to store the API data :param classFilter: Tuple of classes or method to use for filtering :param callback: Name of callback to use for loading or None if pure JSON should be used :param showInternals: Include internal methods inside API data :param showPrivates: Include private methods inside API data :param printErrors: Whether errors should be printed to the console :param highlightCode: Whether to enable code highlighting using Pygments :type distFolder: str :type classFilter: tuple or function :type callback: function :type showInternals: bool :type showPrivates: bool :type printErrors: bool :type highlightCode: bool """ # # Collecting # Console.info("Collecting API Data...") Console.indent() apiData = {} highlightedCode = {} for project in self.__session.getProjects(): classes = project.getScripts() Console.info("Loading API of project %s: %s...", Console.colorize(project.getName(), "bold"), Console.colorize("%s classes" % len(classes), "cyan")) Console.indent() for className in classes: if self.__isIncluded(className, classFilter): data = classes[className].getApi(highlightCode) if not data.isEmpty: apiData[className] = data highlightedCode[className] = classes[ className].getHighlightedCode() else: Console.info("Skipping %s, class is empty." % className) Console.outdent() Console.outdent() # # Processing # Console.info("Processing API Data...") Console.indent() data, index, search = self.__process(apiData, classFilter=classFilter, internals=showInternals, privates=showPrivates, printErrors=printErrors, highlightCode=highlightCode) Console.outdent() # # Writing # Console.info("Storing API data...") Console.indent() writeCounter = 0 extension = "js" if callback else "json" compress = True class JsonEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, set): return list(obj) return json.JSONEncoder.default(self, obj) def encode(content, name): if compress: jsonContent = json.dumps(content, sort_keys=True, cls=JsonEncoder, separators=(',', ':')) else: jsonContent = json.dumps(content, sort_keys=True, cls=JsonEncoder, indent=2) if callback: return "%s(%s,'%s');" % (callback, jsonContent, name) else: return jsonContent Console.info("Saving class data (%s files)...", len(data)) Console.indent() for className in data: try: classData = data[className] if isinstance(classData, dict): classExport = classData else: classExport = classData.export() File.write( self.__profile.expandFileName( os.path.join(distFolder, "%s.%s" % (className, extension))), encode(classExport, className)) except TypeError as writeError: Console.error("Could not write API data of: %s: %s", className, writeError) continue Console.outdent() if highlightCode: Console.info("Saving highlighted code (%s files)...", len(highlightedCode)) Console.indent() for className in highlightedCode: try: File.write( self.__profile.expandFileName( os.path.join(distFolder, "%s.html" % className)), highlightedCode[className]) except TypeError as writeError: Console.error( "Could not write highlighted code of: %s: %s", className, writeError) continue Console.outdent() Console.info("Writing index...") Console.indent() File.write( self.__profile.expandFileName( os.path.join(distFolder, "meta-index.%s" % extension)), encode(index, "meta-index")) File.write( self.__profile.expandFileName( os.path.join(distFolder, "meta-search.%s" % extension)), encode(search, "meta-search")) Console.outdent() Console.outdent()
def getChecksum(self): return File.sha1(self.fp)
def getChecksum(self, mode="rb"): """Returns the SHA1 checksum of the item.""" return File.sha1(open(self.getPath(), mode))
def __init__(self, path, config=None, version=None): """ Constructor call of the project. - First param is the path of the project relative to the current working directory. - Config can be read from jasyproject.json or using constructor parameter @config - Parent is used for structural debug messages (dependency trees) """ if not os.path.isdir(path): raise UserError("Invalid project path: %s" % path) # Only store and work with full path self.__path = os.path.abspath(os.path.expanduser(path)) # Store given params self.version = version # Intialize item registries self.classes = {} self.assets = {} self.docs = {} self.translations = {} # Load project configuration self.__config = Config.Config(config) self.__config.loadValues(os.path.join(self.__path, "jasyproject"), optional=True) # Initialize cache try: File.mkdir(os.path.join(self.__path, ".jasy")) self.__cache = jasy.core.Cache.Cache(self.__path, filename=".jasy/cache") except IOError as err: raise UserError( "Could not initialize project. Cache file in %s could not be initialized! %s" % (self.__path, err)) # Detect version changes if version is None: self.__modified = True else: cachedVersion = self.__cache.read("project[version]") self.__modified = cachedVersion != version self.__cache.store("project[version]", version) # Read name from manifest or use the basename of the project's path self.__name = self.__config.get("name", getProjectNameFromPath(self.__path)) # Read requires self.__requires = self.__config.get("requires", {}) # Defined whenever no package is defined and classes/assets are not stored in the toplevel structure. self.__package = self.__config.get( "package", self.__name if self.__config.has("name") else None) # Read fields (for injecting data into the project and build permutations) self.__fields = self.__config.get("fields", {}) # Read setup for running command pre-scan self.__setup = self.__config.get("setup")