More updates to the blur-shell.
Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/fdb5f48a Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/fdb5f48a Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/fdb5f48a Branch: refs/heads/0.2-dev Commit: fdb5f48aa0fd62fad808bdf302845457e12d3ea2 Parents: 287c44c Author: Aaron McCurry <[email protected]> Authored: Sun Jan 6 18:18:49 2013 -0500 Committer: Aaron McCurry <[email protected]> Committed: Sun Jan 6 18:18:49 2013 -0500 ---------------------------------------------------------------------- src/blur-shell/pom.xml | 2 +- src/blur-shell/src/assemble/bin.xml | 8 + .../java/org/apache/blur/shell/AddCommand.java | 2 +- .../src/main/java/org/apache/blur/shell/Main.java | 7 +- .../java/org/apache/blur/shell/SearchCommand.java | 109 +++++--- .../blur/shell/ShowDiffsOnlyCompletionHandler.java | 201 +++++++++++++++ .../java/org/apache/blur/thrift/LongField.java | 92 +++++++ 7 files changed, 370 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/pom.xml ---------------------------------------------------------------------- diff --git a/src/blur-shell/pom.xml b/src/blur-shell/pom.xml index 3847eb8..6ac95a2 100644 --- a/src/blur-shell/pom.xml +++ b/src/blur-shell/pom.xml @@ -83,7 +83,7 @@ under the License. </repositories> <build> - <finalName>blur-shell</finalName> + <finalName>blur-shell-${project.version}</finalName> <plugins> <plugin> http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/src/assemble/bin.xml ---------------------------------------------------------------------- diff --git a/src/blur-shell/src/assemble/bin.xml b/src/blur-shell/src/assemble/bin.xml new file mode 100644 index 0000000..463fdbc --- /dev/null +++ b/src/blur-shell/src/assemble/bin.xml @@ -0,0 +1,8 @@ +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> + <id>bin</id> + <formats> + <format>jar</format> + </formats> +</assembly> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/src/main/java/org/apache/blur/shell/AddCommand.java ---------------------------------------------------------------------- diff --git a/src/blur-shell/src/main/java/org/apache/blur/shell/AddCommand.java b/src/blur-shell/src/main/java/org/apache/blur/shell/AddCommand.java index e960eb7..dbde107 100644 --- a/src/blur-shell/src/main/java/org/apache/blur/shell/AddCommand.java +++ b/src/blur-shell/src/main/java/org/apache/blur/shell/AddCommand.java @@ -40,7 +40,7 @@ import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.thrift.TException; -public class AddCommand extends Command { +public class AddCommand extends TableSingleArgumentCommand { private static final String HELP = "help"; private static final String WAL = "wal"; private static final String VISIBLE = "visible"; http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/src/main/java/org/apache/blur/shell/Main.java ---------------------------------------------------------------------- diff --git a/src/blur-shell/src/main/java/org/apache/blur/shell/Main.java b/src/blur-shell/src/main/java/org/apache/blur/shell/Main.java index e5694c4..d250d2f 100644 --- a/src/blur-shell/src/main/java/org/apache/blur/shell/Main.java +++ b/src/blur-shell/src/main/java/org/apache/blur/shell/Main.java @@ -175,12 +175,7 @@ public class Main { // reader.addCompleter(new StringsCompleter(commands.keySet())); // reader.addCompleter(new FileNameCompleter()); -// reader.setCompletionHandler(new CompletionHandler() { -// @Override -// public boolean complete(ConsoleReader reader, List<CharSequence> candidates, int position) throws IOException { -// return false; -// } -// }); + reader.setCompletionHandler(new ShowDiffsOnlyCompletionHandler()); for (Completer c : commands.values()) { System.out.println("adding " + c + " " + reader.addCompleter(c)); http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/src/main/java/org/apache/blur/shell/SearchCommand.java ---------------------------------------------------------------------- diff --git a/src/blur-shell/src/main/java/org/apache/blur/shell/SearchCommand.java b/src/blur-shell/src/main/java/org/apache/blur/shell/SearchCommand.java index 2008cf5..842d238 100644 --- a/src/blur-shell/src/main/java/org/apache/blur/shell/SearchCommand.java +++ b/src/blur-shell/src/main/java/org/apache/blur/shell/SearchCommand.java @@ -28,6 +28,7 @@ import jline.Terminal; import jline.console.ConsoleReader; import org.apache.blur.thrift.BlurClient; +import org.apache.blur.thrift.LongField; import org.apache.blur.thrift.StringField; import org.apache.blur.thrift.TextField; import org.apache.blur.thrift.generated.Blur.Iface; @@ -55,7 +56,7 @@ public class SearchCommand extends TableSingleArgumentCommand { private static final String HELP = "help"; private static final String BOOST = "boost"; private static final String FIELD = "field"; - private static final String TYPE = "type"; + private static final String TYPE_STR = "type"; public static void main(String[] args) throws BlurException, CommandException, TException, ParseException { Iface client = BlurClient.getClient("127.0.0.1:40020"); @@ -81,7 +82,7 @@ public class SearchCommand extends TableSingleArgumentCommand { Options options = new Options(); options.addOption("h", HELP, false, "Print the help for this command."); options.addOption("f", FIELD, true, "Fields to fetch during retrieval."); - options.addOption("t", TYPE, false, "Show field type."); + options.addOption("t", TYPE_STR, false, "Show field type."); options.addOption("b", BOOST, false, "Show field boost."); options.addOption("l", DOCLOC, false, "Show document locations."); @@ -101,7 +102,7 @@ public class SearchCommand extends TableSingleArgumentCommand { } boolean showBoost = line.hasOption(BOOST); - boolean showType = line.hasOption(TYPE); + boolean showType = line.hasOption(TYPE_STR); boolean showDocLocations = line.hasOption(DOCLOC); String[] fieldNames = line.getOptionValues(FIELD); @@ -158,8 +159,16 @@ public class SearchCommand extends TableSingleArgumentCommand { private void print(List<Document> docs, List<Long> docLocations, boolean showDocLocations, boolean showBoost, boolean showType, PrintWriter out, int maxLineWidth) { List<String> fieldNames = new ArrayList<String>(); List<String> fieldTypes = new ArrayList<String>(); - for (Document document : docs) { + for (int d = 0; d < docs.size(); d++) { + Document document = docs.get(d); List<Field> fields = document.getFields(); + if (showDocLocations) { + List<Field> newFields = new ArrayList<Field>(); + newFields.add(new LongField("docLocation", docLocations.get(d))); + newFields.addAll(fields); + fields = newFields; + document.setFields(fields); + } for (Field field : fields) { String name = field.getName(); String type = field.getType().name(); @@ -177,53 +186,64 @@ public class SearchCommand extends TableSingleArgumentCommand { int typeNameWidth = maxLength(fieldTypes); int fieldSep = 3; int valueMaxWidth; - int metaDataWidth; - - if (showBoost && showType) { - metaDataWidth = maxFieldNameLength + boostWidth + typeNameWidth + (fieldSep * 3); - } else if (showBoost) { - metaDataWidth = maxFieldNameLength + boostWidth + (fieldSep * 2); - } else if (showType) { - metaDataWidth = maxFieldNameLength + typeNameWidth + (fieldSep * 2); - } else { - metaDataWidth = maxFieldNameLength + fieldSep; + int metaDataWidth = maxFieldNameLength + fieldSep; + + if (showBoost) { + metaDataWidth += boostWidth + fieldSep; + } + if (showType) { + metaDataWidth += typeNameWidth + fieldSep; } valueMaxWidth = maxLineWidth - metaDataWidth; int fieldPaging = metaDataWidth - fieldSep; - for (Document document : docs) { + for (int d = 0; d < docs.size(); d++) { + Document document = docs.get(d); for (int i = 0; i < maxLineWidth; i++) { out.print('-'); } out.println(); - for (Field field : document.getFields()) { - String name = field.getName(); - double boost = field.getBoost(); - TYPE type = field.getType(); - String typeStr = type.name(); - - String valueStr = toString(field); - - for (int i = 0; i < valueStr.length(); i += valueMaxWidth) { - int max = Math.min(i + valueMaxWidth, valueStr.length()); - String displayValue = valueStr.substring(i, max); - if (i == 0) { - if (showBoost && showType) { - out.printf("%" + maxFieldNameLength + "s | %" + boostWidth + ".2f | %" + typeNameWidth + "s | %." + valueMaxWidth + "s%n", name, boost, typeStr, displayValue); - } else if (showBoost) { - out.printf("%" + maxFieldNameLength + "s | %" + boostWidth + ".2f | %." + valueMaxWidth + "s%n", name, boost, displayValue); - } else if (showType) { - out.printf("%" + maxFieldNameLength + "s | %" + typeNameWidth + "s | %." + valueMaxWidth + "s%n", name, typeStr, displayValue); - } else { - out.printf("%" + maxFieldNameLength + "s | %." + valueMaxWidth + "s%n", name, displayValue); - } - } else { - for (int c = 0; c < fieldPaging; c++) { - out.print(' '); - } - out.print(" | "); - out.println(displayValue); - } + List<Field> fields = document.getFields(); + for (Field field : fields) { + printField(showBoost, showType, out, maxFieldNameLength, boostWidth, typeNameWidth, valueMaxWidth, fieldPaging, field); + } + } + } + + private void printField(boolean showBoost, boolean showType, PrintWriter out, int maxFieldNameLength, int boostWidth, int typeNameWidth, int valueMaxWidth, int fieldPaging, + Field field) { + String name = field.getName(); + double boost = field.getBoost(); + TYPE type = field.getType(); + String typeStr = type.name(); + + String valueStr = toString(field); + + for (int i = 0; i < valueStr.length(); i += valueMaxWidth) { + int max = Math.min(i + valueMaxWidth, valueStr.length()); + String displayValue = valueStr.substring(i, max); + + if (i == 0) { + List<Object> args = new ArrayList<Object>(); + String formatString = "%" + maxFieldNameLength + "s | "; + args.add(name); + if (showBoost) { + formatString += "%" + boostWidth + ".2f | "; + args.add(boost); + } + if (showType) { + formatString += "%" + typeNameWidth + "s | "; + args.add(typeStr); + } + formatString += "%." + valueMaxWidth + "s%n"; + args.add(displayValue); + + out.printf(formatString, args.toArray(new Object[] {})); + } else { + for (int c = 0; c < fieldPaging; c++) { + out.print(' '); } + out.print(" | "); + out.println(displayValue); } } } @@ -239,6 +259,9 @@ public class SearchCommand extends TableSingleArgumentCommand { return new TextField(field).getValueString(); case STRING: return new StringField(field).getValueString(); + case LONG: + Long valueLong = new LongField(field).getValueLong(); + return valueLong == null ? "NULL" : valueLong.toString(); default: throw new RuntimeException("Not supported"); } http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-shell/src/main/java/org/apache/blur/shell/ShowDiffsOnlyCompletionHandler.java ---------------------------------------------------------------------- diff --git a/src/blur-shell/src/main/java/org/apache/blur/shell/ShowDiffsOnlyCompletionHandler.java b/src/blur-shell/src/main/java/org/apache/blur/shell/ShowDiffsOnlyCompletionHandler.java new file mode 100644 index 0000000..96a0799 --- /dev/null +++ b/src/blur-shell/src/main/java/org/apache/blur/shell/ShowDiffsOnlyCompletionHandler.java @@ -0,0 +1,201 @@ +package org.apache.blur.shell; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Set; + +import jline.console.ConsoleReader; +import jline.console.CursorBuffer; +import jline.console.completer.CandidateListCompletionHandler; +import jline.console.completer.CompletionHandler; + +public class ShowDiffsOnlyCompletionHandler implements CompletionHandler { + + public static void main(String[] args) throws IOException { + ConsoleReader reader = new ConsoleReader(); + reader.setPrompt("test> "); + ShowDiffsOnlyCompletionHandler handler = new ShowDiffsOnlyCompletionHandler(); + reader.setCompletionHandler(handler); + + String line; + PrintWriter out = new PrintWriter(reader.getOutput()); + while ((line = reader.readLine()) != null) { + line = line.trim(); + // ignore empty lines and comments + if (line.length() == 0 || line.startsWith("#")) { + continue; + } + out.println("output:" + line); + } + } + + public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws IOException { + CursorBuffer buf = reader.getCursorBuffer(); + + // if there is only one completion, then fill in the buffer + if (candidates.size() == 1) { + CharSequence value = candidates.get(0); + + // fail if the only candidate is the same as the current buffer + if (value.equals(buf.toString())) { + return false; + } + + setBuffer(reader, value, pos); + + return true; + } else if (candidates.size() > 1) { + String value = getUnambiguousCompletions(candidates); + setBuffer(reader, value, pos); + } + + printCandidates(reader, removeLeadingValues(buf.toString(), candidates)); + + // redraw the current console buffer + reader.drawLine(); + + return true; + } + + private Collection<CharSequence> removeLeadingValues(String buf, List<CharSequence> candidates) { + int index = buf.lastIndexOf(' '); + if (index < 0) { + return candidates; + } + List<CharSequence> result = new ArrayList<CharSequence>(); + String prefix = buf.substring(0, index); + for (CharSequence c : candidates) { + String s = c.toString(); + if (s.startsWith(prefix)) { + result.add(s.substring(index + 1)); + } else { + result.add(s); + } + } + return result; + } + + public static void setBuffer(final ConsoleReader reader, final CharSequence value, final int offset) throws IOException { + while ((reader.getCursorBuffer().cursor > offset) && reader.backspace()) { + // empty + } + + reader.putString(value); + reader.setCursorPosition(offset + value.length()); + } + + /** + * Print out the candidates. If the size of the candidates is greater than the + * {@link ConsoleReader#getAutoprintThreshold}, they prompt with a warning. + * + * @param candidates + * the list of candidates to print + */ + public static void printCandidates(final ConsoleReader reader, Collection<CharSequence> candidates) throws IOException { + Set<CharSequence> distinct = new HashSet<CharSequence>(candidates); + + if (distinct.size() > reader.getAutoprintThreshold()) { + // noinspection StringConcatenation + reader.print(Messages.DISPLAY_CANDIDATES.format(candidates.size())); + reader.flush(); + + int c; + + String noOpt = Messages.DISPLAY_CANDIDATES_NO.format(); + String yesOpt = Messages.DISPLAY_CANDIDATES_YES.format(); + char[] allowed = { yesOpt.charAt(0), noOpt.charAt(0) }; + + while ((c = reader.readCharacter(allowed)) != -1) { + String tmp = new String(new char[] { (char) c }); + + if (noOpt.startsWith(tmp)) { + reader.println(); + return; + } else if (yesOpt.startsWith(tmp)) { + break; + } else { + reader.beep(); + } + } + } + + // copy the values and make them distinct, without otherwise affecting the + // ordering. Only do it if the sizes differ. + if (distinct.size() != candidates.size()) { + Collection<CharSequence> copy = new ArrayList<CharSequence>(); + + for (CharSequence next : candidates) { + if (!copy.contains(next)) { + copy.add(next); + } + } + + candidates = copy; + } + + reader.println(); + reader.printColumns(candidates); + } + + /** + * Returns a root that matches all the {@link String} elements of the + * specified {@link List}, or null if there are no commonalities. For example, + * if the list contains <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the + * method will return <i>foob</i>. + */ + private String getUnambiguousCompletions(final List<CharSequence> candidates) { + if (candidates == null || candidates.isEmpty()) { + return null; + } + + // convert to an array for speed + String[] strings = candidates.toArray(new String[candidates.size()]); + + String first = strings[0]; + StringBuilder candidate = new StringBuilder(); + + for (int i = 0; i < first.length(); i++) { + if (startsWith(first.substring(0, i + 1), strings)) { + candidate.append(first.charAt(i)); + } else { + break; + } + } + + return candidate.toString(); + } + + /** + * @return true is all the elements of <i>candidates</i> start with + * <i>starts</i> + */ + private boolean startsWith(final String starts, final String[] candidates) { + for (String candidate : candidates) { + if (!candidate.startsWith(starts)) { + return false; + } + } + + return true; + } + + private static enum Messages { + DISPLAY_CANDIDATES, DISPLAY_CANDIDATES_YES, DISPLAY_CANDIDATES_NO, ; + + private static final ResourceBundle bundle = ResourceBundle.getBundle(CandidateListCompletionHandler.class.getName(), Locale.getDefault()); + + public String format(final Object... args) { + if (bundle == null) + return ""; + else + return String.format(bundle.getString(name()), args); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/fdb5f48a/src/blur-thrift/src/main/java/org/apache/blur/thrift/LongField.java ---------------------------------------------------------------------- diff --git a/src/blur-thrift/src/main/java/org/apache/blur/thrift/LongField.java b/src/blur-thrift/src/main/java/org/apache/blur/thrift/LongField.java new file mode 100644 index 0000000..605f128 --- /dev/null +++ b/src/blur-thrift/src/main/java/org/apache/blur/thrift/LongField.java @@ -0,0 +1,92 @@ +package org.apache.blur.thrift; + +import java.nio.ByteBuffer; + +import org.apache.blur.thrift.generated.Field; +import org.apache.blur.thrift.generated.TYPE; + +@SuppressWarnings("serial") +public class LongField extends Field { + + public LongField(String name, Long value) { + super(name, toByteBuffer(value), TYPE.LONG, 1.0); + } + + public static void main(String[] args) { + LongField longField = new LongField("a", 1l); + System.out.println(longField.getValueLong()); + } + + private static ByteBuffer toByteBuffer(Long value) { + if (value == null) { + return null; + } + ByteBuffer buffer = ByteBuffer.allocate(8).putLong(value); + buffer.flip(); + return buffer; + } + + public LongField() { + + } + + public LongField(Field field) { + super(field.name, field.value, field.type, field.boost); + if (field.getType() != TYPE.LONG) { + throw new RuntimeException("Field [" + field + "] is not of type Long."); + } + } + + public Long getValueLong() { + byte[] bs = getValue(); + if (bs == null) { + return null; + } + return ByteBuffer.wrap(bs).getLong(); + } + + public LongField setValueLong(Long value) { + setValue(toByteBuffer(value)); + return this; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("LongField("); + boolean first = true; + + sb.append("name:"); + if (this.name == null) { + sb.append("null"); + } else { + sb.append(this.name); + } + first = false; + if (!first) + sb.append(", "); + sb.append("value:"); + if (this.value == null) { + sb.append("null"); + } else { + sb.append(getValueLong()); + } + first = false; + if (!first) + sb.append(", "); + sb.append("type:"); + if (this.type == null) { + sb.append("null"); + } else { + sb.append(this.type); + } + first = false; + if (!first) + sb.append(", "); + sb.append("boost:"); + sb.append(this.boost); + first = false; + sb.append(")"); + return sb.toString(); + } + +}
