├── .gitignore
├── .travis.yml
├── LICENSE.md
├── README.md
├── _config.yml
├── annotations
├── build.gradle
└── src
│ ├── main
│ └── java
│ │ └── net
│ │ └── je2sh
│ │ └── annotations
│ │ └── CommandProcessor.java
│ └── test
│ └── java
│ └── net
│ └── je2sh
│ └── annotations
│ └── CommandProcessorTests.java
├── base-plugins
├── build.gradle
└── src
│ └── main
│ └── java
│ └── net
│ └── je2sh
│ └── base
│ └── Help.java
├── build.gradle
├── core
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── net
│ │ │ └── je2sh
│ │ │ └── core
│ │ │ ├── AbstractCommand.java
│ │ │ ├── CommandProvider.java
│ │ │ └── plugins
│ │ │ └── PluginContext.java
│ └── kotlin
│ │ └── net
│ │ └── je2sh
│ │ └── core
│ │ ├── Bootstrap.kt
│ │ ├── Command.kt
│ │ ├── CommandContext.kt
│ │ ├── CommandManager.kt
│ │ ├── JeeShell.kt
│ │ ├── annotations
│ │ └── CommandProcessor.kt
│ │ ├── errors
│ │ └── DuplicateCommandException.kt
│ │ ├── impl
│ │ ├── DefaultCommandManager.kt
│ │ └── EmptyCommandManager.kt
│ │ └── plugins
│ │ ├── Plugin.kt
│ │ ├── PluginLifeCycle.kt
│ │ └── RunnablePlugin.kt
│ └── test
│ └── groovy
│ └── net
│ └── je2sh
│ └── core
│ └── CommandTests.groovy
├── examples
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── net
│ │ │ └── je2sh
│ │ │ └── examples
│ │ │ ├── DemoApplication.java
│ │ │ ├── DemoController.java
│ │ │ ├── commands
│ │ │ ├── Echo.java
│ │ │ └── Hello.java
│ │ │ └── plugin
│ │ │ └── SpringPlugin.java
│ └── resources
│ │ ├── application.properties
│ │ ├── static
│ │ └── js
│ │ │ ├── home.js
│ │ │ └── unix_formatting.js
│ │ └── templates
│ │ └── home.html
│ └── test
│ └── groovy
│ └── net
│ └── je2sh
│ └── examples
│ └── commands
│ ├── EchoTests.groovy
│ └── HelloTests.groovy
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
├── shell
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── net
│ │ └── je2sh
│ │ └── shell
│ │ └── StandaloneShell.java
│ └── kotlin
│ └── net
│ └── je2sh
│ └── shell
│ └── ShellPlugin.kt
├── spring
├── build.gradle
└── src
│ └── main
│ ├── java
│ └── net
│ │ └── je2sh
│ │ └── spring
│ │ ├── JeeshRestAutoConfiguration.java
│ │ ├── JeeshSshAutoConfiguration.java
│ │ ├── rest
│ │ ├── CommandRequest.java
│ │ ├── CommandResponse.java
│ │ ├── JeeshRestOptions.java
│ │ ├── JeeshRestSpring.java
│ │ └── RestTerminalProvider.java
│ │ └── ssh
│ │ ├── JeeshSshOptions.java
│ │ └── JeeshSshSpring.java
│ └── resources
│ ├── META-INF
│ └── spring.factories
│ └── application.yaml
├── ssh
├── build.gradle
└── src
│ ├── main
│ ├── java
│ │ └── net
│ │ │ └── je2sh
│ │ │ └── ssh
│ │ │ └── SshPlugin.java
│ └── resources
│ │ └── jeesh
│ │ ├── hostkey.pem
│ │ └── jeesh.properties
│ └── test
│ └── groovy
│ └── net
│ └── je2sh
│ └── ssh
│ └── SshPluginTests.groovy
└── test
├── build.gradle
└── src
└── main
└── java
└── net
└── je2sh
└── test
└── TestUtils.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 |
13 | ### IntelliJ IDEA ###
14 | .idea
15 | *.iws
16 | *.iml
17 | *.ipr
18 |
19 | ### NetBeans ###
20 | nbproject/private/
21 | build/
22 | nbbuild/
23 | dist/
24 | nbdist/
25 | .nb-gradle/
26 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 | before_cache:
5 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
6 | - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
7 | cache:
8 | directories:
9 | - $HOME/.gradle/caches/
10 | - $HOME/.gradle/wrapper/
11 | script: ./gradlew build
12 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 JeeSh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # This is JeeSh
2 |
3 | [](https://travis-ci.org/jeeshell/je2sh)
4 | [](https://www.codefactor.io/repository/github/hartimer/je2sh)
5 |
6 | JeeSh stands for "JVM Extensible & Embeddable Shell". It aims at being a reboot of the famous
7 | [Common Reusable SHell (CRaSH)](https://github.com/crashub/crash).
8 |
9 |
10 | ## Motivation
11 |
12 | CRaSH is no longer maintained and [Spring Boot](https://projects.spring.io/spring-boot/) is removing support
13 | for it with release 2.0. Having the ability to access Spring features through SSH is very handy, especially
14 | for administrative tasks.
15 |
16 |
17 | We envisioned three common use-cases:
18 | * **Standalone shell**. Useful for encoding utilities
19 | * **SSH Server**. If you want to have JeeSh running on your server providing functionality not available
20 | on a normal *nix shell or for embedding it into a [Spring](https://spring.io/) application (common use case for CRaSH)
21 | * **REST Endpoints**. Allows you to expose your commands through a REST API, making it easy to create both
22 | a healthy repertoire of features and a client layer (other than SSH) to interact with it. The *examples* project
23 | provides a sample on how to use [JQueryTerminal](http://terminal.jcubic.pl/) for this purpose.
24 |
25 |
26 | # First Steps
27 |
28 | You can check JeeSh in action right after checking out the project. The **examples** module is a Spring Boot app
29 | that bootstraps JeeSh as both a SSH server and a REST API endpoint. Just run `./gradlew :examples:bootRun`
30 | and navigate to [http://localhost:8080/](http://localhost:8080/) or run `ssh -p 2003 admin@localhost` (admin:admin).
31 |
32 |
33 | Try the `help` command.
34 |
35 |
36 | ## First Command
37 |
38 | JeeSh just takes advantage of [JCommander](http://jcommander.org/) for command specification. Here is
39 | the entire code of the built in `hello` command
40 |
41 | ```java
42 | @Parameters(commandNames = {"hello", "hi"} , commandDescription = "Just says hello")
43 | public class Hello extends AbstractCommand {
44 |
45 | @Parameter(names = {"-n", "--name"}, description = "Your name")
46 | private String name;
47 |
48 | @Override
49 | public void execute(@NotNull CommandContext context) {
50 | context.println("Hello " + Optional.ofNullable(name).orElse("World"));
51 | }
52 |
53 | }
54 | ```
55 |
56 | The requirements:
57 | * Annotate your command with `@Parameters`
58 | * Implement `Command`. You will typically extend `net.je2sh.core.AbstractCommand` for convenience.
59 |
60 |
61 | # Architecture
62 |
63 | JeeSh is broken down into multiple modules, allowing users to only import what they need.
64 | By design, and for experimentation purposes, it is built using Java 8 and Kotlin.
65 |
66 |
67 | The base idea is that you can just define your commands using [JCommander](http://jcommander.org/) and those
68 | will be automatically picked up by JeeSh (if [*annotations*](#annotations) module is used).
69 |
70 |
71 | For parsing and rendering we use [jline3](https://github.com/jline/jline3), which allows using ANSI encodings
72 | and overall makes life easier.
73 |
74 |
75 | ## Core
76 |
77 | The core module provides the basis for everything else. Necessary interfaces and glue to interconnect
78 | the different components that build JeeSh.
79 |
80 | ## Annotations
81 |
82 | Enables *the magic* of interpreting `@Parameters`.
83 |
84 |
85 | This module provides an annotation processor that creates a `CommandProvider` for you and makes it
86 | available as a `ServiceProvider` (`META-INF/services`) which is how **core** loads the available commands.
87 |
88 |
89 | Mode on this subject later on.
90 |
91 |
92 | ## Base Plugins
93 |
94 | Small set of builtin plugins. Function mostly as an reference but also includes the `help` command.
95 |
96 | ## Shell
97 |
98 | Standalone shell instant that can be executed from the terminal
99 |
100 | ## SSH
101 |
102 | Pretty much self-explanatory.
103 |
104 | ## Spring (Boot)
105 |
106 | When included this module autoconfigures JeeSh according the the properties you define. By default
107 | both a SSH Server and a REST API will be enabled. These however can be controlled through the properties:
108 | `jeesh.ssh.enabled` and `jeesh.rest.enabled` respectively (to be added on your `application.[properties|yaml]`).
109 |
110 | # Disclaimer
111 |
112 | This is definitely a work in progress so there is definitely a lot of room for improvement. If you want
113 | to contribute go ahead and grab an issued or submitted your awesome new feature!
114 |
115 | Licensed under the MIT License ([LICENSE](LICENSE.md))
116 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
--------------------------------------------------------------------------------
/annotations/build.gradle:
--------------------------------------------------------------------------------
1 | import javax.tools.ToolProvider
2 |
3 | dependencies {
4 | compile project(':core')
5 | compile group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc3'
6 | compile 'com.squareup:javapoet:1.9.0'
7 |
8 | testCompile 'com.google.testing.compile:compile-testing:0.8'
9 | testCompile group: 'junit', name: 'junit', version: '4.12'
10 | testCompile files(((URLClassLoader) ToolProvider.getSystemToolClassLoader()).getURLs())
11 | }
12 |
--------------------------------------------------------------------------------
/annotations/src/main/java/net/je2sh/annotations/CommandProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.annotations;
26 |
27 | import java.io.IOException;
28 | import java.util.Arrays;
29 | import java.util.Collections;
30 | import java.util.HashMap;
31 | import java.util.List;
32 | import java.util.Map;
33 | import java.util.Objects;
34 | import java.util.Set;
35 |
36 | import com.beust.jcommander.Parameters;
37 | import com.google.auto.service.AutoService;
38 | import com.squareup.javapoet.AnnotationSpec;
39 | import com.squareup.javapoet.ClassName;
40 | import com.squareup.javapoet.JavaFile;
41 | import com.squareup.javapoet.MethodSpec;
42 | import com.squareup.javapoet.ParameterizedTypeName;
43 | import com.squareup.javapoet.TypeName;
44 | import com.squareup.javapoet.TypeSpec;
45 | import com.squareup.javapoet.WildcardTypeName;
46 | import javax.annotation.processing.AbstractProcessor;
47 | import javax.annotation.processing.Processor;
48 | import javax.annotation.processing.RoundEnvironment;
49 | import javax.annotation.processing.SupportedAnnotationTypes;
50 | import javax.annotation.processing.SupportedSourceVersion;
51 | import javax.lang.model.SourceVersion;
52 | import javax.lang.model.element.Element;
53 | import javax.lang.model.element.Modifier;
54 | import javax.lang.model.element.Name;
55 | import javax.lang.model.element.PackageElement;
56 | import javax.lang.model.element.TypeElement;
57 | import javax.lang.model.type.TypeMirror;
58 | import javax.tools.Diagnostic;
59 | import net.je2sh.core.Command;
60 | import net.je2sh.core.CommandProvider;
61 |
62 |
63 |
64 | /**
65 | * Annotation processor capable of understanding classes annotated with {@link Parameters} and
66 | * generating a {@link CommandProvider} for such commands.
67 | *
68 | * This processor uses JavaPoet to build
69 | * the new class(es).
70 | */
71 | @SupportedAnnotationTypes("com.beust.jcommander.Parameters")
72 | @SupportedSourceVersion(SourceVersion.RELEASE_8)
73 | @AutoService(Processor.class)
74 | public class CommandProcessor extends AbstractProcessor {
75 |
76 | @Override
77 | public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
78 |
79 | Map types = new HashMap<>();
80 | TypeMirror expectedInterfaceType =
81 | processingEnv.getElementUtils().getTypeElement(Command.class.getCanonicalName())
82 | .asType();
83 | PackageElement pkg = null;
84 | for (TypeElement a : annotations) {
85 | for (Element element : roundEnv.getElementsAnnotatedWith(a)) {
86 | Parameters parameters =
87 | Objects.requireNonNull(element.getAnnotation(Parameters.class));
88 |
89 | TypeMirror typeMirror = element.asType();
90 |
91 | if (pkg == null) {
92 | pkg = processingEnv.getElementUtils().getPackageOf(element);
93 | }
94 |
95 | if (!processingEnv.getTypeUtils().isAssignable(typeMirror, expectedInterfaceType)) {
96 | processingEnv.getMessager()
97 | .printMessage(Diagnostic.Kind.ERROR,
98 | String.format("Class %s does not implement %s",
99 | element.getSimpleName(),
100 | Command.class.getCanonicalName()));
101 | }
102 |
103 | for (String commandName : extractCommandNames(element.getSimpleName(),
104 | parameters.commandNames())) {
105 | types.put(commandName, typeMirror);
106 | }
107 | }
108 | }
109 |
110 | if (!types.isEmpty()) {
111 | try {
112 | writeFile(types, pkg);
113 | }
114 | catch (IOException e) {
115 | processingEnv.getMessager()
116 | .printMessage(Diagnostic.Kind.ERROR,
117 | "Unable to process jeesh annotations: " +
118 | e.getMessage());
119 | }
120 | }
121 | return false;
122 | }
123 |
124 | private void writeFile(Map types,
125 | PackageElement pkg) throws IOException
126 | {
127 | TypeName wildcardClass = ParameterizedTypeName.get(ClassName.get(Class.class),
128 | WildcardTypeName
129 | .subtypeOf(Command.class));
130 | ParameterizedTypeName returnType =
131 | ParameterizedTypeName.get(ClassName.get(Map.class),
132 | ClassName.get(String.class), wildcardClass);
133 |
134 | MethodSpec.Builder methodBuilder =
135 | MethodSpec.methodBuilder("getCommands")
136 | .addAnnotation(Override.class)
137 | .addModifiers(Modifier.PUBLIC)
138 | .returns(returnType)
139 | .addStatement("$T knownTypes = new $T<>()",
140 | returnType, ClassName.get(HashMap.class));
141 |
142 | for (Map.Entry entry : types.entrySet()) {
143 | methodBuilder.addStatement("knownTypes.put($S, $T.class)", entry.getKey(),
144 | entry.getValue());
145 | }
146 |
147 | MethodSpec getcommands = methodBuilder.addStatement("return knownTypes")
148 | .build();
149 |
150 | AnnotationSpec autoServiceAnnotation =
151 | AnnotationSpec.builder(AutoService.class)
152 | .addMember("value", "$T.class", CommandProvider.class)
153 | .build();
154 |
155 | TypeSpec commandProvider = TypeSpec.classBuilder("CommandProviderImpl")
156 | .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
157 | .addSuperinterface(CommandProvider.class)
158 | .addAnnotation(autoServiceAnnotation)
159 | .addMethod(getcommands)
160 | .build();
161 |
162 | JavaFile javaFile = JavaFile.builder(pkg.getQualifiedName().toString() + ".provider",
163 | commandProvider).build();
164 | javaFile.writeTo(processingEnv.getFiler());
165 | }
166 |
167 | private List extractCommandNames(Name elementName, String[] commandNames) {
168 | if (commandNames.length == 0) {
169 | String className = elementName.toString();
170 | StringBuilder builder = new StringBuilder()
171 | .append(Character.toLowerCase(className.charAt(0)))
172 | .append(className.substring(1, className.length()));
173 |
174 | return Collections.singletonList(builder.toString());
175 | }
176 | return Arrays.asList(commandNames);
177 | }
178 |
179 | }
180 |
--------------------------------------------------------------------------------
/annotations/src/test/java/net/je2sh/annotations/CommandProcessorTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.annotations;
26 |
27 | import static com.google.common.truth.Truth.assertAbout;
28 | import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
29 |
30 | import com.google.testing.compile.JavaFileObjects;
31 | import javax.tools.JavaFileObject;
32 | import org.junit.Test;
33 |
34 |
35 |
36 | public class CommandProcessorTests {
37 |
38 | @Test
39 | public void commandWithoutAnnotationShouldFailt() {
40 | assertAbout(javaSource())
41 | .that(CLASS_WITHOUT_SUPER)
42 | .processedWith(new CommandProcessor())
43 | .failsToCompile()
44 | .withErrorContaining("Class TestingCommand does not implement");
45 | }
46 |
47 | @Test
48 | public void commandWithoutNameUsesClassName() {
49 | assertAbout(javaSource())
50 | .that(CLASS_WITHOUT_NAMES)
51 | .processedWith(new CommandProcessor())
52 | .compilesWithoutError()
53 | .and()
54 | .generatesSources(JavaFileObjects.forSourceString(
55 | "net.je2sh.annotations.provider.CommandProviderImpl.java",
56 | "package net.je2sh.annotations.provider;\n" +
57 | "\n" +
58 | "import com.google.auto.service.AutoService;\n" +
59 | "import java.lang.Class;\n" +
60 | "import java.lang.Override;\n" +
61 | "import java.lang.String;\n" +
62 | "import java.util.HashMap;\n" +
63 | "import java.util.Map;\n" +
64 | "import net.je2sh.annotations.TestingCommand;\n" +
65 | "import net.je2sh.core.Command;\n" +
66 | "import net.je2sh.core.CommandProvider;\n" +
67 | "\n" +
68 | "@AutoService(CommandProvider.class)\n" +
69 | "public final class CommandProviderImpl implements CommandProvider {\n" +
70 | " @Override\n" +
71 | " public Map> getCommands() {\n" +
72 | " Map> knownTypes = new HashMap<>();\n" +
73 | " knownTypes.put(\"testingCommand\", TestingCommand.class);\n" +
74 | " return knownTypes;\n" +
75 | " }\n" +
76 | "}"));
77 | }
78 |
79 | @Test
80 | public void commandWithAnnotationShoudSucceed() {
81 | assertAbout(javaSource())
82 | .that(CLASS_WITH_ANNOTATION)
83 | .processedWith(new CommandProcessor())
84 | .compilesWithoutError()
85 | .and()
86 | .generatesSources(JavaFileObjects.forSourceString(
87 | "net.je2sh.annotations.provider.CommandProviderImpl.java",
88 | "package net.je2sh.annotations.provider;\n" +
89 | "\n" +
90 | "import com.google.auto.service.AutoService;\n" +
91 | "import java.lang.Class;\n" +
92 | "import java.lang.Override;\n" +
93 | "import java.lang.String;\n" +
94 | "import java.util.HashMap;\n" +
95 | "import java.util.Map;\n" +
96 | "import net.je2sh.annotations.TestingCommand;\n" +
97 | "import net.je2sh.core.Command;\n" +
98 | "import net.je2sh.core.CommandProvider;\n" +
99 | "\n" +
100 | "@AutoService(CommandProvider.class)\n" +
101 | "public final class CommandProviderImpl implements CommandProvider {\n" +
102 | " @Override\n" +
103 | " public Map> getCommands() {\n" +
104 | " Map> knownTypes = new HashMap<>();\n" +
105 | " knownTypes.put(\"testing\", TestingCommand.class);\n" +
106 | " return knownTypes;\n" +
107 | " }\n" +
108 | "}"));
109 | }
110 |
111 | /* ### Utility constants ### */
112 |
113 | private static final JavaFileObject CLASS_WITH_ANNOTATION =
114 | JavaFileObjects.forSourceLines("net.je2sh.annotations.TestingCommand",
115 | "package net.je2sh.annotations;\n" +
116 | "\n" +
117 | "import com.beust.jcommander.Parameters;\n" +
118 | "import net.je2sh.core.AbstractCommand;\n" +
119 | "import net.je2sh.core.CommandContext;\n" +
120 | "import org.jetbrains.annotations.NotNull;\n" +
121 | "\n" +
122 | "\n" +
123 | "@Parameters(commandNames = \"testing\")\n" +
124 | "public class TestingCommand extends AbstractCommand {\n" +
125 | "\n" +
126 | " @Override\n" +
127 | " public void execute(@NotNull CommandContext context) {\n" +
128 | " // noop\n" +
129 | " }\n" +
130 | "}");
131 |
132 | private static final JavaFileObject CLASS_WITHOUT_SUPER =
133 | JavaFileObjects.forSourceLines("net.je2sh.annotations.TestingCommand",
134 | "package net.je2sh.annotations;\n" +
135 | "\n" +
136 | "import com.beust.jcommander.Parameters;\n" +
137 | "import net.je2sh.core.AbstractCommand;\n" +
138 | "import net.je2sh.core.CommandContext;\n" +
139 | "import org.jetbrains.annotations.NotNull;\n" +
140 | "\n" +
141 | "@Parameters(commandNames = \"testing\")\n" +
142 | "public class TestingCommand {\n" +
143 | "\n" +
144 | " public void execute(@NotNull CommandContext context) {\n" +
145 | " // noop\n" +
146 | " }\n" +
147 | "}\n" +
148 | "\n" +
149 | "");
150 |
151 | private static final JavaFileObject CLASS_WITHOUT_NAMES =
152 | JavaFileObjects.forSourceLines("net.je2sh.annotations.TestingCommand",
153 | "\n" +
154 | "package net.je2sh.annotations;\n" +
155 | "\n" +
156 | "import com.beust.jcommander.Parameters;\n" +
157 | "import net.je2sh.core.AbstractCommand;\n" +
158 | "import net.je2sh.core.CommandContext;\n" +
159 | "import org.jetbrains.annotations.NotNull;\n" +
160 | "\n" +
161 | "@Parameters\n" +
162 | "public class TestingCommand extends AbstractCommand {\n" +
163 | "\n" +
164 | " @Override\n" +
165 | " public void execute(@NotNull CommandContext context) {\n" +
166 | " // noop\n" +
167 | " }\n" +
168 | "}");
169 | }
170 |
--------------------------------------------------------------------------------
/base-plugins/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compileOnly project(':core')
3 | compileOnly project(':annotations')
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/base-plugins/src/main/java/net/je2sh/base/Help.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.base;
26 |
27 | import java.util.Arrays;
28 | import java.util.Collections;
29 | import java.util.List;
30 | import java.util.Map;
31 | import java.util.Optional;
32 | import java.util.TreeMap;
33 | import java.util.stream.Collectors;
34 |
35 | import com.beust.jcommander.Parameters;
36 | import net.je2sh.asciitable.AnsiContentParser;
37 | import net.je2sh.asciitable.JTable;
38 | import net.je2sh.asciitable.style.JPadding;
39 | import net.je2sh.asciitable.style.JTheme;
40 | import net.je2sh.core.AbstractCommand;
41 | import net.je2sh.core.Command;
42 | import net.je2sh.core.CommandContext;
43 | import org.fusesource.jansi.Ansi;
44 | import org.jetbrains.annotations.NotNull;
45 | import org.jline.utils.AttributedStringBuilder;
46 | import org.jline.utils.AttributedStyle;
47 |
48 |
49 |
50 | @Parameters(commandNames = "help", commandDescription = "Shows the available commands")
51 | public class Help extends AbstractCommand {
52 |
53 | @Override
54 | public void execute(@NotNull CommandContext context) {
55 | context.print("List of available commands. ");
56 |
57 | AttributedStringBuilder headerBuilder =
58 | new AttributedStringBuilder()
59 | .append("To find more about a specific command run ")
60 | .style(AttributedStyle.BOLD.foreground(AttributedStyle.RED))
61 | .append(" -h");
62 |
63 | context.println(headerBuilder.toAnsi(context.getTerminal()));
64 |
65 | Map> commandMap =
66 | context.getPluginContext().getCommandManager().getCommands();
67 |
68 | AnsiContentParser ansiContentParser = new AnsiContentParser();
69 |
70 | JTable table = JTable.of()
71 | .width(60)
72 | .contentParser(ansiContentParser)
73 | .theme(JTheme.NO_LINE);
74 |
75 | Map helpMap = new TreeMap<>();
76 | int maxCommandLength = 1;
77 |
78 | for (Class extends Command> command : commandMap.values()) {
79 | String cmds = getCommandNames(command).stream()
80 | .map(s -> Ansi.ansi().fgRed().bold().a(s).reset()
81 | .toString())
82 | .collect(Collectors.joining(", "));
83 |
84 | helpMap.put(cmds, getDescription(command));
85 | maxCommandLength = Math.max(maxCommandLength, ansiContentParser.getLength(cmds));
86 | }
87 |
88 | for (Map.Entry entry : helpMap.entrySet()) {
89 | table.row()
90 | .col().width(maxCommandLength + 6)
91 | .padding(new JPadding(5, 0, 0, 0, ' '))
92 | .content(Ansi.ansi().fgRed().bold().a(entry.getKey()).reset())
93 | .done()
94 | .col().content(entry.getValue());
95 | }
96 |
97 | table.render().forEach(context::println);
98 | }
99 |
100 | private static List getCommandNames(Class tClass) {
101 | Parameters paramAnn = tClass.getAnnotation(Parameters.class);
102 | if (paramAnn.commandNames().length == 0) {
103 | String simpleName = tClass.getClass().getSimpleName();
104 | simpleName = Character.toLowerCase(simpleName.charAt(0)) +
105 | simpleName.substring(1, simpleName.length());
106 | return Collections.singletonList(simpleName);
107 | }
108 | return Arrays.asList(paramAnn.commandNames());
109 | }
110 |
111 | private static String getDescription(Class tClass) {
112 | return Optional.ofNullable(tClass.getAnnotation(Parameters.class))
113 | .map(Parameters::commandDescription)
114 | .orElse("");
115 |
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | description 'JVM Extensible Embeddable SHell'
2 |
3 | apply plugin: 'java'
4 | apply plugin: 'net.researchgate.release'
5 |
6 | sourceCompatibility = 1.8
7 |
8 | buildscript {
9 | ext.kotlin_version = '1.1.2-5'
10 | repositories {
11 | mavenCentral()
12 | }
13 | dependencies {
14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
15 | classpath 'net.researchgate:gradle-release:2.4.0'
16 |
17 | }
18 | }
19 |
20 | repositories {
21 | mavenCentral()
22 | }
23 |
24 | subprojects {
25 | apply plugin: 'java'
26 | apply plugin: 'kotlin'
27 |
28 | repositories {
29 | mavenCentral()
30 | }
31 |
32 | dependencies {
33 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
34 | }
35 | }
36 |
37 | configure(subprojects.findAll {
38 | it.name in ['core', 'annotations', 'base-plugins', 'ssh', 'shell', 'spring']
39 | }) {
40 | apply plugin: 'maven'
41 | apply plugin: 'signing'
42 |
43 | task javadocJar(type: Jar) {
44 | classifier = 'javadoc'
45 | from javadoc
46 | }
47 |
48 | task sourcesJar(type: Jar) {
49 | classifier = 'sources'
50 | from sourceSets.main.allSource
51 | }
52 |
53 | artifacts {
54 | archives javadocJar, sourcesJar
55 | }
56 |
57 | if (project.hasProperty('ossrhUsername')) {
58 | signing {
59 | sign configurations.archives
60 | }
61 |
62 | uploadArchives {
63 | repositories {
64 | mavenDeployer {
65 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
66 |
67 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
68 | authentication(userName: ossrhUsername, password: ossrhPassword)
69 | }
70 |
71 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
72 | authentication(userName: ossrhUsername, password: ossrhPassword)
73 | }
74 |
75 | pom.project {
76 | name 'JVM Extensible & Embeddable SHell'
77 | packaging 'jar'
78 | // optionally artifactId can be defined here
79 | description 'Reboot of the CRaSH project'
80 | url 'https://jeeshell.github.io/je2sh/'
81 |
82 | scm {
83 | connection 'scm:https://github.com/jeeshell/je2sh.git'
84 | developerConnection 'scm:https://github.com/jeeshell/je2sh.git'
85 | url 'git@github.com:jeeshell/je2sh.git'
86 | }
87 |
88 | licenses {
89 | license {
90 | name 'MIT License'
91 | url 'https://github.com/jeeshell/je2sh/blob/master/LICENSE.md'
92 | }
93 | }
94 |
95 | developers {
96 | developer {
97 | id 'hartimer'
98 | name 'Joao Peixoto'
99 | email 'joao.hartimer@gmail.com'
100 | }
101 | }
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'groovy'
2 |
3 | dependencies {
4 | compile group: 'org.jline', name: 'jline', version: '3.3.1'
5 | compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
6 | compile group: 'com.beust', name: 'jcommander', version: '1.69'
7 | compile group: 'com.google.auto.service', name: 'auto-service', version: '1.0-rc3'
8 | compile 'com.squareup:javapoet:1.9.0'
9 | compile 'net.je2sh:asciitable:1.0.0'
10 |
11 | testCompile group: 'org.spockframework', name: 'spock-core', version: '1.1-groovy-2.4'
12 |
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/core/src/main/java/net/je2sh/core/AbstractCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core;
26 |
27 | import java.util.Optional;
28 |
29 | import com.beust.jcommander.Parameter;
30 | import com.beust.jcommander.Parameters;
31 | import org.jetbrains.annotations.NotNull;
32 |
33 |
34 |
35 | /**
36 | * Abstract implementations of a {@link Command}. Most/All commands should extend this class.
37 | *
38 | * Automatically adds the command switches {@code -h} and {@code --help} to extending command.
39 | *
40 | * The contents of "help" are the ones specified in {@link Parameters#commandDescription()} or
41 | * empty string if none.
42 | *
43 | * @see Command
44 | */
45 | public abstract class AbstractCommand implements Command {
46 |
47 | @Parameter(names = { "-h", "--help" }, help = true, description = "Shows this help")
48 | private boolean help;
49 |
50 | @Override
51 | public boolean getHelp() {
52 | return help;
53 | }
54 |
55 | @NotNull
56 | @Override
57 | public String getDescription() {
58 | return Optional.ofNullable(this.getClass().getAnnotation(Parameters.class))
59 | .map(Parameters::commandDescription)
60 | .orElse("");
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core/src/main/java/net/je2sh/core/CommandProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core;
26 |
27 | import java.util.Map;
28 |
29 |
30 |
31 | /**
32 | * Base interface to define a command provider.
33 | *
34 | * We provide the raw {@link Class}es each command execution, which is parsed by
35 | * {@link com.beust.jcommander.JCommander}, does not leave previously parsed arguments behind
36 | *
37 | * Implementations of this interface are automatically generated if the "annotations" module is
38 | * included and there are classes in the classpath annotated
39 | * with {@link com.beust.jcommander.Parameters}.
40 | *
41 | * @see AbstractCommand
42 | */
43 | public interface CommandProvider {
44 |
45 | Map> getCommands();
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/core/src/main/java/net/je2sh/core/plugins/PluginContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.plugins;
26 |
27 | import java.io.IOException;
28 | import java.security.Principal;
29 | import java.util.HashMap;
30 | import java.util.Map;
31 | import java.util.concurrent.ExecutorService;
32 |
33 | import net.je2sh.core.Bootstrap;
34 | import net.je2sh.core.CommandManager;
35 | import net.je2sh.core.impl.DefaultCommandManager;
36 |
37 |
38 |
39 | /**
40 | * Context holder used by plugins.
41 | *
42 | * Provides relevant information and objects to the plugins.
43 | *
44 | * @see CommandManager
45 | */
46 | public class PluginContext {
47 |
48 | private final DefaultCommandManager commandManager;
49 | private final ExecutorService executor;
50 | private final Map attributes;
51 |
52 | private Principal principal;
53 |
54 | public PluginContext() throws IOException {
55 | this(new DefaultCommandManager(new Bootstrap()), null);
56 | }
57 |
58 | public PluginContext(ExecutorService executor) throws IOException {
59 | this(new DefaultCommandManager(new Bootstrap()), executor);
60 | }
61 |
62 | public PluginContext(DefaultCommandManager commandManager, ExecutorService executor)
63 | {
64 | this.commandManager = commandManager;
65 | this.executor = executor;
66 | this.attributes = new HashMap<>();
67 | }
68 |
69 | public DefaultCommandManager getCommandManager() {
70 | return commandManager;
71 | }
72 |
73 | public ExecutorService getExecutor() {
74 | return executor;
75 | }
76 |
77 | public Map getAttributes() {
78 | return attributes;
79 | }
80 |
81 | public void attribute(String name, Object val) {
82 | attributes.put(name, val);
83 | }
84 |
85 | public Principal getPrincipal() {
86 | return principal;
87 | }
88 |
89 | public void setPrincipal(Principal principal) {
90 | this.principal = principal;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/Bootstrap.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | import java.util.*
28 |
29 | class Bootstrap {
30 |
31 | val runnablePlugins = ServiceLoader.load(net.je2sh.core.plugins.RunnablePlugin::class.java).toList()
32 | val commandProviders = ServiceLoader.load(CommandProvider::class.java).toList()
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/Command.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | interface Command {
28 |
29 | fun execute(context: CommandContext)
30 | fun getHelp(): Boolean
31 | fun getDescription(): String
32 | }
33 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/CommandContext.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | import net.je2sh.core.plugins.PluginContext
28 | import org.jline.terminal.Terminal
29 |
30 | class CommandContext(val pluginContext: PluginContext, val terminal: Terminal) {
31 |
32 | fun print(t: Any) = terminal.writer().print(t)
33 | fun println(t: Any) = terminal.writer().println(t)
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/CommandManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | interface CommandManager {
28 |
29 | fun runCommand(name: String, context: CommandContext, vararg args: String)
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/JeeShell.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | import net.je2sh.core.plugins.PluginContext
28 | import org.jline.reader.EndOfFileException
29 | import org.jline.reader.LineReaderBuilder
30 | import org.jline.reader.UserInterruptException
31 | import org.jline.terminal.Terminal
32 | import org.jline.terminal.TerminalBuilder
33 | import java.lang.Exception
34 |
35 | class JeeShell(val context: PluginContext,
36 | val terminal: Terminal = TerminalBuilder.terminal(),
37 | val commandManager: CommandManager = context.commandManager) {
38 | private val EXIT_CMD = "exit"
39 | private var running = false
40 |
41 | fun run() {
42 | val prompt: String = "${context.attributes["prompt"]?.toString() ?: context.principal?.name ?: "jeesh"} $ "
43 | val reader = LineReaderBuilder.builder()
44 | .terminal(terminal)
45 | .build()
46 | running = true
47 |
48 | while (running) {
49 |
50 | try {
51 | val line = reader.readLine(prompt, null, null, null).trim { it <= ' ' }
52 |
53 | if (line.isEmpty()) {
54 | continue
55 | }
56 |
57 | val args = line.split(" ")
58 | val cmdStr = args[0]
59 |
60 | if (EXIT_CMD == cmdStr) {
61 | break
62 | }
63 |
64 | commandManager.runCommand(cmdStr, CommandContext(context, terminal), *args.toTypedArray())
65 |
66 | } catch (e: UserInterruptException) {
67 | // Ignore
68 | } catch (e: EndOfFileException) {
69 | break
70 | } catch (e: Exception) {
71 | terminal.writer().println("Command failed with \"" + e.message + "\"")
72 | }
73 |
74 | }
75 |
76 | terminal.writer().println("See you next time")
77 | terminal.writer().flush()
78 | terminal.close()
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/annotations/CommandProcessor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.annotations
26 |
27 | import javax.annotation.processing.AbstractProcessor
28 | import javax.annotation.processing.RoundEnvironment
29 | import javax.lang.model.element.TypeElement
30 |
31 |
32 | class CommandProcessor : AbstractProcessor() {
33 | override fun process(annotations: MutableSet?, roundEnv: RoundEnvironment?): Boolean {
34 | return false
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/errors/DuplicateCommandException.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.errors
26 |
27 | class DuplicateCommandException(message: String?) : Exception(message) {
28 | }
29 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/impl/DefaultCommandManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.impl
26 |
27 | import com.beust.jcommander.JCommander
28 | import com.beust.jcommander.ParameterException
29 | import net.je2sh.core.Bootstrap
30 | import net.je2sh.core.Command
31 | import net.je2sh.core.CommandContext
32 | import net.je2sh.core.CommandManager
33 |
34 | class DefaultCommandManager(bootstrap: Bootstrap) : CommandManager {
35 |
36 | val commands: Map>
37 |
38 | init {
39 | commands = bootstrap.commandProviders.map { it.commands }
40 | .reduce { acc, mutableMap -> acc + mutableMap }
41 | }
42 |
43 |
44 | override fun runCommand(name: String, context: CommandContext, vararg args: String) {
45 | val cmdClass = commands[name]
46 | if (cmdClass != null) {
47 | val cmdInstance = cmdClass.newInstance()
48 | try {
49 | val jCommander = JCommander.newBuilder()
50 | .addObject(cmdInstance)
51 | .programName(name)
52 | .build()
53 |
54 | if (args.size > 1) {
55 | jCommander.parse(*args.sliceArray(IntRange(1, args.size - 1)))
56 | }
57 |
58 | if (cmdInstance.getHelp()) {
59 | val usageStr = StringBuilder()
60 | jCommander.usage(usageStr)
61 | context.println(usageStr)
62 | } else {
63 | cmdInstance.execute(context)
64 | }
65 | } catch (e: ParameterException) {
66 | context.println("Unable to parse command: ${e.message}. Try \"$name -h\" for a list of the available options")
67 | }
68 | } else {
69 | context.println("Command \"$name\" not found. Try \"help\" for a list of available commands")
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/impl/EmptyCommandManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.impl
26 |
27 | import net.je2sh.core.CommandContext
28 | import net.je2sh.core.CommandManager
29 |
30 | class EmptyCommandManager : CommandManager {
31 | override fun runCommand(name: String, context: CommandContext, vararg args: String) {
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/plugins/Plugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.plugins
26 |
27 | import net.je2sh.core.CommandManager
28 |
29 | interface Plugin {
30 |
31 | fun configureCommands(commandManager: CommandManager)
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/plugins/PluginLifeCycle.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.plugins
26 |
27 | import net.je2sh.core.JeeShell
28 | import java.io.Closeable
29 | import java.util.concurrent.Future
30 |
31 | abstract class PluginLifeCycle(val context: PluginContext) : Closeable, Runnable {
32 |
33 | private val jeeShell = JeeShell(context)
34 | private var future: Future<*>? = null
35 |
36 | fun start() {
37 | if (context.executor == null) {
38 | run()
39 | } else {
40 | future = context.executor.submit(this)
41 | }
42 | }
43 |
44 | fun stop() {
45 | if (future != null) {
46 | context.executor.shutdownNow()
47 | }
48 | }
49 |
50 | override fun close() = stop()
51 |
52 | override fun run() = jeeShell.run()
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/core/src/main/kotlin/net/je2sh/core/plugins/RunnablePlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core.plugins
26 |
27 | import net.je2sh.core.CommandManager
28 |
29 | abstract class RunnablePlugin(val name: String, val interactive: Boolean = false) : Runnable {
30 |
31 | var commandManager: CommandManager? = null
32 |
33 | open fun configureCommands(commandManager: CommandManager) {
34 | this.commandManager = commandManager
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/core/src/test/groovy/net/je2sh/core/CommandTests.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.core
26 |
27 | import com.beust.jcommander.Parameters
28 | import org.jetbrains.annotations.NotNull
29 | import spock.lang.Specification
30 |
31 | class CommandTests extends Specification {
32 |
33 | static class NoParametersCommand extends AbstractCommand {
34 | @Override
35 | void execute(@NotNull CommandContext context) {
36 | // noop
37 | }
38 | }
39 |
40 | @Parameters
41 | static class NoDescriptionCommand extends AbstractCommand {
42 | @Override
43 | void execute(@NotNull CommandContext context) {
44 | // noop
45 | }
46 | }
47 |
48 | @Parameters(commandDescription = 'A sample command')
49 | static class WithDescriptionCommand extends AbstractCommand {
50 | @Override
51 | void execute(@NotNull CommandContext context) {
52 | // noop
53 | }
54 | }
55 |
56 | def 'Command without @Parameters should return empty string'() {
57 | expect:
58 | new NoParametersCommand().description == ''
59 | }
60 |
61 | def 'Command without @Parameters description should return empty string'() {
62 | expect:
63 | new NoDescriptionCommand().description == ''
64 | }
65 |
66 | def 'Command with @Parameters description should return description'() {
67 | expect:
68 | new WithDescriptionCommand().description == 'A sample command'
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/examples/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.4.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'java'
14 | apply plugin: 'groovy'
15 | apply plugin: 'eclipse'
16 | apply plugin: 'org.springframework.boot'
17 |
18 | version = '0.0.1-SNAPSHOT'
19 | sourceCompatibility = 1.8
20 |
21 | repositories {
22 | mavenCentral()
23 | }
24 |
25 |
26 | dependencies {
27 | compile('org.springframework.boot:spring-boot-starter-web')
28 | compile("org.springframework.boot:spring-boot-starter-thymeleaf")
29 |
30 | compile project(":spring")
31 |
32 | compileOnly project(":annotations")
33 |
34 | testCompile project(':test')
35 | testCompile group: 'org.spockframework', name: 'spock-core', version: '1.1-groovy-2.4'
36 | }
37 |
--------------------------------------------------------------------------------
/examples/src/main/java/net/je2sh/examples/DemoApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples;
26 |
27 | import org.springframework.boot.SpringApplication;
28 | import org.springframework.boot.autoconfigure.SpringBootApplication;
29 |
30 |
31 |
32 | @SpringBootApplication
33 | public class DemoApplication {
34 |
35 | public static void main(String[] args) {
36 | SpringApplication.run(DemoApplication.class, args);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/examples/src/main/java/net/je2sh/examples/DemoController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples;
26 |
27 | import org.springframework.stereotype.Controller;
28 | import org.springframework.web.bind.annotation.GetMapping;
29 |
30 |
31 |
32 | @Controller
33 | public class DemoController {
34 |
35 | @GetMapping("/")
36 | public String home() {
37 | return "home";
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/examples/src/main/java/net/je2sh/examples/commands/Echo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples.commands;
26 |
27 | import java.util.List;
28 |
29 | import com.beust.jcommander.Parameter;
30 | import com.beust.jcommander.ParameterException;
31 | import com.beust.jcommander.Parameters;
32 | import net.je2sh.core.AbstractCommand;
33 | import net.je2sh.core.CommandContext;
34 | import org.jetbrains.annotations.NotNull;
35 |
36 |
37 |
38 | @Parameters(commandNames = "echo", commandDescription = "Echos what you pass in")
39 | public class Echo extends AbstractCommand {
40 |
41 | @Parameter(description = "Message to echo", required = true)
42 | private List message;
43 |
44 | @Override
45 | public void execute(@NotNull CommandContext context) {
46 | if (message == null) throw new ParameterException("No message provided");
47 |
48 | context.println(String.join(" ", message));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/examples/src/main/java/net/je2sh/examples/commands/Hello.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples.commands;
26 |
27 | import java.util.Optional;
28 |
29 | import com.beust.jcommander.Parameter;
30 | import com.beust.jcommander.Parameters;
31 | import net.je2sh.core.AbstractCommand;
32 | import net.je2sh.core.CommandContext;
33 | import org.jetbrains.annotations.NotNull;
34 |
35 |
36 | @Parameters(commandNames = {"hello", "hi"} , commandDescription = "Just says hello")
37 | public class Hello extends AbstractCommand {
38 |
39 | @Parameter(names = {"-n", "--name"}, description = "Your name")
40 | private String name;
41 |
42 | @Override
43 | public void execute(@NotNull CommandContext context) {
44 | context.println("Hello " + Optional.ofNullable(name).orElse("World"));
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/examples/src/main/java/net/je2sh/examples/plugin/SpringPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples.plugin;
26 |
27 | import com.beust.jcommander.Parameters;
28 | import net.je2sh.core.AbstractCommand;
29 | import net.je2sh.core.CommandContext;
30 | import net.je2sh.examples.DemoController;
31 | import org.jetbrains.annotations.NotNull;
32 | import org.springframework.context.ApplicationContext;
33 |
34 |
35 |
36 | @Parameters(commandNames = "names")
37 | public class SpringPlugin extends AbstractCommand {
38 |
39 | @Override
40 | public void execute(@NotNull CommandContext context) {
41 | context.println("Running from spring");
42 |
43 | ApplicationContext beanFactory =
44 | (ApplicationContext) context.getPluginContext().getAttributes().get("spring.context");
45 |
46 | DemoController bean = beanFactory.getBean(DemoController.class);
47 |
48 | context.println("The bean holds " + bean);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/examples/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2017 JeeSh
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | logging.level.net.je2sh=DEBUG
26 |
27 | security.user.name=admin
28 | security.user.password=admin1
29 |
30 | jeesh.ssh.port=2003
31 |
32 |
--------------------------------------------------------------------------------
/examples/src/main/resources/static/js/home.js:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | jQuery(function ($, undefined) {
26 | $('#term_demo').terminal('/jeesh/exec', {
27 | greetings: 'Jeesh REST',
28 | name: 'jeesh',
29 | memory: true,
30 | height: 400,
31 | width: 950,
32 | prompt: 'jeesh > ',
33 | onAjaxError: function (xhr, status, error) {
34 | switch (xhr.status) {
35 | case 403:
36 | this.echo('Login first');
37 | break;
38 | case 500:
39 | this.echo('Something went wrong on the server side... try again later please');
40 | break;
41 | default:
42 | this.echo('Unexpected error. Please try again later');
43 | console.log("Ajax error boy", status, 'and', error, 'and', xhr);
44 | break;
45 | }
46 | }
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/examples/src/main/resources/static/js/unix_formatting.js:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 | /* global jQuery */
25 | (function($) {
26 | if (!$.terminal) {
27 | throw new Error('$.terminal is not defined');
28 | }
29 | // ---------------------------------------------------------------------
30 | // :: Replace overtyping (from man) formatting with terminal formatting
31 | // ---------------------------------------------------------------------
32 | $.terminal.overtyping = function overtyping(string) {
33 | return string.replace(/((?:_\x08.|.\x08_)+)/g, function(full) {
34 | var striped = full.replace(/_x08|\x08_|_\u0008|\u0008_/g, '');
35 | return '[[u;;]' + striped + ']';
36 | }).replace(/((?:.\x08.)+)/g, function(full) {
37 | return '[[b;#fff;]' + full.replace(/(.)(?:\x08|\u0008)\1/g,
38 | function(full, g) {
39 | return g;
40 | }) + ']';
41 | });
42 | };
43 | // ---------------------------------------------------------------------
44 | // :: Html colors taken from ANSI formatting in Linux Terminal
45 | // ---------------------------------------------------------------------
46 | $.terminal.ansi_colors = {
47 | normal: {
48 | black: '#000',
49 | red: '#A00',
50 | green: '#008400',
51 | yellow: '#A50',
52 | blue: '#00A',
53 | magenta: '#A0A',
54 | cyan: '#0AA',
55 | white: '#AAA'
56 | },
57 | faited: {
58 | black: '#000',
59 | red: '#640000',
60 | green: '#006100',
61 | yellow: '#737300',
62 | blue: '#000087',
63 | magenta: '#650065',
64 | cyan: '#008787',
65 | white: '#818181'
66 | },
67 | bold: {
68 | black: '#000',
69 | red: '#F55',
70 | green: '#44D544',
71 | yellow: '#FF5',
72 | blue: '#55F',
73 | magenta: '#F5F',
74 | cyan: '#5FF',
75 | white: '#FFF'
76 | },
77 | // XTerm 8-bit pallete
78 | palette: [
79 | '#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
80 | '#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
81 | '#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
82 | '#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
83 | '#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
84 | '#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
85 | '#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
86 | '#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
87 | '#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
88 | '#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
89 | '#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
90 | '#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
91 | '#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
92 | '#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
93 | '#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
94 | '#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
95 | '#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
96 | '#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
97 | '#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
98 | '#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
99 | '#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
100 | '#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
101 | '#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
102 | '#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
103 | '#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
104 | '#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
105 | '#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
106 | '#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
107 | '#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
108 | '#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
109 | '#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
110 | '#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
111 | '#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
112 | '#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
113 | '#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
114 | '#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
115 | '#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
116 | '#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
117 | '#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
118 | '#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
119 | '#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
120 | '#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
121 | '#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
122 | ]
123 | };
124 | // ---------------------------------------------------------------------
125 | // :: Replace ANSI formatting with terminal formatting
126 | // ---------------------------------------------------------------------
127 | $.terminal.from_ansi = (function() {
128 | var color_list = {
129 | 30: 'black',
130 | 31: 'red',
131 | 32: 'green',
132 | 33: 'yellow',
133 | 34: 'blue',
134 | 35: 'magenta',
135 | 36: 'cyan',
136 | 37: 'white',
137 |
138 | 39: 'inherit' // default color
139 | };
140 | var background_list = {
141 | 40: 'black',
142 | 41: 'red',
143 | 42: 'green',
144 | 43: 'yellow',
145 | 44: 'blue',
146 | 45: 'magenta',
147 | 46: 'cyan',
148 | 47: 'white',
149 |
150 | 49: 'transparent' // default background
151 | };
152 | function format_ansi(code) {
153 | var controls = code.split(';');
154 | var num;
155 | var faited = false;
156 | var reverse = false;
157 | var bold = false;
158 | var styles = [];
159 | var output_color = '';
160 | var output_background = '';
161 | var _8bit_color = false;
162 | var _8bit_background = false;
163 | var process_8bit = false;
164 | var palette = $.terminal.ansi_colors.palette;
165 | function set_styles(num) {
166 | switch (num) {
167 | case 1:
168 | styles.push('b');
169 | bold = true;
170 | faited = false;
171 | break;
172 | case 4:
173 | styles.push('u');
174 | break;
175 | case 3:
176 | styles.push('i');
177 | break;
178 | case 5:
179 | process_8bit = true;
180 | break;
181 | case 38:
182 | _8bit_color = true;
183 | break;
184 | case 48:
185 | _8bit_background = true;
186 | break;
187 | case 2:
188 | faited = true;
189 | bold = false;
190 | break;
191 | case 7:
192 | reverse = true;
193 | break;
194 | default:
195 | if (controls.indexOf('5') === -1) {
196 | if (color_list[num]) {
197 | output_color = color_list[num];
198 | }
199 | if (background_list[num]) {
200 | output_background = background_list[num];
201 | }
202 | }
203 | }
204 | }
205 | for (var i in controls) {
206 | if (controls.hasOwnProperty(i)) {
207 | num = parseInt(controls[i], 10);
208 | if (process_8bit && (_8bit_background || _8bit_color)) {
209 | if (_8bit_color && palette[num]) {
210 | output_color = palette[num];
211 | }
212 | if (_8bit_background && palette[num]) {
213 | output_background = palette[num];
214 | }
215 | } else {
216 | set_styles(num);
217 | }
218 | }
219 | }
220 | if (reverse) {
221 | if (output_color || output_background) {
222 | var tmp = output_background;
223 | output_background = output_color;
224 | output_color = tmp;
225 | } else {
226 | output_color = 'black';
227 | output_background = 'white';
228 | }
229 | }
230 | var colors, color, background, backgrounds;
231 | if (bold) {
232 | colors = backgrounds = $.terminal.ansi_colors.bold;
233 | } else if (faited) {
234 | colors = backgrounds = $.terminal.ansi_colors.faited;
235 | } else {
236 | colors = backgrounds = $.terminal.ansi_colors.normal;
237 | }
238 | if (_8bit_color) {
239 | color = output_color;
240 | } else if (output_color === 'inherit') {
241 | color = output_color;
242 | } else {
243 | color = colors[output_color];
244 | }
245 | if (_8bit_background) {
246 | background = output_background;
247 | } else if (output_background === 'transparent') {
248 | background = output_background;
249 | } else {
250 | background = backgrounds[output_background];
251 | }
252 | return [styles.join(''), color, background];
253 | }
254 | return function from_ansi(input) {
255 | //merge multiple codes
256 | /*input = input.replace(/((?:\x1B\[[0-9;]*[A-Za-z])*)/g, function(group) {
257 | return group.replace(/m\x1B\[/g, ';');
258 | });*/
259 | var splitted = input.split(/(\x1B\[[0-9;]*[A-Za-z])/g);
260 | if (splitted.length === 1) {
261 | return input;
262 | }
263 | var output = [];
264 | //skip closing at the begining
265 | if (splitted.length > 3) {
266 | var str = splitted.slice(0, 3).join('');
267 | if (str.match(/^\[0*m$/)) {
268 | splitted = splitted.slice(3);
269 | }
270 | }
271 | var prev_color, prev_background, code, match;
272 | var inside = false;
273 | for (var i = 0; i < splitted.length; ++i) {
274 | match = splitted[i].match(/^\x1B\[([0-9;]*)([A-Za-z])$/);
275 | if (match) {
276 | switch (match[2]) {
277 | case 'm':
278 | if (+match[1] !== 0) {
279 | code = format_ansi(match[1]);
280 | }
281 | if (inside) {
282 | output.push(']');
283 | if (+match[1] === 0) {
284 | //just closing
285 | inside = false;
286 | prev_color = prev_background = '';
287 | } else {
288 | // someone forget to close - move to next
289 | code[1] = code[1] || prev_color;
290 | code[2] = code[2] || prev_background;
291 | output.push('[[' + code.join(';') + ']');
292 | // store colors to next use
293 | if (code[1]) {
294 | prev_color = code[1];
295 | }
296 | if (code[2]) {
297 | prev_background = code[2];
298 | }
299 | }
300 | } else if (+match[1] !== 0) {
301 | inside = true;
302 | code[1] = code[1] || prev_color;
303 | code[2] = code[2] || prev_background;
304 | output.push('[[' + code.join(';') + ']');
305 | // store colors to next use
306 | if (code[1]) {
307 | prev_color = code[1];
308 | }
309 | if (code[2]) {
310 | prev_background = code[2];
311 | }
312 | }
313 | break;
314 | }
315 | } else {
316 | output.push(splitted[i]);
317 | }
318 | }
319 | if (inside) {
320 | output.push(']');
321 | }
322 | return output.join(''); //.replace(/\[\[[^\]]+\]\]/g, '');
323 | };
324 | })();
325 | $.terminal.defaults.formatters.unshift($.terminal.overtyping);
326 | $.terminal.defaults.formatters.unshift($.terminal.from_ansi);
327 | })(jQuery);
328 |
--------------------------------------------------------------------------------
/examples/src/main/resources/templates/home.html:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
28 | Jeesh Web-base Terminal Demo
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/examples/src/test/groovy/net/je2sh/examples/commands/EchoTests.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples.commands
26 |
27 | import static net.je2sh.test.TestUtils.mockitoAssert
28 | import static org.mockito.Matchers.eq
29 | import static org.mockito.Mockito.verify
30 |
31 | import com.beust.jcommander.ParameterException
32 | import net.je2sh.core.CommandContext
33 | import net.je2sh.core.plugins.PluginContext
34 | import net.je2sh.test.TestUtils
35 | import spock.lang.Specification
36 |
37 | class EchoTests extends Specification {
38 |
39 | CommandContext commandContext
40 | Echo cmd
41 |
42 | def setup() {
43 | commandContext = new CommandContext(Mock(PluginContext), TestUtils.mockedTerminal())
44 | cmd = new Echo()
45 | }
46 |
47 | def 'No arguments should fail'() {
48 | when:
49 | cmd.execute(commandContext)
50 |
51 | then:
52 | thrown(ParameterException)
53 | }
54 |
55 | def 'Message "#arguments" should echo values'() {
56 | given:
57 | TestUtils.parseCommand('echo', cmd, arguments)
58 |
59 | when:
60 | cmd.execute(commandContext)
61 |
62 | then:
63 | mockitoAssert(verify(commandContext.terminal.writer()).println(eq(arguments)))
64 |
65 | where:
66 | arguments << [
67 | 'something',
68 | 'multiple spaces are seen',
69 | '-o option non-existent'
70 | ]
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/examples/src/test/groovy/net/je2sh/examples/commands/HelloTests.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.examples.commands
26 |
27 | import static net.je2sh.test.TestUtils.mockitoAssert
28 | import static org.mockito.Matchers.eq
29 | import static org.mockito.Mockito.verify
30 |
31 | import com.beust.jcommander.ParameterException
32 | import net.je2sh.core.CommandContext
33 | import net.je2sh.core.plugins.PluginContext
34 | import net.je2sh.test.TestUtils
35 | import spock.lang.Specification
36 | import spock.lang.Unroll
37 |
38 | @Unroll
39 | class HelloTests extends Specification {
40 |
41 | CommandContext commandContext
42 | Hello cmd
43 |
44 | def setup() {
45 | commandContext = new CommandContext(Mock(PluginContext), TestUtils.mockedTerminal())
46 | cmd = new Hello()
47 | }
48 |
49 | def 'Wrong command "#cmdStr #arguments" should fail'() {
50 | when:
51 | TestUtils.parseCommand(cmdStr, cmd, (arguments as String).split(' '))
52 | cmd.execute(commandContext)
53 |
54 | then:
55 | thrown(ParameterException)
56 |
57 | where:
58 | [cmdStr, arguments] << [
59 | ['hello', 'hi'],
60 | [
61 | '-n',
62 | '-a',
63 | 'something',
64 | '-n arg with spaces',
65 | '--name arg with spaces',
66 | ]
67 | ].combinations()
68 | }
69 |
70 | def 'No argument should print world'() {
71 | when:
72 | cmd.execute(commandContext)
73 |
74 | then:
75 | mockitoAssert(verify(commandContext.terminal.writer()).println(eq('Hello World')))
76 | }
77 |
78 | def 'Command "#cmdStr #arguments" should succeed'() {
79 | given:
80 | TestUtils.parseCommand(cmdStr, cmd, (arguments as String).split(' '))
81 |
82 | when:
83 | cmd.execute(commandContext)
84 |
85 | then:
86 | mockitoAssert(verify(commandContext.terminal.writer()).println(eq("Hello $arg" as String)))
87 |
88 | where:
89 | [cmdStr, param, arg] << [
90 | ['hello', 'hi'],
91 | ['-n', '--name'],
92 | ['myself']
93 | ].combinations()
94 | arguments = "$param $arg"
95 | }
96 |
97 | }
98 |
99 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | version=1.4.0-SNAPSHOT
2 | group=net.je2sh
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeeshell/je2sh/dc7f722950f7571ec8220cfaaad2a552abae6ac0/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2017 JeeSh
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #
24 |
25 | #Tue Jun 20 08:34:51 PDT 2017
26 | distributionBase=GRADLE_USER_HOME
27 | distributionPath=wrapper/dists
28 | zipStoreBase=GRADLE_USER_HOME
29 | zipStorePath=wrapper/dists
30 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-bin.zip
31 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save ( ) {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'jeesh'
2 |
3 | include 'core', 'shell', 'ssh', 'base-plugins', 'annotations', 'spring', 'examples', 'test'
4 |
5 |
--------------------------------------------------------------------------------
/shell/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'application'
2 | //apply plugin: 'kotlin-kapt'
3 |
4 | dependencies {
5 | compile project(':core')
6 |
7 | runtime project(':base-plugins')
8 |
9 | // kapt 'com.squareup:javapoet:1.9.0'
10 | }
11 |
12 | mainClassName = 'net.je2sh.core.Main'
13 |
--------------------------------------------------------------------------------
/shell/src/main/java/net/je2sh/shell/StandaloneShell.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.shell;
26 |
27 | public class StandaloneShell {
28 |
29 | public static void main(String[] args) throws InterruptedException {
30 |
31 | try (ShellPlugin shellPlugin = new ShellPlugin()) {
32 | shellPlugin.start();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/shell/src/main/kotlin/net/je2sh/shell/ShellPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.shell
26 |
27 | import net.je2sh.core.plugins.PluginContext
28 | import net.je2sh.core.plugins.PluginLifeCycle
29 |
30 | class ShellPlugin : PluginLifeCycle(PluginContext())
31 |
--------------------------------------------------------------------------------
/spring/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '1.5.2.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
11 | }
12 | }
13 |
14 | apply plugin: 'io.spring.dependency-management'
15 | apply plugin: 'org.springframework.boot'
16 |
17 | dependencyManagement {
18 | imports {
19 | mavenBom 'io.spring.platform:platform-bom:Brussels-SR1'
20 | }
21 | }
22 |
23 | dependencies {
24 | compile project(':ssh')
25 | compile 'org.springframework.boot:spring-boot-autoconfigure'
26 | compile group: 'org.springframework', name: 'spring-webmvc'
27 |
28 |
29 | compileOnly group: 'org.springframework.security', name: 'spring-security-config'
30 | compileOnly group: 'org.springframework.security', name: 'spring-security-web'
31 | compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1'
32 |
33 | compileOnly group: 'org.projectlombok', name: 'lombok'
34 | }
35 |
36 | bootRepackage {
37 | enabled = false
38 | }
39 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/JeeshRestAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring;
26 |
27 | import java.io.InputStream;
28 | import java.io.OutputStream;
29 | import java.nio.charset.StandardCharsets;
30 |
31 | import net.je2sh.spring.rest.JeeshRestOptions;
32 | import net.je2sh.spring.rest.RestTerminalProvider;
33 | import org.jline.terminal.Terminal;
34 | import org.jline.terminal.impl.ExternalTerminal;
35 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
36 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
37 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
38 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
39 | import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
40 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
41 | import org.springframework.context.annotation.Bean;
42 | import org.springframework.context.annotation.ComponentScan;
43 | import org.springframework.context.annotation.Configuration;
44 | import org.springframework.core.annotation.Order;
45 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
46 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
47 | import org.springframework.security.core.context.SecurityContextHolder;
48 |
49 |
50 |
51 | @Configuration
52 | @AutoConfigureAfter(WebMvcAutoConfiguration.class)
53 | @ConditionalOnWebApplication
54 | @EnableConfigurationProperties(JeeshRestOptions.class)
55 | @ComponentScan("net.je2sh.spring.rest")
56 | public class JeeshRestAutoConfiguration {
57 |
58 | @Configuration
59 | @ConditionalOnClass(SecurityContextHolder.class)
60 | @Order(1001)
61 | public static class SecurityConfig extends WebSecurityConfigurerAdapter {
62 | @Override
63 | protected void configure(HttpSecurity http) throws Exception {
64 | http.csrf().ignoringAntMatchers("/jeesh/**");
65 | }
66 | }
67 |
68 | @Bean
69 | @ConditionalOnMissingBean(RestTerminalProvider.class)
70 | public RestTerminalProvider terminalProvider() {
71 | return (InputStream in, OutputStream out) -> new ExternalTerminal("Je2sh Terminal", "TERM",
72 | in, out,
73 | StandardCharsets.UTF_8
74 | .name(),
75 | Terminal.SignalHandler.SIG_DFL);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/JeeshSshAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring;
26 |
27 | import java.io.IOException;
28 |
29 | import net.je2sh.spring.ssh.JeeshSshOptions;
30 | import net.je2sh.spring.ssh.JeeshSshSpring;
31 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
32 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
33 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
35 | import org.springframework.boot.autoconfigure.security.SpringBootWebSecurityConfiguration;
36 | import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
37 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
38 | import org.springframework.context.annotation.Bean;
39 | import org.springframework.context.annotation.ComponentScan;
40 | import org.springframework.context.annotation.Configuration;
41 | import org.springframework.security.core.context.SecurityContextHolder;
42 |
43 |
44 |
45 | @Configuration
46 | @AutoConfigureAfter({ WebMvcAutoConfiguration.class, SpringBootWebSecurityConfiguration.class })
47 | @ConditionalOnWebApplication
48 | @ConditionalOnMissingBean(JeeshSshSpring.class)
49 | @ConditionalOnClass(SecurityContextHolder.class)
50 | @EnableConfigurationProperties(JeeshSshOptions.class)
51 | @ComponentScan("net.je2sh.spring.ssh")
52 | public class JeeshSshAutoConfiguration {
53 |
54 | @Bean
55 | public JeeshSshSpring jeeshSshSpring(JeeshSshOptions jeeshSshOptions) throws IOException {
56 | return new JeeshSshSpring(jeeshSshOptions);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/rest/CommandRequest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.rest;
26 |
27 | import java.util.List;
28 |
29 | import lombok.Data;
30 |
31 |
32 |
33 | @Data
34 | public class CommandRequest {
35 |
36 | private Integer id;
37 | private String josnrpc;
38 | private String method;
39 | private List params;
40 | }
41 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/rest/CommandResponse.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.rest;
26 |
27 | import lombok.AllArgsConstructor;
28 | import lombok.Getter;
29 | import lombok.NoArgsConstructor;
30 | import lombok.Setter;
31 |
32 |
33 |
34 | @Getter
35 | @Setter
36 | @NoArgsConstructor
37 | @AllArgsConstructor
38 | public class CommandResponse {
39 |
40 | private Integer id;
41 | private String result;
42 | private String error;
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/rest/JeeshRestOptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.rest;
26 |
27 | import lombok.Getter;
28 | import lombok.Setter;
29 | import org.springframework.boot.context.properties.ConfigurationProperties;
30 |
31 |
32 |
33 | @ConfigurationProperties(prefix = "jeesh.rest")
34 | @Getter
35 | @Setter
36 | public class JeeshRestOptions {
37 |
38 | /**
39 | * Enable exposing Jeesh commands through a REST endpoint. Defaults to {@code true}.
40 | */
41 | private boolean enabled;
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/rest/JeeshRestSpring.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.rest;
26 |
27 | import java.io.ByteArrayOutputStream;
28 | import java.io.IOException;
29 | import java.nio.charset.StandardCharsets;
30 | import java.util.ArrayList;
31 | import java.util.List;
32 |
33 | import net.je2sh.core.CommandContext;
34 | import net.je2sh.core.plugins.PluginContext;
35 | import org.jline.terminal.Terminal;
36 | import org.slf4j.Logger;
37 | import org.slf4j.LoggerFactory;
38 | import org.springframework.beans.BeansException;
39 | import org.springframework.beans.factory.annotation.Autowired;
40 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
41 | import org.springframework.context.ApplicationContext;
42 | import org.springframework.context.ApplicationContextAware;
43 | import org.springframework.web.bind.annotation.RequestBody;
44 | import org.springframework.web.bind.annotation.RequestMapping;
45 | import org.springframework.web.bind.annotation.RestController;
46 |
47 |
48 |
49 | @ConditionalOnProperty(prefix = "jeesh.rest", name = "enabled")
50 | @RestController
51 | @RequestMapping("/jeesh")
52 | public class JeeshRestSpring extends PluginContext implements ApplicationContextAware {
53 |
54 | private static final Logger log = LoggerFactory.getLogger(JeeshRestSpring.class);
55 |
56 | @Autowired
57 | private RestTerminalProvider restTerminalProvider;
58 |
59 | public JeeshRestSpring() throws IOException {
60 | }
61 |
62 | @RequestMapping("/exec")
63 | public CommandResponse exec(@RequestBody CommandRequest commandRequest)
64 | throws IOException
65 | {
66 | log.trace("Received request: {}", commandRequest);
67 | ByteArrayOutputStream resultOutputStream = new ByteArrayOutputStream();
68 |
69 | Terminal cmdTerminal = restTerminalProvider.getTerminal(System.in, resultOutputStream);
70 |
71 | List args;
72 | if (commandRequest.getParams() == null) {
73 | args = new ArrayList<>();
74 | }
75 | else {
76 | args = new ArrayList<>(commandRequest.getParams());
77 | }
78 | args.add(0, commandRequest.getMethod());
79 |
80 | getCommandManager().runCommand(commandRequest.getMethod(),
81 | new CommandContext(this, cmdTerminal),
82 | args.toArray(new String[args.size()]));
83 | cmdTerminal.writer().flush();
84 | return new CommandResponse(commandRequest.getId(),
85 | resultOutputStream.toString(StandardCharsets.UTF_8.name()),
86 | null);
87 | }
88 |
89 | @Override
90 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
91 | attribute("spring.context", applicationContext);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/rest/RestTerminalProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.rest;
26 |
27 | import java.io.IOException;
28 | import java.io.InputStream;
29 | import java.io.OutputStream;
30 |
31 | import org.jline.terminal.Terminal;
32 |
33 |
34 | @FunctionalInterface
35 | public interface RestTerminalProvider {
36 |
37 | Terminal getTerminal(InputStream in, OutputStream out) throws IOException;
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/ssh/JeeshSshOptions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.ssh;
26 |
27 | import lombok.Getter;
28 | import lombok.Setter;
29 | import org.springframework.boot.context.properties.ConfigurationProperties;
30 | import org.springframework.context.annotation.Configuration;
31 |
32 |
33 |
34 | @Configuration
35 | @ConfigurationProperties(prefix = "jeesh.ssh")
36 | @Getter
37 | @Setter
38 | public class JeeshSshOptions {
39 |
40 | /**
41 | * Enable exposing Jeesh commands through SSH. Defaults to {@code true}.
42 | */
43 | private boolean enabled;
44 |
45 | /**
46 | * Port on which to bind the SSH server
47 | */
48 | private Integer port;
49 |
50 | /**
51 | * IP address on which to bind the SSH server
52 | */
53 | private String ip;
54 | }
55 |
--------------------------------------------------------------------------------
/spring/src/main/java/net/je2sh/spring/ssh/JeeshSshSpring.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.spring.ssh;
26 |
27 | import java.io.IOException;
28 | import java.util.Properties;
29 |
30 | import net.je2sh.ssh.SshPlugin;
31 | import org.slf4j.Logger;
32 | import org.slf4j.LoggerFactory;
33 | import org.springframework.beans.BeansException;
34 | import org.springframework.context.ApplicationContext;
35 | import org.springframework.context.ApplicationContextAware;
36 | import org.springframework.context.SmartLifecycle;
37 | import org.springframework.security.core.context.SecurityContextHolder;
38 |
39 |
40 |
41 | public class JeeshSshSpring implements SmartLifecycle, ApplicationContextAware {
42 |
43 | private static final Logger log = LoggerFactory.getLogger(JeeshSshSpring.class);
44 |
45 | private final SshPlugin sshPlugin;
46 | private boolean running = false;
47 |
48 | public JeeshSshSpring(JeeshSshOptions options) throws IOException {
49 | Properties props = new Properties();
50 | props.put(SshPlugin.IP_KEY, options.getIp());
51 | props.put(SshPlugin.PORT_KEY, options.getPort());
52 | this.sshPlugin = new SshPlugin(props, SecurityContextHolder.getContext().getAuthentication());
53 | }
54 |
55 | @Override
56 | public boolean isAutoStartup() {
57 | return true;
58 | }
59 |
60 | @Override
61 | public void stop(Runnable callback) {
62 | stop();
63 | callback.run();
64 | }
65 |
66 | @Override
67 | public void start() {
68 | sshPlugin.start();
69 | running = true;
70 | }
71 |
72 | @Override
73 | public void stop() {
74 | sshPlugin.stop();
75 | running = false;
76 | }
77 |
78 | @Override
79 | public boolean isRunning() {
80 | return running;
81 | }
82 |
83 | @Override
84 | public int getPhase() {
85 | return 0;
86 | }
87 |
88 | @Override
89 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
90 | this.sshPlugin.getContext().attribute("spring.context", applicationContext);
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/spring/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | net.je2sh.spring.JeeshSshAutoConfiguration,\
3 | net.je2sh.spring.JeeshRestAutoConfiguration
4 |
--------------------------------------------------------------------------------
/spring/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | jeesh:
2 | ssh:
3 | enabled: true
4 | port: 2002
5 | ip: 127.0.0.1
6 | rest:
7 | enabled: true
8 | root-protection: true
9 | command-protection: true
10 |
--------------------------------------------------------------------------------
/ssh/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'application'
2 | apply plugin: 'groovy'
3 |
4 | dependencies {
5 | compile project(':core')
6 | compile group: 'org.jline', name: 'jline-remote-ssh', version: '3.3.1'
7 | compile ('org.apache.sshd:apache-sshd:1.4.0') {
8 | exclude group: 'org.slf4j'
9 | }
10 |
11 | runtime project(':base-plugins')
12 |
13 | testCompile project(':test')
14 | testCompile group: 'org.spockframework', name: 'spock-core', version: '1.1-groovy-2.4'
15 | testCompile group: 'com.jcraft', name: 'jsch', version: '0.1.54'
16 | testCompile group: 'org.apache.commons', name: 'commons-io', version: '1.3.2'
17 |
18 | testCompile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6'
19 |
20 | testRuntime group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.25'
21 |
22 | }
23 |
24 | mainClassName = 'net.je2sh.core.Main'
25 |
26 |
--------------------------------------------------------------------------------
/ssh/src/main/java/net/je2sh/ssh/SshPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.ssh;
26 |
27 | import java.io.File;
28 | import java.io.IOException;
29 | import java.security.Principal;
30 | import java.util.Objects;
31 | import java.util.Properties;
32 | import java.util.concurrent.Executors;
33 |
34 | import net.je2sh.core.CommandContext;
35 | import net.je2sh.core.JeeShell;
36 | import net.je2sh.core.plugins.PluginContext;
37 | import net.je2sh.core.plugins.PluginLifeCycle;
38 | import org.apache.sshd.server.SshServer;
39 | import org.apache.sshd.server.auth.password.PasswordAuthenticator;
40 | import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
41 | import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
42 | import org.apache.sshd.server.session.ServerSession;
43 | import org.jline.builtins.ssh.ShellCommand;
44 | import org.jline.builtins.ssh.ShellFactoryImpl;
45 | import org.jline.builtins.ssh.Ssh;
46 | import org.jline.terminal.Terminal;
47 | import org.jline.terminal.TerminalBuilder;
48 | import org.slf4j.Logger;
49 | import org.slf4j.LoggerFactory;
50 |
51 |
52 |
53 | /**
54 | * Plugin that allows access to the available commands through SSH.
55 | *
56 | * This plugin creates a {@link SshServer} and manages its lifecycle.
57 | */
58 | public class SshPlugin extends PluginLifeCycle implements PasswordAuthenticator {
59 |
60 | private static final Logger log = LoggerFactory.getLogger(SshPlugin.class);
61 | public static final String PROPERTIES_FILE = "jeesh/jeesh.properties";
62 | public static final String KEY_FILE = "jeesh/hostkey.pem";
63 | public static final String PORT_KEY = "jeesh.ssh.port";
64 | public static final String IP_KEY = "jeesh.ssh.ip";
65 |
66 | private final SshServer server;
67 | private Principal principal;
68 |
69 | public SshPlugin() throws IOException {
70 | this(null, null);
71 | }
72 |
73 | public SshPlugin(Properties properties, Principal principal) throws IOException {
74 | super(new PluginContext(Executors.newSingleThreadExecutor()));
75 | getContext().setPrincipal(principal);
76 |
77 | ClassLoader classLoader = this.getClass().getClassLoader();
78 |
79 | if (properties == null) {
80 | properties = new Properties();
81 | properties.load(classLoader.getResourceAsStream(PROPERTIES_FILE));
82 | }
83 |
84 | SimpleGeneratorHostKeyProvider keyPairProvider =
85 | new SimpleGeneratorHostKeyProvider(new File(
86 | classLoader.getResource(KEY_FILE).getPath()));
87 | Object port = properties.getOrDefault(PORT_KEY, 2022);
88 | Object ip = properties.getOrDefault(IP_KEY, "127.0.0.1");
89 | log.debug("Binding SSH Server to {}:{}", ip, port);
90 |
91 | server = SshServer.setUpDefaultServer();
92 | server.setPort(Integer.valueOf(port.toString()));
93 | server.setHost((String) ip);
94 | server.setShellFactory(new ShellFactoryImpl(this::shell));
95 | server.setCommandFactory(command -> new ShellCommand(this::execute, command));
96 | server.setKeyPairProvider(keyPairProvider);
97 | server.setPasswordAuthenticator(this);
98 | }
99 |
100 | @Override
101 | public boolean authenticate(String username, String password, ServerSession session)
102 | throws PasswordChangeRequiredException
103 | {
104 | return Objects.equals(username, "admin") && Objects.equals(password, "admin");
105 | }
106 |
107 | @Override
108 | public void run() {
109 | try {
110 | log.debug("Starting SSH Server");
111 | server.start();
112 | }
113 | catch (IOException e) {
114 | log.error("Failure running the SSH Server", e);
115 | throw new RuntimeException(e);
116 | }
117 | }
118 |
119 | @Override
120 | public void close() {
121 | try {
122 | log.debug("Stopping SSH Server");
123 | server.stop(true);
124 | }
125 | catch (IOException e) {
126 | log.error("Unable to gracefully stop SSH server", e);
127 | }
128 | finally {
129 | super.close();
130 | }
131 | }
132 |
133 | private void shell(Ssh.ShellParams params) {
134 | log.info("Starting shell");
135 | new JeeShell(getContext(), params.getTerminal(), getContext().getCommandManager())
136 | .run();
137 | params.getCloser().run();
138 | }
139 |
140 | private void execute(Ssh.ExecuteParams params) {
141 | log.info("Execute received {}", params);
142 | try {
143 | Terminal terminal = TerminalBuilder.builder()
144 | .streams(params.getIn(), params.getOut())
145 | .build();
146 | String[] args = params.getCommand().split(" ");
147 | getContext().getCommandManager().runCommand(args[0],
148 | new CommandContext(getContext(), terminal),
149 | args);
150 | terminal.flush();
151 | }
152 | catch (IOException e) {
153 | log.error("Unable to execute command", e);
154 | }
155 | }
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/ssh/src/main/resources/jeesh/hostkey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIICXAIBAAKBgQDdfIWeSV4o68dRrKSzFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDP
3 | jXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHj
4 | W5q4OOgWhVvj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQIDAQAB
5 | AoGBANG3JDW6NoP8rF/zXoeLgLCj+tfVUPSczhGFVrQkAk4mWfyRkhN0WlwHFOec
6 | K89MpkV1ij/XPVzU4MNbQ2yod1KiDylzvweYv+EaEhASCmYNs6LS03punml42SL9
7 | 97tOmWfVJXxlQoLiY6jHPU97vTc65k8gL+gmmrpchsW0aqmZAkEA/c8zfmKvY37T
8 | cxcLLwzwsqqH7g2KZGTf9aRmx2ebdW+QKviJJhbdluDgl1TNNFj5vCLznFDRHiqJ
9 | wq0wkZ39cwJBAN9l5v3kdXj21UrurNPdlV0n2GZBt2vblooQC37XHF97r2zM7Ou+
10 | Lg6MyfJClyguhWL9dxnGbf3btQ0l3KDstxMCQCRaiEqjAfIjWVATzeNIXDWLHXso
11 | b1kf5cA+cwY+vdKdTy4IeUR+Y/DXdvPWDqpf0C11aCVMohdLCn5a5ikFUycCQDhV
12 | K/BuAallJNfmY7JxN87r00fF3ojWMJnT/fIYMFFrkQrwifXQWTDWE76BSDibsosJ
13 | u1TGksnm8zrDh2UVC/0CQFrHTiSl/3DHvWAbOJawGKg46cnlDcAhSyV8Frs8/dlP
14 | 7YGG3eqkw++lsghqmFO6mRUTKsBmiiB2wgLGhL5pyYY=
15 | -----END RSA PRIVATE KEY-----
16 |
--------------------------------------------------------------------------------
/ssh/src/main/resources/jeesh/jeesh.properties:
--------------------------------------------------------------------------------
1 | jeesh.ssh.port=2001
2 | jeesh.ssh.ip=127.0.0.1
3 |
--------------------------------------------------------------------------------
/ssh/src/test/groovy/net/je2sh/ssh/SshPluginTests.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.ssh
26 |
27 | import com.jcraft.jsch.ChannelExec
28 | import com.jcraft.jsch.JSch
29 | import com.jcraft.jsch.Session
30 | import groovy.util.logging.Slf4j
31 | import net.je2sh.test.TestUtils
32 | import org.apache.commons.io.IOUtils
33 | import spock.lang.Ignore
34 | import spock.lang.Shared
35 | import spock.lang.Specification
36 |
37 | @Slf4j
38 | class SshPluginTests extends Specification {
39 |
40 | @Shared
41 | SshPlugin sshPlugin
42 |
43 | @Shared
44 | Integer sshdPort
45 |
46 | Session session
47 | ChannelExec channel
48 |
49 | def setupSpec() {
50 | sshdPort = TestUtils.findAvailablePort()
51 | log.info("Starting test server on port {}", sshdPort)
52 | def props = new Properties()
53 | props.putAll([(SshPlugin.PORT_KEY): sshdPort])
54 | sshPlugin = new SshPlugin(props, null)
55 | sshPlugin.start()
56 | Thread.sleep(500)
57 | }
58 |
59 | def cleanupSpec() {
60 | sshPlugin?.close()
61 | }
62 |
63 | def setup() {
64 | String host = '127.0.0.1'
65 | String user = 'admin'
66 | JSch jsch = new JSch();
67 | session = jsch.getSession(user, host, sshdPort)
68 | session.password = 'admin'
69 | session.setConfig("StrictHostKeyChecking", "no");
70 |
71 | session.connect()
72 |
73 | channel = session.openChannel('exec')
74 | }
75 |
76 | def cleanup() {
77 | session.disconnect()
78 | }
79 |
80 | @Ignore('This test is currently flapping. Need to investigate why')
81 | def 'Running "help" command should succeed'() {
82 | when:
83 | channel.command = 'help'
84 | channel.inputStream = null
85 | channel.connect()
86 |
87 | def lines = IOUtils.readLines(channel.inputStream)
88 |
89 | channel.disconnect()
90 |
91 | then:
92 | lines[0].contains('List of available commands.')
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/test/build.gradle:
--------------------------------------------------------------------------------
1 | dependencies {
2 | compile project(':core')
3 | compile group: 'cglib', name: 'cglib-nodep', version: '3.2.5'
4 | compile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/test/src/main/java/net/je2sh/test/TestUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2017 JeeSh
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package net.je2sh.test;
26 |
27 | import static org.mockito.Mockito.mock;
28 | import static org.mockito.Mockito.when;
29 |
30 | import java.io.IOException;
31 | import java.io.PrintWriter;
32 | import java.net.ServerSocket;
33 |
34 | import com.beust.jcommander.JCommander;
35 | import net.je2sh.core.AbstractCommand;
36 | import org.jline.terminal.Terminal;
37 |
38 |
39 |
40 | public class TestUtils {
41 |
42 | public static void parseCommand(String name, AbstractCommand cmd, String... args) {
43 | JCommander.newBuilder()
44 | .addObject(cmd)
45 | .programName(name)
46 | .build()
47 | .parse(args);
48 | }
49 |
50 | public static Terminal mockedTerminal() {
51 | return mockedTerminal(mockedWriter());
52 | }
53 |
54 | public static Terminal mockedTerminal(PrintWriter writer) {
55 | Terminal mockedTerminal = mock(Terminal.class);
56 | when(mockedTerminal.writer()).thenReturn(writer);
57 | return mockedTerminal;
58 | }
59 |
60 | public static PrintWriter mockedWriter() {
61 | return mock(PrintWriter.class);
62 | }
63 |
64 | public static boolean mockitoAssert(Object result) {
65 | return result == null;
66 | }
67 |
68 | public static Integer findAvailablePort() {
69 | while(true) {
70 | try (ServerSocket socket = new ServerSocket(0)) {
71 | return socket.getLocalPort();
72 | }
73 | catch (IOException e) {
74 | // noop
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------