diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index 662337cca79..f230b71252d 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -141,7 +141,7 @@ void QdbDevice::setupDefaultNetworkSettings(const QString &host) parameters.setPort(22); parameters.setTimeout(10); parameters.setAuthenticationType(SshParameters::AuthenticationTypeAll); - setSshParameters(parameters); + setDefaultSshParameters(parameters); } // QdbDeviceWizard diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 38741e04420..c1a451ee77c 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -380,7 +380,7 @@ ExecutableItem debugServerRecipe(const Storage &storage, const Sin const auto port = runControl->debugChannel().port(); cmd.addArg(QString(":%1").arg(port)); - if (runControl->device()->extraData(ProjectExplorer::Constants::SSH_FORWARD_DEBUGSERVER_PORT).toBool()) { + if (runControl->device()->sshForwardDebugServerPort()) { QVariantHash extraData; extraData[RemoteLinux::Constants::SshForwardPort] = port; extraData[RemoteLinux::Constants::DisableSharing] = true; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index c2f5cecd3f8..89599a071fa 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -30,6 +30,7 @@ #include #include +#include #include /*! @@ -115,6 +116,9 @@ const char HostKeyCheckingKey[] = "HostKeyChecking"; const char DebugServerKey[] = "DebugServerKey"; const char QmlRuntimeKey[] = "QmlsceneKey"; +const char SshForwardDebugServerPortKey[] = "SshForwardDebugServerPort"; +const char LinkDeviceKey[] = "LinkDevice"; + using AuthType = SshParameters::AuthenticationType; const AuthType DefaultAuthType = SshParameters::AuthenticationTypeAll; const IDevice::MachineType DefaultMachineType = IDevice::Hardware; @@ -139,16 +143,14 @@ public: Utils::SynchronizedValue sshParameters; - PortList freePorts; - QList deviceIcons; QList deviceActions; Store extraData; IDevice::OpenTerminal openTerminal; Utils::StringAspect displayName; - Utils::FilePathAspect debugServerPath; - Utils::FilePathAspect qmlRunCommand; + + SshParametersAspectContainer sshParametersAspectContainer; bool isTesting = false; }; @@ -172,12 +174,49 @@ IDevice::IDevice() { setAutoApply(false); + registerAspect(&d->sshParametersAspectContainer); + + connect(&d->sshParametersAspectContainer, &AspectContainer::applied, this, [this]() { + *d->sshParameters.writeLocked() = d->sshParametersAspectContainer.sshParameters(); + }); + registerAspect(&d->displayName); d->displayName.setSettingsKey(DisplayNameKey); d->displayName.setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay); // allowEmptyCommand.setSettingsKey() intentionally omitted, this is not persisted. + sshForwardDebugServerPort.setSettingsKey(SshForwardDebugServerPortKey); + sshForwardDebugServerPort.setLabelText(Tr::tr("Use SSH port forwarding for debugging")); + sshForwardDebugServerPort.setToolTip( + Tr::tr("Enable debugging on remote targets which cannot expose gdbserver ports.\n" + "The ssh tunneling is used to map the remote gdbserver port to localhost.\n" + "The local and remote ports are determined automatically.")); + sshForwardDebugServerPort.setDefaultValue(false); + sshForwardDebugServerPort.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); + + linkDevice.setSettingsKey(LinkDeviceKey); + linkDevice.setLabelText(Tr::tr("Access via:")); + linkDevice.setToolTip(Tr::tr("Select the device to connect through.")); + linkDevice.setDefaultValue("Direct"); + linkDevice.setComboBoxEditable(false); + linkDevice.setFillCallback([this](const StringSelectionAspect::ResultCallback &cb) { + auto dm = DeviceManager::instance(); + QList items; + auto defaultItem = new QStandardItem(Tr::tr("Direct")); + defaultItem->setData("direct"); + items.append(defaultItem); + for (int i = 0, n = dm->deviceCount(); i < n; ++i) { + const auto device = dm->deviceAt(i); + if (device->id() == this->id()) + continue; + QStandardItem *newItem = new QStandardItem(device->displayName()); + newItem->setData(device->id().toSetting()); + items.append(newItem); + } + cb(items); + }); + auto validateDisplayName = [](const QString &old, const QString &newValue) -> Result<> { if (old == newValue) return ResultOk; @@ -205,11 +244,27 @@ IDevice::IDevice() return newValue; }); - registerAspect(&d->debugServerPath); - d->debugServerPath.setSettingsKey(DebugServerKey); + debugServerPathAspect.setSettingsKey(DebugServerKey); + debugServerPathAspect.setLabelText(Tr::tr("GDB server executable:")); + debugServerPathAspect.setToolTip(Tr::tr("The GDB server executable to use on the device.")); + debugServerPathAspect.setPlaceHolderText(Tr::tr("Leave empty to look up executable in $PATH")); + debugServerPathAspect.setHistoryCompleter("GdbServer"); + debugServerPathAspect.setAllowPathFromDevice(true); + debugServerPathAspect.setExpectedKind(PathChooser::ExistingCommand); - registerAspect(&d->qmlRunCommand); - d->qmlRunCommand.setSettingsKey(QmlRuntimeKey); + qmlRunCommandAspect.setSettingsKey(QmlRuntimeKey); + qmlRunCommandAspect.setLabelText(Tr::tr("QML runtime executable:")); + qmlRunCommandAspect.setToolTip(Tr::tr("The QML runtime executable to use on the device.")); + qmlRunCommandAspect.setPlaceHolderText(Tr::tr("Leave empty to look up executable in $PATH")); + qmlRunCommandAspect.setHistoryCompleter("QmlRuntime"); + qmlRunCommandAspect.setAllowPathFromDevice(true); + qmlRunCommandAspect.setExpectedKind(PathChooser::ExistingCommand); + + freePortsAspect.setSettingsKey(PortsSpecKey); + freePortsAspect.setLabelText(Tr::tr("Free ports:")); + freePortsAspect.setToolTip( + Tr::tr("You can enter lists and ranges like this: '1024,1026-1028,1030'.")); + freePortsAspect.setHistoryCompleter("PortRange"); } IDevice::~IDevice() = default; @@ -258,22 +313,22 @@ FilePath IDevice::filePath(const QString &pathOnDevice) const FilePath IDevice::debugServerPath() const { - return d->debugServerPath(); + return debugServerPathAspect(); } void IDevice::setDebugServerPath(const FilePath &path) { - d->debugServerPath.setValue(path); + debugServerPathAspect.setValue(path); } FilePath IDevice::qmlRunCommand() const { - return d->qmlRunCommand(); + return qmlRunCommandAspect(); } void IDevice::setQmlRunCommand(const FilePath &path) { - d->qmlRunCommand.setValue(path); + qmlRunCommandAspect.setValue(path); } bool IDevice::handlesFile(const FilePath &filePath) const @@ -492,12 +547,34 @@ Id IDevice::idFromMap(const Store &map) return Id::fromSetting(map.value(IdKey)); } +// Backwards compatibility: Pre 17.0 a bunch of settings were stored in the extra data +namespace { + +static const char LinkDevice[] = "RemoteLinux.LinkDevice"; +static const char SSH_FORWARD_DEBUGSERVER_PORT[] = "RemoteLinux.SshForwardDebugServerPort"; + +static void backwardsFromExtraData(IDevice *device, const Store &map) +{ + if (map.contains(LinkDevice)) + device->linkDevice.setValue(Id::fromSetting(map.value(LinkDevice)).toString()); + + if (map.contains(SSH_FORWARD_DEBUGSERVER_PORT)) + device->sshForwardDebugServerPort.setValue(map.value(SSH_FORWARD_DEBUGSERVER_PORT).toBool()); +} + +static void backwardsToExtraData(const IDevice *const device, Store &map) +{ + map.insert(LinkDevice, device->linkDevice()); + map.insert(SSH_FORWARD_DEBUGSERVER_PORT, device->sshForwardDebugServerPort()); +} + +} // namespace + /*! Restores a device object from a serialized state as written by toMap(). If subclasses override this to restore additional state, they must call the base class implementation. */ - void IDevice::fromMap(const Store &map) { AspectContainer::fromMap(map); @@ -509,33 +586,32 @@ void IDevice::fromMap(const Store &map) d->id = newId(); d->origin = static_cast(map.value(OriginKey, ManuallyAdded).toInt()); - d->sshParameters.write([&map](SshParameters &ssh) { - ssh.setHost(map.value(HostKey).toString()); - ssh.setPort(map.value(SshPortKey, 22).toInt()); - ssh.setUserName(map.value(UserNameKey).toString()); - - // Pre-4.9, the authentication enum used to have more values - const int storedAuthType = map.value(AuthKey, DefaultAuthType).toInt(); - const bool outdatedAuthType = storedAuthType > SshParameters::AuthenticationTypeSpecificKey; - ssh.setAuthenticationType( - outdatedAuthType ? SshParameters::AuthenticationTypeAll - : static_cast(storedAuthType)); - - ssh.setPrivateKeyFile( - FilePath::fromSettings(map.value(KeyFileKey, defaultPrivateKeyFilePath()))); - ssh.setTimeout(map.value(TimeoutKey, DefaultTimeout).toInt()); - ssh.setHostKeyCheckingMode(static_cast( - map.value(HostKeyCheckingKey, SshHostKeyCheckingNone).toInt())); - }); - - QString portsSpec = map.value(PortsSpecKey).toString(); - if (portsSpec.isEmpty()) - portsSpec = "10000-10100"; - d->freePorts = PortList::fromString(portsSpec); d->machineType = static_cast(map.value(MachineTypeKey, DefaultMachineType).toInt()); d->version = map.value(VersionKey, 0).toInt(); d->extraData = storeFromVariant(map.value(ExtraDataKey)); + + backwardsFromExtraData(this, d->extraData); + + SshParameters ssh; + ssh.setHost(map.value(HostKey).toString()); + ssh.setPort(map.value(SshPortKey, 22).toInt()); + ssh.setUserName(map.value(UserNameKey).toString()); + + // Pre-4.9, the authentication enum used to have more values + const int storedAuthType = map.value(AuthKey, DefaultAuthType).toInt(); + const bool outdatedAuthType = storedAuthType > SshParameters::AuthenticationTypeSpecificKey; + ssh.setAuthenticationType( + outdatedAuthType ? SshParameters::AuthenticationTypeAll + : static_cast(storedAuthType)); + + ssh.setPrivateKeyFile( + FilePath::fromSettings(map.value(KeyFileKey, defaultPrivateKeyFilePath()))); + ssh.setTimeout(map.value(TimeoutKey, DefaultTimeout).toInt()); + ssh.setHostKeyCheckingMode(static_cast( + map.value(HostKeyCheckingKey, SshHostKeyCheckingNone).toInt())); + + d->sshParametersAspectContainer.setSshParameters(ssh); } /*! @@ -554,21 +630,21 @@ void IDevice::toMap(Store &map) const map.insert(OriginKey, d->origin); map.insert(MachineTypeKey, d->machineType); - - d->sshParameters.read([&map](const auto &ssh) { - map.insert(HostKey, ssh.host()); - map.insert(SshPortKey, ssh.port()); - map.insert(UserNameKey, ssh.userName()); - map.insert(AuthKey, ssh.authenticationType()); - map.insert(KeyFileKey, ssh.privateKeyFile().toSettings()); - map.insert(TimeoutKey, ssh.timeout()); - map.insert(HostKeyCheckingKey, ssh.hostKeyCheckingMode()); - }); - - map.insert(PortsSpecKey, d->freePorts.toString()); map.insert(VersionKey, d->version); - map.insert(ExtraDataKey, variantFromStore(d->extraData)); + Store extraData = d->extraData; + backwardsToExtraData(this, extraData); + + map.insert(ExtraDataKey, variantFromStore(extraData)); + + SshParameters ssh = d->sshParametersAspectContainer.sshParameters(); + map.insert(HostKey, ssh.host()); + map.insert(SshPortKey, ssh.port()); + map.insert(UserNameKey, ssh.userName()); + map.insert(AuthKey, ssh.authenticationType()); + map.insert(KeyFileKey, ssh.privateKeyFile().toSettings()); + map.insert(TimeoutKey, ssh.timeout()); + map.insert(HostKeyCheckingKey, ssh.hostKeyCheckingMode()); } IDevice::Ptr IDevice::clone() const @@ -639,9 +715,23 @@ SshParameters IDevice::sshParameters() const return *d->sshParameters.readLocked(); } -void IDevice::setSshParameters(const SshParameters &sshParameters) +void IDevice::setDefaultSshParameters(const SshParameters &sshParameters) { - *d->sshParameters.writeLocked() = sshParameters; + QTC_ASSERT(QThread::currentThread() == qApp->thread(), + return); // This is not thread-safe. + + sshParametersAspectContainer().host.setDefaultValue(sshParameters.host()); + sshParametersAspectContainer().port.setDefaultValue(sshParameters.port()); + sshParametersAspectContainer().userName.setDefaultValue(sshParameters.userName()); + sshParametersAspectContainer().privateKeyFile.setDefaultPathValue( + sshParameters.privateKeyFile()); + sshParametersAspectContainer().timeout.setDefaultValue(sshParameters.timeout()); + sshParametersAspectContainer().authenticationType.setDefaultValue( + sshParameters.authenticationType()); + sshParametersAspectContainer().hostKeyCheckingMode.setDefaultValue( + sshParameters.hostKeyCheckingMode()); + + *d->sshParameters.writeLocked() = sshParametersAspectContainer().sshParameters(); } QUrl IDevice::toolControlChannel(const ControlChannelHint &) const @@ -654,12 +744,12 @@ QUrl IDevice::toolControlChannel(const ControlChannelHint &) const void IDevice::setFreePorts(const PortList &freePorts) { - d->freePorts = freePorts; + freePortsAspect.setPortList(freePorts); } PortList IDevice::freePorts() const { - return d->freePorts; + return freePortsAspect.portList(); } IDevice::MachineType IDevice::machineType() const @@ -813,6 +903,13 @@ QVariant DeviceConstRef::extraData(Id kind) const return device->extraData(kind); } +Id DeviceConstRef::linkDeviceId() const +{ + const IDevice::ConstPtr device = m_constDevice.lock(); + QTC_ASSERT(device, return {}); + return Id::fromString(device->linkDevice.value()); +} + FilePath DeviceConstRef::filePath(const QString &pathOnDevice) const { const IDevice::ConstPtr device = m_constDevice.lock(); @@ -842,7 +939,12 @@ void DeviceRef::setSshParameters(const SshParameters ¶ms) { const IDevice::Ptr device = m_mutableDevice.lock(); QTC_ASSERT(device, return); - device->setSshParameters(params); + device->setDefaultSshParameters(params); +} + +SshParametersAspectContainer &IDevice::sshParametersAspectContainer() const +{ + return d->sshParametersAspectContainer; } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 9d08accdaec..de621b90f73 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -45,6 +45,7 @@ class FileTransferInterface; class FileTransferSetupData; class Kit; class SshParameters; +class SshParametersAspectContainer; class Target; class Task; @@ -157,7 +158,9 @@ public: static QString defaultPublicKeyFilePath(); SshParameters sshParameters() const; - void setSshParameters(const SshParameters &sshParameters); + void setDefaultSshParameters(const SshParameters &sshParameters); + + SshParametersAspectContainer &sshParametersAspectContainer() const; enum ControlChannelHint { QmlControlChannel }; virtual QUrl toolControlChannel(const ControlChannelHint &) const; @@ -186,8 +189,6 @@ public: Utils::Result<> openTerminal(const Utils::Environment &env, const Utils::FilePath &workingDir) const; - Utils::BoolAspect allowEmptyCommand{this}; - bool isWindowsDevice() const { return osType() == Utils::OsTypeWindows; } bool isLinuxDevice() const { return osType() == Utils::OsTypeLinux; } bool isMacDevice() const { return osType() == Utils::OsTypeMac; } @@ -219,6 +220,14 @@ public: void doApply() const; +public: + Utils::BoolAspect allowEmptyCommand{this}; + Utils::StringSelectionAspect linkDevice{this}; + Utils::BoolAspect sshForwardDebugServerPort{this}; + Utils::FilePathAspect debugServerPathAspect{this}; + Utils::FilePathAspect qmlRunCommandAspect{this}; + Utils::PortListAspect freePortsAspect{this}; + protected: IDevice(); @@ -257,6 +266,7 @@ public: SshParameters sshParameters() const; Utils::FilePath filePath(const QString &pathOnDevice) const; QVariant extraData(Utils::Id kind) const; + Utils::Id linkDeviceId() const; private: std::weak_ptr m_constDevice; diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp index 4a5312344dd..226d4f73af7 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.cpp @@ -3,6 +3,7 @@ #include "sshparameters.h" +#include "../projectexplorertr.h" #include "sshsettings.h" #include @@ -59,7 +60,7 @@ QStringList SshParameters::connectionOptions(const FilePath &binary) const args << "-o" << "User=" + userName(); const bool keyOnly = m_authenticationType == SshParameters::AuthenticationTypeSpecificKey; - if (keyOnly) + if (keyOnly && m_privateKeyFile.isReadableFile()) args << "-o" << "IdentitiesOnly=yes" << "-i" << m_privateKeyFile.path(); const QString batchModeEnabled = (keyOnly || SshSettings::askpassFilePath().isEmpty()) @@ -216,4 +217,90 @@ void printSetupHelp() } // namespace SshTest #endif +void SshParametersAspectContainer::setSshParameters(const SshParameters ¶ms) +{ + QTC_ASSERT(QThread::currentThread() == thread(), return); + + host.setVolatileValue(params.host()); + port.setVolatileValue(params.port()); + userName.setVolatileValue(params.userName()); + privateKeyFile.setVolatileValue(params.privateKeyFile().toUserOutput()); + timeout.setVolatileValue(params.timeout()); + authenticationType.setVolatileValue(params.authenticationType()); + hostKeyCheckingMode.setVolatileValue(params.hostKeyCheckingMode()); + + privateKeyFile.setEnabled( + params.authenticationType() == SshParameters::AuthenticationTypeSpecificKey); + + // This will emit the applied signal which the IDevice uses to update the ssh parameters. + apply(); +} + +SshParameters SshParametersAspectContainer::sshParameters() const +{ + QTC_ASSERT(QThread::currentThread() == thread(), return SshParameters()); + + SshParameters params; + params.setHost(host.expandedValue()); + params.setPort(port.value()); + params.setUserName(userName.expandedValue()); + params.setPrivateKeyFile(privateKeyFile.expandedValue()); + params.setTimeout(timeout.value()); + params.setAuthenticationType(authenticationType.value()); + params.setHostKeyCheckingMode(hostKeyCheckingMode.value()); + return params; +} + +SshParametersAspectContainer::SshParametersAspectContainer() +{ + authenticationType.setDefaultValue(SshParameters::AuthenticationTypeAll); + authenticationType.setDisplayStyle(SelectionAspect::DisplayStyle::RadioButtons); + authenticationType + .addOption(Tr::tr("Default"), Tr::tr("Use all available authentication methods")); + authenticationType + .addOption(Tr::tr("Specific &key"), Tr::tr("Use only the specified private key")); + authenticationType.setToolTip(Tr::tr("Select the authentication method to use")); + authenticationType.setLabelText(Tr::tr("Authentication type:")); + + hostKeyCheckingMode.setToolTip(Tr::tr("The device's SSH host key checking mode")); + hostKeyCheckingMode.setLabelText(Tr::tr("Host key check:")); + hostKeyCheckingMode.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox); + hostKeyCheckingMode.addOption("None", Tr::tr("No host key checking")); + hostKeyCheckingMode.addOption("Allow No Match", Tr::tr("Allow host key checking")); + hostKeyCheckingMode.addOption("Strict", Tr::tr("Strict host key checking")); + + host.setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay); + host.setPlaceHolderText(Tr::tr("Host name or IP address")); + host.setToolTip(Tr::tr("The device's host name or IP address")); + host.setHistoryCompleter("HostName"); + host.setLabelText(Tr::tr("Host name:")); + + userName.setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay); + userName.setPlaceHolderText(Tr::tr("User name")); + userName.setToolTip(Tr::tr("The device's SSH user name")); + userName.setHistoryCompleter("UserName"); + userName.setLabelText(Tr::tr("User name:")); + + port.setDefaultValue(22); + port.setRange(1, 65535); + port.setToolTip(Tr::tr("The device's SSH port number")); + port.setLabelText(Tr::tr("SSH port:")); + + privateKeyFile.setPlaceHolderText(Tr::tr("Private key file")); + privateKeyFile.setToolTip(Tr::tr("The device's private key file")); + privateKeyFile.setLabelText(Tr::tr("Private key file:")); + privateKeyFile.setHistoryCompleter("KeyFile"); + privateKeyFile.setEnabled( + authenticationType.volatileValue() == SshParameters::AuthenticationTypeSpecificKey); + + connect(&authenticationType, &SelectionAspect::volatileValueChanged, this, [this]() { + privateKeyFile.setEnabled( + authenticationType.volatileValue() == SshParameters::AuthenticationTypeSpecificKey); + }); + + timeout.setDefaultValue(10); + timeout.setLabelText(Tr::tr("Timeout:")); + timeout.setToolTip(Tr::tr("The device's SSH connection timeout")); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/sshparameters.h b/src/plugins/projectexplorer/devicesupport/sshparameters.h index 6bd60077d21..50fd2184464 100644 --- a/src/plugins/projectexplorer/devicesupport/sshparameters.h +++ b/src/plugins/projectexplorer/devicesupport/sshparameters.h @@ -73,6 +73,25 @@ private: QString m_userName; }; +class PROJECTEXPLORER_EXPORT SshParametersAspectContainer : public Utils::AspectContainer +{ +public: + SshParametersAspectContainer(); + + SshParameters sshParameters() const; + void setSshParameters(const SshParameters ¶ms); + +public: + Utils::FilePathAspect privateKeyFile{this}; + Utils::IntegerAspect timeout{this}; + Utils::TypedSelectionAspect authenticationType{this}; + Utils::TypedSelectionAspect hostKeyCheckingMode{this}; + + Utils::StringAspect host{this}; + Utils::IntegerAspect port{this}; + Utils::StringAspect userName{this}; +}; + #ifdef WITH_TESTS namespace SshTest { const QString PROJECTEXPLORER_EXPORT getHostFromEnvironment(); diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 9c792cad4fb..76e85af4d8a 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -231,7 +231,6 @@ const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfiguration. // Called "RemoteLinux." for backwards compatibility const char SUPPORTS_RSYNC[] = "RemoteLinux.SupportsRSync"; const char SUPPORTS_SFTP[] = "RemoteLinux.SupportsSftp"; -const char SSH_FORWARD_DEBUGSERVER_PORT[] = "RemoteLinux.SshForwardDebugServerPort"; // SDKs related ids: const char SDK_SETTINGS_CATEGORY[] = "AN.SDKs"; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index e24eabf169d..20c12ca9e5e 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -634,7 +634,7 @@ void RunControlPrivate::startPortsGathererIfNeededAndContinueStart() QUrl RunControlPrivate::getNextChannel(PortList *portList, const QList &usedPorts) { QUrl result; - if (q->device()->extraData(Constants::SSH_FORWARD_DEBUGSERVER_PORT).toBool()) { + if (q->device()->sshForwardDebugServerPort()) { result.setScheme(urlTcpScheme()); result.setHost("localhost"); } else { diff --git a/src/plugins/qnx/qnxdevice.cpp b/src/plugins/qnx/qnxdevice.cpp index 6d30bc316e5..9135e879971 100644 --- a/src/plugins/qnx/qnxdevice.cpp +++ b/src/plugins/qnx/qnxdevice.cpp @@ -66,9 +66,9 @@ public: setMachineType(IDevice::Hardware); SshParameters sshParams; sshParams.setTimeout(10); - setSshParameters(sshParams); + setDefaultSshParameters(sshParams); setFreePorts(PortList::fromString("10000-10100")); - setExtraData(RemoteLinux::Constants::SourceProfile, true); + sourceProfile.setDefaultValue(true); addDeviceAction({Tr::tr("Deploy Qt libraries..."), [](const IDevice::Ptr &device) { QnxDeployQtLibrariesDialog dialog(device, Core::ICore::dialogParent()); diff --git a/src/plugins/remotelinux/filesystemaccess_test.cpp b/src/plugins/remotelinux/filesystemaccess_test.cpp index d67ebea2e30..7351747218b 100644 --- a/src/plugins/remotelinux/filesystemaccess_test.cpp +++ b/src/plugins/remotelinux/filesystemaccess_test.cpp @@ -47,7 +47,7 @@ TestLinuxDeviceFactory::TestLinuxDeviceFactory() device->setupId(IDevice::ManuallyAdded); device->setType("test"); qDebug() << "device : " << device->type(); - device->setSshParameters(SshTest::getParameters()); + device->sshParametersAspectContainer().setSshParameters(SshTest::getParameters()); return device; }); } diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp index 112d08a056c..801a7bc7dc8 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.cpp @@ -3,6 +3,7 @@ #include "genericlinuxdeviceconfigurationwidget.h" +#include "linuxdevice.h" #include "remotelinux_constants.h" #include "remotelinuxtr.h" #include "sshkeycreationdialog.h" @@ -33,325 +34,62 @@ using namespace Utils; namespace RemoteLinux::Internal { GenericLinuxDeviceConfigurationWidget::GenericLinuxDeviceConfigurationWidget( - const IDevice::Ptr &device) : - IDeviceWidget(device) + const IDevice::Ptr &device) + : IDeviceWidget(device) { - m_defaultAuthButton = new QRadioButton(Tr::tr("Default"), this); - - m_keyButton = new QRadioButton(Tr::tr("Specific &key")); - - m_hostLineEdit = new FancyLineEdit(this); - m_hostLineEdit->setPlaceholderText(Tr::tr("IP or host name of the device")); - m_hostLineEdit->setHistoryCompleter("HostName"); - - m_sshPortSpinBox = new QSpinBox(this); - m_sshPortSpinBox->setMinimum(0); - m_sshPortSpinBox->setMaximum(65535); - m_sshPortSpinBox->setValue(22); - - m_hostKeyCheckBox = new QCheckBox(Tr::tr("&Check host key")); - - m_portsLineEdit = new FancyLineEdit(this); - m_portsLineEdit->setToolTip(Tr::tr("You can enter lists and ranges like this: '1024,1026-1028,1030'.")); - m_portsLineEdit->setHistoryCompleter("PortRange"); - - m_portsWarningLabel = new QLabel(this); - - m_timeoutSpinBox = new QSpinBox(this); - m_timeoutSpinBox->setMaximum(10000); - m_timeoutSpinBox->setSingleStep(10); - m_timeoutSpinBox->setValue(1000); - m_timeoutSpinBox->setSuffix(Tr::tr("s")); - - m_userLineEdit = new FancyLineEdit(this); - m_userLineEdit->setHistoryCompleter("UserName"); - - m_keyLabel = new QLabel(Tr::tr("Private key file:")); - - m_keyFileLineEdit = new PathChooser(this); - auto createKeyButton = new QPushButton(Tr::tr("Create New...")); - m_machineTypeValueLabel = new QLabel(this); - - const QString hint = Tr::tr("Leave empty to look up executable in $PATH"); - m_gdbServerLineEdit = new PathChooser(this); - m_gdbServerLineEdit->setExpectedKind(PathChooser::ExistingCommand); - m_gdbServerLineEdit->setPlaceholderText(hint); - m_gdbServerLineEdit->setToolTip(hint); - m_gdbServerLineEdit->setHistoryCompleter("GdbServer"); - m_gdbServerLineEdit->setAllowPathFromDevice(true); - - m_qmlRuntimeLineEdit = new PathChooser(this); - m_qmlRuntimeLineEdit->setExpectedKind(PathChooser::ExistingCommand); - m_qmlRuntimeLineEdit->setPlaceholderText(hint); - m_qmlRuntimeLineEdit->setToolTip(hint); - m_qmlRuntimeLineEdit->setHistoryCompleter("QmlRuntime"); - m_qmlRuntimeLineEdit->setAllowPathFromDevice(true); - - m_sourceProfileCheckBox = - new QCheckBox(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); - - m_linkDeviceComboBox = new QComboBox; - m_linkDeviceComboBox->addItem(Tr::tr("Direct"), QVariant()); - - auto dm = DeviceManager::instance(); - const int dmCount = dm->deviceCount(); - for (int i = 0; i < dmCount; ++i) { - IDevice::ConstPtr dev = dm->deviceAt(i); - if (dev->id() != device->id()) - m_linkDeviceComboBox->addItem(dev->displayName(), dev->id().toSetting()); - } - - auto sshPortLabel = new QLabel(Tr::tr("&SSH port:")); - sshPortLabel->setBuddy(m_sshPortSpinBox); - - m_useSshPortForwardingForDebugging = new QCheckBox; - m_useSshPortForwardingForDebugging->setText(Tr::tr("Use SSH port forwarding for debugging")); - m_useSshPortForwardingForDebugging->setToolTip( - Tr::tr("Enable debugging on remote targets which cannot expose gdbserver ports.\n" - "The ssh tunneling is used to map the remote gdbserver port to localhost.\n" - "The local and remote ports are determined automatically.")); + const QString machineType = device->machineType() == IDevice::Hardware + ? Tr::tr("Physical Device") + : Tr::tr("Emulator"); + auto linuxDevice = std::dynamic_pointer_cast(device); + QTC_ASSERT(linuxDevice, return); using namespace Layouting; + auto portWarningLabel = new QLabel( + QString("%1").arg(Tr::tr("You will need at least one port."))); + + auto updatePortWarningLabel = [portWarningLabel, device]() { + portWarningLabel->setVisible(device->freePortsAspect.volatileValue().isEmpty()); + }; + + updatePortWarningLabel(); + + // clang-format off + connect(&device->freePortsAspect, &PortListAspect::volatileValueChanged, this, updatePortWarningLabel); + Form { - Tr::tr("Machine type:"), m_machineTypeValueLabel, st, br, - Tr::tr("Authentication type:"), m_defaultAuthButton, m_keyButton, st, br, - Tr::tr("&Host name:"), m_hostLineEdit, sshPortLabel, m_sshPortSpinBox, m_hostKeyCheckBox, st, br, - Tr::tr("Free ports:"), m_portsLineEdit, m_portsWarningLabel, Tr::tr("Timeout:"), m_timeoutSpinBox, st, br, - Tr::tr("&Username:"), m_userLineEdit, st, br, - m_keyLabel, m_keyFileLineEdit, createKeyButton, br, - Tr::tr("GDB server executable:"), m_gdbServerLineEdit, br, - Tr::tr("QML runtime executable:"), m_qmlRuntimeLineEdit, br, - QString(), m_sourceProfileCheckBox, br, - QString(), m_useSshPortForwardingForDebugging, br, - Tr::tr("Access via:"), m_linkDeviceComboBox, br, + Tr::tr("Machine type:"), machineType, st, br, + device->sshParametersAspectContainer().authenticationType.labelText(), device->sshParametersAspectContainer().authenticationType, st, br, + device->sshParametersAspectContainer().host, device->sshParametersAspectContainer().port, device->sshParametersAspectContainer().hostKeyCheckingMode, st, br, + device->freePortsAspect, portWarningLabel, device->sshParametersAspectContainer().timeout, st, br, + device->sshParametersAspectContainer().userName, st, br, + device->sshParametersAspectContainer().privateKeyFile, createKeyButton, br, + device->debugServerPathAspect, br, + device->qmlRunCommandAspect, br, + linuxDevice->sourceProfile, br, + device->sshForwardDebugServerPort, br, + device->linkDevice, br, }.attachTo(this); + // clang-format on - connect(m_hostLineEdit, &QLineEdit::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::hostNameEditingFinished); - connect(m_userLineEdit, &QLineEdit::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::userNameEditingFinished); - connect(m_keyFileLineEdit, &PathChooser::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished); - connect(m_keyFileLineEdit, &PathChooser::browsingFinished, - this, &GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished); - connect(m_keyButton, &QAbstractButton::toggled, - this, &GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged); - connect(m_timeoutSpinBox, &QAbstractSpinBox::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::timeoutEditingFinished); - connect(m_timeoutSpinBox, &QSpinBox::valueChanged, - this, &GenericLinuxDeviceConfigurationWidget::timeoutEditingFinished); - connect(m_sshPortSpinBox, &QAbstractSpinBox::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished); - connect(m_sshPortSpinBox, &QSpinBox::valueChanged, - this, &GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished); - connect(m_portsLineEdit, &QLineEdit::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged); - connect(createKeyButton, &QAbstractButton::clicked, - this, &GenericLinuxDeviceConfigurationWidget::createNewKey); - connect(m_gdbServerLineEdit, &PathChooser::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::gdbServerEditingFinished); - connect(m_qmlRuntimeLineEdit, &PathChooser::editingFinished, - this, &GenericLinuxDeviceConfigurationWidget::qmlRuntimeEditingFinished); - connect(m_hostKeyCheckBox, &QCheckBox::toggled, - this, &GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged); - connect(m_sourceProfileCheckBox, &QCheckBox::toggled, - this, &GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged); - connect(m_linkDeviceComboBox, &QComboBox::currentIndexChanged, - this, &GenericLinuxDeviceConfigurationWidget::linkDeviceChanged); - connect(m_useSshPortForwardingForDebugging, &QCheckBox::toggled, - this, &GenericLinuxDeviceConfigurationWidget::sshPortForwardingForDebugging); - - initGui(); + connect( + createKeyButton, + &QAbstractButton::clicked, + this, + &GenericLinuxDeviceConfigurationWidget::createNewKey); } GenericLinuxDeviceConfigurationWidget::~GenericLinuxDeviceConfigurationWidget() = default; -void GenericLinuxDeviceConfigurationWidget::authenticationTypeChanged() -{ - SshParameters sshParams = device()->sshParameters(); - const bool useKeyFile = m_keyButton->isChecked(); - sshParams.setAuthenticationType( - useKeyFile ? SshParameters::AuthenticationTypeSpecificKey - : SshParameters::AuthenticationTypeAll); - device()->setSshParameters(sshParams); - m_keyFileLineEdit->setEnabled(useKeyFile); - m_keyLabel->setEnabled(useKeyFile); -} - -void GenericLinuxDeviceConfigurationWidget::hostNameEditingFinished() -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setHost(m_hostLineEdit->text().trimmed()); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::sshPortEditingFinished() -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setPort(m_sshPortSpinBox->value()); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::timeoutEditingFinished() -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setTimeout(m_timeoutSpinBox->value()); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::userNameEditingFinished() -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setUserName(m_userLineEdit->text()); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::keyFileEditingFinished() -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setPrivateKeyFile(m_keyFileLineEdit->filePath()); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::gdbServerEditingFinished() -{ - device()->setDebugServerPath(m_gdbServerLineEdit->filePath()); -} - -void GenericLinuxDeviceConfigurationWidget::qmlRuntimeEditingFinished() -{ - device()->setQmlRunCommand(m_qmlRuntimeLineEdit->filePath()); -} - -void GenericLinuxDeviceConfigurationWidget::handleFreePortsChanged() -{ - device()->setFreePorts(PortList::fromString(m_portsLineEdit->text())); - updatePortsWarningLabel(); -} - -void GenericLinuxDeviceConfigurationWidget::setPrivateKey(const FilePath &path) -{ - m_keyFileLineEdit->setFilePath(path); - keyFileEditingFinished(); -} - void GenericLinuxDeviceConfigurationWidget::createNewKey() { SshKeyCreationDialog dialog(this); - if (dialog.exec() == QDialog::Accepted) - setPrivateKey(dialog.privateKeyFilePath()); -} - -void GenericLinuxDeviceConfigurationWidget::hostKeyCheckingChanged(bool doCheck) -{ - SshParameters sshParams = device()->sshParameters(); - sshParams.setHostKeyCheckingMode( - doCheck ? SshHostKeyCheckingAllowNoMatch : SshHostKeyCheckingNone); - device()->setSshParameters(sshParams); -} - -void GenericLinuxDeviceConfigurationWidget::sourceProfileCheckingChanged(bool doCheck) -{ - device()->setExtraData(Constants::SourceProfile, doCheck); -} - -void GenericLinuxDeviceConfigurationWidget::linkDeviceChanged(int index) -{ - const QVariant deviceId = m_linkDeviceComboBox->itemData(index); - device()->setExtraData(Constants::LinkDevice, deviceId); -} - -void GenericLinuxDeviceConfigurationWidget::sshPortForwardingForDebugging(bool on) -{ - device()->setExtraData(ProjectExplorer::Constants::SSH_FORWARD_DEBUGSERVER_PORT, on); -} - -void GenericLinuxDeviceConfigurationWidget::updateDeviceFromUi() -{ - hostNameEditingFinished(); - sshPortEditingFinished(); - timeoutEditingFinished(); - userNameEditingFinished(); - keyFileEditingFinished(); - handleFreePortsChanged(); - gdbServerEditingFinished(); - sshPortEditingFinished(); - timeoutEditingFinished(); - sourceProfileCheckingChanged(m_sourceProfileCheckBox->isChecked()); - linkDeviceChanged(m_linkDeviceComboBox->currentIndex()); - sshPortForwardingForDebugging(m_useSshPortForwardingForDebugging->isChecked()); - qmlRuntimeEditingFinished(); -} - -void GenericLinuxDeviceConfigurationWidget::updatePortsWarningLabel() -{ - m_portsWarningLabel->setVisible(!device()->freePorts().hasMore()); -} - -void GenericLinuxDeviceConfigurationWidget::initGui() -{ - if (device()->machineType() == IDevice::Hardware) - m_machineTypeValueLabel->setText(Tr::tr("Physical Device")); - else - m_machineTypeValueLabel->setText(Tr::tr("Emulator")); - m_portsWarningLabel->setPixmap(Utils::Icons::CRITICAL.pixmap()); - m_portsWarningLabel->setToolTip(QLatin1String("") - + Tr::tr("You will need at least one port.") + QLatin1String("")); - m_keyFileLineEdit->setExpectedKind(PathChooser::File); - m_keyFileLineEdit->setHistoryCompleter("Ssh.KeyFile.History"); - m_keyFileLineEdit->lineEdit()->setMinimumWidth(0); - QRegularExpressionValidator * const portsValidator - = new QRegularExpressionValidator(QRegularExpression(PortList::regularExpression()), this); - m_portsLineEdit->setValidator(portsValidator); - - const SshParameters &sshParams = device()->sshParameters(); - - switch (sshParams.authenticationType()) { - case SshParameters::AuthenticationTypeSpecificKey: - m_keyButton->setChecked(true); - break; - case SshParameters::AuthenticationTypeAll: - m_defaultAuthButton->setChecked(true); - break; + if (dialog.exec() == QDialog::Accepted) { + device()->sshParametersAspectContainer().privateKeyFile.setValue( + dialog.privateKeyFilePath()); } - m_timeoutSpinBox->setValue(sshParams.timeout()); - m_hostLineEdit->setEnabled(!device()->isAutoDetected()); - m_sshPortSpinBox->setEnabled(!device()->isAutoDetected()); - m_hostKeyCheckBox->setChecked(sshParams.hostKeyCheckingMode() != SshHostKeyCheckingNone); - m_sourceProfileCheckBox->setChecked(device()->extraData(Constants::SourceProfile).toBool()); - Id linkDeviceId = Id::fromSetting(device()->extraData(Constants::LinkDevice)); - auto dm = DeviceManager::instance(); - int found = -1; - int minus = 0; - for (int i = 0, n = dm->deviceCount(); i < n; ++i) { - const auto otherId = dm->deviceAt(i)->id(); - if (otherId == linkDeviceId) { - found = i; - break; - } else if (otherId == device()->id()) { - // Since we ourselves do not appear in the combo box, we need to adjust the index. - minus = 1; - } - } - m_linkDeviceComboBox->setCurrentIndex(found + 1 - minus); // There's the "Direct" entry first. - - m_hostLineEdit->setText(sshParams.host()); - m_sshPortSpinBox->setValue(sshParams.port()); - m_portsLineEdit->setText(device()->freePorts().toString()); - m_timeoutSpinBox->setValue(sshParams.timeout()); - m_userLineEdit->setText(sshParams.userName()); - m_keyFileLineEdit->setFilePath(sshParams.privateKeyFile()); - m_keyFileLineEdit->setEnabled( - sshParams.authenticationType() == SshParameters::AuthenticationTypeSpecificKey); - m_gdbServerLineEdit->setFilePath(device()->debugServerPath()); - m_qmlRuntimeLineEdit->setFilePath(device()->qmlRunCommand()); - m_useSshPortForwardingForDebugging->setChecked( - device()->extraData(ProjectExplorer::Constants::SSH_FORWARD_DEBUGSERVER_PORT).toBool()); - - updatePortsWarningLabel(); } } // RemoteLinux::Internal diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h index cc007ec6efa..8f8f7322d9c 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwidget.h @@ -31,43 +31,8 @@ public: ~GenericLinuxDeviceConfigurationWidget() override; private: - void authenticationTypeChanged(); - void hostNameEditingFinished(); - void sshPortEditingFinished(); - void timeoutEditingFinished(); - void userNameEditingFinished(); - void keyFileEditingFinished(); - void gdbServerEditingFinished(); - void qmlRuntimeEditingFinished(); - void handleFreePortsChanged(); - void setPrivateKey(const Utils::FilePath &path); void createNewKey(); - void hostKeyCheckingChanged(bool doCheck); - void sourceProfileCheckingChanged(bool doCheck); - void linkDeviceChanged(int index); - void sshPortForwardingForDebugging(bool on); - - void updateDeviceFromUi() override; - void updatePortsWarningLabel(); - void initGui(); - - QRadioButton *m_defaultAuthButton; - QLabel *m_keyLabel; - QRadioButton *m_keyButton; - Utils::FancyLineEdit *m_hostLineEdit; - QSpinBox *m_sshPortSpinBox; - QCheckBox *m_hostKeyCheckBox; - Utils::FancyLineEdit *m_portsLineEdit; - QLabel *m_portsWarningLabel; - Utils::FancyLineEdit *m_userLineEdit; - QSpinBox *m_timeoutSpinBox; - Utils::PathChooser *m_keyFileLineEdit; - QLabel *m_machineTypeValueLabel; - Utils::PathChooser *m_gdbServerLineEdit; - Utils::PathChooser *m_qmlRuntimeLineEdit; - QCheckBox *m_sourceProfileCheckBox; - QComboBox *m_linkDeviceComboBox; - QCheckBox *m_useSshPortForwardingForDebugging; + void updateDeviceFromUi() override {} }; } // RemoteLinux::Internal diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index fcb01d309c5..eb1df06b9fe 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -656,7 +656,7 @@ void SshProcessInterfacePrivate::start() { m_sshParameters = m_device->sshParameters(); - const Id linkDeviceId = Id::fromSetting(m_device->extraData(Constants::LinkDevice)); + const Id linkDeviceId = Id::fromSetting(m_device->linkDevice.value()); if (const IDevice::ConstPtr linkDevice = DeviceManager::instance()->find(linkDeviceId)) { CommandLine cmd{linkDevice->filePath("ssh")}; if (!m_sshParameters.userName().isEmpty()) { @@ -775,10 +775,13 @@ void SshProcessInterfacePrivate::doStart() CommandLine SshProcessInterfacePrivate::fullLocalCommandLine() const { + auto linuxDevice = std::dynamic_pointer_cast(m_device); + QTC_ASSERT(linuxDevice, return {}); + const FilePath sshBinary = SshSettings::sshFilePath(); const bool useTerminal = q->m_setup.m_terminalMode != TerminalMode::Off || q->m_setup.m_ptyData; const bool usePidMarker = !useTerminal; - const bool sourceProfile = m_device->extraData(Constants::SourceProfile).toBool(); + const bool sourceProfile = linuxDevice->sourceProfile(); const bool useX = !m_sshParameters.x11DisplayName().isEmpty(); CommandLine cmd{sshBinary}; @@ -1029,7 +1032,13 @@ LinuxDevice::LinuxDevice() setFreePorts(PortList::fromString(QLatin1String("10000-10100"))); SshParameters sshParams; sshParams.setTimeout(10); - setSshParameters(sshParams); + setDefaultSshParameters(sshParams); + + sourceProfile.setSettingsKey("SourceProfile"); + sourceProfile.setDefaultValue(true); + sourceProfile.setToolTip(Tr::tr("Source profile before executing commands")); + sourceProfile.setLabelText(Tr::tr("Source %1 and %2").arg("/etc/profile").arg("$HOME/.profile")); + sourceProfile.setLabelPlacement(BoolAspect::LabelPlacement::AtCheckBox); addDeviceAction({Tr::tr("Deploy Public Key..."), [](const IDevice::Ptr &device) { if (auto d = Internal::PublicKeyDeploymentDialog::createDialog(device)) { @@ -1368,6 +1377,35 @@ void Internal::LinuxDeviceFactory::shutdownExistingDevices() } }); } + +namespace { +static const char SourceProfile[] = "RemoteLinux.SourceProfile"; + +static void backwardsFromExtraData(LinuxDevice *device) +{ + QVariant sourceProfile = device->extraData(SourceProfile); + if (sourceProfile.isValid()) + device->sourceProfile.setValue(sourceProfile.toBool()); +} + +static void backwardsToExtraData(LinuxDevice *device) +{ + device->setExtraData(SourceProfile, device->sourceProfile.value()); +} + +} // namespace + +void LinuxDevice::fromMap(const Utils::Store &map) +{ + ProjectExplorer::IDevice::fromMap(map); + backwardsFromExtraData(this); +} +void LinuxDevice::toMap(Utils::Store &map) const +{ + backwardsToExtraData(const_cast(this)); + ProjectExplorer::IDevice::toMap(map); +} + } // namespace RemoteLinux #include "linuxdevice.moc" diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index 8b73ab881c2..9f30efbc896 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -76,6 +76,12 @@ public: void shutdown(); + void fromMap(const Utils::Store &map) override; + void toMap(Utils::Store &map) const override; + +public: + Utils::BoolAspect sourceProfile{this}; + protected: LinuxDevice(); diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h index 19e44e0646f..03edc97d44f 100644 --- a/src/plugins/remotelinux/remotelinux_constants.h +++ b/src/plugins/remotelinux/remotelinux_constants.h @@ -19,8 +19,6 @@ const char GenericDeployStepId[] = "RemoteLinux.RsyncDeployStep"; const char CustomCommandDeployStepId[] = "RemoteLinux.GenericRemoteLinuxCustomCommandDeploymentStep"; const char KillAppStepId[] = "RemoteLinux.KillAppStep"; -const char SourceProfile[] = "RemoteLinux.SourceProfile"; -const char LinkDevice[] = "RemoteLinux.LinkDevice"; const char SshForwardPort[] = "RemoteLinux.SshForwardPort"; const char DisableSharing[] = "RemoteLinux.DisableSharing"; diff --git a/src/plugins/remotelinux/remotelinuxfiletransfer.cpp b/src/plugins/remotelinux/remotelinuxfiletransfer.cpp index 47511e0abec..019dc76dcea 100644 --- a/src/plugins/remotelinux/remotelinuxfiletransfer.cpp +++ b/src/plugins/remotelinux/remotelinuxfiletransfer.cpp @@ -121,7 +121,7 @@ private: void start() final { m_sshParameters = displayless(m_device.sshParameters()); - const Id linkDeviceId = Id::fromSetting(m_device.extraData(Constants::LinkDevice)); + const Id linkDeviceId = m_device.linkDeviceId(); const auto linkDevice = DeviceManager::instance()->find(linkDeviceId); const bool useConnectionSharing = !linkDevice && SshSettings::connectionSharingEnabled(); @@ -186,7 +186,7 @@ private: FilePath sftpBinary = SshSettings::sftpFilePath(); // This is a hack. We only test the last hop here. - const Id linkDeviceId = Id::fromSetting(device().extraData(Constants::LinkDevice)); + const Id linkDeviceId = device().linkDeviceId(); if (const auto linkDevice = DeviceManager::instance()->find(linkDeviceId)) sftpBinary = linkDevice->filePath(sftpBinary.fileName()).searchInPath();