This is an automated email from the ASF dual-hosted git repository. jbonofre pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/main by this push: new 737eab789f KARAF-6538 - add commands for executing groovy code new 62289e8909 Merge pull request #1712 from awrb/KARAF-6538 737eab789f is described below commit 737eab789f4fedb36d3aafb02ef02f7eee97694d Author: Aleksy Wróblewski <aleksy.wroblew...@bbbit.io> AuthorDate: Tue Feb 7 00:02:55 2023 +0100 KARAF-6538 - add commands for executing groovy code --- .../features/specs/src/main/feature/feature.xml | 44 ++++++------- .../features/standard/src/main/feature/feature.xml | 4 ++ .../src/test/filtered-resources/etc/feature.xml | 4 ++ .../java/org/apache/karaf/itests/GroovyTest.java | 66 +++++++++++++++++++ .../org/apache/karaf/itests/groovy/script.groovy | 22 +++++++ .../developer-guide/developer-commands.adoc | 48 ++++++++++++++ pom.xml | 1 + shell/groovy/pom.xml | 74 ++++++++++++++++++++++ .../groovy/commands/ExecGroovyCodeAction.java | 69 ++++++++++++++++++++ .../groovy/commands/ExecGroovyFileAction.java | 41 ++++++++++++ .../org.apache.karaf.shell.groovy/commands | 18 ++++++ shell/pom.xml | 1 + 12 files changed, 370 insertions(+), 22 deletions(-) diff --git a/assemblies/features/specs/src/main/feature/feature.xml b/assemblies/features/specs/src/main/feature/feature.xml index 2dd39d631e..3134ad9484 100644 --- a/assemblies/features/specs/src/main/feature/feature.xml +++ b/assemblies/features/specs/src/main/feature/feature.xml @@ -150,29 +150,29 @@ </feature> <!-- groovy --> - <feature name="groovy" version="3.0.3"> + <feature name="groovy" version="${groovy.version}"> <feature prerequisite="true">spifly</feature> - <bundle>mvn:org.codehaus.groovy/groovy/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-ant/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-cli-commons/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-cli-picocli/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-console/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-datetime/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-docgenerator/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-groovydoc/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-groovysh/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-jmx/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-json/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-macro/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-nio/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-servlet/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-sql/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-swing/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-templates/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-test/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-test-junit5/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-testng/3.0.3</bundle> - <bundle>mvn:org.codehaus.groovy/groovy-xml/3.0.3</bundle> + <bundle>mvn:org.codehaus.groovy/groovy/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-ant/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-cli-commons/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-cli-picocli/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-console/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-datetime/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-docgenerator/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-groovydoc/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-groovysh/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-jmx/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-json/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-macro/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-nio/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-servlet/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-sql/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-swing/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-templates/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-test/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-test-junit5/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-testng/${groovy.version}</bundle> + <bundle>mvn:org.codehaus.groovy/groovy-xml/${groovy.version}</bundle> </feature> </features> diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml index 0d07990190..512cdd0ada 100644 --- a/assemblies/features/standard/src/main/feature/feature.xml +++ b/assemblies/features/standard/src/main/feature/feature.xml @@ -379,6 +379,10 @@ disableEofExit = false <feature>jline</feature> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.core/${project.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/${project.version}</bundle> + <conditional> + <condition>groovy</condition> + <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.groovy/${project.version}</bundle> + </conditional> </feature> <feature name="jline" version="${jline.version}" hidden="true"> diff --git a/itests/test/src/test/filtered-resources/etc/feature.xml b/itests/test/src/test/filtered-resources/etc/feature.xml index f827ff6184..66bd2da93a 100644 --- a/itests/test/src/test/filtered-resources/etc/feature.xml +++ b/itests/test/src/test/filtered-resources/etc/feature.xml @@ -254,6 +254,10 @@ <bundle dependency="true" start-level="30">mvn:org.jline/jline/${jline.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.core/${project.version}</bundle> <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.commands/${project.version}</bundle> + <conditional> + <condition>groovy</condition> + <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.groovy/${project.version}</bundle> + </conditional> </feature> <feature name="shell-compat" description="Karaf Shell Compatibility" version="${project.version}"> diff --git a/itests/test/src/test/java/org/apache/karaf/itests/GroovyTest.java b/itests/test/src/test/java/org/apache/karaf/itests/GroovyTest.java new file mode 100644 index 0000000000..ebee38ca81 --- /dev/null +++ b/itests/test/src/test/java/org/apache/karaf/itests/GroovyTest.java @@ -0,0 +1,66 @@ +/* + * Licensed 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.karaf.itests; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy; +import org.ops4j.pax.exam.spi.reactors.PerClass; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.replaceConfigurationFile; + +@RunWith(PaxExam.class) +@ExamReactorStrategy(PerClass.class) +public class GroovyTest extends BaseTest { + + @Configuration + public Option[] config() { + List<Option> result = new LinkedList<>(Arrays.asList(super.config())); + result.add(replaceConfigurationFile("script.groovy", + getConfigFile("/org/apache/karaf/itests/groovy/script.groovy"))); + return result.toArray(new Option[result.size()]); + } + + @Before + public void setUp() throws Exception { + installAndAssertFeature("groovy"); + } + + @Test + public void execGroovyCodeCommand() throws Exception { + String resultNoArgs = executeCommand("groovy:exec \"" + + "def add(x, y) {\n" + + " return x + y \n" + + "}\n" + + "println add(1, 2)\""); + assertContains("3", resultNoArgs); + + String resultTwoArgs = executeCommand("groovy:exec \"(x as int) + (y as int)\" x=1 y=2"); + assertContains("3", resultTwoArgs); + } + + @Test + public void execGroovyFileCommand() throws Exception { + String result = executeCommand("groovy:exec-file script.groovy"); + assertContains("3", result); + } +} diff --git a/itests/test/src/test/resources/org/apache/karaf/itests/groovy/script.groovy b/itests/test/src/test/resources/org/apache/karaf/itests/groovy/script.groovy new file mode 100644 index 0000000000..bcc58bdd54 --- /dev/null +++ b/itests/test/src/test/resources/org/apache/karaf/itests/groovy/script.groovy @@ -0,0 +1,22 @@ +/* + * 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. + */ + +def add(x, y) { + return x + y +} + +println add(1, 2) diff --git a/manual/src/main/asciidoc/developer-guide/developer-commands.adoc b/manual/src/main/asciidoc/developer-guide/developer-commands.adoc index 75863d4e1e..7d795d6bcd 100644 --- a/manual/src/main/asciidoc/developer-guide/developer-commands.adoc +++ b/manual/src/main/asciidoc/developer-guide/developer-commands.adoc @@ -241,3 +241,51 @@ karaf@root()> bundle:watch * ---- will monitor all bundles that have a location matching mvn:* and '-SNAPSHOT' in their URL. + +==== Groovy +With the `groovy` feature installed, you can execute Groovy script files or code directly in the shell: +---- +karaf@root()> groovy:exec--help +DESCRIPTION + groovy:exec + + Executes Groovy code + +SYNTAX + groovy:exec script [args] + +ARGUMENTS + script + Groovy code + (required) + args + Arguments in the format of key=value + +karaf@root()> groovy:exec-file --help +DESCRIPTION + groovy:exec-file + + Executes Groovy file + +SYNTAX + groovy:exec-file path + +ARGUMENTS + path + Groovy script file path + (required) + + +karaf@root()> groovy:exec "1+1" +2 +karaf@root()> groovy:exec "(x as int) + (y as int)" x=1 y=2 +3 +karaf@root()> cat /foo/bar/test.groovy +def add(x, y) { + return x + y +} + +add(1,2) +karaf@root()> groovy:exec-file /foo/bar/test.groovy +3 +---- \ No newline at end of file diff --git a/pom.xml b/pom.xml index a86a9c89c2..f104ba2221 100644 --- a/pom.xml +++ b/pom.xml @@ -192,6 +192,7 @@ <servlet.spec.groupId>javax.servlet</servlet.spec.groupId> <servlet.spec.artifactId>javax.servlet-api</servlet.spec.artifactId> <servlet.spec.version>3.1.0</servlet.spec.version> + <groovy.version>3.0.3</groovy.version> <geronimo.jms-spec.version>1.1.1</geronimo.jms-spec.version> <geronimo.jta-spec.version>1.1.1</geronimo.jta-spec.version> diff --git a/shell/groovy/pom.xml b/shell/groovy/pom.xml new file mode 100644 index 0000000000..57f43fe88f --- /dev/null +++ b/shell/groovy/pom.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <!-- + + 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. + --> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>shell</artifactId> + <version>4.4.4-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>org.apache.karaf.shell.groovy</artifactId> + <packaging>bundle</packaging> + <name>Apache Karaf :: Shell :: Groovy</name> + <description>This bundle provides Groovy support to the Karaf console.</description> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.karaf</groupId> + <artifactId>karaf-bom</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.karaf.shell</groupId> + <artifactId>org.apache.karaf.shell.core</artifactId> + </dependency> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-all</artifactId> + <version>${groovy.version}</version> + <type>pom</type> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.karaf.tooling</groupId> + <artifactId>karaf-services-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> diff --git a/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyCodeAction.java b/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyCodeAction.java new file mode 100644 index 0000000000..1a0c4c0b6b --- /dev/null +++ b/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyCodeAction.java @@ -0,0 +1,69 @@ +/* + * 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.karaf.shell.groovy.commands; + +import groovy.lang.Binding; +import groovy.lang.GroovyShell; +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.lifecycle.Service; + +import java.util.List; + +@Command(scope = "groovy", + name = "exec", + description = "Executes Groovy code") +@Service +public class ExecGroovyCodeAction implements Action { + + @Argument(index = 0, name = "script", description = "Groovy code", required = true) + private String groovyCode; + + + @Argument(index = 1, name = "args", description = "Arguments in the format of key=value", multiValued = true) + private List<String> args; + + @Override + public Object execute() throws Exception { + Binding binding = new Binding(); + + if (args != null) + { + for (String arg : args) + { + int splitAt = arg.indexOf("="); + if (splitAt <= 0) + { + throw new IllegalArgumentException("Invalid argument " + arg); + } + else + { + String key = arg.substring(0, splitAt); + String value = arg.substring(splitAt + 1); + binding.setVariable(key, value); + } + } + } + + GroovyShell sh = new GroovyShell(binding); + System.out.println(sh.evaluate(groovyCode)); + + return null; + } +} diff --git a/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyFileAction.java b/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyFileAction.java new file mode 100644 index 0000000000..7f4e62c375 --- /dev/null +++ b/shell/groovy/src/main/java/org/apache/karaf/shell/groovy/commands/ExecGroovyFileAction.java @@ -0,0 +1,41 @@ +/* + * 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.karaf.shell.groovy.commands; + +import groovy.lang.GroovyShell; +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Argument; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.lifecycle.Service; + +import java.io.File; + +@Command(scope = "groovy", name = "exec-file", description = "Executes Groovy file") +@Service +public class ExecGroovyFileAction implements Action { + + @Argument(index = 0, name = "path", description = "Groovy script file path", required = true) + private String filePath; + + @Override + public Object execute() throws Exception { + GroovyShell sh = new GroovyShell(); + System.out.println(sh.evaluate(new File(filePath))); + return null; + } +} diff --git a/shell/groovy/src/main/resources/META-INF/services/org.apache.karaf.shell.groovy/commands b/shell/groovy/src/main/resources/META-INF/services/org.apache.karaf.shell.groovy/commands new file mode 100644 index 0000000000..7b44a57512 --- /dev/null +++ b/shell/groovy/src/main/resources/META-INF/services/org.apache.karaf.shell.groovy/commands @@ -0,0 +1,18 @@ +##--------------------------------------------------------------------------- +## 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. +##--------------------------------------------------------------------------- +org.apache.karaf.shell.groovy.commands.ExecGroovyCodeAction +org.apache.karaf.shell.groovy.commands.ExecGroovyFileAction diff --git a/shell/pom.xml b/shell/pom.xml index 4fe3f398ab..6b4c2bc9c9 100644 --- a/shell/pom.xml +++ b/shell/pom.xml @@ -39,6 +39,7 @@ <module>console</module> <module>table</module> <module>ssh</module> + <module>groovy</module> </modules> </project>