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>
This commit is contained in:
hjk
2023-01-26 17:48:36 +01:00
parent ae4e178221
commit 2766b4004b
16 changed files with 261 additions and 206 deletions

View File

@@ -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:

View File

@@ -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())

View File

@@ -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);

View File

@@ -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_changeItems.append(Item{std::in_place_index_t<SetValue>(), QPair<QString, QString>{key, value}});
m_dict.clear();
m_changeItems.append(item);
}
void EnvironmentChange::addUnsetValue(const QString &key)
void Environment::set(const QString &key, const QString &value, bool enabled)
{
m_changeItems.append(Item{std::in_place_index_t<UnsetValue>(), key});
addItem(Item{std::in_place_index_t<SetValue>(),
std::tuple<QString, QString, bool>{key, value, enabled}});
}
void EnvironmentChange::addPrependToPath(const FilePaths &values)
void Environment::unset(const QString &key)
{
addItem(Item{std::in_place_index_t<UnsetValue>(), key});
}
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;
}
/*!

View File

@@ -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) {}
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 { 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); }
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) { m_dict.set(key, value, enabled); }
void unset(const QString &key) { m_dict.unset(key); }
void modify(const NameValueItems &items) { m_dict.modify(items); }
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::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:

View File

@@ -32,7 +32,6 @@ namespace Utils {
class DeviceFileAccess;
class Environment;
class EnvironmentChange;
enum class FileStreamHandle;
template <class ...Args> using Continuation = std::function<void(Args...)>;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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()

View File

@@ -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);
}
/*!

View File

@@ -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);

View File

@@ -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);

View File

@@ -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()