
com.igormaznitsa.mvngolang.AbstractGolangSdkAwareMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gosdk-wrapper-maven-plugin Show documentation
Show all versions of gosdk-wrapper-maven-plugin Show documentation
A maven plugin to download GoSDK and call its commands in Maven.
The newest version!
package com.igormaznitsa.mvngolang;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.System.out;
import static java.nio.file.Files.isRegularFile;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singleton;
import com.igormaznitsa.mvngolang.utils.ApacheHttpClient5Loader;
import com.igormaznitsa.mvngolang.utils.ArchiveUnpacker;
import com.igormaznitsa.mvngolang.utils.ProxySettings;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.core5.http.Header;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.settings.Proxy;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@SuppressWarnings({"ReassignedVariable", "CanBeFinal", "SameParameterValue"})
public abstract class AbstractGolangSdkAwareMojo extends AbstractCommonMojo {
public static final String SDK_NAME_PATTERN = "go%s.%s-%s%s";
private static final List SDK_ARCHIVE_MIMES =
List.of(
"application/octet-stream",
"application/zip",
"application/x-tar",
"application/x-gzip"
);
private static final long LOCK_FILE_SLEEP_MS = 100;
private static final Duration DELAY_LOCK_FILE_NOTIFICATION = Duration.ofSeconds(15);
/**
* Section describing proxy settings.
* {@code
*
* http
* 127.0.0.1
* 8085
* johndow
* 123456
* google.com|youtube.com
*
* }
*
* @since 1.0.0
*/
@Parameter(name = "proxy")
private ProxySettings proxy;
/**
* Disable SSL certificate check during HTTP requests.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.disable.ssl.check", name = "disableSslCheck", defaultValue = "false")
private boolean disableSslCheck;
/**
* Hide SDK load indicator.
*
* @since 1.0.1
*/
@Parameter(property = "mvn.golang.hide.load.indicator", name = "hideLoadIndicator", defaultValue = "false")
private boolean hideLoadIndicator;
/**
* The site for GoSDK archives.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.sdk.site", name = "sdkSite", defaultValue = "https://storage.googleapis.com/golang/")
private String sdkSite;
/**
* Allows to define base SDK archive base name. If not defined then base name will be synthesized automatically.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.sdk.archive.base.name", name = "sdkArchiveBaseName")
private String sdkArchiveBaseName;
/**
* Folder to download SDK archives. If not defined then storeFolder in use.
*
* @see #storeFolder
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.download.archive.folder", name = "downloadArchiveFolder")
private String downloadArchiveFolder;
/**
* MD5 to check downloaded archive file.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.expected.archive.md5", name = "expectedArchiveMd5")
private String expectedArchiveMd5;
/**
* If true then downloaded GoSDK archive will not be removed after processing.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.keep.downloaded.archive", name = "keepDownloadedArchive", defaultValue = "false")
private boolean keepDownloadedArchive;
/**
* Force use of existing pre-installed Go folder.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.preinstalled.sdk.folder", name = "preinstalledSdkFolder")
private String preinstalledSdkFolder;
/**
* Force direct URL to load GoSDK archive.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.sdk.download.url", name = "sdkDownloadUrl")
private String sdkDownloadUrl;
/**
* Maven artifact id to load GoSDK archive as an artifact from current Maven repository. It has the highest priority during SDK download.
* Expected format groupId:artifactId:version[:type[:classifier]]
* If the type is not defined, the archive extension will be automatically determined based on the host OS.
*
* Example usage:
* {@code
* com.sdk.go:go-sdk:1.24.1
* }
*
* @since 1.0.4
*/
@Parameter(property = "mvn.golang.sdk.artifact.id", name = "sdkArtifactId")
private String sdkArtifactId;
/**
* GoSDK version.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.go.version", name = "goVersion", defaultValue = "1.24.1")
private String goVersion;
/**
* GoSDK OS.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.os", name = "os")
private String os;
/**
* GoSDK architecture.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.arch", name = "arch")
private String arch;
/**
* Optional suffix for OSX.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.osx.version", name = "osxVersion")
private String osxVersion;
/**
* Force GoSDK archive file name.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.sdk.archive.file.name", name = "sdkArchiveFileName")
private String sdkArchiveFileName;
/**
* Connection timeout for HTTP client operations.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.connection.timeout.ms", name = "connectionTimeout", defaultValue = "60000")
private long connectionTimeout = 60_000L;
/**
* Force use maven proxy settings.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.use.maven.proxy", name = "useMavenProxy", defaultValue = "true")
private boolean useMavenProxy;
/**
* Guess GoSDK archive file extension based on host os.
*
* @since 1.0.0
*/
@Parameter(property = "mvn.golang.sdk.archive.file.auto.extension", name = "sdkArchiveFileAutoExtension", defaultValue = "true")
private boolean sdkArchiveFileAutoExtension;
private static String makeBaseSdkName(
final String sdkVersion,
final String os,
final String arch,
final String osxVersion) {
return String.format(SDK_NAME_PATTERN, sdkVersion, os, arch,
(osxVersion == null || osxVersion.isBlank()) ? "" : "-" + osxVersion);
}
private static String ensureSafeFileName(final String fileName) {
final String baseName;
final String extension;
final int dotIndex = fileName.indexOf('.');
if (dotIndex < 0) {
baseName = fileName;
extension = "";
} else {
baseName = fileName.substring(0, dotIndex);
extension = fileName.substring(dotIndex + 1);
}
final String processedBaseName = baseName.replaceAll("[^a-zA-Z0-9-_]", "_");
return extension.isEmpty() ? processedBaseName : processedBaseName + "." + extension;
}
@SuppressWarnings("UnusedReturnValue")
protected static int printCliProgressBar(
final String prefix,
final String postfix,
final long value,
final long maxValue,
final int progressBarWidth
) {
final StringBuilder builder = new StringBuilder();
builder.append("\r\u001B[?25l");
builder.append(prefix == null ? "" : prefix);
builder.append("[");
final int progress = max(0, min(progressBarWidth,
(int) Math.round(progressBarWidth * ((double) value / (double) maxValue))));
builder.append("▒".repeat(progress));
builder.append("-".repeat(Math.max(0, progressBarWidth - progress)));
builder.append(']');
if (postfix != null) {
builder.append(postfix);
}
builder.append("\u001B[?25h");
out.print(builder);
out.flush();
return progress;
}
protected static List findExecutable(
final String fileName,
final List folders,
final boolean findInBinSubfolder,
final boolean walkSubfolders) throws IOException {
if (fileName == null) {
throw new NullPointerException("File name is null");
}
if (SystemUtils.IS_OS_WINDOWS && fileName.contains(":")) {
throw new IllegalArgumentException("Illegal file name: " + fileName);
}
if (fileName.contains("/") || fileName.contains("\\")) {
final List result = new ArrayList<>();
for (final Path p : folders) {
final Path filePath = p.resolve(fileName);
if (isRegularFile(filePath)) {
result.add(filePath);
}
}
return result;
}
final Set variants;
if (fileName.contains(".")) {
variants = Set.of(fileName);
} else {
final List possibleExtensions;
if (SystemUtils.IS_OS_WINDOWS) {
possibleExtensions = List.of(".exe", ".cmd", ".bat");
} else {
possibleExtensions = List.of(".sh", "");
}
variants = possibleExtensions.stream()
.flatMap(x -> Stream.of(x, x.toUpperCase(Locale.ENGLISH)))
.map(x -> fileName + x)
.collect(Collectors.toSet());
}
final List result = new ArrayList<>();
if (findInBinSubfolder) {
for (final Path path : folders) {
final Path folderBin = path.resolve("bin");
if (Files.isDirectory(folderBin)) {
try (
Stream walker = Files.walk(folderBin, walkSubfolders ? Integer.MAX_VALUE : 1)) {
walker
.filter(x -> isRegularFile(x) && variants.contains(x.getFileName().toString()))
.forEach(result::add);
}
}
}
} else {
for (final Path path : folders) {
try (Stream walker = Files.walk(path, walkSubfolders ? Integer.MAX_VALUE : 1)) {
walker.filter(x -> isRegularFile(x) && variants.contains(x.getFileName().toString()))
.forEach(result::add);
}
}
}
return result;
}
private String findSdkBaseName() {
if (isNullOrEmpty(this.sdkArchiveBaseName)) {
this.logOptional("Making base sdk name on provided parameters");
return makeBaseSdkName(this.goVersion, this.findOs(), this.findArch(), this.osxVersion);
} else {
this.logOptional("Forced direct sdk base name: " + this.sdkArchiveBaseName);
return ensureSafeFileName(this.sdkArchiveBaseName.trim());
}
}
@Override
public final void doExecute() throws MojoExecutionException, MojoFailureException {
final long startTime = System.currentTimeMillis();
final Path goSdkFolder;
if (isNullOrEmpty(this.preinstalledSdkFolder)) {
final String sdkBaseName = this.findSdkBaseName();
if (sdkBaseName.isBlank()) {
throw new MojoExecutionException(
"Detected blank GoSDK base name, may be wrong config properties");
}
this.logOptional("Found sdkBaseName: " + sdkBaseName);
goSdkFolder = this.ensureCachedGoSdk(sdkBaseName);
} else {
this.logInfo("Provided pre-installed GoSDK folder: " + this.preinstalledSdkFolder);
goSdkFolder = new File(this.preinstalledSdkFolder).toPath();
if (!Files.isDirectory(goSdkFolder)) {
throw new MojoExecutionException(
"Can't find defined pre-installed GoSDK folder: " + this.preinstalledSdkFolder);
}
}
try {
this.onMojoExecute(goSdkFolder);
} catch (IOException ex) {
throw new MojoExecutionException("IOException during onMojoExecute", ex);
} finally {
this.logOptional("Elapsed time " + (System.currentTimeMillis() - startTime) + " ms");
}
}
private Path ensureCachedGoSdk(final String sdkBaseName)
throws MojoFailureException, MojoExecutionException {
final Path cacheFolder;
try {
this.logOptional("Finding or creating store folder: " + this.storeFolder);
cacheFolder = Files.createDirectories(this.storeFolder.toPath());
} catch (IOException ex) {
throw new MojoFailureException(
"Can't create cache folder or it is not a folder exists: " + this.storeFolder);
}
try {
final File lockFile = this.lockSdkFolder(cacheFolder.toFile(), sdkBaseName);
try {
Path preparedSdkFolder = cacheFolder.resolve(sdkBaseName);
if (!Files.isDirectory(preparedSdkFolder)) {
this.logOptional("There is no cached GoSDK: " + preparedSdkFolder);
if (this.session.isOffline()) {
throw new MojoFailureException(
"There is no cached GoSDK, the session is offline one: " + preparedSdkFolder);
} else {
final Path tempSdkFolder = preparedSdkFolder.resolveSibling(
".unpack" + preparedSdkFolder.getFileName().toString());
long start = System.currentTimeMillis();
try {
this.loadAndUnpackGoSdk(sdkBaseName, tempSdkFolder);
} finally {
this.logDebug(
"Elapsed time for loadAndUnpackGoSdk: " + (System.currentTimeMillis() - start) +
" ms");
}
start = System.currentTimeMillis();
try {
final Path goFolder = tempSdkFolder.resolve("go");
final Path sourcePath;
if (Files.isDirectory(goFolder)) {
sourcePath = goFolder;
} else {
sourcePath = tempSdkFolder;
}
this.logOptional("Moving unpacked folder " + sourcePath + " to " + preparedSdkFolder);
FileUtils.moveDirectory(sourcePath.toFile(), preparedSdkFolder.toFile());
} finally {
if (Files.exists(tempSdkFolder)) {
this.logOptional("Deleting temp sdk folder: " + tempSdkFolder);
FileUtils.deleteDirectory(tempSdkFolder.toFile());
}
this.logDebug("Elapsed time for all GoSDK unpacking operations: " +
(System.currentTimeMillis() - start) + " ms");
}
}
}
return preparedSdkFolder;
} finally {
this.unlockSdkFolder(lockFile);
}
} catch (IOException ex) {
throw new MojoExecutionException("Detected error during execution", ex);
}
}
private String normalizedSdkSite() {
final String link = this.sdkSite.trim();
if (link.endsWith("/")) {
return link;
} else {
return link + '/';
}
}
private Path findDownloadArchiveFolder() throws IOException {
final Path result;
if (isNullOrEmpty(this.downloadArchiveFolder)) {
result = this.storeFolder.toPath();
} else {
result = new File(this.downloadArchiveFolder.trim()).toPath();
}
this.logDebug("Creating load folder: " + result);
return Files.createDirectories(result);
}
private void loadAndUnpackGoSdk(final String sdkBaseName, final Path destinationFolder)
throws IOException, MojoFailureException {
this.logInfo("Loading GoSDK for base name: " + sdkBaseName);
if (Files.isDirectory(destinationFolder)) {
this.logWarn("Detected existing folder for GoSDK, deleting it: " + destinationFolder);
FileUtils.deleteDirectory(destinationFolder.toFile());
}
final boolean loadAsArtifactId = !isNullOrEmpty(this.sdkArtifactId);
final String sdkArchiveUrl;
final String fileName;
if (isNullOrEmpty(this.sdkDownloadUrl) && !loadAsArtifactId) {
if (isNullOrEmpty(this.sdkArchiveFileName)) {
this.logDebug("Looking for GoSDK archive name");
final Document document =
this.loadGolangSdkList(URLEncoder.encode(sdkBaseName, StandardCharsets.UTF_8));
fileName =
this.extractSdkFileName(document, sdkBaseName, List.of("tar.gz", "zip"));
} else {
this.logInfo("Detected directly provided GoSDK archive name: " + this.sdkArchiveFileName);
fileName = this.sdkArchiveFileName;
}
this.logInfo("Found listed archive: " + fileName);
sdkArchiveUrl = this.normalizedSdkSite() + fileName;
this.logInfo("Loading from: " + sdkArchiveUrl);
} else {
if (loadAsArtifactId) {
this.logDebug("Loading from Maven repository");
sdkArchiveUrl = null;
fileName = isNullOrEmpty(this.sdkArchiveFileName) ? "mavenRepositoryArtifact" :
this.sdkArchiveFileName.trim();
} else {
this.logWarn("Detected directly provided download link: " + this.sdkDownloadUrl);
fileName = isNullOrEmpty(this.sdkArchiveFileName) ? "directLinkGoSdk" :
this.sdkArchiveFileName.trim();
sdkArchiveUrl = this.sdkDownloadUrl.trim();
}
}
final Path loadFolder = this.findDownloadArchiveFolder();
final Path tempArchivePath = loadFolder.resolve(
".tmp_" + Long.toString(System.currentTimeMillis(), 25).toUpperCase(Locale.ENGLISH) + '_' +
ensureSafeFileName(fileName));
try {
Path sdkPath;
if (loadAsArtifactId) {
final String trimmedSdkArtifactId = this.sdkArtifactId.trim();
this.logWarn("Retrieving artifact from the Maven repository: " + trimmedSdkArtifactId);
sdkPath = this.downloadFromArtifactId(trimmedSdkArtifactId);
this.logOptional("SDK artifact archive location: " + sdkPath);
} else {
this.logInfo("Retrieving GoSDK from URL: " + sdkArchiveUrl);
downloadFromUrl(sdkArchiveUrl, tempArchivePath);
sdkPath = tempArchivePath;
}
this.extractArchiveToDestination(sdkPath, destinationFolder);
this.logInfo("Updating file attributes in folder: " + destinationFolder);
this.makeExecutableFilesInFolder(destinationFolder);
} finally {
if (!this.keepDownloadedArchive && Files.exists(tempArchivePath)) {
this.logInfo("Deleting temporary archive file:" + tempArchivePath);
if (Files.deleteIfExists(tempArchivePath)) {
this.logDebug("Deleted successfully");
} else {
this.logWarn("Can't delete temporary archive file: " + tempArchivePath);
tempArchivePath.toFile().deleteOnExit();
}
} else {
if (Files.exists(tempArchivePath)) {
this.logWarn("Downloaded archive not removed for direct request: " + tempArchivePath);
}
}
}
}
private void downloadFromUrl(String sdkArchiveUrl, Path tempArchivePath)
throws IOException, MojoFailureException {
final AtomicInteger lastProgress = new AtomicInteger(-1);
final Header[] headers = ApacheHttpClient5Loader.loadResource("GET",
makeHttpClient(),
sdkArchiveUrl,
(loaded, size, progress) -> {
if (progress >= 0 && lastProgress.get() != progress) {
lastProgress.set(progress);
if (!this.session.isParallel() || this.hideLoadIndicator) {
final String sizeText = (size / 1024L) + "Mb";
final String loadedText = (loaded / 1024L) + "Mb";
printCliProgressBar("Loading GoSDK:", ' ' + loadedText + '/' + sizeText,
progress, 100, 5);
if (progress == 100) {
System.out.println();
}
}
}
},
h -> {
this.logDebug("Opening output stream for archive file:" + tempArchivePath);
try {
return Files.newOutputStream(tempArchivePath);
} catch (IOException ex) {
throw new IllegalStateException(
"IOError during open stream for temporary file: " + tempArchivePath, ex);
}
},
x -> 16 * 1024 * 1024,
SDK_ARCHIVE_MIMES
);
this.logDebug("Headers: " + Arrays.toString(headers));
this.logInfo("Successfully downloaded archive file: " + tempArchivePath);
if (isNullOrEmpty(this.expectedArchiveMd5)) {
final ApacheHttpClient5Loader.XGoogHashHeader xgoogHeader =
new ApacheHttpClient5Loader.XGoogHashHeader(headers);
if (xgoogHeader.isValid()) {
this.logInfo("Detected XGoogHashHeader, validating checksum for downloaded archive");
try (final InputStream fileInputStream = Files.newInputStream(tempArchivePath)) {
if (xgoogHeader.isDataOk(fileInputStream)) {
this.logInfo("Checksum is ok");
} else {
this.logError("Checksum is wrong");
throw new MojoFailureException("Downloaded archive has wrong checksum");
}
}
}
} else {
this.logInfo("Check archive MD5 for provided value: " + this.expectedArchiveMd5);
try (final InputStream fileInputStream = Files.newInputStream(tempArchivePath)) {
if (ApacheHttpClient5Loader.XGoogHashHeader.checkMd5(fileInputStream,
this.expectedArchiveMd5)) {
this.logInfo("MD5 is ok");
} else {
this.logError("MD5 is wrong");
throw new MojoFailureException("Downloaded archive has wrong MD5 checksum");
}
}
}
}
private void extractArchiveToDestination(Path tempArchivePath, Path destinationFolder)
throws IOException {
try {
this.logInfo("Unpacking archive into: " + destinationFolder);
final AtomicInteger counter = new AtomicInteger();
ArchiveUnpacker.INSTANCE.unpackArchive(tempArchivePath.toFile(), destinationFolder.toFile(),
new ArchiveUnpacker.UnpackListener() {
@Override
public void onArchiveType(ArchiveUnpacker source,
ArchiveUnpacker.ArchiveType archiveType) {
logDebug("Archive type: " + archiveType);
}
@Override
public void onArchiveEntry(ArchiveUnpacker source, ArchiveEntry archiveEntry) {
logTrace("Archive entry: " + archiveEntry.getName() + " (" +
(archiveEntry.isDirectory() ? "" : archiveEntry.getSize()) + ')');
counter.incrementAndGet();
}
@Override
public void onCompleted(ArchiveUnpacker source) {
logDebug("Decompression has been completed: " + counter.get() + " item(s)");
}
});
this.logInfo(
String.format("Archive successfully unpacked, detected %d items: %s", counter.get(),
destinationFolder));
} catch (ArchiveException ex) {
throw new IOException("Can't unpack archive for error", ex);
}
}
private Path downloadFromArtifactId(String artifactId) throws IOException {
return this.resolveBinaryArtifact(this.createDependencyArtifact(artifactId));
}
/**
* Creates a dependency artifact from a specification in
* {@code groupId:artifactId:version[:type[:classifier]]} format.
*
* @param artifactSpec artifact specification.
* @return artifact object instance.
*/
private Artifact createDependencyArtifact(final String artifactSpec) throws IOException {
final String[] parts = artifactSpec.split(":");
if (parts.length < 3 || parts.length > 5) {
throw new IOException(
"Invalid artifact specification format"
+ ", expected: groupId:artifactId:version[:type[:classifier]]"
+ ", actual: " + artifactSpec);
}
final String type = parts.length >= 4 ? parts[3] : findArchiveExtensionForOs();
final String classifier = parts.length == 5 ? parts[4] : null;
return this.createDependencyArtifact(parts[0], parts[1], parts[2], type, classifier);
}
private Artifact createDependencyArtifact(
final String groupId,
final String artifactId,
final String version,
final String type,
final String classifier
) {
final Dependency dependency = new Dependency();
dependency.setArtifactId(artifactId);
dependency.setGroupId(groupId);
dependency.setVersion(version);
dependency.setType(type);
dependency.setClassifier(classifier);
dependency.setScope(Artifact.SCOPE_PROVIDED);
return repositorySystem.createDependencyArtifact(dependency);
}
private Path resolveBinaryArtifact(final Artifact artifact) throws IOException {
final ArtifactResolutionRequest request = new ArtifactResolutionRequest()
.setArtifact(this.project.getArtifact())
.setResolveRoot(false)
.setResolveTransitively(false)
.setArtifactDependencies(singleton(artifact))
.setManagedVersionMap(emptyMap())
.setLocalRepository(this.localRepository)
.setRemoteRepositories(this.remoteRepositories)
.setOffline(this.session.isOffline())
.setForceUpdate(this.session.getRequest().isUpdateSnapshots())
.setServers(this.session.getRequest().getServers())
.setMirrors(this.session.getRequest().getMirrors())
.setProxies(this.session.getRequest().getProxies());
final ArtifactResolutionResult result = this.repositorySystem.resolve(request);
try {
this.resolutionErrorHandler.throwErrors(request, result);
} catch (final ArtifactResolutionException e) {
throw new IOException("Unable to resolve artifact: " + e.getMessage(), e);
}
final Set artifacts = result.getArtifacts();
this.logDebug("All resolved artifacts: " + artifacts);
if (artifacts == null || artifacts.isEmpty()) {
throw new IOException("Unable to resolve artifact: " + artifact);
}
if (artifacts.size() > 1) {
this.logWarn("Multiple artifacts detected: " + artifacts);
}
final Artifact resolvedBinaryArtifact = artifacts.iterator().next();
this.logDebug("Resolved artifact: " + resolvedBinaryArtifact);
return resolvedBinaryArtifact.getFile().toPath();
}
protected abstract void onMojoExecute(final Path goSdkFolder)
throws IOException, MojoExecutionException, MojoFailureException;
public String findArch() {
if (isNullOrEmpty(this.arch)) {
final String arch = SystemUtils.OS_ARCH.toLowerCase(Locale.ENGLISH);
if (arch.contains("ppc64le")) {
return "ppc64le";
} else if (arch.contains("armv6l")) {
return "armv6l";
} else if (arch.contains("arm64") || arch.contains("aarch64")) {
return "arm64";
} else if (arch.contains("s390")) {
return "s390x";
}
if (arch.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
return "386";
} else if (arch.contains("em64t")
|| arch.contains("x8664")
|| arch.contains("ia32e")
|| arch.contains("x64")
|| arch.contains("amd64")
|| arch.contains("x86_64")) {
return "amd64";
} else {
return "amd64";
}
} else {
return this.arch;
}
}
private String findOs() {
if (isNullOrEmpty(this.os)) {
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX) {
return "darwin";
} else if (SystemUtils.IS_OS_WINDOWS) {
return "windows";
} else if (SystemUtils.IS_OS_AIX) {
return "aix";
} else if (SystemUtils.IS_OS_FREE_BSD) {
return "freebsd";
} else if (SystemUtils.IS_OS_NET_BSD) {
return "netbsd";
} else if (SystemUtils.IS_OS_OPEN_BSD) {
return "openbsd";
} else if (SystemUtils.IS_OS_SOLARIS) {
return "solaris";
} else {
return "linux";
}
} else {
return this.os;
}
}
private HttpClient makeHttpClient() {
final ProxySettings proxySettings = this.findProxySettings();
this.logDebug("Proxy settings: " + proxySettings);
this.logDebug("Disable SSL check: " + this.disableSslCheck);
this.logDebug("Connection timeout: " + this.connectionTimeout);
return ApacheHttpClient5Loader.INSTANCE.createHttpClient(
this.findProxySettings(),
this.disableSslCheck,
Duration.ofMillis(this.connectionTimeout)
);
}
private void makeExecutableFilesInFolder(final Path folder) throws IOException {
try (Stream walker = Files.walk(folder)) {
walker.filter(
path -> isRegularFile(path)
&& !Files.isSymbolicLink(path)
&& !Files.isExecutable(path)
).forEach(path -> {
try {
Set permissions = Files.getPosixFilePermissions(path);
if (!permissions.contains(PosixFilePermission.OWNER_EXECUTE)) {
this.logTrace("Set executable flag for file: " + path);
permissions = new HashSet<>(permissions);
permissions.add(PosixFilePermission.OWNER_EXECUTE);
}
Files.setPosixFilePermissions(path, permissions);
} catch (UnsupportedOperationException ex) {
final File targetFile = path.toFile();
if (targetFile.setExecutable(true, true)) {
this.logTrace("Set executable flag for file through setExecutable: " + targetFile);
} else {
this.logTrace(
"(!)Cant set executable flag for file through setExecutable: " + targetFile);
}
} catch (IOException ex) {
logError("Can't set execute permission for unpacked file: " + path);
}
});
}
}
private String extractSdkFileName(
final Document document,
final String sdkBaseName,
final List allowedExtensions) throws IOException {
this.logDebug(String.format(
"Extracting GoSDK file name with base %s from document for allowed extensions %s",
sdkBaseName,
allowedExtensions)
);
final Set variantsWithExtensions =
allowedExtensions.stream().map(x -> sdkBaseName + '.' + x).collect(
Collectors.toSet());
final List listOfFoundSdk = new ArrayList<>();
final Element root = document.getDocumentElement();
if ("ListBucketResult".equals(root.getTagName())) {
final NodeList list = root.getElementsByTagName("Contents");
for (int i = 0; i < list.getLength(); i++) {
final Element element = (Element) list.item(i);
final NodeList keys = element.getElementsByTagName("Key");
if (keys.getLength() > 0) {
final String text = keys.item(0).getTextContent();
if (variantsWithExtensions.contains(text)) {
return text;
} else {
listOfFoundSdk.add(text);
}
}
}
this.logWarn(String.format("Can't find any expected distributive %s among provided files:%s",
variantsWithExtensions, listOfFoundSdk.stream().collect(
Collectors.joining("\n", "\n", "\n"))));
if (this.sdkArchiveFileAutoExtension) {
final String supposedSdkName =
sdkBaseName + '.' + findArchiveExtensionForOs();
this.logWarn("Force supposed GoSDK file name: " + supposedSdkName);
return supposedSdkName;
}
throw new IOException("Can't find SDK : " + sdkBaseName);
} else {
throw new IOException("It is not a ListBucket file [" + root.getTagName() + ']');
}
}
private Document loadGolangSdkList(final String keyPrefix) throws IOException {
final String listOfFilesUrl =
this.sdkSite.trim() + (keyPrefix == null ? "" : "?prefix=" + keyPrefix);
this.logDebug("Loading URL list document from GoSDK site: " + listOfFilesUrl);
final String text =
ApacheHttpClient5Loader.loadResourceAsString("GET", this.makeHttpClient(), listOfFilesUrl,
List.of("application/xml"));
this.logDebug("Loaded URL list: " + text);
if (text == null) {
throw new IOException("Empty result as GoSDK list");
}
try {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(text)));
} catch (ParserConfigurationException ex) {
getLog().error("Can't configure XML parser", ex);
throw new IOException("Can't configure XML parser", ex);
} catch (SAXException ex) {
getLog().error("Can't parse document", ex);
throw new IOException("Can't parse document", ex);
} catch (IOException ex) {
getLog().error("Unexpected IOException", ex);
throw new IOException("Unexpected IOException", ex);
}
}
private void unlockSdkFolder(final File lockFile) throws IOException {
long nextNotificationTime =
System.currentTimeMillis() + DELAY_LOCK_FILE_NOTIFICATION.toMillis();
while (lockFile.exists() && !lockFile.delete()) {
if (System.currentTimeMillis() >= nextNotificationTime) {
this.logWarn("Still can't unlock folder and remove file: " + lockFile);
nextNotificationTime = System.currentTimeMillis() + DELAY_LOCK_FILE_NOTIFICATION.toMillis();
}
this.sleep(LOCK_FILE_SLEEP_MS);
}
}
private File lockSdkFolder(final File sdkCacheFolder, final String baseSdkName)
throws IOException {
final File lockFile = new File(sdkCacheFolder, ".lock." + baseSdkName);
lockFile.deleteOnExit();
if (!lockFile.createNewFile()) {
long nextNotificationTime =
System.currentTimeMillis() + DELAY_LOCK_FILE_NOTIFICATION.toMillis();
while (lockFile.exists()) {
if (System.currentTimeMillis() >= nextNotificationTime) {
this.logWarn("Waiting for lock file: " + lockFile);
nextNotificationTime =
System.currentTimeMillis() + DELAY_LOCK_FILE_NOTIFICATION.toMillis();
}
this.sleep(LOCK_FILE_SLEEP_MS);
}
}
return lockFile;
}
private ProxySettings findProxySettings() {
final ProxySettings result;
if (this.useMavenProxy) {
final Proxy activeMavenProxy = this.settings == null ? null : this.settings.getActiveProxy();
if (activeMavenProxy == null) {
this.logDebug("No maven proxy settings");
result = null;
} else {
this.logDebug("Using maven proxy settings: " + activeMavenProxy);
result = new ProxySettings(
activeMavenProxy.getProtocol(),
activeMavenProxy.getHost(),
activeMavenProxy.getPort(),
activeMavenProxy.getUsername(),
activeMavenProxy.getPassword(),
activeMavenProxy.getNonProxyHosts()
);
}
} else {
result = this.proxy;
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy