mirror of
https://github.com/git-learning-game/oh-my-git.git
synced 2024-11-22 16:20:19 +01:00
Start working on a better shell mechanism for Windows
It uses a Perl script to keep a bash session open, which attaches to a port the game keeps open. This avoids having to start a new Git bash for each command, improving the execution speed by a factor of 3-4.
This commit is contained in:
parent
2a82b617be
commit
53c249d059
8 changed files with 145 additions and 15 deletions
|
@ -21,6 +21,8 @@ func _ready():
|
||||||
else:
|
else:
|
||||||
game.toggle_music()
|
game.toggle_music()
|
||||||
|
|
||||||
|
start_remote_shell()
|
||||||
|
|
||||||
global_shell = Shell.new()
|
global_shell = Shell.new()
|
||||||
|
|
||||||
if global_shell.run("command -v git &>/dev/null && echo yes || echo no") == "no\n":
|
if global_shell.run("command -v git &>/dev/null && echo yes || echo no") == "no\n":
|
||||||
|
@ -34,6 +36,25 @@ func _ready():
|
||||||
|
|
||||||
load_state()
|
load_state()
|
||||||
|
|
||||||
|
func start_remote_shell():
|
||||||
|
var user_dir = ProjectSettings.globalize_path("user://")
|
||||||
|
var script_content = helpers.read_file("res://scripts/net-test")
|
||||||
|
var target_filename = user_dir + "net-test"
|
||||||
|
var target_file = File.new()
|
||||||
|
target_file.open(target_filename, File.WRITE)
|
||||||
|
target_file.store_string(script_content)
|
||||||
|
target_file.close()
|
||||||
|
helpers.exec_async(_perl_executable(), [target_filename])
|
||||||
|
|
||||||
|
func _perl_executable():
|
||||||
|
if OS.get_name() == "Windows":
|
||||||
|
return "dependencies/windows/git/usr/bin/perl.exe"
|
||||||
|
else:
|
||||||
|
return "perl"
|
||||||
|
|
||||||
|
func shell_received(text):
|
||||||
|
print(text)
|
||||||
|
|
||||||
func _notification(what):
|
func _notification(what):
|
||||||
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
|
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
|
||||||
#get_tree().quit() # default behavio
|
#get_tree().quit() # default behavio
|
||||||
|
@ -99,3 +120,7 @@ func toggle_music():
|
||||||
music.volume_db -= 100
|
music.volume_db -= 100
|
||||||
else:
|
else:
|
||||||
music.volume_db += 100
|
music.volume_db += 100
|
||||||
|
|
||||||
|
|
||||||
|
func shell_test(command):
|
||||||
|
return $ShellServer.send(command)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[gd_scene load_steps=3 format=2]
|
[gd_scene load_steps=4 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://scenes/game.gd" type="Script" id=1]
|
[ext_resource path="res://scenes/game.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://music/gigantic-greasy-giraffe.ogg" type="AudioStream" id=2]
|
[ext_resource path="res://music/gigantic-greasy-giraffe.ogg" type="AudioStream" id=2]
|
||||||
|
[ext_resource path="res://scenes/tcp_server_shell.tscn" type="PackedScene" id=3]
|
||||||
|
|
||||||
[node name="Node" type="Node"]
|
[node name="Node" type="Node"]
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
@ -10,3 +11,6 @@ script = ExtResource( 1 )
|
||||||
stream = ExtResource( 2 )
|
stream = ExtResource( 2 )
|
||||||
volume_db = -15.0
|
volume_db = -15.0
|
||||||
autoplay = true
|
autoplay = true
|
||||||
|
|
||||||
|
[node name="ShellServer" parent="." instance=ExtResource( 3 )]
|
||||||
|
port = 6666
|
||||||
|
|
|
@ -35,6 +35,9 @@ func exec(command, args=[], crash_on_fail=true):
|
||||||
|
|
||||||
return {"output": output, "exit_code": exit_code}
|
return {"output": output, "exit_code": exit_code}
|
||||||
|
|
||||||
|
func exec_async(command, args=[]):
|
||||||
|
OS.execute(command, args, false)
|
||||||
|
|
||||||
# Return the contents of a file. If no fallback_string is provided, crash when
|
# Return the contents of a file. If no fallback_string is provided, crash when
|
||||||
# the file doesn't exist.
|
# the file doesn't exist.
|
||||||
func read_file(path, fallback_string=null):
|
func read_file(path, fallback_string=null):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
signal data_received(string)
|
signal data_received(string)
|
||||||
|
signal new_connection
|
||||||
|
|
||||||
export var port: int
|
export var port: int
|
||||||
|
|
||||||
|
@ -21,21 +22,24 @@ func _process(_delta):
|
||||||
helpers.crash("Dropping active connection")
|
helpers.crash("Dropping active connection")
|
||||||
_c = _s.take_connection()
|
_c = _s.take_connection()
|
||||||
_connected = true
|
_connected = true
|
||||||
|
emit_signal("new_connection")
|
||||||
print("connected!")
|
print("connected!")
|
||||||
|
|
||||||
if _connected:
|
if _connected:
|
||||||
if _c.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
if _c.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
||||||
_connected = false
|
_connected = false
|
||||||
print("disconnected")
|
print("disconnected")
|
||||||
var available = _c.get_available_bytes()
|
# var available = _c.get_available_bytes()
|
||||||
while available > 0:
|
# while available > 0:
|
||||||
var data = _c.get_utf8_string(available)
|
# var data = _c.get_utf8_string(available)
|
||||||
emit_signal("data_received", data)
|
# emit_signal("data_received", data)
|
||||||
available = _c.get_available_bytes()
|
# available = _c.get_available_bytes()
|
||||||
|
|
||||||
func send(text):
|
func send(text):
|
||||||
if _connected:
|
if _connected:
|
||||||
text += "\n"
|
text += "\n"
|
||||||
_c.put_data(text.to_utf8())
|
_c.put_utf8_string(text)
|
||||||
|
var response = _c.get_utf8_string()
|
||||||
|
emit_signal("data_received", response)
|
||||||
else:
|
else:
|
||||||
helpers.crash("Trying to send data on closed connection")
|
helpers.crash("Trying to send data on closed connection")
|
||||||
|
|
50
scenes/tcp_server_shell.gd
Normal file
50
scenes/tcp_server_shell.gd
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
signal data_received(string)
|
||||||
|
signal new_connection
|
||||||
|
|
||||||
|
export var port: int
|
||||||
|
|
||||||
|
var _s = TCP_Server.new()
|
||||||
|
var _c
|
||||||
|
var _connected = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
start()
|
||||||
|
|
||||||
|
func start():
|
||||||
|
_s.listen(port)
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
if _s.is_connection_available():
|
||||||
|
if _connected:
|
||||||
|
_c.disconnect_from_host()
|
||||||
|
helpers.crash("Dropping active connection")
|
||||||
|
_c = _s.take_connection()
|
||||||
|
_connected = true
|
||||||
|
emit_signal("new_connection")
|
||||||
|
print("connected!")
|
||||||
|
|
||||||
|
if _connected:
|
||||||
|
if _c.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
||||||
|
_connected = false
|
||||||
|
print("disconnected")
|
||||||
|
# var available = _c.get_available_bytes()
|
||||||
|
# while available > 0:
|
||||||
|
# var data = _c.get_utf8_string(available)
|
||||||
|
# emit_signal("data_received", data)
|
||||||
|
# available = _c.get_available_bytes()
|
||||||
|
|
||||||
|
func send(text):
|
||||||
|
if _connected:
|
||||||
|
_c.put_utf8_string(text)
|
||||||
|
var response = _c.get_utf8_string()
|
||||||
|
var exit_code = _c.get_u32()
|
||||||
|
|
||||||
|
var shell_command = ShellCommand.new()
|
||||||
|
shell_command.command = text
|
||||||
|
shell_command.output = response
|
||||||
|
shell_command.exit_code = exit_code
|
||||||
|
return shell_command
|
||||||
|
else:
|
||||||
|
helpers.crash("Trying to send data on closed connection")
|
6
scenes/tcp_server_shell.tscn
Normal file
6
scenes/tcp_server_shell.tscn
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://scenes/tcp_server_shell.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="TCPServerShell" type="Node"]
|
||||||
|
script = ExtResource( 1 )
|
|
@ -85,8 +85,9 @@ func send_command(command):
|
||||||
editor_regex.compile("^(vim?|gedit|emacs|kate|nano|code) ")
|
editor_regex.compile("^(vim?|gedit|emacs|kate|nano|code) ")
|
||||||
command = editor_regex.sub(command, "fake-editor ")
|
command = editor_regex.sub(command, "fake-editor ")
|
||||||
|
|
||||||
var cmd = repository.shell.run_async(command, false)
|
# var cmd = repository.shell.run_async(command, false)
|
||||||
yield(cmd, "done")
|
# yield(cmd, "done")
|
||||||
|
var cmd = game.shell_test(command)
|
||||||
call_deferred("command_done", cmd)
|
call_deferred("command_done", cmd)
|
||||||
|
|
||||||
func command_done(cmd):
|
func command_done(cmd):
|
||||||
|
|
|
@ -1,24 +1,61 @@
|
||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use IPC::Open2;
|
||||||
use IO::Socket;
|
use IO::Socket;
|
||||||
|
|
||||||
|
my $pid = open2(my $out, my $in, 'bash');
|
||||||
|
|
||||||
$socket = IO::Socket::INET->new(PeerAddr => "127.0.0.1",
|
$socket = IO::Socket::INET->new(PeerAddr => "127.0.0.1",
|
||||||
PeerPort => 6666,
|
PeerPort => 6666,
|
||||||
Proto => "tcp",
|
Proto => "tcp",
|
||||||
Type => SOCK_STREAM);
|
Type => SOCK_STREAM);
|
||||||
|
|
||||||
$s = "Hey äöü!";
|
#$s = "Hey äöü!";
|
||||||
|
#
|
||||||
|
#my $send_length = pack("L", length($s));
|
||||||
|
#$socket->send($send_length);
|
||||||
|
#$socket->send($s);
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
#STDOUT->flush();
|
||||||
|
my $len;
|
||||||
|
$socket->recv($len, 4);
|
||||||
|
my $actual_len = unpack("L", $len);
|
||||||
|
if ($actual_len == 0) {
|
||||||
|
print("not connected");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
print("still connected");
|
||||||
|
my $s2;
|
||||||
|
$socket->recv($s2, ord($len));
|
||||||
|
|
||||||
|
print($s2);
|
||||||
|
STDOUT->flush();
|
||||||
|
|
||||||
|
#$s = `bash -c '$s2' 2>&1`;
|
||||||
|
|
||||||
|
$s = "";
|
||||||
|
$command = $s2 . "\necho MAGIC\n";
|
||||||
|
print $in $command;
|
||||||
|
|
||||||
|
inner_while: while (true) {
|
||||||
|
$line = <$out>;
|
||||||
|
if ($line eq "MAGIC\n") {
|
||||||
|
STDOUT->flush();
|
||||||
|
last inner_while;
|
||||||
|
}
|
||||||
|
$s = $s . $line;
|
||||||
|
}
|
||||||
|
print "got complete output";
|
||||||
|
print $s;
|
||||||
|
|
||||||
|
print length($s);
|
||||||
|
STDOUT->flush();
|
||||||
my $send_length = pack("L", length($s));
|
my $send_length = pack("L", length($s));
|
||||||
$socket->send($send_length);
|
$socket->send($send_length);
|
||||||
$socket->send($s);
|
$socket->send($s);
|
||||||
|
|
||||||
while(true) {
|
my $exit_code = pack("L", 0);
|
||||||
my $len;
|
$socket->send($exit_code);
|
||||||
$socket->recv($len, 4);
|
|
||||||
my $actual_len = unpack("L", $len);
|
|
||||||
my $s2;
|
|
||||||
$socket->recv($s2, ord($len));
|
|
||||||
print($s2);
|
|
||||||
STDOUT->flush();
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue