
net.jangaroo.jooc.mvnplugin.AbstractSenchaMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jangaroo-maven-plugin Show documentation
Show all versions of jangaroo-maven-plugin Show documentation
This plugin compiles Jangaroo sources to JavaScript.
The newest version!
package net.jangaroo.jooc.mvnplugin;
import net.jangaroo.apprunner.util.AppManifestDeSerializer;
import net.jangaroo.jooc.config.SearchAndReplace;
import net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils;
import net.jangaroo.jooc.mvnplugin.util.ConversionUtils;
import net.jangaroo.jooc.mvnplugin.util.FileHelper;
import net.jangaroo.jooc.mvnplugin.util.MergeHelper;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingResult;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import static net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils.APP_MANIFEST_FILENAME;
import static net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils.APP_MANIFEST_FRAGMENT_FILENAME;
import static net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils.DEFAULT_LOCALE;
import static net.jangaroo.jooc.mvnplugin.util.MavenPluginHelper.META_INF_PKG;
import static net.jangaroo.jooc.mvnplugin.util.MavenPluginHelper.META_INF_RESOURCES;
public abstract class AbstractSenchaMojo extends AbstractMojo {
protected static final MergeHelper.MergeOptions APP_MANIFEST_CROSS_MODULE_MERGE_STRATEGY = new MergeHelper.MergeOptions(
MergeHelper.ListStrategy.APPEND, MergeHelper.MapStrategy.MERGE
);
protected static final MergeHelper.MergeOptions APP_MANIFEST_LOCALIZATION_MERGE_STRATEGY = new MergeHelper.MergeOptions(
MergeHelper.ListStrategy.MERGE, MergeHelper.MapStrategy.MERGE
);
@Parameter(defaultValue = "${project}", required = true, readonly = true)
protected MavenProject project;
@Parameter(defaultValue = "${session}", required = true, readonly = true)
protected MavenSession session;
@Component
ArtifactHandlerManager artifactHandlerManager;
@Component
private ProjectBuilder projectBuilder;
@Parameter
private String toolkit = SenchaUtils.TOOLKIT_CLASSIC;
/**
* a regexp matching the group and artifact id of a sencha framewrok artifact
*/
@Parameter(defaultValue = "((net\\.jangaroo\\.com)|(com\\.coremedia))\\.sencha:ext-js(-pkg)?(-gpl)?")
private String extFrameworkArtifactRegexp;
/**
* The log level to use for Sencha Cmd.
* The log level for Maven is kind of the base line which determines which log entries are actually shown in the output.
* When you Maven log level is "info", no "debug" messages for Sencha Cmd are logged.
* If no log level is given, the Maven log level will be used.
*/
@Parameter(property = "senchaLogLevel")
private String senchaLogLevel;
/**
* Space-separated command line options for the JVM started by Sencha Cmd.
* Typically, memory settings like -Xms512m -Xmx4096m
are added to adapt to JVM memory requirements.
* This corresponds to running sencha -J-Xms512m -J-Xmx4096m ...
*/
@Parameter(property = "senchaJvmArgs")
private String senchaJvmArgs;
/**
* The maven coordinates ("groupId:artifactId") an app that should be provided in the root
* instead of the "apps/${appName}/".
*
* Only affects the packaging type "jangaroo-apps".
*/
@Parameter
private String rootApp;
/**
* Experimental:
* The configuration can be used to replace the generated npm package name of a Maven module by a different one.
* It defines a list of replacers consisting of a search and a replace field. The search is interpreted as
* a regular pattern matched against the generated npm package name while the replacement is a string which can
* contain tokens (e.g. $1) matching pattern groups. Order is important, the first matching replacer wins.
*/
@Parameter
private List npmPackageNameReplacers = new ArrayList<>();
@Parameter
private List npmPackageVersionReplacers = new ArrayList<>();
private volatile Pattern extFrameworkArtifactPattern;
private Map mavenProjectByDependencyCache = new HashMap<>();
private String npmPackageName;
private String npmPackageVersion;
// ***********************************************************************
// ************************* GETTERS *************************************
// ***********************************************************************
public String getToolkit() {
return toolkit;
}
public Pattern getExtFrameworkArtifactPattern() {
if (extFrameworkArtifactPattern == null) {
extFrameworkArtifactPattern = Pattern.compile(getExtFrameworkArtifactRegexp());
}
return extFrameworkArtifactPattern;
}
public String getExtFrameworkArtifactRegexp() {
return extFrameworkArtifactRegexp;
}
public Dependency getRootApp() {
if (rootApp == null || rootApp.isEmpty()) {
return null;
}
return SenchaUtils.getDependencyByRef(project, rootApp);
}
private String getNpmPackageName() {
if (npmPackageName == null) {
List resolvedNpmPackageNameReplacers = ConversionUtils.getSearchAndReplace(npmPackageNameReplacers);
npmPackageName = ConversionUtils.getNpmPackageName(project.getGroupId(), project.getArtifactId(), resolvedNpmPackageNameReplacers);
}
return npmPackageName;
}
private String getNpmPackageVersion() {
if (npmPackageVersion == null) {
List resolvedNpmPackageVersionReplacers = ConversionUtils.getSearchAndReplace(npmPackageVersionReplacers);
npmPackageVersion = ConversionUtils.getNpmPackageVersion(project.getVersion(), resolvedNpmPackageVersionReplacers);
}
return npmPackageVersion;
}
protected Map getManifestEntries() {
return ConversionUtils.getManifestEntries(getNpmPackageName(), getNpmPackageVersion());
}
// ***********************************************************************
// ************************* SETTERS *************************************
// ***********************************************************************
public String getSenchaLogLevel() {
return senchaLogLevel;
}
protected String getSenchaJvmArgs() {
return senchaJvmArgs;
}
protected boolean isExtFrameworkArtifact(Artifact artifact) {
return isExtFramework(artifact.getGroupId(), artifact.getArtifactId());
}
protected boolean isExtFrameworkDependency(Dependency dependency) {
return isExtFramework(dependency.getGroupId(), dependency.getArtifactId());
}
private boolean isExtFramework(String groupId, String artifactId) {
String key = groupId + ":" + artifactId;
return getExtFrameworkArtifactPattern().matcher(key).matches();
}
@Nonnull
MavenProject getProjectFromDependency(MavenProject project, Dependency dependency) throws MojoExecutionException {
// fast path: look for dependent project in project's references:
String key = ArtifactUtils.key(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion());
if (project.getProjectReferences().containsKey(key)) {
return project.getProjectReferences().get(key);
}
// expensive path: retrieve MavenProject via Maven's ProjectBuildingRequest:
return createProjectFromDependency(dependency);
}
@Nonnull
private MavenProject createProjectFromDependency(@Nonnull Dependency dependency) throws MojoExecutionException {
String dependencyKey = dependency.toString();
if (mavenProjectByDependencyCache.containsKey(dependencyKey)) {
return mavenProjectByDependencyCache.get(dependencyKey);
}
getLog().debug("createProjectFromDependency(" + dependency + ")");
Artifact artifactFromDependency = getArtifact(dependency);
if (artifactFromDependency == null) {
artifactFromDependency = new DefaultArtifact(
dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), dependency.getScope(),
dependency.getType(), dependency.getClassifier(), artifactHandlerManager.getArtifactHandler(dependency.getType())
);
}
ProjectBuildingRequest request = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest());
request.setRemoteRepositories(project.getRemoteArtifactRepositories()); // The artifacts are available repositories defined in the projects - this also covers configured mirrors.
request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
request.setProcessPlugins(false);
request.setResolveDependencies(false);
try {
ProjectBuildingResult result = projectBuilder.build(artifactFromDependency, request);
MavenProject project = result.getProject();
mavenProjectByDependencyCache.put(dependencyKey, project);
return project;
} catch (ProjectBuildingException e) {
throw new MojoExecutionException("Could not resolve required dependencies of POM dependency " + artifactFromDependency, e);
}
}
Artifact getArtifact(Dependency dependency) {
return getArtifact(dependency.getGroupId(), dependency.getArtifactId());
}
Artifact getArtifact(MavenProject mavenProject) {
return getArtifact(mavenProject.getGroupId(), mavenProject.getArtifactId());
}
private Artifact getArtifact(String groupId, String artifactId) {
String versionlessKey = ArtifactUtils.versionlessKey(groupId, artifactId);
return project.getArtifactMap().get(versionlessKey);
}
JangarooApp createJangarooApp(MavenProject project) throws MojoExecutionException {
String packaging = project.getPackaging();
if (Type.JANGAROO_APP_PACKAGING.equals(packaging)) {
return new JangarooApp(project);
} else if (Type.JANGAROO_APP_OVERLAY_PACKAGING.equals(packaging)) {
return createJangarooAppOverlay(project);
}
return null;
}
JangarooAppOverlay createJangarooAppOverlay(MavenProject project) throws MojoExecutionException {
List dependencies = project.getDependencies();
for (Dependency dependency : dependencies) {
if (Type.JAR_EXTENSION.equals(dependency.getType())) {
// First, use MavenProject from project references, because it is already "evaluated" (${project.baseDir} etc.):
MavenProject dependentProject = getProjectFromDependency(project, dependency);
JangarooApp baseApp = createJangarooApp(dependentProject);
if (baseApp != null) {
return new JangarooAppOverlay(project, baseApp);
}
}
}
// no base app, that's okay, you just must tag dependencies as scope provided so that we know what to package:
return new JangarooAppOverlay(project, null);
}
JangarooApps createJangarooApps(MavenProject project) throws MojoExecutionException {
if (Type.JANGAROO_APPS_PACKAGING.equals(project.getPackaging())) {
Set apps = new LinkedHashSet<>();
List dependencies = project.getDependencies();
for (Dependency dependency : dependencies) {
if (Type.JAR_EXTENSION.equals(dependency.getType())) {
// First, use MavenProject from project references, because it is already "evaluated" (${project.baseDir} etc.):
MavenProject dependentProject = getProjectFromDependency(project, dependency);
JangarooApp baseApp = createJangarooApp(dependentProject);
if (baseApp != null) {
apps.add(baseApp);
}
}
}
return new JangarooApps(project, apps);
}
return null;
}
@Nonnull
protected File getArtifactFile(MavenProject mavenProject) throws MojoExecutionException {
Artifact appArtifact = getArtifact(mavenProject);
if (appArtifact == null) {
throw new MojoExecutionException("Artifact of app " + mavenProject + " not found in project dependencies.");
}
File appJarFile = appArtifact.getFile();
if (appJarFile == null) {
throw new MojoExecutionException("Artifact of app " + mavenProject + " has null file, cannot determine JAR location.");
}
if (appJarFile.isDirectory()) {
throw new MojoExecutionException("Artifact of app " + mavenProject + " is a directory.");
}
return appJarFile;
}
@Nonnull
protected File getAppDirOrJar(MavenProject mavenProject) throws MojoExecutionException {
File appReactorDir = new File(mavenProject.getBuild().getDirectory() + SenchaUtils.APP_TARGET_DIRECTORY);
if (appReactorDir.isDirectory()) {
return appReactorDir;
}
return getArtifactFile(mavenProject);
}
protected InputStream getInputStreamForDirOrJar(File dirOrJar, String relativePathInsideDirOrJar, String jarPrefixPath) throws MojoExecutionException {
if (dirOrJar.isDirectory()) {
try {
File file = dirOrJar.toPath().resolve(relativePathInsideDirOrJar).toFile();
if (!file.exists()) {
return null;
}
return new FileInputStream(file);
} catch (FileNotFoundException e) {
return null;
}
} else {
try {
JarFile jarFile = new JarFile(dirOrJar);
ZipEntry entry = jarFile.getEntry(jarPrefixPath + relativePathInsideDirOrJar);
if (entry == null) {
return null;
}
return jarFile.getInputStream(entry);
} catch (IOException e) {
throw new MojoExecutionException("Error reading " + dirOrJar, e);
}
}
}
protected Map> prepareAppManifestByLocale(Set locales, List artifacts) throws MojoExecutionException {
// read all available app manifests (no merge yet)
Map>> rawAppManifestByLocaleByArtifact = new HashMap<>();
for (String locale : locales) {
String appManifestFileName = getAppManifestFragmentFileNameForLocale(locale);
for (Artifact artifact : artifacts) {
String jarPrefixPath = Type.SWC_EXTENSION.equals(artifact.getType()) ? META_INF_PKG : META_INF_RESOURCES;
InputStream manifestInputStream = getInputStreamForDirOrJar(artifact.getFile(), appManifestFileName, jarPrefixPath);
if (manifestInputStream != null) {
final Map localeAppManifest;
try {
localeAppManifest = AppManifestDeSerializer.readAppManifest(manifestInputStream);
} catch (IOException e) {
throw new MojoExecutionException("Could not read app manifest", e);
}
if (!rawAppManifestByLocaleByArtifact.containsKey(locale)) {
rawAppManifestByLocaleByArtifact.put(locale, new HashMap<>());
}
rawAppManifestByLocaleByArtifact.get(locale).put(artifact, localeAppManifest);
}
}
}
Map> appManifestByLocale = new HashMap<>();
for (String locale : locales) {
Map appManifest = new HashMap<>();
for (Artifact artifact : artifacts) {
Map localizedAppManifest = new HashMap<>();
if (!DEFAULT_LOCALE.equals(locale) && rawAppManifestByLocaleByArtifact.containsKey(DEFAULT_LOCALE) && rawAppManifestByLocaleByArtifact.get(DEFAULT_LOCALE).containsKey(artifact)) {
MergeHelper.mergeMapIntoBaseMap(localizedAppManifest, rawAppManifestByLocaleByArtifact.get(DEFAULT_LOCALE).get(artifact), APP_MANIFEST_LOCALIZATION_MERGE_STRATEGY);
}
if (rawAppManifestByLocaleByArtifact.containsKey(locale) && rawAppManifestByLocaleByArtifact.get(locale).containsKey(artifact)) {
MergeHelper.mergeMapIntoBaseMap(localizedAppManifest, rawAppManifestByLocaleByArtifact.get(locale).get(artifact), APP_MANIFEST_LOCALIZATION_MERGE_STRATEGY);
}
MergeHelper.mergeMapIntoBaseMap(appManifest, localizedAppManifest, APP_MANIFEST_CROSS_MODULE_MERGE_STRATEGY);
}
appManifestByLocale.put(locale, appManifest);
}
return appManifestByLocale;
}
protected File prepareFile(File file) throws MojoExecutionException {
Path relativeFilePath = project.getBasedir().toPath().relativize(file.toPath());
getLog().info(String.format("Writing %s for module %s.", relativeFilePath, project.getName()));
if (!file.exists()) {
FileHelper.ensureDirectory(file.getParentFile());
} else {
getLog().debug(relativeFilePath + " for module already exists, deleting...");
if (!file.delete()) {
throw new MojoExecutionException("Could not delete " + relativeFilePath + " file for module");
}
}
return file;
}
@Nonnull
protected String getAppManifestFileNameForLocale(String locale) {
String appManifestFileName = APP_MANIFEST_FILENAME;
if (!DEFAULT_LOCALE.equals(locale)) {
appManifestFileName = appManifestFileName.replace(".json", "-" + locale + ".json");
}
return appManifestFileName;
}
protected String getAppManifestFragmentFileNameForLocale(String locale) {
String appManifestFileName = APP_MANIFEST_FRAGMENT_FILENAME;
if (!DEFAULT_LOCALE.equals(locale)) {
appManifestFileName = appManifestFileName.replace(".json", "-" + locale + ".json");
}
return appManifestFileName;
}
static class JangarooApp {
final MavenProject mavenProject;
Set packages = new LinkedHashSet<>();
JangarooApp(MavenProject mavenProject) {
this.mavenProject = mavenProject;
}
JangarooApp getRootBaseApp() {
return this;
}
}
static class JangarooAppOverlay extends JangarooApp {
final JangarooApp baseApp;
JangarooAppOverlay(MavenProject mavenProject, JangarooApp baseApp) {
super(mavenProject);
this.baseApp = baseApp;
}
@Override
JangarooApp getRootBaseApp() {
return baseApp == null ? null : baseApp.getRootBaseApp();
}
Set getOwnDynamicPackages() {
LinkedHashSet ownDynamicPackages = new LinkedHashSet<>(packages);
if (baseApp != null) {
ownDynamicPackages.removeAll(baseApp.packages);
}
return ownDynamicPackages;
}
Set getAllDynamicPackages() {
LinkedHashSet allDynamicPackages = new LinkedHashSet<>(packages);
JangarooApp rootBaseApp = getRootBaseApp();
if (rootBaseApp != null) {
allDynamicPackages.removeAll(rootBaseApp.packages);
}
return allDynamicPackages;
}
}
static class JangarooApps {
final MavenProject mavenProject;
final Set apps;
JangarooApps(MavenProject mavenProject, Set apps) {
this.mavenProject = mavenProject;
this.apps = apps;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy