summaryrefslogtreecommitdiffstats
path: root/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/gerrit/pgm/init/api/ConsoleUI.java')
-rw-r--r--java/com/google/gerrit/pgm/init/api/ConsoleUI.java278
1 files changed, 278 insertions, 0 deletions
diff --git a/java/com/google/gerrit/pgm/init/api/ConsoleUI.java b/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
new file mode 100644
index 0000000000..444f64fe7a
--- /dev/null
+++ b/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
@@ -0,0 +1,278 @@
+// 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.api;
+
+import com.google.gerrit.common.Die;
+import java.io.Console;
+import java.util.EnumSet;
+import java.util.Set;
+
+/** Console based interaction with the invoking user. */
+public abstract class ConsoleUI {
+ /** Get a UI instance, assuming interactive mode. */
+ public static ConsoleUI getInstance() {
+ return getInstance(false);
+ }
+
+ /** Get a UI instance, possibly forcing batch mode. */
+ public static ConsoleUI getInstance(boolean batchMode) {
+ Console console = batchMode ? null : System.console();
+ return console != null ? new Interactive(console) : new Batch();
+ }
+
+ /** Constructs an exception indicating the user aborted the operation. */
+ protected static Die abort() {
+ return new Die("aborted by user");
+ }
+
+ /** @return true if this is a batch UI that has no user interaction. */
+ public abstract boolean isBatch();
+
+ /** Display a header message before a series of prompts. */
+ public abstract void header(String fmt, Object... args);
+
+ /** Display a message. */
+ public abstract void message(String fmt, Object... args);
+
+ /** Request the user to answer a yes/no question. */
+ public abstract boolean yesno(Boolean def, String fmt, Object... args);
+
+ /** Prints a message asking the user to let us know when its safe to continue. */
+ public abstract void waitForUser();
+
+ /** Prompt the user for a string, suggesting a default, and returning choice. */
+ public abstract String readString(String def, String fmt, Object... args);
+
+ /** Prompt the user to make a choice from an allowed list of values. */
+ public abstract String readString(
+ String def, Set<String> allowedValues, String fmt, Object... args);
+
+ /** Prompt the user for an integer value, suggesting a default. */
+ public int readInt(int def, String fmt, Object... args) {
+ for (; ; ) {
+ String p = readString(String.valueOf(def), fmt, args);
+ try {
+ return Integer.parseInt(p.trim(), 10);
+ } catch (NumberFormatException e) {
+ System.err.println("error: Invalid integer format: " + p.trim());
+ }
+ }
+ }
+
+ /** Prompt the user for a password, returning the string; null if blank. */
+ public abstract String password(String fmt, Object... args);
+
+ /** Display an error message on the system stderr. */
+ public void error(String format, Object... args) {
+ System.err.println(String.format(format, args));
+ System.err.flush();
+ }
+
+ /** Prompt the user to make a choice from an enumeration's values. */
+ public abstract <T extends Enum<?>, A extends EnumSet<? extends T>> T readEnum(
+ T def, A options, String fmt, Object... args);
+
+ private static class Interactive extends ConsoleUI {
+ private final Console console;
+
+ Interactive(Console console) {
+ this.console = console;
+ }
+
+ @Override
+ public boolean isBatch() {
+ return false;
+ }
+
+ @Override
+ public boolean yesno(Boolean def, String fmt, Object... args) {
+ final String prompt = String.format(fmt, args);
+ for (; ; ) {
+ String y = "y";
+ String n = "n";
+ if (def != null) {
+ if (def) {
+ y = "Y";
+ } else {
+ n = "N";
+ }
+ }
+
+ String yn = console.readLine("%-30s [%s/%s]? ", prompt, y, n);
+ if (yn == null) {
+ throw abort();
+ }
+ yn = yn.trim();
+ if (def != null && yn.isEmpty()) {
+ return def;
+ }
+ if (yn.equalsIgnoreCase("y") || yn.equalsIgnoreCase("yes")) {
+ return true;
+ }
+ if (yn.equalsIgnoreCase("n") || yn.equalsIgnoreCase("no")) {
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public void waitForUser() {
+ if (console.readLine("Press enter to continue ") == null) {
+ throw abort();
+ }
+ }
+
+ @Override
+ public String readString(String def, String fmt, Object... args) {
+ final String prompt = String.format(fmt, args);
+ String r;
+ if (def != null) {
+ r = console.readLine("%-30s [%s]: ", prompt, def);
+ } else {
+ r = console.readLine("%-30s : ", prompt);
+ }
+ if (r == null) {
+ throw abort();
+ }
+ r = r.trim();
+ if (r.isEmpty()) {
+ return def;
+ }
+ return r;
+ }
+
+ @Override
+ public String readString(String def, Set<String> allowedValues, String fmt, Object... args) {
+ for (; ; ) {
+ String r = readString(def, fmt, args);
+ if (allowedValues.contains(r.toLowerCase())) {
+ return r.toLowerCase();
+ }
+ if (!"?".equals(r)) {
+ console.printf("error: '%s' is not a valid choice\n", r);
+ }
+ console.printf(" Supported options are:\n");
+ for (String v : allowedValues) {
+ console.printf(" %s\n", v.toLowerCase());
+ }
+ }
+ }
+
+ @Override
+ public String password(String fmt, Object... args) {
+ final String prompt = String.format(fmt, args);
+ for (; ; ) {
+ final char[] a1 = console.readPassword("%-30s : ", prompt);
+ if (a1 == null) {
+ throw abort();
+ }
+
+ final char[] a2 = console.readPassword("%30s : ", "confirm password");
+ if (a2 == null) {
+ throw abort();
+ }
+
+ final String s1 = new String(a1);
+ final String s2 = new String(a2);
+ if (!s1.equals(s2)) {
+ console.printf("error: Passwords did not match; try again\n");
+ continue;
+ }
+ return !s1.isEmpty() ? s1 : null;
+ }
+ }
+
+ @Override
+ public <T extends Enum<?>, A extends EnumSet<? extends T>> T readEnum(
+ T def, A options, String fmt, Object... args) {
+ final String prompt = String.format(fmt, args);
+ for (; ; ) {
+ String r = console.readLine("%-30s [%s/?]: ", prompt, def.toString().toLowerCase());
+ if (r == null) {
+ throw abort();
+ }
+ r = r.trim();
+ if (r.isEmpty()) {
+ return def;
+ }
+ for (T e : options) {
+ if (e.toString().equalsIgnoreCase(r)) {
+ return e;
+ }
+ }
+ if (!"?".equals(r)) {
+ console.printf("error: '%s' is not a valid choice\n", r);
+ }
+ console.printf(" Supported options are:\n");
+ for (T e : options) {
+ console.printf(" %s\n", e.toString().toLowerCase());
+ }
+ }
+ }
+
+ @Override
+ public void header(String fmt, Object... args) {
+ fmt = fmt.replaceAll("\n", "\n*** ");
+ console.printf("\n*** " + fmt + "\n*** \n\n", args);
+ }
+
+ @Override
+ public void message(String fmt, Object... args) {
+ console.printf(fmt, args);
+ }
+ }
+
+ private static class Batch extends ConsoleUI {
+ @Override
+ public boolean isBatch() {
+ return true;
+ }
+
+ @Override
+ public boolean yesno(Boolean def, String fmt, Object... args) {
+ return def != null ? def : true;
+ }
+
+ @Override
+ public String readString(String def, String fmt, Object... args) {
+ return def;
+ }
+
+ @Override
+ public String readString(String def, Set<String> allowedValues, String fmt, Object... args) {
+ return def;
+ }
+
+ @Override
+ public void waitForUser() {}
+
+ @Override
+ public String password(String fmt, Object... args) {
+ return null;
+ }
+
+ @Override
+ public <T extends Enum<?>, A extends EnumSet<? extends T>> T readEnum(
+ T def, A options, String fmt, Object... args) {
+ return def;
+ }
+
+ @Override
+ public void header(String fmt, Object... args) {}
+
+ @Override
+ public void message(String fmt, Object... args) {}
+ }
+}