/*
* 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.zeppelin.interpreter.install;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Logger;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.dep.DependencyResolver;
import org.apache.zeppelin.util.Util;
import org.sonatype.aether.RepositoryException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Commandline utility to install interpreter from maven repository
*/
public class InstallInterpreter {
private final File interpreterListFile;
private final File interpreterBaseDir;
private final List<AvailableInterpreterInfo> availableInterpreters;
private final String localRepoDir;
private URL proxyUrl;
private String proxyUser;
private String proxyPassword;
/**
*
* @param interpreterListFile
* @param interpreterBaseDir interpreter directory for installing binaries
* @throws IOException
*/
public InstallInterpreter(File interpreterListFile, File interpreterBaseDir, String localRepoDir)
throws IOException {
this.interpreterListFile = interpreterListFile;
this.interpreterBaseDir = interpreterBaseDir;
this.localRepoDir = localRepoDir;
availableInterpreters = new LinkedList<>();
readAvailableInterpreters();
}
/**
* Information for available informations
*/
private static class AvailableInterpreterInfo {
public final String name;
public final String artifact;
public final String description;
public AvailableInterpreterInfo(String name, String artifact, String description) {
this.name = name;
this.artifact = artifact;
this.description = description;
}
}
private void readAvailableInterpreters() throws IOException {
if (!interpreterListFile.isFile()) {
System.err.println("Can't find interpreter list " + interpreterListFile.getAbsolutePath());
return;
}
String text = FileUtils.readFileToString(interpreterListFile);
String[] lines = text.split("\n");
Pattern pattern = Pattern.compile("(\\S+)\\s+(\\S+)\\s+(.*)");
int lineNo = 0;
for (String line : lines) {
lineNo++;
if (line == null || line.length() == 0 || line.startsWith("#")) {
continue;
}
Matcher match = pattern.matcher(line);
if (match.groupCount() != 3) {
System.err.println("Error on line " + lineNo + ", " + line);
continue;
}
match.find();
String name = match.group(1);
String artifact = match.group(2);
String description = match.group(3);
availableInterpreters.add(new AvailableInterpreterInfo(name, artifact, description));
}
}
public List<AvailableInterpreterInfo> list() {
for (AvailableInterpreterInfo info : availableInterpreters) {
System.out.println(info.name + "\t\t\t" + info.description);
}
return availableInterpreters;
}
public void installAll() {
for (AvailableInterpreterInfo info : availableInterpreters) {
install(info.name, info.artifact);
}
}
public void install(String [] names) {
for (String name : names) {
install(name);
}
}
public void install(String name) {
// find artifact name
for (AvailableInterpreterInfo info : availableInterpreters) {
if (name.equals(info.name)) {
install(name, info.artifact);
return;
}
}
throw new RuntimeException("Can't find interpreter '" + name + "'");
}
public void install(String [] names, String [] artifacts) {
if (names.length != artifacts.length) {
throw new RuntimeException("Length of given names and artifacts are different");
}
for (int i = 0; i < names.length; i++) {
install(names[i], artifacts[i]);
}
}
public void install(String name, String artifact) {
DependencyResolver depResolver = new DependencyResolver(localRepoDir);
if (proxyUrl != null) {
depResolver.setProxy(proxyUrl, proxyUser, proxyPassword);
}
File installDir = new File(interpreterBaseDir, name);
if (installDir.exists()) {
System.err.println("Directory " + installDir.getAbsolutePath()
+ " already exists"
+ "\n\nSkipped");
return;
}
System.out.println("Install " + name + "(" + artifact + ") to "
+ installDir.getAbsolutePath() + " ... ");
try {
depResolver.load(artifact, installDir);
System.out.println("Interpreter " + name + " installed under " +
installDir.getAbsolutePath() + ".");
startTip();
} catch (RepositoryException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setProxy(URL proxyUrl, String proxyUser, String proxyPassword) {
this.proxyUrl = proxyUrl;
this.proxyUser = proxyUser;
this.proxyPassword = proxyPassword;
}
public static void usage() {
System.out.println("Options");
System.out.println(" -l, --list List available interpreters");
System.out.println(" -a, --all Install all available interpreters");
System.out.println(" -n, --name [NAMES] Install interpreters (comma separated " +
"list)" +
"e.g. md,shell,jdbc,python,angular");
System.out.println(" -t, --artifact [ARTIFACTS] (Optional with -n) custom artifact names" +
". " +
"(comma separated list correspond to --name) " +
"e.g. customGroup:customArtifact:customVersion");
System.out.println(" --proxy-url [url] (Optional) proxy url. http(s)://host:port");
System.out.println(" --proxy-user [user] (Optional) proxy user");
System.out.println(" --proxy-password [password] (Optional) proxy password");
}
public static void main(String [] args) throws IOException {
if (args.length == 0) {
usage();
return;
}
ZeppelinConfiguration conf = ZeppelinConfiguration.create();
InstallInterpreter installer = new InstallInterpreter(
new File(conf.getInterpreterListPath()),
new File(conf.getInterpreterDir()),
conf.getInterpreterLocalRepoPath());
String names = null;
String artifacts = null;
URL proxyUrl = null;
String proxyUser = null;
String proxyPassword = null;
boolean all = false;
for (int i = 0; i < args.length; i++) {
String arg = args[i].toLowerCase(Locale.US);
switch (arg) {
case "--list":
case "-l":
installer.list();
System.exit(0);
break;
case "--all":
case "-a":
all = true;
break;
case "--name":
case "-n":
names = args[++i];
break;
case "--artifact":
case "-t":
artifacts = args[++i];
break;
case "--version":
case "-v":
Util.getVersion();
break;
case "--proxy-url":
proxyUrl = new URL(args[++i]);
break;
case "--proxy-user":
proxyUser = args[++i];
break;
case "--proxy-password":
proxyPassword = args[++i];
break;
case "--help":
case "-h":
usage();
System.exit(0);
break;
default:
System.out.println("Unknown option " + arg);
}
}
if (proxyUrl != null) {
installer.setProxy(proxyUrl, proxyUser, proxyPassword);
}
if (all) {
installer.installAll();
System.exit(0);
}
if (names != null) {
if (artifacts != null) {
installer.install(names.split(","), artifacts.split(","));
} else {
installer.install(names.split(","));
}
}
}
private static void startTip() {
System.out.println("\n1. Restart Zeppelin"
+ "\n2. Create interpreter setting in 'Interpreter' menu on Zeppelin GUI"
+ "\n3. Then you can bind the interpreter on your note");
}
}