| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| package org.apache.flex.compiler.internal.codegen.mxml.flexjs; |
| |
| import com.google.javascript.jscomp.SourceFile; |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.io.FilenameUtils; |
| import org.apache.commons.io.IOUtils; |
| import org.apache.commons.io.filefilter.DirectoryFileFilter; |
| import org.apache.commons.io.filefilter.FileFileFilter; |
| import org.apache.commons.io.filefilter.FileFilterUtils; |
| import org.apache.commons.io.filefilter.IOFileFilter; |
| import org.apache.flex.compiler.clients.problems.ProblemQuery; |
| import org.apache.flex.compiler.codegen.js.IJSPublisher; |
| import org.apache.flex.compiler.config.Configuration; |
| import org.apache.flex.compiler.css.ICSSPropertyValue; |
| import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; |
| import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogPublisher; |
| import org.apache.flex.compiler.internal.codegen.js.goog.JarSourceFile; |
| import org.apache.flex.compiler.internal.css.CSSArrayPropertyValue; |
| import org.apache.flex.compiler.internal.css.CSSFontFace; |
| import org.apache.flex.compiler.internal.css.CSSFunctionCallPropertyValue; |
| import org.apache.flex.compiler.internal.driver.js.flexjs.JSCSSCompilationSession; |
| import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; |
| import org.apache.flex.compiler.internal.graph.GoogDepsWriter; |
| import org.apache.flex.compiler.internal.projects.FlexJSProject; |
| import org.apache.flex.compiler.internal.targets.ITargetAttributes; |
| import org.apache.flex.compiler.utils.JSClosureCompilerWrapper; |
| import org.apache.flex.swc.ISWC; |
| import org.apache.flex.swc.ISWCFileEntry; |
| |
| import java.io.*; |
| import java.net.URL; |
| import java.net.URLDecoder; |
| import java.util.*; |
| |
| public class MXMLFlexJSPublisher extends JSGoogPublisher implements IJSPublisher |
| { |
| |
| public static final String FLEXJS_OUTPUT_DIR_NAME = "bin"; |
| public static final String FLEXJS_INTERMEDIATE_DIR_NAME = "js-debug"; |
| public static final String FLEXJS_RELEASE_DIR_NAME = "js-release"; |
| |
| private static final String FLEXJS_EXTERNS = "externs"; |
| |
| class DependencyRecord |
| { |
| String path; |
| String deps; |
| String line; |
| int lineNumber; |
| } |
| |
| class DependencyLineComparator implements Comparator<DependencyRecord> |
| { |
| @Override |
| public int compare(DependencyRecord o1, DependencyRecord o2) |
| { |
| return new Integer(o1.lineNumber).compareTo(o2.lineNumber); |
| } |
| } |
| |
| public MXMLFlexJSPublisher(FlexJSProject project, Configuration config) |
| { |
| super(project, config); |
| this.isMarmotinniRun = googConfiguration.getMarmotinni() != null; |
| this.outputPathParameter = configuration.getOutput(); |
| this.useStrictPublishing = googConfiguration.getStrictPublish(); |
| |
| this.project = project; |
| } |
| |
| private FlexJSProject project; |
| |
| private boolean isMarmotinniRun; |
| private String outputPathParameter; |
| private boolean useStrictPublishing; |
| |
| @Override |
| public File getOutputFolder() |
| { |
| // Marmotinni is our test-framework. In case of a Marmotinni build |
| // we need to output the code to a different location. |
| // FIXME: I think this is a bad idea ... we should remove this. |
| // (erikdebruin) - If there is a -marmotinni switch, we want |
| // the output redirected to the directory it specifies. |
| // - If there is an -output switch, use that path as the |
| // output parent folder. |
| if (isMarmotinniRun) |
| { |
| outputParentFolder = new File(googConfiguration.getMarmotinni()); |
| } |
| // If the output path is specified using the config-xml or the commandline. |
| else if (outputPathParameter != null) |
| { |
| // FB usually specified -output <project-path>/bin-release/app.swf |
| if (outputPathParameter.contains(".swf")) { |
| if (outputParentFolder == null) |
| outputParentFolder = new File(outputPathParameter); |
| outputParentFolder = outputParentFolder.getParentFile().getParentFile(); |
| } else { |
| outputParentFolder = new File(outputPathParameter); |
| } |
| } |
| else |
| { |
| String mainClassFolder = configuration.getTargetFileDirectory(); |
| if (mainClassFolder.endsWith("src")) |
| outputParentFolder = new File(configuration.getTargetFileDirectory()).getParentFile(); |
| else if (mainClassFolder.endsWith("src/main/flex") || mainClassFolder.endsWith("src\\main\\flex")) |
| outputParentFolder = new File(configuration.getTargetFileDirectory()).getParentFile().getParentFile().getParentFile(); |
| else |
| outputParentFolder = new File(configuration.getTargetFileDirectory()); |
| } |
| |
| outputParentFolder = new File(outputParentFolder, FLEXJS_OUTPUT_DIR_NAME); |
| |
| outputFolder = new File(outputParentFolder, File.separator + FLEXJS_INTERMEDIATE_DIR_NAME); |
| |
| // (erikdebruin) Marmotinni handles file management, so we |
| // bypass the setup. |
| if (!isMarmotinniRun && !googConfiguration.getSkipTranspile()) { |
| setupOutputFolder(); |
| } |
| |
| return outputFolder; |
| } |
| |
| @Override |
| public boolean publish(ProblemQuery problems) throws IOException |
| { |
| // The "intermediate" is the "js-debug" output. |
| final File intermediateDir = outputFolder; |
| |
| final String projectName = FilenameUtils.getBaseName(configuration.getTargetFile()); |
| final String outputFileName = projectName + "." + project.getBackend().getOutputExtension(); |
| |
| // The "release" is the "js-release" directory. |
| File releaseDir = new File(outputParentFolder, FLEXJS_RELEASE_DIR_NAME); |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Copy static resources to the intermediate (and release) directory. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| IOFileFilter pngSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".png")); |
| IOFileFilter gifSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".gif")); |
| IOFileFilter jpgSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".jpg")); |
| IOFileFilter jpegSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".jpeg")); |
| IOFileFilter svgSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".svg")); |
| IOFileFilter jsonSuffixFilter = FileFilterUtils.and(FileFileFilter.FILE, |
| FileFilterUtils.suffixFileFilter(".json")); |
| IOFileFilter assetFiles = FileFilterUtils.or(pngSuffixFilter, jpgSuffixFilter, jpegSuffixFilter, svgSuffixFilter, gifSuffixFilter, |
| jsonSuffixFilter); |
| IOFileFilter resourceFilter = FileFilterUtils.or(DirectoryFileFilter.DIRECTORY, assetFiles); |
| // The source directory is the directory containing the Main class. |
| File imageSrcDir = new File(configuration.getTargetFile()).getAbsoluteFile().getParentFile(); |
| // FIXME: All images need to be located relative to the Main class ... for Maven this is a problem. |
| FileUtils.copyDirectory(imageSrcDir, intermediateDir, resourceFilter); |
| // If we are doing a release build, we need to copy them to the release dir too. |
| if (configuration.release()) { |
| FileUtils.copyDirectory(imageSrcDir, releaseDir, resourceFilter); |
| // The copy-directory contains a lot of empty directories ... clean them up. |
| clearEmptyDirectoryTrees(releaseDir); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Copy / Dump the closure files into the intermediate directory. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| // List of source files we need to pass into the closure compiler. As we have to |
| // read the content in order to dump it to the intermediate, we can just keep it |
| // and eventually use it in case of a release build. |
| List<SourceFile> closureSourceFiles = null; |
| |
| // If the closure lib dir is explicitly set, use that directory. If it |
| // is not set, check if its content is available in the classpath. If |
| // it is found in the classpath, use that as closure lib dir. |
| if (!googConfiguration.isClosureLibSet()) |
| { |
| // Check if the "goog/deps.js" is available in the classpath. |
| File closureLibraryJar = getJarThatContainsClasspathResources("goog/deps.js"); |
| if (closureLibraryJar != null) |
| { |
| // We don't want to add all files to the classpath, so we only output the |
| // resources contained in 'closure-whitelist.properites' to the output. |
| Properties whiteList = new Properties(); |
| whiteList.load(Thread.currentThread().getContextClassLoader().getResourceAsStream( |
| "flexjs/closure-whitelist.properites")); |
| |
| // Add the closure files from classpath. |
| closureSourceFiles = getClasspathResources(closureLibraryJar, whiteList); |
| } |
| } |
| if (closureSourceFiles == null) |
| { |
| File closureLibDir = new File(googConfiguration.getClosureLib()); |
| if (!closureLibDir.exists() || !closureLibDir.isDirectory()) |
| { |
| //only throw this error if closure-lib is set because it |
| //wouldn't make sense with the default fallback path |
| if (googConfiguration.isClosureLibSet()) |
| { |
| throw new RuntimeException("Parameter 'closure-lib' doesn't point to a valid directory."); |
| } |
| } |
| else |
| { |
| closureSourceFiles = getDirectoryResources(new File(closureLibDir, "closure")); |
| } |
| } |
| if (closureSourceFiles == null || closureSourceFiles.size() == 0) |
| { |
| throw new RuntimeException( |
| "Parameter 'closure-lib' not specified and closure resources not available in classpath."); |
| } |
| // Dump a copy of the closure lib files to the intermediate directory. Without this |
| // the application will not be able to run. |
| for(SourceFile closureSourceFile : closureSourceFiles) { |
| FileUtils.write(new File(new File(intermediateDir, "library/closure"), |
| closureSourceFile.getName()), closureSourceFile.getCode()); |
| } |
| closureSourceFiles = closureFilesInOrder(intermediateDir + "/library/closure/", closureSourceFiles, "goog.events.EventTarget"); |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // FIXME: Don't quite know what this does. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| final File projectIntermediateMainFile = new File(intermediateDir, outputFileName); |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Prepare the closure compilation. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| JSClosureCompilerWrapper compilerWrapper = new JSClosureCompilerWrapper(googConfiguration.getJSCompilerOptions()); |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Add all the closure lib files to the compilation unit. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| for (SourceFile closureSourceFile : closureSourceFiles) { |
| compilerWrapper.addJSSourceFile(closureSourceFile); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Add all the externs to the compilation |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| // Iterate over all swc dependencies and add all the externs they contain. |
| // (Externs are located in a "externs" directory in the root of the SWC) |
| List<ISWC> swcs = project.getLibraries(); |
| for (ISWC swc : swcs) |
| { |
| Map<String, ISWCFileEntry> files = swc.getFiles(); |
| for (String key : files.keySet()) |
| { |
| if (key.startsWith(FLEXJS_EXTERNS)) |
| { |
| ISWCFileEntry fileEntry = swc.getFile(key); |
| if (fileEntry != null) |
| { |
| InputStream is = fileEntry.createInputStream(); |
| String code = IOUtils.toString(is, "UTF-8"); |
| is.close(); |
| JarSourceFile externFile = new JarSourceFile(key, code,true); |
| System.out.println("using extern: " + key); |
| compilerWrapper.addJSExternsFile(externFile); |
| |
| // Write the extern into the filesystem. |
| // FIXME: I don't know why we need to do this. |
| //FileUtils.write(new File(intermediateDir, key), externFile.getCode()); |
| } |
| } |
| } |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Add all files generated by the compiler to the compilation unit. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| GoogDepsWriter gdw = new GoogDepsWriter(intermediateDir, projectName, googConfiguration, swcs); |
| // This list contains all files generated by the compiler, this is both the |
| // compiled js files created by the sources of the current project plus the |
| // js files of used dependencies. |
| ArrayList<String> fileList = gdw.getListOfFiles(project, problems); |
| for (String file : fileList) { |
| compilerWrapper.addJSSourceFile(file); |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Generate the index.html for loading the application. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| // The application needs to import all dependencies the application needs, this |
| // is generated here so it can be used for outputting the html templates. |
| String depsFileData = gdw.generateDeps(project, problems); |
| |
| File template = ((JSGoogConfiguration)configuration).getHtmlTemplate(); |
| // Create the index.html for the debug-js version. |
| if (!((JSGoogConfiguration)configuration).getSkipTranspile()) { |
| if (template != null) { |
| writeTemplate(template, "intermediate", projectName, intermediateDir, depsFileData, gdw.additionalHTML); |
| } else { |
| writeHTML("intermediate", projectName, intermediateDir, depsFileData, gdw.additionalHTML); |
| } |
| } |
| // Create the index.html for the release-js version. |
| if (configuration.release()) { |
| if (template != null) { |
| writeTemplate(template, "release", projectName, releaseDir, depsFileData, gdw.additionalHTML); |
| } else { |
| writeHTML("release", projectName, releaseDir, null, gdw.additionalHTML); |
| } |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Generate or copy the main CSS resources. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| project.needCSS = gdw.needCSS; |
| if (project.needCSS || googConfiguration.getSkipTranspile()) { |
| if (!googConfiguration.getSkipTranspile()) { |
| writeCSS(projectName, intermediateDir); |
| } |
| if (project.needCSS && configuration.release()) { |
| FileUtils.copyFile(new File(intermediateDir, projectName + ".css"), |
| new File(releaseDir, projectName + ".css")); |
| } |
| } |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // If we are doing a release build, let the closure compiler do it's job. |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| if (configuration.release()) { |
| final File projectReleaseMainFile = new File(releaseDir, outputFileName); |
| compilerWrapper.setOptions(projectReleaseMainFile.getCanonicalPath(), useStrictPublishing, !googConfiguration.getRemoveCirculars(), projectName); |
| compilerWrapper.targetFilePath = projectReleaseMainFile.getCanonicalPath(); |
| |
| compilerWrapper.compile(); |
| |
| appendSourceMapLocation(projectReleaseMainFile, projectName); |
| } |
| |
| // if (ok) |
| System.out.println("The project '" + projectName + "' has been successfully compiled and optimized."); |
| |
| return true; |
| } |
| |
| protected List<SourceFile> closureFilesInOrder(String path, List<SourceFile> files, String entryPoint) |
| { |
| ArrayList<String> sortedFiles = new ArrayList<String>(); |
| HashMap<String, SourceFile> fileMap = new HashMap<String, SourceFile>(); |
| SourceFile depsFile = null; |
| |
| for (SourceFile sourceFile : files) |
| { |
| if ((sourceFile.getOriginalPath().endsWith("goog/deps.js") || sourceFile.getOriginalPath().endsWith("goog\\deps.js")) && |
| !(sourceFile.getOriginalPath().endsWith("third_party/goog/deps.js") || sourceFile.getOriginalPath().endsWith("third_party\\goog\\deps.js"))) |
| depsFile = sourceFile; |
| System.out.println("originalPath: " + sourceFile.getOriginalPath()); |
| fileMap.put(sourceFile.getOriginalPath(), sourceFile); |
| } |
| |
| ArrayList<String> deps = new ArrayList<String>(); |
| try |
| { |
| BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(path + depsFile.getOriginalPath()), "UTF8")); |
| |
| while (true) |
| { |
| String line = in.readLine(); |
| if (line.startsWith("//") || line.trim().length() == 0) |
| continue; |
| deps.add(line); |
| } |
| } |
| catch (Exception e) |
| { |
| // nothing to see, move along... |
| } |
| |
| sortClosureFile(deps, entryPoint, sortedFiles); |
| |
| ArrayList<SourceFile> list = new ArrayList<SourceFile>(); |
| ArrayList<String> seen = new ArrayList<String>(); |
| sortedFiles.add("deps.js"); |
| sortedFiles.add("base.js"); |
| // in dual branch, add this to node publisher |
| sortedFiles.add("bootstrap/nodejs.js"); |
| int n = sortedFiles.size(); |
| for (int i = n - 1; i >= 0; i--) |
| { |
| String fileName = sortedFiles.get(i); |
| System.out.println("sorted filename: " + fileName); |
| if (seen.contains(fileName)) |
| continue; |
| seen.add(fileName); |
| |
| list.add(fileMap.get("goog/" + fileName)); |
| } |
| return list; |
| } |
| |
| private void sortClosureFile(List<String> deps, String entryPoint, List<String> sortedFiles) |
| { |
| String provided = getProvidedFile(deps, entryPoint); |
| sortedFiles.add(provided); |
| List<String> reqs = getRequires(deps, entryPoint); |
| if (reqs == null) return; |
| for (String req : reqs) |
| { |
| sortClosureFile(deps, req, sortedFiles); |
| } |
| } |
| |
| private String getProvidedFile(List<String> deps, String name) |
| { |
| for (String dep : deps) |
| { |
| int open = dep.indexOf("["); |
| int close = dep.indexOf("]"); |
| String list = dep.substring(open + 1, close); |
| String[] parts = list.split(","); |
| ArrayList<String> provideds = new ArrayList<String>(); |
| for (String part : parts) |
| { |
| part = part.trim(); |
| if (part.startsWith("'")) |
| part = part.substring(1, part.length() - 1); |
| provideds.add(part); |
| } |
| if (provideds.contains(name)) |
| { |
| open = dep.indexOf("'"); |
| close = dep.indexOf("'", open + 1); |
| return dep.substring(open + 1, close); |
| } |
| } |
| return null; |
| } |
| |
| private List<String> getRequires(List<String> deps, String name) |
| { |
| for (String dep : deps) |
| { |
| int open = dep.indexOf("["); |
| int close = dep.indexOf("]"); |
| String list = dep.substring(open + 1, close); |
| String[] parts = list.split(","); |
| ArrayList<String> provideds = new ArrayList<String>(); |
| for (String part : parts) |
| { |
| part = part.trim(); |
| if (part.startsWith("'")) |
| part = part.substring(1, part.length() - 1); |
| provideds.add(part); |
| } |
| if (provideds.contains(name)) |
| { |
| open = dep.indexOf("[", close + 1); |
| close = dep.indexOf("]", open + 1); |
| if (open + 1 == close) |
| return null; |
| String list2 = dep.substring(open + 1, close); |
| String[] parts2 = list2.split(","); |
| ArrayList<String> reqs = new ArrayList<String>(); |
| for (String part : parts2) |
| { |
| part = part.trim(); |
| if (part.startsWith("'")) |
| part = part.substring(1, part.length() - 1); |
| reqs.add(part); |
| } |
| return reqs; |
| } |
| } |
| return null; |
| } |
| |
| protected String readCode(File file) |
| { |
| String code = ""; |
| try |
| { |
| BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8")); |
| |
| String line = in.readLine(); |
| |
| while (line != null) |
| { |
| code += line + "\n"; |
| line = in.readLine(); |
| } |
| code = code.substring(0, code.length() - 1); |
| |
| in.close(); |
| } |
| catch (Exception e) |
| { |
| // nothing to see, move along... |
| } |
| |
| return code; |
| } |
| |
| protected void writeTemplate(File template, String type, String projectName, File targetDir, String deps, List<String> additionalHTML) |
| throws IOException |
| { |
| // Check if the template exists. |
| if(!template.exists()) { |
| throw new IOException("Template specified by 'html-template' does not exist: " + template.getPath()); |
| } |
| |
| String input = readCode(template); |
| ITargetAttributes ta = project.computeTargetAttributes(); |
| Float width = null; |
| Float height = null; |
| String bgcolor = null; |
| String pageTitle = null; |
| if(ta != null) |
| { |
| width = ta.getWidth(); |
| height = ta.getHeight(); |
| bgcolor = ta.getBackgroundColor(); |
| pageTitle = ta.getPageTitle(); |
| } |
| String result = input.replaceAll("\\$\\{application\\}", projectName); |
| if (bgcolor != null) |
| result = result.replaceAll("\\$\\{bgcolor\\}", bgcolor); |
| //result = result.replaceAll("\\$\\{expressInstallSwf\\}", expressInstallSwf); |
| if (height != null) |
| result = result.replaceAll("\\$\\{height\\}", height.toString()); |
| if (pageTitle != null) |
| result = result.replaceAll("\\$\\{title\\}", pageTitle); |
| //result = result.replaceAll("\\$\\{version_major\\}", versionMajor); |
| //result = result.replaceAll("\\$\\{version_minor\\}", versionMinor); |
| //result = result.replaceAll("\\$\\{version_revision\\}", versionRevision); |
| if (width != null) |
| result = result.replaceAll("\\$\\{width\\}", width.toString()); |
| //result = result.replaceAll("\\$\\{useBrowserHistory\\}", useBrowserHistory); |
| |
| StringBuilder addHTML = new StringBuilder(); |
| addHTML.append(getTemplateAdditionalHTML(additionalHTML)); |
| addHTML.append(getTemplateDependencies(type, projectName, deps)); |
| result = result.replaceAll("\\$\\{head\\}", addHTML.toString()); |
| |
| String templateBody = getTemplateBody(projectName); |
| result = result.replaceAll("\\$\\{body\\}", templateBody); |
| |
| writeFile(new File(targetDir, googConfiguration.getHtmlOutputFileName()), result, false); |
| } |
| |
| protected String getTemplateAdditionalHTML(List<String> additionalHTML) |
| { |
| StringBuilder htmlFile = new StringBuilder(); |
| for (String s : additionalHTML) |
| { |
| htmlFile.append(s).append("\n"); |
| } |
| return htmlFile.toString(); |
| } |
| |
| protected String getTemplateDependencies(String type, String projectName, String deps) |
| { |
| StringBuilder depsHTML = new StringBuilder(); |
| if ("intermediate".equals(type)) |
| { |
| depsHTML.append("\t<script type=\"text/javascript\" src=\"./library/closure/goog/base.js\"></script>\n"); |
| depsHTML.append("\t<script type=\"text/javascript\">\n"); |
| depsHTML.append(deps); |
| depsHTML.append("\t\tgoog.require(\""); |
| depsHTML.append(projectName); |
| depsHTML.append("\");\n"); |
| depsHTML.append("\t</script>\n"); |
| } |
| else |
| { |
| depsHTML.append("\t<script type=\"text/javascript\" src=\"./"); |
| depsHTML.append(projectName); |
| depsHTML.append(".js\"></script>\n"); |
| } |
| return depsHTML.toString(); |
| } |
| |
| protected String getTemplateBody(String projectName) |
| { |
| StringBuilder bodyHTML = new StringBuilder(); |
| bodyHTML.append("\t<script type=\"text/javascript\">\n"); |
| bodyHTML.append("\t\tnew "); |
| bodyHTML.append(projectName); |
| bodyHTML.append("()"); |
| bodyHTML.append(".start();\n"); |
| bodyHTML.append("\t</script>\n"); |
| return bodyHTML.toString(); |
| } |
| |
| protected void writeHTML(String type, String projectName, File targetDir, String deps, List<String> additionalHTML) |
| throws IOException |
| { |
| StringBuilder htmlFile = new StringBuilder(); |
| htmlFile.append("<!DOCTYPE html>\n"); |
| htmlFile.append("<html>\n"); |
| htmlFile.append("<head>\n"); |
| htmlFile.append("\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n"); |
| htmlFile.append("\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"); |
| htmlFile.append("\t<link rel=\"stylesheet\" type=\"text/css\" href=\"").append(projectName).append(".css\">\n"); |
| |
| htmlFile.append(getTemplateAdditionalHTML(additionalHTML)); |
| htmlFile.append(getTemplateDependencies(type, projectName, deps)); |
| |
| htmlFile.append("</head>\n"); |
| htmlFile.append("<body>\n"); |
| |
| htmlFile.append(getTemplateBody(projectName)); |
| |
| htmlFile.append("</body>\n"); |
| htmlFile.append("</html>"); |
| |
| writeFile(new File(targetDir, googConfiguration.getHtmlOutputFileName()), htmlFile.toString(), false); |
| } |
| |
| private void writeCSS(String projectName, File targetDir) throws IOException |
| { |
| JSCSSCompilationSession cssSession = (JSCSSCompilationSession) project.getCSSCompilationSession(); |
| writeFile(new File(targetDir, projectName + ".css"), cssSession.emitCSS(), false); |
| for (CSSFontFace fontFace : cssSession.fontFaces) |
| { |
| // check frameworks/fonts folder |
| String configdir = configuration.getLoadConfig(); |
| File dir = new File(configdir); |
| dir = dir.getParentFile(); |
| for (ICSSPropertyValue prop : fontFace.getSources()) |
| { |
| if (prop instanceof CSSArrayPropertyValue) |
| { |
| for (ICSSPropertyValue value : ((CSSArrayPropertyValue)prop).getElements()) |
| { |
| copyFontFile((CSSFunctionCallPropertyValue) value, dir, targetDir); |
| } |
| } |
| else |
| { |
| if (prop instanceof CSSFunctionCallPropertyValue) |
| { |
| copyFontFile((CSSFunctionCallPropertyValue) prop, dir, targetDir); |
| } |
| } |
| } |
| } |
| } |
| |
| protected void copyFontFile(CSSFunctionCallPropertyValue fn, File sourceDir, File targetDir) throws IOException { |
| String fontPath = fn.rawArguments; |
| if (fontPath.startsWith("'")) { |
| fontPath = fontPath.substring(1, fontPath.length() - 1); |
| } |
| if (fontPath.startsWith("\"")) { |
| fontPath = fontPath.substring(1, fontPath.length() - 1); |
| } |
| int c = fontPath.indexOf("?"); |
| if (c != -1) { |
| fontPath = fontPath.substring(0, c); |
| } |
| File fontFile = new File(sourceDir, fontPath); |
| File destFile = new File(targetDir, fontPath); |
| if (fontFile.exists()) |
| { |
| if (!destFile.exists()) { |
| FileUtils.copyFile(fontFile, destFile); |
| } |
| } |
| } |
| |
| protected File getJarThatContainsClasspathResources(String resourcePath) { |
| URL resource = Thread.currentThread().getContextClassLoader().getResource(resourcePath); |
| if (resource != null) { |
| // Strip the url of the parts we don't need. |
| // Unless we are not using some insanely complex setup |
| // the resource will always be on the same machine. |
| String resourceJarPath = resource.getFile(); |
| try { |
| resourceJarPath = URLDecoder.decode(resourceJarPath, "UTF-8"); |
| if (resourceJarPath.contains(":")) { |
| resourceJarPath = resourceJarPath.substring(resourceJarPath.indexOf(":") + 1); |
| } |
| if (resourceJarPath.contains("!")) { |
| resourceJarPath = resourceJarPath.substring(0, resourceJarPath.indexOf("!")); |
| } |
| return new File(resourceJarPath); |
| } catch (UnsupportedEncodingException e) { |
| e.printStackTrace(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * In case of release builds, we also need the 'js-release' directory created. |
| */ |
| @Override |
| protected void setupOutputFolder() { |
| super.setupOutputFolder(); |
| |
| // Only create a release directory for release builds. |
| if (configuration.release()) { |
| File releaseDir = new File(outputParentFolder, FLEXJS_RELEASE_DIR_NAME); |
| if (!releaseDir.exists() && !releaseDir.mkdirs()) { |
| throw new RuntimeException("Unable to create release directory at " + releaseDir.getAbsolutePath()); |
| } |
| } |
| } |
| |
| protected void clearEmptyDirectoryTrees(File baseDirectory) { |
| File[] files = baseDirectory.listFiles(); |
| if(files != null) { |
| for (File file : files) { |
| if (file.isDirectory()) { |
| clearEmptyDirectoryTrees(file); |
| if (isEmptyDirectory(file)) { |
| file.delete(); |
| } |
| } |
| } |
| } |
| } |
| |
| protected boolean isEmptyDirectory(File directory) { |
| File[] files = directory.listFiles(); |
| if(files != null) { |
| for (File file : files) { |
| if (file.isFile()) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| } |