blob: ea1b515fb3c517f3317dee0d0ba76f456431912c [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// 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.
package com.google.gerrit.pgm.init;
import com.google.gerrit.pgm.util.ConsoleUI;
import com.google.gerrit.pgm.util.Die;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.HttpSupport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/** Get optional or required 3rd party library files into $site_path/lib. */
class LibraryDownloader {
private final ConsoleUI ui;
private final File lib_dir;
private final ReloadSiteLibrary reload;
private boolean required;
private String name;
private String jarUrl;
private String sha1;
private File dst;
@Inject
LibraryDownloader(final ReloadSiteLibrary reload, final ConsoleUI ui,
final SitePaths site) {
this.ui = ui;
this.lib_dir = site.lib_dir;
this.reload = reload;
}
void setName(final String name) {
this.name = name;
}
void setJarUrl(final String url) {
this.jarUrl = url;
}
void setSHA1(final String sha1) {
this.sha1 = sha1;
}
void downloadRequired() {
this.required = true;
download();
}
void downloadOptional() {
this.required = false;
download();
}
private void download() {
if (jarUrl == null || !jarUrl.contains("/")) {
throw new IllegalStateException("Invalid JarUrl for " + name);
}
final String jarName = jarUrl.substring(jarUrl.lastIndexOf('/') + 1);
if (jarName.contains("/") || jarName.contains("\\")) {
throw new IllegalStateException("Invalid JarUrl: " + jarUrl);
}
if (name == null) {
name = jarName;
}
dst = new File(lib_dir, jarName);
if (!dst.exists() && shouldGet()) {
doGet();
}
}
private boolean shouldGet() {
if (ui.isBatch()) {
return required;
} else {
final StringBuilder msg = new StringBuilder();
msg.append("\n");
msg.append("Gerrit Code Review is not shipped with %s\n");
if (required) {
msg.append("** This library is required for your configuration. **\n");
} else {
msg.append(" If available, Gerrit can take advantage of features\n");
msg.append(" in the library, but will also function without it.\n");
}
msg.append("Download and install it now");
return ui.yesno(true, msg.toString(), name);
}
}
private void doGet() {
if (!lib_dir.exists() && !lib_dir.mkdirs()) {
throw new Die("Cannot create " + lib_dir);
}
try {
doGetByHttp();
verifyFileChecksum();
} catch (IOException err) {
dst.delete();
if (ui.isBatch()) {
throw new Die("error: Cannot get " + jarUrl, err);
}
System.err.println();
System.err.println();
System.err.println("error: " + err.getMessage());
System.err.println("Please download:");
System.err.println();
System.err.println(" " + jarUrl);
System.err.println();
System.err.println("and save as:");
System.err.println();
System.err.println(" " + dst.getAbsolutePath());
System.err.println();
System.err.flush();
ui.waitForUser();
if (dst.exists()) {
verifyFileChecksum();
} else if (!ui.yesno(!required, "Continue without this library")) {
throw new Die("aborted by user");
}
}
reload.reload();
}
private void doGetByHttp() throws IOException {
System.err.print("Downloading " + jarUrl + " ...");
System.err.flush();
try {
final ProxySelector proxySelector = ProxySelector.getDefault();
final URL url = new URL(jarUrl);
final Proxy proxy = HttpSupport.proxyFor(proxySelector, url);
final HttpURLConnection c = (HttpURLConnection) url.openConnection(proxy);
final InputStream in;
switch (HttpSupport.response(c)) {
case HttpURLConnection.HTTP_OK:
in = c.getInputStream();
break;
case HttpURLConnection.HTTP_NOT_FOUND:
throw new FileNotFoundException(url.toString());
default:
throw new IOException(url.toString() + ": " + HttpSupport.response(c)
+ " " + c.getResponseMessage());
}
try {
final OutputStream out = new FileOutputStream(dst);
try {
final byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) > 0) {
out.write(buf, 0, n);
}
} finally {
out.close();
}
} finally {
in.close();
}
System.err.println(" OK");
System.err.flush();
} catch (IOException err) {
dst.delete();
System.err.println(" !! FAIL !!");
System.err.flush();
throw err;
}
}
private void verifyFileChecksum() {
if (sha1 != null) {
try {
final MessageDigest md = MessageDigest.getInstance("SHA-1");
final FileInputStream in = new FileInputStream(dst);
try {
final byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) > 0) {
md.update(buf, 0, n);
}
} finally {
in.close();
}
if (sha1.equals(ObjectId.fromRaw(md.digest()).name())) {
System.err.println("Checksum " + dst.getName() + " OK");
System.err.flush();
} else if (ui.isBatch()) {
dst.delete();
throw new Die(dst + " SHA-1 checksum does not match");
} else if (!ui.yesno(null /* force an answer */,
"error: SHA-1 checksum does not match\n" + "Use %s anyway",//
dst.getName())) {
dst.delete();
throw new Die("aborted by user");
}
} catch (IOException checksumError) {
dst.delete();
throw new Die("cannot checksum " + dst, checksumError);
} catch (NoSuchAlgorithmException checksumError) {
dst.delete();
throw new Die("cannot checksum " + dst, checksumError);
}
}
}
}