g-python shell part1

This commit is contained in:
sirjonasxx 2020-10-19 02:00:39 +02:00
parent f5c8422da1
commit dccf2a573d
9 changed files with 343 additions and 15 deletions

View File

@ -164,6 +164,14 @@
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.0-alpha0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.maven/maven-artifact -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.6.3</version>
</dependency>
</dependencies>
<repositories>

View File

@ -1,9 +1,165 @@
package gearth.services.gpython;
import gearth.Main;
import gearth.ui.extra.ExtraController;
import javafx.application.Platform;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Region;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
public class GPythonShell {
public void launch() {
private final String extensionName;
private final String cookie;
public GPythonShell(String extensionName, String cookie) {
this.extensionName = extensionName;
this.cookie = cookie;
}
public void launch(OnQtConsoleLaunch onLaunch) {
new Thread(() -> {
try {
// launch the jupyter console
ProcessBuilder gConsoleBuilder = new ProcessBuilder("python", "-m", "jupyter", "console", "--simple-prompt");
Process gConsole = gConsoleBuilder.start();
InputStreamReader in = new InputStreamReader(gConsole.getInputStream());
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(gConsole.getOutputStream()));
readUntilExpectInput(in);
// obtain jupyter kernel name
List<String> sysargs = enterCommandAndAwait(out, in, "import sys; sys.argv");
String kernelName = extractKernelName(sysargs);
onLaunch.launched(false);
}
catch (Exception e) {
e.printStackTrace();
showError();
onLaunch.launched(true);
}
}).start();
}
private List<String> readUntilExpectInput(InputStreamReader in) throws IOException {
List<String> readings = new ArrayList<>();
StringBuilder builder = new StringBuilder();
int c;
while ((c = in.read()) != -1) {
char character = (char)c;
if (character == '\n') {
String reading = builder.toString();
if (reading.endsWith("\r")) {
reading = reading.substring(0, reading.length() - 1);
}
if (reading.matches("Out\\[[0-9+]]: .*")) {
reading = reading.replaceAll("^Out\\[[0-9+]]: ", "");
if (reading.equals("")) {
builder = new StringBuilder();
continue;
}
}
readings.add(reading);
builder = new StringBuilder();
}
else {
builder.append(character);
if (builder.toString().matches("In \\[[0-9]+]: ") && !in.ready()) {
return readings;
}
}
}
return null;
}
private void enterCommand(BufferedWriter out, String command) throws IOException {
out.write(command);
out.newLine();
out.flush();
}
private List<String> enterCommandAndAwait(BufferedWriter out, InputStreamReader in, String command) throws IOException {
enterCommand(out, command);
return readUntilExpectInput(in);
}
private String extractKernelName(List<String> inputArgs) {
// null if not found
String joined = String.join("", inputArgs);
String paramsFull = joined.replaceAll("^[^\\[]*\\[", "").replaceAll("][^]]*$", "");
List<String> params = new ArrayList<>();
boolean backslashed = false;
int beginParameterIndex = -1;
for (int i = 0; i < paramsFull.length(); i++) {
char c = paramsFull.charAt(i);
if (c == '\'' && !backslashed) {
if (beginParameterIndex == -1) {
beginParameterIndex = i + 1;
}
else {
params.add(paramsFull.substring(beginParameterIndex, i));
beginParameterIndex = -1;
}
}
backslashed = c == '\\' && !backslashed;
}
for (int i = 0; i < params.size() - 1; i++) {
if (params.get(i).equals("-f")) {
return params.get(i+1);
}
}
return null;
}
private void showError() {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python error", ButtonType.OK);
alert.setTitle("G-Python error");
FlowPane fp = new FlowPane();
Label lbl = new Label("Something went wrong launching the G-Python shell," +
System.lineSeparator() + "are you sure you followed the installation guide correctly?" +
System.lineSeparator() + System.lineSeparator() + "More information here:");
Hyperlink link = new Hyperlink(ExtraController.INFO_URL_GPYTHON);
fp.getChildren().addAll(lbl, link);
link.setOnAction(event -> {
Main.main.getHostServices().showDocument(link.getText());
event.consume();
});
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(fp);
alert.show();
});
}
public String getExtensionName() {
return extensionName;
}
public static void main(String[] args) throws IOException {
GPythonShell shell = new GPythonShell("test", "cookie");
shell.launch((b) -> {
System.out.println("launched");
});
}
}

View File

@ -0,0 +1,96 @@
package gearth.services.gpython;
import org.apache.maven.artifact.versioning.ComparableVersion;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class GPythonVersionUtils {
private static final String MIN_GPYTHON_VERSION = "0.1";
private static final String MIN_PYTHON_VERSION = "3.2";
// returns null if python not installed
public static String pythonVersion() {
List<String> commandOutput = executeCommand("python", "--version");
if (commandOutput.size() == 0) {
return null;
}
String maybeVersion = commandOutput.get(0);
if (!maybeVersion.contains("Python")) {
return null;
}
return maybeVersion.split(" ")[1];
}
public static boolean validInstallation() {
// validates if user has all dependencies installed
String pythonVersion = pythonVersion();
if (pythonVersion == null) {
return false;
}
ComparableVersion version = new ComparableVersion(pythonVersion);
if (version.compareTo(new ComparableVersion(MIN_PYTHON_VERSION)) < 0) {
return false;
}
List<String> allPackages = executeCommand("python", "-m", "pip", "list");
allPackages = allPackages.subList(2, allPackages.size());
String qtconsole = getPackageVersion(allPackages, "qtconsole");
String pyqt5 = getPackageVersion(allPackages, "pyqt5");
String jupyterConsole = getPackageVersion(allPackages, "jupyter-console");
String gPython = getPackageVersion(allPackages, "g-python");
if (qtconsole == null || pyqt5 == null || jupyterConsole == null || gPython == null) {
return false;
}
ComparableVersion gVersion = new ComparableVersion(gPython);
return gVersion.compareTo(new ComparableVersion(MIN_GPYTHON_VERSION)) >= 0;
}
// null if not found
private static String getPackageVersion(List<String> allPackages, String pkg) {
pkg = pkg.toLowerCase();
for (String maybePkg : allPackages) {
String[] split = maybePkg.split(" +");
if (split[0].toLowerCase().equals(pkg)) {
return split[1];
}
}
return null;
}
private static List<String> executeCommand(String... command) {
List<String> output = new ArrayList<>();
try {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.add(line);
}
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return output;
}
// public static void main(String[] args) {
// System.out.println(validInstallation());
// }
}

