
com.googlecode.cmakemavenproject.GenerateMojo Maven / Gradle / Ivy
package com.googlecode.cmakemavenproject;
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.twdata.maven.mojoexecutor.MojoExecutor;
/**
* Goal which generates project files.
*
* @goal generate
* @phase process-sources
*
* @author Gili Tzabari
*/
public class GenerateMojo
extends AbstractMojo
{
/**
* The release platform.
*
* @parameter expression="${classifier}"
* @readonly
*/
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private String classifier;
/**
* The directory containing CMakeLists.txt
*
* @parameter
* @required
*/
@SuppressWarnings(
{
"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"
})
private File sourcePath;
/**
* The output directory.
*
* @parameter
* @required
*/
@SuppressWarnings(
{
"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"
})
private File targetPath;
/**
* The makefile generator to use.
*
* @parameter
* @required
*/
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private String generator;
/**
* The environment variables.
*
* @parameter
*/
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private Map environmentVariables;
/**
* @component
*/
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private BuildPluginManager pluginManager;
/**
* @parameter expression="${project}"
* @required
* @readonly
*/
@SuppressWarnings(
{
"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD"
})
private MavenProject project;
/**
* @parameter expression="${session}"
* @required
* @readonly
*/
@SuppressWarnings("UWF_UNWRITTEN_FIELD")
private MavenSession session;
private final boolean isPosix = !System.getProperty("os.name").toLowerCase().startsWith("windows");
@Override
public void execute()
throws MojoExecutionException
{
PluginDescriptor pluginDescriptor = (PluginDescriptor) getPluginContext().
get("pluginDescriptor");
String version = pluginDescriptor.getVersion();
try
{
if (!targetPath.exists() && !targetPath.mkdirs())
throw new MojoExecutionException("Cannot create " + targetPath.getAbsolutePath());
final String groupId = "com.googlecode.cmake-maven-project";
final String artifactId = "cmake-binaries";
Plugin dependencyPlugin = MojoExecutor.plugin("org.apache.maven.plugins",
"maven-dependency-plugin", "2.4");
if (classifier == null)
{
String os = System.getProperty("os.name");
if (os.toLowerCase().startsWith("windows"))
classifier = "windows";
else if (os.toLowerCase().startsWith("linux"))
classifier = "linux";
else if (os.toLowerCase().startsWith("mac"))
classifier = "mac";
else
throw new MojoExecutionException("Unsupported os.name: " + os);
}
Path cmakeDir = Paths.get(project.getBuild().getDirectory(), "dependency/cmake").
toAbsolutePath();
MojoExecutor.Element groupIdElement = new MojoExecutor.Element("groupId", groupId);
MojoExecutor.Element artifactIdElement = new MojoExecutor.Element("artifactId", artifactId);
MojoExecutor.Element versionElement = new MojoExecutor.Element("version", version);
MojoExecutor.Element classifierElement = new MojoExecutor.Element("classifier", classifier);
MojoExecutor.Element outputDirectoryElement = new MojoExecutor.Element("outputDirectory",
cmakeDir.toString());
MojoExecutor.Element artifactItemElement = new MojoExecutor.Element("artifactItem",
groupIdElement, artifactIdElement, versionElement, classifierElement,
outputDirectoryElement);
MojoExecutor.Element artifactItemsItem = new MojoExecutor.Element("artifactItems",
artifactItemElement);
Xpp3Dom configuration = MojoExecutor.configuration(artifactItemsItem);
MojoExecutor.ExecutionEnvironment environment = MojoExecutor.executionEnvironment(project,
session, pluginManager);
MojoExecutor.executeMojo(dependencyPlugin, "copy", configuration, environment);
Path binariesArchive = null;
for (Path path: Files.newDirectoryStream(cmakeDir))
{
if (Files.isRegularFile(path))
{
binariesArchive = path;
break;
}
}
if (binariesArchive == null)
throw new IOException("Could not find cmake-binaries archive at: " + cmakeDir);
extract(binariesArchive, cmakeDir);
ProcessBuilder processBuilder = new ProcessBuilder(cmakeDir.resolve("bin/cmake").toString(),
sourcePath.getAbsolutePath(), "-G", generator).directory(targetPath);
Map env = processBuilder.environment();
if (environmentVariables != null)
env.putAll(environmentVariables);
Log log = getLog();
if (log.isDebugEnabled())
{
log.debug("sourcePath: " + sourcePath);
log.debug("targetPath: " + targetPath);
log.debug("environment: " + processBuilder.environment());
log.debug("command-line: " + processBuilder.command());
}
int returnCode = Mojos.waitFor(processBuilder);
if (returnCode != 0)
throw new MojoExecutionException("Return code: " + returnCode);
}
catch (InterruptedException | IOException e)
{
throw new MojoExecutionException("", e);
}
}
/**
* Extracts the contents of an archive.
*
* @param source the file to extract
* @param target the directory to extract to
* @throws IOException if an I/O error occurs
*/
private void extract(Path source, Path target) throws IOException
{
Files.createDirectories(target);
String filename = source.getFileName().toString();
String extension = getFileExtension(filename);
String nameWithoutExtension = filename.substring(0, filename.length() - extension.length());
String nextExtension = getFileExtension(nameWithoutExtension);
switch (extension)
{
case ".jar":
case ".zip":
{
if (!nextExtension.isEmpty())
throw new UnsupportedOperationException("Unsupported file type: " + source);
extractZip(source, target);
break;
}
case ".gz":
{
if (!nextExtension.isEmpty())
{
Path outputDir = Files.createTempDirectory("cmake");
Path result = extractGzip(source, outputDir);
extract(result, target);
Files.deleteIfExists(result);
Files.deleteIfExists(outputDir);
}
else
extractGzip(source, target);
break;
}
case ".tar":
{
if (!nextExtension.isEmpty())
throw new UnsupportedOperationException("Unsupported file type: " + source);
extractTar(source, target);
break;
}
default:
throw new UnsupportedOperationException("Unsupported file type: " + source);
}
}
/**
* Extracts a zip file.
*
* @param source the source file
* @param target the target directory
* @throws IOException if an I/O error occurs
*/
private void extractZip(Path source, Path target) throws IOException
{
ZipFile zipFile = new ZipFile(source.toFile());
ByteBuffer buffer = ByteBuffer.allocate(10 * 1024);
try
{
Enumeration entries = zipFile.getEntriesInPhysicalOrder();
while (entries.hasMoreElements())
{
ZipArchiveEntry entry = entries.nextElement();
List> attributes = new ArrayList<>();
if (isPosix)
{
attributes.add(PosixFilePermissions.asFileAttribute(getPosixPermissions(
entry.getUnixMode())));
}
if (entry.isDirectory())
{
Path directory = target.resolve(entry.getName());
Files.createDirectories(directory);
if (isPosix)
{
Files.setPosixFilePermissions(directory,
(Set) attributes.get(0).value());
}
continue;
}
try (ReadableByteChannel reader = Channels.newChannel(zipFile.getInputStream(entry)))
{
Path targetFile = target.resolve(entry.getName());
// Omitted directories are created using the default permissions
Files.createDirectories(targetFile.getParent());
try (SeekableByteChannel out = Files.newByteChannel(targetFile,
ImmutableSet.of(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE), attributes.toArray(new FileAttribute[0])))
{
long bytesLeft = entry.getSize();
while (bytesLeft > 0)
{
if (bytesLeft < buffer.limit())
buffer.limit((int) bytesLeft);
int count = reader.read(buffer);
if (count == -1)
break;
buffer.flip();
do
{
out.write(buffer);
}
while (buffer.hasRemaining());
buffer.clear();
bytesLeft -= count;
}
}
}
}
}
finally
{
zipFile.close();
}
}
/**
* Extracts a tar file.
*
* @param source the source file
* @param target the target directory
* @throws IOException if an I/O error occurs
*/
private void extractTar(Path source, Path target) throws IOException
{
ByteBuffer buffer = ByteBuffer.allocate(10 * 1024);
try (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(source)))
{
while (true)
{
TarArchiveEntry entry = in.getNextTarEntry();
if (entry == null)
break;
List> attributes = new ArrayList<>();
if (isPosix)
{
attributes.add(PosixFilePermissions.asFileAttribute(getPosixPermissions(
entry.getMode())));
}
if (entry.isDirectory())
{
Path directory = target.resolve(entry.getName());
Files.createDirectories(directory);
if (isPosix)
{
Files.setPosixFilePermissions(directory,
(Set) attributes.get(0).value());
}
continue;
}
ReadableByteChannel reader = Channels.newChannel(in);
Path targetFile = target.resolve(entry.getName());
// Omitted directories are created using the default permissions
Files.createDirectories(targetFile.getParent());
try (SeekableByteChannel out = Files.newByteChannel(targetFile,
ImmutableSet.of(StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE), attributes.toArray(new FileAttribute[0])))
{
long bytesLeft = entry.getSize();
while (bytesLeft > 0)
{
if (bytesLeft < buffer.limit())
buffer.limit((int) bytesLeft);
int count = reader.read(buffer);
if (count == -1)
break;
buffer.flip();
do
{
out.write(buffer);
}
while (buffer.hasRemaining());
buffer.clear();
bytesLeft -= count;
}
}
}
}
}
/**
* Converts an integer mode to a set of PosixFilePermissions.
*
* @param mode the integer mode
* @return the PosixFilePermissions
* @see http://stackoverflow.com/a/9445853/14731
*/
private Set getPosixPermissions(int mode)
{
StringBuilder result = new StringBuilder(9);
// Extract digits from left to right
//
// REFERENCE: http://stackoverflow.com/questions/203854/how-to-get-the-nth-digit-of-an-integer-with-bit-wise-operations
for (int i = 3; i >= 1; --i)
{
// Octal is base-8
mode %= Math.pow(8, i);
int digit = (int) (mode / Math.pow(8, i - 1));
if ((digit & 0b0000_0100) != 0)
result.append("r");
else
result.append("-");
if ((digit & 0b0000_0010) != 0)
result.append("w");
else
result.append("-");
if ((digit & 0b0000_0001) != 0)
result.append("x");
else
result.append("-");
}
return PosixFilePermissions.fromString(result.toString());
}
/**
* Extracts a Gzip file.
*
* @param source the source file
* @param target the target directory
* @return the output file
* @throws IOException if an I/O error occurs
*/
private Path extractGzip(Path source, Path target) throws IOException
{
String filename = source.getFileName().toString();
String extension = getFileExtension(filename);
String nameWithoutExtension = filename.substring(0, filename.length() - extension.length());
Path outPath = target.resolve(nameWithoutExtension);
try (GzipCompressorInputStream in = new GzipCompressorInputStream(Files.newInputStream(
source)))
{
try (OutputStream out = Files.newOutputStream(outPath))
{
final byte[] buffer = new byte[10 * 1024];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
out.write(buffer, 0, count);
}
}
}
return outPath;
}
/**
* Returns a filename extension. For example, {@code getFileExtension("foo.tar.gz")} returns
* {@code .gz}. Unix hidden files (e.g. ".hidden") have no extension.
*
* @param filename the filename
* @return an empty string if no extension is found
* @throws NullArgumentException if filename is null
*/
private String getFileExtension(String filename)
{
Preconditions.checkNotNull(filename, "filename may not be null");
Pattern pattern = Pattern.compile("[^\\.]+(\\.[\\p{Alnum}]+)$");
Matcher matcher = pattern.matcher(filename);
if (!matcher.find())
return "";
return matcher.group(1);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy