package com.digiarea.closurefx.cli.compiler; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ResourceBundle; import com.digiarea.closure.core.IPathResolver; import com.digiarea.closure.core.Path; import com.digiarea.closure.model.ClosureJs; import com.digiarea.closurefx.IConstants; import com.digiarea.closurefx.build.validation.IStatus.StatusType; import com.digiarea.closurefx.build.validation.Status; import com.google.common.io.Files; import com.google.javascript.jscomp.CommandLineRunner; import com.google.javascript.jscomp.Compiler; import com.google.javascript.jscomp.CompilerOptions; import com.google.javascript.jscomp.JSModule; import com.google.javascript.jscomp.Result; import com.google.javascript.jscomp.SourceFile; public class JSCCompilerCli extends Compiler { private IPathResolver pathResolver; private ClosureJs closureJs; private CompilerOptions options; private List<File> sources; private List<File> externs; private ResourceBundle resourceBundle; private JSCPrintStreamErrorManager errorManager; public JSCCompilerCli(ClosureJs closureJs, CompilerOptions options, List<File> sources, List<File> externs, IPathResolver pathResolver) { this.closureJs = closureJs; this.options = options; this.sources = sources; this.externs = externs; this.pathResolver = pathResolver; } public void setResourceBundle(ResourceBundle resourceBundle) { this.resourceBundle = resourceBundle; } public void setErrorManager(JSCPrintStreamErrorManager errorManager) { super.setErrorManager(errorManager); this.errorManager = errorManager; } public JSCPrintStreamErrorManager getErrorManager() { return errorManager; } /** * Compile Buildpath from ClosureJs. * * @param delta * For incremental build. If delta contains JS files which are in * the buildpath, perform full build. */ public void build() { getErrorManager().reportMessage( new Status(StatusType.INFO, resourceBundle .getString(IConstants.Console_Start), null)); List<SourceFile> units = new ArrayList<SourceFile>(); List<SourceFile> unitExterns = new ArrayList<SourceFile>(); try { unitExterns.addAll(CommandLineRunner.getDefaultExterns()); } catch (IOException e) { getErrorManager().reportMessage( new Status(StatusType.WARNING, resourceBundle .getString(IConstants.JSConsole_Externs), null)); } for (File string : sources) { if (!string.exists()) { getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_SourceInvalid), string.getAbsolutePath()), null)); } else { try { SourceFile jsFile = SourceFile.fromFile(string, getCharset(closureJs.getCharset())); units.add(jsFile); } catch (Exception e) { getErrorManager().reportMessage( new Status(StatusType.ERROR, string .getAbsolutePath(), e)); } } } for (File string : externs) { if (!string.exists()) { getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_ExternInvalid), string.getAbsolutePath()), null)); } else { SourceFile jsFile = SourceFile.fromFile(string, getCharset(closureJs.getCharset())); unitExterns.add(jsFile); } } if (closureJs.isDevmode()) { devBuild(units, unitExterns); } else { build(units, unitExterns); } } private Charset getCharset(String charset) { return Charset.forName(charset); } private void devBuild(List<SourceFile> sources, List<SourceFile> externs) { JSModule module = new JSModule("DevMode Module"); for (SourceFile sourceFile : sources) { module.add(sourceFile); } initModules(externs, Arrays.asList(module), options); parse(); check(); } /** * @param sources * @param externs */ public void build(List<SourceFile> sources, List<SourceFile> externs) { try { Result result = compile(externs, sources, options); if (result.success && !isIdeMode()) { String realPath = pathResolver.toRealPath(new Path(closureJs .getOutput().getPath()).append( closureJs.getOutput().getFile()).toString()); if (realPath != null) { File file = new File(realPath); if (file.exists()) { file.delete(); } try { Files.createParentDirs(file); Files.write(toSource().getBytes(), file); getErrorManager() .reportMessage( new Status( StatusType.INFO, resourceBundle .getString(IConstants.JSConsole_Output), null)); } catch (IOException e) { e.printStackTrace(); getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_OutputFailed), realPath), e)); } } if (result.sourceMap != null && closureJs.getSourceMapFile() != null && !closureJs.getSourceMapFile().isEmpty()) { writeSourceMap(result, pathResolver.toRealPath(closureJs .getSourceMapFile()), realPath); } if (result.externExport != null && !result.externExport.isEmpty() && closureJs.getExternExportsPath() != null && !closureJs.getExternExportsPath().isEmpty()) { File file = new File(pathResolver.toRealPath(closureJs .getExternExportsPath())); try { Files.createParentDirs(file); Files.write(result.externExport.getBytes(), file); } catch (IOException e) { e.printStackTrace(); getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_OutputExternsFailed), file.getAbsoluteFile()), null)); } } if (closureJs.getRenaming() != null) { String variableOutput = closureJs.getRenaming() .getVariableMap().getOutput(); if (result.variableMap != null && variableOutput != null && !variableOutput.isEmpty()) { try { result.variableMap.save(pathResolver .toRealPath(variableOutput)); } catch (IOException e) { e.printStackTrace(); getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_VariableMapFailed), variableOutput), null)); } } String propertyOutput = closureJs.getRenaming() .getPropertyMap().getOutput(); if (result.propertyMap != null && propertyOutput != null && !propertyOutput.isEmpty()) { try { result.propertyMap.save(pathResolver .toRealPath(propertyOutput)); } catch (IOException e) { e.printStackTrace(); getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_PropertyMapFailed), propertyOutput), null)); } } String functionOutput = closureJs.getRenaming() .getFunctionMap().getOutput(); if (result.namedAnonFunctionMap != null && functionOutput != null && !functionOutput.isEmpty()) { try { result.namedAnonFunctionMap.save(pathResolver .toRealPath(functionOutput)); } catch (IOException e) { e.printStackTrace(); getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_FunctionMapFailed), functionOutput), null)); } } } } } catch (Exception e) { if (e instanceof InterruptedException || (e.getCause() != null && e.getCause() instanceof InterruptedException)) { getErrorManager().reportMessage( new Status(StatusType.ERROR, resourceBundle .getString(IConstants.Console_Interrupted), null)); } else { getErrorManager().reportMessage( new Status(StatusType.ERROR, "", e)); } } getErrorManager().reportMessage( new Status(StatusType.INFO, resourceBundle .getString(IConstants.Console_Finish), null)); } private void writeSourceMap(Result result, String sourceMap, String output) { File file = new File(sourceMap); try { StringBuffer buffer = new StringBuffer(); result.sourceMap.appendTo(buffer, output); Files.createParentDirs(file); Files.write(buffer.toString().getBytes(), file); } catch (IOException e) { getErrorManager() .reportMessage( new Status( StatusType.ERROR, MessageFormat.format( resourceBundle .getString(IConstants.JSConsole_SourceMapFailed), sourceMap), null)); } } }