rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/AheadOfTime.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sat, 06 Dec 2014 06:28:17 +0100
changeset 1737 82fd3830167d
parent 1710 6db177c4f72c
child 1762 293838e72201
permissions -rw-r--r--
Ability to extract precompiled bck2brwsr JavaScript files from Maven artifacts named bck2brwsr
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 2 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. Look for COPYING file in the top folder.
    16  * If not, see http://opensource.org/licenses/GPL-2.0.
    17  */
    18 
    19 package org.apidesign.bck2brwsr.mojo;
    20 
    21 import java.io.File;
    22 import java.io.FileWriter;
    23 import java.io.IOException;
    24 import java.io.InputStream;
    25 import java.net.MalformedURLException;
    26 import java.net.URL;
    27 import java.net.URLClassLoader;
    28 import java.nio.file.Files;
    29 import java.util.ArrayList;
    30 import java.util.Collection;
    31 import java.util.List;
    32 import java.util.Map;
    33 import java.util.jar.Attributes;
    34 import java.util.jar.JarFile;
    35 import java.util.jar.Manifest;
    36 import java.util.zip.ZipEntry;
    37 import org.apache.maven.artifact.Artifact;
    38 import org.apache.maven.plugin.AbstractMojo;
    39 import org.apache.maven.plugin.MojoExecutionException;
    40 import org.apache.maven.plugin.MojoFailureException;
    41 import org.apache.maven.plugins.annotations.LifecyclePhase;
    42 import org.apache.maven.plugins.annotations.Mojo;
    43 import org.apache.maven.plugins.annotations.Parameter;
    44 import org.apache.maven.plugins.annotations.ResolutionScope;
    45 import org.apache.maven.project.MavenProject;
    46 import org.apidesign.bck2brwsr.aot.Bck2BrwsrJars;
    47 import org.apidesign.vm4brwsr.Bck2Brwsr;
    48 import org.apidesign.vm4brwsr.ObfuscationLevel;
    49 
    50 /**
    51  *
    52  * @author Jaroslav Tulach
    53  * @since 0.9
    54  */
    55 @Mojo(name = "aot",
    56     requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
    57     defaultPhase = LifecyclePhase.PACKAGE
    58 )
    59 public class AheadOfTime extends AbstractMojo {
    60     @Parameter(defaultValue = "${project}")
    61     private MavenProject prj;
    62     
    63     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.jar")
    64     private File mainJar;
    65 
    66     @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.js")
    67     private File mainJavaScript;
    68     
    69     @Parameter
    70     private String[] exports;
    71     
    72     /**
    73      * Directory where to generate ahead-of-time JavaScript files for
    74      * required libraries.
    75      */
    76     @Parameter(defaultValue = "lib")
    77     private String classPathPrefix;
    78 
    79     /** Root JavaScript file to generate */
    80     @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
    81     private File vm;
    82     
    83     @Parameter(defaultValue = "true")
    84     private boolean generateAotLibraries;
    85     
    86     /**
    87      * The obfuscation level for the generated JavaScript file.
    88      *
    89      * @since 0.5
    90      */
    91     @Parameter(defaultValue = "NONE")
    92     private ObfuscationLevel obfuscation;
    93     
    94     @Override
    95     public void execute() throws MojoExecutionException, MojoFailureException {
    96         URLClassLoader loader;
    97         try {
    98             loader = buildClassLoader(mainJar, prj.getArtifacts());
    99         } catch (MalformedURLException ex) {
   100             throw new MojoFailureException("Can't initialize classloader");
   101         }
   102         for (Artifact a : prj.getArtifacts()) {
   103             if (a.getFile() == null) {
   104                 continue;
   105             }
   106             String n = a.getFile().getName();
   107             if (!n.endsWith(".jar")) {
   108                 continue;
   109             }
   110             if ("provided".equals(a.getScope())) {
   111                 continue;
   112             }
   113             File aot = new File(prj.getBuild().getDirectory(), classPathPrefix);
   114             aot.mkdirs();
   115             File js = new File(aot, n.substring(0, n.length() - 4) + ".js");
   116             if (js.exists()) {
   117                 getLog().info("Skipping " + js + " as it already exists.");
   118                 continue;
   119             }
   120             try {
   121                 aotLibrary(a, js , loader);
   122             } catch (IOException ex) {
   123                 throw new MojoFailureException("Can't compile " + a.getFile(), ex);
   124             }
   125         }
   126         
   127         try {
   128             if (mainJavaScript.exists()) {
   129                 getLog().info("Skipping " + mainJavaScript + " as it already exists.");
   130             } else {
   131                 getLog().info("Generating " + mainJavaScript);
   132                 Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, mainJar, loader);
   133                 if (exports != null) {
   134                     for (String e : exports) {
   135                         c = c.addExported(e.replace('.', '/'));
   136                     }
   137                 }
   138                 FileWriter w = new FileWriter(mainJavaScript);
   139                 c.
   140                         obfuscation(obfuscation).
   141                         generate(w);
   142                 w.close();
   143             }
   144         } catch (IOException ex) {
   145             throw new MojoFailureException("Cannot generate script for " + mainJar, ex);
   146         }
   147             
   148         try {
   149             FileWriter w = new FileWriter(vm);
   150             Bck2Brwsr.newCompiler().
   151                     obfuscation(obfuscation).
   152                     standalone(false).
   153                     resources(new Bck2Brwsr.Resources() {
   154 
   155                 @Override
   156                 public InputStream get(String resource) throws IOException {
   157                     return null;
   158                 }
   159             }).
   160                     generate(w);
   161             w.close();
   162             
   163         } catch (IOException ex) {
   164             throw new MojoExecutionException("Can't compile", ex);
   165         }
   166     }
   167 
   168     private void aotLibrary(Artifact a, File js, URLClassLoader loader) throws IOException, MojoExecutionException {
   169         for (Artifact b : prj.getArtifacts()) {
   170             if ("bck2brwsr".equals(b.getClassifier())) { // NOI18N
   171                 getLog().debug("Inspecting " + b.getFile());
   172                 JarFile jf = new JarFile(b.getFile());
   173                 Manifest man = jf.getManifest();
   174                 for (Map.Entry<String, Attributes> entrySet : man.getEntries().entrySet()) {
   175                     String entryName = entrySet.getKey();
   176                     Attributes attr = entrySet.getValue();
   177                     
   178                     if (
   179                         a.getArtifactId().equals(attr.getValue("Bck2BrwsrArtifactId")) &&
   180                         a.getGroupId().equals(attr.getValue("Bck2BrwsrGroupId")) &&
   181                         a.getVersion().equals(attr.getValue("Bck2BrwsrVersion")) &&
   182                         (
   183                             obfuscation == ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrMinified"))
   184                             ||
   185                             obfuscation != ObfuscationLevel.FULL && "true".equals(attr.getValue("Bck2BrwsrDebug"))
   186                         )
   187                     ) {
   188                         getLog().info("Extracting " + js + " from " + b.getFile());
   189                         InputStream is = jf.getInputStream(new ZipEntry(entryName));
   190                         Files.copy(is, js.toPath());
   191                         is.close();
   192                         return;
   193                     }
   194                 }
   195             }
   196         }
   197         if (!generateAotLibraries) {
   198             throw new MojoExecutionException("Not generating " + js + " and no precompiled version found!");
   199         }
   200         getLog().info("Generating " + js);
   201         FileWriter w = new FileWriter(js);
   202         Bck2Brwsr c = Bck2BrwsrJars.configureFrom(null, a.getFile(), loader);
   203         c.
   204             obfuscation(obfuscation).
   205             generate(w);
   206         w.close();
   207     }
   208     private static URLClassLoader buildClassLoader(File root, Collection<Artifact> deps) throws MalformedURLException {
   209         List<URL> arr = new ArrayList<URL>();
   210         if (root != null) {
   211             arr.add(root.toURI().toURL());
   212         }
   213         for (Artifact a : deps) {
   214             if (a.getFile() != null) {
   215                 arr.add(a.getFile().toURI().toURL());
   216             }
   217         }
   218         return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
   219     }
   220 }