oh-my-git/shell.gd

91 lines
2.2 KiB
GDScript

extends Node
class_name Shell
var _cwd
signal output(text)
func _init():
_cwd = "/tmp"
func cd(dir):
_cwd = dir
# Run a shell command given as a string. Run this if you're interested in the
# output of the command.
func run(command):
var debug = false
if debug:
print("$ %s" % command)
var env = {}
env["EDITOR"] = game.fake_editor
env["GIT_AUTHOR_NAME"] = "You"
env["GIT_COMMITTER_NAME"] = "You"
env["GIT_AUTHOR_EMAIL"] = "you@example.com"
env["GIT_COMMITTER_EMAIL"] = "you@example.com"
var hacky_command = ""
for variable in env:
hacky_command += "export %s='%s';" % [variable, env[variable]]
hacky_command += "cd '%s';" % _cwd
hacky_command += command
# Godot's OS.execute wraps each argument in double quotes before executing.
# Because we want to be in a single-quote context, where nothing is evaluated,
# we end those double quotes and start a single quoted string. For each single
# quote appearing in our string, we close the single quoted string, and add
# a double quoted string containing the single quote. Ooooof!
#
# Example: The string
#
# test 'fu' "bla" blubb
#
# becomes
#
# "'test '"'"'fu'"'"' "bla" blubb
#
hacky_command = '"\''+hacky_command.replace("'", "'\"'\"'")+'\'"'
var output = game.exec(_shell_binary(), ["-c", hacky_command])
if debug:
print(output)
return output
func _shell_binary():
var os = OS.get_name()
if os == "X11":
return "sh"
elif os == "Windows":
return "dependencies\\windows\\git\\bin\\sh.exe"
else:
push_error("Unsupported OS")
get_tree().quit()
var _t
func run_async(command):
_t = Thread.new()
_t.start(self, "run_async_thread", command)
func run_async_thread(command):
var port = 1000 + (randi() % 1000)
var s = TCP_Server.new()
s.listen(port)
var _pid = OS.execute("ncat", ["127.0.0.1", str(port), "-c", command], false, [], true)
while not s.is_connection_available():
pass
var c = s.take_connection()
print("ok")
while c.get_status() == StreamPeerTCP.STATUS_CONNECTED:
var available = c.get_available_bytes()
if available > 0:
var data = c.get_utf8_string(available)
emit_signal("output", data)
print(data)
c.disconnect_from_host()
s.stop()