From 1404def3f16710d36a874d819613f7f0c4e12ee7 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Thu, 07 Jul 2016 08:33:54 +0000
Subject: [PATCH] OPENDJ-2748 OPENDJ-1667 dsconfig --displayCommand should print a usable command and parse it correctly afterwards
---
opendj-config/src/test/java/org/forgerock/opendj/config/dsconfig/DSConfigParseTest.java | 48 ++++++++++++++++
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java | 79 ++++++++++++++-----------
opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java | 12 ++++
3 files changed, 104 insertions(+), 35 deletions(-)
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
index 2e5881f..388db59 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ConsoleApplication.java
@@ -281,6 +281,18 @@
}
/**
+ * Displays a message to the output stream without wrapping.
+ *
+ * @param msg
+ * The message.
+ */
+ public final void printlnNoWrap(final LocalizableMessage msg) {
+ if (!isQuiet()) {
+ out.println(msg);
+ }
+ }
+
+ /**
* Prints a progress bar on the same output stream line if not in quiet mode.
*
* <pre>
diff --git a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
index 98b92a5..34128a8 100644
--- a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
+++ b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
@@ -1341,7 +1341,7 @@
if (displayEquivalentArgument.isPresent()) {
println();
// We assume that the app we are running is this one.
- println(INFO_DSCFG_NON_INTERACTIVE.get(commandBuilder));
+ printlnNoWrap(INFO_DSCFG_NON_INTERACTIVE.get(commandBuilder));
}
if (equivalentCommandFileArgument.isPresent()) {
String file = equivalentCommandFileArgument.getValue();
@@ -1422,13 +1422,7 @@
command += line;
command = command.trim();
- // string between quotes support
- command = replaceSpacesInQuotes(command);
- // "\ " support
- command = command.replace("\\ ", "##");
-
- String displayCommand = command.replace("\\ ", " ");
- println(LocalizableMessage.raw(displayCommand));
+ printlnNoWrap(LocalizableMessage.raw(command));
// Append initial arguments to the file line
final String[] allArgsArray = buildCommandArgs(initialArgs, command);
@@ -1448,20 +1442,54 @@
}
private String[] buildCommandArgs(List<String> initialArgs, String batchCommand) {
- final String[] commandArgs = toCommandArgs(batchCommand);
- final int length = commandArgs.length + initialArgs.size();
+ final Collection<String> commandArgs = toCommandArgs(batchCommand);
+ final int length = commandArgs.size() + initialArgs.size();
final List<String> allArguments = new ArrayList<>(length);
- Collections.addAll(allArguments, commandArgs);
+ allArguments.addAll(commandArgs);
allArguments.addAll(initialArgs);
return allArguments.toArray(new String[length]);
}
- private String[] toCommandArgs(String command) {
- String[] fileArguments = command.split("\\s+");
- for (int ii = 0; ii < fileArguments.length; ii++) {
- fileArguments[ii] = fileArguments[ii].replace("##", " ");
+ static Collection<String> toCommandArgs(String command) {
+ Collection<String> commandArgs = new ArrayList<>();
+ StringBuilder builder = new StringBuilder();
+ boolean inQuotes = false;
+ for (int i = 0; i < command.length(); i++) {
+ final char c = command.charAt(i);
+ switch (c) {
+ default:
+ builder.append(c);
+ break;
+ case '\\':
+ builder.append(command.charAt(++i));
+ break;
+ case '"':
+ if (inQuotes) {
+ builder = newArgumentString(commandArgs, builder);
+ inQuotes = false;
+ } else {
+ inQuotes = true;
+ }
+ break;
+ case ' ':
+ if (inQuotes) {
+ builder.append(c);
+ } else {
+ builder = newArgumentString(commandArgs, builder);
+ }
+ break;
+ }
}
- return fileArguments;
+ newArgumentString(commandArgs, builder);
+ return commandArgs;
+ }
+
+ private static StringBuilder newArgumentString(Collection<String> commandArgs, StringBuilder stringBuilder) {
+ if (stringBuilder.length() > 0) {
+ commandArgs.add(stringBuilder.toString());
+ stringBuilder = new StringBuilder();
+ }
+ return stringBuilder;
}
private List<String> removeBatchArgs(String[] args) {
@@ -1487,23 +1515,4 @@
}
return initialArgs;
}
-
- /** Replace spaces in quotes by "\ ". */
- private String replaceSpacesInQuotes(final String line) {
- StringBuilder newLine = new StringBuilder();
- boolean inQuotes = false;
- for (int ii = 0; ii < line.length(); ii++) {
- char ch = line.charAt(ii);
- if (ch == '\"' || ch == '\'') {
- inQuotes = !inQuotes;
- continue;
- }
- if (inQuotes && ch == ' ') {
- newLine.append("\\ ");
- } else {
- newLine.append(ch);
- }
- }
- return newLine.toString();
- }
}
diff --git a/opendj-config/src/test/java/org/forgerock/opendj/config/dsconfig/DSConfigParseTest.java b/opendj-config/src/test/java/org/forgerock/opendj/config/dsconfig/DSConfigParseTest.java
new file mode 100644
index 0000000..6cd877f
--- /dev/null
+++ b/opendj-config/src/test/java/org/forgerock/opendj/config/dsconfig/DSConfigParseTest.java
@@ -0,0 +1,48 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Portions copyright 2016 ForgeRock AS.
+ */
+package org.forgerock.opendj.config.dsconfig;
+
+import org.forgerock.testng.ForgeRockTestCase;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+
+@Test(groups = { "precommit", "config" })
+public class DSConfigParseTest extends ForgeRockTestCase {
+ @DataProvider
+ public Object[][] escapeSequences() {
+ return new Object[][] {
+ {"global-aci:\\(targetattr=\\\"userPassword\\|\\|authPassword\\\"\\)"
+ + "\\(version\\ 3.0\\;\\ acl\\ \\\"Self\\ entry\\ read\\'\\\"\\;"
+ + "\\ allow\\ \\(read,search,compare\\)\\ userdn=\\\"ldap:///self\\\"\\;\\)",
+ "global-aci:(targetattr=\"userPassword||authPassword\")"
+ + "(version 3.0; acl \"Self entry read'\";"
+ + " allow (read,search,compare) userdn=\"ldap:///self\";)"
+ },
+ {"cn=\"admin data\"", "cn=admin data"},
+ {"\"cn=admin data\"", "cn=admin data"},
+ {"cn=\\\"admin", "cn=\"admin"}
+ };
+ }
+
+ @Test(dataProvider = "escapeSequences")
+ public void testEscapeSequenceInCommandArgument(String arg, String value) throws Exception {
+ Collection<String> cmdLine = DSConfig.toCommandArgs(arg);
+ Assert.assertEquals(cmdLine.iterator().next(), value);
+ }
+}
--
Gitblit v1.10.0