Skip to content

Commit 71f0f98

Browse files
authored
Merge pull request #1665 from jline/feat/modernize-graal-module
feat: Modernize graal module — Shell API, dual FFM/JNI profiles, automated smoke test
2 parents 7219e4d + 610af9c commit 71f0f98

File tree

8 files changed

+185
-134
lines changed

8 files changed

+185
-134
lines changed

graal/pom.xml

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,15 @@
1414
<parent />
1515

1616
<artifactId>jline-graal</artifactId>
17-
<name>JLine Graal Demo</name>
17+
<name>JLine Native Demo</name>
1818

1919
<properties>
2020
<automatic.module.name>org.jline.graal</automatic.module.name>
2121
</properties>
2222

2323
<dependencies>
2424
<dependency>
25-
<groupId>org.jline</groupId>
26-
<artifactId>jline-terminal-jni</artifactId>
27-
</dependency>
28-
<dependency>
29-
<artifactId>jline-reader</artifactId>
30-
</dependency>
31-
<dependency>
32-
<artifactId>jline-console</artifactId>
25+
<artifactId>jline-shell</artifactId>
3326
</dependency>
3427

3528
<dependency>
@@ -40,11 +33,6 @@
4033
<groupId>org.slf4j</groupId>
4134
<artifactId>slf4j-jdk14</artifactId>
4235
</dependency>
43-
<dependency>
44-
<groupId>org.graalvm.sdk</groupId>
45-
<artifactId>graal-sdk</artifactId>
46-
<scope>provided</scope>
47-
</dependency>
4836
</dependencies>
4937

5038
<build>
@@ -65,24 +53,83 @@
6553
</executions>
6654
</plugin>
6755
<plugin>
68-
<groupId>org.graalvm.nativeimage</groupId>
69-
<artifactId>native-image-maven-plugin</artifactId>
56+
<groupId>org.graalvm.buildtools</groupId>
57+
<artifactId>native-maven-plugin</artifactId>
7058
<configuration>
7159
<skip>${native.image.skip}</skip>
7260
<imageName>graal</imageName>
7361
<mainClass>org.jline.demo.graal.Graal</mainClass>
74-
<buildArgs />
7562
</configuration>
7663
<executions>
7764
<execution>
65+
<id>build-native</id>
7866
<goals>
79-
<goal>native-image</goal>
67+
<goal>compile-no-fork</goal>
8068
</goals>
8169
<phase>package</phase>
8270
</execution>
8371
</executions>
8472
</plugin>
73+
<plugin>
74+
<groupId>org.codehaus.mojo</groupId>
75+
<artifactId>exec-maven-plugin</artifactId>
76+
<executions>
77+
<execution>
78+
<id>verify-native-image</id>
79+
<goals>
80+
<goal>exec</goal>
81+
</goals>
82+
<phase>verify</phase>
83+
<configuration>
84+
<skip>${native.image.skip}</skip>
85+
<executable>${project.build.directory}/graal</executable>
86+
<arguments>
87+
<argument>--check</argument>
88+
</arguments>
89+
</configuration>
90+
</execution>
91+
</executions>
92+
</plugin>
8593
</plugins>
8694
</build>
8795

96+
<profiles>
97+
<profile>
98+
<id>native-image-ffm</id>
99+
<properties>
100+
<java.release.version>22</java.release.version>
101+
</properties>
102+
<dependencies>
103+
<dependency>
104+
<groupId>org.jline</groupId>
105+
<artifactId>jline-terminal-ffm</artifactId>
106+
<version>${project.version}</version>
107+
</dependency>
108+
</dependencies>
109+
<build>
110+
<plugins>
111+
<plugin>
112+
<groupId>org.graalvm.buildtools</groupId>
113+
<artifactId>native-maven-plugin</artifactId>
114+
<configuration>
115+
<buildArgs>
116+
<arg>--enable-native-access=ALL-UNNAMED</arg>
117+
</buildArgs>
118+
</configuration>
119+
</plugin>
120+
</plugins>
121+
</build>
122+
</profile>
123+
<profile>
124+
<id>native-image-jni</id>
125+
<dependencies>
126+
<dependency>
127+
<groupId>org.jline</groupId>
128+
<artifactId>jline-terminal-jni</artifactId>
129+
<version>${project.version}</version>
130+
</dependency>
131+
</dependencies>
132+
</profile>
133+
</profiles>
134+
88135
</project>

graal/src/main/java/org/jline/demo/graal/Graal.java

Lines changed: 53 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -8,121 +8,81 @@
88
*/
99
package org.jline.demo.graal;
1010

11-
import java.io.File;
12-
import java.nio.file.Path;
1311
import java.nio.file.Paths;
14-
import java.util.*;
15-
import java.util.function.Supplier;
16-
import java.util.logging.LogManager;
1712

