Локальная папка теперь учитывает удалённую рабочую директорию, чтобы на одном сервере можно было держать несколько проектов. Co-authored-by: Cursor <cursoragent@cursor.com>
135 lines
4.3 KiB
Java
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.-]", "_");
|
|
}
|
|
} |