Merge changes If7f8c086,I42a0032f,Id811f144

* changes:
  Bind PluginUser.Factory in PluginModule
  Expose the GerritRuntime to ServerPlugin
  Add GerritRuntime enum to describe the current running environment
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index 5699e3f..6e5424c 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -29,6 +29,7 @@
 import com.google.gerrit.lucene.LuceneIndexModule;
 import com.google.gerrit.pgm.Daemon;
 import com.google.gerrit.pgm.Init;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePath;
 import com.google.gerrit.server.git.receive.AsyncReceiveCommits;
@@ -44,6 +45,7 @@
 import com.google.gerrit.testing.NoteDbMode;
 import com.google.gerrit.testing.SshMode;
 import com.google.gerrit.testing.TempFileUtil;
+import com.google.inject.AbstractModule;
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.Module;
@@ -352,7 +354,13 @@
     daemon.setDatabaseForTesting(
         ImmutableList.<Module>of(
             new InMemoryTestingDatabaseModule(
-                cfg, site, inMemoryRepoManager, inMemoryDatabaseInstance)));
+                cfg, site, inMemoryRepoManager, inMemoryDatabaseInstance),
+            new AbstractModule() {
+              @Override
+              protected void configure() {
+                bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
+              }
+            }));
     daemon.start();
     return new GerritServer(desc, null, createTestInjector(daemon), daemon, null);
   }
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index 730f219..53e43a2 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -66,6 +66,7 @@
 import com.google.gerrit.server.config.GerritGlobalModule;
 import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SysExecutorModule;
 import com.google.gerrit.server.events.EventBroker;
@@ -371,6 +372,11 @@
     manager.stop();
   }
 
+  @Override
+  protected GerritRuntime getGerritRuntime() {
+    return GerritRuntime.DAEMON;
+  }
+
   private boolean sshdOff() {
     return new SshAddressesModule().getListenAddresses(config).isEmpty();
   }
diff --git a/java/com/google/gerrit/pgm/util/SiteProgram.java b/java/com/google/gerrit/pgm/util/SiteProgram.java
index b59e085..45d2a5d 100644
--- a/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.metrics.DisabledMetricMaker;
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerConfigModule;
 import com.google.gerrit.server.config.SitePath;
@@ -155,6 +156,13 @@
         });
     Module configModule = new GerritServerConfigModule();
     modules.add(configModule);
+    modules.add(
+        new AbstractModule() {
+          @Override
+          protected void configure() {
+            bind(GerritRuntime.class).toInstance(getGerritRuntime());
+          }
+        });
     Injector cfgInjector = Guice.createInjector(sitePathModule, configModule);
     Config cfg = cfgInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
     String dbType;
@@ -219,6 +227,11 @@
     }
   }
 
+  /** Returns the current runtime used by this Gerrit program. */
+  protected GerritRuntime getGerritRuntime() {
+    return GerritRuntime.BATCH;
+  }
+
   protected final String getConfiguredSecureStoreClass() {
     return getSecureStoreClassName(sitePath);
   }
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index cb0cdf9..57255a3 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -76,7 +76,6 @@
 import com.google.gerrit.server.CmdLineParserModule;
 import com.google.gerrit.server.CreateGroupPermissionSyncer;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.PluginUser;
 import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.account.AccountCacheImpl;
 import com.google.gerrit.server.account.AccountControl;
@@ -262,7 +261,6 @@
     factory(MergedSender.Factory.class);
     factory(MergeUtil.Factory.class);
     factory(PatchScriptFactory.Factory.class);
-    factory(PluginUser.Factory.class);
     factory(ProjectState.Factory.class);
     factory(RegisterNewEmailSender.Factory.class);
     factory(ReplacePatchSetSender.Factory.class);
diff --git a/java/com/google/gerrit/server/config/GerritRuntime.java b/java/com/google/gerrit/server/config/GerritRuntime.java
new file mode 100644
index 0000000..ac4cede
--- /dev/null
+++ b/java/com/google/gerrit/server/config/GerritRuntime.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 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.server.config;
+
+/** Represents the current runtime environment in which Gerrit is running. */
+public enum GerritRuntime {
+  /** Gerrit is running as a server, with all its features. */
+  DAEMON,
+
+  /** Gerrit is running from the command line, in batch mode (reindex, ...). */
+  BATCH
+}
diff --git a/java/com/google/gerrit/server/plugins/JarPluginProvider.java b/java/com/google/gerrit/server/plugins/JarPluginProvider.java
index 87c3df7..fa458f9 100644
--- a/java/com/google/gerrit/server/plugins/JarPluginProvider.java
+++ b/java/com/google/gerrit/server/plugins/JarPluginProvider.java
@@ -152,7 +152,8 @@
               jarScanner,
               description.dataDir,
               pluginLoader,
