Beispiel #1
0
    def isRebuildNeeded(self, locale, moduleName, modulePath):
        if self.rebuildNeeded:
            return True

        for featureName in self.features:
            try:
                if self.features[featureName].isRebuildNeeded(
                        locale, moduleName, modulePath):
                    return True
            except Exception, exception:
                raise BuildError("Exception in feature %s" % featureName,
                                 exception)
Beispiel #2
0
            def do_GET(self):
                try:
                    search = ""
                    path = self.path
                    qi = path.find("?")
                    if qi > -1:
                        search = path[qi:]
                        path = path[0:qi]

                    if path == "/":
                        self.path = "/cgi-bin/index.py" + search
                        builder.loadProjectManifest()
                        shutil.copy(builder.config.projectManifest,
                                    builder.buildDir)
                        builder.build()

                    if path.startswith("/") and path.endswith(".js"):
                        moduleName = path[1:-3]
                        if moduleName == "boot":
                            builder.loadProjectManifest()
                            shutil.copy(builder.config.projectManifest,
                                        builder.buildDir)
                            builder.build()
                        localeFiles = builder.currentBuild.files[
                            builder.projectManifest["defaultLocale"]]
                        if moduleName in localeFiles:
                            module = localeFiles[moduleName]
                            for fileName in module["__output__"]:
                                if fileName.endswith(".js"):
                                    with open(
                                            builder.buildDir + "/" + fileName,
                                            "r") as f:
                                        self.wfile.write(f.read())
                                        return
                            raise BuildError(
                                "Module %s did not generate a JavaScript output file"
                                % moduleName)

                    if builder.config.simulateHighLatency:
                        time.sleep(0.2 + 2 * random.random())
                    CGIHTTPServer.CGIHTTPRequestHandler.do_GET(self)
                except BuildError, error:
                    error.printMessage()

                    self.wfile.write("<html>")
                    self.wfile.write("<body>")
                    self.wfile.write("<h1>Build Error</h1>")
                    self.wfile.write("<pre>%s</pre>" % str(error))
                    self.wfile.write(
                        "<p>(check console output for more info)</p>")
                    self.wfile.write("</body>")
                    self.wfile.write("</html>")
Beispiel #3
0
    def modulesWritten(self):
        self.buildFullBootModule()

        for locale in self.projectBuilder.locales:
            resources = {}
            bootScripts = []
            for module in self.projectBuilder.modules:
                moduleName = module["name"]
                if moduleName == "inline":
                    continue

                module = self.currentBuild.files[locale][moduleName]

                jsFileName = None
                for fileName in module["__output__"]:
                    if fileName.endswith(".js"):
                        jsFileName = fileName
                if not jsFileName:
                    raise BuildError("Module %s did not generate a JavaScript output file" % moduleName)

                resources[moduleName] = {}
                resources[moduleName][locale] = jsFileName
                resources[moduleName]["dependencies"] = module["__manifest__"]["dependencies"]
                if moduleName == "boot":
                    bootScripts.append("[static_base]/" + jsFileName)
                if "essential" in module["__manifest__"] and module["__manifest__"]["essential"]:
                    resources[moduleName]["essential"] = True

            bootJson = {
                "bootscripts": bootScripts,
                "resources": resources,
                "locale": locale,
                "baseurl": "[static_base]/",
                "config": "[config]"
            }

            if "tiles" in self.projectBuilder.features:
                bootJson["tileModuleDependencies"] = self.projectBuilder.features["tiles"].tileModuleDependencies

            bootJson = json.dumps(bootJson)

            fileName = buildutil.getDestinationFileName("boot", None, bootJson, locale, "json")
            with codecs.open(self.buildDir + "/" + fileName, "w", "utf-8") as f:
                f.write(bootJson)

            bootHash = buildutil.getContentHash(bootJson)
            self.writeVersionFile("__versionjson__", locale, bootHash)

        self.reinstateBootModule()
Beispiel #4
0
    def loadSources(self, locale, moduleName, modulePath):
        module = self.currentBuild.files[locale][moduleName]

        try:
            self.rebuildNeeded = False

            for source in module["__manifest__"]["sources"]:
                path = self.resolveFile(source["path"], modulePath + "/js")
                contents = self.modifiedFiles.read(locale, path)
                if contents:
                    module[path] = contents
                    self.rebuildNeeded = True
        except Exception, exception:
            raise BuildError(
                "Could not load sources for module %s" % moduleName, exception)
Beispiel #5
0
    def applyTranslations(self, allTranslations, locale, moduleName, content,
                          escaping):
        for match in re.finditer(r"\[\[([a-zA-Z0-9_]+)\]\]", content):
            key = match.group(1)
            if not key in allTranslations:
                raise BuildError("Undefined text key %s in module %s" %
                                 (key, moduleName))

            translations = allTranslations[key]
            if not locale in translations:
                raise BuildError(
                    "Translation not provided for text key %s and locale %s" %
                    (key, locale))
            value = translations[locale]
            if escaping == "html":
                value = buildutil.htmlEscape(value)
            elif escaping == "javascript":
                value = json.dumps(value)
                if len(value) > 1:
                    value = value[1:-1]  # strip of the quotes on both sides
            else:
                raise BuildError("Unrecognized escaping type %s" % escaping)
            content = content.replace("[[%s]]" % key, value)
        return content
