forked from CastroFidel/winehelper
Compare commits
14 Commits
border_rad
...
0.5.3
Author | SHA1 | Date | |
---|---|---|---|
e766b4dba2 | |||
bad7e5780a | |||
7fbe9ba31b | |||
377b9e9059 | |||
a815fa1c20 | |||
63f301d2de | |||
213035d868 | |||
65bd514a1a | |||
cb3fdc62dc | |||
9611cc52fc | |||
5cdc4a8f4f | |||
32fa7f6278 | |||
b44fcdb63e | |||
3e2ed1cff5 |
@ -1,5 +1,9 @@
|
|||||||
История изменений:
|
История изменений:
|
||||||
|
|
||||||
|
0.5.3:
|
||||||
|
* исправлена установка grdcontrol для t-flex-*
|
||||||
|
* обновлен графический режим Qt5
|
||||||
|
|
||||||
0.5.2:
|
0.5.2:
|
||||||
* исправлен запуск winehelper.desktop для winehelper-qt
|
* исправлен запуск winehelper.desktop для winehelper-qt
|
||||||
|
|
||||||
|
14
LICENSE_AGREEMENT
Normal file
14
LICENSE_AGREEMENT
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Лицензионные соглашения использования сторонних компонентов:
|
||||||
|
|
||||||
|
Некоторые компоненты, установленные в префикс и необходимые для запуска приложений,
|
||||||
|
могут быть защищены авторским правом или лицензионными соглашениями. Вы обязаны
|
||||||
|
самостоятельно убедиться в законности использования этих компонентов в вашей
|
||||||
|
юрисдикции.
|
||||||
|
|
||||||
|
Мы не несём ответственности за нарушение лицензионных соглашений, связанное с
|
||||||
|
использованием подготовленного префикса, а так же за программное обеспечение,
|
||||||
|
поставляемое из сторонних источников.
|
||||||
|
|
||||||
|
Подтверждая продолжение установки, вы соглашаетесь, что ознакомились с данным
|
||||||
|
отказом от ответственности и принимаете все риски, связанные с использованием
|
||||||
|
программного обеспечения.
|
@ -28,8 +28,8 @@ prepair_wine
|
|||||||
|
|
||||||
if [[ -d "$WINEPREFIX" ]] \
|
if [[ -d "$WINEPREFIX" ]] \
|
||||||
&& grep -q "t-flex-cad" "$WINEPREFIX/winetricks.log" \
|
&& grep -q "t-flex-cad" "$WINEPREFIX/winetricks.log" \
|
||||||
&& systemctl list-units --type service --state running | grep aksusbd \
|
&& systemctl list-units --type service --state running | grep -q aksusbd \
|
||||||
&& systemctl list-units --type service --state running | grep hasplmd \
|
&& systemctl list-units --type service --state running | grep -q hasplmd \
|
||||||
&& rpm -q grdcontrol | grep -q "$GRDCONTROL_VER"
|
&& rpm -q grdcontrol | grep -q "$GRDCONTROL_VER"
|
||||||
then
|
then
|
||||||
print_info "Префикс $PREFIX_NAME готов к установке ПО."
|
print_info "Префикс $PREFIX_NAME готов к установке ПО."
|
||||||
@ -50,7 +50,7 @@ else
|
|||||||
|
|
||||||
if rpm -q grdcontrol | grep -q "$GRDCONTROL_VER"
|
if rpm -q grdcontrol | grep -q "$GRDCONTROL_VER"
|
||||||
then print_info "grdcontrol-$GRDCONTROL_VER уже установлен в системе."
|
then print_info "grdcontrol-$GRDCONTROL_VER уже установлен в системе."
|
||||||
else su_run rpm -iv "$AUTOINSTALL_DIR_LIN/Guardant_Linux/grdcontrol.x86_64.rpm"
|
else su_run "rpm -iv \"$AUTOINSTALL_DIR_LIN/Guardant_Linux/grdcontrol.x86_64.rpm\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$BASE_PFX" == "none" ]] ; then
|
if [[ "$BASE_PFX" == "none" ]] ; then
|
||||||
|
24
winehelper
24
winehelper
@ -7,7 +7,7 @@ if [[ $(id -u) -eq 0 ]] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
##### DEFAULT PATH #####
|
##### DEFAULT PATH #####
|
||||||
export SCRIPT_NAME USER_WORK_PATH RUN_SCRIPT DATA_PATH CHANGELOG_FILE WH_ICON_PATH LICENSE_FILE
|
export SCRIPT_NAME USER_WORK_PATH RUN_SCRIPT DATA_PATH CHANGELOG_FILE WH_ICON_PATH LICENSE_FILE AGREEMENT
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "$0")"
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
|
if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
|
||||||
@ -18,6 +18,7 @@ if [[ "$(realpath "$0")" == "/usr/bin/$SCRIPT_NAME" ]] ; then
|
|||||||
CHANGELOG_FILE="$(realpath "/usr/share/doc/winehelper"-*/CHANGELOG)"
|
CHANGELOG_FILE="$(realpath "/usr/share/doc/winehelper"-*/CHANGELOG)"
|
||||||
WH_ICON_PATH="$DATA_PATH/image/gui/winehelper.svg"
|
WH_ICON_PATH="$DATA_PATH/image/gui/winehelper.svg"
|
||||||
LICENSE_FILE="$(realpath "/usr/share/doc/winehelper"-*/LICENSE)"
|
LICENSE_FILE="$(realpath "/usr/share/doc/winehelper"-*/LICENSE)"
|
||||||
|
AGREEMENT="$(realpath "/usr/share/doc/winehelper"-*/LICENSE_AGREEMENT)"
|
||||||
else
|
else
|
||||||
# переменные для тестового запуска WineHelper из репозитория
|
# переменные для тестового запуска WineHelper из репозитория
|
||||||
USER_WORK_PATH="$HOME/test-$SCRIPT_NAME"
|
USER_WORK_PATH="$HOME/test-$SCRIPT_NAME"
|
||||||
@ -26,6 +27,7 @@ else
|
|||||||
CHANGELOG_FILE="$DATA_PATH/CHANGELOG"
|
CHANGELOG_FILE="$DATA_PATH/CHANGELOG"
|
||||||
WH_ICON_PATH="$DATA_PATH/image/gui/winehelper-devel.svg"
|
WH_ICON_PATH="$DATA_PATH/image/gui/winehelper-devel.svg"
|
||||||
LICENSE_FILE="$DATA_PATH/LICENSE"
|
LICENSE_FILE="$DATA_PATH/LICENSE"
|
||||||
|
AGREEMENT="$DATA_PATH/LICENSE_AGREEMENT"
|
||||||
|
|
||||||
# минимальная проверка синтаксиса скриптов
|
# минимальная проверка синтаксиса скриптов
|
||||||
for self_check_script in "$RUN_SCRIPT" \
|
for self_check_script in "$RUN_SCRIPT" \
|
||||||
@ -367,20 +369,14 @@ print_license_agreement () {
|
|||||||
then return 0
|
then return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$AGREEMENT" ]]; then
|
||||||
|
echo
|
||||||
|
print_warning "$(cat "$AGREEMENT")"
|
||||||
|
else
|
||||||
|
fatal "Файл лицензионного соглашения не найден: $AGREEMENT"
|
||||||
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
print_warning "Лицензионные соглашения использования сторонних компонентов:
|
|
||||||
|
|
||||||
Некоторые компоненты, установленные в префикс и необходимые для запуска приложений, могут
|
|
||||||
быть защищены авторским правом или лицензионными соглашениями. Вы обязаны самостоятельно
|
|
||||||
убедиться в законности использования этих компонентов в вашей юрисдикции.
|
|
||||||
|
|
||||||
Мы не несём ответственности за нарушение лицензионных соглашений, связанное с использованием
|
|
||||||
подготовленного префикса, а так же за программное обеспечение поставляемого из сторонних источников.
|
|
||||||
|
|
||||||
Подтверждая продолжение установки, вы соглашаетесь что ознакомились с данным отказом от
|
|
||||||
ответственности и принимаете все риски, связанные с использованием программного обеспечения.
|
|
||||||
"
|
|
||||||
|
|
||||||
if print_confirmation "Подтвердите продолжение установки" ; then
|
if print_confirmation "Подтвердите продолжение установки" ; then
|
||||||
touch "$license_agreement_file"
|
touch "$license_agreement_file"
|
||||||
chmod 600 "$license_agreement_file"
|
chmod 600 "$license_agreement_file"
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
|
import html
|
||||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget,
|
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton, QLabel, QTabWidget,
|
||||||
QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea,
|
QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea,
|
||||||
QGridLayout, QFrame, QDialog, QTextBrowser)
|
QGridLayout, QFrame, QDialog, QTextBrowser)
|
||||||
@ -20,6 +22,7 @@ class Var:
|
|||||||
CHANGELOG_FILE = os.environ.get("CHANGELOG_FILE")
|
CHANGELOG_FILE = os.environ.get("CHANGELOG_FILE")
|
||||||
WH_ICON_PATH = os.environ.get("WH_ICON_PATH")
|
WH_ICON_PATH = os.environ.get("WH_ICON_PATH")
|
||||||
LICENSE_FILE = os.environ.get("LICENSE_FILE")
|
LICENSE_FILE = os.environ.get("LICENSE_FILE")
|
||||||
|
LICENSE_AGREEMENT_FILE = os.environ.get("AGREEMENT")
|
||||||
|
|
||||||
class WineHelperGUI(QMainWindow):
|
class WineHelperGUI(QMainWindow):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -64,6 +67,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.process = None
|
self.process = None
|
||||||
self.current_script = None
|
self.current_script = None
|
||||||
self.install_process = None
|
self.install_process = None
|
||||||
|
self.current_display_name = None
|
||||||
self.install_dialog = None
|
self.install_dialog = None
|
||||||
self.current_active_button = None
|
self.current_active_button = None
|
||||||
self.installed_buttons = []
|
self.installed_buttons = []
|
||||||
@ -78,10 +82,15 @@ class WineHelperGUI(QMainWindow):
|
|||||||
|
|
||||||
# Создаем табы
|
# Создаем табы
|
||||||
self.tabs = QTabWidget()
|
self.tabs = QTabWidget()
|
||||||
self.main_layout.addWidget(self.tabs, stretch=2)
|
self.main_layout.addWidget(self.tabs, stretch=1)
|
||||||
|
|
||||||
# Создаем панель информации о скрипте
|
# Создаем панель информации о скрипте
|
||||||
self.create_info_panel()
|
self.create_info_panel()
|
||||||
|
self.main_layout.addWidget(self.info_panel, stretch=1)
|
||||||
|
|
||||||
|
# Фиксируем минимальные размеры
|
||||||
|
self.tabs.setMinimumWidth(520)
|
||||||
|
self.info_panel.setMinimumWidth(415)
|
||||||
|
|
||||||
# Вкладки
|
# Вкладки
|
||||||
self.create_auto_install_tab()
|
self.create_auto_install_tab()
|
||||||
@ -89,6 +98,9 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.create_installed_tab()
|
self.create_installed_tab()
|
||||||
self.create_help_tab()
|
self.create_help_tab()
|
||||||
|
|
||||||
|
# Инициализируем состояние, которое будет использоваться для логов
|
||||||
|
self._reset_log_state()
|
||||||
|
|
||||||
# Обновляем список установленных приложений
|
# Обновляем список установленных приложений
|
||||||
self.update_installed_apps()
|
self.update_installed_apps()
|
||||||
|
|
||||||
@ -162,7 +174,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
|
|
||||||
# Заголовок
|
# Заголовок
|
||||||
self.script_title = QLabel("Выберите программу")
|
self.script_title = QLabel("Выберите программу")
|
||||||
self.script_title.setFont(QFont('Arial', 14, QFont.Bold)) # Шрифт и размер шрифта в заголовке инф. панели
|
self.script_title.setFont(QFont('Arial', 12, QFont.Bold)) # Шрифт и размер шрифта в заголовке инф. панели
|
||||||
self.script_title.setAlignment(Qt.AlignCenter)
|
self.script_title.setAlignment(Qt.AlignCenter)
|
||||||
self.info_panel_layout.addWidget(self.script_title)
|
self.info_panel_layout.addWidget(self.script_title)
|
||||||
|
|
||||||
@ -198,7 +210,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
install_action_layout = QVBoxLayout()
|
install_action_layout = QVBoxLayout()
|
||||||
install_action_layout.setContentsMargins(0, 0, 0, 0)
|
install_action_layout.setContentsMargins(0, 0, 0, 0)
|
||||||
self.install_button = QPushButton("Установить")
|
self.install_button = QPushButton("Установить")
|
||||||
self.install_button.setFont(QFont('Arial', 13, QFont.Bold))
|
self.install_button.setFont(QFont('Arial', 12, QFont.Bold)) # Шрифт и размер шрифта в кнопке Установить
|
||||||
self.install_button.setStyleSheet("background-color: #4CAF50; color: white;")
|
self.install_button.setStyleSheet("background-color: #4CAF50; color: white;")
|
||||||
self.install_button.clicked.connect(self.install_current_script)
|
self.install_button.clicked.connect(self.install_current_script)
|
||||||
install_action_layout.addWidget(self.install_button)
|
install_action_layout.addWidget(self.install_button)
|
||||||
@ -249,8 +261,6 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.installed_action_widget.setVisible(False)
|
self.installed_action_widget.setVisible(False)
|
||||||
self.installed_global_action_widget.setVisible(False)
|
self.installed_global_action_widget.setVisible(False)
|
||||||
|
|
||||||
self.main_layout.addWidget(self.info_panel, stretch=1)
|
|
||||||
|
|
||||||
def browse_install_file(self):
|
def browse_install_file(self):
|
||||||
"""Открывает диалог выбора файла для ручной установки"""
|
"""Открывает диалог выбора файла для ручной установки"""
|
||||||
file_path, _ = QFileDialog.getOpenFileName(
|
file_path, _ = QFileDialog.getOpenFileName(
|
||||||
@ -604,7 +614,6 @@ class WineHelperGUI(QMainWindow):
|
|||||||
# Подвкладка "Лицензия"
|
# Подвкладка "Лицензия"
|
||||||
license_tab = QWidget()
|
license_tab = QWidget()
|
||||||
license_layout = QVBoxLayout(license_tab)
|
license_layout = QVBoxLayout(license_tab)
|
||||||
import html
|
|
||||||
license_text = QTextBrowser()
|
license_text = QTextBrowser()
|
||||||
license_text.setOpenExternalLinks(True)
|
license_text.setOpenExternalLinks(True)
|
||||||
|
|
||||||
@ -685,9 +694,12 @@ class WineHelperGUI(QMainWindow):
|
|||||||
if self.current_active_button in self.installed_buttons:
|
if self.current_active_button in self.installed_buttons:
|
||||||
self.current_active_button = None
|
self.current_active_button = None
|
||||||
|
|
||||||
# Очистить существующие кнопки
|
# Полностью очищаем layout перед обновлением, удаляя старые виджеты (рамки с кнопками)
|
||||||
for btn in self.installed_buttons:
|
while self.installed_scroll_layout.count():
|
||||||
btn.deleteLater()
|
item = self.installed_scroll_layout.takeAt(0)
|
||||||
|
widget = item.widget()
|
||||||
|
if widget:
|
||||||
|
widget.deleteLater()
|
||||||
self.installed_buttons.clear()
|
self.installed_buttons.clear()
|
||||||
|
|
||||||
if not os.path.exists(Var.USER_WORK_PATH):
|
if not os.path.exists(Var.USER_WORK_PATH):
|
||||||
@ -833,6 +845,11 @@ class WineHelperGUI(QMainWindow):
|
|||||||
print(f"Error getting prefix name from {desktop_file}: {e}")
|
print(f"Error getting prefix name from {desktop_file}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _get_current_app_title(self):
|
||||||
|
"""Возвращает отображаемое имя для текущей выбранной программы."""
|
||||||
|
# Если display_name не установлено (например, при ошибке), используем имя скрипта
|
||||||
|
return self.current_display_name or self.current_script
|
||||||
|
|
||||||
def backup_prefix_for_app(self):
|
def backup_prefix_for_app(self):
|
||||||
"""Создает резервную копию префикса для выбранного приложения."""
|
"""Создает резервную копию префикса для выбранного приложения."""
|
||||||
prefix_name = self._get_prefix_name_for_selected_app()
|
prefix_name = self._get_prefix_name_for_selected_app()
|
||||||
@ -1206,6 +1223,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
prog_name = self.extract_prog_name_from_script(script_path)
|
prog_name = self.extract_prog_name_from_script(script_path)
|
||||||
prog_url = self.extract_prog_url_from_script(script_path)
|
prog_url = self.extract_prog_url_from_script(script_path)
|
||||||
display_name = prog_name if prog_name else script_name
|
display_name = prog_name if prog_name else script_name
|
||||||
|
self.current_display_name = display_name
|
||||||
|
|
||||||
if icon_names:
|
if icon_names:
|
||||||
# Для заголовка используем первую иконку из списка
|
# Для заголовка используем первую иконку из списка
|
||||||
@ -1228,7 +1246,7 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.install_action_widget.setVisible(True)
|
self.install_action_widget.setVisible(True)
|
||||||
self.installed_action_widget.setVisible(False)
|
self.installed_action_widget.setVisible(False)
|
||||||
self.installed_global_action_widget.setVisible(False)
|
self.installed_global_action_widget.setVisible(False)
|
||||||
self.install_button.setText(f"Установить {display_name}")
|
self.install_button.setText(f"Установить «{display_name}»")
|
||||||
|
|
||||||
def install_current_script(self):
|
def install_current_script(self):
|
||||||
"""Устанавливает текущий выбранный скрипт"""
|
"""Устанавливает текущий выбранный скрипт"""
|
||||||
@ -1242,7 +1260,8 @@ class WineHelperGUI(QMainWindow):
|
|||||||
|
|
||||||
# Создаем диалоговое окно установки
|
# Создаем диалоговое окно установки
|
||||||
self.install_dialog = QDialog(self)
|
self.install_dialog = QDialog(self)
|
||||||
self.install_dialog.setWindowTitle(f"Установка {self.current_script}")
|
title_name = self._get_current_app_title()
|
||||||
|
self.install_dialog.setWindowTitle(f"Установка «{title_name}»")
|
||||||
self.install_dialog.setMinimumSize(750, 400)
|
self.install_dialog.setMinimumSize(750, 400)
|
||||||
self.install_dialog.setWindowModality(Qt.WindowModal)
|
self.install_dialog.setWindowModality(Qt.WindowModal)
|
||||||
|
|
||||||
@ -1255,38 +1274,32 @@ class WineHelperGUI(QMainWindow):
|
|||||||
license_page = QWidget()
|
license_page = QWidget()
|
||||||
license_layout = QVBoxLayout(license_page)
|
license_layout = QVBoxLayout(license_page)
|
||||||
|
|
||||||
license_text = QTextEdit()
|
license_found = False
|
||||||
license_text.setReadOnly(True)
|
|
||||||
|
|
||||||
# Получаем текст лицензии из скрипта winehelper
|
license_text = QTextBrowser()
|
||||||
script_path = os.path.join(Var.DATA_PATH, "winehelper")
|
|
||||||
license_content = ""
|
# Получаем текст лицензионного соглашения из файла
|
||||||
try:
|
try:
|
||||||
with open(script_path, 'r', encoding='utf-8') as f:
|
license_file_path = Var.LICENSE_AGREEMENT_FILE
|
||||||
capturing = False
|
if not license_file_path or not os.path.exists(license_file_path):
|
||||||
for line in f:
|
raise FileNotFoundError
|
||||||
if 'print_warning "Лицензионные соглашения использования сторонних компонентов:' in line:
|
|
||||||
capturing = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if capturing:
|
with open(license_file_path, 'r', encoding='utf-8') as f:
|
||||||
if 'Подтверждая продолжение установки' in line:
|
license_content = f.read()
|
||||||
break
|
|
||||||
# Очищаем строку от лишних символов
|
escaped_license_content = html.escape(license_content)
|
||||||
clean_line = line.strip()
|
|
||||||
clean_line = clean_line.replace('print_warning "', '').replace('\\n', '\n')
|
|
||||||
clean_line = clean_line.rstrip('"')
|
|
||||||
license_content += clean_line + '\n'
|
|
||||||
|
|
||||||
license_text.setHtml(f"""
|
license_text.setHtml(f"""
|
||||||
<h3>Лицензионные соглашения использования сторонних компонентов:</h3>
|
<pre style="font-family: sans-serif; font-size: 10pt; white-space: pre-wrap; word-wrap: break-word;">{escaped_license_content}</pre>
|
||||||
<p>{license_content}</p>
|
|
||||||
""")
|
""")
|
||||||
|
license_found = True
|
||||||
|
except (FileNotFoundError, TypeError):
|
||||||
|
license_text.setHtml(f'<h3>Лицензионные соглашения</h3><p>Не удалось загрузить файл лицензионного соглашения по пути:<br>{Var.LICENSE_AGREEMENT_FILE}</p>')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка чтения файла для извлечения лицензии: {str(e)}")
|
print(f"Ошибка чтения файла лицензии: {str(e)}")
|
||||||
license_text.setHtml("""
|
license_text.setHtml(f"""
|
||||||
<h3>Лицензионные соглашения</h3>
|
<h3>Лицензионные соглашения</h3>
|
||||||
<p>Не удалось загрузить текст лицензионного соглашения.</p>
|
<p>Произошла ошибка при чтении файла лицензии:<br>{str(e)}</p>
|
||||||
""")
|
""")
|
||||||
|
|
||||||
license_layout.addWidget(license_text)
|
license_layout.addWidget(license_text)
|
||||||
@ -1333,12 +1346,21 @@ class WineHelperGUI(QMainWindow):
|
|||||||
lambda state: self.btn_continue.setEnabled(state == Qt.Checked)
|
lambda state: self.btn_continue.setEnabled(state == Qt.Checked)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not license_found:
|
||||||
|
self.license_checkbox.setEnabled(False)
|
||||||
|
|
||||||
self.install_dialog.show()
|
self.install_dialog.show()
|
||||||
|
|
||||||
|
def _reset_log_state(self):
|
||||||
|
"""Сбрасывает состояние буфера и флага прогресса для лога установки."""
|
||||||
|
self.output_buffer = ""
|
||||||
|
self.last_line_was_progress = False
|
||||||
|
|
||||||
def _prepare_installation(self):
|
def _prepare_installation(self):
|
||||||
"""Подготавливает и запускает процесс установки"""
|
"""Подготавливает и запускает процесс установки"""
|
||||||
self.stacked_widget.setCurrentIndex(1)
|
self.stacked_widget.setCurrentIndex(1)
|
||||||
|
self._reset_log_state() # Сбрасываем состояние для обработки лога
|
||||||
|
|
||||||
winehelper_path = self.winehelper_path
|
winehelper_path = self.winehelper_path
|
||||||
script_path = os.path.join(Var.DATA_PATH,
|
script_path = os.path.join(Var.DATA_PATH,
|
||||||
"autoinstall" if self.current_script in self.autoinstall_scripts else "manualinstall",
|
"autoinstall" if self.current_script in self.autoinstall_scripts else "manualinstall",
|
||||||
@ -1377,7 +1399,8 @@ class WineHelperGUI(QMainWindow):
|
|||||||
if install_file:
|
if install_file:
|
||||||
args.append(install_file)
|
args.append(install_file)
|
||||||
|
|
||||||
self.append_log(f"=== Начало установки {self.current_script} ===")
|
title_name = self._get_current_app_title()
|
||||||
|
self.append_log(f"=== Начало установки «{title_name}» ===")
|
||||||
self.append_log(f"Исполняемый файл: {winehelper_path}")
|
self.append_log(f"Исполняемый файл: {winehelper_path}")
|
||||||
self.append_log(f"Аргументы: {' '.join(shlex.quote(a) for a in args)}")
|
self.append_log(f"Аргументы: {' '.join(shlex.quote(a) for a in args)}")
|
||||||
|
|
||||||
@ -1385,40 +1408,106 @@ class WineHelperGUI(QMainWindow):
|
|||||||
self.install_process.start(winehelper_path, args)
|
self.install_process.start(winehelper_path, args)
|
||||||
if not self.install_process.waitForStarted(3000):
|
if not self.install_process.waitForStarted(3000):
|
||||||
raise RuntimeError("Не удалось запустить процесс установки")
|
raise RuntimeError("Не удалось запустить процесс установки")
|
||||||
self.append_log("Процесс установки успешно запущен...")
|
self.append_log("Процесс установки запущен...")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.append_log(f"\n=== ОШИБКА: {str(e)} ===", is_error=True)
|
self.append_log(f"\n=== ОШИБКА: {str(e)} ===", is_error=True)
|
||||||
QMessageBox.critical(self.install_dialog, "Ошибка", f"Не удалось запустить установку:\n{str(e)}")
|
QMessageBox.critical(self.install_dialog, "Ошибка", f"Не удалось запустить установку:\n{str(e)}")
|
||||||
self.cleanup_process()
|
self.cleanup_process()
|
||||||
|
|
||||||
def append_log(self, text, is_error=False):
|
def append_log(self, text, is_error=False, add_newline=True):
|
||||||
"""Добавляет сообщение в лог"""
|
"""Добавляет сообщение в лог"""
|
||||||
if not hasattr(self, 'log_output'): return
|
if not hasattr(self, 'log_output'): return
|
||||||
cursor = self.log_output.textCursor()
|
cursor = self.log_output.textCursor()
|
||||||
cursor.movePosition(QTextCursor.End)
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
|
||||||
if is_error:
|
if is_error:
|
||||||
|
# Для ошибок всегда добавляем перенос строки для лучшей читаемости
|
||||||
cursor.insertHtml(f'<font color="red">{text}</font><br>')
|
cursor.insertHtml(f'<font color="red">{text}</font><br>')
|
||||||
else:
|
else:
|
||||||
cursor.insertText(f"{text}\n")
|
# Вставляем текст. Добавляем перенос строки, если нужно.
|
||||||
|
formatted_text = f"{text}\n" if add_newline else text
|
||||||
|
cursor.insertText(formatted_text)
|
||||||
|
|
||||||
self.log_output.ensureCursorVisible()
|
self.log_output.ensureCursorVisible()
|
||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
|
|
||||||
|
def _process_log_line(self, line_with_delimiter):
|
||||||
|
"""Обрабатывает одну строку лога, управляя заменой строк прогресса."""
|
||||||
|
is_progress_line = '\r' in line_with_delimiter
|
||||||
|
|
||||||
|
# Фильтруем "мусорные" строки прогресса (например, '-=O=-' от wget),
|
||||||
|
# обрабатывая только те, что содержат знак процента.
|
||||||
|
if is_progress_line:
|
||||||
|
if not re.search(r'\d\s*%', line_with_delimiter):
|
||||||
|
return # Игнорируем строку прогресса без процентов
|
||||||
|
|
||||||
|
clean_line = line_with_delimiter.replace('\r', '').replace('\n', '').strip()
|
||||||
|
|
||||||
|
if not clean_line:
|
||||||
|
return
|
||||||
|
|
||||||
|
cursor = self.log_output.textCursor()
|
||||||
|
|
||||||
|
# Если новая строка - это прогресс, и предыдущая тоже была прогрессом,
|
||||||
|
# то мы удаляем старую, чтобы заменить ее новой.
|
||||||
|
if is_progress_line and self.last_line_was_progress:
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
cursor.select(QTextCursor.LineUnderCursor)
|
||||||
|
cursor.removeSelectedText()
|
||||||
|
elif not is_progress_line and self.last_line_was_progress:
|
||||||
|
# Это переход от строки прогресса к финальной строке.
|
||||||
|
# Вместо добавления переноса, мы заменяем предыдущую строку новой.
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
cursor.select(QTextCursor.LineUnderCursor)
|
||||||
|
cursor.removeSelectedText()
|
||||||
|
|
||||||
|
# Добавляем новую очищенную строку.
|
||||||
|
# Для прогресса - без переноса строки, для обычных строк - с переносом.
|
||||||
|
self.append_log(clean_line, add_newline=not is_progress_line)
|
||||||
|
|
||||||
|
self.last_line_was_progress = is_progress_line
|
||||||
|
|
||||||
def handle_process_output(self):
|
def handle_process_output(self):
|
||||||
"""Обрабатывает вывод процесса"""
|
"""Обрабатывает вывод процесса, корректно отображая однострочный прогресс."""
|
||||||
output = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore').strip()
|
new_data = self.install_process.readAllStandardOutput().data().decode('utf-8', errors='ignore')
|
||||||
if output:
|
self.output_buffer += new_data
|
||||||
self.append_log(output)
|
|
||||||
|
while True:
|
||||||
|
# Ищем ближайший разделитель (\n или \r)
|
||||||
|
idx_n = self.output_buffer.find('\n')
|
||||||
|
idx_r = self.output_buffer.find('\r')
|
||||||
|
|
||||||
|
if idx_n == -1 and idx_r == -1:
|
||||||
|
break # Нет полных строк для обработки
|
||||||
|
|
||||||
|
split_idx = min(idx for idx in [idx_n, idx_r] if idx != -1)
|
||||||
|
|
||||||
|
# Получаем строку, включая разделитель
|
||||||
|
line = self.output_buffer[:split_idx + 1]
|
||||||
|
self.output_buffer = self.output_buffer[split_idx + 1:]
|
||||||
|
|
||||||
|
self._process_log_line(line)
|
||||||
|
|
||||||
def handle_process_finished(self, exit_code, exit_status):
|
def handle_process_finished(self, exit_code, exit_status):
|
||||||
"""Обрабатывает завершение процесса"""
|
"""Обрабатывает завершение процесса"""
|
||||||
|
# Обрабатываем остаток в буфере, если он есть
|
||||||
|
if self.output_buffer:
|
||||||
|
self._process_log_line(self.output_buffer)
|
||||||
|
|
||||||
|
# Если последней строкой был прогресс, "завершаем" его переносом строки.
|
||||||
|
if self.last_line_was_progress:
|
||||||
|
cursor = self.log_output.textCursor()
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
cursor.insertText("\n")
|
||||||
|
|
||||||
|
self._reset_log_state()
|
||||||
if exit_code == 0 and exit_status == QProcess.NormalExit:
|
if exit_code == 0 and exit_status == QProcess.NormalExit:
|
||||||
self.append_log("\n=== Установка успешно завершена ===")
|
self.append_log("\n=== Установка успешно завершена ===")
|
||||||
# Создаем кастомный диалог, чтобы кнопка была на русском
|
# Создаем кастомный диалог, чтобы кнопка была на русском
|
||||||
success_box = QMessageBox(self.install_dialog)
|
success_box = QMessageBox(self.install_dialog)
|
||||||
success_box.setWindowTitle("Успех")
|
success_box.setWindowTitle("Успех")
|
||||||
success_box.setText(f"Программа {self.current_script} установлена успешно!")
|
title_name = self._get_current_app_title()
|
||||||
|
success_box.setText(f"Программа «{title_name}» установлена успешно!")
|
||||||
success_box.setIcon(QMessageBox.Information)
|
success_box.setIcon(QMessageBox.Information)
|
||||||
success_box.addButton("Готово", QMessageBox.AcceptRole)
|
success_box.addButton("Готово", QMessageBox.AcceptRole)
|
||||||
success_box.exec_()
|
success_box.exec_()
|
||||||
|
Reference in New Issue
Block a user