| /* |
| * |
| * 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 flex2.tools.oem; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.RandomAccessFile; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| import java.net.URI; |
| |
| import flash.util.Trace; |
| import flex2.compiler.CompilationUnit; |
| import flex2.compiler.CompilerAPI; |
| import flex2.compiler.CompilerException; |
| import flex2.compiler.CompilerSwcContext; |
| import flex2.compiler.FileSpec; |
| import flex2.compiler.ResourceBundlePath; |
| import flex2.compiler.ResourceContainer; |
| import flex2.compiler.Source; |
| import flex2.compiler.SourceList; |
| import flex2.compiler.SourcePath; |
| import flex2.compiler.SubCompiler; |
| import flex2.compiler.SymbolTable; |
| import flex2.compiler.Transcoder; |
| import flex2.compiler.common.CompilerConfiguration; |
| import flex2.compiler.config.ConfigurationException; |
| import flex2.compiler.extensions.ExtensionManager; |
| import flex2.compiler.extensions.ILibraryExtension; |
| import flex2.compiler.i18n.I18nUtils; |
| import flex2.compiler.io.FileUtil; |
| import flex2.compiler.io.LocalFile; |
| import flex2.compiler.io.VirtualFile; |
| import flex2.compiler.swc.SwcAPI; |
| import flex2.compiler.swc.SwcArchive; |
| import flex2.compiler.swc.SwcCache; |
| import flex2.compiler.swc.SwcComponent; |
| import flex2.compiler.swc.SwcDirectoryArchive; |
| import flex2.compiler.swc.SwcLazyReadArchive; |
| import flex2.compiler.swc.SwcException; |
| import flex2.compiler.swc.SwcMovie; |
| import flex2.compiler.util.Benchmark; |
| import flex2.compiler.util.CompilerControl; |
| import flex2.compiler.util.MimeMappings; |
| import flex2.compiler.util.NameFormatter; |
| import flex2.compiler.util.NameMappings; |
| import flex2.compiler.util.PerformanceData; |
| import flex2.compiler.util.QName; |
| import flex2.compiler.util.ThreadLocalToolkit; |
| import flex2.linker.LinkerConfiguration; |
| import flex2.linker.LinkerException; |
| import flex2.linker.SimpleMovie; |
| import flex2.tools.CompcPreLink; |
| import flex2.tools.Mxmlc; |
| import flex2.tools.ToolsConfiguration; |
| import flex2.tools.WebTierAPI; |
| import flex2.tools.oem.internal.LibraryData; |
| import flex2.tools.oem.internal.OEMConfiguration; |
| import flex2.tools.oem.internal.OEMReport; |
| import flex2.tools.oem.internal.OEMUtil; |
| import macromedia.asc.util.ContextStatics; |
| |
| /** |
| * The <code>Library</code> class represents a SWC archive or a RSL. It implements the <code>Builder</code> interface |
| * which allows for building the library incrementally. The following example defines a SWC archive or RSL: |
| * |
| * <pre> |
| * Library lib = new Library(); |
| * </pre> |
| * |
| * You can add components to the <code>Library</code> object in the following ways: |
| * |
| * <pre> |
| * 1. String - Specify a fully-qualified name. |
| * 2. File - Specify a source file. |
| * 3. VirtualLocalFile - Specify an in-memory source object. |
| * 4. URI - Specify a namespace URI. |
| * </pre> |
| * |
| * <p> |
| * To add resource bundles to the <code>Library</code>, you can use the <code>addResourceBundle()</code> method, |
| * as the following example shows: |
| * |
| * <pre> |
| * lib.addResourceBundle("mx.controls")); |
| * </pre> |
| * |
| * <p> |
| * To add archive files to the <code>Library</code>, you can use the <code>addArchiveFile()</code> method, as the following |
| * example shows: |
| * |
| * <pre> |
| * lib.addArchiveFile("defaults.css", new File("path1/myStyle.css")); |
| * </pre> |
| * |
| * Before you can compile with a <code>Library</code> object, you must configure it. The following |
| * four methods are the most common methods you use to configure the <code>Library</code> object: |
| * |
| * <pre> |
| * 1. setLogger() - Use this to set a Logger so that the client can be notified of events that occurred during the compilation. |
| * 2. setConfiguration() - Optional. Use this to specify compiler options. |
| * 3. setOutput() - Optional. Use this to specify an output file name. |
| * 4. setDirectory() - Optional. Use this to specify an RSL output directory. |
| * </pre> |
| * |
| * You must implement the <code>flex2.tools.oem.Logger</code> interface and use the implementation as the <code>Logger</code> |
| * for the compilation. The following is an example <code>Logger</code> implementation: |
| * |
| * <pre> |
| * lib.setLogger(new flex2.tools.oem.Logger() |
| * { |
| * public void log(Message message, int errorCode, String source) |
| * { |
| * System.out.println(message); |
| * } |
| * }); |
| * </pre> |
| * |
| * To specify compiler options for the <code>Library</code> object, you |
| * must get a <code>Configuration</code> object that is populated with default values. Then, you set |
| * compiler options programmatically using methods of the <code>Configuration</code> class. |
| * |
| * <p> |
| * The <code>setOutput()</code> method lets you specify where the <code>Library</code> object writes |
| * the output to. If you call the <code>setOutput()</code> method, the <code>build(boolean)</code> method |
| * writes directly to the specified location; for example: |
| * |
| * <pre> |
| * lib.setOutput(new File("MyLib.swc")); |
| * lib.build(true); |
| * </pre> |
| * |
| * If you do not call the <code>setOutput()</code> method, you can use the <code>build(OutputStream, boolean)</code> |
| * method. This requires that you provide a buffered output stream; for example: |
| * |
| * <pre> |
| * lib.build(new BufferedOutputStream(new FileOutputStream("MyLib.swc")), true); |
| * </pre> |
| * |
| * The <code>setDirectory()</code> method lets you output RSLs to the specified directory; for example: |
| * |
| * <pre> |
| * lib.setDirectory(new File("dir1")); |
| * lib.build(true); |
| * </pre> |
| * |
| * You can save the <code>Library</code> object compilation |
| * data for reuse. You do this using the <code>save(OutputStream)</code> method. Subsequent compilations can use |
| * the <code>load(OutputStream)</code> method to get the old data into the <code>Library</code> object; for example: |
| * |
| * <pre> |
| * lib.save(new BufferedOutputStream(new FileOutputStream("MyLib.incr"))); |
| * </pre> |
| * |
| * When a cache file (for example, <code>MyLib.incr</code>) from a previous compilation is available before the |
| * compilation, you can call the <code>load(OutputStream)</code> method before you call the <code>build()</code> method; for example: |
| * |
| * <pre> |
| * lib.load(new BufferedInputStream(FileInputStream("MyLib.incr"))); |
| * lib.build(true); |
| * </pre> |
| * |
| * The <code>build(false)</code> and <code>build(OutputStream, false)</code> methods always rebuild the library. |
| * The first time you build the <code>Library</code> |
| * object, the <code>build(true)/build(OutputStream, true)</code> methods do a complete build, which |
| * is equivalent to the <code>build(false)/build(OutputStream, false)</code> methods, respectively. After you call the |
| * <code>clean()</code> method, the <code>Library</code> object always does a full build. |
| * |
| * <p> |
| * The <code>clean()</code> method cleans up compilation data in the <code>Library</code> object the output |
| * file, if the <code>setOutput()</code> method was called. |
| * |
| * <p> |
| * You can use the <code>Library</code> class to build a library from a combination of source |
| * files in the file system and in-memory, dynamically-generated source objects. You |
| * must use the <code>addComponent(VirtualLocalFile)</code>, <code>addResourceBundle(VirtualLocalFile)</code>, and |
| * <code>addArchiveFile(String, VirtualLocalFile)</code> methods to use in-memory objects. |
| * |
| * <p> |
| * The <code>Library</code> class can be part of a <code>Project</code>. |
| * |
| * @see flex2.tools.oem.Configuration |
| * @see flex2.tools.oem.Project |
| * @version 2.0.1 |
| */ |
| public class Library implements Builder, Cloneable |
| { |
| static |
| { |
| // This "should" trigger the static initialization of Application which locates |
| // flex-compiler-oem.jar and set application.home correctly. |
| try |
| { |
| // in Java 1.4, simply saying Application.class would load the class |
| // Java 1.5 is much smarter, and you have to coax the JVM to actually load it |
| Class.forName("flex2.tools.oem.Application"); |
| } |
| catch (ClassNotFoundException e) |
| { |
| // I guess it didn't work *shrug* |
| e.printStackTrace(); |
| assert false; |
| } |
| } |
| |
| /** |
| * Constructor. |
| */ |
| public Library() |
| { |
| sources = new TreeSet<VirtualFile>(new Comparator<VirtualFile>() |
| { |
| public int compare(VirtualFile f0, VirtualFile f1) |
| { |
| return f0.getName().compareTo(f1.getName()); |
| } |
| }); |
| classes = new TreeSet<String>(); |
| namespaces = new TreeSet<URI>(); |
| resourceBundles = new TreeSet<String>(); |
| files = new TreeMap<String, VirtualFile>(); |
| stylesheets = new TreeMap<String, VirtualFile>(); |
| |
| oemConfiguration = null; |
| logger = null; |
| output = null; |
| directory = null; |
| mimeMappings = new MimeMappings(); |
| meter = null; |
| resolver = null; |
| cc = new CompilerControl(); |
| |
| data = null; |
| cacheName = null; |
| configurationReport = null; |
| messages = new ArrayList<Message>(); |
| } |
| |
| private Set<VirtualFile> sources; |
| private Set<String> classes, resourceBundles; |
| private Set<URI> namespaces; |
| private Map<String, VirtualFile> files, stylesheets; |
| private OEMConfiguration oemConfiguration; |
| private Logger logger; |
| private File output, directory; |
| private MimeMappings mimeMappings; |
| private ProgressMeter meter; |
| protected PathResolver resolver; |
| private CompilerControl cc; |
| private ApplicationCache applicationCache; |
| private LibraryCache libraryCache; |
| |
| // clean() would null out the following variables |
| LibraryData data; |
| private String cacheName, configurationReport; |
| private List<Message> messages; |
| private HashMap<String, PerformanceData[]> compilerBenchmarks; |
| private Benchmark benchmark; |
| |
| /** |
| * Adds a class, function, variable, or namespace to this <code>Library</code> object. |
| * |
| * This is the equilvalent of the <code>include-classes</code> option of the compc compiler. |
| * |
| * @param includeClass A fully-qualified name. |
| */ |
| public void addComponent(String includeClass) |
| { |
| classes.add(includeClass); |
| } |
| |
| /** |
| * Adds a component to this <code>Library</code> object. |
| * This is the equilvalent of the <code>include-sources</code> option of the compc compiler. |
| * |
| * @param includeSource A source file. |
| */ |
| public void addComponent(File includeSource) |
| { |
| sources.add(new LocalFile(includeSource)); |
| } |
| |
| /** |
| * Adds a component to this <code>Library</code> object. |
| * |
| * This is equilvalent to the <code>include-sources</code> option of the compc compiler. |
| * |
| * @param includeSource An in-memory source object. |
| */ |
| public void addComponent(VirtualLocalFile includeSource) |
| { |
| sources.add(includeSource); |
| } |
| |
| /** |
| * Adds a list of components to this <code>Library</code> object. |
| * |
| * This is equilvalent to the <code>include-namespaces</code> option of the compc compiler. |
| * |
| * @param includeNamespace A namespace URI. |
| */ |
| public void addComponent(URI includeNamespace) |
| { |
| namespaces.add(includeNamespace); |
| } |
| |
| /** |
| * Removes the specified component from this <code>Library</code> object. |
| * The name can be a class, a function, a variable, or a namespace. |
| * |
| * @param includeClass A fully-qualified name. |
| */ |
| public void removeComponent(String includeClass) |
| { |
| classes.remove(includeClass); |
| } |
| |
| /** |
| * Removes the specified component from this <code>Library</code> object. |
| * |
| * @param includeSource A source file. |
| */ |
| public void removeComponent(File includeSource) |
| { |
| sources.remove(new LocalFile(includeSource)); |
| } |
| |
| /** |
| * Removes the specified component from this <code>Library</code> object. |
| * |
| * @param includeSource An in-memory source object. |
| */ |
| public void removeComponent(VirtualLocalFile includeSource) |
| { |
| sources.remove(includeSource); |
| } |
| |
| /** |
| * Removes the specified list of components from this <code>Library</code> object. The input argument is a namespace URI. |
| * |
| * @param includeNamespace A namespace URI. |
| */ |
| public void removeComponent(URI includeNamespace) |
| { |
| namespaces.remove(includeNamespace); |
| } |
| |
| /** |
| * Removes all the components from this <code>Library</code> object. |
| */ |
| public void removeAllComponents() |
| { |
| sources.clear(); |
| classes.clear(); |
| namespaces.clear(); |
| } |
| |
| /** |
| * Adds a resource bundle to this <code>Library</code> object. |
| * |
| * This is equilvalent to the <code>include-resource-bundles</code> option of the compc compiler. |
| * |
| * @param resourceBundle A resource bundle name. |
| */ |
| public void addResourceBundle(String resourceBundle) |
| { |
| resourceBundles.add(resourceBundle); |
| } |
| |
| /** |
| * Removes the specified resource bundle name from this <code>Library</code> object. |
| * |
| * @param resourceBundle A resource bundle name. |
| */ |
| public void removeResourceBundle(String resourceBundle) |
| { |
| resourceBundles.remove(resourceBundle); |
| } |
| |
| /** |
| * Removes all the resource bundles from this <code>Library</code> object. |
| * |
| */ |
| public void removeAllResourceBundles() |
| { |
| resourceBundles.clear(); |
| } |
| |
| /** |
| * Adds a file to this <code>Library</code> object. This is equilvalent to the <code>include-file</code> option of the compc compiler. |
| * |
| * @param name The name in the archive. |
| * @param file The file to be added. |
| */ |
| public void addArchiveFile(String name, File file) |
| { |
| files.put(name, new LocalFile(file)); |
| } |
| |
| /** |
| * Adds an in-memory source object to this <code>Library</code> object. This is equilvalent to the <code> |
| * include-file</code> option of the compc compiler. |
| * |
| * @param name The name in the archive. |
| * @param file The in-memory source object to be added. |
| */ |
| public void addArchiveFile(String name, VirtualLocalFile file) |
| { |
| files.put(name, file); |
| } |
| |
| /** |
| * Removes the specified file from this <code>Library</code> object. |
| * |
| * @param name The name in the archive. |
| */ |
| public void removeArchiveFile(String name) |
| { |
| files.remove(name); |
| } |
| |
| /** |
| * Removes all the archive files from this <code>Library</code> object. |
| */ |
| public void removeAllArchiveFiles() |
| { |
| files.clear(); |
| } |
| |
| /** |
| * Adds a CSS stylesheet to this <code>Library</code> object. This is equilvalent to the <code>include-stylesheet</code> option of the compc compiler. |
| * |
| * @param name The name in the archive. |
| * @param file The file to be added. |
| * @since 3.0 |
| */ |
| public void addStyleSheet(String name, File file) |
| { |
| stylesheets.put(name, new LocalFile(file)); |
| } |
| |
| /** |
| * Adds an in-memory CSS stylesheet object to this <code>Library</code> object. This is equilvalent to the <code> |
| * include-stylesheet</code> option of the compc compiler. |
| * |
| * @param name The name in the archive. |
| * @param file The in-memory source object to be added. |
| * @since 3.0 |
| */ |
| public void addStyleSheet(String name, VirtualLocalFile file) |
| { |
| stylesheets.put(name, file); |
| } |
| |
| /** |
| * Removes the specified CSS stylesheet from this <code>Library</code> object. |
| * |
| * @param name The name in the archive. |
| * @since 3.0 |
| */ |
| public void removeStyleSheet(String name) |
| { |
| stylesheets.remove(name); |
| } |
| |
| /** |
| * Removes all the CSS stylesheets from this <code>Library</code> object. |
| * @since 3.0 |
| */ |
| public void removeAllStyleSheets() |
| { |
| stylesheets.clear(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setConfiguration(Configuration configuration) |
| { |
| oemConfiguration = (OEMConfiguration) configuration; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Configuration getDefaultConfiguration() |
| { |
| return getDefaultConfiguration(false); |
| } |
| |
| /** |
| * |
| * @param processDefaults |
| * @return |
| */ |
| private Configuration getDefaultConfiguration(boolean processDefaults) |
| { |
| return OEMUtil.getLibraryConfiguration(constructCommandLine(null), false, false, |
| OEMUtil.getLogger(logger, messages), resolver, |
| mimeMappings, processDefaults); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public HashMap<String, PerformanceData[]> getCompilerBenchmarks() |
| { |
| return compilerBenchmarks; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Benchmark getBenchmark() |
| { |
| return benchmark; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Configuration getConfiguration() |
| { |
| return oemConfiguration; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setLogger(Logger logger) |
| { |
| this.logger = logger; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Logger getLogger() |
| { |
| return logger; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setSupportedFileExtensions(String mimeType, String[] extensions) |
| { |
| mimeMappings.set(mimeType, extensions); |
| } |
| |
| /** |
| * Sets the output destination. This method is necessary if you use the <code>build(boolean)</code> method. |
| * If you use the <code>build(OutputStream, boolean)</code> method, there is no need to use this method. |
| * |
| * @param output An instance of the <code>java.io.File</code> class. |
| */ |
| public void setOutput(File output) |
| { |
| this.output = output; |
| } |
| |
| /** |
| * Gets the output destination. This method returns <code>null</code> if you did not call the |
| * <code>setOutput()</code> method. |
| * |
| * @return An instance of the <code>java.io.File</code> class, or <code>null</code> if you did not |
| * call the <code>setOutput()</code> method. |
| */ |
| public File getOutput() |
| { |
| return output; |
| } |
| |
| /** |
| * Sets the RSL output directory. |
| * |
| * @param directory An RSL directory. |
| */ |
| public void setDirectory(File directory) |
| { |
| this.directory = directory; |
| } |
| |
| /** |
| * Gets the RSL output directory. |
| * |
| * @return A <code>java.io.File</code>, or <code>null</code> if you did not call the <code>setDirectory()</code> method. |
| */ |
| public File getDirectory() |
| { |
| return directory; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setProgressMeter(ProgressMeter meter) |
| { |
| this.meter = meter; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void setPathResolver(PathResolver resolver) |
| { |
| this.resolver = resolver; |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| // IMPORTANT: If you make changes here, you probably want to mirror them in Application.build() |
| public long build(boolean incremental) throws IOException |
| { |
| // I know that directory is not referenced anywhere in here... |
| // if you setDirectory but do not setOutput, then output==null but dirctory!=null |
| // so this silly looking IF needs to be like this... |
| if (output != null || directory != null) |
| { |
| long size = 0; |
| |
| //TODO PERFORMANCE: A lot of unnecessary recopying and buffering here |
| try |
| { |
| int result = compile(incremental); |
| |
| if (result == SKIP || result == LINK || result == OK) |
| { |
| size = link(null); |
| } |
| |
| return size; |
| } |
| finally |
| { |
| if ((output != null) && (data != null) && (data.swcCache != null)) |
| { |
| refreshLastModified(); |
| } |
| |
| if ((benchmark != null) && benchmark.hasStarted(Benchmark.POSTCOMPILE)) |
| { |
| benchmark.stopTime(Benchmark.POSTCOMPILE, false); |
| } |
| |
| runExtensions(); |
| |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| private void runExtensions() |
| { |
| if (oemConfiguration != null) |
| { |
| Set<ILibraryExtension> extensions = ExtensionManager.getLibraryExtensions( oemConfiguration.getExtensions() ); |
| |
| for ( ILibraryExtension extension : extensions ) |
| { |
| if (ThreadLocalToolkit.errorCount() == 0) |
| { |
| extension.run( this.clone(), oemConfiguration.clone() ); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * Note: If the OutputStream is written to a File, |
| * refreshLastModified() should be called to update the timestamp |
| * in the SwcCache. Otherwise, subsequent builds in this Project |
| * will think the Library has been externally updated and will |
| * force a reload. |
| */ |
| public long build(OutputStream out, boolean incremental) throws IOException |
| { |
| try |
| { |
| int result = compile(incremental); |
| |
| if (result == SKIP || result == LINK || result == OK) |
| { |
| return link(out); |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| finally |
| { |
| if ((benchmark != null) && benchmark.hasStarted(Benchmark.POSTCOMPILE)) |
| { |
| benchmark.stopTime(Benchmark.POSTCOMPILE, false); |
| } |
| |
| runExtensions(); |
| |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| } |
| |
| /** |
| * @param fullRecompile if true a full recompile is needed, do not attempted to use cache file. |
| * |
| * @return {@link Builder#OK} if this method call resulted in compilation of some/all parts of the application; |
| * {@link Builder#LINK} if this method call did not compile anything in the application but advise the caller to link again; |
| * {@link Builder#SKIP} if this method call did not compile anything in the application; |
| * {@link Builder#FAIL} if this method call encountered errors during compilation. |
| */ |
| private int recompile(boolean fullRecompile, Map licenseMap, OEMConfiguration localOEMConfiguration) |
| { |
| data = new LibraryData(); |
| data.configuration = localOEMConfiguration.configuration; |
| data.cacheName = cacheName; |
| |
| NameMappings mappings = CompilerAPI.getNameMappings(localOEMConfiguration.configuration), copy = mappings.copy(); |
| |
| CompilerConfiguration compilerConfig = localOEMConfiguration.configuration.getCompilerConfiguration(); |
| compilerConfig.setMetadataExport(true); |
| |
| if (output != null || directory != null) |
| { |
| OEMUtil.setGeneratedDirectory(compilerConfig, output != null ? output : directory); |
| } |
| |
| Transcoder[] transcoders = WebTierAPI.getTranscoders( localOEMConfiguration.configuration ); |
| SubCompiler[] compilers = WebTierAPI.getCompilers(compilerConfig, mappings, transcoders); |
| |
| if ((data.fileSet = processSources(compilerConfig)) == null) |
| { |
| return FAIL; |
| } |
| |
| data.fileSet.addAll(processStylesheets()); |
| |
| if (!setupSourceContainers(localOEMConfiguration.configuration, data.fileSet)) |
| { |
| return FAIL; |
| } |
| |
| // Setup SWC cache |
| if (libraryCache != null) |
| { |
| ContextStatics contextStatics = libraryCache.getContextStatics(); |
| |
| if (contextStatics != null) |
| { |
| // Clear out ASC's userDefined, so definitions from a |
| // previous compilation don't spill over into this one. |
| contextStatics.userDefined.clear(); |
| data.perCompileData = contextStatics; |
| data.swcCache = libraryCache.getSwcCache(); |
| } |
| } |
| |
| if (data.swcCache == null) |
| { |
| data.swcCache = new SwcCache(); |
| } |
| |
| // load SWCs |
| CompilerSwcContext swcContext = new CompilerSwcContext(true); |
| try |
| { |
| swcContext.load( compilerConfig.getLibraryPath(), |
| compilerConfig.getExternalLibraryPath(), |
| null, |
| compilerConfig.getIncludeLibraries(), |
| mappings, |
| I18nUtils.getTranslationFormat(compilerConfig), |
| data.swcCache ); |
| } |
| catch (SwcException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| return FAIL; |
| } |
| |
| // save the generated cache if the caller provided a libraryCache. |
| if (libraryCache != null) |
| { |
| libraryCache.setSwcCache(data.swcCache); |
| } |
| |
| data.includes = new HashSet<String>(swcContext.getIncludes()); |
| data.excludes = new HashSet<String>(swcContext.getExterns()); |
| localOEMConfiguration.configuration.addExterns( swcContext.getExterns() ); |
| localOEMConfiguration.configuration.addIncludes( swcContext.getIncludes() ); |
| data.swcArchiveFiles = new HashMap<String, VirtualFile>(swcContext.getIncludeFiles()); |
| |
| // The ToolsConfiguration expects class names in QName format. |
| Set<String> qNameClasses = new HashSet<String>(); |
| for (String className : classes) |
| { |
| qNameClasses.add(NameFormatter.toColon(className)); |
| } |
| |
| // Allow -include-classes to override the -external-library-path. |
| localOEMConfiguration.configuration.removeExterns(qNameClasses); |
| |
| // If we want only inheritance dependencies of -include-classes then |
| // add the classes to the includes list. When |
| // -include-inheritance-dependencies-only is turned on the dependency |
| // walker will ignore all the classes except for the includes. |
| if (localOEMConfiguration.configuration.getIncludeInheritanceDependenciesOnly()) |
| { |
| localOEMConfiguration.configuration.addIncludes(qNameClasses); |
| } |
| |
| data.cmdChecksum = localOEMConfiguration.cfgbuf.checksum_ts(); |
| data.linkChecksum = localOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| int[] checksums = new int[] { 0, data.cmdChecksum, data.linkChecksum, data.swcChecksum }; |
| boolean clearCache = false; |
| |
| // C: must do loadCompilationUnits() after checksum calculation... |
| if (!fullRecompile) |
| { |
| if (!loadCompilationUnits(localOEMConfiguration.configuration, data.fileSet, swcContext, checksums)) |
| { |
| return FAIL; |
| } |
| |
| data.checksum = checksums[0]; |
| if (data.units != null && |
| data.units.size() > 0 && |
| OEMUtil.isRecompilationNeeded(data, swcContext, localOEMConfiguration)) |
| { |
| if (!setupSourceContainers(localOEMConfiguration.configuration, data.fileSet)) |
| { |
| return FAIL; |
| } |
| clearCache = true; |
| } |
| } |
| else |
| { |
| clearCache = true; |
| } |
| |
| if (clearCache && (libraryCache != null) && (output != null)) |
| { |
| String path = FileUtil.getCanonicalPath(output); |
| libraryCache.getSwcCache().remove(path); |
| } |
| |
| // validate CompilationUnits... |
| int count = CompilerAPI.validateCompilationUnits(data.fileSpec, data.sourceList, data.sourcePath, data.bundlePath, |
| data.resources, swcContext, data.classes, data.perCompileData, |
| localOEMConfiguration.configuration); |
| |
| SymbolTable symbolTable; |
| |
| if (data.perCompileData != null) |
| { |
| symbolTable = new SymbolTable(localOEMConfiguration.configuration, data.perCompileData); |
| } |
| else |
| { |
| symbolTable = new SymbolTable(localOEMConfiguration.configuration); |
| data.perCompileData = symbolTable.perCompileData; |
| |
| if (libraryCache != null) |
| { |
| libraryCache.setContextStatics(data.perCompileData); |
| } |
| } |
| |
| Map<String, Source> classes = new TreeMap<String, Source>(); |
| if ((data.nsComponents = processInputs(swcContext, copy, classes)) == null) |
| { |
| return FAIL; |
| } |
| |
| // Only updated the LibraryData's classes if processInputs() |
| // is successful. |
| data.classes = classes; |
| data.sources = new ArrayList<Source>(); |
| data.units = compile(compilers, swcContext, symbolTable, mappings, licenseMap, data.classes, data.sources); |
| |
| // need to update the checksum here since doing a compile could add some |
| // some signature checksums and change it. |
| data.checksum = OEMUtil.calculateChecksum(data, swcContext, localOEMConfiguration); |
| boolean forcedToStop = CompilerAPI.forcedToStop(); |
| |
| if (data.units == null || forcedToStop) |
| { |
| return FAIL; |
| } |
| else |
| { |
| return OK; |
| } |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void stop() |
| { |
| cc.stop(); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void clean() |
| { |
| clean(true /* cleanData */, |
| true /* cleanCache */, |
| true /* cleanOutput */, |
| true /* cleanConfig */, |
| true /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public void load(InputStream in) throws IOException |
| { |
| cacheName = OEMUtil.load(in, cacheName); |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public long save(OutputStream out) throws IOException |
| { |
| return OEMUtil.save(out, cacheName, data); |
| } |
| |
| /** |
| * @inheritDoc |
| */ |
| public Report getReport() |
| { |
| OEMUtil.setupLocalizationManager(); |
| return new OEMReport(data == null ? null : data.sources, |
| data == null ? null : data.movie, |
| data == null ? null : data.configuration, |
| data == null ? null : data.sourceList, |
| configurationReport, |
| messages, files); |
| } |
| |
| /** |
| * |
| * @param c |
| * @return |
| */ |
| private String[] constructCommandLine(OEMConfiguration localOEMConfiguration) |
| { |
| String[] commandLine = (localOEMConfiguration != null) ? localOEMConfiguration.getCompilerOptions() : |
| new String[0]; |
| |
| // Translate "classes" into "-include-classes" so the CompcConfiguration can |
| // properly validate the configuration. |
| if (classes.size() > 0) |
| { |
| StringBuilder buffer = new StringBuilder("-include-classes="); |
| |
| for (Iterator<String> iter = classes.iterator(); iter.hasNext();) |
| { |
| String className = iter.next(); |
| buffer.append(className); |
| if (iter.hasNext()) |
| { |
| buffer.append(","); |
| } |
| } |
| |
| String[] newCommandLine = new String[commandLine.length + 1]; |
| System.arraycopy(commandLine, 0, newCommandLine, 0, commandLine.length); |
| newCommandLine[commandLine.length] = buffer.toString(); |
| |
| return newCommandLine; |
| } |
| |
| return commandLine; |
| } |
| |
| /** |
| * |
| * @param swcContext |
| * @param mappings |
| * @param classes |
| * @return |
| */ |
| private Set<SwcComponent> processInputs(CompilerSwcContext swcContext, NameMappings mappings, Map<String, Source> classes) |
| { |
| try |
| { |
| Set<SwcComponent> nsComponents = processNamespaces(mappings, classes); |
| if (nsComponents == null) |
| { |
| return null; |
| } |
| |
| if (!processClasses(classes)) |
| { |
| return null; |
| } |
| |
| for (Map.Entry<String, Source> entry : classes.entrySet()) |
| { |
| Source source = entry.getValue(); |
| String namespaceURI = source.getRelativePath().replace('/', '.'); |
| String localPart = source.getShortName(); |
| Source swcSource = (swcContext != null) ? swcContext.getSource(namespaceURI, localPart) : null; |
| |
| // No sense recompiling the same source file again. |
| if ((swcSource != null) && |
| ((source.getLastModified() == swcSource.getLastModified()) && |
| ((source.getCompilationUnit() == null) || |
| (!source.getCompilationUnit().hasTypeInfo)))) |
| { |
| classes.put(entry.getKey(), swcSource); |
| } |
| } |
| |
| return nsComponents; |
| } |
| catch (SwcException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| assert ThreadLocalToolkit.errorCount() > 0; |
| return null; |
| } |
| } |
| |
| /** |
| * |
| * @param classes |
| * @return |
| */ |
| private boolean processClasses(Map<String, Source> classes) |
| { |
| try |
| { |
| SwcAPI.setupClasses(new ArrayList<String>(this.classes), data.sourcePath, data.sourceList, classes); |
| return true; |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| return false; |
| } |
| } |
| |
| /** |
| * This must be called before CompilerSwcContext.load(). |
| * |
| * @param mappings |
| * @param classes |
| * @return |
| */ |
| private Set<SwcComponent> processNamespaces(NameMappings mappings, Map<String, Source> classes) |
| { |
| Set<SwcComponent> nsComponents = null; |
| |
| try |
| { |
| List<SwcComponent> list = SwcAPI.setupNamespaceComponents(toStrings(namespaces), mappings, |
| data.sourcePath, data.sourceList, |
| classes); |
| nsComponents = new TreeSet<SwcComponent>(new Comparator<SwcComponent>() |
| { |
| public int compare(SwcComponent c0, SwcComponent c1) |
| { |
| return c0.getClassName().compareTo(c1.getClassName()); |
| } |
| }); |
| nsComponents.addAll(list); |
| } |
| catch (ConfigurationException ex) |
| { |
| Mxmlc.processConfigurationException(ex, "oem"); |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| |
| return nsComponents; |
| } |
| |
| /** |
| * |
| * @param set |
| * @return |
| */ |
| private List<String> toStrings(Set<URI> set) |
| { |
| List<String> a = new ArrayList<String>(set.size()); |
| for (Iterator<URI> i = set.iterator(); i.hasNext(); ) |
| { |
| URI uri = i.next(); |
| a.add(uri.toString()); |
| } |
| return a; |
| } |
| |
| /** |
| * @param configuration |
| * @param fileList |
| * @return true, unless a CompilerException occurs. |
| */ |
| private boolean setupSourceContainers(flex2.compiler.common.Configuration configuration, Set<VirtualFile> fileSet) |
| { |
| CompilerConfiguration compilerConfig = configuration.getCompilerConfiguration(); |
| VirtualFile[] asClasspath = compilerConfig.getSourcePath(); |
| boolean result = false; |
| |
| try |
| { |
| // create a SourcePath... |
| data.sourcePath = new SourcePath(WebTierAPI.getSourcePathMimeTypes(), |
| compilerConfig.allowSourcePathOverlap()); |
| data.sourcePath.addPathElements( asClasspath ); |
| |
| List<VirtualFile>[] array = CompilerAPI.getVirtualFileList(fileSet, data.sourcePath.getPaths()); |
| |
| // create a FileSpec... |
| data.fileSpec = new FileSpec(array[0], WebTierAPI.getFileSpecMimeTypes(), false); |
| |
| // create a SourceList... |
| data.sourceList = new SourceList(array[1], asClasspath, null, WebTierAPI.getSourceListMimeTypes(), false); |
| |
| // create a ResourceContainer... |
| data.resources = new ResourceContainer(); |
| |
| // create a ResourceBundlePath... |
| data.bundlePath = new ResourceBundlePath(compilerConfig, null); |
| |
| // clear these... |
| if (data.sources != null) data.sources.clear(); |
| if (data.units != null) data.units.clear(); |
| if (data.swcDefSignatureChecksums != null) data.swcDefSignatureChecksums.clear(); |
| if (data.swcFileChecksums != null) data.swcFileChecksums.clear(); |
| |
| result = true; |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Convert the set of sources, which might include directories and |
| * files with tokens in the name, into a set of resolved |
| * VirtualFiles. |
| * |
| * @return |
| */ |
| private Set<VirtualFile> processSources(CompilerConfiguration compilerConfiguration) |
| { |
| Set<VirtualFile> fileSet = null; |
| |
| try |
| { |
| // Create a list of LocalFile paths and remove the LocalFiles "sources". |
| List<String> localPathList = new ArrayList<String>(); |
| |
| for (Iterator<VirtualFile> iterator = sources.iterator(); iterator.hasNext();) |
| { |
| VirtualFile virtualFile = iterator.next(); |
| |
| if (virtualFile instanceof LocalFile) |
| { |
| localPathList.add(virtualFile.getName()); |
| iterator.remove(); |
| } |
| } |
| |
| // Convert the localPathList to an Array |
| String[] localPathArray = new String[localPathList.size()]; |
| int i = 0; |
| |
| for (String localPath : localPathList) |
| { |
| localPathArray[i++] = localPath; |
| } |
| |
| VirtualFile[] virtualFileArray = |
| compilerConfiguration.expandTokens(localPathArray, compilerConfiguration.getLocales(), null); |
| |
| // Add the token expanded VirtualFile's back into "sources". |
| for (VirtualFile virtualFile : virtualFileArray) |
| { |
| sources.add(virtualFile); |
| } |
| |
| List<VirtualFile> fileList = |
| CompilerAPI.getVirtualFileList(sources, new HashSet<String>(Arrays.asList(WebTierAPI.getSourcePathMimeTypes()))); |
| fileSet = new TreeSet<VirtualFile>(new Comparator<VirtualFile>() |
| { |
| public int compare(VirtualFile f0, VirtualFile f1) |
| { |
| return f0.getName().compareTo(f1.getName()); |
| } |
| }); |
| fileSet.addAll(fileList); |
| } |
| catch (ConfigurationException ex) |
| { |
| Mxmlc.processConfigurationException(ex, "oem"); |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| |
| return fileSet; |
| } |
| |
| /** |
| * |
| * @return |
| */ |
| private Set<VirtualFile> processStylesheets() |
| { |
| Set<VirtualFile> fileSet = null; |
| |
| try |
| { |
| List<VirtualFile> fileList = CompilerAPI.getVirtualFileList(new ArrayList<VirtualFile>(stylesheets.values()), new HashSet<String>(Arrays.asList(new String[] { MimeMappings.CSS }))); |
| fileSet = new TreeSet<VirtualFile>(new Comparator<VirtualFile>() |
| { |
| public int compare(VirtualFile f0, VirtualFile f1) |
| { |
| return f0.getName().compareTo(f1.getName()); |
| } |
| }); |
| fileSet.addAll(fileList); |
| } |
| catch (ConfigurationException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| |
| return fileSet; |
| } |
| |
| /** |
| * |
| * @param configuration |
| * @param fileList |
| * @return |
| */ |
| private boolean loadCompilationUnits(ToolsConfiguration configuration, Set fileSet, CompilerSwcContext swcContext, int[] checksums) |
| { |
| if (data.cacheName == null) // note: NOT (cacheName == null) |
| { |
| return true; |
| } |
| |
| RandomAccessFile cacheFile = null; |
| |
| try |
| { |
| cacheFile = new RandomAccessFile(data.cacheName, "r"); |
| CompilerAPI.loadCompilationUnits(configuration, data.fileSpec, data.sourceList, |
| data.sourcePath, data.resources, data.bundlePath, |
| data.sources = new ArrayList<Source>(), |
| data.units = new ArrayList<CompilationUnit>(), |
| checksums, |
| data.swcDefSignatureChecksums = new HashMap<QName, Long>(), |
| data.swcFileChecksums = new HashMap<String, Long>(), |
| cacheFile, data.cacheName); |
| |
| /* |
| for (int i = 0, size = data.sources.size(); i < size; i++) |
| { |
| Object obj = data.sources.get(i); |
| if (obj instanceof String) |
| { |
| String name = (String) obj; |
| Source s = swcContext.getSource(name); |
| data.sources.set(i, s); |
| data.units.set(i, s != null ? s.getCompilationUnit() : null); |
| } |
| } |
| */ |
| } |
| catch (FileNotFoundException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getMessage()); |
| // if the cache file is not found, no big deal... return true so that we recompile. |
| return true; |
| } |
| catch (IOException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getMessage()); |
| |
| if (!setupSourceContainers(configuration, fileSet)) |
| { |
| return false; |
| } |
| } |
| finally |
| { |
| if (cacheFile != null) try { cacheFile.close(); } catch (IOException ex) {} |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Compiles the <code>Library</code>. This method does not link the <code>Library</code>. |
| * |
| * @param incremental If <code>true</code>, build incrementally; if <code>false</code>, rebuild. |
| * @return {@link Builder#OK} if this method call resulted in compilation of some/all parts of the application; |
| * {@link Builder#LINK} if this method call did not compile anything in the application but advise the caller to link again; |
| * {@link Builder#SKIP} if this method call did not compile anything in the application; |
| * {@link Builder#FAIL} if this method call encountered errors during compilation. |
| */ |
| protected int compile(boolean incremental) |
| { |
| try |
| { |
| messages.clear(); |
| |
| // if there is no configuration, use the default... but don't populate this.configuration. |
| OEMConfiguration tempOEMConfiguration; |
| |
| if (oemConfiguration == null) |
| { |
| tempOEMConfiguration = (OEMConfiguration) getDefaultConfiguration(true); |
| } |
| else |
| { |
| tempOEMConfiguration = OEMUtil.getLibraryConfiguration(constructCommandLine(oemConfiguration), |
| oemConfiguration.keepLinkReport(), |
| oemConfiguration.keepSizeReport(), |
| OEMUtil.getLogger(logger, messages), |
| resolver, mimeMappings); |
| } |
| |
| // if c is null, which indicates problems, this method will return. |
| if (tempOEMConfiguration == null) |
| { |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return FAIL; |
| } |
| else if (oemConfiguration != null && oemConfiguration.keepConfigurationReport()) |
| { |
| configurationReport = OEMUtil.formatConfigurationBuffer(tempOEMConfiguration.cfgbuf); |
| } |
| |
| if (oemConfiguration != null) |
| { |
| oemConfiguration.cfgbuf = tempOEMConfiguration.cfgbuf; |
| } |
| |
| if (tempOEMConfiguration.configuration.benchmark()) |
| { |
| benchmark = CompilerAPI.runBenchmark(); |
| benchmark.setTimeFilter(tempOEMConfiguration.configuration.getBenchmarkTimeFilter()); |
| benchmark.startTime(Benchmark.PRECOMPILE); |
| } |
| else |
| { |
| CompilerAPI.disableBenchmark(); |
| } |
| |
| // add archive files to the link checksum |
| for (Map.Entry<String, VirtualFile>entry : files.entrySet()) |
| { |
| tempOEMConfiguration.cfgbuf.calculateLinkChecksum(entry.getKey(), entry.getValue().getLastModified()); |
| } |
| |
| // initialize some ThreadLocal variables... |
| cc.run(); |
| OEMUtil.init(OEMUtil.getLogger(logger, messages), mimeMappings, meter, resolver, cc); |
| |
| // if there is any problem getting the licenses, this method will return. |
| Map licenseMap = OEMUtil.getLicenseMap(tempOEMConfiguration.configuration); |
| |
| // if there are no SWC inputs, output an error and return -1 |
| VirtualFile[] includeLibs = (tempOEMConfiguration.configuration == null) ? null : tempOEMConfiguration.configuration.getCompilerConfiguration().getIncludeLibraries(); |
| if (sources.size() == 0 && classes.size() == 0 && namespaces.size() == 0 && |
| resourceBundles.size() == 0 && files.size() == 0 && stylesheets.size() == 0 && |
| (includeLibs == null || includeLibs.length == 0)) |
| { |
| ThreadLocalToolkit.log(new ConfigurationException.NoSwcInputs( null, null, -1 )); |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return FAIL; |
| } |
| |
| // if nothing has been built yet, let's rebuild. |
| if (data == null || !incremental) |
| { |
| String compilationType = (cacheName != null) ? "inactive" : "full"; |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Starting " + compilationType + " compile for " + getOutput(), true); |
| } |
| |
| int returnValue = recompile(false, licenseMap, tempOEMConfiguration); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending " + compilationType + " compile for " + getOutput(), true); |
| } |
| |
| clean(returnValue != OK, false, false); |
| return returnValue; |
| } |
| |
| CompilerAPI.setupHeadless(tempOEMConfiguration.configuration); |
| NameMappings mappings = CompilerAPI.getNameMappings(tempOEMConfiguration.configuration), copy = mappings.copy(); |
| |
| // Clear out ASC's userDefined, so definitions from a |
| // previous compilation don't spill over into this one. |
| data.perCompileData.userDefined.clear(); |
| |
| data.sourcePath.clearCache(); |
| data.bundlePath.clearCache(); |
| data.resources.refresh(); |
| |
| CompilerConfiguration compilerConfig = tempOEMConfiguration.configuration.getCompilerConfiguration(); |
| compilerConfig.setMetadataExport(true); |
| |
| if (output != null || directory != null) |
| { |
| OEMUtil.setGeneratedDirectory(compilerConfig, output != null ? output : directory); |
| } |
| |
| Transcoder[] transcoders = WebTierAPI.getTranscoders(tempOEMConfiguration.configuration); |
| SubCompiler[] compilers = WebTierAPI.getCompilers(compilerConfig, mappings, transcoders); |
| |
| CompilerSwcContext swcContext = new CompilerSwcContext(true); |
| try |
| { |
| swcContext.load( compilerConfig.getLibraryPath(), |
| compilerConfig.getExternalLibraryPath(), |
| null, |
| compilerConfig.getIncludeLibraries(), |
| mappings, |
| I18nUtils.getTranslationFormat(compilerConfig), |
| data.swcCache ); |
| } |
| catch (SwcException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return FAIL; |
| } |
| |
| // save the generated swcCache if the class has a libraryCache. |
| if (libraryCache != null) |
| { |
| libraryCache.setSwcCache(data.swcCache); |
| } |
| |
| // If checksum is different, rebuild. |
| if (OEMUtil.isRecompilationNeeded(data, swcContext, tempOEMConfiguration)) |
| { |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Starting full compile for " + getOutput(), true); |
| } |
| |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| int returnValue = recompile(true, licenseMap, tempOEMConfiguration); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending full compile for " + getOutput(), true); |
| } |
| |
| clean(returnValue != OK, false, false); |
| return returnValue; |
| } |
| |
| // If --include-sources is different, rebuild. |
| Set<VirtualFile> fileSet = null; |
| if ((fileSet = processSources(compilerConfig)) == null) |
| { |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return FAIL; |
| } |
| |
| // If --include-stylesheets is different, rebuild. |
| fileSet.addAll(processStylesheets()); |
| |
| boolean isFileSpecDifferent = isDifferent(data.fileSet, fileSet); |
| if (isFileSpecDifferent) |
| { |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Starting full compile for " + getOutput(), true); |
| } |
| |
| clean(true /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| int returnValue = recompile(true, licenseMap, tempOEMConfiguration); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending full compile for " + getOutput(), true); |
| } |
| |
| clean(returnValue != OK, false, false); |
| return returnValue; |
| } |
| |
| if (benchmark != null) |
| { |
| // We aren't really starting the compile here, but it's |
| // the earliest that we know that it's going to be an |
| // active compilation. |
| benchmark.benchmark2("Starting active compile for " + getOutput(), true); |
| } |
| |
| data.includes = new HashSet<String>(swcContext.getIncludes()); |
| data.excludes = new HashSet<String>(swcContext.getExterns()); |
| tempOEMConfiguration.configuration.addExterns( swcContext.getExterns() ); |
| tempOEMConfiguration.configuration.addIncludes( swcContext.getIncludes() ); |
| data.swcArchiveFiles = new HashMap<String, VirtualFile>(swcContext.getIncludeFiles()); |
| |
| // The ToolsConfiguration expects class names in QName format. |
| Set<String> qNameClasses = new HashSet<String>(); |
| for (String className : classes) |
| { |
| qNameClasses.add(NameFormatter.toColon(className)); |
| } |
| |
| // Allow -include-classes to override the -external-library-path. |
| tempOEMConfiguration.configuration.removeExterns(qNameClasses); |
| |
| // If we want only inheritance dependencies of -include-classes then |
| // add the classes to the includes list. When |
| // -include-inheritance-dependencies-only is turned on the dependency |
| // walker will ignore all the classes except for the includes. |
| if (tempOEMConfiguration.configuration.getIncludeInheritanceDependenciesOnly()) |
| { |
| tempOEMConfiguration.configuration.addIncludes(qNameClasses); |
| } |
| |
| int count = CompilerAPI.validateCompilationUnits(data.fileSpec, data.sourceList, data.sourcePath, |
| data.bundlePath, data.resources, swcContext, |
| data.classes, data.perCompileData, |
| tempOEMConfiguration.configuration); |
| |
| Map<String, Source> classes = new TreeMap<String, Source>(); |
| Set<SwcComponent> nsComponents = null; |
| |
| if ((nsComponents = processInputs(swcContext, copy, classes)) == null) |
| { |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return FAIL; |
| } |
| |
| // If the other --include-* are different, build incrementally. |
| boolean isDifferent = isDifferent(data.classes.keySet(), classes.keySet()); |
| if (count > 0 || isDifferent || isResourceBundleListDifferent() || |
| data.swcChecksum != swcContext.checksum()) |
| { |
| // create a symbol table |
| SymbolTable symbolTable = new SymbolTable(tempOEMConfiguration.configuration, data.perCompileData); |
| data.configuration = tempOEMConfiguration.configuration; |
| data.nsComponents = nsComponents; |
| data.classes = classes; |
| data.fileSet = fileSet; |
| data.linkChecksum = tempOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| |
| // compile |
| data.sources = new ArrayList<Source>(); |
| data.units = compile(compilers, swcContext, symbolTable, mappings, licenseMap, classes, data.sources); |
| |
| boolean forcedToStop = CompilerAPI.forcedToStop(); |
| if (data.units == null || forcedToStop) |
| { |
| clean(true, false, false); |
| return FAIL; |
| } |
| else |
| { |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending active compile for " + getOutput(), true); |
| } |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| return OK; |
| } |
| } |
| else |
| { |
| if (benchmark != null) |
| { |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| int retVal = SKIP; |
| if (data != null) |
| { |
| CompilerAPI.displayWarnings(data.units); |
| if (data.linkChecksum != tempOEMConfiguration.cfgbuf.link_checksum_ts()) |
| { |
| retVal = LINK; |
| } |
| } |
| else |
| { |
| retVal = LINK; |
| } |
| data.linkChecksum = tempOEMConfiguration.cfgbuf.link_checksum_ts(); |
| data.swcChecksum = swcContext.checksum(); |
| |
| if (CompilerAPI.forcedToStop()) retVal = FAIL; |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark2("Ending active compile for " + getOutput(), true); |
| } |
| |
| if (retVal == LINK) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| false /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| } |
| else |
| { |
| clean(false /* cleanData */, false /* cleanCache */, false /* cleanOutput */); |
| } |
| |
| return retVal; |
| } |
| } |
| finally |
| { |
| // clean thread locals |
| OEMUtil.clean(); |
| } |
| } |
| |
| /** |
| * |
| * @param compilers |
| * @param swcContext |
| * @param symbolTable |
| * @param licenseMap |
| * @param classes |
| */ |
| private List<CompilationUnit> compile(SubCompiler[] compilers, CompilerSwcContext swcContext, |
| SymbolTable symbolTable, NameMappings nameMappings, Map licenseMap, |
| Map<String, Source> classes, List<Source> sources) |
| { |
| List<CompilationUnit> units = null; |
| Map<String, VirtualFile> rbFiles = new HashMap<String, VirtualFile>(); |
| |
| try |
| { |
| if (benchmark != null) |
| { |
| for (int i = 0; i < compilers.length; i++) |
| { |
| compilers[i].initBenchmarks(); |
| } |
| |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| } |
| |
| units = CompilerAPI.compile(data.fileSpec, data.sourceList, classes.values(), data.sourcePath, data.resources, |
| data.bundlePath, swcContext, symbolTable, nameMappings, data.configuration, |
| compilers, new CompcPreLink(rbFiles, new ArrayList<String>(resourceBundles), false), |
| licenseMap, sources); |
| |
| if (benchmark != null) |
| { |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| if ((benchmark != null) && (ThreadLocalToolkit.getLogger() != null)) |
| { |
| if (compilerBenchmarks == null) |
| compilerBenchmarks = new HashMap<String, PerformanceData[]>(); |
| |
| compilerBenchmarks.clear(); |
| |
| flex2.compiler.Logger logger = ThreadLocalToolkit.getLogger(); |
| for (int i = 0; i < compilers.length; i++) |
| { |
| SubCompiler compiler = compilers[i]; |
| PerformanceData[] times = compiler.getBenchmarks(); |
| |
| if (times == null) |
| continue; |
| |
| compiler.logBenchmarks(logger); |
| String compilerName = compiler.getName(); |
| compilerBenchmarks.put(compilerName, times); |
| } |
| } |
| } |
| catch (CompilerException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (SwcException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (Throwable t) |
| { |
| if (Trace.error) |
| { |
| t.printStackTrace(); |
| } |
| ThreadLocalToolkit.logError(t.getLocalizedMessage()); |
| } |
| finally |
| { |
| data.sourcePath.clearCache(); |
| data.bundlePath.clearCache(); |
| data.resources.refresh(); |
| data.classes = classes; |
| data.rbFiles = rbFiles; |
| |
| Map<String, VirtualFile> m = data.configuration.getCSSArchiveFiles(); |
| if (m != null) |
| { |
| data.cssArchiveFiles = new HashMap<String, VirtualFile>(m); |
| } |
| |
| m = data.configuration.getL10NArchiveFiles(); |
| if (m != null) |
| { |
| data.l10nArchiveFiles = new HashMap<String, VirtualFile>(m); |
| } |
| |
| OEMUtil.saveSignatureChecksums(units, data, data.configuration); |
| OEMUtil.saveSwcFileChecksums(swcContext, data, data.configuration); |
| // Make sure the swcContext is closed so we don't leave any dangling file handles |
| swcContext.close(); |
| } |
| |
| return units; |
| } |
| |
| /** |
| * Links the <code>Library</code>. This method writes the output |
| * to the output stream specified by the client. You should use a |
| * buffered output stream for best performance. |
| * |
| * <p> This method is protected. In most circumstances, the client |
| * only needs to call the <code>build()</code> method. Subclasses |
| * can call this method so that it links and outputs the |
| * application without recompiling. If the OutputStream is |
| * subsequently written to a file, subclasses should call |
| * refreshLastModified(). |
| * |
| * @param out The <code>OutputStream</code>. |
| * @return The size of the application, in bytes. |
| * @throws IOException Thrown when an I/O error occurs during linking. |
| */ |
| protected long link(OutputStream out) throws IOException |
| { |
| if (data == null || data.units == null) |
| { |
| return 0; |
| } |
| |
| boolean hasChanged = (oemConfiguration == null) ? false : oemConfiguration.hasChanged(); |
| flex2.compiler.common.Configuration config = null; |
| |
| if (hasChanged) |
| { |
| oemConfiguration = OEMUtil.getLinkerConfiguration(oemConfiguration.getLinkerOptions(), |
| oemConfiguration.keepLinkReport(), |
| oemConfiguration.keepSizeReport(), |
| OEMUtil.getLogger(logger, messages), |
| mimeMappings, resolver, |
| data.configuration, |
| oemConfiguration.newLinkerOptionsAfterCompile, |
| data.includes, data.excludes); |
| if (oemConfiguration == null) |
| { |
| clean(false /* cleanData */, |
| false /* cleanCache */, |
| false /* cleanOutput */, |
| false /* cleanConfig */, |
| false /* cleanMessages */, |
| true /* cleanThreadLocals */); |
| return 0; |
| } |
| |
| config = oemConfiguration.configuration; |
| } |
| else |
| { |
| config = data.configuration; |
| } |
| |
| if (config.benchmark()) |
| { |
| benchmark = CompilerAPI.runBenchmark(); |
| benchmark.setTimeFilter(config.getBenchmarkTimeFilter()); |
| } |
| else |
| { |
| CompilerAPI.disableBenchmark(); |
| } |
| |
| try |
| { |
| OEMUtil.init(OEMUtil.getLogger(logger, messages), mimeMappings, meter, resolver, cc); |
| |
| SimpleMovie temp = data.movie; |
| data.movie = SwcAPI.link(config, data.units); |
| |
| // link |
| SwcArchive archive = null; |
| Map<String, VirtualFile> archiveFiles = new TreeMap<String, VirtualFile>(); |
| if (data.swcArchiveFiles != null) archiveFiles.putAll(data.swcArchiveFiles); |
| if (data.cssArchiveFiles != null) archiveFiles.putAll(data.cssArchiveFiles); |
| if (data.l10nArchiveFiles != null) archiveFiles.putAll(data.l10nArchiveFiles); |
| archiveFiles.putAll(files); |
| |
| if (directory != null) |
| { |
| archive = new SwcDirectoryArchive(FileUtil.getCanonicalPath(directory)); |
| SwcAPI.exportSwc(archive, |
| archiveFiles, |
| this.stylesheets, |
| (LinkerConfiguration) config, |
| (SwcMovie) data.movie, |
| new ArrayList<SwcComponent>(data.nsComponents), |
| data.swcCache, |
| data.rbFiles); |
| } |
| |
| long size = 0; |
| |
| // TODO PERFORMANCE: A lot of unnecessary recopying and buffering here |
| ByteArrayOutputStream baos = null; |
| String path = null; |
| |
| if (output != null) |
| { |
| path = FileUtil.getCanonicalPath(output); |
| } |
| |
| // Flex Builder supplies an "out" and an "output", but |
| // they really only use the "out", so check for that |
| // first. |
| if (out != null) |
| { |
| baos = new ByteArrayOutputStream(); |
| archive = new SwcLazyReadArchive(baos, path); |
| } |
| else if (output != null) |
| { |
| archive = new SwcLazyReadArchive(path); |
| } |
| |
| SwcAPI.exportSwc(archive, |
| archiveFiles, |
| this.stylesheets, |
| (LinkerConfiguration) config, |
| (SwcMovie) data.movie, |
| new ArrayList<SwcComponent>(data.nsComponents), |
| data.swcCache, |
| data.rbFiles); |
| |
| if (out != null) |
| { |
| ByteArrayInputStream in = new ByteArrayInputStream(baos.toByteArray()); |
| FileUtil.streamOutput(in, out); |
| size = baos.size(); |
| } |
| else if (output != null) |
| { |
| size = output.length(); |
| } |
| |
| if (hasChanged && temp != null) |
| { |
| data.movie = temp; |
| } |
| |
| return size; |
| } |
| catch (LinkerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| return 0; |
| } |
| catch (SwcException ex) |
| { |
| if (Trace.error) |
| { |
| ex.printStackTrace(); |
| } |
| assert ThreadLocalToolkit.errorCount() > 0; |
| return 0; |
| } |
| catch (Throwable t) |
| { |
| if (Trace.error) |
| { |
| t.printStackTrace(); |
| } |
| ThreadLocalToolkit.logError(t.getLocalizedMessage()); |
| return 0; |
| } |
| finally |
| { |
| // clean thread locals |
| OEMUtil.clean(); |
| } |
| } |
| |
| /** |
| * |
| * @param cleanData |
| * @param cleanCache |
| * @param cleanOutput |
| */ |
| private void clean(boolean cleanData, boolean cleanCache, boolean cleanOutput) |
| { |
| clean(cleanData, |
| cleanCache, |
| cleanOutput, |
| true /* cleanConfig */, |
| false /* cleanMessages */, |
| false /* cleanThreadLocals */); |
| } |
| |
| /** |
| * |
| * @param cleanData |
| * @param cleanCache |
| * @param cleanOutput |
| * @param cleanConfig |
| * @param cleanMessages |
| * @param cleanThreadLocals |
| */ |
| private void clean(boolean cleanData, boolean cleanCache, boolean cleanOutput, |
| boolean cleanConfig, boolean cleanMessages, boolean cleanThreadLocals) |
| { |
| if (cleanThreadLocals) |
| { |
| OEMUtil.clean(); |
| } |
| |
| if (oemConfiguration != null && cleanConfig) |
| { |
| oemConfiguration.reset(); |
| } |
| |
| if (cleanData) |
| { |
| data = null; |
| configurationReport = null; |
| } |
| |
| if (cleanCache) |
| { |
| if (cacheName != null) |
| { |
| File dead = FileUtil.openFile(cacheName); |
| if (dead != null && dead.exists()) |
| { |
| dead.delete(); |
| } |
| cacheName = null; |
| } |
| } |
| |
| if (cleanOutput) |
| { |
| if (output != null && output.exists()) |
| { |
| output.delete(); |
| } |
| } |
| |
| if (cleanMessages) |
| { |
| messages.clear(); |
| } |
| } |
| |
| /** |
| * |
| * @param s1 |
| * @param s2 |
| * @return |
| */ |
| private <T> boolean isDifferent(Collection<T> s1, Collection<T> s2) |
| { |
| for (Iterator<T> i = s2.iterator(); i.hasNext(); ) |
| { |
| if (!s1.contains(i.next())) |
| { |
| return true; |
| } |
| } |
| |
| return s1.size() > s2.size(); |
| } |
| |
| /** |
| * |
| * @return |
| */ |
| private boolean isResourceBundleListDifferent() |
| { |
| int size1 = (data == null || data.rbFiles == null) ? 0 : data.rbFiles.size(); |
| int size2 = resourceBundles == null ? 0 : resourceBundles.size(); |
| return size1 != size2; |
| } |
| |
| /** |
| * Returns the cache of sources in the source list and source |
| * path. After building this Library object, the cache may be |
| * saved and used to compile another Application or Library object |
| * with common sources. |
| * |
| * @return The active cache. May be null. |
| * |
| * @since 4.5 |
| */ |
| public ApplicationCache getApplicationCache() |
| { |
| return applicationCache; |
| } |
| |
| /** |
| * Sets the cache for sources in the source list and source path. |
| * After compiling this Library object, the cache may be reused to |
| * build another Application or Library object with common |
| * sources. |
| * |
| * @param applicationCache A reference to the application cache. |
| * |
| * @since 4.5 |
| */ |
| public void setApplicationCache(ApplicationCache applicationCache) |
| { |
| this.applicationCache = applicationCache; |
| } |
| |
| // TODO: deprecate getSwcCache() and setSwcCache(), then add |
| // getLibraryCache() and setLibraryCache(). |
| /** |
| * Get the cache of swcs in the library path. After building this |
| * Library object, the cache may be saved and used to compile |
| * another Library or Application object that uses the same |
| * library path. |
| * |
| * @return The active cache. May be null. |
| * |
| * @since 3.0 |
| */ |
| public LibraryCache getSwcCache() |
| { |
| return libraryCache; |
| } |
| |
| /** |
| * Set the cache for swcs in the library path. After compiling an |
| * Library object, the cache may be reused to build another |
| * Library or Application object that uses the same library path. |
| * |
| * @param swcCache A reference to an allocated swc cache. |
| * |
| * @since 3.0 |
| */ |
| public void setSwcCache(LibraryCache libraryCache) |
| { |
| this.libraryCache = libraryCache; |
| } |
| |
| public void refreshLastModified() |
| { |
| String fileName = FileUtil.getCanonicalPath(output); |
| File file = new File(fileName); |
| long lastModified = file.lastModified(); |
| data.swcCache.setLastModified(fileName, lastModified); |
| } |
| |
| @Override |
| public Library clone() |
| { |
| Library clone; |
| try |
| { |
| clone = (Library) super.clone(); |
| } |
| catch ( CloneNotSupportedException e ) |
| { |
| throw new RuntimeException( e ); //wont happen |
| } |
| clone.oemConfiguration = oemConfiguration.clone(); |
| return clone; |
| } |
| } |