From 6e276b0a00843e48e1695bf27f3530a32dafe441 Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Mar 2023 10:59:30 +0100 Subject: [PATCH] Utils: Add a way to provide fall-back entries in an environment These are used if a (presumably fully-expanded) environment does not have a value for a certain key. Currently this works only for fully-known environments, but this can at least be delayed until the environment is needed, not when it is set up. Change-Id: I9baaa2d23002ddd574101741a91d5f872e6b0314 Reviewed-by: Marcus Tillmanns Reviewed-by: Qt CI Bot --- src/libs/utils/environment.cpp | 20 ++++++++++++++++++++ src/libs/utils/environment.h | 10 ++++++++-- src/plugins/projectexplorer/runcontrol.cpp | 8 +++----- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index e64db0e2a32..cacd60fcd6f 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -494,6 +494,12 @@ void Environment::set(const QString &key, const QString &value, bool enabled) std::tuple{key, value, enabled}}); } +void Environment::setFallback(const QString &key, const QString &value) +{ + addItem(Item{std::in_place_index_t(), + std::tuple{key, value}}); +} + void Environment::unset(const QString &key) { addItem(Item{std::in_place_index_t(), key}); @@ -536,19 +542,33 @@ const NameValueDictionary &Environment::resolved() const if (m_dict.size() != 0) return m_dict; + m_fullDict = false; for (const Item &item : m_changeItems) { switch (item.index()) { case SetSystemEnvironment: m_dict = Environment::systemEnvironment().toDictionary(); + m_fullDict = true; break; case SetFixedDictionary: m_dict = std::get(item); + m_fullDict = true; break; case SetValue: { auto [key, value, enabled] = std::get(item); m_dict.set(key, value, enabled); break; } + case SetFallbackValue: { + auto [key, value] = std::get(item); + if (m_fullDict) { + if (m_dict.value(key).isEmpty()) + m_dict.set(key, value, true); + } else { + QTC_ASSERT(false, qDebug() << "operating on partial dictionary"); + m_dict.set(key, value, true); + } + break; + } case UnsetValue: m_dict.unset(std::get(item)); break; diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 8424eb1d24b..7afa48ba0bb 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -33,6 +33,7 @@ public: bool hasKey(const QString &key) const; void set(const QString &key, const QString &value, bool enabled = true); + void setFallback(const QString &key, const QString &value); void unset(const QString &key); void modify(const NameValueItems &items); @@ -55,6 +56,7 @@ public: void appendToPath(const FilePaths &values); void setupEnglishOutput(); + void setupSudoAskPass(const FilePath &askPass); FilePath searchInPath(const QString &executable, const FilePaths &additionalDirs = FilePaths(), @@ -95,22 +97,25 @@ public: SetSystemEnvironment, SetFixedDictionary, SetValue, + SetFallbackValue, UnsetValue, PrependOrSet, AppendOrSet, Modify, - SetupEnglishOutput, + SetupEnglishOutput }; using Item = std::variant< std::monostate, // SetSystemEnvironment dummy NameValueDictionary, // SetFixedDictionary std::tuple, // SetValue (key, value, enabled) + std::tuple, // SetFallbackValue (key, value) QString, // UnsetValue (key) std::tuple, // PrependOrSet (key, value, separator) std::tuple, // AppendOrSet (key, value, separator) NameValueItems, // Modify - std::monostate // SetupEnglishOutput + std::monostate, // SetupEnglishOutput + FilePath // SetupSudoAskPass (file path of qtc-askpass or ssh-askpass) >; void addItem(const Item &item); @@ -122,6 +127,7 @@ public: private: mutable QList m_changeItems; mutable NameValueDictionary m_dict; // Latest resolved. + mutable bool m_fullDict = false; }; using EnviromentChange = Environment; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 72b2e76e502..96bbc302ac5 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1069,11 +1069,9 @@ bool RunControl::showPromptToStopDialog(const QString &title, void RunControl::provideAskPassEntry(Environment &env) { - if (env.value("SUDO_ASKPASS").isEmpty()) { - const FilePath askpass = SshSettings::askpassFilePath(); - if (askpass.exists()) - env.set("SUDO_ASKPASS", askpass.toUserOutput()); - } + const FilePath askpass = SshSettings::askpassFilePath(); + if (askpass.exists()) + env.setFallback("SUDO_ASKPASS", askpass.toUserOutput()); } bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to)