Skip to content

Commit bf8eec3

Browse files
committed
YARN-11506.The formatted yarn queue list is displayed on the command line
1 parent 3f5786e commit bf8eec3

File tree

4 files changed

+329
-27
lines changed

4 files changed

+329
-27
lines changed

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,6 @@
175175
<groupId>org.jline</groupId>
176176
<artifactId>jline</artifactId>
177177
</dependency>
178-
179-
<dependency>
180-
<groupId>com.blinkfox</groupId>
181-
<artifactId>mini-table</artifactId>
182-
<version>1.0.0</version>
183-
</dependency>
184178
</dependencies>
185179

186180
<build>

hadoop-yarn-project/hadoop-yarn/hadoop-yarn-client/src/main/java/org/apache/hadoop/yarn/client/cli/QueueCLI.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
import java.nio.charset.Charset;
2424
import java.nio.charset.StandardCharsets;
2525
import java.text.DecimalFormat;
26+
import java.util.Arrays;
2627
import java.util.List;
2728
import java.util.Set;
2829

29-
import com.blinkfox.minitable.MiniTable;
3030
import org.apache.commons.cli.CommandLine;
3131
import org.apache.commons.cli.GnuParser;
3232
import org.apache.commons.cli.HelpFormatter;
@@ -37,6 +37,7 @@
3737
import org.apache.hadoop.util.ToolRunner;
3838
import org.apache.hadoop.yarn.api.records.NodeLabel;
3939
import org.apache.hadoop.yarn.api.records.QueueInfo;
40+
import org.apache.hadoop.yarn.client.util.FormattingCLIUtils;
4041
import org.apache.hadoop.yarn.exceptions.YarnException;
4142

4243
import org.apache.hadoop.classification.VisibleForTesting;
@@ -223,18 +224,20 @@ private void printQueueInfo(PrintWriter writer, QueueInfo queueInfo) {
223224
}
224225

