de.saumya.mojo.gems.DefaultMavenArtifactConverter Maven / Gradle / Ivy
package de.saumya.mojo.gems;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Developer;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.License;
import org.apache.maven.model.Model;
import org.apache.maven.model.Relocation;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.velocity.VelocityComponent;
import de.saumya.mojo.gems.gem.Gem;
import de.saumya.mojo.gems.gem.GemPackager;
import de.saumya.mojo.gems.spec.GemDependency;
import de.saumya.mojo.gems.spec.GemRequirement;
import de.saumya.mojo.gems.spec.GemSpecification;
import de.saumya.mojo.gems.spec.GemSpecificationIO;
import de.saumya.mojo.gems.spec.GemVersion;
import de.saumya.mojo.ruby.gems.GemManager;
/**
* This is full of "workarounds" here, since for true artifact2gem conversion I
* would need interpolated POM!
*
* @author cstamas
* @author mkristian
*/
@Component(role = MavenArtifactConverter.class)
public class DefaultMavenArtifactConverter implements MavenArtifactConverter {
private static final String LIB_PATH = "lib/";
private static final String LIB_MAVEN_PATH = LIB_PATH + "maven/";
enum RubyDependencyType {
RUNTIME, DEVELOPMENT;
@Override
public String toString() {
return ":" + name().toLowerCase();
}
public static RubyDependencyType toRubyDependencyType(
final String dependencyScope) {
// ruby scopes
// :development
// :runtime
if ("provided".equals(dependencyScope)
|| "test".equals(dependencyScope)) {
return DEVELOPMENT;
}
else if ("compile".equals(dependencyScope)
|| "runtime".equals(dependencyScope)) {
return RUNTIME;
}
else
// dependencyScope: "system"
{
// TODO better throw an exception since there will be no gem for
// such a dependency or something else
return RUNTIME;
}
}
}
/**
* The Java platform key.
*/
String PLATFORM_JAVA = "java";
@Requirement
private GemPackager gemPackager;
@Requirement
private VelocityComponent velocityComponent;
@Requirement(hints = { "yaml" })
private GemSpecificationIO gemSpecificationIO;
private final Maven2GemVersionConverter maven2GemVersionConverter = new Maven2GemVersionConverter();
public boolean canConvert(final MavenArtifact artifact) {
// TODO: this is where we filter currently what to convert.
// for now, we convert only POMs with packaging "pom", or "jar" (but we
// ensure there is the primary artifact JAR
// also
// RELAXING: doing "pom" packagings but also anything that has primary
// artifact ending with ".jar".
if (canConvert(artifact, "pom", null)) {
return true;
}
if (canConvert(artifact, artifact.getPom().getPackaging(), "jar")) {
return true;
}
return false;
}
private boolean canConvert(final MavenArtifact artifact,
final String packaging, final String extension) {
String fixedExtension = null;
if (extension != null) {
fixedExtension = extension.startsWith(".") ? extension : "."
+ extension;
}
return StringUtils.equals(packaging, artifact.getPom().getPackaging())
&& ((extension == null && artifact.getArtifactFile() == null) || (extension != null
&& artifact.getArtifactFile() != null && artifact.getArtifactFile()
.getName()
.endsWith(fixedExtension)));
}
public String getGemFileName(final MavenArtifact artifact) {
return getGemFileName(artifact.getCoordinates().getGroupId(),
artifact.getCoordinates().getArtifactId(),
artifact.getCoordinates().getVersion(),
this.PLATFORM_JAVA);
}
public GemSpecification createSpecification(final MavenArtifact artifact) {
final GemSpecification result = new GemSpecification();
if( relocateIfNeeded(artifact)){
Dependency dep = artifact.getPom().getDependencies().get(0);
result.setPost_install_message("this gem has a new name: "
+ createGemName(dep.getGroupId(),
dep.getArtifactId(),
dep.getVersion()) + " version: " + dep.getVersion());
}
// this is fix
result.setPlatform(this.PLATFORM_JAVA);
// the must ones
result.setName(createGemName(artifact.getCoordinates().getGroupId(),
artifact.getCoordinates().getArtifactId(),
artifact.getCoordinates().getVersion()));
result.setVersion(new GemVersion(createGemVersion(artifact.getCoordinates()
.getVersion())));
// dependencies
if (artifact.getPom().getDependencies().size() > 0) {
for (final Dependency dependency : artifact.getPom()
.getDependencies()) {
if (!dependency.isOptional()) {
result.getDependencies().add(convertDependency(artifact,
dependency));
}
}
}
// and other stuff "nice to have"
result.setDate(new Date()); // now
result.setDescription(sanitizeStringValue(artifact.getPom()
.getDescription() != null
? artifact.getPom().getDescription()
: artifact.getPom().getName()));
result.setSummary(sanitizeStringValue(artifact.getPom().getName()));
result.setHomepage(sanitizeStringValue(artifact.getPom().getUrl()));
if (artifact.getPom().getLicenses().size() > 0) {
for (final License license : artifact.getPom().getLicenses()) {
result.getLicenses().add(sanitizeStringValue(license.getName()
+ " (" + license.getUrl() + ")"));
}
}
if (artifact.getPom().getDevelopers().size() > 0) {
for (final Developer developer : artifact.getPom().getDevelopers()) {
result.getAuthors().add(sanitizeStringValue(developer.getName()
+ " (" + developer.getEmail() + ")"));
}
}
// by default, we pack into lib/ inside gem (where is the jar and the
// stub ruby)
result.getRequire_paths().add("lib");
return result;
}
public GemArtifact createGemStubFromArtifact(final MavenArtifact artifact,
final File target) throws IOException {
final GemSpecification gemspec = createSpecification(artifact);
if (target == null || (target.exists() && !target.isDirectory())) {
throw new IOException("Must specify target file, where to generate Gem!");
}
// write file
final File gemfile = this.gemPackager.createGemStub(gemspec, target);
return new GemArtifact(gemspec, gemfile);
}
private boolean relocateIfNeeded(final MavenArtifact mart){
Model model = mart.getPom();
if (model.getDistributionManagement() != null) {
final Relocation relocation = model.getDistributionManagement()
.getRelocation();
if (relocation != null) {
String newGroupId = relocation.getGroupId() == null
? mart.getCoordinates().getGroupId()
: relocation.getGroupId();
String newArtifactId = relocation.getArtifactId() == null
? mart.getCoordinates().getArtifactId()
: relocation.getArtifactId();
String newVersion = relocation.getVersion() == null
? mart.getCoordinates().getVersion()
: relocation.getVersion();
Dependency dep = new Dependency();
dep.setArtifactId(newArtifactId);
dep.setGroupId(newGroupId);
dep.setVersion(newVersion);
dep.setType(model.getPackaging());
model.getDependencies().clear();
model.addDependency(dep);
model.setPackaging("pom");
return true;
}
}
return false;
}
public GemArtifact createGemFromArtifact(final MavenArtifact artifact,
final File target) throws IOException {
final GemSpecification gemspec = createSpecification(artifact);
if (target == null || (target.exists() && !target.isDirectory())) {
throw new IOException("Must specify target directory, where to generate Gem!");
}
final Gem gem = new Gem(gemspec);
if (artifact.getArtifactFile() != null) {
gem.addFile(artifact.getArtifactFile(), createLibFileName(artifact,
".jar"));
}
// create "meta" ruby file
final String rubyStubMetaPath = createLibFileName(artifact,
"-maven.rb");
final File rubyStubMetaFile = generateRubyMetaStub(gemspec, artifact);
gem.addFile(rubyStubMetaFile, rubyStubMetaPath);
// create runtime ruby file
final String rubyStubPath = createLibFileName(artifact, ".rb");
// System.err.println( rubyStubPath );
final File rubyStubFile = generateRubyStub(gemspec,
artifact,
RubyDependencyType.RUNTIME);
gem.addFile(rubyStubFile, rubyStubPath);
// create development ruby file
final String rubyDevelopmentStubPath = createLibFileName(artifact,
"-dev.rb");
final File rubyDevelopmentStubFile = generateRubyStub(gemspec,
artifact,
RubyDependencyType.DEVELOPMENT);
gem.addFile(rubyDevelopmentStubFile, rubyDevelopmentStubPath);
final File rubyMainStubFile = generateMainStub(artifact);
gem.addFile(rubyMainStubFile, LIB_PATH + gemspec.getName() + ".rb" );
// write file
final File gemfile = this.gemPackager.createGem(gem, target);
return new GemArtifact(gemspec, gemfile);
}
// ==
protected String sanitizeStringValue(final String val) {
if (val == null) {
return null;
}
// for now, just to overcome the JRuby 1.4 Yaml parse but revealed by
// this POM:
// http://repo1.maven.org/maven2/org/easytesting/fest-assert/1.0/fest-assert-1.0.pom
return val.replaceAll("'", "").replaceAll("\"", "").replace('\n', ' ');
}
protected String createLibFileName(final MavenArtifact artifact,
final String postfix) {
return LIB_MAVEN_PATH
+ createRequireName(artifact.getCoordinates().getGroupId(),
artifact.getCoordinates().getArtifactId(),
artifact.getCoordinates().getVersion())
+ postfix;
}
protected String createRequireName(final String groupId,
final String artifactId, final String version) {
return groupId + "/" + artifactId;
}
protected String createJarfileName(final String groupId,
final String artifactId, final String version) {
return artifactId + ".jar";
}
protected String createGemName(final String groupId,
final String artifactId, final String version) {
// TODO: think about this
// return ( GEMNAME_PREFIX + groupId + GemManager.GROUP_ID_ARTIFACT_ID_SEPARATOR + artifactId ).replace( ':', '.' );
// TODO think about this harder ;-)
return ( GEMNAME_PREFIX + groupId + GemManager.GROUP_ID_ARTIFACT_ID_SEPARATOR + artifactId );
}
protected String getGemFileName(final String groupId,
final String artifactId, final String version, final String platform) {
final String gemName = createGemName(groupId, artifactId, version);
final String gemVersion = createGemVersion(version);
return Gem.constructGemFileName(gemName, gemVersion, platform);
}
protected String getGemFileName(final GemSpecification gemspec) {
return Gem.constructGemFileName(gemspec.getName(), gemspec.getVersion()
.getVersion(), gemspec.getPlatform());
}
protected String createGemVersion(final String mavenVersion)
throws NullPointerException {
return this.maven2GemVersionConverter.createGemVersion(mavenVersion);
}
// ==
private File generateMainStub(MavenArtifact artifact) throws IOException {
final VelocityContext context = new VelocityContext();
context.put("groupId", artifact.getCoordinates().getGroupId());
context.put("artifactId", artifact.getCoordinates().getArtifactId());
return generateRubyFile("main", context, "rubyMainStub");
}
private File generateRubyMetaStub(final GemSpecification gemspec,
final MavenArtifact artifact) throws IOException {
final VelocityContext context = new VelocityContext();
context.put("gemVersion", gemspec.getVersion().getVersion());
context.put("groupId", artifact.getCoordinates().getGroupId());
context.put("artifactId", artifact.getCoordinates().getArtifactId());
context.put("type", artifact.getPom().getPackaging());
context.put("version", artifact.getCoordinates().getVersion());
if (artifact.getArtifactFile() != null) {
context.put("filename", createJarfileName(artifact.getCoordinates()
.getGroupId(),
artifact.getCoordinates()
.getArtifactId(),
artifact.getCoordinates()
.getVersion()));
}
final List packageParts = new ArrayList();
for (final String part : artifact.getCoordinates()
.getGroupId()
.split("\\.")) {
packageParts.add(titleize(part));
}
packageParts.add(titleize(artifact.getCoordinates().getArtifactId()));
context.put("packageParts", packageParts);
return generateRubyFile("metafile", context, "rubyMetaStub");
}
public static class MavenDependency {
public String name;
public List exclusions = new ArrayList();
public String getName() {
return this.name;
}
public String getExclusions() {
final StringBuilder buf = new StringBuilder();
for (final String ex : this.exclusions) {
buf.append(",'").append(ex).append("'");
}
return this.exclusions.size() > 0 ? buf.substring(1) : "";
}
}
private File generateRubyStub(final GemSpecification gemspec,
final MavenArtifact artifact, final RubyDependencyType type)
throws IOException {
final VelocityContext context = new VelocityContext();
switch (type) {
case RUNTIME:
if (artifact.getArtifactFile() != null) {
context.put("jarfile",
createJarfileName(artifact.getCoordinates()
.getGroupId(), artifact.getCoordinates()
.getArtifactId(), artifact.getCoordinates()
.getVersion()));
}
break;
case DEVELOPMENT:
context.put("filename", artifact.getCoordinates().getArtifactId()
+ ".rb");
break;
}
final List deps = new ArrayList();
for (final Dependency dependency : artifact.getPom().getDependencies()) {
if (RubyDependencyType.toRubyDependencyType(dependency.getScope()) == type
&& !dependency.isOptional()) {
final MavenDependency mavenDependency = new MavenDependency();
mavenDependency.name = createRequireName(dependency.getGroupId(),
dependency.getArtifactId(),
dependency.getVersion());
for (final Exclusion exclusion : dependency.getExclusions()) {
mavenDependency.exclusions.add(exclusion.getGroupId() + "/"
+ exclusion.getArtifactId());
}
deps.add(mavenDependency);
}
}
context.put("dependencies", deps);
return generateRubyFile("require" + type.name(), context, "rubyStub"
+ type.name());
}
private File generateRubyFile(final String templateName,
final Context context, final String stubFilename)
throws IOException {
final InputStream input = getClass().getResourceAsStream("/"
+ templateName + ".rb.vm");
if (input == null) {
throw new FileNotFoundException(templateName + ".rb.vm");
}
final String rubyTemplate = IOUtil.toString(input);
final File rubyFile = File.createTempFile(stubFilename, ".rb.tmp");
final FileWriter fw = new FileWriter(rubyFile);
this.velocityComponent.getEngine().evaluate(context,
fw,
"ruby",
rubyTemplate);
fw.flush();
fw.close();
return rubyFile;
}
private String titleize(final String string) {
final String[] titleParts = string.split("[-._]");
final StringBuilder titleizedString = new StringBuilder();
for (final String part : titleParts) {
if (part != null && part.length() != 0) {
titleizedString.append(StringUtils.capitalise(part));
}
}
return titleizedString.toString();
}
private GemDependency convertDependency(final MavenArtifact artifact,
final Dependency dependency) {
final GemDependency result = new GemDependency();
result.setName(createGemName(dependency.getGroupId(),
dependency.getArtifactId(),
dependency.getVersion()));
result.setType(RubyDependencyType.toRubyDependencyType(dependency.getScope())
.toString());
final GemRequirement requirement = new GemRequirement();
// TODO: we are adding "hard" dependencies here, but we should maybe
// support Maven ranges too
// based on
// http://blog.zenspider.com/2008/10/rubygems-howto-preventing-cata.html
final String version = createGemVersion(getDependencyVersion(artifact,
dependency));
final GemVersion gemVersion;
if (version.matches("^[^.]+\\.[^.]+\\..*")) {
// TODO maybe just takethe first two parts
gemVersion = new GemVersion(version.substring(0, version.indexOf('.')) + ".0.a");
}
else {
gemVersion = new GemVersion(version);
}
requirement.addRequirement("~>", gemVersion);
result.setVersion_requirement(requirement);
return result;
}
private String getDependencyVersion(final MavenArtifact artifact,
final Dependency dependency) {
if (dependency.getVersion() != null) {
return dependency.getVersion();
}
else if (StringUtils.equals(artifact.getCoordinates().getGroupId(),
dependency.getGroupId())) {
// hm, this is same groupId, let's suppose they have same
// dependency!
return artifact.getCoordinates().getVersion();
}
else {
// no help here, just interpolated POM
return "unknown";
}
}
public File createGemspecFromArtifact(final MavenArtifact artifact,
final File target) throws IOException {
final GemSpecification gemspec = createSpecification(artifact);
final File targetFile = new File(target, getGemFileName(gemspec)
+ "spec");
FileWriter writer = null;
try {
writer = new FileWriter(targetFile);
writer.append(this.gemSpecificationIO.write(gemspec));
}
finally {
IOUtil.close(writer);
}
return targetFile;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy