[gnome-builder] libide-io: add shell routines to libide-io
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide-io: add shell routines to libide-io
- Date: Tue, 12 Jul 2022 06:39:08 +0000 (UTC)
commit 24891ddf477fd2f7035c106e3e466be3eecc5dc5
Author: Christian Hergert <chergert redhat com>
Date: Mon Jul 11 16:37:43 2022 -0700
libide-io: add shell routines to libide-io
These are useful lower in our stack.
src/libide/io/ide-shell-private.h | 30 +++++++
src/libide/io/ide-shell.c | 164 +++++++++++++++++++++++++++++++++++++-
src/libide/io/ide-shell.h | 12 ++-
src/libide/io/meson.build | 1 +
4 files changed, 202 insertions(+), 5 deletions(-)
---
diff --git a/src/libide/io/ide-shell-private.h b/src/libide/io/ide-shell-private.h
new file mode 100644
index 000000000..a10695804
--- /dev/null
+++ b/src/libide/io/ide-shell-private.h
@@ -0,0 +1,30 @@
+/* ide-shell-private.h
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include "ide-shell.h"
+
+G_BEGIN_DECLS
+
+void _ide_guess_shell (void);
+void _ide_guess_user_path (void);
+
+G_END_DECLS
diff --git a/src/libide/io/ide-shell.c b/src/libide/io/ide-shell.c
index 12f9ecb9a..b188167cd 100644
--- a/src/libide/io/ide-shell.c
+++ b/src/libide/io/ide-shell.c
@@ -18,9 +18,16 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+#define G_LOG_DOMAIN "ide-shell"
+
#include "config.h"
-#include "ide-shell.h"
+#include <libide-threading.h>
+
+#include "ide-shell-private.h"
+
+static const char *user_shell = "/bin/sh";
+static const char *user_default_path = SAFE_PATH;
gboolean
ide_shell_supports_dash_c (const char *shell)
@@ -45,3 +52,158 @@ ide_shell_supports_dash_login (const char *shell)
strcmp (shell, "zsh") == 0 || g_str_has_suffix (shell, "/zsh") ||
strcmp (shell, "sh") == 0 || g_str_has_suffix (shell, "/sh");
}
+
+static void
+ide_guess_shell_communicate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeSubprocess *subprocess = (IdeSubprocess *)object;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *stdout_buf = NULL;
+ const char *key = user_data;
+
+ g_assert (IDE_IS_SUBPROCESS (subprocess));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (key != NULL);
+
+ if (!ide_subprocess_communicate_utf8_finish (subprocess, result, &stdout_buf, NULL, &error))
+ {
+ g_warning ("Failure to parse host information: %s", error->message);
+ return;
+ }
+
+ if (stdout_buf != NULL)
+ g_strstrip (stdout_buf);
+
+ g_debug ("Guessed %s as \"%s\"", key, stdout_buf);
+
+ if (ide_str_equal0 (key, "SHELL"))
+ {
+ if (stdout_buf[0] == '/')
+ user_shell = g_steal_pointer (&stdout_buf);
+ }
+ else if (ide_str_equal0 (key, "PATH"))
+ {
+ if (!ide_str_empty0 (stdout_buf))
+ user_default_path = g_steal_pointer (&stdout_buf);
+ }
+}
+
+void
+_ide_guess_shell (void)
+{
+ g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+ g_autoptr(IdeSubprocess) subprocess = NULL;
+ g_autofree gchar *command = NULL;
+ g_autoptr(GError) error = NULL;
+ g_auto(GStrv) argv = NULL;
+
+#ifdef __APPLE__
+ command = g_strdup_printf ("sh -c 'dscacheutil -q user -a name %s | grep ^shell: | cut -f 2 -d \" \"'",
+ g_get_user_name ());
+#else
+ command = g_strdup_printf ("sh -c 'getent passwd %s | head -n1 | cut -f 7 -d :'",
+ g_get_user_name ());
+#endif
+
+ if (!g_shell_parse_argv (command, NULL, &argv, &error))
+ {
+ g_warning ("Failed to parse command into argv: %s",
+ error ? error->message : "unknown error");
+ return;
+ }
+
+ /*
+ * We don't use the runtime shell here, because we want to know
+ * what the host thinks the user shell should be.
+ */
+ launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+
+ ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
+ ide_subprocess_launcher_set_clear_env (launcher, FALSE);
+ ide_subprocess_launcher_set_cwd (launcher, g_get_home_dir ());
+ ide_subprocess_launcher_push_args (launcher, (const gchar * const *)argv);
+
+ if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
+ {
+ g_warning ("Failed to spawn getent: %s", error->message);
+ return;
+ }
+
+ ide_subprocess_communicate_utf8_async (subprocess,
+ NULL,
+ NULL,
+ ide_guess_shell_communicate_cb,
+ (gpointer)"SHELL");
+}
+
+void
+_ide_guess_user_path (void)
+{
+ g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+ g_autoptr(IdeSubprocess) subprocess = NULL;
+ g_autofree gchar *command = NULL;
+ g_autoptr(GError) error = NULL;
+ g_auto(GStrv) argv = NULL;
+
+ command = g_strdup_printf ("sh --login -c 'echo $PATH'");
+
+ if (!g_shell_parse_argv (command, NULL, &argv, &error))
+ {
+ g_warning ("Failed to parse command into argv: %s",
+ error ? error->message : "unknown error");
+ return;
+ }
+
+ launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+ ide_subprocess_launcher_set_run_on_host (launcher, TRUE);
+ ide_subprocess_launcher_set_clear_env (launcher, FALSE);
+ ide_subprocess_launcher_set_cwd (launcher, g_get_home_dir ());
+ ide_subprocess_launcher_push_args (launcher, (const gchar * const *)argv);
+
+ if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
+ {
+ g_warning ("Failed to spawn getent: %s", error->message);
+ return;
+ }
+
+ ide_subprocess_communicate_utf8_async (subprocess,
+ NULL,
+ NULL,
+ ide_guess_shell_communicate_cb,
+ (gpointer)"PATH");
+}
+
+/**
+ * ide_get_user_shell:
+ *
+ * Gets the user preferred shell on the host.
+ *
+ * If the background shell discovery has not yet finished due to
+ * slow or misconfigured getent on the host, this will provide a
+ * sensible fallback.
+ *
+ * Returns: (not nullable): a shell such as "/bin/sh"
+ */
+const gchar *
+ide_get_user_shell (void)
+{
+ return user_shell;
+}
+
+/**
+ * ide_get_user_default_path:
+ *
+ * Gets the default `$PATH` on the system for the user on the host.
+ *
+ * This value is sniffed during startup and will default to `SAFE_PATH`
+ * configured when building Builder until that value has been discovered.
+ *
+ * Returns: (not nullable): a string such as "/bin:/usr/bin"
+ */
+const char *
+ide_get_user_default_path (void)
+{
+ return user_default_path;
+}
diff --git a/src/libide/io/ide-shell.h b/src/libide/io/ide-shell.h
index ac086bae5..d2124f3e8 100644
--- a/src/libide/io/ide-shell.h
+++ b/src/libide/io/ide-shell.h
@@ -24,9 +24,13 @@
G_BEGIN_DECLS
-IDE_AVAILABLE_IN_42
-gboolean ide_shell_supports_dash_c (const char *shell);
-IDE_AVAILABLE_IN_42
-gboolean ide_shell_supports_dash_login (const char *shell);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_shell_supports_dash_c (const char *shell);
+IDE_AVAILABLE_IN_ALL
+gboolean ide_shell_supports_dash_login (const char *shell);
+IDE_AVAILABLE_IN_ALL
+const char *ide_get_user_shell (void);
+IDE_AVAILABLE_IN_ALL
+const char *ide_get_user_default_path (void);
G_END_DECLS
diff --git a/src/libide/io/meson.build b/src/libide/io/meson.build
index 7fa64065b..8dcddbe89 100644
--- a/src/libide/io/meson.build
+++ b/src/libide/io/meson.build
@@ -21,6 +21,7 @@ libide_io_public_headers = [
libide_io_private_headers = [
'ide-gfile-private.h',
+ 'ide-shell-private.h',
]
install_headers(libide_io_public_headers, subdir: libide_io_header_subdir)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]