2020-09-08 16:00:18 +02:00
|
|
|
extends Node
|
|
|
|
class_name Shell
|
|
|
|
|
2020-10-22 16:19:22 +02:00
|
|
|
var exit_code
|
|
|
|
|
2020-09-08 16:00:18 +02:00
|
|
|
var _cwd
|
2020-10-22 16:19:22 +02:00
|
|
|
var _os = OS.get_name()
|
2020-09-08 16:00:18 +02:00
|
|
|
|
|
|
|
func _init():
|
2020-10-26 21:29:11 +01:00
|
|
|
# Create required directories and move into the tmp directory.
|
|
|
|
_cwd = "/tmp"
|
|
|
|
run("mkdir -p '%s/repos'" % game.tmp_prefix)
|
2020-10-26 19:56:52 +01:00
|
|
|
_cwd = game.tmp_prefix
|
2020-09-08 16:00:18 +02:00
|
|
|
|
|
|
|
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.
|
2020-09-29 18:36:24 +02:00
|
|
|
func run(command, crash_on_fail=true):
|
2020-11-02 13:13:04 +01:00
|
|
|
var shell_command = ShellCommand.new()
|
|
|
|
shell_command.command = command
|
|
|
|
shell_command.crash_on_fail = crash_on_fail
|
|
|
|
|
|
|
|
run_async_thread(shell_command)
|
|
|
|
exit_code = shell_command.exit_code
|
|
|
|
return shell_command.output
|
|
|
|
|
|
|
|
func run_async(command, crash_on_fail=true):
|
|
|
|
var shell_command = ShellCommand.new()
|
|
|
|
shell_command.command = command
|
|
|
|
shell_command.crash_on_fail = crash_on_fail
|
|
|
|
|
2020-11-02 15:19:52 +01:00
|
|
|
var t = Thread.new()
|
|
|
|
shell_command.thread = t
|
|
|
|
t.start(self, "run_async_thread", shell_command)
|
2020-11-02 13:13:04 +01:00
|
|
|
|
|
|
|
return shell_command
|
|
|
|
|
2020-11-02 15:19:52 +01:00
|
|
|
func run_async_thread(shell_command):
|
2020-10-29 20:34:28 +01:00
|
|
|
var debug = false
|
2020-09-08 16:00:18 +02:00
|
|
|
|
2020-11-02 13:13:04 +01:00
|
|
|
var command = shell_command.command
|
|
|
|
var crash_on_fail = shell_command.crash_on_fail
|
|
|
|
|
2020-09-08 16:00:18 +02:00
|
|
|
if debug:
|
|
|
|
print("$ %s" % command)
|
|
|
|
|
|
|
|
var env = {}
|
2020-10-29 17:23:12 +01:00
|
|
|
env["HOME"] = game.tmp_prefix
|
2020-09-08 16:00:18 +02:00
|
|
|
|
|
|
|
var hacky_command = ""
|
|
|
|
for variable in env:
|
|
|
|
hacky_command += "export %s='%s';" % [variable, env[variable]]
|
2021-02-19 11:50:34 +01:00
|
|
|
|
2021-02-27 15:07:35 +01:00
|
|
|
#hacky_command += "export PATH=\'"+game.tmp_prefix+":'\"$PATH\";"
|
2020-09-29 16:12:58 +02:00
|
|
|
hacky_command += "cd '%s' || exit 1;" % _cwd
|
2020-09-08 16:00:18 +02:00
|
|
|
hacky_command += command
|
2020-10-26 15:26:23 +01:00
|
|
|
|
2021-02-27 15:07:35 +01:00
|
|
|
#print(hacky_command)
|
2021-02-26 12:14:07 +01:00
|
|
|
|
2020-10-26 15:26:23 +01:00
|
|
|
var result
|
2021-02-26 12:14:07 +01:00
|
|
|
var shell_command_internal = game.shell_test(hacky_command)
|
|
|
|
# if _os == "X11" or _os == "OSX":
|
|
|
|
# # Godot's OS.execute wraps each argument in double quotes before executing
|
|
|
|
# # on Linux and macOS.
|
|
|
|
# # 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("'", "'\"'\"'")+'\'"'
|
|
|
|
# result = helpers.exec(_shell_binary(), ["-c", hacky_command], crash_on_fail)
|
|
|
|
# elif _os == "Windows":
|
|
|
|
# # On Windows, if the command contains a newline (even if inside a string),
|
|
|
|
# # execution will end. To avoid that, we first write the command to a file,
|
|
|
|
# # and run that file with bash.
|
|
|
|
# var script_path = game.tmp_prefix + "command" + str(randi())
|
|
|
|
# helpers.write_file(script_path, hacky_command)
|
|
|
|
# result = helpers.exec(_shell_binary(), [script_path], crash_on_fail)
|
|
|
|
# else:
|
|
|
|
# helpers.crash("Unimplemented OS: %s" % _os)
|
2020-09-08 16:00:18 +02:00
|
|
|
|
2021-02-26 12:14:07 +01:00
|
|
|
shell_command.output = shell_command_internal.output
|
|
|
|
shell_command.exit_code = shell_command_internal.exit_code
|
2020-11-02 15:19:52 +01:00
|
|
|
shell_command.emit_signal("done")
|
2020-09-09 11:01:30 +02:00
|
|
|
|
|
|
|
func _shell_binary():
|
2020-10-22 16:19:22 +02:00
|
|
|
if _os == "X11" or _os == "OSX":
|
2020-09-11 13:12:12 +02:00
|
|
|
return "bash"
|
2020-10-22 16:19:22 +02:00
|
|
|
elif _os == "Windows":
|
2020-09-11 13:12:12 +02:00
|
|
|
return "dependencies\\windows\\git\\bin\\bash.exe"
|
2020-09-09 11:01:30 +02:00
|
|
|
else:
|
2020-10-22 16:19:22 +02:00
|
|
|
helpers.crash("Unsupported OS: %s" % _os)
|
2020-09-08 16:46:12 +02:00
|
|
|
|
2020-11-02 13:13:04 +01:00
|
|
|
#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()
|
|
|
|
# while c.get_status() == StreamPeerTCP.STATUS_CONNECTED:
|
|
|
|
# read_from(c)
|
|
|
|
# OS.delay_msec(1000/30)
|
|
|
|
# read_from(c)
|
|
|
|
# c.disconnect_from_host()
|
|
|
|
# s.stop()
|
2020-09-08 22:16:18 +02:00
|
|
|
|
2020-09-15 09:30:19 +02:00
|
|
|
func read_from(c):
|
|
|
|
var total_available = c.get_available_bytes()
|
|
|
|
print(str(total_available)+" bytes available")
|
|
|
|
while total_available > 0:
|
|
|
|
var available = min(1024, total_available)
|
|
|
|
total_available -= available
|
|
|
|
print("reading "+str(available))
|
|
|
|
var data = c.get_utf8_string(available)
|
|
|
|
#emit_signal("output", data)
|
|
|
|
print(data.size())
|