in compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyalePublisher.java [209:637]
public boolean publish(ProblemQuery problems) throws IOException
{
// The "intermediate" is the "js-debug" output.
final File intermediateDir = outputFolder;
// The source directory is the source path entry containing the Main class.
List<File> sourcePaths = project.getSourcePath();
String targetFile = configuration.getTargetFile().toLowerCase();
if (googConfiguration.isVerbose())
{
System.out.println("find project folder for " + targetFile);
}
File imageSrcDir = null;
for (File sp : sourcePaths)
{
if (googConfiguration.isVerbose())
{
System.out.println("checking source path " + sp.getAbsolutePath());
}
String lowercasePath = sp.getAbsolutePath().toLowerCase();
if (targetFile.startsWith(lowercasePath))
imageSrcDir = sp;
}
if (imageSrcDir == null)
{
imageSrcDir = new File(configuration.getTargetFile()).getAbsoluteFile().getParentFile();
if (googConfiguration.isVerbose())
{
System.out.println("not found on source path, using parent file " + imageSrcDir.getAbsolutePath());
}
}
final String projectName = FilenameUtils.getBaseName(configuration.getTargetFile());
String qName = null;
try {
qName = project.mainCU.getQualifiedNames().get(0);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String mainClassQName = qName;
DefinitionPromise cpromise = (DefinitionPromise)project.mainCU.getDefinitionPromises().get(0);
IDefinition actualDef = cpromise.getActualDefinition();
IClassDefinition baseDef = null;
if(actualDef instanceof IClassDefinition)
{
IClassDefinition cdef = (IClassDefinition) cpromise.getActualDefinition();
baseDef = (IClassDefinition) project.resolveQNameToDefinition(cdef.getBaseClassAsDisplayString());
}
if (baseDef != null)
{
String factoryClassName = null;
IClassDefinition.IClassIterator classIterator = baseDef.classIterator(project, true);
while (classIterator.hasNext())
{
baseDef = classIterator.next();
if (baseDef.hasMetaTagByName("Frame")) {
factoryClassName = getFactoryClass(baseDef.getMetaTagByName("Frame"));
break;
}
}
if (factoryClassName != null)
{
mainClassQName = generateFactoryClass(factoryClassName, projectName, mainClassQName, intermediateDir);
}
}
final String outputFileName = projectName + "." + project.getBackend().getOutputExtension();
// The "release" is the "js-release" directory.
File releaseDir = new File(outputParentFolder, ROYALE_RELEASE_DIR_NAME);
if (moduleOutput != null)
releaseDir = new File(releaseDir, File.separator + moduleOutput);
/////////////////////////////////////////////////////////////////////////////////
// Copy static resources to the intermediate (and release) directory.
/////////////////////////////////////////////////////////////////////////////////
IOFileFilter pngSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".png"));
IOFileFilter gifSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".gif"));
IOFileFilter jpgSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".jpg"));
IOFileFilter jpegSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".jpeg"));
IOFileFilter svgSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".svg"));
IOFileFilter jsonSuffixFilter = FileFilterUtils.and(FileFileFilter.INSTANCE,
FileFilterUtils.suffixFileFilter(".json"));
IOFileFilter assetFiles = FileFilterUtils.or(pngSuffixFilter, jpgSuffixFilter, jpegSuffixFilter, svgSuffixFilter, gifSuffixFilter,
jsonSuffixFilter);
IOFileFilter resourceFilter = FileFilterUtils.or(DirectoryFileFilter.DIRECTORY, assetFiles);
// FIXME: All images need to be located relative to the Main class ... for Maven this is a problem.
FileUtils.copyDirectory(imageSrcDir, intermediateDir, resourceFilter);
// Iterate over all themes SWCs and add the contents of any included files in
// an assets folder to an assets folder in the destination folder.
final ISWCManager swcManager = project.getWorkspace().getSWCManager();
List<ISWC> themeSWCs = new ArrayList<ISWC>();
List<IFileSpecification> themes = project.getThemeFiles();
for (final IFileSpecification themeFile : themes)
{
final String extension = FilenameUtils.getExtension(themeFile.getPath());
if ("swc".equalsIgnoreCase(extension))
{
final ISWC swc = swcManager.get(new File(themeFile.getPath()));
themeSWCs.add(swc);
Map<String, ISWCFileEntry> files = swc.getFiles();
for (String key : files.keySet())
{
if (key.startsWith(ROYALE_THEME_ASSETS))
{
ISWCFileEntry fileEntry = swc.getFile(key);
if (fileEntry != null)
{
InputStream is = fileEntry.createInputStream();
int n = is.available();
int total = 0;
byte[] data = new byte[n];
while (total < n)
{
total += is.read(data, total, n - total);
}
FileUtils.writeByteArrayToFile(new File(intermediateDir, key), data);
if (configuration.release())
{
FileUtils.writeByteArrayToFile(new File(releaseDir, key), data);
}
}
}
}
}
}
// 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.properties' to the output.
Properties whiteList = new Properties();
whiteList.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(
"royale/closure-whitelist.properties"));
// 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(), Charset.forName("utf8"));
}
List<String> closureEntryPoints = new ArrayList<String>();
closureEntryPoints.add("goog.events.EventTarget");
closureEntryPoints.add("goog.html.sanitizer.HtmlSanitizer");
closureSourceFiles = closureFilesInOrder(intermediateDir + "/library/closure/", closureSourceFiles, closureEntryPoints);
/////////////////////////////////////////////////////////////////////////////////
// Prepare the closure compilation.
/////////////////////////////////////////////////////////////////////////////////
JSClosureCompilerWrapper compilerWrapper = null;
if (configuration.release())
{
compilerWrapper = new JSClosureCompilerWrapper(googConfiguration.getJSCompilerOptions());
compilerWrapper.setPropertyNamesToKeep(closurePropertyNamesToKeep);
if (closureSymbolNamesToExport == null) {
closureSymbolNamesToExport = new HashSet<String>();
}
//the HTML template always needs this name to be exported, even if
//other class names are not exported
closureSymbolNamesToExport.add(mainClassQName);
compilerWrapper.setExtraSymbolNamesToExport(closureSymbolNamesToExport);
}
if (compilerWrapper != null)
{
/////////////////////////////////////////////////////////////////////////////////
// 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)
Set<ISWC> swcExterns = project.swcExterns;
List<ISWC> swcs = project.getLibraries();
List<ISWC> allswcs = new ArrayList<ISWC>();
allswcs.addAll(swcs);
allswcs.addAll(themeSWCs);
for (ISWC swc : allswcs)
{
Map<String, ISWCFileEntry> files = swc.getFiles();
for (String key : files.keySet())
{
if (key.startsWith(ROYALE_EXTERNS))
{
ISWCFileEntry fileEntry = swc.getFile(key);
if (fileEntry != null)
{
InputStream is = fileEntry.createInputStream();
String code = IOUtils.toString(is, "UTF-8");
is.close();
if (compilerWrapper != null)
{
JarSourceFile externFile = new JarSourceFile(key, code,true);
if (googConfiguration.isVerbose())
{
System.out.println("using extern: " + key);
}
compilerWrapper.addJSExternsFile(externFile);
}
if (swcExterns.contains(swc))
{
List<String> lines = IOUtils.readLines(new StringReader(code));
collectAdditionalHTML(lines, swc.getSWCFile().getAbsolutePath() + ":" + key);
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// Add all files generated by the compiler to the compilation unit.
/////////////////////////////////////////////////////////////////////////////////
GoogDepsWriter gdw = getGoogDepsWriter(intermediateDir, mainClassQName, googConfiguration, allswcs);
// 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> sourceExternFiles = new ArrayList<String>();
ArrayList<String> fileList = gdw.getListOfFiles(project, sourceExternFiles, problems);
if (fileList == null)
return false; // some error occurred
for (String sourceExtern : project.sourceExterns)
{
String sourceExternFileName = sourceExtern.replace(".", "/") + ".js";
File sourceExternFile = new File(intermediateDir, sourceExternFileName);
if (sourceExternFile.exists())
{
String sourceExternPath = sourceExternFile.getAbsolutePath();
if (!sourceExternFiles.contains(sourceExternPath))
sourceExternFiles.add(sourceExternPath);
}
}
if (compilerWrapper != null)
{
for (String file : fileList)
{
compilerWrapper.addJSSourceFile(file);
if (googConfiguration.isVerbose())
{
System.out.println("using source file: " + file);
}
}
}
for (String file : sourceExternFiles)
{
if (compilerWrapper != null)
{
compilerWrapper.addJSExternsFile(file);
if (googConfiguration.isVerbose())
{
System.out.println("using extern file: " + file);
}
}
collectFileAdditionalHTML(file);
}
additionalHTML.addAll(gdw.additionalHTML);
/////////////////////////////////////////////////////////////////////////////////
// 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);
// FOR MODULES: this generates inject_script lines for js to be added to __deps.js
String additionalScript = "";
if (project.isModule(mainClassQName))
{
for (String s : additionalHTML)
{
additionalScript += s.trim() + System.lineSeparator();
}
// need better test someday
depsFileData += "\ngoog.require('" + mainClassQName + "');\n";
writeFile(new File(intermediateDir, projectName + "__deps.js"), depsFileData + additionalScript + "\n", false);
gdw.needCSS = true;
if (configuration.release()) {
writeFile(new File(releaseDir, projectName + ".js"), additionalScript, false);
}
}
else
{
project.needCSS = gdw.needCSS;
File template = ((JSGoogConfiguration)configuration).getHtmlTemplate();
List<String> wrappedScript = new ArrayList<String>();
if (additionalHTML.size() > 0)
{
wrappedScript.add("<script type=\"text/javascript\">");
wrappedScript.addAll(additionalHTML);
wrappedScript.add("</script>");
}
// Create the index.html for the debug-js version.
if (!((JSGoogConfiguration)configuration).getSkipTranspile()) {
if (template != null) {
writeTemplate(template, "intermediate", projectName, mainClassQName, intermediateDir, depsFileData, wrappedScript, problems);
} else {
writeHTML("intermediate", projectName, mainClassQName, intermediateDir, depsFileData, wrappedScript, problems);
}
}
// Create the index.html for the release-js version.
if (configuration.release()) {
if (template != null) {
writeTemplate(template, "release", projectName, mainClassQName, releaseDir, depsFileData, wrappedScript, problems);
} else {
writeHTML("release", projectName, mainClassQName, releaseDir, null, wrappedScript, problems);
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// Generate or copy the main CSS resources.
/////////////////////////////////////////////////////////////////////////////////
project.needCSS = gdw.needCSS;
if (project.needCSS || googConfiguration.getSkipTranspile()) {
if (!googConfiguration.getSkipTranspile()) {
writeCSS(projectName, intermediateDir, false);
}
if (project.needCSS && configuration.release()) {
// if release version minify css string
writeCSS(projectName, releaseDir, true);
}
}
/////////////////////////////////////////////////////////////////////////////////
// If we are doing a release build, let the closure compiler do it's job.
/////////////////////////////////////////////////////////////////////////////////
if (compilerWrapper != null) {
boolean ok = true;
final File projectReleaseMainFile = new File(releaseDir, outputFileName);
compilerWrapper.setOptions(projectReleaseMainFile.getCanonicalPath(), useStrictPublishing, !googConfiguration.getRemoveCirculars(), projectName);
compilerWrapper.targetFilePath = projectReleaseMainFile.getCanonicalPath();
compilerWrapper.setSourceMap(googConfiguration.getSourceMap());
compilerWrapper.setVerbose(googConfiguration.isVerbose());
compilerWrapper.setPreventRenameMxmlSymbolReferences(googConfiguration.getPreventRenameMxmlSymbolReferences());
ok = compilerWrapper.compile();
// FOR MODULES: add additionalScript to main js release file too
if (project.isModule(mainClassQName))
{
StringBuilder appendString = new StringBuilder();
appendString.append(additionalScript);
writeFile(projectReleaseMainFile, appendString.toString(), true);
}
appendSourceMapLocation(projectReleaseMainFile, projectName);
if (ok)
System.out.println("The project '" + projectName + "' has been successfully compiled and optimized.");
}
else
System.out.println("The project '" + projectName + "' has been successfully compiled.");
return true;
}