net.flexmojos.oss.plugin.optimizer.AbstractOptimizerMojo Maven / Gradle / Ivy
/**
* Flexmojos is a set of maven goals to allow maven users to compile, optimize and test Flex SWF, Flex SWC, Air SWF and Air SWC.
* Copyright (C) 2008-2012 Marvin Froeder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package net.flexmojos.oss.plugin.optimizer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import org.apache.maven.model.Build;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.util.FileUtils;
import net.flexmojos.oss.compiler.FlexCompiler;
import net.flexmojos.oss.compiler.ICompilerConfiguration;
import net.flexmojos.oss.compiler.IOptimizerConfiguration;
import net.flexmojos.oss.plugin.AbstractMavenMojo;
import net.flexmojos.oss.plugin.utilities.ConfigurationResolver;
import net.flexmojos.oss.util.PathUtil;
import scala.None$;
import scala.Option;
import scala.Some;
import apparat.tools.reducer.MatryoshkaType;
import apparat.tools.reducer.Reducer.ReducerTool;
import apparat.tools.reducer.ReducerConfiguration;
import apparat.tools.stripper.Stripper.StripperTool;
import apparat.tools.stripper.StripperConfiguration;
public abstract class AbstractOptimizerMojo
extends AbstractMavenMojo
{
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat( "#.##" );
/**
* @parameter expression="${project.build}"
* @required
* @readonly
*/
protected Build build;
/**
* @component
*/
protected FlexCompiler compiler;
/**
* The maven configuration directory
*
* @parameter expression="${basedir}/src/main/config"
* @required
* @readonly
*/
protected File configDirectory;
/**
* Keep the specified metadata in the SWF
*
* Equivalent to -compiler.keep-as3-metadata
*
* Usage:
*
*
* <keepAs3Metadatas>
* <keepAs3Metadata>Bindable</keepAs3Metadata>
* <keepAs3Metadata>Events</keepAs3Metadata>
* </keepAs3Metadatas>
*
*
* @parameter
*/
protected String[] keepAs3Metadatas;
/**
* Load a file containing configuration options.
*
* Equivalent to -load-config
*
* Overwrite loadConfigs when defined!
*
* @parameter expression="${flex.loadConfig}"
*/
protected File loadConfig;
/**
* Load a file containing configuration options
*
* Equivalent to -load-config
*
* Usage:
*
*
* <loadConfigs>
* <loadConfig>???</loadConfig>
* <loadConfig>???</loadConfig>
* </loadConfigs>
*
*
* @parameter
*/
protected File[] loadConfigs;
/**
* The project packaging type.
*
* @parameter expression="${project.packaging}"
* @required
* @readonly
*/
protected String packaging;
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
protected MavenProject project;
/**
* @component
*/
protected MavenProjectHelper projectHelper;
/**
* Use apparat to reduce the file size of SWFs by making use of the full feature set the Flash Player provides and
* which is ignored by the ActionScript compiler.
*
* Equivalent to apparat reducer
*
* Reducer will only touch lossless images and not touch you encoded JPEG images
*
* @parameter default-value="true" expression="${flex.reduce}"
*/
protected boolean reduce;
/**
* Strength of deblocking filter
*
* Equivalent to -d
*
*
* @parameter expression="${flex.reduceDeblock}"
*/
private float reduceDeblock;
/**
* Whether or not to use LZMA compression. Only available with SWF files.
*
* @parameter expression="${flex.reduceLzma}" default-value="false"
*/
private boolean reduceLzma;
/**
* Which Matryoshka implementation to use, valid values are: "none", "quiet" or "preloader".
*
* @parameter expression="${flex.reduceMatryoshkaType}" default-value="none"
*/
private String reduceMatryoshkaType;
/**
* A custom Matryoshka. Only used if the matryoshkaType is set to "custom".
*
* @parameter expression="${flex.reduceMatryoshka}"
*/
private File reduceMatryoshka;
/**
* Whether or not to merge ABC files into a single one.
*
* Equivalent to -d
*
*
* @parameter expression="${flex.reduceMergeABC}" default-value="true"
*/
private boolean reduceMergeABC;
/**
* Compression quality from 0.0 to 1.0
*
* Equivalent to -q
*
*
* @parameter expression="${flex.reduceQuality}"
*/
private float reduceQuality;
/**
* Whether or not to sort the constant pool. Only if reduceMergeABC
is specified.
*
* @parameter expression="${flex.reduceSortCPool}" default-value="true"
*/
private boolean reduceSortCPool;
/**
* Whether or not to merge control flow where possible.
*
* @parameter expression="${flex.reduceMergeCF}" default-value="true"
*/
private boolean reduceMergeCF;
/**
* Use apparat to strip
*
* Equivalent to apparat stripper
*
*
* @parameter default-value="true" expression="${flex.strip}"
*/
protected boolean strip;
/**
* Name of the Flex Tool Group that should be used for the build.
*
* @parameter expression="${flex.compilerName}"
*/
protected String compilerName;
public abstract String getInput();
public String[] getKeepAs3Metadata()
{
return keepAs3Metadatas;
}
public String[] getLoadConfig()
{
return PathUtil.paths( ConfigurationResolver.resolveConfiguration( loadConfigs, loadConfig, configDirectory ) );
}
public IOptimizerConfiguration getOptimizerConfiguration( File input, File output )
{
// mocking real code doesn't seem to be a good idea, but produces a much cleaner code
IOptimizerConfiguration cfg = mock( IOptimizerConfiguration.class, RETURNS_NULL );
ICompilerConfiguration compilerCfg = mock( ICompilerConfiguration.class, RETURNS_NULL );
when( cfg.getLoadConfig() ).thenReturn( getLoadConfig() );
when( cfg.getInput() ).thenReturn( PathUtil.path( input ) );
when( cfg.getOutput() ).thenReturn( PathUtil.path( output ) );
when( cfg.getCompilerConfiguration() ).thenReturn( compilerCfg );
when( compilerCfg.getKeepAs3Metadata() ).thenReturn( getKeepAs3Metadata() );
return cfg;
}
public String getOutput()
{
return PathUtil.path( new File( build.getDirectory(), build.getFinalName() + ".swf" ) );
}
protected File optimize()
throws MojoFailureException, MojoExecutionException
{
File input = PathUtil.file( getInput() );
double originalSize = input.length();
{
getLog().debug( "Backuping original file " + input );
final File output = new File( project.getBuild().getOutputDirectory(), "original.swf" );
try
{
FileUtils.copyFile( input, output );
}
catch ( IOException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
input = output;
}
input = optimize( input );
if ( reduce )
{
getLog().debug( "Reducing" );
final File output = new File( project.getBuild().getOutputDirectory(), "reduced.swf" );
reduce( input, output );
input = output;
}
if ( strip )
{
getLog().debug( "Stripping" );
final File output = new File( project.getBuild().getOutputDirectory(), "stripped.swf" );
reduce( input, output );
input = output;
}
{
getLog().debug( "Placing optimized file on target folder" );
final File output = PathUtil.file( getOutput() );
try
{
FileUtils.copyFile( input, output );
}
catch ( IOException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
double finalSize = output.length();
double rate = ( finalSize / originalSize ) * 100;
getLog().info( "Optimization result: " + DECIMAL_FORMAT.format( rate ) + "%" );
return output;
}
}
protected abstract File optimize( File input )
throws MojoFailureException, MojoExecutionException;
protected void optimize( File input, File output )
throws MojoFailureException, MojoExecutionException
{
int result;
try
{
result = compiler.optimize( getOptimizerConfiguration( input, output ), true, compilerName ).getExitCode();
}
catch ( Exception e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
if ( result != 0 )
{
throw new MojoFailureException( "Got " + result + " errors building project, check logs" );
}
}
protected void reduce( final File input, final File output )
{
ReducerTool s = new ReducerTool();
ReducerConfiguration cfg = new ReducerConfiguration()
{
public float deblock()
{
return reduceDeblock;
}
public File input()
{
return input;
}
public boolean lzma()
{
return reduceLzma;
}
public int matryoshkaType()
{
if ( reduceMatryoshkaType.equalsIgnoreCase( "quiet" ) )
{
return MatryoshkaType.QUIET();
}
else if ( reduceMatryoshkaType.equalsIgnoreCase( "preloader" ) )
{
return MatryoshkaType.PRELOADER();
}
else if ( reduceMatryoshkaType.equalsIgnoreCase( "custom" ) )
{
return MatryoshkaType.CUSTOM();
}
else
{
return MatryoshkaType.NONE();
}
}
@SuppressWarnings( "unchecked" )
public Option matryoshka()
{
return ( null == reduceMatryoshka ) ? None$.MODULE$ : new Some( reduceMatryoshka );
}
public boolean mergeABC()
{
return reduceMergeABC;
}
public File output()
{
return output;
}
public float quality()
{
return reduceQuality;
}
public boolean sortCPool()
{
return reduceSortCPool;
}
public boolean mergeCF()
{
return reduceMergeCF;
}
};
s.configure( cfg );
s.run();
}
protected void strip( final File input, final File output )
{
StripperTool s = new StripperTool();
StripperConfiguration cfg = new StripperConfiguration()
{
public File input()
{
return input;
}
public File output()
{
return output;
}
};
s.configure( cfg );
s.run();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy