Merge pull request #44514 from madmiraal/split-os-execute
Split OS::execute into two methods
This commit is contained in:
commit
1218441b16
@ -228,24 +228,32 @@ Error _OS::shell_open(String p_uri) {
|
|||||||
return OS::get_singleton()->shell_open(p_uri);
|
return OS::get_singleton()->shell_open(p_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) {
|
int _OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr) {
|
||||||
OS::ProcessID pid = -2;
|
|
||||||
int exitcode = 0;
|
|
||||||
List<String> args;
|
List<String> args;
|
||||||
for (int i = 0; i < p_arguments.size(); i++) {
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
args.push_back(p_arguments[i]);
|
args.push_back(p_arguments[i]);
|
||||||
}
|
}
|
||||||
String pipe;
|
String pipe;
|
||||||
Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, &exitcode, p_read_stderr);
|
int exitcode = 0;
|
||||||
p_output.clear();
|
Error err = OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr);
|
||||||
p_output.push_back(pipe);
|
r_output.push_back(pipe);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (p_blocking) {
|
|
||||||
return exitcode;
|
|
||||||
} else {
|
|
||||||
return pid;
|
|
||||||
}
|
}
|
||||||
|
return exitcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _OS::create_process(const String &p_path, const Vector<String> &p_arguments) {
|
||||||
|
List<String> args;
|
||||||
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
|
args.push_back(p_arguments[i]);
|
||||||
|
}
|
||||||
|
OS::ProcessID pid = 0;
|
||||||
|
Error err = OS::get_singleton()->create_process(p_path, args, &pid);
|
||||||
|
if (err != OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error _OS::kill(int p_pid) {
|
Error _OS::kill(int p_pid) {
|
||||||
@ -697,7 +705,8 @@ void _OS::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
|
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
|
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
|
||||||
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(true), DEFVAL(Array()), DEFVAL(false));
|
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr"), &_OS::execute, DEFVAL(Array()), DEFVAL(false));
|
||||||
|
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments"), &_OS::create_process);
|
||||||
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
|
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
|
||||||
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
|
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
|
||||||
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
|
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
|
||||||
|
@ -155,8 +155,8 @@ public:
|
|||||||
int get_low_processor_usage_mode_sleep_usec() const;
|
int get_low_processor_usage_mode_sleep_usec() const;
|
||||||
|
|
||||||
String get_executable_path() const;
|
String get_executable_path() const;
|
||||||
int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true, Array p_output = Array(), bool p_read_stderr = false);
|
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false);
|
||||||
|
int create_process(const String &p_path, const Vector<String> &p_arguments);
|
||||||
Error kill(int p_pid);
|
Error kill(int p_pid);
|
||||||
Error shell_open(String p_uri);
|
Error shell_open(String p_uri);
|
||||||
|
|
||||||
|
@ -129,7 +129,8 @@ public:
|
|||||||
virtual int get_low_processor_usage_mode_sleep_usec() const;
|
virtual int get_low_processor_usage_mode_sleep_usec() const;
|
||||||
|
|
||||||
virtual String get_executable_path() const;
|
virtual String get_executable_path() const;
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
|
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
|
||||||
|
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0;
|
||||||
virtual Error kill(const ProcessID &p_pid) = 0;
|
virtual Error kill(const ProcessID &p_pid) = 0;
|
||||||
virtual int get_process_id() const;
|
virtual int get_process_id() const;
|
||||||
virtual void vibrate_handheld(int p_duration_ms = 500);
|
virtual void vibrate_handheld(int p_duration_ms = 500);
|
||||||
|
@ -25,6 +25,29 @@
|
|||||||
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
|
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="create_process">
|
||||||
|
<return type="int">
|
||||||
|
</return>
|
||||||
|
<argument index="0" name="path" type="String">
|
||||||
|
</argument>
|
||||||
|
<argument index="1" name="arguments" type="PackedStringArray">
|
||||||
|
</argument>
|
||||||
|
<description>
|
||||||
|
Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The file specified in [code]path[/code] must exist and be executable. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space.
|
||||||
|
If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code].
|
||||||
|
For example, running another instance of the project:
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
var pid = OS.create_process(OS.get_executable_path(), [])
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
var pid = OS.CreateProcess(OS.GetExecutablePath(), new string[] {});
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
See [method execute] if you wish to run an external command and retrieve the results.
|
||||||
|
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="delay_msec" qualifiers="const">
|
<method name="delay_msec" qualifiers="const">
|
||||||
<return type="void">
|
<return type="void">
|
||||||
</return>
|
</return>
|
||||||
@ -71,48 +94,34 @@
|
|||||||
</argument>
|
</argument>
|
||||||
<argument index="1" name="arguments" type="PackedStringArray">
|
<argument index="1" name="arguments" type="PackedStringArray">
|
||||||
</argument>
|
</argument>
|
||||||
<argument index="2" name="blocking" type="bool" default="true">
|
<argument index="2" name="output" type="Array" default="[ ]">
|
||||||
</argument>
|
</argument>
|
||||||
<argument index="3" name="output" type="Array" default="[ ]">
|
<argument index="3" name="read_stderr" type="bool" default="false">
|
||||||
</argument>
|
|
||||||
<argument index="4" name="read_stderr" type="bool" default="false">
|
|
||||||
</argument>
|
</argument>
|
||||||
<description>
|
<description>
|
||||||
Execute the file at the given path with the arguments passed as an array of strings. Platform path resolution will take place. The resolved file must exist and be executable.
|
Executes a command. The file specified in [code]path[/code] must exist and be executable. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space. If an [code]output[/code] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [code]output[/code]. If [code]read_stderr[/code] is [code]true[/code], the output to the standard error stream will be included too.
|
||||||
The arguments are used in the given order and separated by a space, so [code]OS.execute("ping", ["-w", "3", "godotengine.org"], false)[/code] will resolve to [code]ping -w 3 godotengine.org[/code] in the system's shell.
|
If the command is successfully executed, the method will return the exit code of the command, or [code]-1[/code] if it fails.
|
||||||
This method has slightly different behavior based on whether the [code]blocking[/code] mode is enabled.
|
[b]Note:[/b] The Godot thread will pause its execution until the executed command terminates. Use [Thread] to create a separate thread that will not pause the Godot thread, or use [method create_process] to create a completely independent process.
|
||||||
If [code]blocking[/code] is [code]true[/code], the Godot thread will pause its execution while waiting for the process to terminate. The shell output of the process will be written to the [code]output[/code] array as a single string. When the process terminates, the Godot thread will resume execution.
|
For example, to retrieve a list of the working directory's contents:
|
||||||
If [code]blocking[/code] is [code]false[/code], the Godot thread will continue while the new process runs. It is not possible to retrieve the shell output in non-blocking mode, so [code]output[/code] will be empty.
|
|
||||||
The return value also depends on the blocking mode. When blocking, the method will return an exit code of the process. When non-blocking, the method returns a process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process forking (non-blocking) or opening (blocking) fails, the method will return [code]-1[/code] or another exit code.
|
|
||||||
Example of blocking mode and retrieving the shell output:
|
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var output = []
|
var output = []
|
||||||
var exit_code = OS.execute("ls", ["-l", "/tmp"], true, output)
|
var exit_code = OS.execute("ls", ["-l", "/tmp"], output)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var output = new Godot.Collections.Array();
|
var output = new Godot.Collections.Array();
|
||||||
int exitCode = OS.Execute("ls", new string[] {"-l", "/tmp"}, true, output);
|
int exitCode = OS.Execute("ls", new string[] {"-l", "/tmp"}, output);
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
Example of non-blocking mode, running another instance of the project and storing its process ID:
|
To execute a composite command, a platform-specific shell can be invoked. For example:
|
||||||
[codeblocks]
|
|
||||||
[gdscript]
|
|
||||||
var pid = OS.execute(OS.get_executable_path(), [], false)
|
|
||||||
[/gdscript]
|
|
||||||
[csharp]
|
|
||||||
var pid = OS.Execute(OS.GetExecutablePath(), new string[] {}, false);
|
|
||||||
[/csharp]
|
|
||||||
[/codeblocks]
|
|
||||||
If you wish to access a shell built-in or perform a composite command, a platform-specific shell can be invoked. For example:
|
|
||||||
[codeblocks]
|
[codeblocks]
|
||||||
[gdscript]
|
[gdscript]
|
||||||
var output = []
|
var output = []
|
||||||
OS.execute("CMD.exe", ["/C", "cd %TEMP% && dir"], true, output)
|
OS.execute("CMD.exe", ["/C", "cd %TEMP% && dir"], output)
|
||||||
[/gdscript]
|
[/gdscript]
|
||||||
[csharp]
|
[csharp]
|
||||||
var output = new Godot.Collections.Array();
|
var output = new Godot.Collections.Array();
|
||||||
OS.Execute("CMD.exe", new string[] {"/C", "cd %TEMP% && dir"}, true, output);
|
OS.Execute("CMD.exe", new string[] {"/C", "cd %TEMP% && dir"}, output);
|
||||||
[/csharp]
|
[/csharp]
|
||||||
[/codeblocks]
|
[/codeblocks]
|
||||||
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
|
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
|
||||||
|
@ -257,31 +257,26 @@ uint64_t OS_Unix::get_ticks_usec() const {
|
|||||||
return longtime;
|
return longtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
// Don't compile this code at all to avoid undefined references.
|
// Don't compile this code at all to avoid undefined references.
|
||||||
// Actual virtual call goes to OS_JavaScript.
|
// Actual virtual call goes to OS_JavaScript.
|
||||||
ERR_FAIL_V(ERR_BUG);
|
ERR_FAIL_V(ERR_BUG);
|
||||||
#else
|
#else
|
||||||
if (p_blocking && r_pipe) {
|
if (r_pipe) {
|
||||||
String argss;
|
String command = "\"" + p_path + "\"";
|
||||||
argss = "\"" + p_path + "\"";
|
|
||||||
|
|
||||||
for (int i = 0; i < p_arguments.size(); i++) {
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
argss += String(" \"") + p_arguments[i] + "\"";
|
command += String(" \"") + p_arguments[i] + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_stderr) {
|
if (read_stderr) {
|
||||||
argss += " 2>&1"; // Read stderr too
|
command += " 2>&1"; // Include stderr
|
||||||
} else {
|
} else {
|
||||||
argss += " 2>/dev/null"; //silence stderr
|
command += " 2>/dev/null"; // Silence stderr
|
||||||
}
|
}
|
||||||
FILE *f = popen(argss.utf8().get_data(), "r");
|
|
||||||
|
|
||||||
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'.");
|
|
||||||
|
|
||||||
|
FILE *f = popen(command.utf8().get_data(), "r");
|
||||||
|
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command);
|
||||||
char buf[65535];
|
char buf[65535];
|
||||||
|
|
||||||
while (fgets(buf, 65535, f)) {
|
while (fgets(buf, 65535, f)) {
|
||||||
if (p_pipe_mutex) {
|
if (p_pipe_mutex) {
|
||||||
p_pipe_mutex->lock();
|
p_pipe_mutex->lock();
|
||||||
@ -292,10 +287,10 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int rv = pclose(f);
|
int rv = pclose(f);
|
||||||
|
|
||||||
if (r_exitcode) {
|
if (r_exitcode) {
|
||||||
*r_exitcode = WEXITSTATUS(rv);
|
*r_exitcode = WEXITSTATUS(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,45 +298,58 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo
|
|||||||
ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK);
|
ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK);
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// is child
|
// The child process
|
||||||
|
|
||||||
if (!p_blocking) {
|
|
||||||
// For non blocking calls, create a new session-ID so parent won't wait for it.
|
|
||||||
// This ensures the process won't go zombie at end.
|
|
||||||
setsid();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<CharString> cs;
|
|
||||||
cs.push_back(p_path.utf8());
|
|
||||||
for (int i = 0; i < p_arguments.size(); i++) {
|
|
||||||
cs.push_back(p_arguments[i].utf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<char *> args;
|
Vector<char *> args;
|
||||||
for (int i = 0; i < cs.size(); i++) {
|
args.push_back((char *)p_path.utf8().get_data());
|
||||||
args.push_back((char *)cs[i].get_data());
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
|
args.push_back((char *)p_arguments[i].utf8().get_data());
|
||||||
}
|
}
|
||||||
args.push_back(0);
|
args.push_back(0);
|
||||||
|
|
||||||
execvp(p_path.utf8().get_data(), &args[0]);
|
execvp(p_path.utf8().get_data(), &args[0]);
|
||||||
// still alive? something failed..
|
// The execvp() function only returns if an error occurs.
|
||||||
fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.utf8().get_data());
|
CRASH_NOW_MSG("Could not create child process: " + p_path);
|
||||||
raise(SIGKILL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_blocking) {
|
int status;
|
||||||
int status;
|
waitpid(pid, &status, 0);
|
||||||
waitpid(pid, &status, 0);
|
if (r_exitcode) {
|
||||||
if (r_exitcode) {
|
*r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status;
|
||||||
*r_exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status;
|
}
|
||||||
}
|
return OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
|
||||||
if (r_child_id) {
|
#ifdef __EMSCRIPTEN__
|
||||||
*r_child_id = pid;
|
// Don't compile this code at all to avoid undefined references.
|
||||||
|
// Actual virtual call goes to OS_JavaScript.
|
||||||
|
ERR_FAIL_V(ERR_BUG);
|
||||||
|
#else
|
||||||
|
pid_t pid = fork();
|
||||||
|
ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK);
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
// The new process
|
||||||
|
// Create a new session-ID so parent won't wait for it.
|
||||||
|
// This ensures the process won't go zombie at the end.
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
Vector<char *> args;
|
||||||
|
args.push_back((char *)p_path.utf8().get_data());
|
||||||
|
for (int i = 0; i < p_arguments.size(); i++) {
|
||||||
|
args.push_back((char *)p_arguments[i].utf8().get_data());
|
||||||
}
|
}
|
||||||
|
args.push_back(0);
|
||||||
|
|
||||||
|
execvp(p_path.utf8().get_data(), &args[0]);
|
||||||
|
// The execvp() function only returns if an error occurs.
|
||||||
|
CRASH_NOW_MSG("Could not create child process: " + p_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r_child_id) {
|
||||||
|
*r_child_id = pid;
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,8 @@ public:
|
|||||||
virtual void delay_usec(uint32_t p_usec) const override;
|
virtual void delay_usec(uint32_t p_usec) const override;
|
||||||
virtual uint64_t get_ticks_usec() const override;
|
virtual uint64_t get_ticks_usec() const override;
|
||||||
|
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
||||||
|
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
|
||||||
virtual Error kill(const ProcessID &p_pid) override;
|
virtual Error kill(const ProcessID &p_pid) override;
|
||||||
virtual int get_process_id() const override;
|
virtual int get_process_id() const override;
|
||||||
|
|
||||||
|
@ -2855,8 +2855,7 @@ void EditorNode::_discard_changes(const String &p_str) {
|
|||||||
args.push_back(exec.get_base_dir());
|
args.push_back(exec.get_base_dir());
|
||||||
args.push_back("--project-manager");
|
args.push_back("--project-manager");
|
||||||
|
|
||||||
OS::ProcessID pid = 0;
|
Error err = OS::get_singleton()->create_process(exec, args);
|
||||||
Error err = OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
ERR_FAIL_COND(err);
|
ERR_FAIL_COND(err);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -5139,9 +5138,7 @@ void EditorNode::_global_menu_new_window(const Variant &p_tag) {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("-p");
|
args.push_back("-p");
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5467,7 +5464,7 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err
|
|||||||
|
|
||||||
static void _execute_thread(void *p_ud) {
|
static void _execute_thread(void *p_ud) {
|
||||||
EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
|
EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
|
||||||
Error err = OS::get_singleton()->execute(eta->path, eta->args, true, nullptr, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
|
Error err = OS::get_singleton()->execute(eta->path, eta->args, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
|
||||||
print_verbose("Thread exit status: " + itos(eta->exitcode));
|
print_verbose("Thread exit status: " + itos(eta->exitcode));
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
eta->exitcode = err;
|
eta->exitcode = err;
|
||||||
|
@ -201,7 +201,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
|
|||||||
int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1);
|
int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1);
|
||||||
for (int i = 0; i < instances; i++) {
|
for (int i = 0; i < instances; i++) {
|
||||||
OS::ProcessID pid = 0;
|
OS::ProcessID pid = 0;
|
||||||
Error err = OS::get_singleton()->execute(exec, args, false, &pid);
|
Error err = OS::get_singleton()->create_process(exec, args, &pid);
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
pids.push_back(pid);
|
pids.push_back(pid);
|
||||||
}
|
}
|
||||||
|
@ -2211,7 +2211,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
|
|||||||
args.push_back(script_path);
|
args.push_back(script_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error err = OS::get_singleton()->execute(path, args, false);
|
Error err = OS::get_singleton()->create_process(path, args);
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1297,9 +1297,7 @@ void ProjectList::_global_menu_new_window(const Variant &p_tag) {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("-p");
|
args.push_back("-p");
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectList::_global_menu_open_project(const Variant &p_tag) {
|
void ProjectList::_global_menu_open_project(const Variant &p_tag) {
|
||||||
@ -1310,9 +1308,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back(conf);
|
args.push_back(conf);
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2055,9 +2051,7 @@ void ProjectManager::_open_selected_projects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
Error err = OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
Error err = OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
ERR_FAIL_COND(err);
|
ERR_FAIL_COND(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2143,9 +2137,7 @@ void ProjectManager::_run_project_confirm() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
Error err = OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
Error err = OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
ERR_FAIL_COND(err);
|
ERR_FAIL_COND(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2270,8 +2262,7 @@ void ProjectManager::_language_selected(int p_id) {
|
|||||||
void ProjectManager::_restart_confirm() {
|
void ProjectManager::_restart_confirm() {
|
||||||
List<String> args = OS::get_singleton()->get_cmdline_args();
|
List<String> args = OS::get_singleton()->get_cmdline_args();
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
OS::ProcessID pid = 0;
|
Error err = OS::get_singleton()->create_process(exec, args);
|
||||||
Error err = OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
ERR_FAIL_COND(err);
|
ERR_FAIL_COND(err);
|
||||||
|
|
||||||
_dim_window();
|
_dim_window();
|
||||||
|
@ -2686,8 +2686,7 @@ void Main::cleanup() {
|
|||||||
//attempt to restart with arguments
|
//attempt to restart with arguments
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
List<String> args = OS::get_singleton()->get_restart_on_exit_arguments();
|
List<String> args = OS::get_singleton()->get_restart_on_exit_arguments();
|
||||||
OS::ProcessID pid = 0;
|
OS::get_singleton()->create_process(exec, args);
|
||||||
OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
OS::get_singleton()->set_restart_on_exit(false, List<String>()); //clear list (uses memory)
|
OS::get_singleton()->set_restart_on_exit(false, List<String>()); //clear list (uses memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +308,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("devices");
|
args.push_back("devices");
|
||||||
int ec;
|
int ec;
|
||||||
OS::get_singleton()->execute(adb, args, true, nullptr, &devices, &ec);
|
OS::get_singleton()->execute(adb, args, &devices, &ec);
|
||||||
|
|
||||||
Vector<String> ds = devices.split("\n");
|
Vector<String> ds = devices.split("\n");
|
||||||
Vector<String> ldevices;
|
Vector<String> ldevices;
|
||||||
@ -361,7 +361,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||||||
int ec2;
|
int ec2;
|
||||||
String dp;
|
String dp;
|
||||||
|
|
||||||
OS::get_singleton()->execute(adb, args, true, nullptr, &dp, &ec2);
|
OS::get_singleton()->execute(adb, args, &dp, &ec2);
|
||||||
|
|
||||||
Vector<String> props = dp.split("\n");
|
Vector<String> props = dp.split("\n");
|
||||||
String vendor;
|
String vendor;
|
||||||
@ -432,7 +432,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
|
|||||||
|
|
||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("kill-server");
|
args.push_back("kill-server");
|
||||||
OS::get_singleton()->execute(adb, args, true);
|
OS::get_singleton()->execute(adb, args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1800,7 +1800,7 @@ public:
|
|||||||
args.push_back("uninstall");
|
args.push_back("uninstall");
|
||||||
args.push_back(get_package_name(package_name));
|
args.push_back(get_package_name(package_name));
|
||||||
|
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
print_line("Installing to device (please wait...): " + devices[p_device].name);
|
print_line("Installing to device (please wait...): " + devices[p_device].name);
|
||||||
@ -1815,7 +1815,7 @@ public:
|
|||||||
args.push_back("-r");
|
args.push_back("-r");
|
||||||
args.push_back(tmp_export_path);
|
args.push_back(tmp_export_path);
|
||||||
|
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
if (err || rv != 0) {
|
if (err || rv != 0) {
|
||||||
EditorNode::add_io_error("Could not install to device.");
|
EditorNode::add_io_error("Could not install to device.");
|
||||||
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
||||||
@ -1832,7 +1832,7 @@ public:
|
|||||||
args.push_back(devices[p_device].id);
|
args.push_back(devices[p_device].id);
|
||||||
args.push_back("reverse");
|
args.push_back("reverse");
|
||||||
args.push_back("--remove-all");
|
args.push_back("--remove-all");
|
||||||
OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
|
|
||||||
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
|
if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) {
|
||||||
int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
|
int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
|
||||||
@ -1843,7 +1843,7 @@ public:
|
|||||||
args.push_back("tcp:" + itos(dbg_port));
|
args.push_back("tcp:" + itos(dbg_port));
|
||||||
args.push_back("tcp:" + itos(dbg_port));
|
args.push_back("tcp:" + itos(dbg_port));
|
||||||
|
|
||||||
OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
print_line("Reverse result: " + itos(rv));
|
print_line("Reverse result: " + itos(rv));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1857,7 +1857,7 @@ public:
|
|||||||
args.push_back("tcp:" + itos(fs_port));
|
args.push_back("tcp:" + itos(fs_port));
|
||||||
args.push_back("tcp:" + itos(fs_port));
|
args.push_back("tcp:" + itos(fs_port));
|
||||||
|
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
print_line("Reverse result2: " + itos(rv));
|
print_line("Reverse result2: " + itos(rv));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1885,7 +1885,7 @@ public:
|
|||||||
args.push_back("-n");
|
args.push_back("-n");
|
||||||
args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
|
args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp");
|
||||||
|
|
||||||
err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv);
|
err = OS::get_singleton()->execute(adb, args, nullptr, &rv);
|
||||||
if (err || rv != 0) {
|
if (err || rv != 0) {
|
||||||
EditorNode::add_io_error("Could not execute on device.");
|
EditorNode::add_io_error("Could not execute on device.");
|
||||||
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
CLEANUP_AND_RETURN(ERR_CANT_CREATE);
|
||||||
@ -2288,7 +2288,7 @@ public:
|
|||||||
args.push_back(user);
|
args.push_back(user);
|
||||||
args.push_back(export_path);
|
args.push_back(export_path);
|
||||||
int retval;
|
int retval;
|
||||||
OS::get_singleton()->execute(apksigner, args, true, NULL, NULL, &retval);
|
OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
EditorNode::add_io_error("'apksigner' returned with error #" + itos(retval));
|
EditorNode::add_io_error("'apksigner' returned with error #" + itos(retval));
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
@ -2303,7 +2303,7 @@ public:
|
|||||||
args.push_back("--verbose");
|
args.push_back("--verbose");
|
||||||
args.push_back(export_path);
|
args.push_back(export_path);
|
||||||
|
|
||||||
OS::get_singleton()->execute(apksigner, args, true, NULL, NULL, &retval);
|
OS::get_singleton()->execute(apksigner, args, nullptr, &retval);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed.");
|
EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed.");
|
||||||
return ERR_CANT_CREATE;
|
return ERR_CANT_CREATE;
|
||||||
|
@ -979,7 +979,7 @@ Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) {
|
|||||||
codesign_args.push_back("-s");
|
codesign_args.push_back("-s");
|
||||||
codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release"));
|
codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release"));
|
||||||
codesign_args.push_back(p_file);
|
codesign_args.push_back(p_file);
|
||||||
return OS::get_singleton()->execute("codesign", codesign_args, true);
|
return OS::get_singleton()->execute("codesign", codesign_args);
|
||||||
}
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -1229,7 +1229,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
|
|||||||
install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
|
install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
|
||||||
install_name_args.push_back(destination);
|
install_name_args.push_back(destination);
|
||||||
|
|
||||||
OS::get_singleton()->execute("install_name_tool", install_name_args, true);
|
OS::get_singleton()->execute("install_name_tool", install_name_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creating Info.plist
|
// Creating Info.plist
|
||||||
@ -1848,7 +1848,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
|||||||
archive_args.push_back("archive");
|
archive_args.push_back("archive");
|
||||||
archive_args.push_back("-archivePath");
|
archive_args.push_back("-archivePath");
|
||||||
archive_args.push_back(archive_path);
|
archive_args.push_back(archive_path);
|
||||||
err = OS::get_singleton()->execute("xcodebuild", archive_args, true);
|
err = OS::get_singleton()->execute("xcodebuild", archive_args);
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
|
|
||||||
if (ep.step("Making .ipa", 4)) {
|
if (ep.step("Making .ipa", 4)) {
|
||||||
@ -1863,7 +1863,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
|
|||||||
export_args.push_back("-allowProvisioningUpdates");
|
export_args.push_back("-allowProvisioningUpdates");
|
||||||
export_args.push_back("-exportPath");
|
export_args.push_back("-exportPath");
|
||||||
export_args.push_back(dest_dir);
|
export_args.push_back(dest_dir);
|
||||||
err = OS::get_singleton()->execute("xcodebuild", export_args, true);
|
err = OS::get_singleton()->execute("xcodebuild", export_args);
|
||||||
ERR_FAIL_COND_V(err, err);
|
ERR_FAIL_COND_V(err, err);
|
||||||
#else
|
#else
|
||||||
print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
|
print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package.");
|
||||||
|
@ -106,14 +106,18 @@ void OS_JavaScript::finalize() {
|
|||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
|
|
||||||
Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||||
|
return create_process(p_path, p_arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
|
||||||
Array args;
|
Array args;
|
||||||
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||||
args.push_back(E->get());
|
args.push_back(E->get());
|
||||||
}
|
}
|
||||||
String json_args = JSON::print(args);
|
String json_args = JSON::print(args);
|
||||||
int failed = godot_js_os_execute(json_args.utf8().get_data());
|
int failed = godot_js_os_execute(json_args.utf8().get_data());
|
||||||
ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() must be implemented in JavaScript via 'engine.setOnExecute' if required.");
|
ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() or create_process() must be implemented in JavaScript via 'engine.setOnExecute' if required.");
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,8 @@ public:
|
|||||||
MainLoop *get_main_loop() const override;
|
MainLoop *get_main_loop() const override;
|
||||||
bool main_loop_iterate();
|
bool main_loop_iterate();
|
||||||
|
|
||||||
Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
||||||
|
Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
|
||||||
Error kill(const ProcessID &p_pid) override;
|
Error kill(const ProcessID &p_pid) override;
|
||||||
int get_process_id() const override;
|
int get_process_id() const override;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ static void handle_crash(int sig) {
|
|||||||
|
|
||||||
// Try to get the file/line number using addr2line
|
// Try to get the file/line number using addr2line
|
||||||
int ret;
|
int ret;
|
||||||
Error err = OS::get_singleton()->execute(String("addr2line"), args, true, nullptr, &output, &ret);
|
Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
|
||||||
if (err == OK) {
|
if (err == OK) {
|
||||||
output.erase(output.length() - 1, 1);
|
output.erase(output.length() - 1, 1);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ void DisplayServerX11::alert(const String &p_alert, const String &p_title) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (program.length()) {
|
if (program.length()) {
|
||||||
OS::get_singleton()->execute(program, args, true);
|
OS::get_singleton()->execute(program, args);
|
||||||
} else {
|
} else {
|
||||||
print_line(p_alert);
|
print_line(p_alert);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ Error OS_LinuxBSD::shell_open(String p_uri) {
|
|||||||
args.push_back(p_uri);
|
args.push_back(p_uri);
|
||||||
|
|
||||||
// Agnostic
|
// Agnostic
|
||||||
ok = execute("xdg-open", args, true, nullptr, nullptr, &err_code);
|
ok = execute("xdg-open", args, nullptr, &err_code);
|
||||||
if (ok == OK && !err_code) {
|
if (ok == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
@ -136,25 +136,25 @@ Error OS_LinuxBSD::shell_open(String p_uri) {
|
|||||||
}
|
}
|
||||||
// GNOME
|
// GNOME
|
||||||
args.push_front("open"); // The command is `gio open`, so we need to add it to args
|
args.push_front("open"); // The command is `gio open`, so we need to add it to args
|
||||||
ok = execute("gio", args, true, nullptr, nullptr, &err_code);
|
ok = execute("gio", args, nullptr, &err_code);
|
||||||
if (ok == OK && !err_code) {
|
if (ok == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
args.pop_front();
|
args.pop_front();
|
||||||
ok = execute("gvfs-open", args, true, nullptr, nullptr, &err_code);
|
ok = execute("gvfs-open", args, nullptr, &err_code);
|
||||||
if (ok == OK && !err_code) {
|
if (ok == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
return ERR_FILE_NOT_FOUND;
|
return ERR_FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
// KDE
|
// KDE
|
||||||
ok = execute("kde-open5", args, true, nullptr, nullptr, &err_code);
|
ok = execute("kde-open5", args, nullptr, &err_code);
|
||||||
if (ok == OK && !err_code) {
|
if (ok == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
ok = execute("kde-open", args, true, nullptr, nullptr, &err_code);
|
ok = execute("kde-open", args, nullptr, &err_code);
|
||||||
return !err_code ? ok : FAILED;
|
return !err_code ? ok : FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const {
|
|||||||
String pipe;
|
String pipe;
|
||||||
List<String> arg;
|
List<String> arg;
|
||||||
arg.push_back(xdgparam);
|
arg.push_back(xdgparam);
|
||||||
Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, true, nullptr, &pipe);
|
Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, &pipe);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
return ".";
|
return ".";
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back(p_path);
|
args.push_back(p_path);
|
||||||
args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args.
|
args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args.
|
||||||
Error result = execute("gio", args, true, nullptr, nullptr, &err_code); // For GNOME based machines.
|
Error result = execute("gio", args, nullptr, &err_code); // For GNOME based machines.
|
||||||
if (result == OK && !err_code) {
|
if (result == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
@ -317,7 +317,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
|
|||||||
args.pop_front();
|
args.pop_front();
|
||||||
args.push_front("move");
|
args.push_front("move");
|
||||||
args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`.
|
args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`.
|
||||||
result = execute("kioclient5", args, true, nullptr, nullptr, &err_code); // For KDE based machines.
|
result = execute("kioclient5", args, nullptr, &err_code); // For KDE based machines.
|
||||||
if (result == OK && !err_code) {
|
if (result == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
@ -326,7 +326,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
|
|||||||
|
|
||||||
args.pop_front();
|
args.pop_front();
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
result = execute("gvfs-trash", args, true, nullptr, nullptr, &err_code); // For older Linux machines.
|
result = execute("gvfs-trash", args, nullptr, &err_code); // For older Linux machines.
|
||||||
if (result == OK && !err_code) {
|
if (result == OK && !err_code) {
|
||||||
return OK;
|
return OK;
|
||||||
} else if (err_code == 2) {
|
} else if (err_code == 2) {
|
||||||
@ -432,7 +432,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
|
|||||||
mv_args.push_back(trash_path + "/files");
|
mv_args.push_back(trash_path + "/files");
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
Error err = execute("mv", mv_args, true, nullptr, nullptr, &retval);
|
Error err = execute("mv", mv_args, nullptr, &retval);
|
||||||
|
|
||||||
// Issue an error if "mv" failed to move the given resource to the trash can.
|
// Issue an error if "mv" failed to move the given resource to the trash can.
|
||||||
if (err != OK || retval != 0) {
|
if (err != OK || retval != 0) {
|
||||||
|
@ -135,7 +135,7 @@ static void handle_crash(int sig) {
|
|||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
String out = "";
|
String out = "";
|
||||||
Error err = OS::get_singleton()->execute(String("atos"), args, true, NULL, &out, &ret);
|
Error err = OS::get_singleton()->execute(String("atos"), args, &out, &ret);
|
||||||
if (err == OK && out.substr(0, 2) != "0x") {
|
if (err == OK && out.substr(0, 2) != "0x") {
|
||||||
out.erase(out.length() - 1, 1);
|
out.erase(out.length() - 1, 1);
|
||||||
output = out;
|
output = out;
|
||||||
|
@ -256,9 +256,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
|
|||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back(((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename);
|
args.push_back(((OS_OSX *)(OS_OSX::get_singleton()))->open_with_filename);
|
||||||
String exec = OS::get_singleton()->get_executable_path();
|
String exec = OS::get_singleton()->get_executable_path();
|
||||||
|
OS::get_singleton()->create_process(exec, args);
|
||||||
OS::ProcessID pid = 0;
|
|
||||||
OS::get_singleton()->execute(exec, args, false, &pid);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return YES;
|
return YES;
|
||||||
|
@ -419,7 +419,7 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset
|
|||||||
args.push_back(p_path);
|
args.push_back(p_path);
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("xcrun", args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
|
|
||||||
print_line("altool (" + p_path + "):\n" + str);
|
print_line("altool (" + p_path + "):\n" + str);
|
||||||
@ -470,7 +470,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
|
|||||||
args.push_back(p_path);
|
args.push_back(p_path);
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("codesign", args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
|
|
||||||
print_line("codesign (" + p_path + "):\n" + str);
|
print_line("codesign (" + p_path + "):\n" + str);
|
||||||
@ -504,7 +504,7 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
|
|||||||
args.push_back(p_app_path_name);
|
args.push_back(p_app_path_name);
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute("hdiutil", args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute("hdiutil", args, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
|
|
||||||
print_line("hdiutil returned: " + str);
|
print_line("hdiutil returned: " + str);
|
||||||
|
@ -1411,7 +1411,7 @@ public:
|
|||||||
args.push_back(cert_pass);
|
args.push_back(cert_pass);
|
||||||
args.push_back(p_path);
|
args.push_back(p_path);
|
||||||
|
|
||||||
OS::get_singleton()->execute(signtool_path, args, true);
|
OS::get_singleton()->execute(signtool_path, args);
|
||||||
#endif // WINDOWS_ENABLED
|
#endif // WINDOWS_ENABLED
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
|
@ -638,7 +638,11 @@ void OS_UWP::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
Error OS_UWP::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||||
|
return FAILED;
|
||||||
|
};
|
||||||
|
|
||||||
|
Error OS_UWP::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
|
||||||
return FAILED;
|
return FAILED;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -199,7 +199,8 @@ public:
|
|||||||
virtual void delay_usec(uint32_t p_usec) const;
|
virtual void delay_usec(uint32_t p_usec) const;
|
||||||
virtual uint64_t get_ticks_usec() const;
|
virtual uint64_t get_ticks_usec() const;
|
||||||
|
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
|
||||||
|
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr);
|
||||||
virtual Error kill(const ProcessID &p_pid);
|
virtual Error kill(const ProcessID &p_pid);
|
||||||
|
|
||||||
virtual bool has_environment(const String &p_var) const;
|
virtual bool has_environment(const String &p_var) const;
|
||||||
|
@ -173,11 +173,11 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WINDOWS_ENABLED
|
#ifdef WINDOWS_ENABLED
|
||||||
OS::get_singleton()->execute(rcedit_path, args, true);
|
OS::get_singleton()->execute(rcedit_path, args);
|
||||||
#else
|
#else
|
||||||
// On non-Windows we need WINE to run rcedit
|
// On non-Windows we need WINE to run rcedit
|
||||||
args.push_front(rcedit_path);
|
args.push_front(rcedit_path);
|
||||||
OS::get_singleton()->execute(wine_path, args, true);
|
OS::get_singleton()->execute(wine_path, args);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
Error err = OS::get_singleton()->execute(signtool_path, args, true, nullptr, &str, nullptr, true);
|
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
|
||||||
ERR_FAIL_COND_V(err != OK, err);
|
ERR_FAIL_COND_V(err != OK, err);
|
||||||
|
|
||||||
print_line("codesign (" + p_path + "): " + str);
|
print_line("codesign (" + p_path + "): " + str);
|
||||||
|
@ -410,24 +410,23 @@ String OS_Windows::_quote_command_line_argument(const String &p_text) const {
|
|||||||
return p_text;
|
return p_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex) {
|
||||||
String path = p_path.replace("/", "\\");
|
String path = p_path.replace("/", "\\");
|
||||||
|
String command = _quote_command_line_argument(path);
|
||||||
|
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||||
|
command += " " + _quote_command_line_argument(E->get());
|
||||||
|
}
|
||||||
|
|
||||||
if (p_blocking && r_pipe) {
|
if (r_pipe) {
|
||||||
String argss = _quote_command_line_argument(path);
|
|
||||||
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
|
||||||
argss += " " + _quote_command_line_argument(E->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_stderr) {
|
if (read_stderr) {
|
||||||
argss += " 2>&1"; // Read stderr too
|
command += " 2>&1"; // Include stderr
|
||||||
}
|
}
|
||||||
// Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command.
|
// Add extra quotes around the full command, to prevent it from stripping quotes in the command,
|
||||||
argss = _quote_command_line_argument(argss);
|
// because _wpopen calls command as "cmd.exe /c command", instead of executing it directly
|
||||||
|
command = _quote_command_line_argument(command);
|
||||||
FILE *f = _wpopen((LPCWSTR)(argss.utf16().get_data()), L"r");
|
|
||||||
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
|
|
||||||
|
|
||||||
|
FILE *f = _wpopen((LPCWSTR)(command.utf16().get_data()), L"r");
|
||||||
|
ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command);
|
||||||
char buf[65535];
|
char buf[65535];
|
||||||
while (fgets(buf, 65535, f)) {
|
while (fgets(buf, 65535, f)) {
|
||||||
if (p_pipe_mutex) {
|
if (p_pipe_mutex) {
|
||||||
@ -438,49 +437,57 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
|
|||||||
p_pipe_mutex->unlock();
|
p_pipe_mutex->unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int rv = _pclose(f);
|
int rv = _pclose(f);
|
||||||
|
|
||||||
if (r_exitcode) {
|
if (r_exitcode) {
|
||||||
*r_exitcode = rv;
|
*r_exitcode = rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
String cmdline = _quote_command_line_argument(path);
|
|
||||||
const List<String>::Element *I = p_arguments.front();
|
|
||||||
while (I) {
|
|
||||||
cmdline += " " + _quote_command_line_argument(I->get());
|
|
||||||
I = I->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessInfo pi;
|
ProcessInfo pi;
|
||||||
ZeroMemory(&pi.si, sizeof(pi.si));
|
ZeroMemory(&pi.si, sizeof(pi.si));
|
||||||
pi.si.cb = sizeof(pi.si);
|
pi.si.cb = sizeof(pi.si);
|
||||||
ZeroMemory(&pi.pi, sizeof(pi.pi));
|
ZeroMemory(&pi.pi, sizeof(pi.pi));
|
||||||
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
|
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
|
||||||
|
|
||||||
Char16String modstr = cmdline.utf16(); // Windows wants to change this no idea why.
|
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
|
||||||
int ret = CreateProcessW(nullptr, (LPWSTR)(modstr.ptrw()), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
|
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
|
||||||
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
|
|
||||||
|
|
||||||
if (p_blocking) {
|
WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
||||||
WaitForSingleObject(pi.pi.hProcess, INFINITE);
|
if (r_exitcode) {
|
||||||
if (r_exitcode) {
|
DWORD ret2;
|
||||||
DWORD ret2;
|
GetExitCodeProcess(pi.pi.hProcess, &ret2);
|
||||||
GetExitCodeProcess(pi.pi.hProcess, &ret2);
|
*r_exitcode = ret2;
|
||||||
*r_exitcode = ret2;
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(pi.pi.hProcess);
|
|
||||||
CloseHandle(pi.pi.hThread);
|
|
||||||
} else {
|
|
||||||
ProcessID pid = pi.pi.dwProcessId;
|
|
||||||
if (r_child_id) {
|
|
||||||
*r_child_id = pid;
|
|
||||||
}
|
|
||||||
process_map->insert(pid, pi);
|
|
||||||
}
|
}
|
||||||
|
CloseHandle(pi.pi.hProcess);
|
||||||
|
CloseHandle(pi.pi.hThread);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
Error OS_Windows::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id) {
|
||||||
|
String path = p_path.replace("/", "\\");
|
||||||
|
String command = _quote_command_line_argument(path);
|
||||||
|
for (const List<String>::Element *E = p_arguments.front(); E; E = E->next()) {
|
||||||
|
command += " " + _quote_command_line_argument(E->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessInfo pi;
|
||||||
|
ZeroMemory(&pi.si, sizeof(pi.si));
|
||||||
|
pi.si.cb = sizeof(pi.si);
|
||||||
|
ZeroMemory(&pi.pi, sizeof(pi.pi));
|
||||||
|
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
|
||||||
|
|
||||||
|
int ret = CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, false, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
|
||||||
|
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
|
||||||
|
|
||||||
|
ProcessID pid = pi.pi.dwProcessId;
|
||||||
|
if (r_child_id) {
|
||||||
|
*r_child_id = pid;
|
||||||
|
}
|
||||||
|
process_map->insert(pid, pi);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,7 +136,8 @@ public:
|
|||||||
virtual void delay_usec(uint32_t p_usec) const override;
|
virtual void delay_usec(uint32_t p_usec) const override;
|
||||||
virtual uint64_t get_ticks_usec() const override;
|
virtual uint64_t get_ticks_usec() const override;
|
||||||
|
|
||||||
virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
|
||||||
|
virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) override;
|
||||||
virtual Error kill(const ProcessID &p_pid) override;
|
virtual Error kill(const ProcessID &p_pid) override;
|
||||||
virtual int get_process_id() const override;
|
virtual int get_process_id() const override;
|
||||||
|
|
||||||
|
@ -617,7 +617,7 @@ MainLoop *test() {
|
|||||||
|
|
||||||
List<String> args;
|
List<String> args;
|
||||||
args.push_back("-l");
|
args.push_back("-l");
|
||||||
Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret);
|
Error err = OS::get_singleton()->execute("/bin/ls", args, &ret);
|
||||||
print_line("error: " + itos(err));
|
print_line("error: " + itos(err));
|
||||||
print_line(ret);
|
print_line(ret);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user