225226
private void printQueueInfos(PrintWriter writer, List<QueueInfo> queueInfos) {
226-
MiniTable miniTable = new MiniTable(queueInfos.size() + " queues were found")
227-
.addHeaders("Queue Name", "Queue Path", "State", "Capacity",
227+
String titleString = queueInfos.size() + " queues were found";
228+
List<String> headerStrings = Arrays.asList("Queue Name", "Queue Path", "State", "Capacity",
228229
"Current Capacity", "Maximum Capacity", "Weight", "Maximum Parallel Apps");
230+
FormattingCLIUtils formattingCLIUtils = new FormattingCLIUtils(titleString)
231+
.addHeaders(headerStrings);
229232
DecimalFormat df = new DecimalFormat("#.00");
230233
for (QueueInfo queueInfo : queueInfos) {
231-
miniTable.addDatas(queueInfo.getQueueName(),queueInfo.getQueuePath()
232-
,queueInfo.getQueueState(),df.format(queueInfo.getCapacity() * 100) + "%"
233-
,df.format(queueInfo.getCurrentCapacity() * 100) + "%"
234-
,df.format(queueInfo.getMaximumCapacity() * 100) + "%"
235-
,df.format(queueInfo.getWeight())
236-
,queueInfo.getMaxParallelApps());
234+
formattingCLIUtils.addDatas(queueInfo.getQueueName(), queueInfo.getQueuePath(),
235+
queueInfo.getQueueState(), df.format(queueInfo.getCapacity() * 100) + "%",
236+
df.format(queueInfo.getCurrentCapacity() * 100) + "%",
237+
df.format(queueInfo.getMaximumCapacity() * 100) + "%",
238+
df.format(queueInfo.getWeight()),
239+
queueInfo.getMaxParallelApps());
237240
}
238-
writer.print(miniTable.render());
241+
writer.print(formattingCLIUtils.render());
239242
}
240243
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.yarn.client.util;
19+
20+
import java.util.ArrayList;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
/**
26+
* The main core class that generates the ASCII TABLE.
27+
*/
28+
public final class FormattingCLIUtils {
29+
/** Table title. */
30+
private String title;
31+
/** Last processed row type. */
32+
private TableRowType lastTableRowType;
33+
/** StringBuilder object used to concatenate strings. */
34+
private StringBuilder join;
35+
/** An ordered Map that holds each row of data. */
36+
private List<TableRow> tableRows;
37+
/** Maps the maximum length of each column. */
38+
private Map<Integer, Integer> maxColMap;
39+
40+
/**
41+
* Default empty constructor.
42+
*/
43+
public FormattingCLIUtils() {
44+
this.init();
45+
}
46+
47+
/**
48+
* Contains the title constructor.
49+
* @param title titleName
50+
*/
51+
public FormattingCLIUtils(String title) {
52+
this.init();
53+
this.title = title;
54+
}
55+
56+
/**
57+
* Initialize the data.
58+
*/
59+
private void init() {
60+
this.join = new StringBuilder();
61+
this.tableRows = new ArrayList<>();
62+
this.maxColMap = new HashMap<>();
63+
}
64+
65+
/**
66+
* Adds elements from the collection to the header data in the table.
67+
* @param headers Header data
68+
* @return FormattingCLIUtils object
69+
*/
70+
public FormattingCLIUtils addHeaders(List<?> headers) {
71+
return this.appendRows(TableRowType.HEADER, headers.toArray());
72+
}
73+
74+
/**
75+
* Adds header data to the table.
76+
* @param objects Header data
77+
* @return FormattingCLIUtils object
78+
*/
79+
public FormattingCLIUtils addHeaders(Object... objects) {
80+
return this.appendRows(TableRowType.HEADER, objects);
81+
}
82+
83+
/**
84+
* Adds a row of normal data to the table.
85+
* @param datas Common row data
86+
* @return FormattingCLIUtils object
87+
*/
88+
public FormattingCLIUtils addDatas(List<?> datas) {
89+
return this.appendRows(TableRowType.DATA, datas.toArray());
90+
}
91+
92+
/**
93+
* Adds a row of normal data to the table.
94+
* @param objects Common row data
95+
* @return FormattingCLIUtils object
96+
*/
97+
public FormattingCLIUtils addDatas(Object... objects) {
98+
return this.appendRows(TableRowType.DATA, objects);
99+
}
100+
101+
/**
102+
* Adds the middle row of data to the table.
103+
* @param tableRowType TableRowType
104+
* @param objects Table row data
105+
* @return FormattingCLIUtils object
106+
*/
107+
private FormattingCLIUtils appendRows(TableRowType tableRowType, Object... objects) {
108+
if (objects != null && objects.length > 0) {
109+
int len = objects.length;
110+
if (this.maxColMap.size() > len) {
111+
throw new IllegalArgumentException("The number of columns that inserted a row " +
112+
"of data into the table is different from the number of previous columns, check!");
113+
}
114+
List<String> datas = new ArrayList<>();
115+
for (int i = 0; i < len; i++) {
116+
Object o = objects[i];
117+
String value = o == null ? "null" : o.toString();
118+
datas.add(value);
119+
Integer maxColSize = this.maxColMap.get(i);
120+
if (maxColSize == null) {
121+
this.maxColMap.put(i, value.length());
122+
continue;
123+
}
124+
if (value.length() > maxColSize) {
125+
this.maxColMap.put(i, value.length());
126+
}
127+
}
128+
this.tableRows.add(new TableRow(tableRowType, datas));
129+
}
130+
return this;
131+
}
132+
133+
/**
134+
* Builds the string for the row of the table title.
135+
*/
136+
private void buildTitle() {
137+
if (this.title != null) {
138+
int maxTitleSize = 0;
139+
for (Integer maxColSize : this.maxColMap.values()) {
140+
maxTitleSize += maxColSize;
141+
}
142+
maxTitleSize += 3 * (this.maxColMap.size() - 1);
143+
if (this.title.length() > maxTitleSize) {
144+
this.title = this.title.substring(0, maxTitleSize);
145+
}
146+
this.join.append("+");
147+
for (int i = 0; i < maxTitleSize + 2; i++) {
148+
this.join.append("-");
149+
}
150+
this.join.append("+\n")
151+
.append("|")
152+
.append(StrUtils.center(this.title, maxTitleSize + 2, ' '))
153+
.append("|\n");
154+
this.lastTableRowType = TableRowType.TITLE;
155+
}
156+
}
157+
158+
/**
159+
* Build the table, first build the title, and then walk through each row of data to build.
160+
*/
161+
private void buildTable() {
162+
this.buildTitle();
163+
for (int i = 0, len = this.tableRows.size(); i < len; i++) {
164+
List<String> datas = this.tableRows.get(i).datas;
165+
switch (this.tableRows.get(i).tableRowType) {
166+
case HEADER:
167+
if (this.lastTableRowType != TableRowType.HEADER) {
168+
this.buildRowBorder(datas);
169+
}
170+
this.buildRowData(datas);
171+
this.buildRowBorder(datas);
172+
break;
173+
case DATA:
174+
this.buildRowData(datas);
175+
if (i == len - 1) {
176+
this.buildRowBorder(datas);
177+
}
178+
break;
179+
default:
180+
break;
181+
}
182+
}
183+
}
184+
185+
/**
186+
* Method to build a border row.
187+
* @param datas dataLine
188+
*/
189+
private void buildRowBorder(List<String> datas) {
190+
this.join.append("+");
191+
for (int i = 0, len = datas.size(); i < len; i++) {
192+
for (int j = 0; j < this.maxColMap.get(i) + 2; j++) {
193+
this.join.append("-");
194+
}
195+
this.join.append("+");
196+
}
197+
this.join.append("\n");
198+
}
199+
200+
/**
201+
* A way to build rows of data.
202+
* @param datas dataLine
203+
*/
204+
private void buildRowData(List<String> datas) {
205+
this.join.append("|");
206+
for (int i = 0, len = datas.size(); i < len; i++) {
207+
this.join.append(StrUtils.center(datas.get(i), this.maxColMap.get(i) + 2, ' '))
208+
.append("|");
209+
}
210+
this.join.append("\n");
211+
}
212+
213+
/**
214+
* Rendering is born as a result.
215+
* @return ASCII string of Table
216+
*/
217+
public String render() {
218+
this.buildTable();
219+
return this.join.toString();
220+
}
221+
222+
/**
223+
* The type of each table row and the entity class of the data.
224+
*/
225+
private static class TableRow {
226+
private TableRowType tableRowType;
227+
private List<String> datas;
228+
TableRow(TableRowType tableRowType, List<String> datas) {
229+
this.tableRowType = tableRowType;
230+
this.datas = datas;
231+
}
232+
}
233+
234+
/**
235+
* An enumeration class that distinguishes between table headers and normal table data.
236+
*/
237+
private enum TableRowType {
238+
TITLE, HEADER, DATA
239+
}
240+
241+
/**
242+
* String utility class.
243+
*/
244+
private static final class StrUtils {
245+
/**
246+
* Puts a string in the middle of a given size.
247+
* @param str
248+
* @param size
249+
* @param padChar
250+
* @return
251+
*/
252+
private static String center(String str, int size, char padChar) {
253+
if (str != null && size > 0) {
254+
int strLen = str.length();
255+
int pads = size - strLen;
256+
if (pads > 0) {
257+
str = leftPad(str, strLen + pads / 2, padChar);
258+
str = rightPad(str, size, padChar);
259+
}
260+
}
261+
return str;
262+
}
263+
264+
/**
265+
* Left-fill the given string and size.
266+
* @param str String
267+
* @param size totalSize
268+
* @param padChar Fill character
269+
* @return String result
270+
*/
271+
private static String leftPad(final String str, int size, char padChar) {
272+
int pads = size - str.length();
273+
return pads <= 0 ? str : repeat(padChar, pads).concat(str);
274+
}
275+
276+
/**
277+
* Right-fill the given string and size.
278+
* @param str String
279+
* @param size totalSize
280+
* @param padChar Fill character
281+
* @return String result
282+
*/
283+
private static String rightPad(final String str, int size, char padChar) {
284+
int pads = size - str.length();
285+
return pads <= 0 ? str : str.concat(repeat(padChar, pads));
286+
}
287+
288+
/**
289+
* Re-fill characters as strings.
290+
* @param ch String
291+
* @param repeat Number of repeats
292+
* @return String
293+
*/
294+
private static String repeat(char ch, int repeat) {
295+
char[] buf = new char[repeat];
296+
for (int i = repeat - 1; i >= 0; i--) {
297+
buf[i] = ch;
298+
}
299+
return new String(buf);
300+
}
301+
}
302+
}

0 commit comments

Comments
 (0)