[gnome-builder] libide/io: use preferred shell for host $PATH discovery
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide/io: use preferred shell for host $PATH discovery
- Date: Tue, 27 Sep 2022 18:43:57 +0000 (UTC)
commit c79803a6ba883d78875d66dfe50947b4f09b3e0e
Author: Christian Hergert <chergert redhat com>
Date: Tue Sep 27 11:42:49 2022 -0700
libide/io: use preferred shell for host $PATH discovery
Previously, we tried to discover the user's preferred shell and host $PATH
environment variables concurrently. That prevents us from being able to use
the users preferred shell to discover $PATH.
The side-effect of this is that we may not pick up environment changes that
are defined in places like ~/.bashrc when bash is the preferred shell.
This fixes that by asynchronously discovering $SHELL, then using that to
run $SHELL -l -c 'echo $PATH' assuming we found a shell that we know
supports -l (for --login shell) and -c (for command). Otherwise, we still
fallback to using /bin/sh for discovery.
This fixes an issue where the podman plugin failed to discover tooling like
rust-analyzer being available within the container because we didn't pick
up environment settings from .bashrc which might give access to rustc,
cargo, rust-analyzer, etc.
Fixes #1822
src/libide/io/ide-shell-private.h | 5 +-
src/libide/io/ide-shell.c | 178 +++++++++++++++++++++++++++++---------
src/main.c | 5 +-
3 files changed, 142 insertions(+), 46 deletions(-)
---
diff --git a/src/libide/io/ide-shell-private.h b/src/libide/io/ide-shell-private.h
index a10695804..d9f8e3135 100644
--- a/src/libide/io/ide-shell-private.h
+++ b/src/libide/io/ide-shell-private.h
@@ -1,6 +1,6 @@
/* ide-shell-private.h
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2022 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
@@ -24,7 +24,6 @@
G_BEGIN_DECLS
-void _ide_guess_shell (void);
-void _ide_guess_user_path (void);
+void _ide_shell_init (void);
G_END_DECLS
diff --git a/src/libide/io/ide-shell.c b/src/libide/io/ide-shell.c
index 77e141206..77b9224fb 100644
--- a/src/libide/io/ide-shell.c
+++ b/src/libide/io/ide-shell.c
@@ -1,6 +1,6 @@
/* ide-shell.c
*
- * Copyright 2021 Christian Hergert <chergert redhat com>
+ * Copyright 2021-2022 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
@@ -79,18 +79,24 @@ ide_guess_shell_communicate_cb (GObject *object,
gpointer user_data)
{
IdeSubprocess *subprocess = (IdeSubprocess *)object;
+ g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
g_autofree gchar *stdout_buf = NULL;
- const char *key = user_data;
+ const char *key;
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_SUBPROCESS (subprocess));
g_assert (G_IS_ASYNC_RESULT (result));
- g_assert (key != NULL);
+ g_assert (IDE_IS_TASK (task));
+
+ key = ide_task_get_task_data (task);
if (!ide_subprocess_communicate_utf8_finish (subprocess, result, &stdout_buf, NULL, &error))
{
- g_warning ("Failure to parse host information: %s", error->message);
- return;
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
}
if (stdout_buf != NULL)
@@ -108,17 +114,36 @@ ide_guess_shell_communicate_cb (GObject *object,
if (!ide_str_empty0 (stdout_buf))
user_default_path = g_steal_pointer (&stdout_buf);
}
+ else
+ {
+ g_critical ("Unknown key %s", key);
+ }
+
+ ide_task_return_boolean (task, TRUE);
+
+ IDE_EXIT;
}
-void
-_ide_guess_shell (void)
+static void
+_ide_guess_shell (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
+ g_autoptr(IdeTask) task = NULL;
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;
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (NULL, cancellable, callback, user_data);
+ ide_task_set_task_data (task, g_strdup ("SHELL"), g_free);
+
#ifdef __APPLE__
command = g_strdup_printf ("sh -c 'dscacheutil -q user -a name %s | grep ^shell: | cut -f 2 -d \" \"'",
g_get_user_name ());
@@ -129,9 +154,8 @@ _ide_guess_shell (void)
if (!g_shell_parse_argv (command, NULL, &argv, &error))
{
- g_warning ("Failed to parse command into argv: %s",
- error ? error->message : "unknown error");
- return;
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
}
/*
@@ -139,60 +163,73 @@ _ide_guess_shell (void)
* 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_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_subprocess_communicate_utf8_async (subprocess,
+ NULL,
+ cancellable,
+ ide_guess_shell_communicate_cb,
+ g_steal_pointer (&task));
- ide_subprocess_communicate_utf8_async (subprocess,
- NULL,
- NULL,
- ide_guess_shell_communicate_cb,
- (gpointer)"SHELL");
+ IDE_EXIT;
}
-void
-_ide_guess_user_path (void)
+static void
+_ide_guess_user_path (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
g_autoptr(IdeSubprocessLauncher) launcher = NULL;
g_autoptr(IdeSubprocess) subprocess = NULL;
- g_autofree gchar *command = NULL;
+ g_autoptr(IdeTask) task = NULL;
g_autoptr(GError) error = NULL;
- g_auto(GStrv) argv = NULL;
- command = g_strdup_printf ("sh --login -c 'echo $PATH'");
+ IDE_ENTRY;
- if (!g_shell_parse_argv (command, NULL, &argv, &error))
- {
- g_warning ("Failed to parse command into argv: %s",
- error ? error->message : "unknown error");
- return;
- }
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ task = ide_task_new (NULL, cancellable, callback, user_data);
+ ide_task_set_task_data (task, g_strdup ("PATH"), g_free);
+
+ /* This works by running 'echo $PATH' on the host, preferably
+ * through the user $SHELL we discovered.
+ */
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)))
+ if (ide_shell_supports_dash_c (user_shell))
{
- g_warning ("Failed to spawn getent: %s", error->message);
- return;
+ ide_subprocess_launcher_push_argv (launcher, user_shell);
+ if (ide_shell_supports_dash_login (user_shell))
+ ide_subprocess_launcher_push_argv (launcher, "-l");
+ ide_subprocess_launcher_push_argv (launcher, "-c");
+ ide_subprocess_launcher_push_argv (launcher, "echo $PATH");
+ }
+ else
+ {
+ ide_subprocess_launcher_push_args (launcher,
+ IDE_STRV_INIT ("/bin/sh", "-l", "-c", "echo $PATH"));
}
- ide_subprocess_communicate_utf8_async (subprocess,
- NULL,
- NULL,
- ide_guess_shell_communicate_cb,
- (gpointer)"PATH");
+ if (!(subprocess = ide_subprocess_launcher_spawn (launcher, NULL, &error)))
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_subprocess_communicate_utf8_async (subprocess,
+ NULL,
+ NULL,
+ ide_guess_shell_communicate_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
}
/**
@@ -227,3 +264,64 @@ ide_get_user_default_path (void)
{
return user_default_path;
}
+
+static void
+ide_shell_init_guess_path_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (object == NULL);
+ g_assert (IDE_IS_TASK (result));
+ g_assert (user_data == NULL);
+
+ if (!ide_task_propagate_boolean (IDE_TASK (result), &error))
+ g_warning ("Failed to guess user $PATH using $SHELL %s: %s",
+ user_shell, error->message);
+
+ IDE_EXIT;
+}
+
+static void
+ide_shell_init_guess_shell_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (object == NULL);
+ g_assert (IDE_IS_TASK (result));
+ g_assert (user_data == NULL);
+
+ if (!ide_task_propagate_boolean (IDE_TASK (result), &error))
+ g_warning ("Failed to guess user $SHELL: %s", error->message);
+
+ _ide_guess_user_path (NULL,
+ ide_shell_init_guess_path_cb,
+ NULL);
+
+ IDE_EXIT;
+}
+
+void
+_ide_shell_init (void)
+{
+ IDE_ENTRY;
+
+ /* First we need to guess the user shell, so that we can potentially
+ * get the path using that shell (instead of just /bin/sh which might
+ * not include things like .bashrc).
+ */
+ _ide_guess_shell (NULL,
+ ide_shell_init_guess_shell_cb,
+ NULL);
+
+ IDE_EXIT;
+}
diff --git a/src/main.c b/src/main.c
index 6f2495bcd..7a4b77282 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,6 @@
/* main.c
*
- * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ * Copyright 2018-2022 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
@@ -298,8 +298,7 @@ main (gint argc,
_ide_thread_pool_init (FALSE);
/* Guess the user $SHELL and $PATH early */
- _ide_guess_shell ();
- _ide_guess_user_path ();
+ _ide_shell_init ();
/* Ensure availability of some symbols possibly dropped in link */
_ide_tweaks_init ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]