mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 22:46:04 +00:00
v2.4.0 — internationalization (EN/RU) + custom git templates
- i18n engine (lib/i18n.sh, lib/lang/en.sh, lib/lang/ru.sh)
- first-run language picker, persisted to .language + config.json
- install.sh, common.sh, backup.sh, templates_catalog.sh wired through t()/tf()
- backup.sh preserves .language marker and records language in metadata.json
- custom git template feature (first item in pro template picker)
* validates HTTPS URLs, rejects shell metachars
* 100MB size guard, 90s clone timeout
* auto-detects index.html in dist/public/build/_site/site/docs/out/www
- bot v2.4.0: i18n.py + lang/{en,ru}.json, /lang command, language toggle button
- bot: custom git template via text input with waiter gating
This commit is contained in:
@@ -1,20 +1,29 @@
|
||||
#!/bin/bash
|
||||
# GoTelegram v2.2 — Каталог шаблонов сайтов
|
||||
# Выбор из ~200 шаблонов, превью-ссылки, скачивание через git sparse-checkout
|
||||
# GoTelegram v2.4 — website templates catalog
|
||||
# Pick from ~1800 templates, preview links, git sparse-checkout downloads,
|
||||
# + custom git URL templates (user-supplied public repos)
|
||||
|
||||
CATALOG_FILE="$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")/templates_catalog.json"
|
||||
TEMPLATES_CACHE="/tmp/gotelegram_templates"
|
||||
|
||||
# ── Загрузка каталога ────────────────────────────────────────────────────────
|
||||
# Custom git template limits
|
||||
CUSTOM_GIT_MAX_SIZE_MB=100
|
||||
CUSTOM_GIT_CLONE_TIMEOUT=90
|
||||
|
||||
# ── Catalog loading ────────────────────────────────────────────────────
|
||||
load_catalog() {
|
||||
if [ ! -f "$CATALOG_FILE" ]; then
|
||||
log_error "Каталог шаблонов не найден: $CATALOG_FILE"
|
||||
if type tf &>/dev/null; then
|
||||
log_error "$(tf templates_catalog_not_found "$CATALOG_FILE")"
|
||||
else
|
||||
log_error "Templates catalog not found: $CATALOG_FILE"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Категории ────────────────────────────────────────────────────────────────
|
||||
# ── Categories ─────────────────────────────────────────────────────────
|
||||
get_categories() {
|
||||
jq -r '.categories[] | "\(.id)|\(.name)|\(.icon)|\(.templates | length)"' "$CATALOG_FILE" 2>/dev/null
|
||||
}
|
||||
@@ -24,13 +33,13 @@ get_category_name() {
|
||||
jq -r ".categories[] | select(.id == \"$cat_id\") | .name" "$CATALOG_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# ── Шаблоны по категории ────────────────────────────────────────────────────
|
||||
# ── Templates in a category ────────────────────────────────────────────
|
||||
get_templates_by_category() {
|
||||
local cat_id="$1"
|
||||
jq -r ".categories[] | select(.id == \"$cat_id\") | .templates[] | \"\(.id)|\(.name)|\(.source)|\(.preview_url)\"" "$CATALOG_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# ── Информация о шаблоне ────────────────────────────────────────────────────
|
||||
# ── Template info ──────────────────────────────────────────────────────
|
||||
get_template_info() {
|
||||
local tpl_id="$1"
|
||||
jq ".categories[].templates[] | select(.id == \"$tpl_id\")" "$CATALOG_FILE" 2>/dev/null
|
||||
@@ -42,16 +51,19 @@ get_template_field() {
|
||||
jq -r ".categories[].templates[] | select(.id == \"$tpl_id\") | .$field" "$CATALOG_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# ── Интерактивный выбор категории ────────────────────────────────────────────
|
||||
# ── Interactive category picker (returns category id or special __custom_git__/__random__) ──
|
||||
select_category() {
|
||||
load_catalog || return 1
|
||||
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}📂 Категории шаблонов сайтов:${NC}" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t templates_categories)${NC}" >&2
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..55})${NC}" >&2
|
||||
|
||||
# First item: custom git URL template
|
||||
printf " ${CYAN}%2d)${NC} ${GREEN}%s${NC}\n" 1 "$(t templates_custom_git)" >&2
|
||||
|
||||
local cats=()
|
||||
local i=1
|
||||
local i=2
|
||||
while IFS='|' read -r id name icon count; do
|
||||
[ "$count" -eq 0 ] && continue
|
||||
local emoji
|
||||
@@ -67,40 +79,52 @@ select_category() {
|
||||
chart-bar) emoji="🔧" ;;
|
||||
*) emoji="📄" ;;
|
||||
esac
|
||||
printf " ${CYAN}%2d)${NC} ${emoji} %-30s ${DIM}(%d шаблонов)${NC}\n" "$i" "$name" "$count" >&2
|
||||
printf " ${CYAN}%2d)${NC} ${emoji} %-30s ${DIM}$(tf templates_count_fmt "$count")${NC}\n" "$i" "$name" >&2
|
||||
cats+=("$id")
|
||||
((i++))
|
||||
done < <(get_categories)
|
||||
|
||||
printf " ${CYAN}%2d)${NC} 🎲 Случайный шаблон\n" "$i" >&2
|
||||
printf " ${CYAN}%2d)${NC} %s\n" "$i" "$(t templates_random)" >&2
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..55})${NC}" >&2
|
||||
echo -ne " ${WHITE}Выбор:${NC} " >&2
|
||||
echo -ne " ${WHITE}$(t choose):${NC} " >&2
|
||||
read -r choice
|
||||
|
||||
# Случайный
|
||||
if [ "$choice" -eq "$i" ] 2>/dev/null; then
|
||||
if ! [[ "$choice" =~ ^[0-9]+$ ]]; then
|
||||
log_error "$(t invalid_choice)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Custom git URL
|
||||
if [ "$choice" -eq 1 ]; then
|
||||
echo "__custom_git__"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Random
|
||||
if [ "$choice" -eq "$i" ]; then
|
||||
local random_cat="${cats[$((RANDOM % ${#cats[@]}))]}"
|
||||
echo "$random_cat"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -lt "$i" ]; then
|
||||
echo "${cats[$((choice-1))]}"
|
||||
# Regular category (offset by 1 because item 1 is custom git)
|
||||
if [ "$choice" -ge 2 ] && [ "$choice" -lt "$i" ]; then
|
||||
echo "${cats[$((choice-2))]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_error "Неверный выбор"
|
||||
log_error "$(t invalid_choice)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Интерактивный выбор шаблона ──────────────────────────────────────────────
|
||||
# ── Interactive template picker ────────────────────────────────────────
|
||||
select_template() {
|
||||
local cat_id="$1"
|
||||
local cat_name
|
||||
cat_name=$(get_category_name "$cat_id")
|
||||
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}📋 $cat_name — доступные шаблоны:${NC}" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(tf templates_list "$cat_name")${NC}" >&2
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..60})${NC}" >&2
|
||||
|
||||
local tpls=()
|
||||
@@ -112,29 +136,29 @@ select_template() {
|
||||
done < <(get_templates_by_category "$cat_id")
|
||||
|
||||
if [ ${#tpls[@]} -eq 0 ]; then
|
||||
log_info "В этой категории нет шаблонов"
|
||||
log_info "$(t templates_cat_empty)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..60})${NC}" >&2
|
||||
echo -ne " ${WHITE}Выбор (1-$((i-1))):${NC} " >&2
|
||||
echo -ne " ${WHITE}$(t choose) (1-$((i-1))):${NC} " >&2
|
||||
read -r choice
|
||||
|
||||
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -lt "$i" ]; then
|
||||
local selected_id="${tpls[$((choice-1))]}"
|
||||
|
||||
# Показываем превью
|
||||
show_template_preview "$selected_id"
|
||||
# Show preview
|
||||
show_template_preview "$selected_id" || return 1
|
||||
|
||||
echo "$selected_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_error "Неверный выбор"
|
||||
log_error "$(t invalid_choice)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Показ превью шаблона ────────────────────────────────────────────────────
|
||||
# ── Template preview ───────────────────────────────────────────────────
|
||||
show_template_preview() {
|
||||
local tpl_id="$1"
|
||||
local info
|
||||
@@ -148,36 +172,36 @@ show_template_preview() {
|
||||
description=$(echo "$info" | jq -r '.description // "—"')
|
||||
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}🔍 Превью шаблона:${NC}" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t templates_preview_title)${NC}" >&2
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..55})${NC}" >&2
|
||||
echo -e " ${WHITE}Название:${NC} $name" >&2
|
||||
echo -e " ${WHITE}Источник:${NC} $source" >&2
|
||||
echo -e " ${WHITE}Описание:${NC} $description" >&2
|
||||
echo -e " ${WHITE}$(t templates_name)${NC} $name" >&2
|
||||
echo -e " ${WHITE}$(t templates_source)${NC} $source" >&2
|
||||
echo -e " ${WHITE}$(t templates_description)${NC} $description" >&2
|
||||
|
||||
if [ -n "$preview_url" ]; then
|
||||
echo "" >&2
|
||||
echo -e " ${GREEN}👁 Превью:${NC} ${CYAN}${preview_url}${NC}" >&2
|
||||
echo -e " ${DIM}Откройте ссылку в браузере для просмотра шаблона${NC}" >&2
|
||||
echo -e " ${GREEN}$(t templates_preview)${NC} ${CYAN}${preview_url}${NC}" >&2
|
||||
echo -e " ${DIM}$(t templates_preview_hint)${NC}" >&2
|
||||
fi
|
||||
|
||||
if [ -n "$repo_url" ]; then
|
||||
echo -e " ${DIM}📦 Репо: ${repo_url}${NC}" >&2
|
||||
echo -e " ${DIM}$(t templates_repo) ${repo_url}${NC}" >&2
|
||||
fi
|
||||
|
||||
# Благодарность автору
|
||||
# Thanks
|
||||
echo "" >&2
|
||||
echo -e " ${MAGENTA}💜 Спасибо авторам ${source} за открытый код!${NC}" >&2
|
||||
echo -e " ${MAGENTA}$(tf templates_thanks "$source")${NC}" >&2
|
||||
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..55})${NC}" >&2
|
||||
echo "" >&2
|
||||
|
||||
if ! confirm "Установить этот шаблон?"; then
|
||||
if ! confirm "$(t templates_install_this)"; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Скачивание шаблона ───────────────────────────────────────────────────────
|
||||
# ── Template download (from catalog) ───────────────────────────────────
|
||||
download_template() {
|
||||
local tpl_id="$1"
|
||||
local output_dir="${2:-$TEMPLATES_CACHE}"
|
||||
@@ -194,9 +218,9 @@ download_template() {
|
||||
rm -rf "$clone_dir"
|
||||
mkdir -p "$clone_dir"
|
||||
|
||||
log_info "Скачивание шаблона \"$name\"..."
|
||||
log_info "$(tf templates_downloading "$name")"
|
||||
|
||||
# Для HTML5 UP — отдельный репо с папками
|
||||
# HTML5 UP — one repo with folders
|
||||
if [ "$source" = "html5up" ]; then
|
||||
local tmp_clone="/tmp/html5up_clone_$$"
|
||||
rm -rf "$tmp_clone"
|
||||
@@ -204,7 +228,7 @@ download_template() {
|
||||
# Sparse checkout
|
||||
git clone --depth 1 --filter=blob:none --sparse "$repo_url" "$tmp_clone" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
# Fallback: полный clone
|
||||
# Fallback: full clone
|
||||
git clone --depth 1 "$repo_url" "$tmp_clone" 2>/dev/null
|
||||
fi
|
||||
|
||||
@@ -217,7 +241,7 @@ download_template() {
|
||||
fi
|
||||
rm -rf "$tmp_clone"
|
||||
|
||||
# Для learning-zone — один большой репо
|
||||
# learning-zone — one big repo
|
||||
elif [ "$source" = "learning-zone" ]; then
|
||||
local tmp_clone="/tmp/lz_clone_$$"
|
||||
rm -rf "$tmp_clone"
|
||||
@@ -236,14 +260,14 @@ download_template() {
|
||||
fi
|
||||
rm -rf "$tmp_clone"
|
||||
|
||||
# Для StartBootstrap — каждый шаблон в своём репо
|
||||
# StartBootstrap — each template in its own repo
|
||||
elif [ "$source" = "startbootstrap" ]; then
|
||||
local sb_tmp="/tmp/sb_clone_$$"
|
||||
rm -rf "$sb_tmp"
|
||||
git clone --depth 1 "$repo_url" "$sb_tmp" 2>/dev/null
|
||||
if [ -d "$sb_tmp" ]; then
|
||||
rm -rf "$sb_tmp/.git"
|
||||
# StartBootstrap хранит production-файлы в dist/
|
||||
# StartBootstrap stores production files in dist/
|
||||
if [ -f "$sb_tmp/dist/index.html" ]; then
|
||||
cp -r "$sb_tmp/dist/"* "$clone_dir/"
|
||||
elif [ -f "$sb_tmp/index.html" ]; then
|
||||
@@ -260,7 +284,7 @@ download_template() {
|
||||
fi
|
||||
rm -rf "$sb_tmp"
|
||||
|
||||
# Для ThemeWagon / ColorlibHQ — каждый шаблон в отдельном репо
|
||||
# ThemeWagon / ColorlibHQ — each template in its own repo
|
||||
elif [ "$source" = "themewagon" ] || [ "$source" = "colorlib" ]; then
|
||||
local tw_tmp="/tmp/tw_clone_$$"
|
||||
rm -rf "$tw_tmp"
|
||||
@@ -283,7 +307,7 @@ download_template() {
|
||||
fi
|
||||
rm -rf "$tw_tmp"
|
||||
|
||||
# Для dawidolko — один большой репо с папками (как learning-zone)
|
||||
# dawidolko — one big repo with folders (similar to learning-zone)
|
||||
elif [ "$source" = "dawidolko" ]; then
|
||||
local tmp_clone="/tmp/dw_clone_$$"
|
||||
rm -rf "$tmp_clone"
|
||||
@@ -301,13 +325,13 @@ download_template() {
|
||||
rm -rf "$tmp_clone"
|
||||
fi
|
||||
|
||||
# Проверяем результат
|
||||
# Check result
|
||||
if [ -f "$clone_dir/index.html" ]; then
|
||||
log_success "Шаблон \"$name\" скачан"
|
||||
log_success "$(tf templates_downloaded "$name")"
|
||||
echo "$clone_dir"
|
||||
return 0
|
||||
else
|
||||
# fallback: ищем index.html в подпапках (нестандартная структура)
|
||||
# fallback: find index.html in subfolders (non-standard structure)
|
||||
local fallback_index
|
||||
fallback_index=$(find "$clone_dir" -name "index.html" -type f 2>/dev/null | head -1)
|
||||
if [ -n "$fallback_index" ]; then
|
||||
@@ -315,33 +339,253 @@ download_template() {
|
||||
fallback_dir=$(dirname "$fallback_index")
|
||||
if [ "$fallback_dir" != "$clone_dir" ]; then
|
||||
cp -r "$fallback_dir/"* "$clone_dir/"
|
||||
log_success "Шаблон \"$name\" скачан (из подпапки)"
|
||||
log_success "$(tf templates_downloaded_subfolder "$name")"
|
||||
echo "$clone_dir"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
log_error "Шаблон не содержит index.html"
|
||||
log_dim "Путь: $clone_dir"
|
||||
log_error "$(t templates_no_index)"
|
||||
log_dim "$(tf templates_path "$clone_dir")"
|
||||
ls -la "$clone_dir" 2>/dev/null >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Полный интерактивный процесс выбора ──────────────────────────────────────
|
||||
# ── Custom git URL helpers ─────────────────────────────────────────────
|
||||
|
||||
# Validate a user-supplied git URL
|
||||
# Accepts: https://host/path[.git][@branch]
|
||||
# Rejects: ssh://, git://, file://, absolute file paths
|
||||
_validate_custom_git_url() {
|
||||
local url="$1"
|
||||
# Must begin with https://
|
||||
[[ "$url" =~ ^https:// ]] || return 1
|
||||
# Reject shell metacharacters that could be exploited
|
||||
[[ "$url" =~ [[:space:]\;\`\$\(\)\<\>\|\\\&] ]] && return 1
|
||||
# Reasonable length limit
|
||||
[ "${#url}" -gt 512 ] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parse URL → sets CUSTOM_GIT_CLEAN and CUSTOM_GIT_BRANCH globals
|
||||
_parse_custom_git_url() {
|
||||
local url="$1"
|
||||
CUSTOM_GIT_CLEAN=""
|
||||
CUSTOM_GIT_BRANCH=""
|
||||
# Handle trailing @branch
|
||||
if [[ "$url" =~ ^(https://[^@]+)@([A-Za-z0-9._/-]+)$ ]]; then
|
||||
CUSTOM_GIT_CLEAN="${BASH_REMATCH[1]}"
|
||||
CUSTOM_GIT_BRANCH="${BASH_REMATCH[2]}"
|
||||
else
|
||||
CUSTOM_GIT_CLEAN="$url"
|
||||
fi
|
||||
# Strip trailing slash
|
||||
CUSTOM_GIT_CLEAN="${CUSTOM_GIT_CLEAN%/}"
|
||||
# Append .git if missing (works better with git clone on some hosts)
|
||||
if [[ ! "$CUSTOM_GIT_CLEAN" =~ \.git$ ]]; then
|
||||
CUSTOM_GIT_CLEAN="${CUSTOM_GIT_CLEAN}.git"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check repo size (in MB) by inspecting cloned directory
|
||||
_clone_dir_size_mb() {
|
||||
local dir="$1"
|
||||
du -sm "$dir" 2>/dev/null | awk '{print $1}'
|
||||
}
|
||||
|
||||
# ── Show detailed help for custom git template ─────────────────────────
|
||||
show_custom_git_help() {
|
||||
local line
|
||||
line=$(printf '─%.0s' $(seq 1 60))
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${GREEN}$(t custom_git_title)${NC}" >&2
|
||||
echo -e " ${DIM}${line}${NC}" >&2
|
||||
echo -e " $(t custom_git_help_1)" >&2
|
||||
echo -e " $(t custom_git_help_2)" >&2
|
||||
echo -e " $(t custom_git_help_3)" >&2
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t custom_git_formats)${NC}" >&2
|
||||
echo -e " ${CYAN}$(t custom_git_fmt_github)${NC}" >&2
|
||||
echo -e " ${CYAN}$(t custom_git_fmt_gitlab)${NC}" >&2
|
||||
echo -e " ${CYAN}$(t custom_git_fmt_gitext)${NC}" >&2
|
||||
echo -e " ${CYAN}$(t custom_git_fmt_branch)${NC}" >&2
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t custom_git_auto_detect)${NC}" >&2
|
||||
echo -e " $(t custom_git_auto_1)" >&2
|
||||
echo -e " $(t custom_git_auto_2)" >&2
|
||||
echo -e " $(t custom_git_auto_3)" >&2
|
||||
echo -e " $(t custom_git_auto_4)" >&2
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t custom_git_requirements)${NC}" >&2
|
||||
echo -e " ${YELLOW}$(t custom_git_req_1)${NC}" >&2
|
||||
echo -e " ${YELLOW}$(t custom_git_req_2)${NC}" >&2
|
||||
echo -e " ${YELLOW}$(t custom_git_req_3)${NC}" >&2
|
||||
echo -e " ${YELLOW}$(t custom_git_req_4)${NC}" >&2
|
||||
echo "" >&2
|
||||
echo -e " ${BOLD}${WHITE}$(t custom_git_examples)${NC}" >&2
|
||||
echo -e " ${DIM}$(t custom_git_ex_1)${NC}" >&2
|
||||
echo -e " ${DIM}$(t custom_git_ex_2)${NC}" >&2
|
||||
echo -e " ${DIM}${line}${NC}" >&2
|
||||
echo "" >&2
|
||||
}
|
||||
|
||||
# ── Download a custom git template ─────────────────────────────────────
|
||||
# Prompts user for a URL (unless passed), clones, detects index.html,
|
||||
# copies result into $output_dir/custom_<hash>, echoes the final path.
|
||||
download_custom_git_template() {
|
||||
local url="${1:-}"
|
||||
local output_dir="${2:-$TEMPLATES_CACHE}"
|
||||
|
||||
show_custom_git_help
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
echo -ne " ${WHITE}$(t custom_git_enter_url)${NC} " >&2
|
||||
read -r url
|
||||
url=$(echo "$url" | tr -d '\r\n[:space:]')
|
||||
fi
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
log_error "$(t custom_git_empty)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _validate_custom_git_url "$url"; then
|
||||
log_error "$(t custom_git_bad_url)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_parse_custom_git_url "$url"
|
||||
local clean_url="$CUSTOM_GIT_CLEAN"
|
||||
local branch="$CUSTOM_GIT_BRANCH"
|
||||
|
||||
# Stable-ish directory name from a hash of the original URL
|
||||
local hash
|
||||
hash=$(echo -n "$url" | md5sum 2>/dev/null | awk '{print $1}' | head -c 10)
|
||||
[ -z "$hash" ] && hash=$(date +%s)
|
||||
local tpl_id="custom_${hash}"
|
||||
local clone_dir="$output_dir/${tpl_id}"
|
||||
local tmp_clone="/tmp/custom_git_clone_$$"
|
||||
|
||||
rm -rf "$clone_dir" "$tmp_clone"
|
||||
mkdir -p "$clone_dir"
|
||||
|
||||
log_info "$(t custom_git_cloning)"
|
||||
|
||||
# Clone with timeout so a hung server can't freeze the installer
|
||||
local clone_status=0
|
||||
local git_args=("clone" "--depth" "1")
|
||||
[ -n "$branch" ] && git_args+=("--branch" "$branch")
|
||||
git_args+=("$clean_url" "$tmp_clone")
|
||||
|
||||
if command -v timeout &>/dev/null; then
|
||||
timeout "$CUSTOM_GIT_CLONE_TIMEOUT" git "${git_args[@]}" 2>/tmp/custom_git_err_$$
|
||||
clone_status=$?
|
||||
else
|
||||
git "${git_args[@]}" 2>/tmp/custom_git_err_$$
|
||||
clone_status=$?
|
||||
fi
|
||||
|
||||
if [ $clone_status -ne 0 ] || [ ! -d "$tmp_clone" ]; then
|
||||
local err_msg
|
||||
err_msg=$(head -3 "/tmp/custom_git_err_$$" 2>/dev/null | tr '\n' ' ')
|
||||
rm -f "/tmp/custom_git_err_$$"
|
||||
rm -rf "$tmp_clone" "$clone_dir"
|
||||
log_error "$(tf custom_git_clone_failed "${err_msg:-$clone_status}")"
|
||||
return 1
|
||||
fi
|
||||
rm -f "/tmp/custom_git_err_$$"
|
||||
|
||||
# Drop .git before measuring size (we only care about payload)
|
||||
rm -rf "$tmp_clone/.git"
|
||||
|
||||
# Size guard
|
||||
local size_mb
|
||||
size_mb=$(_clone_dir_size_mb "$tmp_clone")
|
||||
if [ -n "$size_mb" ] && [ "$size_mb" -gt "$CUSTOM_GIT_MAX_SIZE_MB" ]; then
|
||||
rm -rf "$tmp_clone" "$clone_dir"
|
||||
log_error "$(tf custom_git_too_big "${size_mb}MB")"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "$(t custom_git_scanning)"
|
||||
|
||||
# Priority list of common static-site output folders
|
||||
local candidates=("" "dist" "public" "build" "_site" "site" "docs" "out" "www")
|
||||
local found_dir=""
|
||||
for sub in "${candidates[@]}"; do
|
||||
local try_dir="$tmp_clone"
|
||||
[ -n "$sub" ] && try_dir="$tmp_clone/$sub"
|
||||
if [ -f "$try_dir/index.html" ]; then
|
||||
found_dir="$try_dir"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Fallback: search for any index.html in the repo (shallow depth first)
|
||||
if [ -z "$found_dir" ]; then
|
||||
local fallback_index
|
||||
fallback_index=$(find "$tmp_clone" -maxdepth 4 -name "index.html" -type f 2>/dev/null | head -1)
|
||||
if [ -n "$fallback_index" ]; then
|
||||
found_dir=$(dirname "$fallback_index")
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$found_dir" ] || [ ! -f "$found_dir/index.html" ]; then
|
||||
rm -rf "$tmp_clone" "$clone_dir"
|
||||
log_error "$(t custom_git_no_index)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Show what we found (human-friendly relative path)
|
||||
local rel_path="${found_dir#$tmp_clone}"
|
||||
rel_path="${rel_path#/}"
|
||||
[ -z "$rel_path" ] && rel_path="(root)"
|
||||
log_dim "$(tf custom_git_found_at "$rel_path")"
|
||||
|
||||
# Copy the detected directory as the new template
|
||||
cp -r "$found_dir"/* "$clone_dir/" 2>/dev/null
|
||||
cp -r "$found_dir"/.[!.]* "$clone_dir/" 2>/dev/null
|
||||
|
||||
rm -rf "$tmp_clone"
|
||||
|
||||
if [ ! -f "$clone_dir/index.html" ]; then
|
||||
rm -rf "$clone_dir"
|
||||
log_error "$(t custom_git_no_index)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Remember the URL so users can see what template they used
|
||||
echo "$url" > "$clone_dir/.custom_git_source" 2>/dev/null
|
||||
|
||||
log_success "$(tf custom_git_installed "$url")"
|
||||
echo "$clone_dir"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Full interactive template selection ───────────────────────────────
|
||||
interactive_template_selection() {
|
||||
load_catalog || return 1
|
||||
|
||||
# Выбор категории
|
||||
# Category selection
|
||||
local cat_id
|
||||
cat_id=$(select_category)
|
||||
[ $? -ne 0 ] && return 1
|
||||
|
||||
# Выбор шаблона
|
||||
# Custom git URL path
|
||||
if [ "$cat_id" = "__custom_git__" ]; then
|
||||
local template_dir
|
||||
template_dir=$(download_custom_git_template)
|
||||
[ $? -ne 0 ] && return 1
|
||||
echo "$template_dir"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Template selection
|
||||
local tpl_id
|
||||
tpl_id=$(select_template "$cat_id")
|
||||
[ $? -ne 0 ] && return 1
|
||||
|
||||
# Скачивание
|
||||
# Download
|
||||
local template_dir
|
||||
template_dir=$(download_template "$tpl_id")
|
||||
[ $? -ne 0 ] && return 1
|
||||
|
||||
Reference in New Issue
Block a user