Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b37e696094 | ||
|
|
289ce65431 | ||
|
|
704ce3bef2 | ||
|
|
00f3b76d2a | ||
|
|
efbbfa13ee | ||
|
|
3c4d02c5ec |
14
build.py
14
build.py
@@ -311,6 +311,7 @@ def _version_key(path: str):
|
||||
return (0, 0, 0)
|
||||
|
||||
|
||||
|
||||
def cleanup_old_releases():
|
||||
"""Keep the first release (v1.0.0) and the last 5 releases, delete the rest."""
|
||||
import glob
|
||||
@@ -327,9 +328,20 @@ def cleanup_old_releases():
|
||||
keep = set([first] + last_5)
|
||||
|
||||
removed = []
|
||||
_flags = subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0
|
||||
for f in all_exes:
|
||||
if f not in keep:
|
||||
os.remove(f)
|
||||
# Use git rm so deletion is staged for commit
|
||||
try:
|
||||
subprocess.run(
|
||||
["git", "rm", "-f", "--quiet", f],
|
||||
cwd=PROJECT_DIR, creationflags=_flags,
|
||||
capture_output=True,
|
||||
)
|
||||
except Exception:
|
||||
# Fallback: just delete the file
|
||||
if os.path.exists(f):
|
||||
os.remove(f)
|
||||
removed.append(os.path.basename(f))
|
||||
|
||||
if removed:
|
||||
|
||||
@@ -9,6 +9,15 @@ from typing import Dict, Optional, Tuple
|
||||
from core.ssh_client import ShellSession, SFTPSession
|
||||
|
||||
|
||||
_CRITICAL_KEYS = ('ip', 'port', 'username', 'password', 'type',
|
||||
'access_key', 'secret_key', 'use_ssl')
|
||||
|
||||
|
||||
def _server_changed(old: dict, new: dict) -> bool:
|
||||
"""Check if critical connection fields differ."""
|
||||
return any(old.get(k) != new.get(k) for k in _CRITICAL_KEYS)
|
||||
|
||||
|
||||
class SessionData:
|
||||
"""Container for session data including the actual sessions and their metadata."""
|
||||
def __init__(self, alias: str, server: dict, key_path: str):
|
||||
@@ -70,6 +79,11 @@ class SessionPool:
|
||||
self._sessions[alias] = session_data
|
||||
else:
|
||||
session_data = self._sessions[alias]
|
||||
# Invalidate if server connection data changed
|
||||
if _server_changed(session_data.server, server):
|
||||
session_data.cleanup()
|
||||
session_data.server = server
|
||||
session_data.key_path = key_path
|
||||
|
||||
# Update access time for LRU
|
||||
self._update_last_access(alias)
|
||||
@@ -108,6 +122,11 @@ class SessionPool:
|
||||
self._sessions[alias] = session_data
|
||||
else:
|
||||
session_data = self._sessions[alias]
|
||||
# Invalidate if server connection data changed
|
||||
if _server_changed(session_data.server, server):
|
||||
session_data.cleanup()
|
||||
session_data.server = server
|
||||
session_data.key_path = key_path
|
||||
|
||||
# Update access time for LRU
|
||||
self._update_last_access(alias)
|
||||
|
||||
@@ -401,12 +401,15 @@ del /f /q "%~f0" >nul 2>&1
|
||||
return
|
||||
time.sleep(0.1)
|
||||
|
||||
first_run = True
|
||||
while self._running:
|
||||
# Check if enough time passed since last check
|
||||
# On first run after startup, always check regardless of interval
|
||||
last_check = self.store.get_last_update_check()
|
||||
now = time.time()
|
||||
|
||||
if not last_check or (now - last_check) >= _CHECK_INTERVAL:
|
||||
if first_run or not last_check or (now - last_check) >= _CHECK_INTERVAL:
|
||||
first_run = False
|
||||
info = self.check_now()
|
||||
if info and self._gui_callback:
|
||||
mode = self.store.get_update_mode()
|
||||
|
||||
16
gui/app.py
16
gui/app.py
@@ -299,9 +299,19 @@ class App(ctk.CTk):
|
||||
self.sidebar._select(new_alias)
|
||||
self.session_pool.rename_server(alias, new_alias)
|
||||
else:
|
||||
info = self._tab_instances.get("info")
|
||||
if info and hasattr(info, "refresh"):
|
||||
info.refresh()
|
||||
# Data may have changed (IP, port, password) — force reconnect
|
||||
self._force_reconnect(alias)
|
||||
|
||||
def _force_reconnect(self, alias: str):
|
||||
"""Force tabs to reconnect after server data changed."""
|
||||
# Invalidate cached SSH/SFTP sessions in pool
|
||||
self.session_pool.disconnect_session(alias)
|
||||
# Reset _current_alias so set_server() bypasses early return
|
||||
for widget in self._tab_instances.values():
|
||||
if getattr(widget, '_current_alias', None) == alias:
|
||||
widget._current_alias = None
|
||||
# Re-trigger server selection (calls set_server on all tabs)
|
||||
self._on_server_select(alias)
|
||||
|
||||
def _delete_server(self, alias: str):
|
||||
if messagebox.askyesno(t("delete_server"), t("delete_confirm").format(alias=alias)):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
"""Version info for ServerManager."""
|
||||
|
||||
__version__ = "1.9.8"
|
||||
__version__ = "1.9.13"
|
||||
__app_name__ = "ServerManager"
|
||||
__author__ = "aibot777"
|
||||
__description__ = "Desktop GUI for managing remote servers"
|
||||
|
||||
Reference in New Issue
Block a user