You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by gn...@apache.org on 2009/03/25 16:41:13 UTC
svn commit: r758310 - in
/servicemix/smx4/kernel/trunk/gshell/gshell-core/src:
main/java/org/apache/geronimo/gshell/commands/text/
main/resources/META-INF/spring/ main/resources/org/apache/geronimo/
main/resources/org/apache/geronimo/gshell/ main/resou...
Author: gnodet
Date: Wed Mar 25 15:41:09 2009
New Revision: 758310
URL: http://svn.apache.org/viewvc?rev=758310&view=rev
Log:
SMX4KNL-252: Create a sort command
Added:
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java
Modified:
servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml
Added: servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java?rev=758310&view=auto
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java (added)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/java/org/apache/geronimo/gshell/commands/text/SortAction.java Wed Mar 25 15:41:09 2009
@@ -0,0 +1,391 @@
+/*
+ * 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 org.apache.geronimo.gshell.commands.text;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.vfs.FileObject;
+import org.apache.geronimo.gshell.clp.Argument;
+import org.apache.geronimo.gshell.clp.Option;
+import org.apache.geronimo.gshell.command.CommandContext;
+import org.apache.geronimo.gshell.io.Closer;
+import org.apache.geronimo.gshell.vfs.FileObjects;
+import org.apache.geronimo.gshell.vfs.support.VfsActionSupport;
+
+/**
+ * Sort lines of text
+ *
+ * TODO: remove this file when gshell is upgraded
+ *
+ */
+public class SortAction extends VfsActionSupport {
+
+ @Option(name = "-f")
+ private boolean caseInsensitive;
+
+ @Option(name = "-r")
+ private boolean reverse;
+
+ @Option(name = "-u")
+ private boolean unique;
+
+ @Option(name = "-t")
+ private String separator;
+
+ @Option(name = "-b")
+ private boolean ignoreBlanks;
+
+ @Option(name = "-k", argumentRequired = true, multiValued = true)
+ private List<String> sortFields;
+
+ @Option(name = "-n")
+ private boolean numeric;
+
+ @Argument(index = 0, required=false)
+ private String path;
+
+
+ public Object execute(CommandContext context) throws Exception {
+ assert context != null;
+
+ if (path != null) {
+ FileObject file = resolveFile(context, path);
+
+ try {
+ sort(context, file);
+ }
+ finally {
+ FileObjects.close(file);
+ }
+ }
+ else {
+ sort(context.getIo().inputStream, context.getIo().out);
+ }
+ return Result.SUCCESS;
+ }
+
+ protected void sort(final CommandContext context, final FileObject file) throws Exception {
+ assert context != null;
+ assert file != null;
+
+ ensureFileExists(file);
+ ensureFileHasContent(file);
+ ensureFileIsReadable(file);
+
+ BufferedInputStream input = new BufferedInputStream(file.getContent().getInputStream());
+ try {
+ sort(input, context.getIo().out);
+ }
+ finally {
+ Closer.close(input);
+ }
+ }
+
+ protected void sort(InputStream input, PrintWriter out) throws Exception {
+ BufferedReader r = new BufferedReader(new InputStreamReader(input));
+ List<String> strings = new ArrayList<String>();
+ for (String s = r.readLine(); s != null; s = r.readLine()) {
+ strings.add(s);
+ }
+ char sep = (separator == null || separator.length() == 0) ? '\0' : separator.charAt(0);
+ Collections.sort(strings, new SortComparator(caseInsensitive, reverse, ignoreBlanks, numeric, sep, sortFields));
+ String last = null;
+ for (String s : strings) {
+ if (last == null) {
+ last = s;
+ } else if (!unique || !s.equals(last)) {
+ out.println(s);
+ }
+ }
+ }
+
+ public static class SortComparator implements Comparator<String> {
+
+ private boolean caseInsensitive;
+ private boolean reverse;
+ private boolean ignoreBlanks;
+ private boolean numeric;
+ private char separator;
+ private List<Key> sortKeys;
+
+ private static Pattern fpPattern;
+ static {
+ final String Digits = "(\\p{Digit}+)";
+ final String HexDigits = "(\\p{XDigit}+)";
+ final String Exp = "[eE][+-]?" + Digits;
+ final String fpRegex = "([\\x00-\\x20]*[+-]?(NaN|Infinity|(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|(\\.(" + Digits + ")(" + Exp + ")?)|(((0[xX]" + HexDigits + "(\\.)?)|(0[xX]" + HexDigits + "?(\\.)" + HexDigits + "))[pP][+-]?" + Digits + "))" + "[fFdD]?))[\\x00-\\x20]*)(.*)";
+ fpPattern = Pattern.compile(fpRegex);
+ }
+
+ public SortComparator(boolean caseInsensitive,
+ boolean reverse,
+ boolean ignoreBlanks,
+ boolean numeric,
+ char separator,
+ List<String> sortFields) {
+ this.caseInsensitive = caseInsensitive;
+ this.reverse = reverse;
+ this.separator = separator;
+ this.ignoreBlanks = ignoreBlanks;
+ this.numeric = numeric;
+ if (sortFields == null || sortFields.size() == 0) {
+ sortFields = new ArrayList<String>();
+ sortFields.add("1");
+ }
+ sortKeys = new ArrayList<Key>();
+ for (String f : sortFields) {
+ sortKeys.add(new Key(f));
+ }
+ }
+
+ public int compare(String o1, String o2) {
+ int res = 0;
+
+ List<Integer> fi1 = getFieldIndexes(o1);
+ List<Integer> fi2 = getFieldIndexes(o2);
+ for (Key key : sortKeys) {
+ int[] k1 = getSortKey(o1, fi1, key);
+ int[] k2 = getSortKey(o2, fi2, key);
+ if (key.numeric) {
+ Double d1 = getDouble(o1, k1[0], k1[1]);
+ Double d2 = getDouble(o2, k2[0], k2[1]);
+ res = d1.compareTo(d2);
+ } else {
+ res = compareRegion(o1, k1[0], k1[1], o2, k2[0], k2[1], key.caseInsensitive);
+ }
+ if (res != 0) {
+ if (key.reverse) {
+ res = - res;
+ }
+ break;
+ }
+ }
+ return res;
+ }
+
+ protected Double getDouble(String s, int start, int end) {
+ Matcher m = fpPattern.matcher(s.substring(start, end));
+ m.find();
+ return new Double(s.substring(0, m.end(1)));
+ }
+
+ protected int compareRegion(String s1, int start1, int end1, String s2, int start2, int end2, boolean caseInsensitive) {
+ int n1 = end1, n2 = end2;
+ for (int i1 = start1, i2 = start2; i1 < end1 && i2 < n2; i1++, i2++) {
+ char c1 = s1.charAt(i1);
+ char c2 = s2.charAt(i2);
+ if (c1 != c2) {
+ if (caseInsensitive) {
+ c1 = Character.toUpperCase(c1);
+ c2 = Character.toUpperCase(c2);
+ if (c1 != c2) {
+ c1 = Character.toLowerCase(c1);
+ c2 = Character.toLowerCase(c2);
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+ }
+ } else {
+ return c1 - c2;
+ }
+ }
+ }
+ return n1 - n2;
+ }
+
+ protected int[] getSortKey(String str, List<Integer> fields, Key key) {
+ int start;
+ int end;
+ if (key.startField * 2 < fields.size()) {
+ start = fields.get((key.startField - 1) * 2);
+ if (key.ignoreBlanksStart) {
+ while (start < fields.get((key.startField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(start))) {
+ start++;
+ }
+ }
+ if (key.startChar > 0) {
+ start = Math.min(start + key.startChar - 1, fields.get((key.startField - 1) * 2 + 1));
+ }
+ } else {
+ start = 0;
+ }
+ if (key.endField > 0 && key.endField * 2 < fields.size()) {
+ end = fields.get((key.endField - 1) * 2);
+ if (key.ignoreBlanksEnd) {
+ while (end < fields.get((key.endField - 1) * 2 + 1) && Character.isWhitespace(str.charAt(end))) {
+ end++;
+ }
+ }
+ if (key.endChar > 0) {
+ end = Math.min(end + key.endChar - 1, fields.get((key.endField - 1) * 2 + 1));
+ }
+ } else {
+ end = str.length();
+ }
+ return new int[] { start, end };
+ }
+
+ protected List<Integer> getFieldIndexes(String o) {
+ List<Integer> fields = new ArrayList<Integer>();
+ if (o.length() > 0) {
+ if (separator == '\0') {
+ int i = 0;
+ fields.add(0);
+ for (int idx = 1; idx < o.length(); idx++) {
+ if (Character.isWhitespace(o.charAt(idx)) && !Character.isWhitespace(o.charAt(idx - 1))) {
+ fields.add(idx - 1);
+ fields.add(idx);
+ }
+ }
+ fields.add(o.length() - 1);
+ } else {
+ int last = -1;
+ for (int idx = o.indexOf(separator); idx >= 0; idx = o.indexOf(separator, idx + 1)) {
+ if (last >= 0) {
+ fields.add(last);
+ fields.add(idx - 1);
+ } else if (idx > 0) {
+ fields.add(0);
+ fields.add(idx - 1);
+ }
+ last = idx + 1;
+ }
+ if (last < o.length()) {
+ fields.add(last < 0 ? 0 : last);
+ fields.add(o.length() - 1);
+ }
+ }
+ }
+ return fields;
+ }
+
+ public class Key {
+ int startField;
+ int startChar;
+ int endField;
+ int endChar;
+ boolean ignoreBlanksStart;
+ boolean ignoreBlanksEnd;
+ boolean caseInsensitive;
+ boolean reverse;
+ boolean numeric;
+
+ public Key(String str) {
+ boolean modifiers = false;
+ boolean startPart = true;
+ boolean inField = true;
+ boolean inChar = false;
+ for (char c : str.toCharArray()) {
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (!inField && !inChar) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ if (startPart) {
+ if (inChar) {
+ startChar = startChar * 10 + (c - '0');
+ } else {
+ startField = startField * 10 + (c - '0');
+ }
+ } else {
+ if (inChar) {
+ endChar = endChar * 10 + (c - '0');
+ } else {
+ endField = endField * 10 + (c - '0');
+ }
+ }
+ break;
+ case '.':
+ if (!inField) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ inField = false;
+ inChar = true;
+ break;
+ case 'n':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ numeric = true;
+ break;
+ case 'f':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ caseInsensitive = true;
+ break;
+ case 'r':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ reverse = true;
+ break;
+ case 'b':
+ inField = false;
+ inChar = false;
+ modifiers = true;
+ if (startPart) {
+ ignoreBlanksStart = true;
+ } else {
+ ignoreBlanksEnd = true;
+ }
+ break;
+ case ',':
+ inField = true;
+ inChar = false;
+ startPart = false;
+ break;
+ default:
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ }
+ if (!modifiers) {
+ ignoreBlanksStart = ignoreBlanksEnd = SortComparator.this.ignoreBlanks;
+ reverse = SortComparator.this.reverse;
+ caseInsensitive = SortComparator.this.caseInsensitive;
+ numeric = SortComparator.this.numeric;
+ }
+ if (startField < 1) {
+ throw new IllegalArgumentException("Bad field syntax: " + str);
+ }
+ }
+ }
+ }
+
+}
Modified: servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml?rev=758310&r1=758309&r2=758310&view=diff
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml (original)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/META-INF/spring/gshell-commands.xml Wed Mar 25 15:41:09 2009
@@ -173,6 +173,16 @@
<null/>
</gshell:completers>
</gshell:command>
+
+ <gshell:command name="sort">
+ <gshell:action class="org.apache.geronimo.gshell.commands.text.SortAction">
+ <property name="fileSystemAccess" ref="fileSystemAccess"/>
+ </gshell:action>
+ <gshell:completers>
+ <ref bean="fileObjectNameCompleter"/>
+ <null/>
+ </gshell:completers>
+ </gshell:command>
</gshell:command-bundle>
<gshell:command-bundle>
Added: servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties?rev=758310&view=auto
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties (added)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-core/src/main/resources/org/apache/geronimo/gshell/commands/text/SortAction.properties Wed Mar 25 15:41:09 2009
@@ -0,0 +1,27 @@
+##
+## 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.
+##
+
+##
+## $Rev: 703511 $ $Date: 2008-10-10 18:07:36 +0200 (Fri, 10 Oct 2008) $
+##
+
+command.description=Sort lines of text.
+
+command.manual=\
+ TODO: about manual
\ No newline at end of file
Added: servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java
URL: http://svn.apache.org/viewvc/servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java?rev=758310&view=auto
==============================================================================
--- servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java (added)
+++ servicemix/smx4/kernel/trunk/gshell/gshell-core/src/test/java/org/apache/geronimo/gshell/commands/text/SortTest.java Wed Mar 25 15:41:09 2009
@@ -0,0 +1,63 @@
+/*
+ * 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 org.apache.geronimo.gshell.commands.text;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+/**
+ * TODO: remove this file when gshell is upgraded
+ */
+public class SortTest extends TestCase {
+
+ public void testFieldIndexesDefaultSep() {
+ SortAction.SortComparator comparator = new SortAction.SortComparator(false, false, false, false, '\0', null);
+ List<Integer> indexes = comparator.getFieldIndexes(" ad re t ");
+ assertTrue(Arrays.asList(0, 2, 3, 6, 7, 9, 10, 10).equals(indexes));
+ }
+
+ public void testFieldIndexesWithSep() {
+ SortAction.SortComparator comparator = new SortAction.SortComparator(false, false, false, false, '[', null);
+ List<Integer> indexes = comparator.getFieldIndexes("[ 10] [Active ] [ ] [ 8] OPS4J Pax Logging - Service (1.3.0)");
+ assertTrue(Arrays.asList(1, 6, 8, 20, 22, 30, 32, 73 ).equals(indexes));
+
+ indexes = comparator.getFieldIndexes(" ad re t ");
+ assertTrue(Arrays.asList(0, 10).equals(indexes));
+ }
+
+ public void testSort() {
+ String s0 = "0321 abcd ddcba a";
+ String s1 = " 57t bcad ddacb b";
+ String s2 = " 128 cab ddbac c";
+ List<String> strings = Arrays.asList(s0, s1, s2);
+
+ Collections.sort(strings, new SortAction.SortComparator(false, false, false, false, '\0', Arrays.asList("2")));
+ assertTrue(Arrays.asList(s0, s1, s2).equals(strings));
+
+ Collections.sort(strings, new SortAction.SortComparator(false, false, false, false, '\0', Arrays.asList("2.2b")));
+ assertTrue(Arrays.asList(s2, s0, s1).equals(strings));
+
+ Collections.sort(strings, new SortAction.SortComparator(false, false, false, true, '\0', null));
+ assertTrue(Arrays.asList(s1, s2, s0).equals(strings));
+ }
+
+}