You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by np...@apache.org on 2021/10/12 20:41:57 UTC

[sling-org-apache-sling-pipes] branch master updated: SLING-10869 introduce binding declarations

This is an automated email from the ASF dual-hosted git repository.

npeltier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-pipes.git


The following commit(s) were added to refs/heads/master by this push:
     new ed5ef03  SLING-10869 introduce binding declarations
ed5ef03 is described below

commit ed5ef03fb4016bc25804525918891dbb79728f47
Author: Nicolas Peltier <np...@apache.org>
AuthorDate: Tue Oct 12 22:41:38 2021 +0200

    SLING-10869 introduce binding declarations
    
    ability to add a binding in a script file (which scope will be the full file) with binding foo = bar (bar being a json or a csv)
---
 pom.xml                                            |  2 +
 .../sling/pipes/internal/CommandExecutorImpl.java  | 53 ++++++++++++++++------
 .../pipes/internal/CommandExecutorImplTest.java    | 48 ++++++++++++++++----
 src/test/resources/declbasedinit.txt               | 27 +++++++++++
 4 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/pom.xml b/pom.xml
index 9024be5..2a3a250 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,8 @@
     <sling.java.version>8</sling.java.version>
     <org.ops4j.pax.exam.version>4.13.3</org.ops4j.pax.exam.version>
     <project.build.outputTimestamp>1</project.build.outputTimestamp>
+    <maven.compiler.source>8</maven.compiler.source>
+    <maven.compiler.target>8</maven.compiler.target>
   </properties>
 
   <scm>
diff --git a/src/main/java/org/apache/sling/pipes/internal/CommandExecutorImpl.java b/src/main/java/org/apache/sling/pipes/internal/CommandExecutorImpl.java
index 29c849d..366a16a 100644
--- a/src/main/java/org/apache/sling/pipes/internal/CommandExecutorImpl.java
+++ b/src/main/java/org/apache/sling/pipes/internal/CommandExecutorImpl.java
@@ -98,6 +98,12 @@ public class CommandExecutorImpl extends AbstractPlumberServlet implements Comma
     static final String KEY_NAME = "name";
     static final String KEY_PATH = "path";
     static final String KEY_EXPR = "expr";
+    static final String DECL_BINDING = "binding";
+    static final String DECL_BINDING_CONTENT = "declcontent";
+    static final Pattern DECL_BINDING_PATTERN = Pattern.compile(DECL_BINDING + WHITE_SPACE_SEPARATOR + "*"
+            + "(?<" + DECL_BINDING + ">[\\w_\\-\\d]+)"
+            + WHITE_SPACE_SEPARATOR + "*=" + WHITE_SPACE_SEPARATOR + "*" +
+            "(?<" +  DECL_BINDING_CONTENT + ">.*)");
 
     private static final String HELP_START =
         "\n a <pipe token> is <pipe> <expr|conf>? (<options>)?" +
@@ -126,11 +132,23 @@ public class CommandExecutorImpl extends AbstractPlumberServlet implements Comma
         help = null;
     }
 
