def __init__(self, id, config): self.id = id self.config = config self.root = getKey(config, "root", ".") self.enableDebug = getKey(config, "debug", False) info('Static "%s" => "%s" [debug:%s]', self.id, self.root, self.enableDebug)
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, id, config, mimeTypes=None): self.id = id self.config = config self.mimeTypes = mimeTypes self.root = getKey(config, "root", ".") self.enableDebug = getKey(config, "debug", False) Console.info('Static "%s" => "%s" [debug:%s]', self.id, self.root, self.enableDebug)
def getRequires(self, prefix="external"): """ Return the project requirements as project instances """ result = [] for entry in self.__requires: repo = None revision = None if type(entry) is dict: source = entry["source"] config = getKey(entry, "config") version = getKey(entry, "version") else: source = entry config = None version = None if version: info("Processing: %s @ %s", source, version) else: info("Processing: %s", source) indent() if isGitRepositoryUrl(source): if not version: version = "master" # Auto cloning always happens relative to main project root folder (not to project requiring it) retval = cloneGit(source, version, prefix=prefix) if not retval: raise JasyError("Could not clone GIT repository %s" % source) path, revision = retval path = os.path.abspath(path) repo = "git" else: if not source.startswith(("/", "~")): path = os.path.join(self.__path, source) else: path = source # Other references to requires projects are always relative to the project requiring it path = os.path.normpath(os.path.expanduser(path)) repo = "local" project = getProjectFromPath(path, config, version, repo, revision) result.append(project) outdent() return result
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: info("Processing %s image animation configs...", len(configs)) indent() for fileId in configs: debug("Processing %s...", fileId) asset = assets[fileId] base = dirname(fileId) try: config = json.loads(asset.getText()) except ValueError as err: raise JasyError("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 JasyError("Unknown asset %s in %s" % (imageId, fileId)) animationAsset = assets[imageId] if "rows" in data or "columns" in data: rows = getKey(data, "rows", 1) columns = getKey(data, "columns", 1) frames = 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 JasyError("Invalid image frame data for: %s" % imageId) debug(" - Animation %s has %s frames", imageId, frames) debug(" - Deleting animation config from assets: %s", fileId) del assets[fileId] outdent()
def __init__(self, id, config): self.id = id self.config = config self.host = getKey(config, "host") self.auth = getKey(config, "auth") self.enableDebug = getKey(config, "debug", False) self.enableMirror = getKey(config, "mirror", False) self.enableOffline = getKey(config, "offline", False) if self.enableMirror: self.mirror = Cache.Cache(os.getcwd(), ".jasy/mirror-%s" % self.id, hashkeys=True) Console.info('Proxy "%s" => "%s" [debug:%s|mirror:%s|offline:%s]', self.id, self.host, self.enableDebug, self.enableMirror, self.enableOffline)
def get(self, name, default=None): """Returns the value of the given field or None when field is not set.""" if not "." in name: return getKey(self.__data, name, default) splits = name.split(".") current = self.__data for split in splits[:-1]: if split in current: current = current[split] else: return default return getKey(current, splits[-1], default)
def __init__(self, project, id=None): # Call Item's init method first super().__init__(project, id) self.extension = os.path.splitext(self.id.lower())[1] self.type = getKey(extensions, self.extension, "other") self.shortType = self.type[0]
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 open(self): """Opens a cache file in the given path""" try: if os.path.exists(self.__file): self.__shelve = shelve.open(self.__file, flag="w") storedVersion = getKey(self.__shelve, "jasy-version") storedHost = getKey(self.__shelve, "jasy-host") if storedVersion == version and storedHost == hostId: return info("Jasy version or host has been changed. Recreating cache...") self.__shelve.close() self.__shelve = shelve.open(self.__file, flag="n") self.__shelve["jasy-version"] = version self.__shelve["jasy-host"] = hostId except dbm.error as dbmerror: errno = None try: errno = dbmerror.errno except: pass if errno is 35: raise IOError("Cache file is locked by another process!") elif "type could not be determined" in str(dbmerror): error("Could not detect cache file format: %s" % self.__file) warn("Recreating cache database...") self.clear() elif "module is not available" in str(dbmerror): error("Unsupported cache file format: %s" % self.__file) warn("Recreating cache database...") self.clear() else: raise error
def getRequires(self, prefix="external"): """ Return the project requirements as project instances """ global projects result = [] for entry in self.__requires: if type(entry) is dict: source = entry["source"] config = getKey(entry, "config") version = getKey(entry, "version") kind = getKey(entry, "kind") else: source = entry config = None version = None kind = None revision = None if isRepository(source): kind = kind or getRepositoryType(source) path = os.path.abspath(os.path.join(prefix, getRepositoryFolder(source, version, kind))) # Only clone and update when the folder is unique in this session # This reduces git/hg/svn calls which are typically quite expensive if not path in projects: revision = updateRepository(source, version, path) if revision is None: raise JasyError("Could not update repository %s" % source) else: kind = "local" if not source.startswith(("/", "~")): path = os.path.join(self.__path, source) else: path = os.path.abspath(os.path.expanduser(source)) if path in projects: project = projects[path] else: fullversion = [] # Produce user readable version when non is defined if version is None and revision is not None: version = "master" if version is not None: if "/" in version: fullversion.append(version[version.rindex("/")+1:]) else: fullversion.append(version) if revision is not None: # Shorten typical long revisions as used by e.g. Git if type(revision) is str and len(revision) > 20: fullversion.append(revision[:10]) else: fullversion.append(revision) if fullversion: fullversion = "-".join(fullversion) else: fullversion = None project = Project(path, config, fullversion) projects[path] = project result.append(project) return result
def __init__(self, project, id=None): self.id = id self.extension = splitext(self.id.lower())[1] self.type = getKey(extensions, self.extension, "other") self.shortType = self.type[0] self.project = project
def __init__(self, path, config=None, version=None, repo=None, revision=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 JasyError("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 self.__repo = repo self.__revision = revision # Intialize item registries self.classes = {} self.assets = {} self.docs = {} self.translations = {} # Load project configuration configFilePath = os.path.join(self.__path, "jasyproject.json") isJasyProject = os.path.exists(configFilePath) if isJasyProject: try: storedConfig = json.load(open(configFilePath)) except ValueError as err: raise JasyError("Could not parse jasyproject.json at %s: %s" % (configFilePath, err)) if config: for key in storedConfig: if not key in config: config[key] = storedConfig[key] else: config = storedConfig if config is None: raise JasyError("Could not initialize project configuration in %s!" % self.__path) # Initialize cache try: self.__cache = Cache(self.__path) except IOError as err: raise JasyError("Could not initialize project. Cache file could not be initialized! %s" % err) # Read name from manifest or use the basename of the project's path self.__name = getKey(config, "name", getProjectNameFromPath(self.__path)) # Read requires self.__requires = getKey(config, "requires", {}) # Defined whenever no package is defined and classes/assets are not stored in the toplevel structure. self.__package = getKey(config, "package", self.__name if isJasyProject else None) # Read fields (for injecting data into the project and build permuations) self.__fields = getKey(config, "fields", {}) # Store config self.__config = config # This section is a must for non jasy projects if not "content" in config and not isJasyProject: raise JasyError("Missing 'content' section for compat project!")
def create(name="myproject", origin=None, skeleton=None, **argv): """Creates a new project""" header("Creating project %s" % name) if not validProjectName.match(name): raise JasyError("Invalid project name: %s" % name) # # Initial Checks # # Figuring out destination folder destinationPath = os.path.abspath(name) if os.path.exists(destinationPath): raise JasyError("Cannot create project in %s. File or folder exists!" % destinationPath) # Origin can be either: # 1) None, which means a skeleton from the current main project # 2) An repository URL # 3) A project name known inside the current session # 4) Relative or absolute folder path if origin is None: originProject = session.getMain() if originProject is None: raise JasyError("Auto discovery failed! No Jasy projects registered!") originPath = originProject.getPath() originName = originProject.getName() elif isRepository(origin): info("Using remote skeleton") tempDirectory = tempfile.TemporaryDirectory() originPath = os.path.join(tempDirectory.name, "clone") originUrl = origin originVersion = getKey(argv, "origin-version") indent() originRevision = updateRepository(originUrl, originVersion, originPath) outdent() if originRevision is None: raise JasyError("Could not clone origin repository!") debug("Cloned revision: %s" % originRevision) originProject = getProjectFromPath(originPath) originName = originProject.getName() else: originProject = session.getProjectByName(origin) if originProject is not None: originPath = originProject.getPath() originName = origin elif os.path.isdir(origin): originPath = origin originProject = getProjectFromPath(originPath) originName = originProject.getName() else: raise JasyError("Invalid value for origin: %s" % origin) # Figure out the skeleton root folder skeletonDir = os.path.join(originPath, originProject.getConfigValue("skeletonDir", "skeleton")) if not os.path.isdir(skeletonDir): raise JasyError("The project %s offers no skeletons!" % originName) # For convenience: Use first skeleton in skeleton folder if no other selection was applied if skeleton is None: skeleton = getFirstSubFolder(skeletonDir) # Finally we have the skeleton path (the root folder to copy for our app) skeletonPath = os.path.join(skeletonDir, skeleton) if not os.path.isdir(skeletonPath): raise JasyError('Skeleton %s does not exist in project "%s"' % (skeleton, originName)) # # Actual Work # # Prechecks done info( "Creating %s from %s %s...", colorize(name, "bold"), colorize(skeleton + " @", "bold"), colorize(originName, "magenta"), ) debug("Skeleton: %s", colorize(skeletonPath, "grey")) debug("Destination: %s", colorize(destinationPath, "grey")) # Copying files to destination info("Copying files...") shutil.copytree(skeletonPath, destinationPath) debug("Files were copied successfully.") # Build data for template substitution data = {} data.update(argv) data["name"] = name data["origin"] = originName data["skeleton"] = os.path.basename(skeletonPath) data["jasy"] = jasy.__version__ # Do actual replacement of placeholders massFilePatcher(destinationPath, data) debug("Files were patched successfully.") # Change to directory before continuing os.chdir(destinationPath) # Create configuration file from question configs and custom scripts info("Starting configuration...") config = Config() config.injectValues(**argv) config.readQuestions("jasycreate", optional=True) config.executeScript("jasycreate.py", optional=True) config.write("jasyscript.yaml") # Done info("Your application %s was created successfully!", colorize(name, "bold"))