| /* |
| * |
| * 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; |
| |
| import flex2.compiler.*; |
| import flex2.compiler.common.CompilerConfiguration; |
| import flex2.compiler.common.DefaultsConfigurator; |
| import flex2.compiler.config.ConfigurationBuffer; |
| import flex2.compiler.config.ConfigurationException; |
| import flex2.compiler.extensions.ExtensionManager; |
| import flex2.compiler.extensions.ICompcExtension; |
| import flex2.compiler.i18n.I18nUtils; |
| import flex2.compiler.io.FileUtil; |
| import flex2.compiler.io.VirtualFile; |
| import flex2.compiler.swc.*; |
| import flex2.compiler.util.*; |
| import flex2.linker.LinkerException; |
| import flash.localization.LocalizationManager; |
| import flash.localization.XLRLocalizer; |
| import flash.localization.ResourceBundleLocalizer; |
| import flash.util.Trace; |
| import org.apache.flex.tools.FlexTool; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.RandomAccessFile; |
| import java.util.*; |
| |
| /** |
| * Entry-point for compc, the command-line tool for compiling components. |
| * |
| * @author Brian Deitte |
| */ |
| public class Compc extends Tool implements FlexTool |
| { |
| @Override |
| public String getName() { |
| return FLEX_TOOL_COMPC; |
| } |
| |
| @Override |
| public int execute(String[] args) { |
| compc(args); |
| return ThreadLocalToolkit.errorCount(); |
| } |
| |
| public static void main(String[] args) |
| { |
| compc(args); |
| System.exit(ThreadLocalToolkit.errorCount()); |
| } |
| |
| public static void compc(String[] args) |
| { |
| CompilerAPI.useAS3(); |
| |
| Benchmark benchmark = null; |
| ConfigurationBuffer cfgbuf = new ConfigurationBuffer(CompcConfiguration.class, CompcConfiguration.getAliases()); |
| |
| // Do not set this. The include-classes should be included in the configuration buffer checksum so changes |
| // to the class list can be detected during incremental builds. |
| //cfgbuf.setDefaultVar("include-classes"); |
| |
| try |
| { |
| // setup the path resolver |
| CompilerAPI.usePathResolver(); |
| |
| // set up for localizing messages |
| LocalizationManager l10n = new LocalizationManager(); |
| l10n.addLocalizer( new XLRLocalizer() ); |
| l10n.addLocalizer( new ResourceBundleLocalizer() ); |
| ThreadLocalToolkit.setLocalizationManager( l10n ); |
| |
| // setup a console-based logger... |
| CompilerAPI.useConsoleLogger(); |
| |
| // process configuration |
| DefaultsConfigurator.loadCompcDefaults( cfgbuf ); |
| CompcConfiguration configuration = (CompcConfiguration) Mxmlc.processConfiguration( |
| l10n, "compc", args, cfgbuf, CompcConfiguration.class, "include-classes"); |
| |
| benchmark = compc( cfgbuf, configuration ); |
| |
| Set<ICompcExtension> extensions = ExtensionManager.getCompcExtensions( configuration.getCompilerConfiguration().getExtensionsConfiguration().getExtensionMappings() ); |
| for ( ICompcExtension extension : extensions ) |
| { |
| if(ThreadLocalToolkit.errorCount() == 0) { |
| extension.run( (CompcConfiguration) configuration.clone() ); |
| } |
| } |
| } |
| catch (ConfigurationException ex) |
| { |
| displayStartMessage(); |
| Mxmlc.processConfigurationException(ex, "compc"); |
| } |
| catch (CompilerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (LinkerException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (SwcException ex) |
| { |
| assert ThreadLocalToolkit.errorCount() > 0; |
| } |
| catch (Throwable t) // IOException, Throwable |
| { |
| ThreadLocalToolkit.logError(t.getMessage()); |
| if (Trace.error) |
| { |
| t.printStackTrace(); |
| } |
| } |
| finally |
| { |
| if (benchmark != null) |
| { |
| if ((ThreadLocalToolkit.errorCount() == 0) && |
| benchmark.hasStarted(Benchmark.POSTCOMPILE)) |
| { |
| benchmark.stopTime(Benchmark.POSTCOMPILE, false); |
| } |
| benchmark.totalTime(); |
| benchmark.peakMemoryUsage(true); |
| } |
| |
| CompilerAPI.removePathResolver(); |
| } |
| |
| } |
| |
| public static Benchmark compc( ConfigurationBuffer cfgbuf, CompcConfiguration configuration ) |
| throws Exception, ConfigurationException, CompilerException |
| { |
| LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager(); |
| CompilerAPI.useConsoleLogger(true, true, configuration.getWarnings(), true); |
| |
| Benchmark benchmark = null; |
| if (configuration.benchmark()) |
| { |
| benchmark = CompilerAPI.runBenchmark(); |
| benchmark.startTime(Benchmark.PRECOMPILE); |
| } |
| else |
| { |
| CompilerAPI.disableBenchmark(); |
| } |
| |
| CompilerAPI.setupHeadless(configuration); |
| |
| String[] sourceMimeTypes = WebTierAPI.getSourcePathMimeTypes(); |
| CompilerConfiguration compilerConfig = configuration.getCompilerConfiguration(); |
| |
| // create a SourcePath... |
| SourcePath sourcePath = new SourcePath(sourceMimeTypes, compilerConfig.allowSourcePathOverlap()); |
| sourcePath.addPathElements( compilerConfig.getSourcePath() ); |
| |
| List<VirtualFile>[] array = CompilerAPI.getVirtualFileList(configuration.getIncludeSources(), |
| configuration.getStylesheets().values(), |
| new HashSet<String>(Arrays.asList(sourceMimeTypes)), |
| sourcePath.getPaths()); |
| |
| // note: if Configuration is ever shared with other parts of the system, then this part will need |
| // to change, since we're setting a compc-specific setting below |
| compilerConfig.setMetadataExport(true); |
| |
| // create a FileSpec... can reuse based on appPath, debug settings, etc... |
| FileSpec fileSpec = new FileSpec(array[0], WebTierAPI.getFileSpecMimeTypes(), false); |
| |
| // create a SourceList... |
| SourceList sourceList = new SourceList(array[1], compilerConfig.getSourcePath(), null, |
| WebTierAPI.getSourceListMimeTypes(), false); |
| |
| ResourceContainer resources = new ResourceContainer(); |
| ResourceBundlePath bundlePath = new ResourceBundlePath(configuration.getCompilerConfiguration(), null); |
| |
| Map<String, Source> classes = new HashMap<String, Source>(); |
| NameMappings mappings = CompilerAPI.getNameMappings(configuration); |
| List<SwcComponent> nsComponents = SwcAPI.setupNamespaceComponents(configuration, mappings, sourcePath, |
| sourceList, classes); |
| SwcAPI.setupClasses(configuration, sourcePath, sourceList, classes); |
| |
| if (benchmark != null) |
| { |
| benchmark.benchmark(l10n.getLocalizedTextString(new Mxmlc.InitialSetup())); |
| } |
| |
| // load SWCs |
| CompilerSwcContext swcContext = new CompilerSwcContext(); |
| SwcCache cache = new SwcCache(); |
| |
| // lazy read should only be set by mxmlc/compc |
| cache.setLazyRead(true); |
| // for compc the theme and include-libraries values have been purposely not passed in below. |
| // This is done because the theme attribute doesn't make sense and the include-libraries value |
| // actually causes issues when the default value is used with external libraries. |
| // FIXME: why don't we just get rid of these values from the configurator for compc? That's a problem |
| // for include-libraries at least, since this value appears in flex-config.xml |
| swcContext.load( compilerConfig.getLibraryPath(), |
| compilerConfig.getExternalLibraryPath(), |
| null, |
| compilerConfig.getIncludeLibraries(), |
| mappings, |
| I18nUtils.getTranslationFormat(compilerConfig), |
| cache ); |
| configuration.addExterns( swcContext.getExterns() ); |
| configuration.addIncludes( swcContext.getIncludes() ); |
| configuration.addFiles( swcContext.getIncludeFiles() ); |
| |
| // Allow -include-classes to override the -external-library-path. |
| configuration.removeExterns( configuration.getClasses() ); |
| |
| // 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 (configuration.getIncludeInheritanceDependenciesOnly()) |
| configuration.addIncludes(configuration.getClasses()); |
| |
| // The output file. |
| File swcFile = new File(configuration.getOutput()); |
| |
| // Checksums to figure out if incremental compile can be done. |
| String incrementalFileName = null; |
| SwcChecksums swcChecksums = null; |
| |
| // Should we attempt to build incrementally using the incremental file? |
| boolean recompile = true; |
| |
| // If incremental compilation is enabled and the output file exists, |
| // use the persisted store to figure out if a compile/link is necessary. |
| // link without a compile is not supported without changes to the |
| // persistantStore since units for Sources of type isSwcScriptOwner() |
| // aren't stored/restored properly. units contains null entries for those |
| // type of Source. To force a rebuild, with -incremental specified, delete the |
| // incremental file. |
| if (configuration.getCompilerConfiguration().getIncremental()) |
| { |
| swcChecksums = new SwcChecksums(swcContext, cfgbuf, configuration); |
| |
| // If incremental compilation is enabled, read the cached |
| // compilation units... Do not include the checksum in the file name so that |
| // cache files don't pile up as the configuration changes. There needs |
| // to be a 1-to-1 mapping between the swc file and the cache file. |
| incrementalFileName = configuration.getOutput() + ".cache"; |
| |
| // If the output file doesn't exist don't bother loading the |
| // cache since a recompile is needed. |
| if (swcFile.exists()) |
| { |
| RandomAccessFile incrementalFile = null; |
| try |
| { |
| incrementalFile = new RandomAccessFile(incrementalFileName, "r"); |
| |
| // For loadCompilationUnits, loadedChecksums[1] must match |
| // the cached value else IOException is thrown. |
| int[] loadedChecksums = swcChecksums.copy(); |
| |
| CompilerAPI.loadCompilationUnits(configuration, fileSpec, sourceList, |
| sourcePath, resources, bundlePath, |
| null /* sources */, null /* units */, |
| loadedChecksums, |
| swcChecksums.getSwcDefSignatureChecksums(), |
| swcChecksums.getSwcFileChecksums(), |
| swcChecksums.getArchiveFileChecksums(), |
| incrementalFile, incrementalFileName, |
| null /* font manager */); |
| |
| if (!swcChecksums.isRecompilationNeeded(loadedChecksums) && !swcChecksums.isRelinkNeeded(loadedChecksums)) |
| { |
| recompile = false; |
| } |
| } |
| catch (FileNotFoundException ex) |
| { |
| ThreadLocalToolkit.logDebug(ex.getLocalizedMessage()); |
| } |
| catch (IOException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getLocalizedMessage()); |
| } |
| finally |
| { |
| if (incrementalFile != null) |
| { |
| try |
| { |
| incrementalFile.close(); |
| } |
| catch (IOException ex) |
| { |
| } |
| // If the load failed, or recompilation is needed, reset |
| // all the variables to their original state. |
| if (recompile) |
| { |
| fileSpec = new FileSpec(array[0], WebTierAPI.getFileSpecMimeTypes(), false); |
| |
| sourceList = new SourceList(array[1], compilerConfig.getSourcePath(), null, WebTierAPI.getSourceListMimeTypes(), false); |
| |
| sourcePath = new SourcePath(sourceMimeTypes, compilerConfig.allowSourcePathOverlap()); |
| sourcePath.addPathElements(compilerConfig.getSourcePath()); |
| |
| resources = new ResourceContainer(); |
| bundlePath = new ResourceBundlePath(configuration.getCompilerConfiguration(), null); |
| |
| classes = new HashMap<String, Source>(); |
| nsComponents = SwcAPI.setupNamespaceComponents(configuration, mappings, sourcePath, sourceList, classes); |
| SwcAPI.setupClasses(configuration, sourcePath, sourceList, classes); |
| } |
| } |
| } |
| } |
| } |
| |
| // Validate CompilationUnits in FileSpec and SourcePath. If |
| // count > 0 something changed. |
| int count = CompilerAPI.validateCompilationUnits( |
| fileSpec, sourceList, sourcePath, bundlePath, resources, |
| swcContext, |
| null /* perCompileData */, |
| configuration); |
| |
| // This isn't really incremental since any change requires a total |
| // recompile, relink and re-export, but it shouldn't update the output |
| // file if there are no changes to it's dependencies. |
| if (recompile || count > 0 || !swcFile.exists()) |
| { |
| // Get standard bundle of compilers, transcoders. |
| Transcoder[] transcoders = WebTierAPI.getTranscoders( configuration ); |
| SubCompiler[] compilers = WebTierAPI.getCompilers(compilerConfig, mappings, transcoders); |
| |
| ArrayList<Source> sources = new ArrayList<Source>(); |
| Map<String, VirtualFile> rbFiles = new HashMap<String, VirtualFile>(); |
| |
| if (benchmark != null) |
| { |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| } |
| |
| List<CompilationUnit> units = |
| CompilerAPI.compile(fileSpec, sourceList, classes.values(), sourcePath, resources, bundlePath, |
| swcContext, mappings, configuration, compilers, |
| new CompcPreLink(rbFiles, configuration.getIncludeResourceBundles(), false), |
| configuration.getLicensesConfiguration().getLicenseMap(), sources); |
| |
| if (benchmark != null) |
| { |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| // Link the swc and then export it. |
| SwcAPI.exportSwc(configuration, units, nsComponents, cache, rbFiles); |
| |
| // If there were no errors and the swc exists then it was exported successfully. |
| if (ThreadLocalToolkit.errorCount() == 0 && swcFile.isFile()) |
| { |
| ThreadLocalToolkit.log(new OutputMessage(FileUtil.getCanonicalPath(swcFile), Long.toString(swcFile.length()))); |
| } |
| |
| // If incremental compilation is enabled, save the compilation units. |
| if (configuration.getCompilerConfiguration().getIncremental()) |
| { |
| // Make sure the checksums are all current. |
| swcChecksums.saveChecksums(units); |
| |
| // These are files which don't necessarily have dependencies on them |
| // so the compiler won't figure out if they've been modified. |
| Map<String, VirtualFile> archiveFiles = new TreeMap<String, VirtualFile>(); |
| if (configuration.getCSSArchiveFiles() != null) archiveFiles.putAll(configuration.getCSSArchiveFiles()); |
| if (configuration.getL10NArchiveFiles() != null) archiveFiles.putAll(configuration.getL10NArchiveFiles()); |
| if (configuration.getFiles() != null) archiveFiles.putAll(configuration.getFiles()); |
| if (configuration.getStylesheets() != null) archiveFiles.putAll(configuration.getStylesheets()); |
| swcChecksums.saveArchiveFilesChecksums(archiveFiles); |
| |
| RandomAccessFile incrementalFile = null; |
| try |
| { |
| incrementalFile = new RandomAccessFile(incrementalFileName, "rw"); |
| |
| // In case we're reusing the file, clear it. |
| incrementalFile.setLength(0); |
| |
| CompilerAPI.persistCompilationUnits( |
| configuration, fileSpec, sourceList, sourcePath, resources, bundlePath, |
| null, /* sources */ |
| null, /* units */ |
| swcChecksums.getChecksums(), |
| swcChecksums.getSwcDefSignatureChecksums(), |
| swcChecksums.getSwcFileChecksums(), |
| swcChecksums.getArchiveFileChecksums(), |
| "", incrementalFile); |
| } |
| catch (IOException ex) |
| { |
| ThreadLocalToolkit.logInfo(ex.getLocalizedMessage()); |
| |
| // Get rid of the cache file since the write failed. |
| new File(incrementalFileName).deleteOnExit(); |
| } |
| finally |
| { |
| if (incrementalFile != null) |
| { |
| try |
| { |
| incrementalFile.close(); |
| } |
| catch (IOException ex) |
| { |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| if (benchmark != null) |
| { |
| benchmark.stopTime(Benchmark.PRECOMPILE, false); |
| benchmark.startTime(Benchmark.POSTCOMPILE); |
| } |
| |
| // swc is already up-to-date so no need to compile/link or rewrite file |
| ThreadLocalToolkit.log(new NoUpdateMessage(FileUtil.getCanonicalPath(swcFile))); |
| |
| } |
| |
| return benchmark; |
| } |
| |
| public static final void displayStartMessage() |
| { |
| LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager(); |
| |
| ThreadLocalToolkit.logInfo(l10n.getLocalizedTextString(new StartMessage(VersionInfo.buildMessage()))); |
| } |
| |
| public static class StartMessage extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = -3698237096980702681L; |
| |
| public StartMessage(String buildMessage) |
| { |
| super(); |
| this.buildMessage = buildMessage; |
| } |
| |
| public final String buildMessage; |
| } |
| |
| public static class OutputMessage extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = 8747873783743625156L; |
| |
| public String name; |
| public String length; |
| |
| public OutputMessage(String name, String length) |
| { |
| this.name = name; |
| this.length = length; |
| } |
| } |
| |
| public static class NoUpdateMessage extends CompilerMessage.CompilerInfo |
| { |
| private static final long serialVersionUID = -3432746769116961891L; |
| |
| public String name; |
| |
| public NoUpdateMessage(String name) |
| { |
| this.name = name; |
| } |
| } |
| } |