Add CI/CD
This commit is contained in:
parent
1f55dfc055
commit
8ec21b41fa
3 changed files with 1929 additions and 0 deletions
663
pitoolsv2.sh
Executable file
663
pitoolsv2.sh
Executable file
|
|
@ -0,0 +1,663 @@
|
|||
#!/bin/bash
|
||||
# PITOOLSV2 — простой SSH-оркестратор:
|
||||
# pinstall — создать файл/директорию с правами
|
||||
# piproject — собрать проект по .prj
|
||||
# deploypi — деплой одного .prj на один хост
|
||||
# multideploypi — деплой нескольких блоков MLT+PRJ/DR/FL из одного .prj
|
||||
|
||||
# ------------------------- pinstall --------------------------
|
||||
# pinstall [-h|--here] [-u|--user] [-s|--script] FILE...
|
||||
# Создаёт файлы/каталоги с умными правами и владельцем.
|
||||
pinstall() {
|
||||
local mode=644 owner="$USER" group create_dir=0
|
||||
|
||||
# Получаем группу текущего пользователя
|
||||
group="$(id -gn "$USER" 2>/dev/null || id -gn 2>/dev/null || whoami 2>/dev/null || echo "$USER")"
|
||||
|
||||
# Парсим флаги
|
||||
while [ $# -gt 0 ] && [ "${1#-}" != "$1" ]; do
|
||||
case "$1" in
|
||||
-h|--here)
|
||||
# Наследуем права и владельца от текущей директории
|
||||
if [ -d . ]; then
|
||||
mode="$(stat -c '%a' . 2>/dev/null || echo 644)"
|
||||
owner="$(stat -c '%U' . 2>/dev/null || echo "$USER")"
|
||||
group="$(stat -c '%G' . 2>/dev/null || echo "$group")"
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
-u|--user)
|
||||
# Стандартные права для пользовательских файлов
|
||||
mode=644
|
||||
owner="$USER"
|
||||
group="$(id -gn "$USER" 2>/dev/null || id -gn 2>/dev/null || whoami 2>/dev/null || echo "$USER")"
|
||||
shift
|
||||
;;
|
||||
-s|--script)
|
||||
# Принудительно исполняемые права
|
||||
mode=755
|
||||
shift
|
||||
;;
|
||||
-d|--directory)
|
||||
# Создавать директорию
|
||||
create_dir=1
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
# Конец флагов
|
||||
shift
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
echo "Использование: pinstall [-h|--here] [-u|--user] [-s|--script] [-d|--directory] ФАЙЛ..." >&2
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
# Не флаг - выходим из цикла
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Проверка: хотя бы один файл должен быть указан
|
||||
[ $# -eq 0 ] && {
|
||||
echo "Использование: pinstall [-h|--here] [-u|--user] [-s|--script] [-d|--directory] ФАЙЛ..." >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Счётчик созданных объектов
|
||||
local created=0
|
||||
|
||||
# Обрабатываем все переданные файлы
|
||||
for f in "$@"; do
|
||||
local eff_mode="$mode"
|
||||
|
||||
# Автоматически делаем скрипты исполняемыми
|
||||
case "$(basename "$f")" in
|
||||
*.sh|*.py|*.pl|*.rb|*.go|*.js|Makefile|makefile|*.mk)
|
||||
eff_mode=755
|
||||
;;
|
||||
esac
|
||||
|
||||
# Убираем возможный / в конце для проверки существования
|
||||
local check_path="$f"
|
||||
[[ "$check_path" == */ ]] && check_path="${check_path%/}"
|
||||
|
||||
# Проверяем, существует ли уже
|
||||
if [ -e "$check_path" ]; then
|
||||
# Существует — обновляем права если нужно
|
||||
if [ -d "$check_path" ]; then
|
||||
# Это директория
|
||||
if [ "$eff_mode" != "644" ] && [ "$eff_mode" != "755" ]; then
|
||||
chmod "$eff_mode" "$check_path" 2>/dev/null && \
|
||||
echo " 🔧 Обновлены права директории: $f" >&2
|
||||
fi
|
||||
else
|
||||
# Это файл
|
||||
if [ "$eff_mode" != "644" ]; then
|
||||
chmod "$eff_mode" "$check_path" 2>/dev/null && \
|
||||
echo " 🔧 Обновлены права файла: $f" >&2
|
||||
fi
|
||||
fi
|
||||
continue # Уже существует, пропускаем создание
|
||||
fi
|
||||
|
||||
# Определяем, создавать директорию или файл
|
||||
local is_dir="$create_dir"
|
||||
[ "$is_dir" -eq 0 ] && [[ "$f" == */ ]] && is_dir=1
|
||||
|
||||
if [ "$is_dir" -eq 1 ]; then
|
||||
# Создаём директорию
|
||||
if install -d -m "$eff_mode" -o "$owner" -g "$group" "$f" 2>/dev/null; then
|
||||
echo " 📂 Создана директория: ${f%/}" >&2
|
||||
created=$((created + 1))
|
||||
else
|
||||
echo " ⚠️ Не удалось создать директорию: $f" >&2
|
||||
fi
|
||||
else
|
||||
# Создаём файл
|
||||
if install -D -m "$eff_mode" -o "$owner" -g "$group" \
|
||||
--backup=numbered /dev/null "$f" 2>/dev/null; then
|
||||
# Проверяем, был ли авто-режим 755
|
||||
case "$(basename "$f")" in
|
||||
*.sh|*.py|*.pl|*.rb|*.go|*.js|Makefile|makefile|*.mk)
|
||||
echo " 🔥 AUTO 755 → $f" >&2
|
||||
;;
|
||||
*)
|
||||
echo " 📄 Создан файл: $f" >&2
|
||||
;;
|
||||
esac
|
||||
created=$((created + 1))
|
||||
else
|
||||
echo " ⚠️ Не удалось создать файл: $f" >&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
[ "$created" -gt 0 ] && echo "✅ Создано объектов: $created" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------ piproject --------------------------
|
||||
# piproject SPEC.prj
|
||||
# Читает PRJ/DR/FL и создаёт структуру проекта локально.
|
||||
piproject() {
|
||||
local spec="$1" root="" curdir="" line="" created_projects=0
|
||||
|
||||
# Проверка аргументов
|
||||
[ -z "$spec" ] && {
|
||||
echo "Использование: piproject ФАЙЛ.prj" >&2
|
||||
echo "Пример: piproject мойпроект.prj" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
[ ! -f "$spec" ] && {
|
||||
echo "❌ Файл спецификации не найден: $spec" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "🌳 Читаем спецификацию: $spec"
|
||||
|
||||
# Проверяем, есть ли хоть одна PRJ: строка
|
||||
if ! grep -q "^PRJ:" "$spec" 2>/dev/null; then
|
||||
echo "❌ В файле нет PRJ: определения" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Читаем файл построчно
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
# Убираем пробелы в начале и конце
|
||||
line="${line#"${line%%[![:space:]]*}"}"
|
||||
line="${line%"${line##*[![:space:]]}"}"
|
||||
|
||||
# Пропускаем пустые строки и комментарии
|
||||
case "$line" in
|
||||
""|"#"*)
|
||||
continue
|
||||
;;
|
||||
|
||||
PRJ:*)
|
||||
# Начало нового проекта - определяем корневую директорию
|
||||
root="${line#PRJ:}"
|
||||
root="${root#"${root%%[![:space:]]*}"}"
|
||||
root="${root%"${root##*[![:space:]]}"}"
|
||||
|
||||
# Проверяем безопасность пути
|
||||
if [[ "$root" == *".."* ]] || [[ "$root" == /* ]]; then
|
||||
echo "⚠️ Предупреждение: путь '$root' может быть небезопасен" >&2
|
||||
fi
|
||||
|
||||
# Создаём корневую директорию
|
||||
echo "📁 Создаём проект: $root/"
|
||||
if pinstall -d "$root/"; then
|
||||
curdir="$root"
|
||||
created_projects=$((created_projects + 1))
|
||||
else
|
||||
echo "❌ Не удалось создать корень проекта: $root" >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
|
||||
DR:*)
|
||||
# Создание поддиректории
|
||||
[ -z "$root" ] && {
|
||||
echo "❌ Сначала определите PRJ: в файле $spec" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
local dir_path="${line#DR:}"
|
||||
dir_path="${dir_path#"${dir_path%%[![:space:]]*}"}"
|
||||
dir_path="${dir_path%"${dir_path##*[![:space:]]}"}"
|
||||
|
||||
# Защита от небезопасных путей
|
||||
if [[ "$dir_path" == *".."* ]] || [[ "$dir_path" == /* ]]; then
|
||||
echo "⚠️ Предупреждение: путь '$dir_path' может быть небезопасен" >&2
|
||||
fi
|
||||
|
||||
# Создаём поддиректорию
|
||||
if [ -n "$dir_path" ]; then
|
||||
curdir="$root/$dir_path"
|
||||
if pinstall -d "$curdir/"; then
|
||||
echo " 📂 Директория: $dir_path"
|
||||
else
|
||||
echo " ⚠️ Не удалось создать директорию: $dir_path" >&2
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
FL:*)
|
||||
# Создание файла
|
||||
[ -z "$root" ] && {
|
||||
echo "❌ Сначала определите PRJ: в файле $spec" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
local file_path="${line#FL:}"
|
||||
file_path="${file_path#"${file_path%%[![:space:]]*}"}"
|
||||
file_path="${file_path%"${file_path##*[![:space:]]}"}"
|
||||
|
||||
if [ -z "$file_path" ]; then
|
||||
echo "⚠️ Пустое имя файла в FL:, пропускаем" >&2
|
||||
continue
|
||||
fi
|
||||
|
||||
# Определяем полный путь к файлу
|
||||
local full_path=""
|
||||
if [[ "$file_path" == */* ]]; then
|
||||
# В пути есть слеш - создаём относительно корня
|
||||
full_path="$root/$file_path"
|
||||
|
||||
# Создаём родительские директории если нужно
|
||||
local parent_dir="${full_path%/*}"
|
||||
if [ -n "$parent_dir" ] && [ ! -d "$parent_dir" ]; then
|
||||
pinstall -d "$parent_dir/" >/dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
# Простое имя файла - создаём в текущей директории
|
||||
[ -z "$curdir" ] && curdir="$root"
|
||||
full_path="$curdir/$file_path"
|
||||
fi
|
||||
|
||||
# Создаём файл
|
||||
if pinstall "$full_path"; then
|
||||
echo " 📄 Файл: $file_path"
|
||||
else
|
||||
echo " ⚠️ Не удалось создать файл: $file_path" >&2
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
# Неизвестная строка
|
||||
echo "⚠️ Неизвестная строка в $spec (пропускаем): $line" >&2
|
||||
;;
|
||||
esac
|
||||
done < "$spec"
|
||||
|
||||
if [ "$created_projects" -gt 0 ]; then
|
||||
echo "✅ Готово! Создано проектов: $created_projects"
|
||||
else
|
||||
echo "ℹ️ Ничего не создано (всё уже существует?)"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------ deploypi ---------------------------
|
||||
# deploypi ХОСТ ПОЛЬЗОВАТЕЛЬ SPEC.prj
|
||||
# Копирует pitoolsv2 + spec на хост и запускает piproject.
|
||||
deploypi() {
|
||||
local host="$1" user="$2" spec="$3"
|
||||
|
||||
# Проверка аргументов
|
||||
[ -z "$host" ] || [ -z "$user" ] || [ -z "$spec" ] && {
|
||||
echo "Использование: deploypi ХОСТ ПОЛЬЗОВАТЕЛЬ ФАЙЛ.prj" >&2
|
||||
echo "Пример: deploypi server.ru vasya мойпроект.prj" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
[ ! -f "$spec" ] && {
|
||||
echo "❌ Файл спецификации не найден: $spec" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "🚀 DEPLOYpi: $spec → $user@$host"
|
||||
|
||||
# Определяем путь к текущему скрипту
|
||||
local self=""
|
||||
if [ -f "$0" ]; then
|
||||
self="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
||||
elif [ -n "${BASH_SOURCE[0]}" ]; then
|
||||
self="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
|
||||
else
|
||||
self="./pitoolsv2.sh"
|
||||
fi
|
||||
|
||||
# Безопасное получение имени спецификации
|
||||
local spec_basename="$(basename "$spec")"
|
||||
spec_basename="${spec_basename//[!a-zA-Zа-яА-ЯёЁ0-9._-]/_}"
|
||||
|
||||
echo "🔍 Проверяем соединение с $host..."
|
||||
|
||||
# Проверяем доступность SSH
|
||||
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new \
|
||||
"$user@$host" "exit 0" 2>/dev/null; then
|
||||
echo "❌ Не могу подключиться к $user@$host через SSH" >&2
|
||||
echo " Проверьте: ssh $user@$host" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "📤 Загружаем инструменты и спецификацию..."
|
||||
|
||||
# 1. Копируем сам скрипт на удалённый хост
|
||||
if ! scp -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new \
|
||||
"$self" "$user@$host:~/.pitoolsv2.sh" 2>/dev/null; then
|
||||
echo "❌ Не удалось загрузить pitoolsv2 на $host" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 2. Копируем спецификацию проекта
|
||||
if ! scp -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new \
|
||||
"$spec" "$user@$host:~/$spec_basename" 2>/dev/null; then
|
||||
echo "❌ Не удалось загрузить спецификацию на $host" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "⚡ Выполняем удалённо..."
|
||||
|
||||
# 3. Запускаем создание проекта на удалённом хосте
|
||||
ssh -o ConnectTimeout=30 -o StrictHostKeyChecking=accept-new "$user@$host" "
|
||||
echo '🔍 Проверяем загруженные файлы...'
|
||||
|
||||
if [ ! -f ~/.pitoolsv2.sh ]; then
|
||||
echo '❌ Ошибка: pitoolsv2 не найден' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f ~/'$spec_basename' ]; then
|
||||
echo '❌ Ошибка: спецификация не найдена' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo '⚙️ Настраиваем окружение...'
|
||||
# Добавляем загрузку pitools в .bashrc если ещё нет
|
||||
if ! grep -q 'pitoolsv2' ~/.bashrc 2>/dev/null; then
|
||||
echo '[ -f ~/.pitoolsv2.sh ] && . ~/.pitoolsv2.sh # PITOOLSv2' >> ~/.bashrc
|
||||
echo ' ✅ Добавили в .bashrc'
|
||||
fi
|
||||
|
||||
# Загружаем скрипт и выполняем
|
||||
. ~/.pitoolsv2.sh 2>/dev/null || {
|
||||
echo '❌ Не удалось загрузить pitoolsv2' >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd ~ || { echo '❌ Не могу перейти в домашнюю директорию' >&2; exit 1; }
|
||||
echo '🛠️ Запускаем создание проекта...'
|
||||
|
||||
if piproject '$spec_basename'; then
|
||||
echo '✅ Удалённый проект успешно создан!'
|
||||
echo ''
|
||||
echo 'Созданные файлы:'
|
||||
find . -type f -name '*$spec_basename*' -o -path './*' | head -10
|
||||
exit 0
|
||||
else
|
||||
echo '❌ Ошибка при создании проекта' >&2
|
||||
exit 1
|
||||
fi
|
||||
" 2>&1
|
||||
|
||||
local result=$?
|
||||
if [ $result -eq 0 ]; then
|
||||
echo "✅ $host: проект '$spec_basename' успешно развёрнут!"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Ошибка выполнения на $host" >&2
|
||||
return $result
|
||||
fi
|
||||
}
|
||||
|
||||
# ---------------------- multideploypi ------------------------
|
||||
# multideploypi INFRA.prj
|
||||
# Читает файл, разбивает на блоки:
|
||||
# MLT:host1,host2
|
||||
# PRJ/DR/FL...
|
||||
# Каждый блок деплоит на свои хосты через deploypi.
|
||||
multideploypi() {
|
||||
local spec="$1"
|
||||
|
||||
# Проверка аргументов
|
||||
[ -z "$spec" ] && {
|
||||
echo "Использование: multideploypi ФАЙЛ_МУЛЬТИ.prj" >&2
|
||||
echo "Пример: multideploypi инфраструктура.prj" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
[ ! -f "$spec" ] && {
|
||||
echo "❌ Файл спецификации не найден: $spec" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "🌍 MULTIDEPLOYpi: обрабатываем $spec"
|
||||
|
||||
local line current_hosts="" tmpdir block_spec prj_seen=0
|
||||
local block_counter=0
|
||||
local pids=""
|
||||
local temp_files=""
|
||||
|
||||
# Создаём временную директорию
|
||||
tmpdir="$(mktemp -d -t pitools-XXXXXX 2>/dev/null)" || {
|
||||
echo "❌ Не удалось создать временную директорию" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Функция для очистки временных файлов
|
||||
cleanup() {
|
||||
for pid in $pids; do
|
||||
kill "$pid" 2>/dev/null || true
|
||||
done
|
||||
rm -rf "$tmpdir" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Устанавливаем обработчик прерывания
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Завершение текущего блока
|
||||
finish_block() {
|
||||
local hosts="$1" specfile="$2"
|
||||
|
||||
[ -z "$hosts" ] && return 0
|
||||
[ ! -s "$specfile" ] && return 0
|
||||
[ "$prj_seen" -eq 0 ] && {
|
||||
echo "⚠️ Блок без PRJ: директивы, пропускаем" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
# Разбиваем хосты по запятым
|
||||
local hosts_arr
|
||||
IFS=',' read -r -a hosts_arr <<< "$hosts"
|
||||
|
||||
local valid_hosts=0
|
||||
for h in "${hosts_arr[@]}"; do
|
||||
h="${h#"${h%%[![:space:]]*}"}"
|
||||
h="${h%"${h##*[![:space:]]}"}"
|
||||
[ -z "$h" ] && continue
|
||||
valid_hosts=$((valid_hosts + 1))
|
||||
done
|
||||
|
||||
if [ "$valid_hosts" -eq 0 ]; then
|
||||
echo "⚠️ В блоке нет валидных хостов, пропускаем" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "🔧 Блок $block_counter → $valid_hosts хост(ов): ${hosts_arr[*]}"
|
||||
|
||||
# Запускаем деплой на каждый хост
|
||||
for h in "${hosts_arr[@]}"; do
|
||||
h="${h#"${h%%[![:space:]]*}"}"
|
||||
h="${h%"${h##*[![:space:]]}"}"
|
||||
[ -z "$h" ] && continue
|
||||
|
||||
# Создаём копию спецификации для каждого хоста
|
||||
local host_spec=""
|
||||
host_spec="$(mktemp "$tmpdir/spec_${h}_XXXXXX.prj" 2>/dev/null)" || continue
|
||||
temp_files="$temp_files $host_spec"
|
||||
cp "$specfile" "$host_spec"
|
||||
|
||||
# Запускаем деплой в фоне
|
||||
(
|
||||
echo " 🚀 Начинаем деплой на $h..."
|
||||
if deploypi "$h" "$USER" "$host_spec" > "$tmpdir/deploy_${h}.log" 2>&1; then
|
||||
echo " ✅ $h: деплой успешен"
|
||||
else
|
||||
echo " ❌ $h: деплой не удался (лог: $tmpdir/deploy_${h}.log)" >&2
|
||||
fi
|
||||
) &
|
||||
pids="$pids $!"
|
||||
done
|
||||
}
|
||||
|
||||
# Инициализируем первый блок
|
||||
block_counter=1
|
||||
block_spec="$(mktemp "$tmpdir/block_${block_counter}_XXXXXX.prj" 2>/dev/null)" || {
|
||||
echo "❌ Не удалось создать временный файл" >&2
|
||||
return 1
|
||||
}
|
||||
temp_files="$temp_files $block_spec"
|
||||
|
||||
echo "📖 Парсим спецификацию..."
|
||||
|
||||
# Читаем файл построчно
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
# Убираем лишние пробелы
|
||||
line="${line#"${line%%[![:space:]]*}"}"
|
||||
line="${line%"${line##*[![:space:]]}"}"
|
||||
|
||||
case "$line" in
|
||||
""|"#"*)
|
||||
# Комментарии и пустые строки сохраняем для читаемости
|
||||
[ -n "$block_spec" ] && echo "$line" >> "$block_spec"
|
||||
;;
|
||||
|
||||
MLT:*)
|
||||
# Новый блок хостов
|
||||
echo "📦 Нашли MLT блок: ${line#MLT:}"
|
||||
|
||||
# Завершаем предыдущий блок
|
||||
finish_block "$current_hosts" "$block_spec"
|
||||
|
||||
# Начинаем новый блок
|
||||
current_hosts="${line#MLT:}"
|
||||
block_counter=$((block_counter + 1))
|
||||
block_spec="$(mktemp "$tmpdir/block_${block_counter}_XXXXXX.prj" 2>/dev/null)" || {
|
||||
echo "❌ Не удалось создать временный файл для блока $block_counter" >&2
|
||||
return 1
|
||||
}
|
||||
temp_files="$temp_files $block_spec"
|
||||
prj_seen=0
|
||||
|
||||
# Сохраняем MLT строку в новый блок
|
||||
echo "$line" >> "$block_spec"
|
||||
;;
|
||||
|
||||
PRJ:*)
|
||||
# Начало описания проекта
|
||||
echo "$line" >> "$block_spec"
|
||||
prj_seen=1
|
||||
;;
|
||||
|
||||
DR:*|FL:*)
|
||||
# Описание директорий и файлов
|
||||
[ -z "$block_spec" ] && {
|
||||
echo "❌ DR: или FL: без MLT: блока" >&2
|
||||
return 1
|
||||
}
|
||||
echo "$line" >> "$block_spec"
|
||||
;;
|
||||
|
||||
*)
|
||||
# Неизвестные строки пропускаем с предупреждением
|
||||
echo "⚠️ Неизвестная директива, пропускаем: $line" >&2
|
||||
;;
|
||||
esac
|
||||
done < "$spec"
|
||||
|
||||
# Завершаем последний блок
|
||||
finish_block "$current_hosts" "$block_spec"
|
||||
|
||||
# Ждём завершения всех фоновых процессов
|
||||
if [ -n "$pids" ]; then
|
||||
echo "⏳ Ждём завершения всех деплоев..."
|
||||
local failed=0
|
||||
for pid in $pids; do
|
||||
if wait "$pid"; then
|
||||
echo "✓ Процесс $pid завершился успешно"
|
||||
else
|
||||
echo "✗ Процесс $pid завершился с ошибкой" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$failed" -eq 1 ]; then
|
||||
echo "⚠️ Некоторые деплои не удались. Логи в: $tmpdir"
|
||||
echo " Посмотреть: ls -la $tmpdir/*.log"
|
||||
# Не удаляем временную директорию при ошибках
|
||||
trap - EXIT INT TERM
|
||||
return 1
|
||||
else
|
||||
echo "✅ Все деплои успешно завершены!"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
echo "ℹ️ Нет хостов для деплоя"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# -------------------------- help -----------------------------
|
||||
# Короткая подсказка по доступным командам.
|
||||
pitools_help() {
|
||||
cat <<EOF
|
||||
PITOOLSv2 — Простой SSH-оркестратор для всех
|
||||
===========================================
|
||||
|
||||
Доступные команды:
|
||||
pinstall [-h|-u|-s|-d] ФАЙЛ... Создать файлы/директории
|
||||
-h, --here Унаследовать права от текущей папки
|
||||
-u, --user Стандартные права пользователя (644)
|
||||
-s, --script Исполняемые права (755)
|
||||
-d, --directory Создать директорию (не файл)
|
||||
.sh, .py, .js файлы автоматически получают 755!
|
||||
|
||||
piproject ФАЙЛ.prj Создать структуру проекта
|
||||
Формат:
|
||||
PRJ:имя_проекта # Корень проекта
|
||||
DR:подпапка # Создать папку
|
||||
FL:файл # Создать файл
|
||||
FL:путь/к/файлу # Файл с путём
|
||||
# Комментарии разрешены
|
||||
|
||||
deploypi ХОСТ ПОЛЬЗОВАТЕЛЬ ФАЙЛ.prj Деплой на один хост
|
||||
Пример: deploypi server.ru vasya проект.prj
|
||||
|
||||
multideploypi ФАЙЛ_МУЛЬТИ.prj Деплой на несколько хостов
|
||||
Формат:
|
||||
MLT:хост1,хост2,хост3 # Хосты для этого блока
|
||||
PRJ:проект # Описание проекта
|
||||
DR:... # Папки
|
||||
FL:... # Файлы
|
||||
|
||||
pitools_help Показать эту справку
|
||||
|
||||
Примеры:
|
||||
pinstall script.sh # Создаёт script.sh с правами 755
|
||||
piproject мойпроект.prj # Создать локальный проект
|
||||
deploypi server1 vasya app.prj # Деплой на один сервер
|
||||
multideploypi infra.prj # Деплой на несколько серверов
|
||||
|
||||
Советы:
|
||||
- Если файл/папка уже существует, права будут обновлены
|
||||
- Ошибки не останавливают выполнение (только предупреждения)
|
||||
- Все пути безопасно обрабатываются
|
||||
EOF
|
||||
}
|
||||
|
||||
# Автоматическое выполнение команды если скрипт вызван напрямую
|
||||
if [ "$0" = "${BASH_SOURCE[0]:-$0}" ]; then
|
||||
case "${1:-}" in
|
||||
pinstall|piproject|deploypi|multideploypi|pitools_help)
|
||||
"$@"
|
||||
;;
|
||||
"")
|
||||
echo "PITOOLSv2 загружен успешно!"
|
||||
echo "Используйте 'pitools_help' для справки."
|
||||
echo ""
|
||||
echo "Быстрый старт:"
|
||||
echo " . ./pitoolsv2.sh # Загрузить в текущую сессию"
|
||||
echo " piproject пример.prj # Создать проект"
|
||||
;;
|
||||
*)
|
||||
echo "❌ Неизвестная команда: $1" >&2
|
||||
echo "Используйте: pinstall, piproject, deploypi, multideploypi, pitools_help" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
Loading…
Add table
Add a link
Reference in a new issue