Skip to content

Commit

Permalink
Render byte arrays in the CLI as a hex dump
Browse files Browse the repository at this point in the history
  • Loading branch information
nezihyigitbasi authored and electrum committed Oct 31, 2014
1 parent b640bc4 commit 84f6c56
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 1 deletion.
Expand Up @@ -13,6 +13,8 @@
*/
package com.facebook.presto.cli;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import org.fusesource.jansi.AnsiString;
Expand All @@ -25,13 +27,19 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.repeat;
import static com.google.common.collect.Iterables.partition;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.io.BaseEncoding.base16;
import static java.lang.Math.max;
import static java.lang.String.format;

public class AlignedTablePrinter
implements OutputPrinter
{
private static final Splitter LINE_SPLITTER = Splitter.on('\n');
private static final Splitter HEX_SPLITTER = Splitter.fixedLength(2);
private static final Joiner HEX_BYTE_JOINER = Joiner.on(' ');
private static final Joiner HEX_LINE_JOINER = Joiner.on('\n');

private final List<String> fieldNames;
private final Writer writer;
Expand Down Expand Up @@ -126,7 +134,45 @@ public void printRows(List<List<?>> rows, boolean complete)

static String formatValue(Object o)
{
return (o == null) ? "NULL" : o.toString();
if (o == null) {
return "NULL";
}

if (o instanceof byte[]) {
return formatHexDump((byte[]) o, 16);
}

return o.toString();
}

private static String formatHexDump(byte[] bytes, int bytesPerLine)
{
// hex dump: "616263"
String hexDump = base16().lowerCase().encode(bytes);

// hex pairs: ["61", "62", "63"]
Iterable<String> hexPairs = HEX_SPLITTER.split(hexDump);

// hex lines: [["61", "62", "63], [...]]
Iterable<List<String>> hexLines = partition(hexPairs, bytesPerLine);

// lines: ["61 62 63", ...]
Iterable<String> lines = transform(hexLines, joinerFunction(HEX_BYTE_JOINER));

// joined: "61 62 63\n..."
return HEX_LINE_JOINER.join(lines);
}

private static Function<Iterable<String>, String> joinerFunction(final Joiner joiner)
{
return new Function<Iterable<String>, String>()
{
@Override
public String apply(Iterable<String> iterable)
{
return joiner.join(iterable);
}
};
}

private static String center(String s, int maxWidth, int padding)
Expand Down
Expand Up @@ -19,6 +19,7 @@
import java.io.StringWriter;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
import static org.testng.Assert.assertEquals;

Expand Down Expand Up @@ -95,6 +96,34 @@ public void testAlignedPrintingNoRows()
assertEquals(writer.getBuffer().toString(), expected);
}

@Test
public void testAlignedPrintingHex()
throws Exception
{
StringWriter writer = new StringWriter();
List<String> fieldNames = ImmutableList.of("first", "binary", "last");
OutputPrinter printer = new AlignedTablePrinter(fieldNames, writer);

printer.printRows(rows(
row("hello", bytes("hello"), "world"),
row("a", bytes("some long text that is more than 16 bytes"), "b"),
row("cat", bytes(""), "dog")),
true);
printer.finish();

String expected = "" +
" first | binary | last \n" +
"-------+-------------------------------------------------+-------\n" +
" hello | 68 65 6c 6c 6f | world \n" +
" a | 73 6f 6d 65 20 6c 6f 6e 67 20 74 65 78 74 20 74+| b \n" +
" | 68 61 74 20 69 73 20 6d 6f 72 65 20 74 68 61 6e+| \n" +
" | 20 31 36 20 62 79 74 65 73 | \n" +
" cat | | dog \n" +
"(3 rows)\n";

assertEquals(writer.getBuffer().toString(), expected);
}

static List<?> row(Object... values)
{
return asList(values);
Expand All @@ -104,4 +133,9 @@ static List<List<?>> rows(List<?>... rows)
{
return asList(rows);
}

static byte[] bytes(String s)
{
return s.getBytes(UTF_8);
}
}
Expand Up @@ -19,6 +19,7 @@
import java.io.StringWriter;
import java.util.List;

import static com.facebook.presto.cli.TestAlignedTablePrinter.bytes;
import static com.facebook.presto.cli.TestAlignedTablePrinter.row;
import static com.facebook.presto.cli.TestAlignedTablePrinter.rows;
import static org.testng.Assert.assertEquals;
Expand Down Expand Up @@ -133,4 +134,38 @@ public void testVerticalPrintingNoRows()

assertEquals(writer.getBuffer().toString(), "(no rows)\n");
}

@Test
public void testVerticalPrintingHex()
throws Exception
{
StringWriter writer = new StringWriter();
List<String> fieldNames = ImmutableList.of("first", "binary", "last");
OutputPrinter printer = new VerticalRecordPrinter(fieldNames, writer);

printer.printRows(rows(
row("hello", bytes("hello"), "world"),
row("a", bytes("some long text that is more than 16 bytes"), "b"),
row("cat", bytes(""), "dog")),
true);
printer.finish();

String expected = "" +
"-[ RECORD 1 ]-------------------------------------------\n" +
"first | hello\n" +
"binary | 68 65 6c 6c 6f\n" +
"last | world\n" +
"-[ RECORD 2 ]-------------------------------------------\n" +
"first | a\n" +
"binary | 73 6f 6d 65 20 6c 6f 6e 67 20 74 65 78 74 20 74\n" +
" | 68 61 74 20 69 73 20 6d 6f 72 65 20 74 68 61 6e\n" +
" | 20 31 36 20 62 79 74 65 73\n" +
"last | b\n" +
"-[ RECORD 3 ]-------------------------------------------\n" +
"first | cat\n" +
"binary | \n" +
"last | dog\n";

assertEquals(writer.getBuffer().toString(), expected);
}
}
3 changes: 3 additions & 0 deletions presto-docs/src/main/sphinx/release/release-0.80.rst
Expand Up @@ -11,3 +11,6 @@ General Changes

* Add property ``task.verbose-stats`` to enable verbose statistics collection for
tasks. The default is ``false``.

* Format binary data in the CLI as a hex dump.

0 comments on commit 84f6c56

Please sign in to comment.