20 Commits
v1.1 ... v1.0.2

Author SHA1 Message Date
11253286f8 Improved configuration file management with advanced features
- Added send2trash library for safer file deletion
- Implemented folder and file moving functionality in ConfigSelectorWindow
- Created FolderSelectorDialog for moving files to a folder
- Improved file and folder renaming with improved error handling
- Added emoji icons for better visual representation of actions
- Updated requirements.txt to include send2trash library
- Removed drag-and-drop support. Postponed for future
2025-02-19 23:06:15 +03:00
ea432d2893 Add configuration file selection and management window
- Implement ConfigSelectorWindow for advanced configuration file selection
- Add drag-and-drop support for configuration files
- Create file management features: add, edit, rename, and delete configs
- Enhance file selection process with a tree-view interface
- Improve configuration file handling with user-friendly interactions
2025-02-19 22:25:28 +03:00
d3f832cdbb Add connection state verification in command execution
- Check serial connection status before sending commands
- Prevent command execution on closed or inactive connections
- Add informative log message when connection is lost
- Enhance robustness of command sending mechanism
2025-02-19 21:51:55 +03:00
7d92682482 Enhance terminal widgets with read-only mode and clear functionality
- Add read-only mode to TerminalWidget to prevent manual text editing
- Disable text paste and key input in terminal widgets
- Modify context menu to remove cut and paste options
- Add clear buttons for interactive, file execution, and TFTP log terminals
- Implement temporary state changes for text appending and clearing
2025-02-19 21:49:49 +03:00
0ebcf9cb6a Enhance command execution with robust error handling and connection monitoring
- Add consecutive error tracking and connection state checks
- Implement automatic pause and user notification for persistent connection issues
- Improve block and line mode execution with enhanced error detection
- Modify logging and status reporting for better visibility of execution problems
- Add connection verification before and during command execution
2025-02-19 21:39:58 +03:00
99e9163760 Add advanced port monitoring and execution progress tracking
- Implement real-time COM port state monitoring with automatic reconnection
- Add connection indicator with dynamic status updates
- Create progress bar and timer for file command execution
- Enhance execution control with detailed progress tracking
- Implement thread-safe port monitoring and execution mechanisms
- Improve error handling and user feedback during command execution
2025-02-19 21:23:47 +03:00
b573de9166 Add advanced file execution control with pause and stop functionality
- Implement multi-stage command execution from file
- Add start, pause, and stop buttons for file command execution
- Create thread-safe execution control with pause and stop mechanisms
- Enhance error handling and user feedback during file command execution
- Improve command execution flow with step-by-step processing
2025-02-19 21:04:38 +03:00
f45f1bf556 Improve command logging and terminal display formatting
- Simplify command logging messages with concise `[CMD]` prefix
- Remove redundant command attempt counter from log messages
- Modify TerminalWidget to handle `[CMD]` tagged messages
- Enhance command display with consistent formatting and separators
2025-02-19 20:56:25 +03:00
e6766660c6 Add Enter key support for command input
- Bind Enter key to send command in interactive tab
2025-02-18 20:10:51 +03:00
e0705ad6b5 Add advanced TerminalWidget with enhanced text display and formatting
- Implement TerminalWidget class with color-coded message types
- Add support for error, warning, info, and command message styles
- Include automatic scrollbar and text formatting
- Replace CustomText with TerminalWidget in interactive tabs
- Enhance text appending methods with type-specific display
- Improve terminal readability with command separators
2025-02-18 00:35:14 +03:00
c0d8fd8d89 Improve interactive tab buttons with Unicode icons
- Add Unicode icons to the connect, disconnect and send buttons in the interactive tab
2025-02-18 00:11:42 +03:00
ce81100150 Enhance status bar with TFTP server indicator
- Add TFTP server status indicator to the status bar
- Implement tooltip for TFTP server status
- Update status bar update method to reflect TFTP server state
- Improve status bar layout with separate frames for indicators
2025-02-17 19:39:29 +03:00
48c9bd2d40 Bump version to 1.0.2
- Update application version number in ComConfigCopy.py
- Minor version increment to reflect recent changes
2025-02-17 18:35:58 +03:00
e0f64060f5 Add status bar with connection and settings information
- Implement create_status_bar method to add a new status bar
- Add connection indicator with color-coded status
- Create tooltip for connection status details
- Update status bar with current port, baudrate, and copy mode settings
- Integrate status bar updates in connection and settings change events
2025-02-17 18:31:58 +03:00
f5935d6b8f Merge pull request 'v1.0.1' (#4) from v1.0.1 into main
Reviewed-on: #4
2025-02-16 22:02:20 +00:00
1a511ff54f Enhance update checking
- Refactor UpdateChecker
- Add support for parsing release details with improved formatting
- Implement more robust version comparison and release type handling
- Add logging for update checking process
- Improve error handling and release information extraction
- Update update checking logic to handle stable and pre-release versions
2025-02-17 00:53:24 +03:00
f84e20631b Update contact email in README.md
- Change contact email from LowaWorkMail@gmail.com to SPRF555@gmail.com
2025-02-17 00:11:10 +03:00
4a67e70a92 Обновить README.md 2025-02-16 20:52:02 +00:00
12562e615f Bump version to 1.0.1
- Update application version number in ComConfigCopy.py
- Minor version increment to reflect recent changes
2025-02-16 23:48:59 +03:00
7ebeb52808 Refactor and optimize code structure with base widget and utility functions
- Create CustomWidgetBase for shared context menu and shortcut functionality
- Add utility functions for common tasks like text appending and file selection
- Simplify command processing with a generic send_command_and_process_response function
- Remove redundant comments and unused imports
- Improve code organization and readability
- Enhance modularity of custom widgets and utility methods
2025-02-16 23:45:19 +03:00
5 changed files with 1580 additions and 371 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@ ComConfigCopy - это утилита, разработанная для авт
## Контакты
- Email: LowaWorkMail@gmail.com
- Email: SPRF555@gmail.com
- Telegram: [@LowaSC](https://t.me/LowaSC)
- Репозиторий: [ComConfigCopy](https://gitea.filow.ru/LowaSC/ComConfigCopy)

View File

@@ -69,7 +69,7 @@ class AboutWindow(tk.Toplevel):
ttk.Label(
contact_frame,
text="Email: LowaWorkMail@gmail.com"
text="Email: SPRF555@gmail.com"
).pack(anchor="w")
telegram_link = ttk.Label(

View File

@@ -2,3 +2,4 @@ tftpy>=0.8.0
pyserial>=3.5
requests>=2.31.0
packaging>=23.2
send2trash>=1.8.0

View File

@@ -1,175 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import logging
import requests
import threading
import re
from packaging import version
import xml.etree.ElementTree as ET
import html
class UpdateCheckError(Exception):
"""Исключение для ошибок проверки обновлений"""
pass
class ReleaseType:
"""Типы релизов"""
STABLE = "stable"
PRERELEASE = "prerelease"
class UpdateChecker:
"""Класс для проверки обновлений программы"""
def __init__(self, current_version, repo_url):
def __init__(self, current_version, repo_url, include_prereleases=False):
self.current_version = current_version
self.repo_url = repo_url
# Формируем базовый URL API
self.api_url = repo_url.replace("gitea.filow.ru", "gitea.filow.ru/api/v1/repos/LowaSC/ComConfigCopy")
self._update_available = False
self._latest_version = None
self._latest_release = None
self._error = None
self._changelog = None
self.include_prereleases = include_prereleases
self.rss_url = f"{repo_url}/releases.rss"
self.release_info = None
def get_changelog(self, callback=None):
"""
Получение changelog из репозитория.
:param callback: Функция обратного вызова, которая будет вызвана после получения changelog
"""
def fetch():
try:
# Пытаемся получить CHANGELOG.md из репозитория
response = requests.get(f"{self.api_url}/contents/CHANGELOG.md", timeout=10)
response.raise_for_status()
def _clean_html(self, html_text):
"""Очищает HTML-разметку и форматирует текст"""
if not html_text:
return ""
text = re.sub(r'<[^>]+>', '', html_text)
text = html.unescape(text)
text = re.sub(r'\n\s*\n', '\n\n', text)
return '\n'.join(line.strip() for line in text.splitlines()).strip()
content = response.json()
if "content" in content:
import base64
changelog_content = base64.b64decode(content["content"]).decode("utf-8")
self._changelog = changelog_content
self._error = None
else:
raise UpdateCheckError("Не удалось получить содержимое CHANGELOG.md")
def _parse_release_info(self, item):
"""Извлекает информацию о релизе из RSS item"""
title = item.find('title').text if item.find('title') is not None else ''
link = item.find('link').text if item.find('link') is not None else ''
description = item.find('description').text if item.find('description') is not None else ''
content = item.find('{http://purl.org/rss/1.0/modules/content/}encoded')
content_text = content.text if content is not None else ''
except requests.RequestException as e:
error_msg = f"Ошибка получения changelog: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
self._changelog = None
except Exception as e:
error_msg = f"Неизвестная ошибка при получении changelog: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
self._changelog = None
finally:
if callback:
callback(self._changelog, self._error)
# Запускаем получение в отдельном потоке
threading.Thread(target=fetch, daemon=True).start()
def check_updates(self, callback=None):
"""
Проверка наличия обновлений.
:param callback: Функция обратного вызова, которая будет вызвана после проверки
"""
def check():
try:
response = requests.get(f"{self.api_url}/releases", timeout=10)
response.raise_for_status()
releases = response.json()
if not releases:
raise UpdateCheckError("Не найдено релизов в репозитории")
latest_release = releases[0]
latest_version = latest_release.get("tag_name", "").lstrip("v")
if not latest_version:
raise UpdateCheckError("Не удалось определить версию последнего релиза")
try:
if version.parse(latest_version) > version.parse(self.current_version):
self._update_available = True
self._latest_version = latest_version
self._latest_release = latest_release
logging.info(f"Доступно обновление: {latest_version}")
else:
logging.info("Обновления не требуются")
except version.InvalidVersion as e:
raise UpdateCheckError(f"Некорректный формат версии: {e}")
self._error = None
except requests.RequestException as e:
error_msg = f"Ошибка сетевого подключения: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
except UpdateCheckError as e:
logging.error(str(e), exc_info=True)
self._error = str(e)
except Exception as e:
error_msg = f"Неизвестная ошибка при проверке обновлений: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
finally:
if callback:
callback(self._update_available, self._error)
@property
def update_available(self):
"""Доступно ли обновление"""
return self._update_available
@property
def latest_version(self):
"""Последняя доступная версия"""
return self._latest_version
@property
def error(self):
"""Последняя ошибка при проверке обновлений"""
return self._error
@property
def changelog(self):
"""Текущий changelog"""
return self._changelog
def get_release_notes(self):
"""Получение информации о последнем релизе"""
if self._latest_release:
return {
"version": self._latest_version,
"description": self._latest_release.get("body", ""),
"download_url": self._latest_release.get("assets", [{}])[0].get("browser_download_url", "")
}
# Извлекаем версию и проверяем тип релиза из тега
version_match = re.search(r'/releases/tag/(?:pre-)?v?(\d+\.\d+(?:\.\d+)?)', link)
if not version_match:
return None
def get_releases(self, callback=None):
"""
Получение списка релизов из репозитория.
:param callback: Функция обратного вызова, которая будет вызвана после получения списка релизов
"""
def fetch():
version_str = version_match.group(1)
# Проверяем наличие префикса pre- в теге
is_prerelease = 'pre-' in link.lower()
# Форматируем название релиза
formatted_title = title
if title == version_str or not title.strip():
# Если заголовок пустой или совпадает с версией, создаем стандартное название
release_type = "Пре-релиз" if is_prerelease else "Версия"
formatted_title = f"{release_type} {version_str}"
elif not re.search(version_str, title):
# Если версия не указана в заголовке, добавляем её
formatted_title = f"{title} ({version_str})"
# Форматируем описание
formatted_description = self._clean_html(content_text or description)
if not formatted_description.strip():
formatted_description = "Нет описания"
# Добавляем метку типа релиза в начало описания
release_type_label = "[Пре-релиз] " if is_prerelease else ""
formatted_description = f"{release_type_label}{formatted_description}"
return {
'title': formatted_title,
'link': link,
'description': formatted_description,
'version': version_str,
'type': ReleaseType.PRERELEASE if is_prerelease else ReleaseType.STABLE
}
def check_updates(self, callback=None):
"""Проверяет наличие обновлений в асинхронном режиме"""
def check_worker():
try:
response = requests.get(f"{self.api_url}/releases", timeout=10)
logging.info(f"Текущая версия программы: {self.current_version}")
logging.info(f"Проверка пре-релизов: {self.include_prereleases}")
logging.info(f"Запрос RSS ленты: {self.rss_url}")
response = requests.get(self.rss_url, timeout=10)
response.raise_for_status()
releases = response.json()
if not releases:
raise UpdateCheckError("Не найдено релизов в репозитории")
root = ET.fromstring(response.content)
items = root.findall('.//item')
if not items:
raise UpdateCheckError("Релизы не найдены")
logging.info(f"Найдено {len(items)} релизов")
latest_version = None
latest_info = None
for item in items:
release_info = self._parse_release_info(item)
if not release_info:
continue
is_prerelease = release_info['type'] == ReleaseType.PRERELEASE
logging.info(
f"Проверка релиза: {release_info['title']}, "
f"версия: {release_info['version']}, "
f"тип: {'пре-релиз' if is_prerelease else 'стабильная'}"
)
# Пропускаем пре-релизы если они не включены
if is_prerelease and not self.include_prereleases:
logging.info(f"Пропуск пре-релиза: {release_info['version']}")
continue
# Сравниваем версии
try:
current_ver = version.parse(latest_version or "0.0.0")
new_ver = version.parse(release_info['version'].split('-')[0]) # Убираем суффикс для сравнения
if new_ver > current_ver:
latest_version = release_info['version']
latest_info = release_info
logging.info(f"Новая версия: {latest_version}")
except version.InvalidVersion as e:
logging.warning(f"Некорректный формат версии {release_info['version']}: {e}")
continue
if not latest_info:
raise UpdateCheckError("Не найдены подходящие версии")
self.release_info = latest_info
# Сравниваем с текущей версией
current_ver = version.parse(self.current_version)
latest_ver = version.parse(latest_version.split('-')[0])
update_available = latest_ver > current_ver
logging.info(f"Сравнение версий: текущая {current_ver} <-> последняя {latest_ver}")
logging.info(f"Доступно обновление: {update_available}")
self._error = None
if callback:
callback(releases, None)
callback(update_available, None)
except requests.RequestException as e:
error_msg = f"Ошибка сетевого подключения: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
except UpdateCheckError as e:
logging.error(str(e))
if callback:
callback(None, error_msg)
callback(False, str(e))
except Exception as e:
error_msg = f"Ошибка при получении списка релизов: {e}"
logging.error(error_msg, exc_info=True)
self._error = error_msg
logging.error(f"Ошибка при проверке обновлений: {e}", exc_info=True)
if callback:
callback(None, error_msg)
callback(False, str(e))
# Запускаем получение в отдельном потоке
threading.Thread(target=fetch, daemon=True).start()
threading.Thread(target=check_worker, daemon=True).start()
def get_release_notes(self):
"""Возвращает информацию о последнем релизе"""
return self.release_info