Repository: flex-falcon Updated Branches: refs/heads/dual [created] 4d0e513db
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCFlex.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCFlex.java b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCFlex.java new file mode 100644 index 0000000..ec4b173 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCFlex.java @@ -0,0 +1,742 @@ +/* + * + * 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.clients; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.io.FilenameUtils; +import org.apache.flex.compiler.clients.problems.ProblemPrinter; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.clients.problems.ProblemQueryProvider; +import org.apache.flex.compiler.clients.problems.WorkspaceProblemFormatter; +import org.apache.flex.compiler.codegen.js.IJSPublisher; +import org.apache.flex.compiler.codegen.js.IJSWriter; +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.config.ConfigurationBuffer; +import org.apache.flex.compiler.config.Configurator; +import org.apache.flex.compiler.config.ICompilerSettingsConstants; +import org.apache.flex.compiler.driver.IBackend; +import org.apache.flex.compiler.driver.js.IJSApplication; +import org.apache.flex.compiler.exceptions.ConfigurationException; +import org.apache.flex.compiler.exceptions.ConfigurationException.IOError; +import org.apache.flex.compiler.exceptions.ConfigurationException.MustSpecifyTarget; +import org.apache.flex.compiler.exceptions.ConfigurationException.OnlyOneSource; +import org.apache.flex.compiler.internal.config.FlashBuilderConfigurator; +import org.apache.flex.compiler.internal.driver.as.ASBackend; +import org.apache.flex.compiler.internal.driver.js.amd.AMDBackend; +import org.apache.flex.compiler.internal.driver.js.goog.GoogBackend; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.internal.driver.js.jsc.JSCBackend; +import org.apache.flex.compiler.internal.driver.js.node.NodeBackend; +import org.apache.flex.compiler.internal.driver.mxml.flexjs.MXMLFlexJSBackend; +import org.apache.flex.compiler.internal.parsing.as.FlexJSASDocDelegate; +import org.apache.flex.compiler.internal.projects.CompilerProject; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.projects.ISourceFileHandler; +import org.apache.flex.compiler.internal.targets.FlexJSTarget; +import org.apache.flex.compiler.internal.targets.JSTarget; +import org.apache.flex.compiler.internal.units.ResourceModuleCompilationUnit; +import org.apache.flex.compiler.internal.units.SourceCompilationUnitFactory; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.problems.ConfigurationProblem; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.problems.InternalCompilerProblem; +import org.apache.flex.compiler.problems.UnableToBuildSWFProblem; +import org.apache.flex.compiler.problems.UnexpectedExceptionProblem; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.targets.ITarget; +import org.apache.flex.compiler.targets.ITarget.TargetType; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.tools.FlexTool; +import org.apache.flex.utils.ArgumentUtil; +import org.apache.flex.utils.FilenameNormalization; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; + +/** + * @author Erik de Bruin + * @author Michael Schmalle + */ +public class MXMLJSCFlex implements JSCompilerEntryPoint, ProblemQueryProvider, + FlexTool +{ + @Override + public ProblemQuery getProblemQuery() + { + return problems; + } + + + /* + * Exit code enumerations. + */ + static enum ExitCode + { + SUCCESS(0), + PRINT_HELP(1), + FAILED_WITH_PROBLEMS(2), + FAILED_WITH_ERRORS(3), + FAILED_WITH_EXCEPTIONS(4), + FAILED_WITH_CONFIG_PROBLEMS(5); + + ExitCode(int code) + { + this.code = code; + } + + final int code; + } + + public static MXMLJSC.JSOutputType jsOutputType; + + @Override + public String getName() + { + return FLEX_TOOL_MXMLC; + } + + @Override + public int execute(String[] args) + { + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + return mainNoExit(args, problems, true); + } + + /** + * Java program entry point. + * + * @param args command line arguments + */ + public static void main(final String[] args) + { + int exitCode = staticMainNoExit(args); + System.exit(exitCode); + } + + /** + * Entry point for the {@code <compc>} Ant task. + * + * @param args Command line arguments. + * @return An exit code. + */ + public static int staticMainNoExit(final String[] args) + { + long startTime = System.nanoTime(); + + final MXMLJSCFlex mxmlc = new MXMLJSCFlex(); + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + final int exitCode = mxmlc.mainNoExit(args, problems, true); + + long endTime = System.nanoTime(); + System.out.println((endTime - startTime) / 1e9 + " seconds"); + + return exitCode; + } + + protected Workspace workspace; + protected FlexJSProject project; + + protected ProblemQuery problems; + protected ISourceFileHandler asFileHandler; + protected Configuration config; + protected Configurator projectConfigurator; + private ConfigurationBuffer configBuffer; + private ICompilationUnit mainCU; + protected ITarget target; + protected ITargetSettings targetSettings; + protected IJSApplication jsTarget; + private IJSPublisher jsPublisher; + + public MXMLJSCFlex() + { + IBackend backend = new MXMLFlexJSBackend(); + workspace = new Workspace(); + workspace.setASDocDelegate(new FlexJSASDocDelegate()); + project = new FlexJSProject(workspace, backend); + problems = new ProblemQuery(); // this gets replaced in configure(). Do we need it here? + asFileHandler = backend.getSourceFileHandlerInstance(); + } + + @Override + public int mainNoExit(final String[] args, List<ICompilerProblem> problems, + Boolean printProblems) + { + int exitCode = -1; + try + { + exitCode = _mainNoExit(ArgumentUtil.fixArgs(args), problems); + } + catch (Exception e) + { + System.err.println(e.toString()); + } + finally + { + if (problems != null && !problems.isEmpty()) + { + if (printProblems) + { + final WorkspaceProblemFormatter formatter = new WorkspaceProblemFormatter( + workspace); + final ProblemPrinter printer = new ProblemPrinter(formatter); + printer.printProblems(problems); + } + } + } + return exitCode; + } + + /** + * Entry point that doesn't call <code>System.exit()</code>. This is for + * unit testing. + * + * @param args command line arguments + * @return exit code + */ + private int _mainNoExit(final String[] args, + List<ICompilerProblem> outProblems) + { + ExitCode exitCode = ExitCode.SUCCESS; + try + { + final boolean continueCompilation = configure(args); + +/* if (outProblems != null && !config.isVerbose()) + JSSharedData.STDOUT = JSSharedData.STDERR = null;*/ + + if (continueCompilation) + { + project.setProblems(problems.getProblems()); + compile(); + if (problems.hasFilteredProblems()) + { + if (problems.hasErrors()) + exitCode = ExitCode.FAILED_WITH_ERRORS; + else + exitCode = ExitCode.FAILED_WITH_PROBLEMS; + } + } + else if (problems.hasFilteredProblems()) + { + exitCode = ExitCode.FAILED_WITH_CONFIG_PROBLEMS; + } + else + { + exitCode = ExitCode.PRINT_HELP; + } + } + catch (Exception e) + { + if (outProblems == null) { + System.err.println(e.getMessage()); + } else + { + final ICompilerProblem unexpectedExceptionProblem = new UnexpectedExceptionProblem( + e); + problems.add(unexpectedExceptionProblem); + } + exitCode = ExitCode.FAILED_WITH_EXCEPTIONS; + } + finally + { + waitAndClose(); + + if (outProblems != null && problems.hasFilteredProblems()) + { + for (ICompilerProblem problem : problems.getFilteredProblems()) + { + outProblems.add(problem); + } + } + } + return exitCode.code; + } + + /** + * Main body of this program. This method is called from the public static + * method's for this program. + * + * @return true if compiler succeeds + * @throws IOException + * @throws InterruptedException + */ + protected boolean compile() + { + JSGoogConfiguration googConfiguration = (JSGoogConfiguration) config; + boolean compilationSuccess = false; + + try + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + + if (!googConfiguration.getSkipTranspile()) + { + if (!setupTargetFile()) { + return false; + } + + buildArtifact(); + } + if (jsTarget != null || googConfiguration.getSkipTranspile()) + { + List<ICompilerProblem> errors = new ArrayList<ICompilerProblem>(); + List<ICompilerProblem> warnings = new ArrayList<ICompilerProblem>(); + + if (!config.getCreateTargetWithErrors()) + { + problems.getErrorsAndWarnings(errors, warnings); + if (errors.size() > 0) + return false; + } + + jsPublisher = (IJSPublisher) project.getBackend().createPublisher( + project, errors, config); + + File outputFolder = jsPublisher.getOutputFolder(); + + if (!googConfiguration.getSkipTranspile()) + { + ArrayList<ICompilationUnit> roots = new ArrayList<ICompilationUnit>(); + roots.add(mainCU); + Set<ICompilationUnit> incs = target.getIncludesCompilationUnits(); + roots.addAll(incs); + project.mixinClassNames = new TreeSet<String>(); + List<ICompilationUnit> reachableCompilationUnits = project.getReachableCompilationUnitsInSWFOrder(roots); + ((FlexJSTarget)target).collectMixinMetaData(project.mixinClassNames, reachableCompilationUnits); + for (final ICompilationUnit cu : reachableCompilationUnits) + { + ICompilationUnit.UnitType cuType = cu.getCompilationUnitType(); + + if (cuType == ICompilationUnit.UnitType.AS_UNIT + || cuType == ICompilationUnit.UnitType.MXML_UNIT) + { + final File outputClassFile = getOutputClassFile( + cu.getQualifiedNames().get(0), outputFolder); + + System.out.println("Compiling file: " + outputClassFile); + + ICompilationUnit unit = cu; + + IJSWriter writer; + if (cuType == ICompilationUnit.UnitType.AS_UNIT) + { + writer = (IJSWriter) project.getBackend().createWriter(project, + errors, unit, false); + } + else + { + writer = (IJSWriter) project.getBackend().createMXMLWriter( + project, errors, unit, false); + } + + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(outputClassFile)); + + File outputSourceMapFile = null; + if (project.config.getSourceMap()) + { + outputSourceMapFile = getOutputSourceMapFile( + cu.getQualifiedNames().get(0), outputFolder); + } + + writer.writeTo(out, outputSourceMapFile); + out.flush(); + out.close(); + writer.close(); + } + } + } + + if (jsPublisher != null) + { + compilationSuccess = jsPublisher.publish(problems); + } + else + { + compilationSuccess = true; + } + } + } + catch (Exception e) + { + final ICompilerProblem problem = new InternalCompilerProblem(e); + problems.add(problem); + } + + return compilationSuccess; + } + + /** + * Build target artifact. + * + * @throws InterruptedException threading error + * @throws IOException IO error + * @throws ConfigurationException + */ + protected void buildArtifact() throws InterruptedException, IOException, + ConfigurationException + { + jsTarget = buildJSTarget(); + } + + private IJSApplication buildJSTarget() throws InterruptedException, + FileNotFoundException, ConfigurationException + { + final List<ICompilerProblem> problemsBuildingSWF = new ArrayList<ICompilerProblem>(); + + project.mainCU = mainCU; + final IJSApplication app = buildApplication(project, + config.getMainDefinition(), mainCU, problemsBuildingSWF); + problems.addAll(problemsBuildingSWF); + if (app == null) + { + ICompilerProblem problem = new UnableToBuildSWFProblem( + getOutputFilePath()); + problems.add(problem); + } + + return app; + } + + /** + * Replaces FlexApplicationProject::buildSWF() + * + * @param applicationProject + * @param rootClassName + * @param problems + * @return + * @throws InterruptedException + */ + + private IJSApplication buildApplication(CompilerProject applicationProject, + String rootClassName, ICompilationUnit mainCU, + Collection<ICompilerProblem> problems) throws InterruptedException, + ConfigurationException, FileNotFoundException + { + Collection<ICompilerProblem> fatalProblems = applicationProject.getFatalProblems(); + if (!fatalProblems.isEmpty()) + { + problems.addAll(fatalProblems); + return null; + } + + return ((JSTarget) target).build(mainCU, problems); + } + + /** + * Get the output file path. If {@code -output} is specified, use its value; + * otherwise, use the same base name as the target file. + * + * @return output file path + */ + private String getOutputFilePath() + { + if (config.getOutput() == null) + { + final String extension = "." + project.getBackend().getOutputExtension(); + return FilenameUtils.removeExtension(config.getTargetFile()).concat( + extension); + } + else + return config.getOutput(); + } + + /** + * @author Erik de Bruin + * + * Get the output class file. This includes the (sub)directory in + * which the original class file lives. If the directory structure + * doesn't exist, it is created. + * + * @param qname + * @param outputFolder + * @return output class file path + */ + private File getOutputClassFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension()); + } + + /** + * @param qname + * @param outputFolder + * @return output source map file path + */ + private File getOutputSourceMapFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension() + ".map"); + } + + /** + * Mxmlc uses target file as the main compilation unit and derive the output + * SWF file name from this file. + * + * @return true if successful, false otherwise. + * @throws OnlyOneSource + * @throws InterruptedException + */ + protected boolean setupTargetFile() throws InterruptedException + { + final String mainFileName = config.getTargetFile(); + + final String normalizedMainFileName = FilenameNormalization.normalize(mainFileName); + + final SourceCompilationUnitFactory compilationUnitFactory = project.getSourceCompilationUnitFactory(); + + File normalizedMainFile = new File(normalizedMainFileName); + if (compilationUnitFactory.canCreateCompilationUnit(normalizedMainFile)) + { + project.addIncludeSourceFile(normalizedMainFile); + + final List<String> sourcePath = config.getCompilerSourcePath(); + String mainQName = null; + if (sourcePath != null && !sourcePath.isEmpty()) + { + for (String path : sourcePath) + { + final String otherPath = new File(path).getAbsolutePath(); + if (mainFileName.startsWith(otherPath)) + { + mainQName = mainFileName.substring(otherPath.length() + 1); + mainQName = mainQName.replaceAll("\\\\", "/"); + mainQName = mainQName.replaceAll("\\/", "."); + if (mainQName.endsWith(".as")) + mainQName = mainQName.substring(0, + mainQName.length() - 3); + break; + } + } + } + + if (mainQName == null) + mainQName = FilenameUtils.getBaseName(mainFileName); + + Collection<ICompilationUnit> mainFileCompilationUnits = workspace.getCompilationUnits( + normalizedMainFileName, project); + + mainCU = Iterables.getOnlyElement(mainFileCompilationUnits); + + config.setMainDefinition(mainQName); + } + + Preconditions.checkNotNull(mainCU, + "Main compilation unit can't be null"); + + ITargetSettings settings = getTargetSettings(); + if (settings != null) + project.setTargetSettings(settings); + + target = project.getBackend().createTarget(project, + getTargetSettings(), null); + + return true; + } + + private ITargetSettings getTargetSettings() + { + if (targetSettings == null) + targetSettings = projectConfigurator.getTargetSettings(null); + + return targetSettings; + } + + /** + * Create a new Configurator. This method may be overridden to allow + * Configurator subclasses to be created that have custom configurations. + * + * @return a new instance or subclass of {@link Configurator}. + */ + protected Configurator createConfigurator() + { + return project.getBackend().createConfigurator(); + } + + /** + * Load configurations from all the sources. + * + * @param args command line arguments + * @return True if mxmlc should continue with compilation. + */ + protected boolean configure(final String[] args) + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + project.configurator = projectConfigurator = createConfigurator(); + + try + { + if (useFlashBuilderProjectFiles(args)) + { + projectConfigurator.setConfiguration( + FlashBuilderConfigurator.computeFlashBuilderArgs(args, + getTargetType().getExtension()), + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + else + { + projectConfigurator.setConfiguration(args, + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + + projectConfigurator.applyToProject(project); + project.config = (JSGoogConfiguration) projectConfigurator.getConfiguration(); + + config = projectConfigurator.getConfiguration(); + configBuffer = projectConfigurator.getConfigurationBuffer(); + + problems = new ProblemQuery(projectConfigurator.getCompilerProblemSettings()); + problems.addAll(projectConfigurator.getConfigurationProblems()); + + if (configBuffer.getVar("version") != null) //$NON-NLS-1$ + return false; + + if (problems.hasErrors()) + return false; + + validateTargetFile(); + return true; + } + catch (ConfigurationException e) + { + final ICompilerProblem problem = new ConfigurationProblem(e); + problems.add(problem); + return false; + } + catch (Exception e) + { + final ICompilerProblem problem = new ConfigurationProblem(null, -1, + -1, -1, -1, e.getMessage()); + problems.add(problem); + return false; + } + finally + { + if (config == null) + { + config = new Configuration(); + configBuffer = new ConfigurationBuffer(Configuration.class, + Configuration.getAliases()); + } + } + } + + private boolean useFlashBuilderProjectFiles(String[] args) + { + for (String arg : args) + { + if (arg.equals("-fb") + || arg.equals("-use-flashbuilder-project-files")) + return true; + } + return false; + } + + protected TargetType getTargetType() + { + return TargetType.SWF; + } + + /** + * Validate target file. + * + * @throws MustSpecifyTarget + * @throws IOError + */ + protected void validateTargetFile() throws ConfigurationException + { + if (mainCU instanceof ResourceModuleCompilationUnit) + return; //when compiling a Resource Module, no target file is defined. + + final String targetFile = config.getTargetFile(); + if (targetFile == null) + throw new ConfigurationException.MustSpecifyTarget(null, null, -1); + + final File file = new File(targetFile); + if (!file.exists()) + throw new ConfigurationException.IOError(targetFile); + } + + /** + * Wait till the workspace to finish compilation and close. + */ + protected void waitAndClose() + { + workspace.startIdleState(); + try + { + workspace.close(); + } + finally + { + workspace.endIdleState(Collections.<ICompilerProject, Set<ICompilationUnit>> emptyMap()); + } + } + + /** + * Force terminate the compilation process. + */ + protected void close() + { + workspace.close(); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNative.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNative.java b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNative.java new file mode 100644 index 0000000..5ae898d --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNative.java @@ -0,0 +1,741 @@ +/* + * + * 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.clients; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.io.FilenameUtils; +import org.apache.flex.compiler.clients.problems.ProblemPrinter; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.clients.problems.ProblemQueryProvider; +import org.apache.flex.compiler.clients.problems.WorkspaceProblemFormatter; +import org.apache.flex.compiler.codegen.js.IJSPublisher; +import org.apache.flex.compiler.codegen.js.IJSWriter; +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.config.ConfigurationBuffer; +import org.apache.flex.compiler.config.Configurator; +import org.apache.flex.compiler.config.ICompilerSettingsConstants; +import org.apache.flex.compiler.driver.IBackend; +import org.apache.flex.compiler.driver.js.IJSApplication; +import org.apache.flex.compiler.exceptions.ConfigurationException; +import org.apache.flex.compiler.exceptions.ConfigurationException.IOError; +import org.apache.flex.compiler.exceptions.ConfigurationException.MustSpecifyTarget; +import org.apache.flex.compiler.exceptions.ConfigurationException.OnlyOneSource; +import org.apache.flex.compiler.internal.config.FlashBuilderConfigurator; +import org.apache.flex.compiler.internal.driver.as.ASBackend; +import org.apache.flex.compiler.internal.driver.js.amd.AMDBackend; +import org.apache.flex.compiler.internal.driver.js.goog.GoogBackend; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.internal.driver.js.jsc.JSCBackend; +import org.apache.flex.compiler.internal.driver.js.node.NodeBackend; +import org.apache.flex.compiler.internal.driver.mxml.flexjs.MXMLFlexJSBackend; +import org.apache.flex.compiler.internal.parsing.as.FlexJSASDocDelegate; +import org.apache.flex.compiler.internal.projects.CompilerProject; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.projects.ISourceFileHandler; +import org.apache.flex.compiler.internal.targets.FlexJSTarget; +import org.apache.flex.compiler.internal.targets.JSTarget; +import org.apache.flex.compiler.internal.units.ResourceModuleCompilationUnit; +import org.apache.flex.compiler.internal.units.SourceCompilationUnitFactory; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.problems.ConfigurationProblem; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.problems.InternalCompilerProblem; +import org.apache.flex.compiler.problems.UnableToBuildSWFProblem; +import org.apache.flex.compiler.problems.UnexpectedExceptionProblem; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.targets.ITarget; +import org.apache.flex.compiler.targets.ITarget.TargetType; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.tools.FlexTool; +import org.apache.flex.utils.ArgumentUtil; +import org.apache.flex.utils.FilenameNormalization; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; + +/** + * @author Erik de Bruin + * @author Michael Schmalle + */ +public class MXMLJSCNative implements JSCompilerEntryPoint, ProblemQueryProvider, + FlexTool +{ + @Override + public ProblemQuery getProblemQuery() + { + return problems; + } + + + /* + * Exit code enumerations. + */ + static enum ExitCode + { + SUCCESS(0), + PRINT_HELP(1), + FAILED_WITH_PROBLEMS(2), + FAILED_WITH_ERRORS(3), + FAILED_WITH_EXCEPTIONS(4), + FAILED_WITH_CONFIG_PROBLEMS(5); + + ExitCode(int code) + { + this.code = code; + } + + final int code; + } + + @Override + public String getName() + { + return FLEX_TOOL_MXMLC; + } + + @Override + public int execute(String[] args) + { + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + return mainNoExit(args, problems, true); + } + + /** + * Java program entry point. + * + * @param args command line arguments + */ + public static void main(final String[] args) + { + int exitCode = staticMainNoExit(args); + System.exit(exitCode); + } + + /** + * Entry point for the {@code <compc>} Ant task. + * + * @param args Command line arguments. + * @return An exit code. + */ + public static int staticMainNoExit(final String[] args) + { + long startTime = System.nanoTime(); + + final MXMLJSCNative mxmlc = new MXMLJSCNative(); + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + final int exitCode = mxmlc.mainNoExit(args, problems, true); + + long endTime = System.nanoTime(); + System.out.println((endTime - startTime) / 1e9 + " seconds"); + + return exitCode; + } + + protected Workspace workspace; + protected FlexJSProject project; + + protected ProblemQuery problems; + protected ISourceFileHandler asFileHandler; + protected Configuration config; + protected Configurator projectConfigurator; + private ConfigurationBuffer configBuffer; + private ICompilationUnit mainCU; + protected ITarget target; + protected ITargetSettings targetSettings; + protected IJSApplication jsTarget; + private IJSPublisher jsPublisher; + + public MXMLJSCNative() + { + IBackend backend = new JSCBackend(); + + workspace = new Workspace(); + workspace.setASDocDelegate(new FlexJSASDocDelegate()); + project = new FlexJSProject(workspace, backend); + problems = new ProblemQuery(); // this gets replaced in configure(). Do we need it here? + asFileHandler = backend.getSourceFileHandlerInstance(); + } + + @Override + public int mainNoExit(final String[] args, List<ICompilerProblem> problems, + Boolean printProblems) + { + int exitCode = -1; + try + { + exitCode = _mainNoExit(ArgumentUtil.fixArgs(args), problems); + } + catch (Exception e) + { + System.err.println(e.toString()); + } + finally + { + if (problems != null && !problems.isEmpty()) + { + if (printProblems) + { + final WorkspaceProblemFormatter formatter = new WorkspaceProblemFormatter( + workspace); + final ProblemPrinter printer = new ProblemPrinter(formatter); + printer.printProblems(problems); + } + } + } + return exitCode; + } + + /** + * Entry point that doesn't call <code>System.exit()</code>. This is for + * unit testing. + * + * @param args command line arguments + * @return exit code + */ + private int _mainNoExit(final String[] args, + List<ICompilerProblem> outProblems) + { + ExitCode exitCode = ExitCode.SUCCESS; + try + { + final boolean continueCompilation = configure(args); + +/* if (outProblems != null && !config.isVerbose()) + JSSharedData.STDOUT = JSSharedData.STDERR = null;*/ + + if (continueCompilation) + { + project.setProblems(problems.getProblems()); + compile(); + if (problems.hasFilteredProblems()) + { + if (problems.hasErrors()) + exitCode = ExitCode.FAILED_WITH_ERRORS; + else + exitCode = ExitCode.FAILED_WITH_PROBLEMS; + } + } + else if (problems.hasFilteredProblems()) + { + exitCode = ExitCode.FAILED_WITH_CONFIG_PROBLEMS; + } + else + { + exitCode = ExitCode.PRINT_HELP; + } + } + catch (Exception e) + { + if (outProblems == null) { + System.err.println(e.getMessage()); + } else + { + final ICompilerProblem unexpectedExceptionProblem = new UnexpectedExceptionProblem( + e); + problems.add(unexpectedExceptionProblem); + } + exitCode = ExitCode.FAILED_WITH_EXCEPTIONS; + } + finally + { + waitAndClose(); + + if (outProblems != null && problems.hasFilteredProblems()) + { + for (ICompilerProblem problem : problems.getFilteredProblems()) + { + outProblems.add(problem); + } + } + } + return exitCode.code; + } + + /** + * Main body of this program. This method is called from the public static + * method's for this program. + * + * @return true if compiler succeeds + * @throws IOException + * @throws InterruptedException + */ + protected boolean compile() + { + JSGoogConfiguration googConfiguration = (JSGoogConfiguration) config; + boolean compilationSuccess = false; + + try + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + + if (!googConfiguration.getSkipTranspile()) + { + if (!setupTargetFile()) { + return false; + } + + buildArtifact(); + } + if (jsTarget != null || googConfiguration.getSkipTranspile()) + { + List<ICompilerProblem> errors = new ArrayList<ICompilerProblem>(); + List<ICompilerProblem> warnings = new ArrayList<ICompilerProblem>(); + + if (!config.getCreateTargetWithErrors()) + { + problems.getErrorsAndWarnings(errors, warnings); + if (errors.size() > 0) + return false; + } + + jsPublisher = (IJSPublisher) project.getBackend().createPublisher( + project, errors, config); + + File outputFolder = jsPublisher.getOutputFolder(); + + if (!googConfiguration.getSkipTranspile()) + { + ArrayList<ICompilationUnit> roots = new ArrayList<ICompilationUnit>(); + roots.add(mainCU); + Set<ICompilationUnit> incs = target.getIncludesCompilationUnits(); + roots.addAll(incs); + project.mixinClassNames = new TreeSet<String>(); + List<ICompilationUnit> reachableCompilationUnits = project.getReachableCompilationUnitsInSWFOrder(roots); + ((FlexJSTarget)target).collectMixinMetaData(project.mixinClassNames, reachableCompilationUnits); + for (final ICompilationUnit cu : reachableCompilationUnits) + { + ICompilationUnit.UnitType cuType = cu.getCompilationUnitType(); + + if (cuType == ICompilationUnit.UnitType.AS_UNIT + || cuType == ICompilationUnit.UnitType.MXML_UNIT) + { + final File outputClassFile = getOutputClassFile( + cu.getQualifiedNames().get(0), outputFolder); + + System.out.println("Compiling file: " + outputClassFile); + + ICompilationUnit unit = cu; + + IJSWriter writer; + if (cuType == ICompilationUnit.UnitType.AS_UNIT) + { + writer = (IJSWriter) project.getBackend().createWriter(project, + errors, unit, false); + } + else + { + writer = (IJSWriter) project.getBackend().createMXMLWriter( + project, errors, unit, false); + } + + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(outputClassFile)); + + File outputSourceMapFile = null; + if (project.config.getSourceMap()) + { + outputSourceMapFile = getOutputSourceMapFile( + cu.getQualifiedNames().get(0), outputFolder); + } + + writer.writeTo(out, outputSourceMapFile); + out.flush(); + out.close(); + writer.close(); + } + } + } + + if (jsPublisher != null) + { + compilationSuccess = jsPublisher.publish(problems); + } + else + { + compilationSuccess = true; + } + } + } + catch (Exception e) + { + final ICompilerProblem problem = new InternalCompilerProblem(e); + problems.add(problem); + } + + return compilationSuccess; + } + + /** + * Build target artifact. + * + * @throws InterruptedException threading error + * @throws IOException IO error + * @throws ConfigurationException + */ + protected void buildArtifact() throws InterruptedException, IOException, + ConfigurationException + { + jsTarget = buildJSTarget(); + } + + private IJSApplication buildJSTarget() throws InterruptedException, + FileNotFoundException, ConfigurationException + { + final List<ICompilerProblem> problemsBuildingSWF = new ArrayList<ICompilerProblem>(); + + project.mainCU = mainCU; + final IJSApplication app = buildApplication(project, + config.getMainDefinition(), mainCU, problemsBuildingSWF); + problems.addAll(problemsBuildingSWF); + if (app == null) + { + ICompilerProblem problem = new UnableToBuildSWFProblem( + getOutputFilePath()); + problems.add(problem); + } + + return app; + } + + /** + * Replaces FlexApplicationProject::buildSWF() + * + * @param applicationProject + * @param rootClassName + * @param problems + * @return + * @throws InterruptedException + */ + + private IJSApplication buildApplication(CompilerProject applicationProject, + String rootClassName, ICompilationUnit mainCU, + Collection<ICompilerProblem> problems) throws InterruptedException, + ConfigurationException, FileNotFoundException + { + Collection<ICompilerProblem> fatalProblems = applicationProject.getFatalProblems(); + if (!fatalProblems.isEmpty()) + { + problems.addAll(fatalProblems); + return null; + } + + return ((JSTarget) target).build(mainCU, problems); + } + + /** + * Get the output file path. If {@code -output} is specified, use its value; + * otherwise, use the same base name as the target file. + * + * @return output file path + */ + private String getOutputFilePath() + { + if (config.getOutput() == null) + { + final String extension = "." + project.getBackend().getOutputExtension(); + return FilenameUtils.removeExtension(config.getTargetFile()).concat( + extension); + } + else + return config.getOutput(); + } + + /** + * @author Erik de Bruin + * + * Get the output class file. This includes the (sub)directory in + * which the original class file lives. If the directory structure + * doesn't exist, it is created. + * + * @param qname + * @param outputFolder + * @return output class file path + */ + private File getOutputClassFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension()); + } + + /** + * @param qname + * @param outputFolder + * @return output source map file path + */ + private File getOutputSourceMapFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension() + ".map"); + } + + /** + * Mxmlc uses target file as the main compilation unit and derive the output + * SWF file name from this file. + * + * @return true if successful, false otherwise. + * @throws OnlyOneSource + * @throws InterruptedException + */ + protected boolean setupTargetFile() throws InterruptedException + { + final String mainFileName = config.getTargetFile(); + + final String normalizedMainFileName = FilenameNormalization.normalize(mainFileName); + + final SourceCompilationUnitFactory compilationUnitFactory = project.getSourceCompilationUnitFactory(); + + File normalizedMainFile = new File(normalizedMainFileName); + if (compilationUnitFactory.canCreateCompilationUnit(normalizedMainFile)) + { + project.addIncludeSourceFile(normalizedMainFile); + + final List<String> sourcePath = config.getCompilerSourcePath(); + String mainQName = null; + if (sourcePath != null && !sourcePath.isEmpty()) + { + for (String path : sourcePath) + { + final String otherPath = new File(path).getAbsolutePath(); + if (mainFileName.startsWith(otherPath)) + { + mainQName = mainFileName.substring(otherPath.length() + 1); + mainQName = mainQName.replaceAll("\\\\", "/"); + mainQName = mainQName.replaceAll("\\/", "."); + if (mainQName.endsWith(".as")) + mainQName = mainQName.substring(0, + mainQName.length() - 3); + break; + } + } + } + + if (mainQName == null) + mainQName = FilenameUtils.getBaseName(mainFileName); + + Collection<ICompilationUnit> mainFileCompilationUnits = workspace.getCompilationUnits( + normalizedMainFileName, project); + + mainCU = Iterables.getOnlyElement(mainFileCompilationUnits); + + config.setMainDefinition(mainQName); + } + + Preconditions.checkNotNull(mainCU, + "Main compilation unit can't be null"); + + ITargetSettings settings = getTargetSettings(); + if (settings != null) + project.setTargetSettings(settings); + + target = project.getBackend().createTarget(project, + getTargetSettings(), null); + + return true; + } + + private ITargetSettings getTargetSettings() + { + if (targetSettings == null) + targetSettings = projectConfigurator.getTargetSettings(null); + + return targetSettings; + } + + /** + * Create a new Configurator. This method may be overridden to allow + * Configurator subclasses to be created that have custom configurations. + * + * @return a new instance or subclass of {@link Configurator}. + */ + protected Configurator createConfigurator() + { + return project.getBackend().createConfigurator(); + } + + /** + * Load configurations from all the sources. + * + * @param args command line arguments + * @return True if mxmlc should continue with compilation. + */ + protected boolean configure(final String[] args) + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + project.configurator = projectConfigurator = createConfigurator(); + + try + { + if (useFlashBuilderProjectFiles(args)) + { + projectConfigurator.setConfiguration( + FlashBuilderConfigurator.computeFlashBuilderArgs(args, + getTargetType().getExtension()), + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + else + { + projectConfigurator.setConfiguration(args, + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + + projectConfigurator.applyToProject(project); + project.config = (JSGoogConfiguration) projectConfigurator.getConfiguration(); + + config = projectConfigurator.getConfiguration(); + configBuffer = projectConfigurator.getConfigurationBuffer(); + + problems = new ProblemQuery(projectConfigurator.getCompilerProblemSettings()); + problems.addAll(projectConfigurator.getConfigurationProblems()); + + if (configBuffer.getVar("version") != null) //$NON-NLS-1$ + return false; + + if (problems.hasErrors()) + return false; + + validateTargetFile(); + return true; + } + catch (ConfigurationException e) + { + final ICompilerProblem problem = new ConfigurationProblem(e); + problems.add(problem); + return false; + } + catch (Exception e) + { + final ICompilerProblem problem = new ConfigurationProblem(null, -1, + -1, -1, -1, e.getMessage()); + problems.add(problem); + return false; + } + finally + { + if (config == null) + { + config = new Configuration(); + configBuffer = new ConfigurationBuffer(Configuration.class, + Configuration.getAliases()); + } + } + } + + private boolean useFlashBuilderProjectFiles(String[] args) + { + for (String arg : args) + { + if (arg.equals("-fb") + || arg.equals("-use-flashbuilder-project-files")) + return true; + } + return false; + } + + protected TargetType getTargetType() + { + return TargetType.SWF; + } + + /** + * Validate target file. + * + * @throws MustSpecifyTarget + * @throws IOError + */ + protected void validateTargetFile() throws ConfigurationException + { + if (mainCU instanceof ResourceModuleCompilationUnit) + return; //when compiling a Resource Module, no target file is defined. + + final String targetFile = config.getTargetFile(); + if (targetFile == null) + throw new ConfigurationException.MustSpecifyTarget(null, null, -1); + + final File file = new File(targetFile); + if (!file.exists()) + throw new ConfigurationException.IOError(targetFile); + } + + /** + * Wait till the workspace to finish compilation and close. + */ + protected void waitAndClose() + { + workspace.startIdleState(); + try + { + workspace.close(); + } + finally + { + workspace.endIdleState(Collections.<ICompilerProject, Set<ICompilationUnit>> emptyMap()); + } + } + + /** + * Force terminate the compilation process. + */ + protected void close() + { + workspace.close(); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNode.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNode.java b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNode.java new file mode 100644 index 0000000..94b0842 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/clients/MXMLJSCNode.java @@ -0,0 +1,739 @@ +/* + * + * 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.clients; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.io.FilenameUtils; +import org.apache.flex.compiler.clients.problems.ProblemPrinter; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.clients.problems.ProblemQueryProvider; +import org.apache.flex.compiler.clients.problems.WorkspaceProblemFormatter; +import org.apache.flex.compiler.codegen.js.IJSPublisher; +import org.apache.flex.compiler.codegen.js.IJSWriter; +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.config.ConfigurationBuffer; +import org.apache.flex.compiler.config.Configurator; +import org.apache.flex.compiler.config.ICompilerSettingsConstants; +import org.apache.flex.compiler.driver.IBackend; +import org.apache.flex.compiler.driver.js.IJSApplication; +import org.apache.flex.compiler.exceptions.ConfigurationException; +import org.apache.flex.compiler.exceptions.ConfigurationException.IOError; +import org.apache.flex.compiler.exceptions.ConfigurationException.MustSpecifyTarget; +import org.apache.flex.compiler.exceptions.ConfigurationException.OnlyOneSource; +import org.apache.flex.compiler.internal.config.FlashBuilderConfigurator; +import org.apache.flex.compiler.internal.driver.as.ASBackend; +import org.apache.flex.compiler.internal.driver.js.amd.AMDBackend; +import org.apache.flex.compiler.internal.driver.js.goog.GoogBackend; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.internal.driver.js.jsc.JSCBackend; +import org.apache.flex.compiler.internal.driver.js.node.NodeBackend; +import org.apache.flex.compiler.internal.driver.mxml.flexjs.MXMLFlexJSBackend; +import org.apache.flex.compiler.internal.parsing.as.FlexJSASDocDelegate; +import org.apache.flex.compiler.internal.projects.CompilerProject; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.projects.ISourceFileHandler; +import org.apache.flex.compiler.internal.targets.FlexJSTarget; +import org.apache.flex.compiler.internal.targets.JSTarget; +import org.apache.flex.compiler.internal.units.ResourceModuleCompilationUnit; +import org.apache.flex.compiler.internal.units.SourceCompilationUnitFactory; +import org.apache.flex.compiler.internal.workspaces.Workspace; +import org.apache.flex.compiler.problems.ConfigurationProblem; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.problems.InternalCompilerProblem; +import org.apache.flex.compiler.problems.UnableToBuildSWFProblem; +import org.apache.flex.compiler.problems.UnexpectedExceptionProblem; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.targets.ITarget; +import org.apache.flex.compiler.targets.ITarget.TargetType; +import org.apache.flex.compiler.targets.ITargetSettings; +import org.apache.flex.compiler.units.ICompilationUnit; +import org.apache.flex.tools.FlexTool; +import org.apache.flex.utils.ArgumentUtil; +import org.apache.flex.utils.FilenameNormalization; + +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; + +/** + * @author Erik de Bruin + * @author Michael Schmalle + */ +public class MXMLJSCNode implements JSCompilerEntryPoint, ProblemQueryProvider, + FlexTool +{ + @Override + public ProblemQuery getProblemQuery() + { + return problems; + } + + /* + * Exit code enumerations. + */ + static enum ExitCode + { + SUCCESS(0), + PRINT_HELP(1), + FAILED_WITH_PROBLEMS(2), + FAILED_WITH_ERRORS(3), + FAILED_WITH_EXCEPTIONS(4), + FAILED_WITH_CONFIG_PROBLEMS(5); + + ExitCode(int code) + { + this.code = code; + } + + final int code; + } + + @Override + public String getName() + { + return FLEX_TOOL_MXMLC; + } + + @Override + public int execute(String[] args) + { + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + return mainNoExit(args, problems, true); + } + + /** + * Java program entry point. + * + * @param args command line arguments + */ + public static void main(final String[] args) + { + int exitCode = staticMainNoExit(args); + System.exit(exitCode); + } + + /** + * Entry point for the {@code <compc>} Ant task. + * + * @param args Command line arguments. + * @return An exit code. + */ + public static int staticMainNoExit(final String[] args) + { + long startTime = System.nanoTime(); + + final MXMLJSCNode mxmlc = new MXMLJSCNode(); + final List<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + final int exitCode = mxmlc.mainNoExit(args, problems, true); + + long endTime = System.nanoTime(); + System.out.println((endTime - startTime) / 1e9 + " seconds"); + + return exitCode; + } + + protected Workspace workspace; + protected FlexJSProject project; + + protected ProblemQuery problems; + protected ISourceFileHandler asFileHandler; + protected Configuration config; + protected Configurator projectConfigurator; + private ConfigurationBuffer configBuffer; + private ICompilationUnit mainCU; + protected ITarget target; + protected ITargetSettings targetSettings; + protected IJSApplication jsTarget; + private IJSPublisher jsPublisher; + + public MXMLJSCNode() + { + IBackend backend = new NodeBackend(); + workspace = new Workspace(); + workspace.setASDocDelegate(new FlexJSASDocDelegate()); + project = new FlexJSProject(workspace, backend); + problems = new ProblemQuery(); // this gets replaced in configure(). Do we need it here? + asFileHandler = backend.getSourceFileHandlerInstance(); + } + + @Override + public int mainNoExit(final String[] args, List<ICompilerProblem> problems, + Boolean printProblems) + { + int exitCode = -1; + try + { + exitCode = _mainNoExit(ArgumentUtil.fixArgs(args), problems); + } + catch (Exception e) + { + System.err.println(e.toString()); + } + finally + { + if (problems != null && !problems.isEmpty()) + { + if (printProblems) + { + final WorkspaceProblemFormatter formatter = new WorkspaceProblemFormatter( + workspace); + final ProblemPrinter printer = new ProblemPrinter(formatter); + printer.printProblems(problems); + } + } + } + return exitCode; + } + + /** + * Entry point that doesn't call <code>System.exit()</code>. This is for + * unit testing. + * + * @param args command line arguments + * @return exit code + */ + private int _mainNoExit(final String[] args, + List<ICompilerProblem> outProblems) + { + ExitCode exitCode = ExitCode.SUCCESS; + try + { + final boolean continueCompilation = configure(args); + +/* if (outProblems != null && !config.isVerbose()) + JSSharedData.STDOUT = JSSharedData.STDERR = null;*/ + + if (continueCompilation) + { + project.setProblems(problems.getProblems()); + compile(); + if (problems.hasFilteredProblems()) + { + if (problems.hasErrors()) + exitCode = ExitCode.FAILED_WITH_ERRORS; + else + exitCode = ExitCode.FAILED_WITH_PROBLEMS; + } + } + else if (problems.hasFilteredProblems()) + { + exitCode = ExitCode.FAILED_WITH_CONFIG_PROBLEMS; + } + else + { + exitCode = ExitCode.PRINT_HELP; + } + } + catch (Exception e) + { + if (outProblems == null) { + System.err.println(e.getMessage()); + } else + { + final ICompilerProblem unexpectedExceptionProblem = new UnexpectedExceptionProblem( + e); + problems.add(unexpectedExceptionProblem); + } + exitCode = ExitCode.FAILED_WITH_EXCEPTIONS; + } + finally + { + waitAndClose(); + + if (outProblems != null && problems.hasFilteredProblems()) + { + for (ICompilerProblem problem : problems.getFilteredProblems()) + { + outProblems.add(problem); + } + } + } + return exitCode.code; + } + + /** + * Main body of this program. This method is called from the public static + * method's for this program. + * + * @return true if compiler succeeds + * @throws IOException + * @throws InterruptedException + */ + protected boolean compile() + { + JSGoogConfiguration googConfiguration = (JSGoogConfiguration) config; + boolean compilationSuccess = false; + + try + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + + if (!googConfiguration.getSkipTranspile()) + { + if (!setupTargetFile()) { + return false; + } + + buildArtifact(); + } + if (jsTarget != null || googConfiguration.getSkipTranspile()) + { + List<ICompilerProblem> errors = new ArrayList<ICompilerProblem>(); + List<ICompilerProblem> warnings = new ArrayList<ICompilerProblem>(); + + if (!config.getCreateTargetWithErrors()) + { + problems.getErrorsAndWarnings(errors, warnings); + if (errors.size() > 0) + return false; + } + + jsPublisher = (IJSPublisher) project.getBackend().createPublisher( + project, errors, config); + + File outputFolder = jsPublisher.getOutputFolder(); + + if (!googConfiguration.getSkipTranspile()) + { + ArrayList<ICompilationUnit> roots = new ArrayList<ICompilationUnit>(); + roots.add(mainCU); + Set<ICompilationUnit> incs = target.getIncludesCompilationUnits(); + roots.addAll(incs); + project.mixinClassNames = new TreeSet<String>(); + List<ICompilationUnit> reachableCompilationUnits = project.getReachableCompilationUnitsInSWFOrder(roots); + ((FlexJSTarget)target).collectMixinMetaData(project.mixinClassNames, reachableCompilationUnits); + for (final ICompilationUnit cu : reachableCompilationUnits) + { + ICompilationUnit.UnitType cuType = cu.getCompilationUnitType(); + + if (cuType == ICompilationUnit.UnitType.AS_UNIT + || cuType == ICompilationUnit.UnitType.MXML_UNIT) + { + final File outputClassFile = getOutputClassFile( + cu.getQualifiedNames().get(0), outputFolder); + + System.out.println("Compiling file: " + outputClassFile); + + ICompilationUnit unit = cu; + + IJSWriter writer; + if (cuType == ICompilationUnit.UnitType.AS_UNIT) + { + writer = (IJSWriter) project.getBackend().createWriter(project, + errors, unit, false); + } + else + { + writer = (IJSWriter) project.getBackend().createMXMLWriter( + project, errors, unit, false); + } + + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(outputClassFile)); + + File outputSourceMapFile = null; + if (project.config.getSourceMap()) + { + outputSourceMapFile = getOutputSourceMapFile( + cu.getQualifiedNames().get(0), outputFolder); + } + + writer.writeTo(out, outputSourceMapFile); + out.flush(); + out.close(); + writer.close(); + } + } + } + + if (jsPublisher != null) + { + compilationSuccess = jsPublisher.publish(problems); + } + else + { + compilationSuccess = true; + } + } + } + catch (Exception e) + { + final ICompilerProblem problem = new InternalCompilerProblem(e); + problems.add(problem); + } + + return compilationSuccess; + } + + /** + * Build target artifact. + * + * @throws InterruptedException threading error + * @throws IOException IO error + * @throws ConfigurationException + */ + protected void buildArtifact() throws InterruptedException, IOException, + ConfigurationException + { + jsTarget = buildJSTarget(); + } + + private IJSApplication buildJSTarget() throws InterruptedException, + FileNotFoundException, ConfigurationException + { + final List<ICompilerProblem> problemsBuildingSWF = new ArrayList<ICompilerProblem>(); + + project.mainCU = mainCU; + final IJSApplication app = buildApplication(project, + config.getMainDefinition(), mainCU, problemsBuildingSWF); + problems.addAll(problemsBuildingSWF); + if (app == null) + { + ICompilerProblem problem = new UnableToBuildSWFProblem( + getOutputFilePath()); + problems.add(problem); + } + + return app; + } + + /** + * Replaces FlexApplicationProject::buildSWF() + * + * @param applicationProject + * @param rootClassName + * @param problems + * @return + * @throws InterruptedException + */ + + private IJSApplication buildApplication(CompilerProject applicationProject, + String rootClassName, ICompilationUnit mainCU, + Collection<ICompilerProblem> problems) throws InterruptedException, + ConfigurationException, FileNotFoundException + { + Collection<ICompilerProblem> fatalProblems = applicationProject.getFatalProblems(); + if (!fatalProblems.isEmpty()) + { + problems.addAll(fatalProblems); + return null; + } + + return ((JSTarget) target).build(mainCU, problems); + } + + /** + * Get the output file path. If {@code -output} is specified, use its value; + * otherwise, use the same base name as the target file. + * + * @return output file path + */ + private String getOutputFilePath() + { + if (config.getOutput() == null) + { + final String extension = "." + project.getBackend().getOutputExtension(); + return FilenameUtils.removeExtension(config.getTargetFile()).concat( + extension); + } + else + return config.getOutput(); + } + + /** + * @author Erik de Bruin + * + * Get the output class file. This includes the (sub)directory in + * which the original class file lives. If the directory structure + * doesn't exist, it is created. + * + * @param qname + * @param outputFolder + * @return output class file path + */ + private File getOutputClassFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension()); + } + + /** + * @param qname + * @param outputFolder + * @return output source map file path + */ + private File getOutputSourceMapFile(String qname, File outputFolder) + { + String[] cname = qname.split("\\."); + String sdirPath = outputFolder + File.separator; + if (cname.length > 0) + { + for (int i = 0, n = cname.length - 1; i < n; i++) + { + sdirPath += cname[i] + File.separator; + } + + File sdir = new File(sdirPath); + if (!sdir.exists()) + sdir.mkdirs(); + + qname = cname[cname.length - 1]; + } + + return new File(sdirPath + qname + "." + project.getBackend().getOutputExtension() + ".map"); + } + + /** + * Mxmlc uses target file as the main compilation unit and derive the output + * SWF file name from this file. + * + * @return true if successful, false otherwise. + * @throws OnlyOneSource + * @throws InterruptedException + */ + protected boolean setupTargetFile() throws InterruptedException + { + final String mainFileName = config.getTargetFile(); + + final String normalizedMainFileName = FilenameNormalization.normalize(mainFileName); + + final SourceCompilationUnitFactory compilationUnitFactory = project.getSourceCompilationUnitFactory(); + + File normalizedMainFile = new File(normalizedMainFileName); + if (compilationUnitFactory.canCreateCompilationUnit(normalizedMainFile)) + { + project.addIncludeSourceFile(normalizedMainFile); + + final List<String> sourcePath = config.getCompilerSourcePath(); + String mainQName = null; + if (sourcePath != null && !sourcePath.isEmpty()) + { + for (String path : sourcePath) + { + final String otherPath = new File(path).getAbsolutePath(); + if (mainFileName.startsWith(otherPath)) + { + mainQName = mainFileName.substring(otherPath.length() + 1); + mainQName = mainQName.replaceAll("\\\\", "/"); + mainQName = mainQName.replaceAll("\\/", "."); + if (mainQName.endsWith(".as")) + mainQName = mainQName.substring(0, + mainQName.length() - 3); + break; + } + } + } + + if (mainQName == null) + mainQName = FilenameUtils.getBaseName(mainFileName); + + Collection<ICompilationUnit> mainFileCompilationUnits = workspace.getCompilationUnits( + normalizedMainFileName, project); + + mainCU = Iterables.getOnlyElement(mainFileCompilationUnits); + + config.setMainDefinition(mainQName); + } + + Preconditions.checkNotNull(mainCU, + "Main compilation unit can't be null"); + + ITargetSettings settings = getTargetSettings(); + if (settings != null) + project.setTargetSettings(settings); + + target = project.getBackend().createTarget(project, + getTargetSettings(), null); + + return true; + } + + private ITargetSettings getTargetSettings() + { + if (targetSettings == null) + targetSettings = projectConfigurator.getTargetSettings(null); + + return targetSettings; + } + + /** + * Create a new Configurator. This method may be overridden to allow + * Configurator subclasses to be created that have custom configurations. + * + * @return a new instance or subclass of {@link Configurator}. + */ + protected Configurator createConfigurator() + { + return project.getBackend().createConfigurator(); + } + + /** + * Load configurations from all the sources. + * + * @param args command line arguments + * @return True if mxmlc should continue with compilation. + */ + protected boolean configure(final String[] args) + { + project.getSourceCompilationUnitFactory().addHandler(asFileHandler); + project.configurator = projectConfigurator = createConfigurator(); + + try + { + if (useFlashBuilderProjectFiles(args)) + { + projectConfigurator.setConfiguration( + FlashBuilderConfigurator.computeFlashBuilderArgs(args, + getTargetType().getExtension()), + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + else + { + projectConfigurator.setConfiguration(args, + ICompilerSettingsConstants.FILE_SPECS_VAR); + } + + projectConfigurator.applyToProject(project); + project.config = (JSGoogConfiguration) projectConfigurator.getConfiguration(); + + config = projectConfigurator.getConfiguration(); + configBuffer = projectConfigurator.getConfigurationBuffer(); + + problems = new ProblemQuery(projectConfigurator.getCompilerProblemSettings()); + problems.addAll(projectConfigurator.getConfigurationProblems()); + + if (configBuffer.getVar("version") != null) //$NON-NLS-1$ + return false; + + if (problems.hasErrors()) + return false; + + validateTargetFile(); + return true; + } + catch (ConfigurationException e) + { + final ICompilerProblem problem = new ConfigurationProblem(e); + problems.add(problem); + return false; + } + catch (Exception e) + { + final ICompilerProblem problem = new ConfigurationProblem(null, -1, + -1, -1, -1, e.getMessage()); + problems.add(problem); + return false; + } + finally + { + if (config == null) + { + config = new Configuration(); + configBuffer = new ConfigurationBuffer(Configuration.class, + Configuration.getAliases()); + } + } + } + + private boolean useFlashBuilderProjectFiles(String[] args) + { + for (String arg : args) + { + if (arg.equals("-fb") + || arg.equals("-use-flashbuilder-project-files")) + return true; + } + return false; + } + + protected TargetType getTargetType() + { + return TargetType.SWF; + } + + /** + * Validate target file. + * + * @throws MustSpecifyTarget + * @throws IOError + */ + protected void validateTargetFile() throws ConfigurationException + { + if (mainCU instanceof ResourceModuleCompilationUnit) + return; //when compiling a Resource Module, no target file is defined. + + final String targetFile = config.getTargetFile(); + if (targetFile == null) + throw new ConfigurationException.MustSpecifyTarget(null, null, -1); + + final File file = new File(targetFile); + if (!file.exists()) + throw new ConfigurationException.IOError(targetFile); + } + + /** + * Wait till the workspace to finish compilation and close. + */ + protected void waitAndClose() + { + workspace.startIdleState(); + try + { + workspace.close(); + } + finally + { + workspace.endIdleState(Collections.<ICompilerProject, Set<ICompilationUnit>> emptyMap()); + } + } + + /** + * Force terminate the compilation process. + */ + protected void close() + { + workspace.close(); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java index 23c5fa1..1afe68f 100644 --- a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java @@ -132,12 +132,12 @@ public class JSGoogPublisher extends JSPublisher implements IJSPublisher // XXX (mschmalle) until we figure out what is going on with this configuration, just skip // HTML generation for JSC output type - String outputType = googConfiguration.getJSOutputType(); - if (!outputType.equals(JSOutputType.JSC.getText())) - { + //String outputType = googConfiguration.getJSOutputType(); + //if (!outputType.equals(JSOutputType.JSC.getText())) + //{ writeHTML("intermediate", projectName, intermediateDirPath); writeHTML("release", projectName, releaseDirPath); - } + //} ArrayList<String> optionList = new ArrayList<String>(); http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/mxml/flexjs/TestFlexJSMXMLApplication.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/mxml/flexjs/TestFlexJSMXMLApplication.java b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/mxml/flexjs/TestFlexJSMXMLApplication.java index 8cb54be..70dec15 100644 --- a/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/mxml/flexjs/TestFlexJSMXMLApplication.java +++ b/compiler-jx/src/test/java/org/apache/flex/compiler/internal/codegen/mxml/flexjs/TestFlexJSMXMLApplication.java @@ -21,13 +21,16 @@ package org.apache.flex.compiler.internal.codegen.mxml.flexjs; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import org.apache.flex.compiler.clients.MXMLJSC; import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitter; 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.projects.FlexJSProject; import org.apache.flex.compiler.internal.test.FlexJSTestBase; +import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.compiler.tree.mxml.IMXMLDocumentNode; import org.apache.flex.compiler.tree.mxml.IMXMLFileNode; +import org.apache.flex.utils.FilenameNormalization; import org.apache.flex.utils.ITestAdapter; import org.apache.flex.utils.TestAdapterFactory; import org.junit.Test; @@ -787,6 +790,27 @@ public class TestFlexJSMXMLApplication extends FlexJSTestBase assertOutMXMLPostProcess(outTemplate.replaceAll("AppName", appName), true); } + @Test + public void testFlexJSMainFileDual() + { + MXMLJSC mxmlc = new MXMLJSC(); + String[] args = new String[7]; + args[0] = "-compiler.targets=SWF,JSFlex"; + args[1] = "-remove-circulars"; + args[2] = "-library-path=" + new File(FilenameNormalization.normalize(env.ASJS + "/frameworks/libs")).getPath(); + args[3] = "-external-library-path+=" + testAdapter.getPlayerglobal().getPath(); + args[4] = "-output=" + new File(testAdapter.getTempDir(), "bin-debug/FlexJSTest_again.swf").getPath(); + if (env.GOOG != null) + args[5] = "-closure-lib=" + new File(FilenameNormalization.normalize(env.GOOG)).getPath(); + else + args[5] = "-define=COMPILE::temp,false"; + args[6] = new File(testAdapter.getUnitTestBaseDir(), "flexjs/files/FlexJSTest_again.mxml").getPath(); + + ArrayList<ICompilerProblem> problems = new ArrayList<ICompilerProblem>(); + int result = mxmlc.mainNoExit(args, problems, true); + assertThat(result, is(0)); + } + @Override protected void addSourcePaths(List<File> sourcePaths) { http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/test/java/org/apache/flex/utils/EnvProperties.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/test/java/org/apache/flex/utils/EnvProperties.java b/compiler-jx/src/test/java/org/apache/flex/utils/EnvProperties.java index ea75057..1b526b8 100644 --- a/compiler-jx/src/test/java/org/apache/flex/utils/EnvProperties.java +++ b/compiler-jx/src/test/java/org/apache/flex/utils/EnvProperties.java @@ -66,6 +66,11 @@ public class EnvProperties { public String ASJS; /** + * GOOG_HOME + */ + public String GOOG; + + /** * PLAYERGLOBAL_VERSION */ public String FPVER; @@ -144,6 +149,9 @@ public class EnvProperties { if (ASJS == null) ASJS = FilenameNormalization.normalize("../../../../flex-asjs"); System.out.println("environment property - ASJS_HOME = " + ASJS); + + GOOG = p.getProperty(prefix + "GOOG_HOME", System.getenv("GOOG_HOME")); + System.out.println("environment property - GOOG_HOME = " + GOOG); } } http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/test/resources/flexjs/files/CSSTestSource.css ---------------------------------------------------------------------- diff --git a/compiler-jx/src/test/resources/flexjs/files/CSSTestSource.css b/compiler-jx/src/test/resources/flexjs/files/CSSTestSource.css index f18dc6f..8b48967 100755 --- a/compiler-jx/src/test/resources/flexjs/files/CSSTestSource.css +++ b/compiler-jx/src/test/resources/flexjs/files/CSSTestSource.css @@ -22,6 +22,12 @@ @namespace basic "library://ns.apache.org/flexjs/basic"; @namespace "http://www.w3.org/1999/xhtml"; +table.tableSection tr>td:last-child +{ /* removing fraction of width i.e 2% to align the tbody columns with thead columns. */ /* It is must as we need to consider the tbody scroll width too */ /* if the width is in pixels, then (width - 18px) would be enough */ width: 31%; } +/** for older browsers (IE8), if you know number of columns in your table **/ +table.tableSection tr>td:first-child + td + td +{ width : 31%; } + /* //---------------------------- // Named styles http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/test/resources/flexjs/files/CSSTestSource_result.css ---------------------------------------------------------------------- diff --git a/compiler-jx/src/test/resources/flexjs/files/CSSTestSource_result.css b/compiler-jx/src/test/resources/flexjs/files/CSSTestSource_result.css index 6a17c84..8cedccd 100755 --- a/compiler-jx/src/test/resources/flexjs/files/CSSTestSource_result.css +++ b/compiler-jx/src/test/resources/flexjs/files/CSSTestSource_result.css @@ -19,6 +19,16 @@ //////////////////////////////////////////////////////////////////////////////// */ /* Generated by Apache Flex Cross-Compiler */ +table.tableSection tr>td:last-child { + width: 31%; +} + + +table.tableSection tr>td:first-child + td + td { + width : 31%; +} + + .glass { border-color: #767473; highlight-alphas: .07 .45; http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/6fced513/compiler-jx/src/test/resources/flexjs/files/MyInitialView.mxml ---------------------------------------------------------------------- diff --git a/compiler-jx/src/test/resources/flexjs/files/MyInitialView.mxml b/compiler-jx/src/test/resources/flexjs/files/MyInitialView.mxml index 1fe77f9..c083269 100644 --- a/compiler-jx/src/test/resources/flexjs/files/MyInitialView.mxml +++ b/compiler-jx/src/test/resources/flexjs/files/MyInitialView.mxml @@ -48,7 +48,7 @@ limitations under the License. return String(comboBox.selectedItem); } - public function startTimer(event:org.apache.flex.events.Event):void + public function startTimer():void { timer = new org.apache.flex.utils.Timer(1000); timer.addEventListener('timer', timerHandler); @@ -69,7 +69,7 @@ limitations under the License. destinationPropertyName="text" /> </basic:beads> </basic:Label> - <basic:TextButton text="Let's Start Timer" x="100" y="75" click="startTimer(event)" /> + <basic:TextButton text="Let's Start Timer" x="100" y="75" click="startTimer()" /> <basic:TextButton text="Stop Timer" x="100" y="100" click="timer.removeEventListener('timer', timerHandler);timer.stop()" /> <basic:Label id="timerLabel" x="100" y="125" />
