summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2023-01-26 17:48:36 +0100
committerhjk <hjk@qt.io>2023-03-24 07:45:35 +0000
commit2766b4004b69377480f9e3a701fd20eb51b578bd (patch)
treecb7e93e91c71ab7a41de1bfff2cfeee0a52f70c3
parentae4e1782214b3284cd8cf8b842909ffa6e2d3aaa (diff)
downloadqt-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.py4
-rw-r--r--src/libs/utils/aspects.cpp15
-rw-r--r--src/libs/utils/aspects.h1
-rw-r--r--src/libs/utils/environment.cpp255
-rw-r--r--src/libs/utils/environment.h98
-rw-r--r--src/libs/utils/filepath.h1
-rw-r--r--src/libs/utils/launchersocket.cpp2
-rw-r--r--src/libs/utils/pathchooser.cpp14
-rw-r--r--src/libs/utils/pathchooser.h2
-rw-r--r--src/libs/utils/qtcprocess.cpp29
-rw-r--r--src/plugins/cmakeprojectmanager/presetsparser.cpp14
-rw-r--r--src/plugins/coreplugin/systemsettings.cpp6
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.cpp13
-rw-r--r--src/plugins/projectexplorer/runconfigurationaspects.h1
-rw-r--r--src/plugins/remotelinux/linuxdevice.cpp10
-rw-r--r--src/plugins/vcsbase/commonvcssettings.cpp6
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()