/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 gobblin.cli; import java.util.ArrayList; import java.util.List; import com.google.common.base.Preconditions; import com.google.common.primitives.Ints; /** * A format helper for CLI output. Unfortunately it only supports strings, so * values need to be converted previous to passing in. This is done in order to * support table-like formatting. * <p/> * It's recommended that this class is built using the inner {@link Builder} class. * * @author ahollenbach@nerdwallet.com */ public class CliTablePrinter { /** * Labels for each columns */ private List<String> labels; /** * A list of sprintf-style flag strings (corresponding to each column) */ private List<String> flags; /** * Overall indentation of a table */ private int indentation; /** * Number of spaces to place between columns */ private int delimiterWidth; /** * Table of data to print */ private List<List<String>> data; /** * The row format (generated by the constructor). */ private String rowFormat; public CliTablePrinter(List<String> labels, List<String> flags, int indentation, int delimiterWidth, List<List<String>> data) { Preconditions.checkArgument(data.size() > 0); Preconditions.checkArgument(data.get(0).size() > 0); if (labels != null) { Preconditions.checkArgument(data.get(0).size() == labels.size()); } if (flags != null) { Preconditions.checkArgument(data.get(0).size() == flags.size()); } this.labels = labels; this.flags = flags; this.indentation = indentation; this.delimiterWidth = delimiterWidth; this.data = data; this.rowFormat = getRowFormat(getColumnMaxWidths()); } /** * Used to build a {@link CliTablePrinter} object. */ public static final class Builder { private List<String> labels; private List<String> flags; private int indentation; private int delimiterWidth; private List<List<String>> data; public Builder() { // Set defaults this.delimiterWidth = 1; } public Builder labels(List<String> labels) { this.labels = labels; return this; } public Builder data(List<List<String>> data) { this.data = data; return this; } public Builder indentation(int indentation) { this.indentation = indentation; return this; } public Builder delimiterWidth(int delimiterWidth) { this.delimiterWidth = delimiterWidth; return this; } public Builder flags(List<String> flags) { this.flags = flags; return this; } public CliTablePrinter build() { return new CliTablePrinter(this.labels, this.flags, this.indentation, this.delimiterWidth, this.data); } } /** * Prints the table of data */ public void printTable() { if (this.labels != null) { System.out.printf(this.rowFormat, this.labels.toArray()); } for (List<String> row : this.data) { System.out.printf(this.rowFormat, row.toArray()); } } /** * A function for determining the max widths of columns, accounting for labels and data. * * @return An array of maximum widths for the strings in each column */ private List<Integer> getColumnMaxWidths() { int numCols = data.get(0).size(); int[] widths = new int[numCols]; if (this.labels != null) { for (int i=0; i<numCols; i++) { widths[i] = this.labels.get(i).length(); } } for (List<String> row : this.data) { for (int i=0;i<row.size(); i++) { if (row.get(i) == null) { widths[i] = Math.max(widths[i], 4); } else { widths[i] = Math.max(widths[i], row.get(i).length()); } } } return Ints.asList(widths); } /** * Generates a simple row format string given a set of widths * * @param widths A list of widths for each column in the table * @return A row format for each row in the table */ private String getRowFormat(List<Integer> widths) { StringBuilder rowFormat = new StringBuilder(spaces(this.indentation)); for (int i=0; i< widths.size(); i++) { rowFormat.append("%"); rowFormat.append(this.flags != null ? this.flags.get(i) : ""); rowFormat.append(widths.get(i).toString()); rowFormat.append("s"); rowFormat.append(spaces(this.delimiterWidth)); } rowFormat.append("\n"); return rowFormat.toString(); } private static String spaces(int numSpaces) { StringBuilder sb = new StringBuilder(); for (int i=0; i<numSpaces; i++) { sb.append(" "); } return sb.toString(); } }