18-
import org.jline.builtins.ConfigurationPath;
19-
import org.jline.console.impl.Builtins;
20-
import org.jline.console.impl.Builtins.Command;
21-
import org.jline.console.impl.SystemRegistryImpl;
22-
import org.jline.keymap.KeyMap;
23-
import org.jline.reader.*;
24-
import org.jline.reader.LineReader.Option;
25-
import org.jline.reader.impl.DefaultParser;
13+
import org.jline.reader.LineReader;
14+
import org.jline.shell.Shell;
2615
import org.jline.terminal.Terminal;
27-
import org.jline.terminal.Terminal.Signal;
2816
import org.jline.terminal.TerminalBuilder;
2917
import org.jline.terminal.spi.TerminalExt;
18+
import org.jline.terminal.spi.TerminalProvider;
3019
import org.jline.utils.OSUtils;
31-
import org.jline.widget.TailTipWidgets;
32-
import org.jline.widget.TailTipWidgets.TipType;
33-
import org.jline.widget.Widgets;
3420

3521
public class Graal {
3622

3723
public static void main(String[] args) {
24+
if (args.length > 0 && "--check".equals(args[0])) {
25+
check();
26+
return;
27+
}
3828
try {
39-
// Init log
40-
String fname = System.getProperty("java.util.logging.config.file");
41-
if (fname != null) {
42-
LogManager.getLogManager().readConfiguration();
43-
}
44-
Supplier<Path> workDir = () -> Paths.get(System.getProperty("user.dir"));
45-
//
46-
// Parser & Terminal
47-
//
48-
DefaultParser parser = new DefaultParser();
49-
parser.setEofOnUnclosedQuote(true);
50-
parser.setEscapeChars(null);
51-
parser.setRegexVariable(null); // we do not have console variables!
5229
Terminal terminal = TerminalBuilder.builder().build();
53-
Thread executeThread = Thread.currentThread();
54-
terminal.handle(Signal.INT, signal -> executeThread.interrupt());
55-
//
56-
// Command registries
57-
//
58-
File file = new File(Graal.class
59-
.getProtectionDomain()
60-
.getCodeSource()
61-
.getLocation()
62-
.toURI()
63-
.getPath());
64-
String root = file.getCanonicalPath();
65-
root = root.substring(0, root.length() - 6);
66-
ConfigurationPath configPath = new ConfigurationPath(Paths.get(root), Paths.get(root));
67-
Set<Builtins.Command> commands = new HashSet<>(Arrays.asList(Builtins.Command.values()));
68-
commands.remove(Command.TTOP); // ttop command is not supported in GraalVM
69-
Builtins builtins = new Builtins(commands, workDir, configPath, null);
70-
SystemRegistryImpl systemRegistry = new SystemRegistryImpl(parser, terminal, workDir, configPath);
71-
systemRegistry.setCommandRegistries(builtins);
72-
//
73-
// LineReader
74-
//
75-
LineReader reader = LineReaderBuilder.builder()
30+
31+
System.out.println(terminal.getName() + ": " + terminal.getType() + ", provider="
32+
+ ((TerminalExt) terminal).getProvider().name());
33+
34+
Shell shell = Shell.builder()
7635
.terminal(terminal)
77-
.completer(systemRegistry.completer())
78-
.parser(parser)
36+
.prompt("graal> ")
37+
.helpCommands(true)
38+
.historyCommands(true)
39+
.optionCommands(true)
40+
.variableCommands(true)
41+
.commandHighlighter(true)
42+
.historyFile(Paths.get(System.getProperty("user.home"), ".jline-graal-history"))
43+
.option(LineReader.Option.INSERT_BRACKET, true)
44+
.option(LineReader.Option.EMPTY_WORD_OPTIONS, false)
45+
.option(LineReader.Option.USE_FORWARD_SLASH, true)
46+
.option(LineReader.Option.DISABLE_EVENT_EXPANSION, true)
7947
.variable(LineReader.SECONDARY_PROMPT_PATTERN, "%M%P > ")
8048
.variable(LineReader.INDENTATION, 2)
8149
.variable(LineReader.LIST_MAX, 100)
82-
.variable(LineReader.HISTORY_FILE, Paths.get(root, "history"))
83-
.option(Option.INSERT_BRACKET, true)
84-
.option(Option.EMPTY_WORD_OPTIONS, false)
85-
.option(Option.USE_FORWARD_SLASH, true) // use forward slash in directory separator
86-
.option(Option.DISABLE_EVENT_EXPANSION, true)
50+
.onReaderReady(reader -> {
51+
if (OSUtils.IS_WINDOWS) {
52+
reader.setVariable(LineReader.BLINK_MATCHING_PAREN, 0);
53+
}
54+
})
8755
.build();
88-
if (OSUtils.IS_WINDOWS) {
89-
reader.setVariable(
90-
LineReader.BLINK_MATCHING_PAREN, 0); // if enabled cursor remains in begin parenthesis (gitbash)
91-
}
92-
//
93-
// complete command registries
94-
//
95-
builtins.setLineReader(reader);
96-
//
97-
// widgets and console initialization
98-
//
99-
new TailTipWidgets(reader, systemRegistry::commandDescription, 5, TipType.COMPLETER);
100-
KeyMap<Binding> keyMap = reader.getKeyMaps().get("main");
101-
keyMap.bind(new Reference(Widgets.TAILTIP_TOGGLE), KeyMap.alt("s"));
102-
//
103-
// REPL-loop
104-
//
105-
System.out.println(terminal.getName() + ": " + terminal.getType() + ", provider="
106-
+ ((TerminalExt) terminal).getProvider().name());
107-
while (true) {
56+
57+
shell.run();
58+
} catch (Throwable t) {
59+
t.printStackTrace();
60+
}
61+
}
62+
63+
/**
64+
* Verify that a terminal provider can be loaded and used.
65+
* This is used as a smoke test for native image builds.
66+
*/
67+
private static void check() {
68+
try {
69+
TerminalProvider provider = null;
70+
for (String name : new String[] {"ffm", "jni"}) {
10871
try {
109-
systemRegistry.cleanUp(); // reset output streams
110-
String line = reader.readLine("graal> ");
111-
Object result = systemRegistry.execute(line);
112-
if (result != null) {
113-
System.out.println(result);
114-
}
115-
} catch (UserInterruptException e) {
116-
// Ignore
117-
} catch (EndOfFileException e) {
72+
provider = TerminalProvider.load(name);
11873
break;
119-
} catch (Exception e) {
120-
systemRegistry.trace(true, e); // print exception
74+
} catch (Throwable ignored) {
12175
}
12276
}
123-
systemRegistry.close();
77+
if (provider == null) {
78+
throw new IllegalStateException("No terminal provider found");
79+
}
80+
System.out.println("Provider loaded: " + provider.name());
81+
System.out.println("CHECK PASSED");
12482
} catch (Throwable t) {
125-
t.printStackTrace();
83+
System.err.println("CHECK FAILED: " + t.getMessage());
84+
t.printStackTrace(System.err);
85+
System.exit(1);
12686
}
12787
}
12888
}

pom.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
<picocli.version>4.7.7</picocli.version>
9999
<graal.version>25.0.2</graal.version>
100100
<graal.plugin.version>21.2.0</graal.plugin.version>
101+
<native.plugin.version>0.10.6</native.plugin.version>
101102
<palantir.version>2.89.0</palantir.version>
102103

103104
<surefire.argLine>--add-opens java.base/java.io=org.jline.nativ --add-opens java.base/java.io=org.jline.terminal</surefire.argLine>
@@ -309,6 +310,11 @@
309310
<artifactId>native-image-maven-plugin</artifactId>
310311
<version>${graal.plugin.version}</version>
311312
</plugin>
313+
<plugin>
314+
<groupId>org.graalvm.buildtools</groupId>
315+
<artifactId>native-maven-plugin</artifactId>
316+
<version>${native.plugin.version}</version>
317+
</plugin>
312318
<plugin>
313319
<groupId>org.apache.maven.plugins</groupId>
314320
<artifactId>maven-enforcer-plugin</artifactId>
@@ -602,7 +608,13 @@
602608
</profile>
603609

604610
<profile>
605-
<id>native-image</id>
611+
<id>native-image-ffm</id>
612+
<properties>
613+
<native.image.skip>false</native.image.skip>
614+
</properties>
615+
</profile>
616+
<profile>
617+
<id>native-image-jni</id>
606618
<properties>
607619
<native.image.skip>false</native.image.skip>
608620
</properties>

terminal-ffm/src/main/resources/META-INF/native-image/org.jline/jline-terminal-ffm/native-image.properties

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"reflection": [
3+
{
4+
"type": "org.jline.terminal.impl.ffm.FfmTerminalProvider",
5+
"allDeclaredConstructors": true,
6+
"allPublicConstructors": true
7+
}
8+
],
9+
"resources": [
10+
{"glob": "META-INF/services/org.jline.terminal.spi.TerminalProvider"},
11+
{"glob": "META-INF/jline/providers/ffm"}
12+
],
13+
"foreign": {
14+
"downcalls": [
15+
{
16+
"returnType": "int",
17+
"parameterTypes": ["int", "long long", "void*"],
18+
"options": {
19+
"firstVariadicArg": 2
20+
}
21+
},
22+
{
23+
"returnType": "int",
24+
"parameterTypes": ["int"]
25+
},
26+
{
27+
"returnType": "int",
28+
"parameterTypes": ["int", "int", "void*"]
29+
},
30+
{
31+
"returnType": "int",
32+
"parameterTypes": ["int", "void*"]
33+
},
34+
{
35+
"returnType": "int",
36+
"parameterTypes": ["int", "void*", "long long"]
37+
},
38+
{
39+
"returnType": "int",
40+
"parameterTypes": ["void*", "void*", "void*", "void*", "void*"]
41+
}
42+
]
43+
}
44+
}

terminal-ffm/src/main/resources/META-INF/native-image/org.jline/jline-terminal-ffm/reflection-config.json

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)