net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils 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.
package net.jangaroo.jooc.mvnplugin.sencha;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import net.jangaroo.jooc.mvnplugin.Type;
import net.jangaroo.jooc.mvnplugin.sencha.executor.SenchaCmdExecutor;
import net.jangaroo.jooc.mvnplugin.util.MavenDependencyHelper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
public class SenchaUtils {
public static final String SEPARATOR = "/";
public static final String LOCAL_PACKAGES_PATH = "/packages/";
private static final String BUILD_PATH = "build/";
public static final String APP_TARGET_DIRECTORY = "/app";
/**
* The name of the folder of the generated module inside the packages folder of the module.
* Make sure that the name is not too long to avoid exceeding the max path length in windows.
* The old path length relative to the target folder was 43 chars:
* classes\META-INF\resources\joo\classes\com
*
* So to avoid compatiblity issues the max length for the path is:
*
* 43 - SENCHA_BASE_BATH.length - SENCHA_PACKAGES.length - SENCHA_PACKAGE_LOCAL.length
* - SENCHA_CLASS_PATH.length - 4 (Separator)
*/
public static final String SENCHA_OVERRIDES_PATH = "overrides";
public static final String SENCHA_LOCALE_PATH = "locale";
public static final String SENCHA_RESOURCES_PATH = "resources";
public static final String SENCHA_BUNDLED_RESOURCES_PATH = "bundledResources";
public static final String PRODUCTION_PROFILE = "production";
public static final String TESTING_PROFILE = "testing";
public static final String DEVELOPMENT_PROFILE = "development";
public static final String TOOLKIT_CLASSIC = "classic";
private static final String SENCHA_CFG = "sencha.cfg";
public static final String SENCHA_DIRECTORYNAME = ".sencha";
public static final String SENCHA_WORKSPACE_CONFIG = SENCHA_DIRECTORYNAME + SEPARATOR + "workspace" + SEPARATOR + SENCHA_CFG;
public static final String SENCHA_PACKAGE_CONFIG = SENCHA_DIRECTORYNAME + SEPARATOR + "package" + SEPARATOR + SENCHA_CFG;
public static final String SENCHA_APP_CONFIG = SENCHA_DIRECTORYNAME + SEPARATOR + "app" + SEPARATOR + SENCHA_CFG;
public static final String SENCHA_WORKSPACE_FILENAME = "workspace.json";
public static final String SENCHA_PACKAGE_FILENAME = "package.json";
public static final String SENCHA_APP_FILENAME = "app.json";
public static final String SENCHA_PKG_EXTENSION = ".pkg";
public static final String PACKAGE_CONFIG_FILENAME = "packageConfig.js";
public static final String REQUIRED_CLASSES_FILENAME = "requiredClasses.js";
public static final String SENCHA_TEST_APP_TEMPLATE_ARTIFACT_ID = "sencha-test-app-template";
public static final String SENCHA_APP_TEMPLATE_ARTIFACT_ID = "sencha-app-template";
public static final String SENCHA_APP_TEMPLATE_GROUP_ID = "net.jangaroo";
private static final Pattern SENCHA_VERSION_PATTERN = Pattern.compile("^[0-9]+(\\.[0-9]+){0,3}$");
public static final String AUTO_CONTENT_COMMENT = "DO NOT CHANGE - This file was automatically generated by the " +
"jangaroo-maven-plugin and it will be overwritten by the next call of the plugin's " +
"goal \"generate-workspace\".";
public static final Map PLACEHOLDERS = ImmutableMap.of( // TODO data structure and location??
Type.APP, "${app.dir}",
Type.CODE, "${package.dir}",
Type.THEME, "${package.dir}",
Type.WORKSPACE, "${workspace.dir}"
);
private static final ObjectMapper objectMapper;
static {
objectMapper = new ObjectMapper();
objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
}
private SenchaUtils() {
// hide constructor
}
public static String getSenchaPackageName(String groupId, String artifactId) {
return groupId + "__" + artifactId;
}
public static String getSenchaPackageName(@Nonnull MavenProject project) {
return getSenchaPackageName(project.getGroupId(), project.getArtifactId());
}
public static String getSenchaVersionForMavenVersion(String version) {
// Very simple matching for now, maybe needs some adjustment
String senchaVersion = version.replaceAll("[^0-9.-]", "").replace("-", ".").replaceAll("[.]+", ".").replaceAll("[.]+$", "");
if (SENCHA_VERSION_PATTERN.matcher(senchaVersion).matches()) {
return senchaVersion;
} else {
return null;
}
}
@Nullable
public static Dependency getThemeDependency(@Nullable String theme, @Nonnull MavenProject project) {
Dependency themeDependency = MavenDependencyHelper.fromKey(theme);
// verify that provided artifact is under project dependencies
Set dependencyArtifacts = project.getDependencyArtifacts();
for (Artifact artifact : dependencyArtifacts) {
Dependency artifactDependency = MavenDependencyHelper.fromArtifact(artifact);
if (MavenDependencyHelper.equalsGroupIdAndArtifactId(artifactDependency, themeDependency)) {
return artifactDependency;
}
}
return null;
}
public static File findClosestSenchaWorkspaceDir(File dir) {
File result;
try {
result = dir.getCanonicalFile();
} catch (IOException e) {
return null; //NOSONAR
}
while (null != result) {
String[] list = result.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return SenchaUtils.SENCHA_WORKSPACE_FILENAME.equals(name);
}
});
if (null != list
&& list.length > 0) {
break;
}
result = result.getParentFile();
}
return result;
}
/**
* Generates an absolute path to the module dir for the given relative path using a placeholder.
*
* @param packageType the Maven project's packaging type
* @param relativePath the path relative to the Sencha module
* @return path prefixed with a placeholder and a separator to have an absolute path
*/
public static String generateAbsolutePathUsingPlaceholder(String packageType, String relativePath) {
// make sure only normal slashes are used and no backslashes (e.g. on windows systems)
String normalizedRelativePath = FilenameUtils.separatorsToUnix(relativePath);
String result = PLACEHOLDERS.get(packageType);
if (StringUtils.isNotEmpty(normalizedRelativePath) && !normalizedRelativePath.startsWith(SEPARATOR)) {
result += SEPARATOR + normalizedRelativePath;
}
return result;
}
public static ObjectMapper getObjectMapper() {
return objectMapper;
}
public static Path getRelativePathFromWorkspaceToWorkingDir(File workingDirectory) throws MojoExecutionException {
File closestSenchaWorkspaceDir = findClosestSenchaWorkspaceDir(workingDirectory);
if (null == closestSenchaWorkspaceDir) {
throw new MojoExecutionException("could not find Sencha workspace above workingDirectory");
}
Path workspacePath = closestSenchaWorkspaceDir.toPath().normalize();
Path workingDirectoryPath = workingDirectory.toPath().normalize();
if (workspacePath.getRoot() == null || !workspacePath.getRoot().equals(workingDirectoryPath.getRoot())) {
throw new MojoExecutionException("cannot find a relative path from workspace directory to working directory");
}
return workspacePath.relativize(workingDirectoryPath);
}
public static boolean isRequiredSenchaDependency(@Nonnull Dependency dependency,
@Nonnull Dependency remotePackageDependency) {
return !MavenDependencyHelper.equalsGroupIdAndArtifactId(dependency, remotePackageDependency)
&& Type.JAR_EXTENSION.equals(dependency.getType())
&& !Artifact.SCOPE_PROVIDED.equals(dependency.getScope())
&& !Artifact.SCOPE_TEST.equals(dependency.getScope());
}
public static String generateSenchaAppId(MavenProject project) {
String appIdString = SenchaUtils.getSenchaPackageName(project) +
SenchaUtils.getSenchaVersionForMavenVersion(project.getVersion());
return UUID.nameUUIDFromBytes(appIdString.getBytes()).toString();
}
public static boolean doesSenchaAppExist(File directory) {
File senchaCfg = new File(directory, SenchaUtils.SENCHA_APP_CONFIG);
return senchaCfg.exists();
}
public static String getPackagesPath(MavenProject project) {
return LOCAL_PACKAGES_PATH + getSenchaPackageName(project);
}
public static String getPackagesBuildPath(MavenProject project) {
return getPackagesPath(project) + "/" + BUILD_PATH;
}
public static void generateSenchaWorkspace(File workingDirectory, String extDirectory, Log log, String logLevel)
throws MojoExecutionException {
Path senchaCfg = Paths.get(workingDirectory.getAbsolutePath(), SenchaUtils.SENCHA_WORKSPACE_CONFIG);
try {
// delete existing senchaCfg so that Sencha Cmd is forced to re-create it
Files.deleteIfExists(senchaCfg);
} catch (IOException ioe) {
throw new MojoExecutionException("Could not delete existing sencha.cfg file in " + senchaCfg, ioe);
}
log.info("Generating Sencha workspace module");
SenchaCmdExecutor senchaCmdExecutor = new SenchaCmdExecutor(workingDirectory, "generate workspace .", log, logLevel);
senchaCmdExecutor.execute();
// sencha.cfg should be recreated
updateSenchaCfgWithExtDirectory(senchaCfg, extDirectory);
}
public static void generateSenchaAppFromTemplate(File workingDirectory,
String appName,
String applicationClass,
String toolkit,
Log log,
String logLevel
) throws MojoExecutionException {
String templateName = getSenchaPackageName(SENCHA_APP_TEMPLATE_GROUP_ID, SENCHA_APP_TEMPLATE_ARTIFACT_ID) + "/tpl";
ImmutableMap properties = ImmutableMap.of("appName", appName, "applicationClass", applicationClass);
generateSenchaAppFromTemplate(workingDirectory, appName, toolkit, templateName, properties, log, logLevel);
}
public static void generateSenchaTestAppFromTemplate(File workingDirectory,
MavenProject project,
String appName,
String testSuite,
String toolkit,
Log log,
String logLevel
) throws MojoExecutionException {
String templateName = getSenchaPackageName(SENCHA_APP_TEMPLATE_GROUP_ID, SENCHA_TEST_APP_TEMPLATE_ARTIFACT_ID) + "/tpl";
ImmutableMap properties = ImmutableMap.of("moduleName", getSenchaPackageName(project), "testSuite", testSuite);
generateSenchaAppFromTemplate(workingDirectory, appName, toolkit, templateName, properties, log, logLevel);
}
public static void generateSenchaAppFromTemplate(File workingDirectory,
String appName,
String toolkit,
String templateName,
Map properties,
Log log,
String logLevel
) throws MojoExecutionException {
StringBuilder arguments = new StringBuilder("generate app")
.append(" -ext ")
.append(toolkit)
.append(" --template ").append(templateName)
.append(" --path=\"\"")
.append(" --refresh=false");
if (properties != null) {
for (Map.Entry entry: properties.entrySet()) {
arguments.append(String.format(" -D%s=%s",entry.getKey(), entry.getValue()));
}
}
arguments.append(" ").append(appName);
SenchaCmdExecutor senchaCmdExecutor = new SenchaCmdExecutor(workingDirectory, arguments.toString(), log, logLevel);
senchaCmdExecutor.execute();
}
public static void refreshApp(File dir, Log log, String logLevel) throws MojoExecutionException {
SenchaCmdExecutor senchaCmdExecutor = new SenchaCmdExecutor(dir, "app refresh", log, logLevel);
senchaCmdExecutor.execute();
}
private static void updateSenchaCfgWithExtDirectory(Path senchaCfg, String extDirectory) throws MojoExecutionException {
createSenchaCfgWithExtDirectory(senchaCfg, senchaCfg, extDirectory);
}
public static void createSenchaCfgWithExtDirectory(Path senchaCfgSource, Path senchaCfgTarget, String extDirectory)
throws MojoExecutionException {
if (Files.exists(senchaCfgSource)) {
try {
List senchaCfgTmpContent = Files.readAllLines(senchaCfgSource, Charset.forName("UTF-8"));
Files.write(senchaCfgTarget, getSenchaCfgContent(senchaCfgTmpContent, extDirectory), Charset.forName("UTF-8"));
} catch (IOException e) {
throw new MojoExecutionException("Modifying sencha.cfg file failed", e);
}
} else {
throw new MojoExecutionException("Could not find sencha.cfg file in " + senchaCfgSource);
}
}
private static List getSenchaCfgContent(@Nonnull List currentContent, String extDirectory) {
// prepend comment and delete first comment line with usually contains the date time
if (currentContent.get(0).startsWith("#")) { // if the first
currentContent.remove(0);
}
List newSenchaCfg = new ArrayList<>(currentContent.size());
newSenchaCfg.add("#");
newSenchaCfg.add("# " + AUTO_CONTENT_COMMENT);
newSenchaCfg.add("#");
newSenchaCfg.add("");
newSenchaCfg.addAll(currentContent);
newSenchaCfg.add("ext.dir=" + extDirectory);
return newSenchaCfg;
}
}