Line data Source code
1 : // Copyright (C) 2009 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.pgm; 16 : 17 : import static java.util.stream.Collectors.joining; 18 : 19 : import com.google.common.base.Joiner; 20 : import com.google.common.collect.ImmutableList; 21 : import com.google.common.collect.Lists; 22 : import com.google.common.collect.Sets; 23 : import com.google.gerrit.common.IoUtil; 24 : import com.google.gerrit.common.PageLinks; 25 : import com.google.gerrit.common.PluginData; 26 : import com.google.gerrit.index.SchemaDefinitions; 27 : import com.google.gerrit.index.project.ProjectSchemaDefinitions; 28 : import com.google.gerrit.pgm.init.BaseInit; 29 : import com.google.gerrit.pgm.init.Browser; 30 : import com.google.gerrit.pgm.init.InitPlugins; 31 : import com.google.gerrit.pgm.init.api.ConsoleUI; 32 : import com.google.gerrit.pgm.util.ErrorLogFile; 33 : import com.google.gerrit.server.config.GerritServerConfigModule; 34 : import com.google.gerrit.server.config.SitePath; 35 : import com.google.gerrit.server.index.GerritIndexStatus; 36 : import com.google.gerrit.server.index.account.AccountSchemaDefinitions; 37 : import com.google.gerrit.server.index.change.ChangeSchemaDefinitions; 38 : import com.google.gerrit.server.index.group.GroupSchemaDefinitions; 39 : import com.google.gerrit.server.ioutil.HostPlatform; 40 : import com.google.gerrit.server.securestore.SecureStoreClassName; 41 : import com.google.gerrit.server.util.ReplicaUtil; 42 : import com.google.inject.AbstractModule; 43 : import com.google.inject.Guice; 44 : import com.google.inject.Inject; 45 : import com.google.inject.Module; 46 : import com.google.inject.util.Providers; 47 : import java.io.IOException; 48 : import java.nio.file.Path; 49 : import java.util.ArrayList; 50 : import java.util.Collections; 51 : import java.util.List; 52 : import java.util.Set; 53 : import org.kohsuke.args4j.Option; 54 : 55 : /** Initialize a new Gerrit installation. */ 56 : public class Init extends BaseInit { 57 : @Option( 58 : name = "--batch", 59 : aliases = {"-b"}, 60 : usage = "Batch mode; skip interactive prompting") 61 : private boolean batchMode; 62 : 63 : @Option(name = "--delete-caches", usage = "Delete all persistent caches without asking") 64 : private boolean deleteCaches; 65 : 66 : @Option(name = "--no-auto-start", usage = "Don't automatically start daemon after init") 67 : private boolean noAutoStart; 68 : 69 : @Option(name = "--skip-plugins", usage = "Don't install plugins") 70 : private boolean skipPlugins; 71 : 72 : @Option(name = "--list-plugins", usage = "List available plugins") 73 : private boolean listPlugins; 74 : 75 : @Option(name = "--install-plugin", usage = "Install given plugin without asking") 76 : private List<String> installPlugins; 77 : 78 : @Option(name = "--install-all-plugins", usage = "Install all plugins from war without asking") 79 : private boolean installAllPlugins; 80 : 81 : @Option( 82 : name = "--secure-store-lib", 83 : usage = "Path to jar providing SecureStore implementation class") 84 : private String secureStoreLib; 85 : 86 : @Option(name = "--dev", usage = "Setup site with default options suitable for developers") 87 : private boolean dev; 88 : 89 : @Option(name = "--skip-all-downloads", usage = "Don't download libraries") 90 : private boolean skipAllDownloads; 91 : 92 : @Option(name = "--skip-download", usage = "Don't download given library") 93 : private List<String> skippedDownloads; 94 : 95 15 : @Option(name = "--reindex-threads", usage = "Number of threads to use for reindex after init") 96 : private int reindexThreads = 1; 97 : 98 : @Inject Browser browser; 99 : 100 : private GerritIndexStatus indexStatus; 101 : 102 : public Init() { 103 15 : super(new WarDistribution(), null); 104 15 : } 105 : 106 : public Init(Path sitePath) { 107 0 : super(sitePath, true, new WarDistribution(), null); 108 0 : batchMode = true; 109 0 : noAutoStart = true; 110 0 : } 111 : 112 : @Override 113 : protected boolean beforeInit(SiteInit init) throws Exception { 114 15 : indexStatus = new GerritIndexStatus(init.site); 115 15 : ErrorLogFile.errorOnlyConsole(); 116 : 117 15 : if (!skipPlugins) { 118 1 : final List<PluginData> plugins = 119 1 : InitPlugins.listPluginsAndRemoveTempFiles(init.site, pluginsDistribution); 120 1 : ConsoleUI ui = ConsoleUI.getInstance(false); 121 1 : if (installAllPlugins && !nullOrEmpty(installPlugins)) { 122 0 : ui.message("Cannot use --install-plugin together with --install-all-plugins.\n"); 123 0 : return true; 124 : } 125 1 : verifyInstallPluginList(ui, plugins); 126 1 : if (listPlugins) { 127 0 : if (!plugins.isEmpty()) { 128 0 : ui.message("Available plugins:\n"); 129 0 : for (PluginData plugin : plugins) { 130 0 : ui.message(" * %s version %s\n", plugin.name, plugin.version); 131 0 : } 132 : } else { 133 0 : ui.message("No plugins found.\n"); 134 : } 135 0 : return true; 136 : } 137 : } 138 15 : return false; 139 : } 140 : 141 : @Override 142 : protected void afterInit(SiteRun run) throws Exception { 143 15 : List<SchemaDefinitions<?>> schemaDefs = 144 15 : ImmutableList.of( 145 : AccountSchemaDefinitions.INSTANCE, 146 : ChangeSchemaDefinitions.INSTANCE, 147 : GroupSchemaDefinitions.INSTANCE, 148 : ProjectSchemaDefinitions.INSTANCE); 149 15 : List<Module> modules = new ArrayList<>(); 150 15 : modules.add( 151 15 : new AbstractModule() { 152 : @Override 153 : protected void configure() { 154 15 : bind(Path.class).annotatedWith(SitePath.class).toInstance(getSitePath()); 155 15 : bind(Browser.class); 156 15 : bind(String.class) 157 15 : .annotatedWith(SecureStoreClassName.class) 158 15 : .toProvider(Providers.of(getConfiguredSecureStoreClass())); 159 15 : } 160 : }); 161 15 : modules.add(new GerritServerConfigModule()); 162 15 : Guice.createInjector(modules).injectMembers(this); 163 15 : if (!ReplicaUtil.isReplica(run.flags.cfg)) { 164 15 : List<String> indicesToReindex = new ArrayList<>(); 165 15 : for (SchemaDefinitions<?> schemaDef : schemaDefs) { 166 15 : if (!indexStatus.exists(schemaDef.getName())) { 167 15 : indicesToReindex.add(schemaDef.getName()); 168 : } 169 15 : } 170 15 : reindex(indicesToReindex, run.flags.isNew); 171 : } 172 15 : start(run); 173 15 : } 174 : 175 : @Override 176 : protected List<String> getInstallPlugins() { 177 15 : return installPlugins; 178 : } 179 : 180 : @Override 181 : protected boolean installAllPlugins() { 182 15 : return installAllPlugins; 183 : } 184 : 185 : @Override 186 : protected ConsoleUI getConsoleUI() { 187 15 : return ConsoleUI.getInstance(batchMode); 188 : } 189 : 190 : @Override 191 : protected boolean getAutoStart() { 192 15 : return !noAutoStart; 193 : } 194 : 195 : @Override 196 : protected boolean getDeleteCaches() { 197 15 : return deleteCaches; 198 : } 199 : 200 : @Override 201 : protected boolean skipPlugins() { 202 15 : return skipPlugins; 203 : } 204 : 205 : @Override 206 : protected boolean isDev() { 207 15 : return dev; 208 : } 209 : 210 : @Override 211 : protected boolean skipAllDownloads() { 212 15 : return skipAllDownloads; 213 : } 214 : 215 : @Override 216 : protected List<String> getSkippedDownloads() { 217 15 : return skippedDownloads != null ? skippedDownloads : Collections.emptyList(); 218 : } 219 : 220 : @Override 221 : protected String getSecureStoreLib() { 222 15 : return secureStoreLib; 223 : } 224 : 225 : void start(SiteRun run) throws Exception { 226 15 : if (run.flags.autoStart) { 227 0 : if (HostPlatform.isWin32()) { 228 0 : System.err.println("Automatic startup not supported on Win32."); 229 : } else { 230 0 : startDaemon(run); 231 0 : if (!run.ui.isBatch()) { 232 0 : browser.open(PageLinks.ADMIN_PROJECTS); 233 : } 234 : } 235 : } 236 15 : } 237 : 238 : void startDaemon(SiteRun run) { 239 0 : String[] argv = {run.site.gerrit_sh.toAbsolutePath().toString(), "start"}; 240 : Process proc; 241 : try { 242 0 : System.err.println("Executing " + argv[0] + " " + argv[1]); 243 0 : proc = Runtime.getRuntime().exec(argv); 244 0 : } catch (IOException e) { 245 0 : System.err.println("error: cannot start Gerrit: " + e.getMessage()); 246 0 : return; 247 0 : } 248 : 249 : try { 250 0 : proc.getOutputStream().close(); 251 0 : } catch (IOException e) { 252 : // Ignored 253 0 : } 254 : 255 0 : IoUtil.copyWithThread(proc.getInputStream(), System.err); 256 0 : IoUtil.copyWithThread(proc.getErrorStream(), System.err); 257 : 258 : for (; ; ) { 259 : try { 260 0 : int rc = proc.waitFor(); 261 0 : if (rc != 0) { 262 0 : System.err.println("error: cannot start Gerrit: exit status " + rc); 263 : } 264 0 : break; 265 0 : } catch (InterruptedException e) { 266 : // retry 267 0 : } 268 : } 269 0 : } 270 : 271 : private void verifyInstallPluginList(ConsoleUI ui, List<PluginData> plugins) { 272 1 : if (nullOrEmpty(installPlugins)) { 273 1 : return; 274 : } 275 0 : Set<String> missing = Sets.newHashSet(installPlugins); 276 0 : plugins.stream().forEach(p -> missing.remove(p.name)); 277 0 : if (!missing.isEmpty()) { 278 0 : ui.message("Cannot find plugin(s): %s\n", Joiner.on(", ").join(missing)); 279 0 : listPlugins = true; 280 : } 281 0 : } 282 : 283 : private void reindex(List<String> indices, boolean isNewSite) throws Exception { 284 15 : if (indices.isEmpty()) { 285 1 : return; 286 : } 287 15 : List<String> reindexArgs = 288 15 : Lists.newArrayList( 289 15 : "--site-path", getSitePath().toString(), "--threads", Integer.toString(reindexThreads)); 290 15 : for (String index : indices) { 291 15 : reindexArgs.add("--index"); 292 15 : reindexArgs.add(index); 293 15 : } 294 15 : if (isNewSite) { 295 0 : reindexArgs.add("--disable-cache-stats"); 296 : } 297 : 298 15 : getConsoleUI() 299 15 : .message(String.format("Init complete, reindexing %s with:", String.join(",", indices))); 300 15 : getConsoleUI().message(" reindex " + reindexArgs.stream().collect(joining(" "))); 301 15 : Reindex reindexPgm = new Reindex(); 302 15 : reindexPgm.main(reindexArgs.stream().toArray(String[]::new)); 303 15 : } 304 : 305 : private static boolean nullOrEmpty(List<?> list) { 306 1 : return list == null || list.isEmpty(); 307 : } 308 : }