diff options
author | hjk <hjk@qt.io> | 2023-01-26 17:48:36 +0100 |
---|---|---|
committer | hjk <hjk@qt.io> | 2023-03-24 07:45:35 +0000 |
commit | 2766b4004b69377480f9e3a701fd20eb51b578bd (patch) | |
tree | cb7e93e91c71ab7a41de1bfff2cfeee0a52f70c3 | |
parent | ae4e1782214b3284cd8cf8b842909ffa6e2d3aaa (diff) | |
download | qt-creator-2766b4004b69377480f9e3a701fd20eb51b578bd.tar.gz |
Utils: Continue Environment/EnvironmentChange consolidation
Make Environment a stack of changes that gets "expanded" to
a full environment before things are actively accessed.
Later this expansion should be done lazily if possible.
Task-number: QTCREATORBUG-28357
Change-Id: If1c7bfdb9f58b81e71c51ed87ee75d6964a47019
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
-rw-r--r-- | share/qtcreator/debugger/creatortypes.py | 4 | ||||
-rw-r--r-- | src/libs/utils/aspects.cpp | 15 | ||||
-rw-r--r-- | src/libs/utils/aspects.h | 1 | ||||
-rw-r--r-- | src/libs/utils/environment.cpp | 255 | ||||
-rw-r--r-- | src/libs/utils/environment.h | 98 | ||||
-rw-r--r-- | src/libs/utils/filepath.h | 1 | ||||
-rw-r--r-- | src/libs/utils/launchersocket.cpp | 2 | ||||
-rw-r--r-- | src/libs/utils/pathchooser.cpp | 14 | ||||
-rw-r--r-- | src/libs/utils/pathchooser.h | 2 | ||||
-rw-r--r-- | src/libs/utils/qtcprocess.cpp | 29 | ||||
-rw-r--r-- | src/plugins/cmakeprojectmanager/presetsparser.cpp | 14 | ||||
-rw-r--r-- | src/plugins/coreplugin/systemsettings.cpp | 6 | ||||
-rw-r--r-- | src/plugins/projectexplorer/runconfigurationaspects.cpp | 13 | ||||
-rw-r--r-- | src/plugins/projectexplorer/runconfigurationaspects.h | 1 | ||||
-rw-r--r-- | src/plugins/remotelinux/linuxdevice.cpp | 10 | ||||
-rw-r--r-- | src/plugins/vcsbase/commonvcssettings.cpp | 6 |
16 files changed, 263 insertions, 208 deletions
diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index af79054460..a11377b0db 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -235,7 +235,7 @@ def qdump__Utils__Port(d, value): -def qdump__Utils__Environment(d, value): +def x_qdump__Utils__Environment(d, value): qdump__Utils__NameValueDictionary(d, value) @@ -243,7 +243,7 @@ def qdump__Utils__DictKey(d, value): d.putStringValue(value["name"]) -def qdump__Utils__NameValueDictionary(d, value): +def x_qdump__Utils__NameValueDictionary(d, value): dptr = d.extractPointer(value) if d.qtVersion() >= 0x60000: if dptr == 0: diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 51be951a8f..aed8c851d1 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -632,7 +632,7 @@ public: QString m_placeHolderText; QString m_historyCompleterKey; PathChooser::Kind m_expectedKind = PathChooser::File; - EnvironmentChange m_environmentChange; + Environment m_environment; QPointer<ElidingLabel> m_labelDisplay; QPointer<FancyLineEdit> m_lineEditDisplay; QPointer<PathChooser> m_pathChooserDisplay; @@ -975,16 +975,11 @@ void StringAspect::setExpectedKind(const PathChooser::Kind expectedKind) d->m_pathChooserDisplay->setExpectedKind(expectedKind); } -void StringAspect::setEnvironmentChange(const EnvironmentChange &change) -{ - d->m_environmentChange = change; - if (d->m_pathChooserDisplay) - d->m_pathChooserDisplay->setEnvironmentChange(change); -} - void StringAspect::setEnvironment(const Environment &env) { - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); + d->m_environment = env; + if (d->m_pathChooserDisplay) + d->m_pathChooserDisplay->setEnvironment(env); } void StringAspect::setBaseFileName(const FilePath &baseFileName) @@ -1082,7 +1077,7 @@ void StringAspect::addToLayout(Layouting::LayoutBuilder &builder) d->m_pathChooserDisplay->setHistoryCompleter(d->m_historyCompleterKey); if (d->m_validator) d->m_pathChooserDisplay->setValidationFunction(d->m_validator); - d->m_pathChooserDisplay->setEnvironmentChange(d->m_environmentChange); + d->m_pathChooserDisplay->setEnvironment(d->m_environment); d->m_pathChooserDisplay->setBaseDirectory(d->m_baseFileName); d->m_pathChooserDisplay->setOpenTerminalHandler(d->m_openTerminal); if (defaultValue() == value()) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index 1aaaca3f29..0b9a560659 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -383,7 +383,6 @@ public: void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); void setExpectedKind(const PathChooser::Kind expectedKind); - void setEnvironmentChange(const EnvironmentChange &change); void setEnvironment(const Environment &env); void setBaseFileName(const FilePath &baseFileName); void setUndoRedoEnabled(bool readOnly); diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index 462eeab31d..e64db0e2a3 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -19,84 +19,137 @@ Q_GLOBAL_STATIC_WITH_ARGS(Environment, staticSystemEnvironment, (QProcessEnvironment::systemEnvironment().toStringList())) Q_GLOBAL_STATIC(QVector<EnvironmentProvider>, environmentProviders) +Environment::Environment() + : m_dict(HostOsInfo::hostOs()) +{} + +Environment::Environment(OsType osType) + : m_dict(osType) +{} + +Environment::Environment(const QStringList &env, OsType osType) + : m_dict(osType) +{ + m_changeItems.append(NameValueDictionary(env, osType)); +} + +Environment::Environment(const NameValuePairs &nameValues) +{ + m_changeItems.append(NameValueDictionary(nameValues)); +} + +Environment::Environment(const NameValueDictionary &dict) +{ + m_changeItems.append(dict); +} + NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const { - return m_dict.diff(other.m_dict, checkAppendPrepend); + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict.diff(otherDict, checkAppendPrepend); } Environment::FindResult Environment::find(const QString &name) const { - const auto it = m_dict.constFind(name); - if (it == m_dict.constEnd()) + const NameValueDictionary &dict = resolved(); + const auto it = dict.constFind(name); + if (it == dict.constEnd()) return {}; return Entry{it.key().name, it.value().first, it.value().second}; } void Environment::forEachEntry(const std::function<void(const QString &, const QString &, bool)> &callBack) const { - for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) + const NameValueDictionary &dict = resolved(); + for (auto it = dict.m_values.constBegin(); it != dict.m_values.constEnd(); ++it) callBack(it.key().name, it.value().first, it.value().second); } +bool Environment::operator==(const Environment &other) const +{ + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict == otherDict; +} + +bool Environment::operator!=(const Environment &other) const +{ + const NameValueDictionary &dict = resolved(); + const NameValueDictionary &otherDict = other.resolved(); + return dict != otherDict; +} + +QString Environment::value(const QString &key) const +{ + const NameValueDictionary &dict = resolved(); + return dict.value(key); +} + +QString Environment::value_or(const QString &key, const QString &defaultValue) const +{ + const NameValueDictionary &dict = resolved(); + return dict.hasKey(key) ? dict.value(key) : defaultValue; +} + +bool Environment::hasKey(const QString &key) const +{ + const NameValueDictionary &dict = resolved(); + return dict.hasKey(key); +} + bool Environment::hasChanges() const { - return m_dict.size() != 0; + const NameValueDictionary &dict = resolved(); + return dict.size() != 0; +} + +OsType Environment::osType() const +{ + return m_dict.m_osType; +} + +QStringList Environment::toStringList() const +{ + const NameValueDictionary &dict = resolved(); + return dict.toStringList(); } QProcessEnvironment Environment::toProcessEnvironment() const { + const NameValueDictionary &dict = resolved(); QProcessEnvironment result; - for (auto it = m_dict.m_values.constBegin(); it != m_dict.m_values.constEnd(); ++it) { + for (auto it = dict.m_values.constBegin(); it != dict.m_values.constEnd(); ++it) { if (it.value().second) - result.insert(it.key().name, expandedValueForKey(m_dict.key(it))); + result.insert(it.key().name, expandedValueForKey(dict.key(it))); } return result; } void Environment::appendOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == osType()); + QTC_CHECK(value.osType() == m_dict.m_osType); if (value.isEmpty()) return; - appendOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(osType()))); + appendOrSet("PATH", value.nativePath(), OsSpecificAspects::pathListSeparator(osType())); } void Environment::prependOrSetPath(const FilePath &value) { - QTC_CHECK(value.osType() == osType()); + QTC_CHECK(value.osType() == m_dict.m_osType); if (value.isEmpty()) return; - prependOrSet("PATH", value.nativePath(), - QString(OsSpecificAspects::pathListSeparator(osType()))); + prependOrSet("PATH", value.nativePath(), OsSpecificAspects::pathListSeparator(osType())); } void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep) { - QTC_ASSERT(!key.contains('='), return ); - const auto it = m_dict.findKey(key); - if (it == m_dict.m_values.end()) { - m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); - } else { - // Append unless it is already there - const QString toAppend = sep + value; - if (!it.value().first.endsWith(toAppend)) - it.value().first.append(toAppend); - } + addItem(Item{std::in_place_index_t<AppendOrSet>(), key, value, sep}); } void Environment::prependOrSet(const QString &key, const QString &value, const QString &sep) { - QTC_ASSERT(!key.contains('='), return ); - const auto it = m_dict.findKey(key); - if (it == m_dict.m_values.end()) { - m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); - } else { - // Prepend unless it is already there - const QString toPrepend = value + sep; - if (!it.value().first.startsWith(toPrepend)) - it.value().first.prepend(toPrepend); - } + addItem(Item{std::in_place_index_t<PrependOrSet>(), key, value, sep}); } void Environment::prependOrSetLibrarySearchPath(const FilePath &value) @@ -105,11 +158,11 @@ void Environment::prependOrSetLibrarySearchPath(const FilePath &value) switch (osType()) { case OsTypeWindows: { const QChar sep = ';'; - prependOrSet("PATH", value.nativePath(), QString(sep)); + prependOrSet("PATH", value.nativePath(), sep); break; } case OsTypeMac: { - const QString sep = ":"; + const QChar sep = ':'; const QString nativeValue = value.nativePath(); prependOrSet("DYLD_LIBRARY_PATH", nativeValue, sep); prependOrSet("DYLD_FRAMEWORK_PATH", nativeValue, sep); @@ -118,7 +171,7 @@ void Environment::prependOrSetLibrarySearchPath(const FilePath &value) case OsTypeLinux: case OsTypeOtherUnix: { const QChar sep = ':'; - prependOrSet("LD_LIBRARY_PATH", value.nativePath(), QString(sep)); + prependOrSet("LD_LIBRARY_PATH", value.nativePath(), sep); break; } default: @@ -141,8 +194,7 @@ Environment Environment::systemEnvironment() void Environment::setupEnglishOutput() { - m_dict.set("LC_MESSAGES", "en_US.utf8"); - m_dict.set("LANGUAGE", "en_US:en"); + addItem(Item{std::in_place_index_t<SetupEnglishOutput>()}); } using SearchResultCallback = std::function<IterationPolicy(const FilePath &)>; @@ -190,7 +242,8 @@ static FilePaths appendExeExtensions(const Environment &env, const FilePath &exe QString Environment::expandedValueForKey(const QString &key) const { - return expandVariables(m_dict.value(key)); + const NameValueDictionary &dict = resolved(); + return expandVariables(dict.value(key)); } static void searchInDirectoriesHelper(const SearchResultCallback &resultCallback, @@ -324,14 +377,16 @@ void Environment::setSystemEnvironment(const Environment &environment) */ QString Environment::expandVariables(const QString &input) const { + const NameValueDictionary &dict = resolved(); + QString result = input; if (osType() == OsTypeWindows) { for (int vStart = -1, i = 0; i < result.length(); ) { if (result.at(i++) == '%') { if (vStart > 0) { - const auto it = m_dict.findKey(result.mid(vStart, i - vStart - 1)); - if (it != m_dict.m_values.constEnd()) { + const auto it = dict.findKey(result.mid(vStart, i - vStart - 1)); + if (it != dict.m_values.constEnd()) { result.replace(vStart - 1, i - vStart + 1, it->first); i = vStart - 1 + it->first.length(); vStart = -1; @@ -403,6 +458,12 @@ QStringList Environment::expandVariables(const QStringList &variables) const return transform(variables, [this](const QString &i) { return expandVariables(i); }); } +NameValueDictionary Environment::toDictionary() const +{ + const NameValueDictionary &dict = resolved(); + return dict; +} + void EnvironmentProvider::addProvider(EnvironmentProvider &&provider) { environmentProviders->append(std::move(provider)); @@ -421,63 +482,125 @@ std::optional<EnvironmentProvider> EnvironmentProvider::provider(const QByteArra return std::nullopt; } -void EnvironmentChange::addSetValue(const QString &key, const QString &value) +void Environment::addItem(const Item &item) +{ + m_dict.clear(); + m_changeItems.append(item); +} + +void Environment::set(const QString &key, const QString &value, bool enabled) { - m_changeItems.append(Item{std::in_place_index_t<SetValue>(), QPair<QString, QString>{key, value}}); + addItem(Item{std::in_place_index_t<SetValue>(), + std::tuple<QString, QString, bool>{key, value, enabled}}); } -void EnvironmentChange::addUnsetValue(const QString &key) +void Environment::unset(const QString &key) { - m_changeItems.append(Item{std::in_place_index_t<UnsetValue>(), key}); + addItem(Item{std::in_place_index_t<UnsetValue>(), key}); } -void EnvironmentChange::addPrependToPath(const FilePaths &values) +void Environment::modify(const NameValueItems &items) { + addItem(Item{std::in_place_index_t<Modify>(), items}); +} + +void Environment::prependToPath(const FilePaths &values) +{ + m_dict.clear(); for (int i = values.size(); --i >= 0; ) { const FilePath value = values.at(i); - m_changeItems.append(Item{std::in_place_index_t<PrependToPath>(), value}); + m_changeItems.append(Item{ + std::in_place_index_t<PrependOrSet>(), + QString("PATH"), + value.nativePath(), + value.pathListSeparator() + }); } } -void EnvironmentChange::addAppendToPath(const FilePaths &values) +void Environment::appendToPath(const FilePaths &values) { - for (const FilePath &value : values) - m_changeItems.append(Item{std::in_place_index_t<AppendToPath>(), value}); + m_dict.clear(); + for (const FilePath &value : values) { + m_changeItems.append(Item{ + std::in_place_index_t<AppendOrSet>(), + QString("PATH"), + value.nativePath(), + value.pathListSeparator() + }); + } } -EnvironmentChange EnvironmentChange::fromDictionary(const NameValueDictionary &dict) +const NameValueDictionary &Environment::resolved() const { - EnvironmentChange change; - change.m_changeItems.append(Item{std::in_place_index_t<SetFixedDictionary>(), dict}); - return change; -} + if (m_dict.size() != 0) + return m_dict; -void EnvironmentChange::applyToEnvironment(Environment &env) const -{ for (const Item &item : m_changeItems) { switch (item.index()) { case SetSystemEnvironment: - env = Environment::systemEnvironment(); + m_dict = Environment::systemEnvironment().toDictionary(); break; case SetFixedDictionary: - env = Environment(std::get<SetFixedDictionary>(item)); + m_dict = std::get<SetFixedDictionary>(item); break; case SetValue: { - const QPair<QString, QString> data = std::get<SetValue>(item); - env.set(data.first, data.second); + auto [key, value, enabled] = std::get<SetValue>(item); + m_dict.set(key, value, enabled); break; } case UnsetValue: - env.unset(std::get<UnsetValue>(item)); + m_dict.unset(std::get<UnsetValue>(item)); break; - case PrependToPath: - env.prependOrSetPath(std::get<PrependToPath>(item)); + case PrependOrSet: { + auto [key, value, sep] = std::get<PrependOrSet>(item); + QTC_ASSERT(!key.contains('='), return m_dict); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); + } else { + // Prepend unless it is already there + const QString toPrepend = value + sep; + if (!it.value().first.startsWith(toPrepend)) + it.value().first.prepend(toPrepend); + } break; - case AppendToPath: - env.appendOrSetPath(std::get<AppendToPath>(item)); + } + case AppendOrSet: { + auto [key, value, sep] = std::get<AppendOrSet>(item); + QTC_ASSERT(!key.contains('='), return m_dict); + const auto it = m_dict.findKey(key); + if (it == m_dict.m_values.end()) { + m_dict.m_values.insert(DictKey(key, m_dict.nameCaseSensitivity()), {value, true}); + } else { + // Prepend unless it is already there + const QString toAppend = sep + value; + if (!it.value().first.endsWith(toAppend)) + it.value().first.append(toAppend); + } + break; + } + case Modify: { + NameValueItems items = std::get<Modify>(item); + m_dict.modify(items); + break; + } + case SetupEnglishOutput: + m_dict.set("LC_MESSAGES", "en_US.utf8"); + m_dict.set("LANGUAGE", "en_US:en"); break; } } + + return m_dict; +} + +Environment Environment::appliedToEnvironment(const Environment &base) const +{ + Environment res = base; + res.m_dict.clear(); + res.m_changeItems.append(m_changeItems); + return res; } /*! diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 541a730965..8424eb1d24 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -22,27 +22,24 @@ namespace Utils { class QTCREATOR_UTILS_EXPORT Environment final { public: - Environment() : m_dict(HostOsInfo::hostOs()) {} - explicit Environment(OsType osType) : m_dict(osType) {} - explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()) - : m_dict(env, osType) {} - explicit Environment(const NameValuePairs &nameValues) : m_dict(nameValues) {} - explicit Environment(const NameValueDictionary &dict) : m_dict(dict) {} - - QString value(const QString &key) const { return m_dict.value(key); } - QString value_or(const QString &key, const QString &defaultValue) const - { - return m_dict.hasKey(key) ? m_dict.value(key) : defaultValue; - } - bool hasKey(const QString &key) const { return m_dict.hasKey(key); } - - void set(const QString &key, const QString &value, bool enabled = true) { m_dict.set(key, value, enabled); } - void unset(const QString &key) { m_dict.unset(key); } - void modify(const NameValueItems &items) { m_dict.modify(items); } + Environment(); + explicit Environment(OsType osType); + explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs()); + explicit Environment(const NameValuePairs &nameValues); + explicit Environment(const NameValueDictionary &dict); + + QString value(const QString &key) const; + QString value_or(const QString &key, const QString &defaultValue) const; + bool hasKey(const QString &key) const; + + void set(const QString &key, const QString &value, bool enabled = true); + void unset(const QString &key); + void modify(const NameValueItems &items); bool hasChanges() const; - QStringList toStringList() const { return m_dict.toStringList(); } + OsType osType() const; + QStringList toStringList() const; QProcessEnvironment toProcessEnvironment() const; void appendOrSet(const QString &key, const QString &value, const QString &sep = QString()); @@ -54,6 +51,9 @@ public: void prependOrSetLibrarySearchPath(const FilePath &value); void prependOrSetLibrarySearchPaths(const FilePaths &values); + void prependToPath(const FilePaths &values); + void appendToPath(const FilePaths &values); + void setupEnglishOutput(); FilePath searchInPath(const QString &executable, @@ -74,76 +74,58 @@ public: FilePath expandVariables(const FilePath &input) const; QStringList expandVariables(const QStringList &input) const; - OsType osType() const { return m_dict.osType(); } - - NameValueDictionary toDictionary() const { return m_dict; } // FIXME: avoid + NameValueDictionary toDictionary() const; // FIXME: avoid NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid - void setCombineWithDeviceEnvironment(bool combine) { m_combineWithDeviceEnvironment = combine; } - bool combineWithDeviceEnvironment() const { return m_combineWithDeviceEnvironment; } - struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional<Entry>; FindResult find(const QString &name) const; // Note res->key may differ in case from name. void forEachEntry(const std::function<void (const QString &, const QString &, bool)> &callBack) const; - friend bool operator!=(const Environment &first, const Environment &second) - { - return first.m_dict != second.m_dict; - } - - friend bool operator==(const Environment &first, const Environment &second) - { - return first.m_dict == second.m_dict; - } + bool operator!=(const Environment &other) const; + bool operator==(const Environment &other) const; static Environment systemEnvironment(); static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!! static void setSystemEnvironment(const Environment &environment); // don't use at all!!! -private: - NameValueDictionary m_dict; - bool m_combineWithDeviceEnvironment = true; -}; - -class QTCREATOR_UTILS_EXPORT EnvironmentChange final -{ -public: - EnvironmentChange() = default; - enum Type { SetSystemEnvironment, SetFixedDictionary, SetValue, UnsetValue, - PrependToPath, - AppendToPath, + PrependOrSet, + AppendOrSet, + Modify, + SetupEnglishOutput, }; using Item = std::variant< - std::monostate, // SetSystemEnvironment dummy - NameValueDictionary, // SetFixedDictionary - QPair<QString, QString>, // SetValue - QString, // UnsetValue - FilePath, // PrependToPath - FilePath // AppendToPath + std::monostate, // SetSystemEnvironment dummy + NameValueDictionary, // SetFixedDictionary + std::tuple<QString, QString, bool>, // SetValue (key, value, enabled) + QString, // UnsetValue (key) + std::tuple<QString, QString, QString>, // PrependOrSet (key, value, separator) + std::tuple<QString, QString, QString>, // AppendOrSet (key, value, separator) + NameValueItems, // Modify + std::monostate // SetupEnglishOutput >; - static EnvironmentChange fromDictionary(const NameValueDictionary &dict); + void addItem(const Item &item); - void applyToEnvironment(Environment &) const; + Environment appliedToEnvironment(const Environment &base) const; - void addSetValue(const QString &key, const QString &value); - void addUnsetValue(const QString &key); - void addPrependToPath(const FilePaths &values); - void addAppendToPath(const FilePaths &values); + const NameValueDictionary &resolved() const; private: - QList<Item> m_changeItems; + mutable QList<Item> m_changeItems; + mutable NameValueDictionary m_dict; // Latest resolved. }; +using EnviromentChange = Environment; + class QTCREATOR_UTILS_EXPORT EnvironmentProvider { public: diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 0ecdc09dab..220c6de5da 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -32,7 +32,6 @@ namespace Utils { class DeviceFileAccess; class Environment; -class EnvironmentChange; enum class FileStreamHandle; template <class ...Args> using Continuation = std::function<void(Args...)>; diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index f4feda595a..ccf2ee7b2f 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -246,6 +246,8 @@ void CallerHandle::start(const QString &program, const QStringList &arguments) p.command = m_command; p.arguments = m_arguments; p.env = m_setup->m_environment.toStringList(); + if (p.env.isEmpty()) + p.env = Environment::systemEnvironment().toStringList(); p.workingDir = m_setup->m_workingDirectory.path(); p.processMode = m_setup->m_processMode; p.writeData = m_setup->m_writeData; diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 53825931b9..0f0737f54c 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -171,7 +171,7 @@ public: FilePath m_initialBrowsePathOverride; QString m_defaultValue; FilePath m_baseDirectory; - EnvironmentChange m_environmentChange; + Environment m_environment; BinaryVersionToolTipEventFilter *m_binaryVersionToolTipEventFilter = nullptr; QList<QAbstractButton *> m_buttons; const MacroExpander *m_macroExpander = globalMacroExpander(); @@ -196,8 +196,7 @@ FilePath PathChooserPrivate::expandedPath(const FilePath &input) const FilePath path = input; - Environment env = path.deviceEnvironment(); - m_environmentChange.applyToEnvironment(env); + Environment env = m_environment.appliedToEnvironment(path.deviceEnvironment()); path = env.expandVariables(path); if (m_macroExpander) @@ -324,20 +323,15 @@ void PathChooser::setBaseDirectory(const FilePath &base) triggerChanged(); } -void PathChooser::setEnvironment(const Environment &env) -{ - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); -} - FilePath PathChooser::baseDirectory() const { return d->m_baseDirectory; } -void PathChooser::setEnvironmentChange(const EnvironmentChange &env) +void PathChooser::setEnvironment(const Environment &env) { QString oldExpand = filePath().toString(); - d->m_environmentChange = env; + d->m_environment = env; if (filePath().toString() != oldExpand) { triggerChanged(); emit rawPathChanged(); diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h index 92b5973b2d..62a370185d 100644 --- a/src/libs/utils/pathchooser.h +++ b/src/libs/utils/pathchooser.h @@ -20,7 +20,6 @@ namespace Utils { class CommandLine; class MacroExpander; class Environment; -class EnvironmentChange; class PathChooserPrivate; class QTCREATOR_UTILS_EXPORT PathChooser : public QWidget @@ -77,7 +76,6 @@ public: void setBaseDirectory(const FilePath &base); void setEnvironment(const Environment &env); - void setEnvironmentChange(const EnvironmentChange &change); /** Returns the suggested label title when used in a form layout. */ static QString label(); diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 04276a610b..5220e8b5d5 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -353,13 +353,18 @@ public: return; } + QProcessEnvironment penv = m_setup.m_environment.toProcessEnvironment(); + if (penv.isEmpty()) + penv = Environment::systemEnvironment().toProcessEnvironment(); + const QStringList senv = penv.toStringList(); + bool startResult = m_ptyProcess->startProcess(program, HostOsInfo::isWindowsHost() ? QStringList{m_setup.m_nativeArguments} << arguments : arguments, m_setup.m_workingDirectory.nativePath(), - m_setup.m_environment.toProcessEnvironment().toStringList(), + senv, m_setup.m_ptyData->size().width(), m_setup.m_ptyData->size().height()); @@ -458,7 +463,9 @@ private: handler->setWindowsSpecificStartupFlags(m_setup.m_belowNormalPriority, m_setup.m_createConsoleOnWindows); - m_process->setProcessEnvironment(m_setup.m_environment.toProcessEnvironment()); + const QProcessEnvironment penv = m_setup.m_environment.toProcessEnvironment(); + if (!penv.isEmpty()) + m_process->setProcessEnvironment(penv); m_process->setWorkingDirectory(m_setup.m_workingDirectory.path()); m_process->setStandardInputFile(m_setup.m_standardInputFile); m_process->setProcessChannelMode(m_setup.m_processChannelMode); @@ -715,7 +722,6 @@ public: , q(parent) , m_killTimer(this) { - m_setup.m_controlEnvironment = Environment::systemEnvironment(); m_killTimer.setSingleShot(true); connect(&m_killTimer, &QTimer::timeout, this, [this] { m_killTimer.stop(); @@ -769,22 +775,6 @@ public: return rootCommand; } - Environment fullEnvironment() const - { - Environment env = m_setup.m_environment; - if (!env.hasChanges() && env.combineWithDeviceEnvironment()) { - // FIXME: Either switch to using EnvironmentChange instead of full Environments, or - // feed the full environment into the QtcProcess instead of fixing it up here. - // qWarning("QtcProcess::start: Empty environment set when running '%s'.", - // qPrintable(m_setup.m_commandLine.executable().toString())); - env = m_setup.m_commandLine.executable().deviceEnvironment(); - } - // TODO: needs SshSettings - // if (m_runAsRoot) - // RunControl::provideAskPassEntry(env); - return env; - } - QtcProcess *q; std::unique_ptr<ProcessBlockingInterface> m_blockingInterface; std::unique_ptr<ProcessInterface> m_process; @@ -1227,7 +1217,6 @@ void QtcProcess::start() d->m_state = QProcess::Starting; d->m_process->m_setup = d->m_setup; d->m_process->m_setup.m_commandLine = d->fullCommandLine(); - d->m_process->m_setup.m_environment = d->fullEnvironment(); d->emitGuardedSignal(&QtcProcess::starting); d->m_process->start(); } diff --git a/src/plugins/cmakeprojectmanager/presetsparser.cpp b/src/plugins/cmakeprojectmanager/presetsparser.cpp index ceb67a50be..06c12de840 100644 --- a/src/plugins/cmakeprojectmanager/presetsparser.cpp +++ b/src/plugins/cmakeprojectmanager/presetsparser.cpp @@ -482,16 +482,6 @@ static QHash<QString, QString> merge(const QHash<QString, QString> &first, return result; } -static Utils::Environment merge(const Utils::Environment &first, const Utils::Environment &second) -{ - Utils::Environment result = first; - second.forEachEntry([&](const QString &key, const QString &value, bool) { - result.set(key, value); - }); - - return result; -} - static CMakeConfig merge(const CMakeConfig &first, const CMakeConfig &second) { return Utils::setUnionMerge<CMakeConfig>( @@ -549,7 +539,7 @@ void PresetsDetails::ConfigurePreset::inheritFrom(const ConfigurePreset &other) if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = merge(other.environment.value(), environment.value()); + environment = environment.value().appliedToEnvironment(other.environment.value()); if (!warnings && other.warnings) warnings = other.warnings; @@ -575,7 +565,7 @@ void PresetsDetails::BuildPreset::inheritFrom(const BuildPreset &other) if (!environment && other.environment) environment = other.environment; else if (environment && other.environment) - environment = merge(other.environment.value(), environment.value()); + environment = environment.value().appliedToEnvironment(other.environment.value()); if (!configurePreset && other.configurePreset) configurePreset = other.configurePreset; diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index f34e7fb5b7..a65f7fee8b 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -438,9 +438,9 @@ void SystemSettingsWidget::resetFileBrowser() void SystemSettingsWidget::updatePath() { - EnvironmentChange change; - change.addAppendToPath(VcsManager::additionalToolsPath()); - m_patchChooser->setEnvironmentChange(change); + Environment env; + env.appendToPath(VcsManager::additionalToolsPath()); + m_patchChooser->setEnvironment(env); } void SystemSettingsWidget::updateEnvironmentChangesLabel() diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 9ba24c0467..7e278d353e 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -570,19 +570,12 @@ void ExecutableAspect::setExpectedKind(const PathChooser::Kind expectedKind) Sets the environment in which paths will be searched when the expected kind of paths is chosen as PathChooser::Command or PathChooser::ExistingCommand to \a env. - - \sa Utils::StringAspect::setEnvironmentChange() */ -void ExecutableAspect::setEnvironmentChange(const EnvironmentChange &change) -{ - m_executable.setEnvironmentChange(change); - if (m_alternativeExecutable) - m_alternativeExecutable->setEnvironmentChange(change); -} - void ExecutableAspect::setEnvironment(const Environment &env) { - setEnvironmentChange(EnvironmentChange::fromDictionary(env.toDictionary())); + m_executable.setEnvironment(env); + if (m_alternativeExecutable) + m_alternativeExecutable->setEnvironment(env); } /*! diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index 9e948bc6ec..9656c2f5bd 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -168,7 +168,6 @@ public: void setPlaceHolderText(const QString &placeHolderText); void setHistoryCompleter(const QString &historyCompleterKey); void setExpectedKind(const Utils::PathChooser::Kind expectedKind); - void setEnvironmentChange(const Utils::EnvironmentChange &change); void setEnvironment(const Utils::Environment &env); void setDisplayStyle(Utils::StringAspect::DisplayStyle style); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 191ee9d5d3..aa5889516c 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -338,9 +338,6 @@ Environment LinuxDevicePrivate::getEnvironment() QtcProcess getEnvProc; getEnvProc.setCommand({FilePath("env").onDevice(q->rootPath()), {}}); - Environment inEnv; - inEnv.setCombineWithDeviceEnvironment(false); - getEnvProc.setEnvironment(inEnv); getEnvProc.runBlocking(); const QString remoteOutput = getEnvProc.cleanedStdOut(); @@ -919,16 +916,11 @@ LinuxDevice::LinuxDevice() d->m_terminals.removeOne(proc); }); - // We recreate the same way that QtcProcess uses to create the actual environment. - const Environment finalEnv = (!env.hasChanges() && env.combineWithDeviceEnvironment()) - ? d->getEnvironment() - : env; // If we will not set any environment variables, we can leave out the shell executable // as the "ssh ..." call will automatically launch the default shell if there are // no arguments. But if we will set environment variables, we need to explicitly // specify the shell executable. - const QString shell = finalEnv.hasChanges() ? finalEnv.value_or("SHELL", "/bin/sh") - : QString(); + const QString shell = env.hasChanges() ? env.value_or("SHELL", "/bin/sh") : QString(); proc->setCommand({filePath(shell), {}}); proc->setTerminalMode(TerminalMode::On); diff --git a/src/plugins/vcsbase/commonvcssettings.cpp b/src/plugins/vcsbase/commonvcssettings.cpp index 160095d38d..2f970ccbb8 100644 --- a/src/plugins/vcsbase/commonvcssettings.cpp +++ b/src/plugins/vcsbase/commonvcssettings.cpp @@ -135,9 +135,9 @@ CommonSettingsWidget::CommonSettingsWidget(CommonOptionsPage *page) void CommonSettingsWidget::updatePath() { - EnvironmentChange change; - change.addAppendToPath(Core::VcsManager::additionalToolsPath()); - m_page->settings().sshPasswordPrompt.setEnvironmentChange(change); + Environment env; + env.appendToPath(Core::VcsManager::additionalToolsPath()); + m_page->settings().sshPasswordPrompt.setEnvironment(env); } void CommonSettingsWidget::apply() |