Compare commits

...

18 Commits

Author SHA1 Message Date
Sergey Palcheh
b4d663f2a7 added a more precise definition of the wine version for the prefix being created 2025-08-26 11:42:10 +06:00
Sergey Palcheh
c5db176ca4 the component manager has been restored 2025-08-26 11:16:50 +06:00
Sergey Palcheh
d73c0a47ab code block removed from _handle_prefix_creation_output method 2025-08-26 10:43:11 +06:00
Sergey Palcheh
aadd579cdc added the ability to install the application in the created prefix 2025-08-25 16:58:42 +06:00
Sergey Palcheh
0608a3f250 the Management header has been deleted 2025-08-25 15:56:47 +06:00
Sergey Palcheh
274a21941d added deletion of the created prefix 2025-08-25 15:43:34 +06:00
Sergey Palcheh
d499147bdc added the choice of a prefix to be created for management 2025-08-25 15:20:57 +06:00
Sergey Palcheh
dd5d8bb657 changes to the default fill button 2025-08-25 14:41:40 +06:00
Sergey Palcheh
f73f717d0e the prefix control unit has been added to the Create prefix tab 2025-08-25 14:19:45 +06:00
Sergey Palcheh
cefb3c8d5a changing the tab display in the main window 2025-08-25 13:03:36 +06:00
Sergey Palcheh
a4f01e7340 refactoring the install_current_script() method 2025-08-25 11:33:45 +06:00
Sergey Palcheh
70f2976a70 fixed the display in the wine version selection bar 2025-08-25 11:13:24 +06:00
Sergey Palcheh
34713bb61a added a prefix creation tab 2025-08-24 20:56:34 +06:00
Sergey Palcheh
eea04f0d91 added separation of wine/proton display by groups 2025-08-23 22:04:29 +06:00
Sergey Palcheh
45bc97d796 added wine/proton separation by prefix bit depth 2025-08-23 20:00:47 +06:00
Sergey Palcheh
88f1febf54 added the function of selecting the wine version with improved downloads 2025-08-23 16:07:26 +06:00
Sergey Palcheh
c756459993 added generation of wine metadata 2025-08-22 18:09:12 +06:00
Sergey Palcheh
b97b2169ab added prefix creation 2025-08-22 13:14:48 +06:00
4 changed files with 1351 additions and 139 deletions

View File

@@ -4,7 +4,7 @@ _winehelper_completions() {
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="--help --version --debug install installed -r -i remove-all --clear-pfx killall remove-prefix backup-prefix restore-prefix --changelog changelog"
opts="--help --version --debug install installed -r -i remove-all --clear-pfx killall remove-prefix backup-prefix restore-prefix create-prefix --changelog changelog"
wine_cmd="winecfg winereg winefile wineconsole winetricks desktop regedit explorer cmd run"
case "${prev}" in

View File

@@ -14,6 +14,7 @@ _winehelper() {
'remove-all[Удалить WineHelper и все связанные данные]'
'--clear-pfx[Очистить префикс \[имя_префикса\]]'
'killall[Убить все процессы]'
'create-prefix[Создать новый префикс]'
'remove-prefix[Удалить префикс и все связанные данные]'
'backup-prefix[Создать резерную копию префикса]'
'restore-prefix[восстановить префикс из резервной копии "путь/до/whpack"]'
@@ -55,6 +56,8 @@ _winehelper() {
remove-prefix|backup-prefix)
_get_prefixes
;;
create-prefix)
;;
restore-prefix)
_files
;;

View File

