def writeI18NFiles(self, globalCodes, script): # for each locale code, collect mappings transKeys = globalCodes['Translations'].keys() localeKeys = globalCodes['Locales'].keys() newParts = {} # language codes to part objects, {"C": part} newPackages= {} # language codes to private package objects, {"C": package} for localeCode in set(transKeys + localeKeys): # new: also provide a localeCode "part" with corresponding packages part = Part(localeCode) part.bit_mask = script.getPartBitMask() newParts[localeCode] = part package = Package(part.bit_mask) # this might be modified later newPackages[localeCode] = package part.packages.append(package) data = {} data[localeCode] = { 'Translations': {}, 'Locales': {} } # we want to have the locale code in the data if localeCode in transKeys: data[localeCode]['Translations'] = globalCodes['Translations'][localeCode] package.data.translations[localeCode] = globalCodes['Translations'][localeCode] if localeCode in localeKeys: data[localeCode]['Locales'] = globalCodes['Locales'][localeCode] package.data.locales[localeCode] = globalCodes['Locales'][localeCode] # write to file #dataS = json.dumpsCode(data) hash, dataS = package.packageContent() # TODO: this currently works only for pure data packages dataS = dataS.replace('\\\\\\', '\\').replace(r'\\', '\\') # undo damage done by simplejson to raw strings with escapes \\ -> \ package.compiled = dataS fPath = self._resolveFileName(script.baseScriptPath, script.variants, script.settings, localeCode) self.writePackage(dataS, fPath, script) package.file = os.path.basename(fPath) # TODO: the use of os.path.basename is a hack package.hash = hash # Finalize the new packages and parts # - add prerequisite languages to parts; e.g. ["C", "en", "en_EN"] for partId, part in newParts.items(): if newPackages["C"] not in part.packages: package = newPackages["C"] part.packages.append(package) # all need "C" package.id |= part.bit_mask # adapt package's bit string if len(partId) > 2 and partId[2] == "_": # it's a sub-language -> include main language mainlang = partId[:2] if mainlang not in newPackages: raise RuntimeError("Locale '%s' specified, but not base locale '%s'" % (partId, mainlang)) if newPackages[mainlang] not in part.packages: part.packages.append(newPackages[mainlang]) # add main language newPackages[mainlang].id |= part.bit_mask # adapt package's bit string # finally, sort packages for part in newParts.values(): part.packagesSorted # - add to script object script.parts.update([(x.name, x) for x in newParts.values()]) # TODO: update might overwrite exist. entries! script.packages.extend(newPackages.values()) return globalCodes
def generateI18NParts(self, script, globalCodes): # for each locale code, collect mappings transKeys = globalCodes['Translations'].keys() localeKeys = globalCodes['Locales'].keys() newParts = {} # language codes to part objects, {"C": part} newPackages= {} # language codes to private package objects, {"C": package} for localeCode in set(transKeys + localeKeys): # new: also provide a localeCode "part" with corresponding packages part = Part(localeCode) part.bit_mask = script.getPartBitMask() newParts[localeCode] = part package = Package(part.bit_mask) # this might be modified later newPackages[localeCode] = package part.packages.append(package) data = {} data[localeCode] = { 'Translations': {}, 'Locales': {} } # we want to have the locale code in the data if localeCode in transKeys: data[localeCode]['Translations'] = globalCodes['Translations'][localeCode] package.data.translations[localeCode] = globalCodes['Translations'][localeCode] if localeCode in localeKeys: data[localeCode]['Locales'] = globalCodes['Locales'][localeCode] package.data.locales[localeCode] = globalCodes['Locales'][localeCode] # file name and hash code hash, dataS = package.packageContent() # TODO: this currently works only for pure data packages dataS = dataS.replace('\\\\\\', '\\').replace(r'\\', '\\') # undo damage done by simplejson to raw strings with escapes \\ -> \ package.compiled = dataS package.hash = hash fPath = self._resolveFileName(script.baseScriptPath, script.variants, script.settings, localeCode) package.file = os.path.basename(fPath) if self._job.get("compile-options/paths/scripts-add-hash", False): package.file = self._fileNameWithHash(package.file, package.hash) setattr(package,"__localeflag", True) # TODO: temp. hack for writeI18NPackages() # Finalize the new packages and parts # - add prerequisite languages to parts; e.g. ["C", "en", "en_EN"] for partId, part in newParts.items(): if newPackages["C"] not in part.packages: package = newPackages["C"] part.packages.append(package) # all need "C" package.id |= part.bit_mask # adapt package's bit string if len(partId) > 2 and partId[2] == "_": # it's a sub-language -> include main language mainlang = partId[:2] if mainlang not in newPackages: raise RuntimeError("Locale '%s' specified, but not base locale '%s'" % (partId, mainlang)) if newPackages[mainlang] not in part.packages: part.packages.append(newPackages[mainlang]) # add main language newPackages[mainlang].id |= part.bit_mask # adapt package's bit string # finally, sort packages for part in newParts.values(): part.packagesSorted # - add to script object for partId in newParts: if partId in script.parts: raise RuntimeError("Name collison between code part and generated I18N part.") script.parts[partId] = newParts[partId] script.packages.extend(newPackages.values()) return script
def runCompiled(self, script, treeCompiler, version="build"): def getOutputFile(compileType): filePath = compConf.get("paths/file") if not filePath: filePath = os.path.join(compileType, "script", self.getAppName() + ".js") return filePath def getFileUri(scriptUri): appfile = os.path.basename(fileRelPath) fileUri = os.path.join(scriptUri, appfile) # make complete with file name fileUri = Path.posifyPath(fileUri) return fileUri def generateBootScript(globalCodes, script, bootPackage="", compileType="build"): def packagesOfFiles(fileUri, packages): # returns list of lists, each containing destination file name of the corresp. part # npackages = [['script/gui-0.js'], ['script/gui-1.js'],...] npackages = [] file = os.path.basename(fileUri) if self._job.get("packages/loader-with-boot", True): totalLen = len(packages) else: totalLen = len(packages) + 1 for packageId, packageFileName in enumerate(self.packagesFileNames(file, totalLen, classPackagesOnly=True)): npackages.append((packageFileName,)) packages[packageId].file = packageFileName # TODO: very unnice to fix this here return npackages # besser: fixPackagesFiles() def packagesOfFilesX(fileUri, packages): # returns list of lists, each containing destination file name of the corresp. package # npackages = [['script/gui-0.js'], ['script/gui-1.js'],...] file = os.path.basename(fileUri) loader_with_boot = self._job.get("packages/loader-with-boot", True) for packageId, package in enumerate(packages): if loader_with_boot: suffix = packageId - 1 if suffix < 0: suffix = "" else: suffix = packageId packageFileName = self._resolveFileName(file, self._variants, self._settings, suffix) package.file = packageFileName return packages # ---------------------------------------------------------------------------- self._console.info("Generating boot script...") if not self._job.get("packages/i18n-with-boot", True): globalCodes = self.writeI18NFiles(globalCodes, script) # remove I18N info from globalCodes, so they don't go into the loader globalCodes["Translations"] = {} globalCodes["Locales"] = {} else: if compileType == "build": # also remove them here, as this info is now with the packages globalCodes["Translations"] = {} globalCodes["Locales"] = {} plugCodeFile = compConf.get("code/decode-uris-plug", False) if compileType == "build": filepackages = packagesOfFiles(fileUri, packages) bootContent = self.generateBootCode(parts, filepackages, boot, script, compConf, variants, settings, bootPackage, globalCodes, compileType, plugCodeFile, format) else: filepackages = [x.classes for x in packages] bootContent = self.generateBootCode(parts, filepackages, boot, script, compConf, variants={}, settings={}, bootCode=None, globalCodes=globalCodes, version=compileType, decodeUrisFile=plugCodeFile, format=format) return bootContent def getPackageData(package): data = {} data["resources"] = package.data.resources data["translations"] = package.data.translations data["locales"] = package.data.locales data = json.dumpsCode(data) data += ';\n' return data def compilePackage(packageIndex, package): self._console.info("Compiling package #%s:" % packageIndex, False) self._console.indent() # Compile file content pkgCode = self._treeCompiler.compileClasses(package.classes, variants, optimize, format) pkgData = getPackageData(package) hash = sha.getHash(pkgData + pkgCode)[:12] # first 12 chars should be enough isBootPackage = packageIndex == 0 if isBootPackage: compiledContent = ("qx.$$packageData['%s']=" % hash) + pkgData + pkgCode else: compiledContent = u'''qx.$$packageData['%s']=%s\n''' % (hash, pkgData) compiledContent += u'''qx.Part.$$notifyLoad("%s", function() {\n%s\n});''' % (hash, pkgCode) # package.hash = hash # to fill qx.$$loader.packageHashes in generateBootScript() self._console.debug("Done: %s" % self._computeContentSize(compiledContent)) self._console.outdent() return compiledContent # -- Main -------------------------------------------------------------- # Early return compileType = self._job.get("compile/type", "") if compileType not in ("build", "source"): return packages = script.packagesSortedSimple() parts = script.parts boot = script.boot variants = script.variants self._classList = script.classes self._treeCompiler = treeCompiler self._variants = variants self._console.info("Generate %s version..." % compileType) self._console.indent() # - Evaluate job config --------------------- # Compile config compConf = self._job.get("compile-options") compConf = ExtMap(compConf) # Whether the code should be formatted format = compConf.get("code/format", False) script.scriptCompress = compConf.get("paths/gzip", False) # Read in settings settings = self.getSettings() script.settings = settings # Read libraries libs = self._job.get("library", []) # Get translation maps locales = compConf.get("code/locales", []) translationMaps = self.getTranslationMaps(packages, variants, locales) # Read in base file name fileRelPath = getOutputFile(compileType) filePath = self._config.absPath(fileRelPath) script.baseScriptPath = filePath if compileType == "build": # read in uri prefixes scriptUri = compConf.get('uris/script', 'script') scriptUri = Path.posifyPath(scriptUri) fileUri = getFileUri(scriptUri) # for resource list resourceUri = compConf.get('uris/resource', 'resource') resourceUri = Path.posifyPath(resourceUri) else: # source version needs place where the app HTML ("index.html") lives self.approot = self._config.absPath(compConf.get("paths/app-root", "")) resourceUri = None scriptUri = None # Get global script data (like qxlibraries, qxresources,...) globalCodes = self.generateGlobalCodes(script, libs, translationMaps, settings, variants, format, resourceUri, scriptUri) if compileType == "build": # - Specific job config --------------------- # read in compiler options optimize = compConf.get("code/optimize", []) self._treeCompiler.setOptimize(optimize) # - Generating packages --------------------- self._console.info("Generating packages...") self._console.indent() bootPackage = "" for packageIndex, package in enumerate(packages): package.compiled = compilePackage(packageIndex, package) self._console.outdent() if not len(packages): raise RuntimeError("No valid boot package generated.") # - Put loader and packages together ------- loader_with_boot = self._job.get("packages/loader-with-boot", True) # handle loader and boot package if loader_with_boot: bootCode = generateBootScript(globalCodes, script, packages[0].compiled) packages[0].compiled = bootCode else: loaderCode = generateBootScript(globalCodes, script) loadPackage = Package(0) # make a dummy Package for the loader loadPackage.compiled = loaderCode packages.insert(0, loadPackage) # attach file names for package, fileName in zip(packages, self.packagesFileNames(script.baseScriptPath, len(packages))): package.file = fileName # write packages self.writePackages(packages, script) # ---- 'source' version ------------------------------------------------ else: sourceContent = generateBootScript(globalCodes, script, bootPackage="", compileType=compileType) # Construct file name resolvedFilePath = self._resolveFileName(filePath, variants, settings) # Save result file filetool.save(resolvedFilePath, sourceContent) if compConf.get("paths/gzip"): filetool.gzip(resolvedFilePath, sourceContent) self._console.outdent() self._console.debug("Done: %s" % self._computeContentSize(sourceContent)) self._console.outdent() self._console.outdent() return # runCompiled()