View File

@ -1,4 +0,0 @@
package gearth.services.gpython;
public class JupyterConsole {
}

View File

@ -0,0 +1,7 @@
package gearth.services.gpython;
public interface OnQtConsoleLaunch {
void launched(boolean failed);
}

View File

@ -1,4 +0,0 @@
package gearth.services.gpython;
public class PythonUtils {
}

View File

@ -1,5 +1,6 @@
package gearth.ui.extensions;
import gearth.Main;
import gearth.services.extensionhandler.ExtensionConnectedListener;
import gearth.services.extensionhandler.ExtensionHandler;
import gearth.services.extensionhandler.extensions.ExtensionListener;
@ -9,18 +10,21 @@ import gearth.services.extensionhandler.extensions.implementations.network.execu
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunner;
import gearth.services.extensionhandler.extensions.implementations.network.executer.ExtensionRunnerFactory;
import gearth.services.gpython.GPythonShell;
import gearth.services.gpython.OnQtConsoleLaunch;
import gearth.ui.SubForm;
import gearth.ui.extensions.logger.ExtensionLogger;
import gearth.ui.extra.ExtraController;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import java.io.File;
import java.io.IOException;
/**
* Created by Jonas on 06/04/18.
@ -103,10 +107,24 @@ public class ExtensionsController extends SubForm {
@Override
protected void onTabOpened() {
btn_gpython.setDisable(!parentController.extraController.useGPython());
updateGPythonStatus();
}
public void updateGPythonStatus() {
if (!pythonShellLaunching) {
btn_gpython.setDisable(!parentController.extraController.useGPython());
}
}
private volatile boolean pythonShellLaunching = false;
public void gpythonBtnClicked(ActionEvent actionEvent) {
new GPythonShell().launch();
pythonShellLaunching = true;
Platform.runLater(() -> btn_gpython.setDisable(true));
GPythonShell shell = new GPythonShell("test", "cookie");
shell.launch((b) -> {
pythonShellLaunching = false;
Platform.runLater(this::updateGPythonStatus);
});
}
}

View File

@ -1,15 +1,21 @@
package gearth.ui.extra;
import gearth.Main;
import gearth.misc.Cacher;
import gearth.protocol.HConnection;
import gearth.protocol.connection.HState;
import gearth.protocol.connection.proxy.ProxyProviderFactory;
import gearth.protocol.connection.proxy.SocksConfiguration;
import gearth.services.gpython.GPythonVersionUtils;
import gearth.ui.SubForm;
import gearth.ui.info.InfoController;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.control.*;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.web.WebView;
import org.json.JSONObject;
/**
@ -17,6 +23,8 @@ import org.json.JSONObject;
*/
public class ExtraController extends SubForm implements SocksConfiguration {
public static final String INFO_URL_GPYTHON = "www.placeholder.com";
public static final String NOTEPAD_CACHE_KEY = "notepad_text";
public static final String SOCKS_CACHE_KEY = "socks_config";
public static final String GPYTHON_CACHE_KEY = "use_gpython";
@ -143,4 +151,47 @@ public class ExtraController extends SubForm implements SocksConfiguration {
public boolean useGPython() {
return cbx_gpython.isSelected();
}
public void gpythonCbxClick(ActionEvent actionEvent) {
if (cbx_gpython.isSelected()) {
new Thread(() -> {
Platform.runLater(() -> {
cbx_gpython.setSelected(false);
cbx_gpython.setDisable(true);
});
if (!GPythonVersionUtils.validInstallation()) {
Platform.runLater(() -> {
Alert alert = new Alert(Alert.AlertType.ERROR, "G-Python installation", ButtonType.OK);
alert.setTitle("G-Python installation");
FlowPane fp = new FlowPane();
Label lbl = new Label("Before using G-Python, install the right packages using pip!" +
System.lineSeparator() + System.lineSeparator() + "More information here:");
Hyperlink link = new Hyperlink(INFO_URL_GPYTHON);
fp.getChildren().addAll( lbl, link);
link.setOnAction(event -> {
Main.main.getHostServices().showDocument(link.getText());
event.consume();
});
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
alert.getDialogPane().setContent(fp);
alert.show();
cbx_gpython.setDisable(false);
});
}
else {
Platform.runLater(() -> {
cbx_gpython.setSelected(true);
cbx_gpython.setDisable(false);
parentController.extensionsController.updateGPythonStatus();
});
}
}).start();
}
}
}

View File

@ -112,7 +112,7 @@
<Insets top="2.0" />
</padding>
</CheckBox>
<CheckBox fx:id="cbx_gpython" mnemonicParsing="false" text="Enable G-Python scripting" textFill="#000000ba" GridPane.rowIndex="1">
<CheckBox fx:id="cbx_gpython" mnemonicParsing="false" onAction="#gpythonCbxClick" text="Enable G-Python scripting" textFill="#000000ba" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="10.0" top="2.0" />
</GridPane.margin>