blob: 777bf744587f3c9d7627f46850604b96a300ff82 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.storm.submit.command;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang.StringUtils;
import org.apache.storm.submit.dependency.AetherUtils;
import org.apache.storm.submit.dependency.DependencyResolver;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.util.repository.AuthenticationBuilder;
import org.json.simple.JSONValue;
/**
* Main class of dependency resolver.
*/
public class DependencyResolverMain {
private static final String OPTION_ARTIFACTS_LONG = "artifacts";
private static final String OPTION_ARTIFACT_REPOSITORIES_LONG = "artifactRepositories";
private static final String OPTION_MAVEN_LOCAL_REPOSITORY_DIRECTORY_LONG = "mavenLocalRepositoryDirectory";
private static final String OPTION_PROXY_URL_LONG = "proxyUrl";
private static final String OPTION_PROXY_USERNAME_LONG = "proxyUsername";
private static final String OPTION_PROXY_PASSWORD_LONG = "proxyPassword";
public static final String DEFAULT_FAILBACK_MAVEN_LOCAL_REPOSITORY_DIRECTORY = "local-repo";
/**
* Main entry of dependency resolver.
*
* @param args console arguments
* @throws ParseException If there's parsing error on option parse.
* @throws MalformedURLException If proxy URL is malformed.
*/
public static void main(String[] args) throws ParseException, MalformedURLException {
Options options = buildOptions();
CommandLineParser parser = new DefaultParser();
CommandLine commandLine = parser.parse(options, args);
if (!commandLine.hasOption(OPTION_ARTIFACTS_LONG)) {
throw new IllegalArgumentException("artifacts must be presented.");
}
String artifactsArg = commandLine.getOptionValue(OPTION_ARTIFACTS_LONG);
// DO NOT CHANGE THIS TO SYSOUT
System.err.println("DependencyResolver input - artifacts: " + artifactsArg);
List<Dependency> dependencies = parseArtifactArgs(artifactsArg);
List<RemoteRepository> repositories;
if (commandLine.hasOption(OPTION_ARTIFACT_REPOSITORIES_LONG)) {
String remoteRepositoryArg = commandLine.getOptionValue(OPTION_ARTIFACT_REPOSITORIES_LONG);
// DO NOT CHANGE THIS TO SYSOUT
System.err.println("DependencyResolver input - repositories: " + remoteRepositoryArg);
repositories = parseRemoteRepositoryArgs(remoteRepositoryArg);
} else {
repositories = Collections.emptyList();
}
try {
String localMavenRepoPath = getOrDefaultLocalMavenRepositoryPath(
commandLine.getOptionValue(OPTION_MAVEN_LOCAL_REPOSITORY_DIRECTORY_LONG),
DEFAULT_FAILBACK_MAVEN_LOCAL_REPOSITORY_DIRECTORY);
// create root directory if not exist
Files.createDirectories(new File(localMavenRepoPath).toPath());
DependencyResolver resolver = new DependencyResolver(localMavenRepoPath, repositories);
if (commandLine.hasOption(OPTION_PROXY_URL_LONG)) {
String proxyUrl = commandLine.getOptionValue(OPTION_PROXY_URL_LONG);
String proxyUsername = commandLine.getOptionValue(OPTION_PROXY_USERNAME_LONG);
String proxyPassword = commandLine.getOptionValue(OPTION_PROXY_PASSWORD_LONG);
resolver.setProxy(parseProxyArg(proxyUrl, proxyUsername, proxyPassword));
}
List<ArtifactResult> artifactResults = resolver.resolve(dependencies);
Iterable<ArtifactResult> missingArtifacts = filterMissingArtifacts(artifactResults);
if (missingArtifacts.iterator().hasNext()) {
printMissingArtifactsToSysErr(missingArtifacts);
throw new RuntimeException("Some artifacts are not resolved");
}
System.out.println(JSONValue.toJSONString(transformArtifactResultToArtifactToPaths(artifactResults)));
System.out.flush();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private static Iterable<ArtifactResult> filterMissingArtifacts(List<ArtifactResult> artifactResults) {
return Iterables.filter(artifactResults, new Predicate<ArtifactResult>() {
@Override
public boolean apply(ArtifactResult artifactResult) {
return artifactResult.isMissing();
}
});
}
private static void printMissingArtifactsToSysErr(Iterable<ArtifactResult> missingArtifacts) {
for (ArtifactResult artifactResult : missingArtifacts) {
System.err.println("ArtifactResult : " + artifactResult + " / Errors : " + artifactResult.getExceptions());
}
}
private static List<Dependency> parseArtifactArgs(String artifactArgs) {
List<String> artifacts = Arrays.asList(artifactArgs.split(","));
List<Dependency> dependencies = new ArrayList<>(artifacts.size());
for (String artifactOpt : artifacts) {
if (artifactOpt.trim().isEmpty()) {
continue;
}
dependencies.add(AetherUtils.parseDependency(artifactOpt));
}
return dependencies;
}
private static List<RemoteRepository> parseRemoteRepositoryArgs(String remoteRepositoryArg) {
List<String> repositories = Arrays.asList(remoteRepositoryArg.split(","));
List<RemoteRepository> remoteRepositories = new ArrayList<>(repositories.size());
for (String repositoryOpt : repositories) {
if (repositoryOpt.trim().isEmpty()) {
continue;
}
remoteRepositories.add(AetherUtils.parseRemoteRepository(repositoryOpt));
}
return remoteRepositories;
}
private static Proxy parseProxyArg(String proxyUrl, String proxyUsername, String proxyPassword) throws MalformedURLException {
URL url = new URL(proxyUrl);
if (StringUtils.isNotEmpty(proxyUsername) && StringUtils.isNotEmpty(proxyPassword)) {
AuthenticationBuilder authBuilder = new AuthenticationBuilder();
authBuilder.addUsername(proxyUsername).addPassword(proxyPassword);
return new Proxy(url.getProtocol(), url.getHost(), url.getPort(), authBuilder.build());
} else {
return new Proxy(url.getProtocol(), url.getHost(), url.getPort());
}
}
private static Map<String, String> transformArtifactResultToArtifactToPaths(List<ArtifactResult> artifactResults) {
Map<String, String> artifactToPath = new LinkedHashMap<>();
for (ArtifactResult artifactResult : artifactResults) {
Artifact artifact = artifactResult.getArtifact();
artifactToPath.put(AetherUtils.artifactToString(artifact), artifact.getFile().getAbsolutePath());
}
return artifactToPath;
}
private static String getOrDefaultLocalMavenRepositoryPath(String customLocalMavenPath, String defaultPath) {
if (customLocalMavenPath != null) {
Path customPath = new File(customLocalMavenPath).toPath();
Preconditions.checkArgument(!Files.exists(customPath) || Files.isDirectory(customPath),
"Custom local maven repository path exist and is not a directory!");
return customLocalMavenPath;
}
String localMavenRepoPathStr = getLocalMavenRepositoryPath();
if (StringUtils.isNotEmpty(localMavenRepoPathStr)) {
Path localMavenRepoPath = new File(localMavenRepoPathStr).toPath();
if (Files.exists(localMavenRepoPath) && Files.isDirectory(localMavenRepoPath)) {
return localMavenRepoPathStr;
}
}
return defaultPath;
}
private static String getLocalMavenRepositoryPath() {
String userHome = System.getProperty("user.home");
if (StringUtils.isNotEmpty(userHome)) {
return userHome + File.separator + ".m2" + File.separator + "repository";
}
return null;
}
private static Options buildOptions() {
Options options = new Options();
options.addOption(null,
OPTION_ARTIFACTS_LONG,
true,
"REQUIRED string representation of artifacts");
options.addOption(null,
OPTION_ARTIFACT_REPOSITORIES_LONG,
true,
"OPTIONAL string representation of artifact repositories");
options.addOption(null,
OPTION_MAVEN_LOCAL_REPOSITORY_DIRECTORY_LONG,
true,
"OPTIONAL string representation of local maven repository directory path");
options.addOption(null,
OPTION_PROXY_URL_LONG,
true,
"OPTIONAL URL representation of proxy server");
options.addOption(null,
OPTION_PROXY_USERNAME_LONG,
true,
"OPTIONAL Username of proxy server (basic auth)");
options.addOption(null,
OPTION_PROXY_PASSWORD_LONG,
true,
"OPTIONAL Password of proxy server (basic auth)");
return options;
}
}