| // 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 static com.google.gerrit.pgm.init.InitUtil.die; |
| import static com.google.gerrit.pgm.init.InitUtil.savePublic; |
| import static com.google.gerrit.pgm.init.InitUtil.saveSecure; |
| |
| import com.google.gerrit.pgm.util.ConsoleUI; |
| import com.google.gerrit.server.config.SitePaths; |
| import com.google.gerrit.server.util.SocketUtil; |
| import com.google.inject.Inject; |
| import com.google.inject.Singleton; |
| |
| import org.eclipse.jgit.errors.ConfigInvalidException; |
| import org.eclipse.jgit.storage.file.FileBasedConfig; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.InetSocketAddress; |
| import java.net.URLDecoder; |
| import java.util.Arrays; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| /** Upgrade from a 2.0.x site to a 2.1 site. */ |
| @Singleton |
| class UpgradeFrom2_0_x implements InitStep { |
| static final String[] etcFiles = {"gerrit.config", // |
| "secure.config", // |
| "replication.config", // |
| "ssh_host_rsa_key", // |
| "ssh_host_rsa_key.pub", // |
| "ssh_host_dsa_key", // |
| "ssh_host_dsa_key.pub", // |
| "ssh_host_key", // |
| "contact_information.pub", // |
| "gitweb_config.perl", // |
| "keystore", // |
| "GerritSite.css", // |
| "GerritSiteFooter.html", // |
| "GerritSiteHeader.html", // |
| }; |
| |
| private final ConsoleUI ui; |
| |
| private final FileBasedConfig cfg; |
| private final FileBasedConfig sec; |
| private final File site_path; |
| private final File etc_dir; |
| private final Section.Factory sections; |
| |
| @Inject |
| UpgradeFrom2_0_x(final SitePaths site, final InitFlags flags, |
| final ConsoleUI ui, final Section.Factory sections) { |
| this.ui = ui; |
| this.sections = sections; |
| |
| this.cfg = flags.cfg; |
| this.sec = flags.sec; |
| this.site_path = site.site_path; |
| this.etc_dir = site.etc_dir; |
| } |
| |
| boolean isNeedUpgrade() { |
| for (String name : etcFiles) { |
| if (new File(site_path, name).exists()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public void run() throws IOException, ConfigInvalidException { |
| if (!isNeedUpgrade()) { |
| return; |
| } |
| |
| if (!ui.yesno(true, "Upgrade '%s'", site_path.getCanonicalPath())) { |
| throw die("aborted by user"); |
| } |
| |
| for (String name : etcFiles) { |
| final File src = new File(site_path, name); |
| final File dst = new File(etc_dir, name); |
| if (src.exists()) { |
| if (dst.exists()) { |
| throw die("File " + src + " would overwrite " + dst); |
| } |
| if (!src.renameTo(dst)) { |
| throw die("Cannot rename " + src + " to " + dst); |
| } |
| } |
| } |
| |
| // We have to reload the configuration after the rename as |
| // the initial load pulled up an non-existent (and thus |
| // believed to be empty) file. |
| // |
| cfg.load(); |
| sec.load(); |
| |
| final Properties oldprop = readGerritServerProperties(); |
| if (oldprop != null) { |
| final Section database = sections.get("database", null); |
| |
| String url = oldprop.getProperty("url"); |
| if (url != null && !convertUrl(database, url)) { |
| database.set("type", "jdbc"); |
| database.set("driver", oldprop.getProperty("driver")); |
| database.set("url", url); |
| } |
| |
| String username = oldprop.getProperty("user"); |
| if (username == null || username.isEmpty()) { |
| username = oldprop.getProperty("username"); |
| } |
| if (username != null && !username.isEmpty()) { |
| cfg.setString("database", null, "username", username); |
| } |
| |
| String password = oldprop.getProperty("password"); |
| if (password != null && !password.isEmpty()) { |
| sec.setString("database", null, "password", password); |
| } |
| } |
| |
| String[] values; |
| |
| values = cfg.getStringList("ldap", null, "password"); |
| cfg.unset("ldap", null, "password"); |
| sec.setStringList("ldap", null, "password", Arrays.asList(values)); |
| |
| values = cfg.getStringList("sendemail", null, "smtpPass"); |
| cfg.unset("sendemail", null, "smtpPass"); |
| sec.setStringList("sendemail", null, "smtpPass", Arrays.asList(values)); |
| |
| saveSecure(sec); |
| savePublic(cfg); |
| } |
| |
| private boolean convertUrl(final Section database, String url) |
| throws UnsupportedEncodingException { |
| String username = null; |
| String password = null; |
| |
| if (url.contains("?")) { |
| final int q = url.indexOf('?'); |
| for (String pair : url.substring(q + 1).split("&")) { |
| final int eq = pair.indexOf('='); |
| if (0 < eq) { |
| return false; |
| } |
| |
| String n = URLDecoder.decode(pair.substring(0, eq), "UTF-8"); |
| String v = URLDecoder.decode(pair.substring(eq + 1), "UTF-8"); |
| |
| if ("user".equals(n) || "username".equals(n)) { |
| username = v; |
| |
| } else if ("password".equals(n)) { |
| password = v; |
| |
| } else { |
| // There is a parameter setting we don't recognize, use the |
| // JDBC URL format instead to preserve the configuration. |
| // |
| return false; |
| } |
| } |
| url = url.substring(0, q); |
| } |
| |
| if (url.startsWith("jdbc:h2:file:")) { |
| url = url.substring("jdbc:h2:file:".length()); |
| database.set("type", "h2"); |
| database.set("database", url); |
| return true; |
| } |
| |
| if (url.startsWith("jdbc:postgresql://")) { |
| url = url.substring("jdbc:postgresql://".length()); |
| final int sl = url.indexOf('/'); |
| if (sl < 0) { |
| return false; |
| } |
| |
| final InetSocketAddress addr = SocketUtil.parse(url.substring(0, sl), 0); |
| database.set("type", "postgresql"); |
| sethost(database, addr); |
| database.set("database", url.substring(sl + 1)); |
| setuser(database, username, password); |
| return true; |
| } |
| |
| if (url.startsWith("jdbc:postgresql:")) { |
| url = url.substring("jdbc:postgresql:".length()); |
| database.set("type", "postgresql"); |
| database.set("hostname", "localhost"); |
| database.set("database", url); |
| setuser(database, username, password); |
| return true; |
| } |
| |
| if (url.startsWith("jdbc:mysql://")) { |
| url = url.substring("jdbc:mysql://".length()); |
| final int sl = url.indexOf('/'); |
| if (sl < 0) { |
| return false; |
| } |
| |
| final InetSocketAddress addr = SocketUtil.parse(url.substring(0, sl), 0); |
| database.set("type", "mysql"); |
| sethost(database, addr); |
| database.set("database", url.substring(sl + 1)); |
| setuser(database, username, password); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| private void sethost(final Section database, final InetSocketAddress addr) { |
| database.set("hostname", SocketUtil.hostname(addr)); |
| if (0 < addr.getPort()) { |
| database.set("port", String.valueOf(addr.getPort())); |
| } |
| } |
| |
| private void setuser(final Section database, String username, String password) { |
| if (username != null && !username.isEmpty()) { |
| database.set("username", username); |
| } |
| if (password != null && !password.isEmpty()) { |
| sec.setString("database", null, "password", password); |
| } |
| } |
| |
| private Properties readGerritServerProperties() throws IOException { |
| final Properties srvprop = new Properties(); |
| final String name = System.getProperty("GerritServer"); |
| File path; |
| if (name != null) { |
| path = new File(name); |
| } else { |
| path = new File(site_path, "GerritServer.properties"); |
| if (!path.exists()) { |
| path = new File("GerritServer.properties"); |
| } |
| } |
| if (path.exists()) { |
| try { |
| final InputStream in = new FileInputStream(path); |
| try { |
| srvprop.load(in); |
| } finally { |
| in.close(); |
| } |
| } catch (IOException e) { |
| throw new IOException("Cannot read " + name, e); |
| } |
| final Properties dbprop = new Properties(); |
| for (final Map.Entry<Object, Object> e : srvprop.entrySet()) { |
| final String key = (String) e.getKey(); |
| if (key.startsWith("database.")) { |
| dbprop.put(key.substring("database.".length()), e.getValue()); |
| } |
| } |
| return dbprop; |
| } else { |
| return null; |
| } |
| } |
| } |