/* * Copyright 2009 Google Inc. * * Licensed 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 com.google.gwt.core.linker; import com.google.gwt.core.ext.Linker; import com.google.gwt.core.ext.LinkerContext; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.linker.Artifact; import com.google.gwt.core.ext.linker.ArtifactSet; import com.google.gwt.core.ext.linker.CompilationResult; import com.google.gwt.core.ext.linker.EmittedArtifact; import com.google.gwt.core.ext.linker.EmittedArtifact.Visibility; import com.google.gwt.core.ext.linker.LinkerOrder; import com.google.gwt.core.ext.linker.LinkerOrder.Order; import com.google.gwt.core.ext.linker.ModuleMetricsArtifact; import com.google.gwt.core.ext.linker.SelectionProperty; import com.google.gwt.core.ext.linker.Shardable; import com.google.gwt.core.ext.linker.SyntheticArtifact; import com.google.gwt.core.ext.linker.Transferable; import com.google.gwt.soyc.CompilerMetricsXmlFormatter; import com.google.gwt.soyc.SoycDashboard; import com.google.gwt.soyc.io.ArtifactsOutputDirectory; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * Converts SOYC report files into emitted private artifacts. */ @LinkerOrder(Order.POST) @Shardable public class SoycReportLinker extends Linker { /** * An artifact giving a one-line description of a permutation ID in terms of * its deferred bindings. */ @Transferable private static class PermDescriptionArtifact extends Artifact<PermDescriptionArtifact> { private List<String> permDesc; private int permId; public PermDescriptionArtifact(int permId, List<String> permDesc) { super(SoycReportLinker.class); this.permId = permId; this.permDesc = permDesc; } public List<String> getPermDesc() { return permDesc; } public int getPermId() { return permId; } @Override public int hashCode() { return permId; } @Override protected int compareToComparableArtifact(PermDescriptionArtifact o) { int cmp; cmp = permId - o.getPermId(); if (cmp != 0) { return cmp; } cmp = permDesc.size() - o.getPermDesc().size(); if (cmp != 0) { return cmp; } for (int i = 0; i < permDesc.size(); i++) { cmp = permDesc.get(i).compareTo(o.getPermDesc().get(i)); if (cmp != 0) { return cmp; } } return 0; } @Override protected Class<PermDescriptionArtifact> getComparableArtifactType() { return PermDescriptionArtifact.class; } } @Override public String getDescription() { return "Emit compile report artifacts"; } @Override public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts, boolean onePermutation) { boolean reportFilesPresent = anyReportFilesPresent(artifacts); boolean metricsPresent = anyCompilerMetricsPresent(artifacts); if (!reportFilesPresent && !metricsPresent) { return artifacts; } artifacts = new ArtifactSet(artifacts); if (!onePermutation) { buildCompilerMetricsXml(artifacts); } if (reportFilesPresent) { if (onePermutation) { emitPermutationDescriptions(artifacts); } else { buildTopLevelFiles(logger, artifacts); } } return artifacts; } /** * Check whether an artifact set contains any compilerMetrics. */ boolean anyCompilerMetricsPresent(ArtifactSet artifacts) { return !artifacts.find(ModuleMetricsArtifact.class).isEmpty(); } /** * Check whether an artifact set contains any SOYC report documents. */ boolean anyReportFilesPresent(ArtifactSet artifacts) { String prefix1 = ArtifactsOutputDirectory.COMPILE_REPORT_DIRECTORY + "/"; String prefix2 = "soycReport/" + prefix1; for (EmittedArtifact art : artifacts.find(EmittedArtifact.class)) { if (art.getPartialPath().startsWith(prefix1)) { return true; } if (art.getPartialPath().startsWith(prefix2)) { return true; } } return false; } /** * Compiler Metrics are captured in the module load, precompilation, * and compile permutations step, then all merged together into a single * XML file as output. That file can then be consumed by external * reporting tools. */ private void buildCompilerMetricsXml(ArtifactSet artifacts) { ModuleMetricsArtifact moduleMetrics = null; Set<ModuleMetricsArtifact> moduleMetricsSet = artifacts.find( ModuleMetricsArtifact.class); if (!moduleMetricsSet.isEmpty()) { for (ModuleMetricsArtifact metrics : moduleMetricsSet) { moduleMetrics = metrics; // We only need one module metrics definition. break; } } // No module metrics? Then we'll skip creating the compilerMetrics output if (moduleMetrics == null) { return; } byte[] xmlResult = CompilerMetricsXmlFormatter.writeMetricsAsXml( artifacts, moduleMetrics); EmittedArtifact metricsArtifact = new SyntheticArtifact( SoycReportLinker.class, "compilerMetrics.xml", xmlResult); metricsArtifact.setVisibility(Visibility.Private); artifacts.add(metricsArtifact); } private void buildTopLevelFiles(TreeLogger logger, ArtifactSet artifacts) { ArtifactsOutputDirectory out = new ArtifactsOutputDirectory(); try { new SoycDashboard(out).generateCrossPermutationFiles( extractPermutationDescriptions(artifacts)); } catch (IOException e) { logger.log(TreeLogger.ERROR, "Error while generating a Story of Your Compile", e); e.printStackTrace(); } artifacts.addAll(out.getArtifacts()); } private void emitPermutationDescriptions(ArtifactSet artifacts) { for (CompilationResult res : artifacts.find(CompilationResult.class)) { int permId = res.getPermutationId(); List<String> permDesc = new ArrayList<String>(); for (Map<SelectionProperty, String> propertyMap : res.getPropertyMap()) { permDesc.add(SymbolMapsLinker.propertyMapToString(propertyMap)); } artifacts.add(new PermDescriptionArtifact(permId, permDesc)); } } private Map<String, List<String>> extractPermutationDescriptions( ArtifactSet artifacts) { Map<String, List<String>> permDescriptions = new TreeMap<String, List<String>>(); for (PermDescriptionArtifact art : artifacts.find( PermDescriptionArtifact.class)) { permDescriptions.put(Integer.toString(art.getPermId()), art.getPermDesc()); } return permDescriptions; } }