Beispiel #6
0
    def writeFiles(self, locale, moduleName, modulePath):
        print "    Writing output file..."

        module = self.currentBuild.files[locale][moduleName]

        try:
            contents = module["__concat__"]
            filename = buildutil.getDestinationFileName(
                moduleName, None, contents, locale, "js")
            with codecs.open(self.buildDir + "/" + filename, "w",
                             "utf-8") as f:
                f.write(contents)
            module["__output__"].append(filename)
        except Exception, exception:
            raise BuildError(
                "Could not write output file for module %s" % moduleName,
                exception)
Beispiel #7
0
    def concatenateSources(self, locale, moduleName, modulePath):
        module = self.currentBuild.files[locale][moduleName]

        try:
            print "    Concatenating sources..."

            concat = ""
            for source in module["__manifest__"]["sources"]:
                path = self.resolveFile(source["path"], modulePath + "/js")
                content = module[path].strip()
                if len(content) > 0:
                    content += ("\n" if content[-1] == ";" else ";\n")
                concat += content
            module["__concat__"] = concat
        except Exception, exception:
            raise BuildError(
                "Could not concatenate sources for module %s" % moduleName,
                exception)
Beispiel #8
0
    def sourcesLoaded(self, locale, moduleName, modulePath):
        self.rebuildNeeded = False

        module = self.currentBuild.files[locale][moduleName]

        if not "styles" in module["__manifest__"]:
            return

        try:
            for style in module["__manifest__"]["styles"]:
                path = self.projectBuilder.resolveFile(style["path"],
                                                       modulePath + "/css")
                contents = self.projectBuilder.modifiedFiles.read(locale, path)
                if contents:
                    module[path] = contents
                    self.rebuildNeeded = True
        except Exception, exception:
            raise BuildError(
                "Could not load styles for module %s" % moduleName, exception)
Beispiel #9
0
class Feature(ShermanFeature):
    @ShermanFeature.priority(10)
    def manifestLoaded(self, moduleName, modulePath, manifest):
        try:
            paths = []
            for source in manifest["sources"]:
                if not "runJsLint" in source or source["runJsLint"] == True:
                    path = self.projectBuilder.resolveFile(
                        source["path"], modulePath + "/js")
                    paths.append(path)

            errors = []
            if JSLINT_MP:
                pool = multiprocessing.Pool(JSLINT_MP_PROCESSES)
                results = [
                    pool.apply_async(JSLint(), (
                        self.shermanDir,
                        path,
                    )) for path in paths
                ]
                for result in results:
                    r = result.get()
                    if not r[0]:
                        errors.append(r[1])
            else:
                for path in paths:
                    jsLint = JSLint()
                    if not jsLint(self.shermanDir, path):
                        errors.append(path)

            for error in errors:
                print "  jslint error in file %s" % error
        except Exception, exception:
            raise BuildError("Could not run jslint for module %s" % moduleName,
                             exception)
        if len(errors) > 0:
            shutil.move(self.shermanDir + "/report.html",
                        self.projectDir + "/report.html")
            raise BuildError(
                "jslint errors detected, see report.html for details.")
Beispiel #10
0
    def buildModule(self, moduleName):
        defaultLocale = self.projectManifest["defaultLocale"]

        if self.currentBuild.files[defaultLocale][moduleName]["__built__"]:
            return  # module already built

        self.currentBuild.files[defaultLocale][moduleName]["__built__"] = True

        if os.path.exists(self.projectDir + "/modules/" + moduleName):
            modulePath = self.projectDir + "/modules/" + moduleName
        elif os.path.exists(self.shermanDir + "/modules/" + moduleName):
            modulePath = self.shermanDir + "/modules/" + moduleName
        else:
            raise BuildError("Could not find module %s" % moduleName)

        self.loadModuleManifest(moduleName, modulePath)

        # make sure dependencies are built before the module itself
        for prerequisite in self.currentBuild.files[defaultLocale][moduleName][
                "__manifest__"]["dependencies"]:
            self.buildModule(prerequisite)

        print "Building module %s..." % moduleName

        defaultLocale = self.projectManifest["defaultLocale"]
        manifest = self.currentBuild.files[defaultLocale][moduleName][
            "__manifest__"]
        self.invokeFeatures("manifestLoaded", moduleName, modulePath, manifest)

        for locale in self.locales:
            print "  Processing locale %s..." % locale

            self.loadSources(locale, moduleName, modulePath)

            if self.isRebuildNeeded(locale, moduleName, modulePath):
                self.removeOldFiles(locale, moduleName, modulePath)

                self.concatenateSources(locale, moduleName, modulePath)

                self.writeFiles(locale, moduleName, modulePath)