-    boolean isCommandCandidate(String line) {
-        return StringUtils.isNotBlank(line) && !line.startsWith(COMMENT_PREFIX);
+    boolean isBlankLine(String line) {
+        return StringUtils.isBlank(line) || line.startsWith(COMMENT_PREFIX);
     }
 
-    List<String> getCommandList(SlingHttpServletRequest request) throws IOException {
+    boolean isJsonBinding(String line) {
+        return line.indexOf(DECL_BINDING) >= 0;
+    }
+
+    private void handleInputEnd(StringBuilder builder, String currentBinding, List<String> cmds, Map<String, Object> bindings) {
+        if (StringUtils.isBlank(currentBinding) && builder.length() > 0) {
+            cmds.add(builder.toString().trim());
+        } else if (StringUtils.isNoneBlank(currentBinding, builder)) {
+            bindings.put(currentBinding, builder.toString().trim());
+        }
+    }
+
+    List<String> getCommandList(SlingHttpServletRequest request, Map<String, Object> bindings) throws IOException {
         List<String> cmds = new ArrayList<>();
         if (request.getParameterMap().containsKey(REQ_PARAM_CMD)) {
             cmds.add(request.getParameter(REQ_PARAM_CMD));
@@ -140,18 +158,27 @@ public class CommandExecutorImpl extends AbstractPlumberServlet implements Comma
                 InputStream is = paramFile.getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                 String line;
-                StringBuilder cmdBuilder = new StringBuilder();
+                String currentBinding = null;
+                StringBuilder readerBuilder = new StringBuilder();
                 while ((line = reader.readLine()) != null) {
-                    if (isCommandCandidate(line)) {
-                        cmdBuilder.append(LINE_SEPARATOR + line.trim());
-                    } else if (cmdBuilder.length() > 0){
-                        cmds.add(cmdBuilder.toString().trim());
-                        cmdBuilder = new StringBuilder();
+                    if (isBlankLine(line)) {
+                        if (readerBuilder.length() > 0) {
+                            handleInputEnd(readerBuilder, currentBinding, cmds, bindings);
+                            readerBuilder = new StringBuilder();
+                            currentBinding = null;
+                        }
+                    }  else if (isJsonBinding(line)) {
+                        Matcher matcher = DECL_BINDING_PATTERN.matcher(line);
+                        if (matcher.find()) {
+                            currentBinding = matcher.group(DECL_BINDING);
+                            readerBuilder.append(matcher.group(DECL_BINDING_CONTENT).trim());
+                        }
+                    } else {
+                        //depending on what we are appending, we keep lines return or not
+                        readerBuilder.append((StringUtils.isBlank(currentBinding) ? LINE_SEPARATOR : "\n") + line.trim());
                     }
                 }
-                if (cmdBuilder.length() > 0) {
-                    cmds.add(cmdBuilder.toString().trim());
-                }
+                handleInputEnd(readerBuilder, currentBinding, cmds, bindings);
             }
         }
         return cmds;
@@ -167,7 +194,7 @@ public class CommandExecutorImpl extends AbstractPlumberServlet implements Comma
             } else {
                 ResourceResolver resolver = request.getResourceResolver();
                 Map<String, Object> bindings = plumber.getBindingsFromRequest(request, true);
-                List<String> cmds = getCommandList(request);
+                List<String> cmds = getCommandList(request, bindings);
                 if (cmds.isEmpty()) {
                     writer.println("No command to execute!");
                 }
diff --git a/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java b/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
index 753e833..d36c4f2 100644
--- a/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
@@ -37,8 +37,12 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Matcher;
 import java.util.stream.Collectors;
 
+import static org.apache.sling.pipes.internal.CommandExecutorImpl.DECL_BINDING;
+import static org.apache.sling.pipes.internal.CommandExecutorImpl.DECL_BINDING_CONTENT;
+import static org.apache.sling.pipes.internal.CommandExecutorImpl.DECL_BINDING_PATTERN;
 import static org.apache.sling.pipes.internal.CommandExecutorImpl.PARAMS_SEPARATOR;
 import static org.apache.sling.pipes.internal.CommandUtil.keyValuesToArray;
 import static org.junit.Assert.assertArrayEquals;
@@ -232,7 +236,7 @@ public class CommandExecutorImplTest extends AbstractPipeTest {
         MockSlingHttpServletRequest request = context.request();
         request.setParameterMap(params);
         request.setMethod("POST");
-        List<String> cmdList = commands.getCommandList(context.request());
+        List<String> cmdList = commands.getCommandList(context.request(), new HashMap<>());
         assertEquals(5, cmdList.size());
         for (int i = 0; i < 3; i ++) {
             assertEquals("echo /content | $ /apps/pipes-it/fruit | children nt:unstructured", cmdList.get(i));
@@ -247,12 +251,16 @@ public class CommandExecutorImplTest extends AbstractPipeTest {
         return items.toArray(new String[jsonItems.size()]);
     }
 
+    JsonObject executeFile(String fileName) throws IOException, ServletException {
+        Map<String, Object> params = new HashMap<>();
+        params.put(CommandExecutorImpl.REQ_PARAM_FILE, IOUtils.toString(getClass().getResourceAsStream("/" + fileName
+                + ".txt"), "UTF-8"));
+        return testServlet(params);
+    }
+
     @Test
     public void testChainedCommand() throws IOException, ServletException {
-        Map<String, Object> params = new HashMap<>();
-        params.put(CommandExecutorImpl.REQ_PARAM_FILE, IOUtils.toString(getClass().getResourceAsStream("/chainedCommand"
-            + ".txt"), "UTF-8"));
-        JsonObject response = testServlet(params);
+        JsonObject response = executeFile("chainedCommand");
         assertEquals(5, response.getJsonNumber("size").intValue());
         assertArrayEquals(new String[]{ "/content/fruits/banana/isnota/pea","/content/fruits/banana/isnota/carrot",
             "/content/fruits/apple/isnota/pea","/content/fruits/apple/isnota/plum",
@@ -261,12 +269,34 @@ public class CommandExecutorImplTest extends AbstractPipeTest {
 
     @Test
     public void testFileCommandServlet() throws IOException, ServletException {
-        Map<String, Object> params = new HashMap<>();
-        params.put(CommandExecutorImpl.REQ_PARAM_FILE, IOUtils.toString(getClass().getResourceAsStream("/testcommand"
-                + ".txt"), "UTF-8"));
-        JsonObject response = testServlet(params);
+        JsonObject response = executeFile("testcommand");
         assertEquals(5, response.getJsonNumber("size").intValue());
         assertArrayEquals(new String[]{"/content/beatles/john", "/content/beatles/paul", "/content/beatles/georges",
                 "/content/beatles/ringo", "/content/beatles/ringo/jcr:content"}, getItemsArray(response));
     }
+
+
+    void assertDeclBinding(String input, String expectedBinding, String expectedContent) {
+        Matcher matcher = DECL_BINDING_PATTERN.matcher(input);
+        assertTrue(input + " should match", matcher.matches());
+        assertEquals("binding should be " + expectedBinding, expectedBinding, matcher.group(DECL_BINDING));
+        assertEquals("content should be " + expectedContent, expectedContent, matcher.group(DECL_BINDING_CONTENT));
+    }
+
+    @Test
+    public void testDeclBindingPattern() {
+        assertDeclBinding("binding blah = {\"foo\":\"bar\"}", "blah", "{\"foo\":\"bar\"}");
+        assertDeclBinding("binding blah={\"foo\":\"bar\"}", "blah", "{\"foo\":\"bar\"}");
+        assertDeclBinding("binding blah = {", "blah", "{");
+        assertDeclBinding("binding csvStart = name,title", "csvStart", "name,title");
+        assertDeclBinding("binding csvStart =", "csvStart", "");
+    }
+
+    @Test
+    public void testDeclaredBindingBasedInit() throws ServletException, IOException {
+        JsonObject response = executeFile("declbasedinit");
+        assertEquals(4, response.getJsonNumber("size").intValue());
+        assertArrayEquals(new String[]{"/content/pages/1/leaves/child1","/content/pages/1/leaves/child2",
+                "/content/pages/2/leaves/child1","/content/pages/2/leaves/child2"}, getItemsArray(response));
+    }
 }
\ No newline at end of file
diff --git a/src/test/resources/declbasedinit.txt b/src/test/resources/declbasedinit.txt
new file mode 100644
index 0000000..c346f4a
--- /dev/null
+++ b/src/test/resources/declbasedinit.txt
@@ -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.
+
+binding pages = name,label
+1,first
+2,second
+
+binding leaves = {"child1": {"title":"child one"},
+    "child2": {"title":"child two"}
+}
+
+echo /content
+    | csv ${pages} @ name page | mkdir pages/${page.name} | write title=page.label
+    | json ${leaves} @ name leaf | mkdir leaves/${leaf.key} | write title=leaf.value.title
\ No newline at end of file