-              pluginConfig.getString("metricsPrefix", null));
+              pluginConfig.getString("metricsPrefix", null),
+              description.gerritRuntime);
       plugin.setCleanupHandle(new CleanupHandle(tmp, jarFile));
       keep = true;
       return plugin;
diff --git a/java/com/google/gerrit/server/plugins/PluginLoader.java b/java/com/google/gerrit/server/plugins/PluginLoader.java
index 07ffbdc..53ddc9f 100644
--- a/java/com/google/gerrit/server/plugins/PluginLoader.java
+++ b/java/com/google/gerrit/server/plugins/PluginLoader.java
@@ -33,6 +33,7 @@
 import com.google.gerrit.server.cache.PersistentCacheFactory;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.config.ConfigUtil;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.gerrit.server.plugins.ServerPluginProvider.PluginDescription;
@@ -89,6 +90,7 @@
   private final PersistentCacheFactory persistentCacheFactory;
   private final boolean remoteAdmin;
   private final UniversalServerPluginProvider serverPluginFactory;
+  private final GerritRuntime gerritRuntime;
 
   @Inject
   public PluginLoader(
@@ -100,7 +102,8 @@
       @GerritServerConfig Config cfg,
       @CanonicalWebUrl Provider<String> provider,
       PersistentCacheFactory cacheFactory,
-      UniversalServerPluginProvider pluginFactory) {
+      UniversalServerPluginProvider pluginFactory,
+      GerritRuntime gerritRuntime) {
     pluginsDir = sitePaths.plugins_dir;
     dataDir = sitePaths.data_dir;
     tempDir = sitePaths.tmp_dir;
@@ -113,6 +116,7 @@
     serverPluginFactory = pluginFactory;
 
     remoteAdmin = cfg.getBoolean("plugins", null, "allowRemoteAdmin", false);
+    this.gerritRuntime = gerritRuntime;
 
     long checkFrequency =
         ConfigUtil.getTimeUnit(
@@ -611,7 +615,8 @@
         new PluginDescription(
             pluginUserFactory.create(name),
             getPluginCanonicalWebUrl(name),
-            getPluginDataDir(name)));
+            getPluginDataDir(name),
+            gerritRuntime));
   }
 
   // Only one active plugin per plugin name can exist for each plugin name.
