org.apache.royale.swc.SWCDepends Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The Apache Royale Compiler
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.swc;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.royale.compiler.Messages;
import org.apache.royale.compiler.clients.problems.ProblemFormatter;
import org.apache.royale.compiler.clients.problems.ProblemPrinter;
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.clients.problems.WorkspaceProblemFormatter;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.common.DependencyTypeSet;
import org.apache.royale.compiler.common.VersionInfo;
import org.apache.royale.compiler.config.CommandLineConfigurator;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.ConfigurationBuffer;
import org.apache.royale.compiler.config.ConfigurationPathResolver;
import org.apache.royale.compiler.config.ConfigurationValue;
import org.apache.royale.compiler.config.Configurator;
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.internal.config.annotations.Arguments;
import org.apache.royale.compiler.internal.config.annotations.Config;
import org.apache.royale.compiler.internal.config.annotations.InfiniteArguments;
import org.apache.royale.compiler.internal.config.annotations.Mapping;
import org.apache.royale.compiler.internal.config.annotations.SoftPrerequisites;
import org.apache.royale.compiler.internal.config.localization.LocalizationManager;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.projects.LibraryDependencyGraph;
import org.apache.royale.compiler.internal.targets.SWFTarget;
import org.apache.royale.compiler.internal.workspaces.Workspace;
import org.apache.royale.compiler.problems.ConfigurationProblem;
import org.apache.royale.compiler.problems.FileIOProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.InternalCompilerProblem;
import org.apache.royale.compiler.targets.ITargetSettings;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.swc.catalog.XMLFormatter;
/**
* swcdepends command line utility.
*
* Use this utility to see the dependency order of all SWCs in your configuration.
* You can also see:
*
* - the swcs a swc is dependent on (on by default).
* - the scripts that are causing the dependency (off by default).
* - the dependency types of the scripts (off by default).
*
*/
public class SWCDepends
{
// XML names
public static final String SWC_DEPENDENCY_ORDER_ELEMENT = "swc-dependency-order";
public static final String SWC_DEPENDENCIES_ELEMENT = "swc-dependencies";
public static final String SWC_ELEMENT = "swc";
public static final String DEFINITION_DEPENDENCIES_ELEMENT = "definition-dependencies";
public static final String DEFINITION_ELEMENT = "def";
public static final String PATH_ATTRIBUTE = "path";
public static final String ID_ATTRIBUTE = "id";
static final String NEWLINE = System.getProperty("line.separator");
private static final String DEFAULT_VAR = "no-default-arg";
private static final String L10N_CONFIG_PREFIX = "org.apache.royale.compiler.internal.config.configuration";
protected Workspace workspace;
protected RoyaleProject project;
protected DependencyConfiguration config;
protected ProblemQuery problems;
protected ConfigurationBuffer configBuffer;
protected Configurator projectConfigurator;
protected ICompilationUnit mainCU;
protected SWFTarget target;
protected ITargetSettings targetSettings;
private List dependencyOrder; // of all discovered swcs
/**
* Entry point for swcdepends
tool.
*
* @param args command line arguments
*/
public static void main(final String[] args)
{
int exitCode = staticMainNoExit(args);
System.exit(exitCode);
}
public static int staticMainNoExit(final String[] args)
{
final SWCDepends swcDepends = new SWCDepends();
return swcDepends.mainNoExit(args);
}
public SWCDepends()
{
workspace = new Workspace();
project = new RoyaleProject(workspace);
problems = new ProblemQuery();
}
public int mainNoExit(final String[] args)
{
int result = 0;
if (configure(args))
{
XMLStreamWriter xmlWriter = null;
try
{
List showSwcs = config.getShowSwcs();
DependencyTypeSet dependencyTypes = getDependencyTypeSet();
LibraryDependencyGraph graph = project.createLibraryDependencyGraph(dependencyTypes);
xmlWriter = new XMLFormatter(getXMLWriter());
xmlWriter.writeStartDocument();
// write SWCDependencyOrder
xmlWriter.writeStartElement(SWC_DEPENDENCY_ORDER_ELEMENT);
dependencyOrder = graph.getDependencyOrder();
for (String swcName : dependencyOrder)
{
if (!showSwc(swcName, showSwcs))
continue;
println(swcName + ":");
xmlWriter.writeStartElement(SWC_ELEMENT);
xmlWriter.writeAttribute(PATH_ATTRIBUTE, swcName);
// Show the dependencies of this swc.
printDependencies(swcName, xmlWriter, graph);
xmlWriter.writeEndElement(); // SWC
}
xmlWriter.writeEndElement(); // SWC_DEPENDENCY_ORDER
xmlWriter.writeEndDocument();
xmlWriter.flush();
xmlWriter.close();
}
catch (IOException e)
{
final FileIOProblem problem = new FileIOProblem(e);
problems.add(problem);
}
catch (Exception e)
{
final ICompilerProblem problem = new InternalCompilerProblem(e);
problems.add(problem);
}
finally
{
if (xmlWriter != null)
{
try
{
xmlWriter.close();
}
catch (XMLStreamException e)
{
// ignore
}
}
}
}
else
{
result = 1;
}
// Print out any errors we may have encountered
ProblemFormatter formatter = new WorkspaceProblemFormatter(workspace, null);
ProblemPrinter printer = new ProblemPrinter(formatter, System.err);
printer.printProblems(problems.getFilteredProblems());
if( problems.hasErrors() )
result = 1;
return result;
}
/**
* @param swcName name of swc
* @param swcs list of swcs to show. An empty list means show all.
* @return true if the swc should be shown, false otherwise.
*/
private boolean showSwc(String swcName, Listswcs)
{
// filter the swcs that are shown
boolean show = true;
if (swcs.size() != 0)
{
show = false;
for (String showSwc : swcs)
{
if (swcName.endsWith(showSwc))
{
show = true;
break;
}
}
}
return show;
}
/**
* Print the dependencies of a SWC.
*
* @param xmlWriter
* @param graph
* @throws XMLStreamException
*/
private void printDependencies(String swcName, XMLStreamWriter xmlWriter, LibraryDependencyGraph graph) throws XMLStreamException
{
// show swc dependencies
if (config.getShowDependencyList())
{
Set dependencies = graph.getDependencies(swcName);
if (dependencies.size() > 0)
{
xmlWriter.writeStartElement(SWC_DEPENDENCIES_ELEMENT);
// Sort by dependency order so the swcs are always
// in the same order.
List swcDependencies = new ArrayList(graph.getDependencies(swcName));
Collections.sort(swcDependencies,
new Comparator()
{
@Override
public int compare(String o1, String o2)
{
return dependencyOrder.indexOf(o1) - dependencyOrder.indexOf(o2);
}
});
List swcFilter = config.getShowDependentSwcs();
for (String swcDependency : swcDependencies)
{
if (!showSwc(swcDependency, swcFilter))
continue;
println("\t" + swcDependency);
xmlWriter.writeStartElement(SWC_ELEMENT);
xmlWriter.writeAttribute(PATH_ATTRIBUTE, swcDependency);
printExterns(swcName, swcDependency, xmlWriter, graph);
xmlWriter.writeEndElement(); // SWC
}
xmlWriter.writeEndElement(); // SWC_DEPENDENCY_ORDER
}
}
}
/**
* Print the external scripts that are causing the dependency.
*
* @param swcDependency
* @param xmlWriter
* @param graph
* @throws XMLStreamException
*/
private void printExterns(String swcName, String swcDependency,
XMLStreamWriter xmlWriter, LibraryDependencyGraph graph)
throws XMLStreamException
{
// list the external scripts that caused the dependencies between
// swcLocation and swcDepName.
if (config.getShowExterns())
{
xmlWriter.writeStartElement(DEFINITION_DEPENDENCIES_ELEMENT);
Map dependencyMap = graph.getDependencySet(swcName, swcDependency);
for (Map.Entry entry : dependencyMap.entrySet())
{
xmlWriter.writeStartElement(DEFINITION_ELEMENT);
xmlWriter.writeAttribute(ID_ATTRIBUTE, entry.getKey());
if (config.getShowTypes())
{
System.out.print("\t\t" + entry.getKey() + "\t");
StringBuilder sb = new StringBuilder();
for (Iteratoriter = entry.getValue().iterator();
iter.hasNext();)
{
DependencyType type = iter.next();
System.out.print(type.getSymbol());
sb.append(type.getSymbol());
if (iter.hasNext())
{
sb.append(",");
System.out.print(" ");
}
}
println("");
xmlWriter.writeAttribute("types", sb.toString());
}
else
{
println("\t\t" + entry.getKey());
}
xmlWriter.writeEndElement(); // SCRIPT_NAME
}
xmlWriter.writeEndElement(); // DEPENDENT_SCRIPTS
}
}
/**
* @return A writer for the xml-based dependency report.
*
* @throws XMLStreamException
* @throws IOException
*/
private XMLStreamWriter getXMLWriter() throws XMLStreamException, IOException
{
Writer writer = null;
if (config.getDependencyReport() != null)
writer = new FileWriter(config.getDependencyReport());
else
writer = new StringWriter(); // throw away output
final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
assert xmlOutputFactory != null : "Expect XMLOutputFactory implementation.";
return xmlOutputFactory.createXMLStreamWriter(writer);
}
/**
* @return the dependency set requested by the user. The default to
* to show all dependency types.
*/
private DependencyTypeSet getDependencyTypeSet()
{
List desiredDependencies = config.getDesiredScriptDependencyTypes();
if (desiredDependencies != null)
{
DependencyTypeSet dependencySet = DependencyTypeSet.noneOf();
List validDependencies = new ArrayList();
for (DependencyType type : DependencyTypeSet.allOf())
{
validDependencies.add(String.valueOf(type.getSymbol()));
}
// convert strings to a enum set.
for (String desiredDependency : desiredDependencies)
{
if (validDependencies.contains(desiredDependency))
dependencySet.add(DependencyType.get(desiredDependency.charAt(0)));
}
return dependencySet;
}
return DependencyTypeSet.allOf();
}
/**
* Load configurations from all the sources.
*
* @param args command line arguments
* @return True if mxmlc should continue with compilation.
*/
protected boolean configure(final String[] args)
{
projectConfigurator = createConfigurator();
try
{
ConfigurationPathResolver resolver = new ConfigurationPathResolver(System.getProperty("user.dir"));
projectConfigurator.setConfigurationPathResolver(resolver);
projectConfigurator.setConfiguration(args, getConfigurationDefaultVariable());
projectConfigurator.applyToProject(project);
problems = new ProblemQuery(projectConfigurator.getCompilerProblemSettings());
// Get the configuration and configBuffer which are now initialized.
config = (DependencyConfiguration)projectConfigurator.getConfiguration();
Messages.setLocale(config.getToolsLocale());
configBuffer = projectConfigurator.getConfigurationBuffer();
problems.addAll(projectConfigurator.getConfigurationProblems());
// Print version if "-version" is present.
if (configBuffer.getVar("version") != null)
{
println(VersionInfo.buildMessage());
return false;
}
// Print help if "-help" is present.
final List helpVar = configBuffer.getVar("help");
if (helpVar != null)
{
processHelp(helpVar);
return false;
}
for (String fileName : projectConfigurator.getLoadedConfigurationFiles())
{
println(Messages.getString("MXMLC.Loading_configuration_format",
Collections.singletonMap("configurationName", fileName)));
}
// Add a blank line between the configuration list and the rest of
// the output to make the start of the output easier to detect.
println("");
// If we have configuration errors then exit before trying to
// validate the target.
if (problems.hasErrors())
return false;
return true;
}
catch (Exception e)
{
final ICompilerProblem problem = new ConfigurationProblem(null, -1, -1, -1, -1, e.getMessage());
problems.add(problem);
return false;
}
}
/**
* Print detailed help information if -help is provided.
*/
private void processHelp(final List helpVar)
{
final Set keywords = new LinkedHashSet();
for (final ConfigurationValue val : helpVar)
{
for (final 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");
final String usages = CommandLineConfigurator.usage(
getProgramName(),
DEFAULT_VAR,
configBuffer,
keywords,
LocalizationManager.get(),
L10N_CONFIG_PREFIX);
println(getStartMessage());
println(usages);
}
/**
* Print a message.
*
* @param msg Message text.
*/
protected void println(final String msg)
{
System.out.println(msg);
}
/**
* Get the start up message that contains the program name with the
* copyright notice.
*
* @return the start up message.
*/
private String getStartMessage()
{
// This must not be localized.
String message = "SWC Dependency utility (swcdepends)" + NEWLINE +
VersionInfo.buildMessage() + NEWLINE;
return message;
}
private String getConfigurationDefaultVariable()
{
return DEFAULT_VAR;
}
private Configurator createConfigurator()
{
return new Configurator(DependencyConfiguration.class);
}
/**
* @return always "swcdepends"
*/
private String getProgramName()
{
return "swcdepends";
}
/**
* dependency.* configuration options
*
*/
public static class DependencyConfiguration extends Configuration
{
//
// 'show-external-classes' option
//
// Should we show the external scripts
//
private boolean showExterns = false;
public boolean getShowExterns()
{
return showExterns;
}
@Config
@Mapping({"dependency", "show-external-classes"})
public void setShowExternalClasses(ConfigurationValue cv, boolean showExterns) throws ConfigurationException
{
this.showExterns = showExterns;
}
//
// 'show-dependency-list' option
//
// Should swc dependencies be shown in addition to the dependency
// order?
//
private boolean showDependencyList = true;
public boolean getShowDependencyList()
{
return showDependencyList;
}
@Config
@Mapping({"dependency", "show-dependency-list"})
public void setShowDependencyList(ConfigurationValue cv, boolean showSwcDependencies) throws ConfigurationException
{
this.showDependencyList = showSwcDependencies;
}
//
// 'show-types' option
//
// Should we show the external scripts
//
private boolean showTypes = false;
public boolean getShowTypes()
{
return showTypes;
}
@Config
@Mapping({"dependency", "show-types"})
@SoftPrerequisites("show-external-classes")
public void setShowTypes(ConfigurationValue cv, boolean showTypes) throws ConfigurationException
{
this.showTypes = showTypes;
// if showTypes is set, then turn on show-external-classes show the types will be seen.
if (showTypes)
showExterns = true;
}
//
// 'types' option
//
private List desiredTypes = new LinkedList();
public List getDesiredScriptDependencyTypes()
{
return desiredTypes;
}
@Config(allowMultiple=true)
@Mapping({"dependency", "types"})
@Arguments("type")
@InfiniteArguments
public void setTypes( ConfigurationValue cfgval, String[] types ) throws ConfigurationException
{
for (int i = 0; i < types.length; ++i)
{
desiredTypes.add( types[i] );
}
}
//
// 'show-swcs' option
//
// Filter which SWCs to show in the dependency order.
//
private List showSwcs = new LinkedList();
public List getShowSwcs()
{
return showSwcs;
}
@Config(allowMultiple = true)
@Mapping({"dependency", "show-swcs"})
@Arguments("swc-name")
@InfiniteArguments
public void setShowSwcs(ConfigurationValue cfgval, String[] swcs) throws ConfigurationException
{
for (int i = 0; i < swcs.length; ++i)
{
showSwcs.add(swcs[i]);
}
}
//
// 'show-swcs' option
//
// Filter which SWCs to show in the "dependent SWCs" list.
//
private List showDependentSwcs = new LinkedList();
public List getShowDependentSwcs()
{
return showDependentSwcs;
}
@Config(allowMultiple = true)
@Mapping({"dependency", "show-dependent-swcs"})
@Arguments("swc-name")
@InfiniteArguments
public void setShowDependentSwcs(ConfigurationValue cfgval, String[] swcs) throws ConfigurationException
{
for (int i = 0; i < swcs.length; ++i)
{
showDependentSwcs.add(swcs[i]);
}
}
//
// 'minimize-dependency-set' option
//
// Removes a SWC from the dependency set if the scripts resolved in a SWC are a subset of the scripts resolved in another dependent SWC.
// No longer supported, the dependency set is always minimized.
//
@Config(removed=true)
@Mapping({"dependency", "minimize-dependency-set"})
public void setMinimizeDependencySet(ConfigurationValue cv, boolean minimumSet) throws ConfigurationException
{
// leave configuration option here so old scripts do not error.
}
//
// -dependency-report option
//
// Takes a path that specifies a filename where an xml version of the report
// is written.
private String dependencyReportFileName;
public File getDependencyReport()
{
return dependencyReportFileName != null ? new File(dependencyReportFileName) : null;
}
@Config()
@Mapping({"dependency", "dependency-report"})
@Arguments("filename")
public void setDependencyReport(ConfigurationValue cv, String filename)
{
this.dependencyReportFileName = getOutputPath(cv, filename);
}
}
}