/* * * 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 flash.localization.LocalizationManager; import flex2.compiler.common.Configuration; import flex2.compiler.common.ConfigurationPathResolver; import flex2.compiler.common.PathResolver; import flex2.compiler.config.*; import flex2.compiler.io.VirtualFile; import flex2.compiler.util.CompilerMessage; import flex2.compiler.util.ThreadLocalToolkit; import org.apache.flex.compiler.clients.MXMLC; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.Map.Entry; /** * A command line tool for compiling Flex applications. Despite the * name, in addition to .mxml files, this tool can be used to compile * other file formats, like .as and .css. */ public final class Mxmlc extends Tool { static private String l10nConfigPrefix = "flex2.configuration"; public static final String FILE_SPECS = "file-specs"; /** * The entry-point for Mxmlc. * Note that if you change anything in this method, make sure to check Compc, Shell, and * the server's CompileFilter to see if the same change needs to be made there. You * should also inform the Zorn team of the change. * * @param args */ public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { System.exit(mxmlcNoExit(args)); } public static int mxmlcNoExit(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { COMPILER = MXMLC.class; JS_COMPILER = MxmlJSC.class; return compile(args); } public static void mxmlc(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { COMPILER = MXMLC.class; JS_COMPILER = MxmlJSC.class; compile(args); } public static Configuration processConfiguration(LocalizationManager lmgr, String program, String[] args, ConfigurationBuffer cfgbuf, Class<? extends Configuration> cls, String defaultVar) throws ConfigurationException, IOException { return processConfiguration(lmgr, program, args, cfgbuf, cls, defaultVar, true); } public static Configuration processConfiguration(LocalizationManager lmgr, String program, String[] args, ConfigurationBuffer cfgbuf, Class<? extends Configuration> cls, String defaultVar, boolean ignoreUnknownItems) throws IOException { ToolsConfiguration toolsConfiguration = null; try { SystemPropertyConfigurator.load(cfgbuf, "flex"); // Parse the command line a first time, to peak at stuff like // "flexlib" and "load-config". The first parse is thrown // away after that and we intentionally parse a second time // below. See note below. CommandLineConfigurator.parse(cfgbuf, defaultVar, args); String flexlib = cfgbuf.getToken("flexlib"); if (flexlib == null) { String appHome = System.getProperty("application.home"); if (appHome == null) { appHome = "."; } else { appHome += File.separator + "frameworks"; // FIXME - need to eliminate this from the compiler } cfgbuf.setToken("flexlib", appHome); } // Framework Type // halo, gumbo, interop... String framework = cfgbuf.getToken("framework"); if (framework == null) { cfgbuf.setToken("framework", "halo"); } String configname = cfgbuf.getToken("configname"); if (configname == null) { cfgbuf.setToken("configname", "flex"); } String buildNumber = cfgbuf.getToken("build.number"); if (buildNumber == null) { if ("".equals(VersionInfo.getBuild())) { buildNumber = "workspace"; } else { buildNumber = VersionInfo.getBuild(); } cfgbuf.setToken("build.number", buildNumber); } // We need to intercept "help" options because we want to try to correctly // interpret them even when the rest of the configuration is totally screwed up. if (cfgbuf.getVar("version") != null) { System.out.println(VersionInfo.buildMessage()); System.exit(0); } processHelp(cfgbuf, program, defaultVar, lmgr, args); // at this point, we should have enough to know both // flexlib and the config file. ConfigurationPathResolver configResolver = new ConfigurationPathResolver(); List<ConfigurationValue> configs = cfgbuf.peekConfigurationVar("load-config"); if (configs != null) { for (ConfigurationValue cv : configs) { for (String path : cv.getArgs()) { VirtualFile configFile = ConfigurationPathResolver.getVirtualFile(path, configResolver, cv); cfgbuf.calculateChecksum(configFile); InputStream in = configFile.getInputStream(); if (in != null) { FileConfigurator.load(cfgbuf, new BufferedInputStream(in), configFile.getName(), configFile.getParent(), "flex-config", ignoreUnknownItems); } else { throw new ConfigurationException.ConfigurationIOError(path, cv.getVar(), cv.getSource(), cv.getLine()); } } } } PathResolver resolver = ThreadLocalToolkit.getPathResolver(); // Load project file, if any... List fileValues = cfgbuf.getVar(FILE_SPECS); if ((fileValues != null) && (fileValues.size() > 0)) { ConfigurationValue cv = (ConfigurationValue) fileValues.get(fileValues.size() - 1); if (cv.getArgs().size() > 0) { String val = cv.getArgs().get(cv.getArgs().size() - 1); int index = val.lastIndexOf('.'); if (index != -1) { String project = val.substring(0, index) + "-config.xml"; VirtualFile projectFile = resolver.resolve(configResolver, project); if (projectFile != null) { cfgbuf.calculateChecksum(projectFile); InputStream in = projectFile.getInputStream(); if (in != null) { FileConfigurator.load(cfgbuf, new BufferedInputStream(in), projectFile.getName(), projectFile.getParent(), "flex-config", ignoreUnknownItems); } } } } } // The command line needs to take precedence over all defaults and config files. // This is a bit gross, but by simply re-merging the command line back on top, // we will get the behavior we want. cfgbuf.clearSourceVars(CommandLineConfigurator.source); CommandLineConfigurator.parse(cfgbuf, defaultVar, args); toolsConfiguration = null; try { toolsConfiguration = (ToolsConfiguration) cls.newInstance(); toolsConfiguration.setConfigPathResolver(configResolver); } catch (Exception e) { LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager(); throw new ConfigurationException(l10n.getLocalizedTextString(new CouldNotInstantiate(toolsConfiguration))); } cfgbuf.commit(toolsConfiguration); // enterprise service config file has other config file dependencies. add them here... calculateServicesChecksum(toolsConfiguration, cfgbuf); toolsConfiguration.validate(cfgbuf); // consolidate license keys... VirtualFile licenseFile = toolsConfiguration.getLicenseFile(); if (licenseFile != null) { Map<String, String> fileLicenses = Tool.getLicenseMapFromFile(licenseFile.getName()); Map<String, String> cmdLicenses = toolsConfiguration.getLicensesConfiguration().getLicenseMap(); if (cmdLicenses == null) { toolsConfiguration.getLicensesConfiguration().setLicenseMap(fileLicenses); } else if (fileLicenses != null) { fileLicenses.putAll(cmdLicenses); toolsConfiguration.getLicensesConfiguration().setLicenseMap(fileLicenses); } } } catch (ConfigurationException e) { e.printStackTrace(); } return toolsConfiguration; } static void processHelp(ConfigurationBuffer cfgbuf, String program, String defaultVar, LocalizationManager lmgr, String[] args) { if (cfgbuf.getVar("help") != null) { Set<String> keywords = new HashSet<String>(); List vals = cfgbuf.getVar("help"); for (Iterator it = vals.iterator(); it.hasNext(); ) { ConfigurationValue val = (ConfigurationValue) it.next(); for (Object element : val.getArgs()) { String keyword = (String) element; while (keyword.startsWith("-")) keyword = keyword.substring(1); keywords.add(keyword); } } if (keywords.size() == 0) { keywords.add("help"); } ThreadLocalToolkit.logInfo(getStartMessage(program)); System.out.println(); System.out.println(CommandLineConfigurator.usage(program, defaultVar, cfgbuf, keywords, lmgr, l10nConfigPrefix)); System.exit(0); } if (args.length == 0 && ("mxmlc".equals(program) || "compc".equals(program))) { ThreadLocalToolkit.logInfo(getStartMessage(program)); System.err.println(CommandLineConfigurator.brief(program, defaultVar, lmgr, l10nConfigPrefix)); System.exit(1); } } private static void calculateServicesChecksum(Configuration config, ConfigurationBuffer cfgbuf) { Map<String, Long> services = null; if (config.getCompilerConfiguration().getServicesDependencies() != null) { services = config.getCompilerConfiguration().getServicesDependencies().getConfigPaths(); } if (services != null) { for (Entry<String, Long> entry : services.entrySet()) { cfgbuf.calculateChecksum(entry.getKey(), entry.getValue()); } } } public static void processConfigurationException(ConfigurationException ex, String program) { ThreadLocalToolkit.log(ex); if (ex.source == null || ex.source.equals("command line")) { Map<String, String> p = new HashMap<String, String>(); p.put("program", program); String help = ThreadLocalToolkit.getLocalizationManager().getLocalizedTextString("flex2.compiler.CommandLineHelp", p); if (help != null) { // "Use '" + program + " -help' for information about using the command line."); System.err.println(help); } } } private static String getStartMessage(String program) { LocalizationManager l10n = ThreadLocalToolkit.getLocalizationManager(); return l10n.getLocalizedTextString(new StartMessage(program, VersionInfo.buildMessage())); } public static class CouldNotInstantiate extends CompilerMessage.CompilerInfo { private static final long serialVersionUID = -8970190710117830662L; public CouldNotInstantiate(Configuration config) { super(); this.config = config; } public final Configuration config; } public static class StartMessage extends CompilerMessage.CompilerInfo { private static final long serialVersionUID = 4807822711658875257L; public StartMessage(String program, String buildMessage) { super(); this.program = program; this.buildMessage = buildMessage; } public final String program, buildMessage; } public static class OutputMessage extends CompilerMessage.CompilerInfo { private static final long serialVersionUID = -4859993585489031839L; public String name; public String length; public OutputMessage(String name, String length) { this.name = name; this.length = length; } } }