Beispiel #11
0
    def loadFeatures(self):
        if not "features" in self.target:
            raise BuildError(
                "No features defined in manifest file %s for target %s" %
                (self.config.projectManifest, self.config.target))

        paths = [self.projectDir + "/features", self.shermanDir + "/features"]

        for feature in self.target["features"]:
            featureName = feature["name"]

            if featureName in self.features:
                continue  # already loaded

            try:
                f = None
                (f, path, description) = imp.find_module(featureName, paths)

                sys.path.append(self.shermanDir)
                module = imp.load_module(featureName, f, path, description)
                self.features[featureName] = module.Feature(
                    shermanfeature.Options(projectDir=self.projectDir,
                                           shermanDir=self.shermanDir,
                                           buildDir=self.buildDir,
                                           projectBuilder=self,
                                           featureOptions=feature["options"]
                                           if "options" in feature else {}))

            #except ImportError, error:
            #    raise BuildError("Could not load feature %s" % featureName, error)
            #except Exception, exception:
            #    raise BuildError("Exception while loading feature %s" % featureName, exception)
            finally:
                if f:
                    f.close()

            print "Enabled feature: %s" % featureName
Beispiel #12
0
    def invokeFeatures(self, hookName, *args):
        hooks = []
        for featureName in self.features:
            feature = self.features[featureName]
            if hookName in feature.__class__.__dict__:
                function = feature.__class__.__dict__[hookName]
            else:
                for base in feature.__class__.__bases__:
                    if hookName in base.__dict__:
                        function = base.__dict__[hookName]
                        break
            hooks.append((function.priority if "priority" in function.func_dict
                          else shermanfeature.DEFAULT_PRIORITY, featureName,
                          (feature, function)))

        hooks = sorted(hooks, key=lambda hook: hook[0])

        for hook in hooks:
            (priority, featureName, (feature, function)) = hook
            try:
                function(feature, *args)
            except Exception, exception:
                raise BuildError("Exception in feature %s" % featureName,
                                 exception)
Beispiel #13
0
class ProjectBuilder(object):
    def __init__(self, config):
        self.shermanDir = os.path.abspath(os.path.dirname(__file__))
        self.projectDir = os.path.dirname(config.projectManifest)
        self.buildDir = config.buildDir or tempfile.mkdtemp(
            ".build", "sherman.")

        self.config = config

        self.projectManifest = None
        self.locales = []
        self.target = None
        self.modules = []

        self.rebuildNeeded = False

        self.features = {}

        class ModifiedFiles(object):
            def __init__(self):
                self.timestamps = {}

            def read(self, locale, path):
                path = os.path.abspath(path)
                key = locale + ":" + path
                mtime = os.stat(path).st_mtime
                if key in self.timestamps and mtime == self.timestamps[key]:
                    return False
                self.timestamps[key] = mtime
                with codecs.open(path, "r", "utf-8") as f:
                    return f.read()

        self.modifiedFiles = ModifiedFiles()

        class Build(object):
            # locale => {
            #     module => {
            #         filename => content,
            #         "__concat__" => content,
            #         "__manifest__" => object,
            #         "__output__" => [ filename, ... ]
            #     }
            # }
            files = {}

        self.currentBuild = Build()

        self.loadProjectManifest()

    def resolveFile(self, path, directory=""):
        if path[0] == "/":
            if os.path.exists(self.projectDir + path):
                return self.projectDir + path
            elif os.path.exists(self.shermanDir + path):
                return self.shermanDir + path
        else:
            if os.path.exists(directory + "/" + path):
                return directory + "/" + path
        raise BuildError("Missing resource: %s" % path)

    def loadProjectManifest(self):
        try:
            with open(self.config.projectManifest, "r") as f:
                contents = f.read()

            self.projectManifest = json.loads(contents)
        except Exception, exception:
            raise BuildError(
                "Could not load manifest file %s" %
                self.config.projectManifest, exception)

        if not "locales" in self.projectManifest or len(
                self.projectManifest["locales"]) == 0:
            raise BuildError("No locales defined in manifest file %s" %
                             self.config.projectManifest)
        if not "defaultLocale" in self.projectManifest:
            raise BuildError("No default locale defined in manifest file %s" %
                             self.config.projectManifest)
        if not self.projectManifest["defaultLocale"] in self.projectManifest[
                "locales"]:
            raise BuildError(
                "Default locale not defined among locales in manifest file %s"
                % self.config.projectManifest)

        self.locales = self.projectManifest["locales"]

        if not self.config.target in self.projectManifest["targets"]:
            raise BuildError("No target %s defined in manifest file %s" %
                             (self.config.target, self.config.projectManifest))

        self.target = self.projectManifest["targets"][self.config.target]

        if "modules" in self.target:
            self.modules = self.target["modules"]
        else:
            if not "modules" in self.projectManifest:
                raise BuildError(
                    "No modules defined in manifest file %s for target %s" %
                    (self.config.projectManifest, self.config.target))
            self.modules = self.projectManifest["modules"]

        if "options" in self.target:
            if "fileNamePattern" in self.target["options"]:
                buildutil.fileNamePattern = self.target["options"][
                    "fileNamePattern"]