#!/usr/bin/env python3 """ Скрипт миграции tmux сессий в новую структуру инвентарей """ import os import re import shutil from pathlib import Path class SessionMigrator: def __init__(self): self.source_dir = Path.home() / '.config' / 'tmux' / 'sessions' self.target_dir = Path.home() / '.config' / 'tmux-sessions' / 'inventory' def parse_session_file(self, file_path): """Парсит файл сессии и извлекает данные""" with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # Базовые данные data = { 'filename': file_path.name, 'session_name': None, 'sshpass_path': None, 'servers': [] } # Парсим имя сессии session_match = re.search(r'session_name=(["\']?)([^"\'\n]+)\1', content) if session_match: data['session_name'] = session_match.group(2).strip() # Парсим путь к паролю sshpass_match = re.search(r'sshpass=\$\(pass ([^)\n]+)\)', content) if sshpass_match: data['sshpass_path'] = sshpass_match.group(1).strip() # Парсим серверы из массива servers servers_match = re.search(r'servers=\(([^)]+)\)', content, re.DOTALL) if servers_match: servers_content = servers_match.group(1) # Извлекаем строки серверов server_lines = re.findall(r'"([^"]+)"', servers_content) for line in server_lines: parts = line.strip().split(' ', 1) if len(parts) == 2: data['servers'].append(f'"{parts[0]} {parts[1]}"') # Обработка специального формата для Приморье if 'Приморье' in file_path.name: data = self._parse_primorye_format(content, data) return data def _parse_primorye_format(self, content, data): """Специальный парсинг для файла Приморье с другим форматом""" # Имя сессии session_match = re.search(r'SESSION=([^\n]+)', content) if session_match: data['session_name'] = session_match.group(1).strip() # Путь к паролю sshpass_match = re.search(r'SSHPASS=\$\(pass ([^)\n]+)\)', content) if sshpass_match: data['sshpass_path'] = sshpass_match.group(1).strip() # Извлекаем серверы из tmux new-window команд servers = [] window_matches = re.findall(r'tmux new-window[^>]+-n ([^\s]+)[^>]+"sshpass[^>]+ssh ([^"\s]+)"', content) for server_name, server_connect in window_matches: servers.append(f'"{server_name} {server_connect}"') data['servers'] = servers return data def generate_config_content(self, data): """Генерирует содержимое нового конфигурационного файла""" lines = [ f"# Конфигурация для проекта {data['filename'].replace('.session', '')}", f"SESSION_NAME=\"{data['session_name']}\"", f"SSHPASS_PATH=\"{data['sshpass_path']}\"", "", "# Список серверов в формате \"имя_вкладки подключение\"", "SERVERS=(" ] # Добавляем серверы for server in data['servers']: lines.append(f" {server}") lines.extend([ ")", "" ]) return '\n'.join(lines) def sanitize_filename(self, filename): """Очищает имя файла от недопустимых символов""" # Убираем расширение .session clean_name = filename.replace('.session', '') # Заменяем пробелы и другие проблемные символы clean_name = re.sub(r'[^\w\-_.]', '_', clean_name) return clean_name + '.conf' def migrate(self): """Основная функция миграции""" print("🚀 Начинаем миграцию tmux сессий...") print(f"📁 Исходный каталог: {self.source_dir}") print(f"📁 Целевой каталог: {self.target_dir}") print() # Создаем целевой каталог если не существует self.target_dir.mkdir(parents=True, exist_ok=True) # Получаем список файлов сессий session_files = list(self.source_dir.glob('*.session')) if not session_files: print("❌ Не найдено файлов сессий для миграции") return migrated_count = 0 errors = [] for session_file in session_files: try: print(f"📖 Обрабатываем: {session_file.name}") # Парсим файл data = self.parse_session_file(session_file) # Проверяем что все необходимые данные есть if not data['session_name']: print(f" ⚠️ Предупреждение: не найдено имя сессии в {session_file.name}") if not data['sshpass_path']: print(f" ⚠️ Предупреждение: не найден путь к паролю в {session_file.name}") if not data['servers']: print(f" ⚠️ Предупреждение: не найдены серверы в {session_file.name}") # Генерируем новое имя файла new_filename = self.sanitize_filename(session_file.name) new_file_path = self.target_dir / new_filename # Генерируем содержимое config_content = self.generate_config_content(data) # Сохраняем файл with open(new_file_path, 'w', encoding='utf-8') as f: f.write(config_content) print(f" ✅ Создан: {new_filename}") print(f" Session: {data['session_name']}") print(f" Servers: {len(data['servers'])}") print(f" Pass path: {data['sshpass_path']}") print() migrated_count += 1 except Exception as e: error_msg = f"Ошибка обработки {session_file.name}: {str(e)}" print(f" ❌ {error_msg}") errors.append(error_msg) # Выводим итоги print("=" * 50) print(f"📊 Миграция завершена!") print(f"✅ Успешно мигрировано: {migrated_count}/{len(session_files)}") if errors: print(f"❌ Ошибки ({len(errors)}):") for error in errors: print(f" - {error}") # Показываем созданные файлы print(f"\n📁 Созданные файлы в {self.target_dir}:") for conf_file in sorted(self.target_dir.glob('*.conf')): print(f" 📄 {conf_file.name}") print(f"\n🎯 Теперь вы можете использовать новый лаунчер:") print(f" tmux-sessions # Меню выбора") print(f" tmux-sessions --list # Список проектов") def main(): migrator = SessionMigrator() # Проверяем существует ли исходный каталог if not migrator.source_dir.exists(): print(f"❌ Исходный каталог не существует: {migrator.source_dir}") return # Запускаем миграцию migrator.migrate() if __name__ == '__main__': main()