diff --git a/java/com/google/gerrit/server/plugins/PluginModule.java b/java/com/google/gerrit/server/plugins/PluginModule.java
index db18470..6bc37bd 100644
--- a/java/com/google/gerrit/server/plugins/PluginModule.java
+++ b/java/com/google/gerrit/server/plugins/PluginModule.java
@@ -17,10 +17,15 @@
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.systemstatus.ServerInformation;
 import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.config.GerritRuntime;
 
 public class PluginModule extends LifecycleModule {
   @Override
   protected void configure() {
+    requireBinding(GerritRuntime.class);
+
+    factory(PluginUser.Factory.class);
     bind(ServerInformationImpl.class);
     bind(ServerInformation.class).to(ServerInformationImpl.class);
 
diff --git a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
index 8e162ba..cad0e1e 100644
--- a/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
+++ b/java/com/google/gerrit/server/plugins/PluginRestApiModule.java
@@ -18,10 +18,13 @@
 
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.restapi.RestApiModule;
+import com.google.gerrit.server.PluginUser;
+import com.google.inject.Key;
 
 public class PluginRestApiModule extends RestApiModule {
   @Override
   protected void configure() {
+    requireBinding(Key.get(PluginUser.Factory.class));
     bind(PluginsCollection.class);
     DynamicMap.mapOf(binder(), PLUGIN_KIND);
     put(PLUGIN_KIND).to(InstallPlugin.Overwrite.class);
diff --git a/java/com/google/gerrit/server/plugins/ServerPlugin.java b/java/com/google/gerrit/server/plugins/ServerPlugin.java
index b46ecf5..3e6589c 100644
--- a/java/com/google/gerrit/server/plugins/ServerPlugin.java
+++ b/java/com/google/gerrit/server/plugins/ServerPlugin.java
@@ -21,6 +21,7 @@
 import com.google.gerrit.extensions.registration.ReloadableRegistrationHandle;
 import com.google.gerrit.lifecycle.LifecycleManager;
 import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.util.RequestContext;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
@@ -44,6 +45,7 @@
   private final String pluginCanonicalWebUrl;
   private final ClassLoader classLoader;
   private final String metricsPrefix;
+  private final GerritRuntime gerritRuntime;
   protected Class<? extends Module> sysModule;
   protected Class<? extends Module> sshModule;
   protected Class<? extends Module> httpModule;
@@ -63,7 +65,8 @@
       PluginContentScanner scanner,
       Path dataDir,
       ClassLoader classLoader,
-      String metricsPrefix)
+      String metricsPrefix,
+      GerritRuntime gerritRuntime)
       throws InvalidPluginException {
     super(
         name,
@@ -77,33 +80,12 @@
     this.classLoader = classLoader;
     this.manifest = scanner == null ? null : getPluginManifest(scanner);
     this.metricsPrefix = metricsPrefix;
+    this.gerritRuntime = gerritRuntime;
     if (manifest != null) {
       loadGuiceModules(manifest, classLoader);
     }
   }
 
-  public ServerPlugin(
-      String name,
-      String pluginCanonicalWebUrl,
-      PluginUser pluginUser,
-      Path srcJar,
-      FileSnapshot snapshot,
-      PluginContentScanner scanner,
-      Path dataDir,
-      ClassLoader classLoader)
-      throws InvalidPluginException {
-    this(
-        name,
-        pluginCanonicalWebUrl,
-        pluginUser,
-        srcJar,
-        snapshot,
-        scanner,
-        dataDir,
-        classLoader,
-        null);
-  }
-
   private void loadGuiceModules(Manifest manifest, ClassLoader classLoader)
       throws InvalidPluginException {
     Attributes main = manifest.getMainAttributes();
diff --git a/java/com/google/gerrit/server/plugins/ServerPluginProvider.java b/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
index 632f838..f2f64c2 100644
--- a/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
+++ b/java/com/google/gerrit/server/plugins/ServerPluginProvider.java
@@ -16,6 +16,7 @@
 
 import com.google.gerrit.extensions.annotations.ExtensionPoint;
 import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.config.GerritRuntime;
 import java.nio.file.Path;
 import org.eclipse.jgit.internal.storage.file.FileSnapshot;
 
@@ -36,6 +37,7 @@
     public final PluginUser user;
     public final String canonicalUrl;
     public final Path dataDir;
+    final GerritRuntime gerritRuntime;
 
     /**
      * Creates a new PluginDescription for ServerPluginProvider.
@@ -43,11 +45,14 @@
      * @param user Gerrit user for interacting with plugins
      * @param canonicalUrl plugin root Web URL
      * @param dataDir directory for plugin data
+     * @param gerritRuntime current Gerrit runtime (daemon, batch, ...)
      */
-    public PluginDescription(PluginUser user, String canonicalUrl, Path dataDir) {
+    public PluginDescription(
+        PluginUser user, String canonicalUrl, Path dataDir, GerritRuntime gerritRuntime) {
       this.user = user;
       this.canonicalUrl = canonicalUrl;
       this.dataDir = dataDir;
+      this.gerritRuntime = gerritRuntime;
     }
   }
 
diff --git a/java/com/google/gerrit/server/plugins/TestServerPlugin.java b/java/com/google/gerrit/server/plugins/TestServerPlugin.java
index dbdc576..3751c3f 100644
--- a/java/com/google/gerrit/server/plugins/TestServerPlugin.java
+++ b/java/com/google/gerrit/server/plugins/TestServerPlugin.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.plugins;
 
 import com.google.gerrit.server.PluginUser;
+import com.google.gerrit.server.config.GerritRuntime;
 import java.nio.file.Path;
 
 public class TestServerPlugin extends ServerPlugin {
@@ -33,7 +34,17 @@
       String sshName,
       Path dataDir)
       throws InvalidPluginException {
-    super(name, pluginCanonicalWebUrl, user, null, null, null, dataDir, classloader);
+    super(
+        name,
+        pluginCanonicalWebUrl,
+        user,
+        null,
+        null,
+        null,
+        dataDir,
+        classloader,
+        null,
+        GerritRuntime.DAEMON);
     this.classLoader = classloader;
     this.sysName = sysName;
     this.httpName = httpName;
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index b472857..700eb83 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -32,6 +32,7 @@
 import com.google.gerrit.server.FanOutExecutor;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.GerritPersonIdentProvider;
+import com.google.gerrit.server.PluginUser;
 import com.google.gerrit.server.api.GerritApiModule;
 import com.google.gerrit.server.api.PluginApiModule;
 import com.google.gerrit.server.cache.h2.H2CacheModule;
@@ -48,6 +49,7 @@
 import com.google.gerrit.server.config.GerritGlobalModule;
 import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
+import com.google.gerrit.server.config.GerritRuntime;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerId;
 import com.google.gerrit.server.config.GerritServerIdProvider;
@@ -168,9 +170,11 @@
                 bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
               }
             });
+    bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
     bind(MetricMaker.class).to(DisabledMetricMaker.class);
     install(cfgInjector.getInstance(GerritGlobalModule.class));
     install(new GerritApiModule());
+    factory(PluginUser.Factory.class);
     install(new PluginApiModule());
     install(new DefaultPermissionBackendModule());
     install(new SearchingChangeCacheImpl.Module());