@@ -811,10 +811,48 @@ init_wine_ver () {
export WINEDIR="$WH_DIST_DIR/$WH_WINE_USE"
if [[ ! -d "$WINEDIR" ]] ; then
local wine_package="$WH_TMP_DIR/$WH_WINE_USE.tar.xz"
try_download "$CLOUD_URL/$WH_WINE_USE.tar.xz" "$wine_package" check256sum
local download_url wine_package_name wine_package check_sum_arg
WINE_METADATA_FILE="$WH_TMP_DIR/wine_metadata.json"
# Сначала пытаемся сформировать URL по старой схеме, как основной для автоустановки
local old_schema_url="$CLOUD_URL/$WH_WINE_USE.tar.xz"
# `curl -f -s -I` делает HEAD-запрос. `-f` заставляет его вернуть код ошибки при 404.
if curl -f -s -I "$old_schema_url" > /dev/null ; then
download_url="$old_schema_url"
elif [[ -f "$WINE_METADATA_FILE" ]]; then
# Если по старому URL ничего нет, ищем в метаданных
print_info "Версия '$WH_WINE_USE' не найдена на основном сервере, ищем в метаданных..."
download_url=$(jq -r --arg name "$WH_WINE_USE" '.[] | .[] | select(.name == $name) | .url' "$WINE_METADATA_FILE" | head -n 1)
else
# Если и метаданных нет, то считаем, что должен был быть старый URL
print_warning "Файл метаданных не найден. Предполагается, что версия '$WH_WINE_USE' находится на основном сервере."
download_url="$old_schema_url"
fi
# Если URL так и не был найден, выводим ошибку.
if [[ -z "$download_url" ]]; then
fatal "Не удалось найти URL для скачивания версии '$WH_WINE_USE'."
fi
wine_package_name="$(basename "$download_url")"
wine_package="$WH_TMP_DIR/$wine_package_name"
# Проверяем хэш-сумму только для файлов с нашего сервера
if [[ "$download_url" == *"$CLOUD_URL"* ]]; then
check_sum_arg="check256sum"
fi
try_download "$download_url" "$wine_package" "$check_sum_arg"
unpack "$wine_package" "$WH_DIST_DIR/"
try_remove_file "$wine_package"
# Управление структурой подкаталога Proton "files", перемещая содержимое вверх
if [[ -d "$WINEDIR/files" ]]; then
print_info "Обнаружена структура каталогов Proton, исправляем пути..."
mv "$WINEDIR"/files/* "$WINEDIR/"
rmdir "$WINEDIR/files"
fi
fi
[[ ! -f "$WINEDIR/version" ]] && echo "$WH_WINE_USE" > "$WINEDIR/version"
@@ -1465,6 +1503,343 @@ remove_prefix() {
fi
}
generate_wine_metadata () {
WINE_METADATA_FILE="$WH_TMP_DIR/wine_metadata.json"
if [[ -f "$WINE_METADATA_FILE" ]]; then
if find "$WINE_METADATA_FILE" -mmin -1440 | grep -q . ; then
print_info "Файл метаданных $WINE_METADATA_FILE обновлялся менее 24 часов назад. Пропускаем генерацию."
return 0
fi
print_info "Файл метаданных $WINE_METADATA_FILE устарел."
print_info "Начинаем обновление..."
else
print_info "Генерации метаданных..."
fi
TMP_WINE_META="$WH_TMP_DIR/wine_metadata"
local FETCH_ERROR_FLAG="$TMP_WINE_META/fetch.error"
rm -f "$FETCH_ERROR_FLAG"
mkdir -p "$TMP_WINE_META"
cleanup() {
rm -rf "$TMP_WINE_META"
}
trap cleanup EXIT
fetch_github_releases() {
local repo="$1"
local wine_metadata_file="$2"
local url="https://api.github.com/repos/$repo/releases"
if ! curl -s --fail -H "Accept: application/vnd.github.v3+json" "$url" > "$wine_metadata_file"; then
touch "$FETCH_ERROR_FLAG"
return 1
fi
if ! jq -e 'type == "array"' "$wine_metadata_file" >/dev/null 2>&1; then
try_remove_file "$wine_metadata_file"
touch "$FETCH_ERROR_FLAG"
return 1
fi
print_info "Получение данных для $repo"
}
create_wine_entries() {
local input_file="$1"
local file_extension="$2"
local exclude_patterns="$3"
jq -r --arg ext "$file_extension" '
.[] |
.assets[] |
select(.browser_download_url | test($ext)) |
{
name: (.name | gsub($ext; "")),
url: .browser_download_url
}
' "$input_file" | \
if [[ -n "$exclude_patterns" ]]; then
jq -c --arg patterns "$exclude_patterns" '
select(.name | test($patterns) | not)
'
else
jq -c '.'
fi
}
# Формат: "ключ_json;репозиторий;расширениеайлааблон_исключения"
local sources=(
"proton_ge;GloriousEggroll/proton-ge-custom;\\.tar\\.gz$;github-action"
"wine_kron4ek;Kron4ek/Wine-Builds;\\.tar\\.xz$;"
"proton_lg;Castro-Fidel/wine_builds;\\.tar\\.xz$;plugins"
"proton_cachyos;CachyOS/proton-cachyos;\\.tar\\.xz$;znver"
"proton_sarek;pythonlover02/Proton-Sarek;\\.tar\\.gz$;"
"proton_em;Etaash-mathamsetty/Proton;\\.tar\\.xz$;"
)
for source_data in "${sources[@]}"; do
(
IFS=';' read -r key repo extension exclude_pattern <<< "$source_data"
local releases_file="$TMP_WINE_META/${key}_releases.json"
local entries_file="$TMP_WINE_META/${key}.json"
fetch_github_releases "$repo" "$releases_file" || exit 1
create_wine_entries "$releases_file" "$extension" "$exclude_pattern" > "$entries_file"
) &
done
wait
if [[ -f "$FETCH_ERROR_FLAG" ]]; then
fatal "Ошибка при получении релизов. Возможно, превышен лимит запросов к API GitHub или проблема с сетью."
fi
print_ok "Все данные получены."
print_info "Создание итогового JSON файла..."
jq -n \
--slurpfile proton_ge "$TMP_WINE_META/proton_ge.json" \
--slurpfile wine_kron4ek "$TMP_WINE_META/wine_kron4ek.json" \
--slurpfile proton_lg "$TMP_WINE_META/proton_lg.json" \
--slurpfile proton_cachyos "$TMP_WINE_META/proton_cachyos.json" \
--slurpfile proton_sarek "$TMP_WINE_META/proton_sarek.json" \
--slurpfile proton_em "$TMP_WINE_META/proton_em.json" \
'{
proton_ge: $proton_ge,
wine_kron4ek: $wine_kron4ek,
proton_lg: $proton_lg,
proton_cachyos: $proton_cachyos,
proton_sarek: $proton_sarek,
proton_em: $proton_em
}' > "$WINE_METADATA_FILE"
if jq empty "$WINE_METADATA_FILE" 2>/dev/null; then
print_ok "JSON файл создан успешно: $WINE_METADATA_FILE"
else
print_error "Ошибка создания JSON файла"
exit 1
fi
}
select_wine_version() {
if ! command -v jq &> /dev/null; then
print_warning "Команда 'jq' не найдена. Невозможно отобразить список версий WINE/Proton."
print_warning "Будет использована версия по умолчанию: $WH_WINE_USE"
return
fi
generate_wine_metadata
WINE_METADATA_FILE="$WH_TMP_DIR/wine_metadata.json"
[[ ! -f "$WINE_METADATA_FILE" ]] && fatal "Файл метаданных WINE не найден."
local arch_filter_jq
if [[ "$WINEARCH" == "win64" ]]; then
print_info "Фильтруем версии для 64-битного префикса..."
# Для 64-битных префиксов показываем сборки с 'amd64', 'x86_64', 'wow64'
# или те, у которых нет явного указания на 32-битную архитектуру.
arch_filter_jq='select((.name | test("amd64|x86_64|wow64")) or (.name | test("i[3-6]86|x86(?!_64)") | not))'
else # win32
print_info "Фильтруем версии для 32-битного префикса..."
# Для 32-битных префиксов показываем только сборки с явным указанием 32-битной архитектуры.
arch_filter_jq='select(.name | test("i[3-6]86|x86(?!_64)"))'
fi
local options=()
local total_versions_found=0
# --- System ---
options+=("--- System ---")
options+=("system")
# --- Other versions from JSON ---
local group_keys
mapfile -t group_keys < <(jq -r 'keys_unsorted | .[]' "$WINE_METADATA_FILE")
for key in "${group_keys[@]}"; do
local group_versions
mapfile -t group_versions < <(jq -r --arg key "$key" '.[$key] | .[] | '"$arch_filter_jq"' | .name' "$WINE_METADATA_FILE" | sort -V -r | uniq)
if [[ ${#group_versions[@]} -gt 0 ]]; then
# Prettify the group name (e.g., "proton_ge" -> "Proton Ge")
local pretty_key
pretty_key=$(echo "$key" | tr '_' ' ' | sed -e "s/\b\(.\)/\u\1/g")
options+=("--- $pretty_key ---")
options+=("${group_versions[@]}")
((total_versions_found+=${#group_versions[@]}))
fi
done
if [[ $total_versions_found -eq 0 ]]; then
print_warning "Не найдено подходящих версий WINE/Proton для архитектуры $WINEARCH."
print_warning "Будет использована версия по умолчанию: $WH_WINE_USE"
return
fi
# --- Пользовательское меню с разделением на группы и пустыми строками ---
local selectable_options=("Отмена")
local display_groups=()
local current_group_items=()
local choice_idx=0
# Помощник для переноса текущей группы элементов в основной массив display_groups
flush_current_group() {
if ((${#current_group_items[@]} > 0)); then
# Объединяйте элементы с помощью уникального разделителя для последующего разделения
display_groups+=("$(IFS='@@@'; echo "${current_group_items[*]}")")
current_group_items=()
fi
}
current_group_items+=(" 0) Отмена создания префикса")
# Обработка массива основных параметров для создания групп
for opt in "${options[@]}"; do
if [[ "$opt" == "---"* ]]; then
flush_current_group
display_groups+=("$opt") # Добавьте заголовок как отдельный элемент
else
((choice_idx++))
current_group_items+=(" ${choice_idx}) $opt")
selectable_options+=("$opt")
fi
done
flush_current_group # Очистка последней группы
print_info "Выберите версию WINE/Proton для $WINEARCH префикса:"
# Показывать группы одну за другой
local first_block=true
for group_data in "${display_groups[@]}"; do
if [[ "$group_data" == "---"* ]]; then
if [[ "$first_block" = false ]]; then
echo
fi
echo "$group_data"
else
# Это блок элементов для печати в столбцах
local items_to_print=()
IFS='@@@' read -r -a items_to_print <<< "$group_data"
local num_items=${#items_to_print[@]}
local term_width=${COLUMNS:-80}
local max_len=0
for item in "${items_to_print[@]}"; do
(( ${#item} > max_len )) && max_len=${#item}
done
((max_len+=2))
local num_cols=$(( term_width / max_len ))
(( num_cols = num_cols > 0 ? num_cols : 1 ))
local num_rows=$(( (num_items + num_cols - 1) / num_cols ))
for ((i=0; i<num_rows; i++)); do
for ((j=0; j<num_cols; j++)); do
local index=$(( i + j * num_rows ))
(( index < num_items )) && printf "%-*s" "$max_len" "${items_to_print[index]}"
done
echo
done
fi
first_block=false
done
while true; do
local max_choice=$(( ${#selectable_options[@]} - 1 ))
read -p "Введите номер (0-$max_choice): " user_choice
if [[ "$user_choice" =~ ^[0-9]+$ ]] && (( user_choice >= 0 && user_choice <= max_choice )); then
if [[ "$user_choice" == "0" ]]; then
print_info "Создание префикса отменено."
exit 0
fi
local selected_opt="${selectable_options[$user_choice]}"
export WH_WINE_USE="$selected_opt"
break
else
print_error "Неверный выбор. Введите число от 0 до $max_choice."
fi
done
}
create_prefix() {
print_info "Существующие префиксы:"
local prefixes=()
for prefix in "$WH_PREFIXES_DIR"/*; do
if [[ -d "$prefix" ]] ; then
prefixes+=("$(basename "$prefix")")
echo " - $(basename "$prefix")"
fi
done
if [[ ${#prefixes[@]} -eq 0 ]]; then
print_info "Нет существующих префиксов."
fi
echo
read -p "Введите имя для нового префикса или 0 для отмены (по умолчанию: default): " prefix_name
if [[ "$prefix_name" == "0" ]] ; then
print_info "Создание префикса отменено."
exit 0
fi
prefix_name=${prefix_name:-default}
if [[ ! "$prefix_name" =~ ^[a-zA-Z0-9_.-]+$ ]] ; then
fatal "Имя префикса может содержать только латинские буквы, цифры, точки, дефисы и подчеркивания"
fi
if [[ -d "$WH_PREFIXES_DIR/$prefix_name" ]] ; then
fatal "Префикс с именем '$prefix_name' уже существует. Создание отменено."
fi
print_info "Создается префикс с именем: \"$prefix_name\""
print_info "Выберите разрядность префикса:"
echo " 0) Отмена создания префикса"
echo " 1) 32-bit"
echo " 2) 64-bit"
echo
local arch_choice
read -p "Ваш выбор [0-2] (по умолчанию 1): " arch_choice
case "${arch_choice:-1}" in
0) print_info "Создание префикса отменено." ; exit 0 ;;
1) export WINEARCH="win32" ;;
2) export WINEARCH="win64" ;;
*) fatal "Неверный выбор. Операция отменена." ;;
esac
select_wine_version
print_info "Выберите тип создаваемого префикса:"
echo " 0) Отмена создания префикса"
echo " 1) Чистый префикс (без библиотек)"
echo " 2) С рекомендуемыми библиотеками (по умолчанию)"
echo
local pfx_type_choice
read -p "Ваш выбор [0-2] (по умолчанию 1): " pfx_type_choice
case "${pfx_type_choice:-1}" in
0) print_info "Создание префикса отменено." ; exit 0 ;;
1) export BASE_PFX="none" ;;
2) ;; # Оставляем BASE_PFX пустым, чтобы init_wineprefix использовал значение по умолчанию
*) fatal "Неверный выбор. Операция отменена." ;;
esac
export WINEPREFIX="$WH_PREFIXES_DIR/$prefix_name"
if ! init_wine_ver || ! init_wineprefix; then
fatal "Ошибка инициализации префикса."
fi
print_ok "Префикс '$prefix_name' (${WINEARCH}) успешно создан."
}
remove_winehelper () {
local answer
if [[ $1 =~ --force|-y ]] ; then
@@ -1748,6 +2123,7 @@ wh_info () {
installed список установленных программ
run [программа] запуск программы (отладка)
remove-all удалить WineHelper и все связанные данные
create-prefix создать префикс
remove-prefix [имя_префикса] удалить префикс и все связанные данные
backup-prefix [имя_префикса] создать резервную копию префикса
restore-prefix \"путь/до/whpack\" восстановить префикс из резервной копии
@@ -1796,8 +2172,11 @@ case "$arg1" in
backup-prefix) backup_prefix "$@" ;;
restore-prefix) restore_prefix "$@" ;;
remove-all) remove_winehelper "$@" ;;
create-prefix) create_prefix "$@" ;;
remove-prefix) remove_prefix "$@" ;;
create-base-pfx) create_base_pfx "$@" ;;
generate-db) generate_wine_metadata "$@" ;;
init-prefix) prepair_wine ; wait_wineserver ;;
*)
if [[ -f "$arg1" ]] ; then
WIN_FILE_EXEC="$(readlink -f "$arg1")"

File diff suppressed because it is too large Load Diff