SSHRemotePlugin/src/main/java/com/example/plugin/SshServerManager.java
stud_i_sram b70941fb53 Включить remote path в локальный путь к проекту
Локальная папка теперь учитывает удалённую рабочую директорию, чтобы на одном сервере можно было держать несколько проектов.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-18 14:22:12 +03:00

135 lines
4.3 KiB
Java

package com.example.plugin;
import com.intellij.credentialStore.CredentialAttributes;
import com.intellij.ide.passwordSafe.PasswordSafe;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.util.xmlb.XmlSerializerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@State(
name = "SshServerManager",
storages = { @Storage("ssh-servers.xml") }
)
public class SshServerManager implements PersistentStateComponent<SshServerManager.State> {
public static class State {
public List<SshServer> servers = new ArrayList<>();
public String currentServerId;
}
private State myState = new State();
@Nullable
@Override
public State getState() {
return myState;
}
@Override
public void loadState(@NotNull State state) {
XmlSerializerUtil.copyBean(state, myState);
}
// ---------- CRUD ----------
public List<SshServer> getServers() {
return myState.servers;
}
public Optional<SshServer> findServer(String id) {
return myState.servers.stream().filter(s -> s.id.equals(id)).findFirst();
}
public void addServer(SshServer server) {
myState.servers.add(server);
}
public void removeServer(String id) {
myState.servers.removeIf(s -> s.id.equals(id));
if (id.equals(myState.currentServerId)) {
myState.currentServerId = null;
}
PasswordSafe.getInstance().setPassword(createCredentialAttributes(id), null);
}
public void updateServer(SshServer updated) {
for (int i = 0; i < myState.servers.size(); i++) {
if (myState.servers.get(i).id.equals(updated.id)) {
myState.servers.set(i, updated);
break;
}
}
}
// ---------- Текущий сервер ----------
public String getCurrentServerId() {
return myState.currentServerId;
}
public void setCurrentServerId(String id) {
myState.currentServerId = id;
}
public Optional<SshServer> getCurrentServer() {
return Optional.ofNullable(myState.currentServerId).flatMap(this::findServer);
}
// ---------- Пароль ----------
public String getPassword(String serverId) {
return PasswordSafe.getInstance().getPassword(createCredentialAttributes(serverId));
}
public void setPassword(String serverId, String password) {
PasswordSafe.getInstance().setPassword(createCredentialAttributes(serverId), password);
}
private CredentialAttributes createCredentialAttributes(String serverId) {
return new CredentialAttributes("SshRemotePlugin.server." + serverId);
}
// ---------- Singleton ----------
public static SshServerManager getInstance() {
return com.intellij.openapi.application.ApplicationManager.getApplication()
.getService(SshServerManager.class);
}
// ---------- Вспомогательные статические методы ----------
/**
* Возвращает локальный путь к папке проекта на основе хоста, имени сервера и удалённой рабочей директории.
*/
public static String getLocalProjectPath(SshServer server) {
Path path = Paths.get(System.getProperty("user.home"), "ssh-remote-projects",
sanitize(server.host), sanitize(server.name));
if (server.remoteProjectPath != null && !server.remoteProjectPath.isBlank()) {
String normalized = server.remoteProjectPath.replace('\\', '/').replaceAll("/+", "/");
for (String segment : normalized.split("/")) {
if (!segment.isEmpty()) {
path = path.resolve(sanitize(segment));
}
}
}
return path.toString().replace('\\', '/');
}
/**
* Заменяет в строке все символы, кроме букв, цифр, точки и дефиса, на '_'.
*/
public static String sanitize(String input) {
return input.replaceAll("[^a-zA-Z0-9.-]", "_");
}
}