Files
fush/build.sh
2026-05-22 00:26:27 +03:00

566 lines
22 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# build.sh - универсальный скрипт сборки для fush shell
# Поддерживает операционные системы Linux и OpenIndiana/Hipster
# Обеспечивает компиляцию, тестирование, установку и запуск shell
# Использует цветной вывод и автоматическое определение окружения
set -e
# Определение цветов для вывода
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
NC='\033[0m' # No Color
else
RED=''
GREEN=''
YELLOW=''
BLUE=''
CYAN=''
MAGENTA=''
NC=''
fi
# Определение корневой директории проекта fush
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$SCRIPT_DIR"
FUSH_DIR="$PROJECT_ROOT"
# Проверяем, что мы находимся в директории проекта fush
if [ ! -d "$FUSH_DIR" ] || [ ! -f "$FUSH_DIR/go.mod" ]; then
# Пробуем подняться на уровень выше (на случай если скрипт в scripts/)
if [ -f "$SCRIPT_DIR/../go.mod" ]; then
FUSH_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
PROJECT_ROOT="$FUSH_DIR"
cd "$FUSH_DIR"
echo -e "${YELLOW}Скрипт запущен из поддиректории. Переход в корень проекта: ${FUSH_DIR}${NC}"
else
echo -e "${RED}error: Не найдена директория проекта fush с файлом go.mod${NC}"
echo -e "${RED}error: Проверены директории:${NC}"
echo -e "${RED} - ${FUSH_DIR}${NC}"
echo -e "${RED} - ${SCRIPT_DIR}/..${NC}"
echo -e "${RED}Убедитесь, что файл go.mod существует в корне проекта${NC}"
exit 1
fi
else
cd "$FUSH_DIR"
fi
# Определение переменных
PROJECT_NAME="fush"
BINARY_NAME="bin/${PROJECT_NAME}"
ROOT_BINARY_NAME="${PROJECT_NAME}"
BUILD_DIR="bin"
GO="go"
# Получение информации о версии
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S')
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
GO_VERSION=$(go version | awk '{print $3}' | sed 's/go//')
REQUIRED_VERSION="1.26.0"
# Функция для сравнения версий (работает без sort -V)
version_compare() {
# Удаляем префикс 'v' если есть
local v1="${1#v}"
local v2="${2#v}"
# Разбиваем на компоненты
IFS='.' read -ra v1_arr <<< "$v1"
IFS='.' read -ra v2_arr <<< "$v2"
# Сравниваем компоненты
for i in 0 1 2; do
# Получаем числовые значения, удаляя ведущие нули
local num1="${v1_arr[$i]}"
local num2="${v2_arr[$i]}"
# Удаляем ведущие нули
num1="${num1#0}"
num2="${num2#0}"
# Если строка пустая после удаления нулей, значит было "0"
if [ -z "$num1" ]; then
num1=0
fi
if [ -z "$num2" ]; then
num2=0
fi
# Сравниваем как числа
if [ $num1 -lt $num2 ]; then
echo "-1"
return
elif [ $num1 -gt $num2 ]; then
echo "1"
return
fi
done
echo "0"
}
# Функция для отображения прав и информации о файле
show_file_info() {
local file_path="$1"
local file_name="$2"
if [ -f "$file_path" ]; then
echo -e "${CYAN}================================${NC}"
echo -e "${GREEN}Информация о собранном файле:${NC}"
echo -e "${CYAN}Имя файла:${NC} ${YELLOW}${file_name}${NC}"
echo -e "${CYAN}Полный путь:${NC} ${YELLOW}${file_path}${NC}"
echo -e "${CYAN}Размер:${NC} ${YELLOW}$(ls -lh "$file_path" | awk '{print $5}')${NC}"
echo -e "${CYAN}Права доступа:${NC} ${YELLOW}$(ls -l "$file_path" | awk '{print $1}')${NC}"
echo -e "${CYAN}Владелец:${NC} ${YELLOW}$(ls -l "$file_path" | awk '{print $3":"$4}')${NC}"
echo -e "${CYAN}Тип файла:${NC} ${YELLOW}$(file "$file_path" | cut -d: -f2)${NC}"
echo -e "${CYAN}================================${NC}"
else
echo -e "${RED}Файл не найден: ${file_path}${NC}"
fi
}
# Функция для вывода справки
show_help() {
echo -e "${CYAN}================================${NC}"
echo -e "${CYAN}fush Shell - Скрипт сборки${NC}"
echo -e "${CYAN}================================${NC}"
echo -e "${GREEN}Использование:${NC}"
echo -e " $0 [команда]"
echo
echo -e "${GREEN}Доступные команды:${NC}"
echo -e " ${YELLOW}all${NC} - Очистка и сборка (по умолчанию)"
echo -e " ${YELLOW}build${NC} - Сборка проекта"
echo -e " ${YELLOW}clean${NC} - Очистка временных файлов"
echo -e " ${YELLOW}install${NC} - Установка в систему"
echo -e " ${YELLOW}test${NC} - Запуск тестов"
echo -e " ${YELLOW}run${NC} - Сборка и запуск"
echo -e " ${YELLOW}help${NC} - Показать эту справку"
echo
echo -e "${GREEN}Примеры:${NC}"
echo -e " $0 # Выполнить очистку и сборку"
echo -e " $0 build # Только сборка"
echo -e " $0 install # Собрать и установить"
echo -e " $0 run # Собрать и запустить"
echo
}
# Функция проверки версии Go
check_go_version() {
echo -e "${YELLOW}Проверка версии Go...${NC}"
if [ -z "$GO_VERSION" ]; then
echo -e "${RED}error: Go не установлен${NC}"
exit 1
fi
echo -e "${GREEN}✓ Go версия ${GO_VERSION}${NC}"
# Сравнение версий с помощью собственной функции
local cmp=$(version_compare "$GO_VERSION" "$REQUIRED_VERSION")
if [ "$cmp" = "-1" ]; then
echo -e "${RED}error: Требуется Go версии ${REQUIRED_VERSION} или выше. Текущая версия: ${GO_VERSION}${NC}"
exit 1
fi
echo -e "${GREEN}✓ Версия Go соответствует требованиям${NC}"
}
# Функция проверки операционной системы
check_os() {
OS=$(uname -s)
case "$OS" in
Linux|SunOS)
echo -e "${GREEN}✓ Поддерживаемая ОС: ${OS}${NC}"
;;
*)
echo -e "${RED}error: Неподдерживаемая ОС: ${OS}${NC}"
echo -e "${RED}error: fush поддерживает только Linux и OpenIndiana${NC}"
exit 1
;;
esac
}
# Функция проверки наличия файлов проекта
check_project_files() {
echo -e "${YELLOW}Проверка файлов проекта в ${FUSH_DIR}...${NC}"
# Проверяем наличие go.mod
if [ ! -f "$FUSH_DIR/go.mod" ]; then
echo -e "${RED}error: Файл go.mod не найден в ${FUSH_DIR}${NC}"
exit 1
fi
echo -e "${GREEN}✓ Найден go.mod${NC}"
# Проверяем наличие go.sum
if [ ! -f "$FUSH_DIR/go.sum" ]; then
echo -e "${YELLOW}Предупреждение: Файл go.sum не найден в ${FUSH_DIR}${NC}"
echo -e "${YELLOW}Он будет создан при установке зависимостей${NC}"
else
echo -e "${GREEN}✓ Найден go.sum${NC}"
fi
# Проверяем наличие директории cmd/fush
if [ ! -d "$FUSH_DIR/cmd/fush" ]; then
echo -e "${RED}error: Директория cmd/fush не найдена в ${FUSH_DIR}${NC}"
exit 1
fi
echo -e "${GREEN}✓ Найдена директория cmd/fush${NC}"
# Проверяем наличие main.go
if [ ! -f "$FUSH_DIR/cmd/fush/main.go" ]; then
echo -e "${RED}error: Файл cmd/fush/main.go не найден${NC}"
exit 1
fi
echo -e "${GREEN}✓ Найден main.go${NC}"
}
# Функция установки зависимостей
install_deps() {
echo -e "${YELLOW}Установка зависимостей в ${FUSH_DIR}...${NC}"
# Проверяем наличие go.mod
if [ ! -f "go.mod" ]; then
echo -e "${RED}error: Файл go.mod не найден в текущей директории${NC}"
echo -e "${RED}error: Текущая директория: $(pwd)${NC}"
exit 1
fi
# Обновляем go.mod и создаем go.sum
echo -e "${YELLOW}Выполнение go mod download...${NC}"
$GO mod download 2>&1 | while IFS= read -r line; do
if [[ "$line" == *"error"* ]] || [[ "$line" == *"Error"* ]]; then
echo -e "${RED}error: $line${NC}"
else
echo "$line"
fi
done
echo -e "${YELLOW}Выполнение go mod tidy...${NC}"
$GO mod tidy 2>&1 | while IFS= read -r line; do
if [[ "$line" == *"error"* ]] || [[ "$line" == *"Error"* ]]; then
echo -e "${RED}error: $line${NC}"
else
echo "$line"
fi
done
# Проверяем наличие go.sum после установки
if [ -f "go.sum" ]; then
echo -e "${GREEN}✓ Файл go.sum успешно создан/обновлен${NC}"
GO_SUM_SIZE=$(ls -lh go.sum | awk '{print $5}')
echo -e "${GREEN}✓ Размер go.sum: ${GO_SUM_SIZE}${NC}"
else
echo -e "${RED}error: Файл go.sum не был создан после go mod tidy${NC}"
exit 1
fi
# Проверка наличия Lua
echo -e "${YELLOW}Проверка наличия Lua...${NC}"
if command -v lua >/dev/null 2>&1; then
echo -e "${GREEN}✓ Lua найден${NC}"
else
echo -e "${YELLOW}Предупреждение: Lua не найден. Для работы скриптов потребуется установить Lua${NC}"
echo -e "${YELLOW}Установите Lua с помощью вашего пакетного менеджера:${NC}"
echo -e " - Ubuntu/Debian: sudo apt-get install lua5.3"
echo -e " - OpenIndiana: sudo pkg install lua"
fi
}
# Функция сборки проекта
build_project() {
echo -e "${YELLOW}Компиляция ${PROJECT_NAME}...${NC}"
echo -e "${YELLOW}Директория проекта: ${FUSH_DIR}${NC}"
echo -e "${YELLOW}Текущая директория: $(pwd)${NC}"
# Проверяем наличие go.mod
if [ ! -f "go.mod" ]; then
echo -e "${RED}error: Файл go.mod не найден. Убедитесь, что вы находитесь в директории проекта fush${NC}"
return 1
fi
# Проверяем наличие go.sum
if [ ! -f "go.sum" ]; then
echo -e "${RED}error: Файл go.sum не найден. Выполните сначала установку зависимостей${NC}"
return 1
fi
# Проверяем существование директории cmd/fush
if [ ! -d "cmd/fush" ]; then
echo -e "${RED}error: Директория cmd/fush не найдена${NC}"
return 1
fi
# Проверяем существование main.go
if [ ! -f "cmd/fush/main.go" ]; then
echo -e "${RED}error: Файл cmd/fush/main.go не найден${NC}"
return 1
fi
# Создаем директорию для бинарных файлов
mkdir -p "$BUILD_DIR"
echo -e "${GREEN}✓ Директория ${BUILD_DIR} создана${NC}"
# Формируем флаги сборки
LDFLAGS="-X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}"
# Выполняем сборку с явным указанием выходного файла
echo -e "${YELLOW}Выполнение: go build -v -ldflags=\"${LDFLAGS}\" -o ${BINARY_NAME} ./cmd/fush${NC}"
# Захватываем вывод команды и выводим в реальном времени
go build -v -ldflags="${LDFLAGS}" -o "${BINARY_NAME}" ./cmd/fush 2>&1 | while IFS= read -r line; do
if [[ "$line" == *"error"* ]] || [[ "$line" == *"Error"* ]] || [[ "$line" == *"undefined"* ]] || [[ "$line" == *"cannot"* ]]; then
echo -e "${RED}error: $line${NC}"
else
echo "$line"
fi
done
BUILD_EXIT_CODE=${PIPESTATUS[0]}
# Проверяем результат сборки
if [ $BUILD_EXIT_CODE -ne 0 ]; then
echo -e "${RED}error: Сборка завершилась с ошибкой (код: $BUILD_EXIT_CODE)${NC}"
return 1
fi
# Проверяем, создался ли бинарный файл
if [ -f "${BINARY_NAME}" ]; then
echo -e "${GREEN}✓ Сборка успешно завершена${NC}"
echo -e "${GREEN}✓ Исполняемый файл: ${BINARY_NAME}${NC}"
echo -e "${GREEN}✓ Полный путь: ${FUSH_DIR}/${BINARY_NAME}${NC}"
# Показываем размер бинарного файла
SIZE=$(ls -lh "${BINARY_NAME}" | awk '{print $5}')
echo -e "${GREEN}✓ Размер бинарного файла: ${SIZE}${NC}"
# Проверка прав доступа
if [ -x "${BINARY_NAME}" ]; then
echo -e "${GREEN}✓ Бинарный файл имеет права на выполнение${NC}"
else
echo -e "${YELLOW}Добавление прав на выполнение...${NC}"
chmod +x "${BINARY_NAME}"
echo -e "${GREEN}✓ Права на выполнение добавлены${NC}"
fi
# Копируем бинарный файл в корень проекта
echo -e "${YELLOW}Копирование бинарного файла в корень проекта...${NC}"
cp "${BINARY_NAME}" "${ROOT_BINARY_NAME}"
if [ -f "${ROOT_BINARY_NAME}" ]; then
chmod +x "${ROOT_BINARY_NAME}"
echo -e "${GREEN}✓ Бинарный файл скопирован в: ${ROOT_BINARY_NAME}${NC}"
else
echo -e "${RED}error: Не удалось скопировать бинарный файл в корень проекта${NC}"
return 1
fi
# Отображаем информацию о собранных файлах
echo ""
show_file_info "${BINARY_NAME}" "fush (в папке bin)"
echo ""
show_file_info "${ROOT_BINARY_NAME}" "fush (в корне проекта)"
return 0
else
echo -e "${RED}error: Бинарный файл не создан по пути: ${BINARY_NAME}${NC}"
echo -e "${RED}error: Содержимое директории ${BUILD_DIR}:${NC}"
ls -la "$BUILD_DIR" 2>/dev/null || echo "Директория пуста или не существует"
return 1
fi
}
# Функция очистки
clean_project() {
echo -e "${YELLOW}Очистка в ${FUSH_DIR}...${NC}"
if [ -d "$BUILD_DIR" ]; then
rm -rf "$BUILD_DIR"
echo -e "${GREEN}✓ Директория ${BUILD_DIR} удалена${NC}"
fi
if [ -f "$PROJECT_NAME" ]; then
rm -f "$PROJECT_NAME"
echo -e "${GREEN}✓ Файл ${PROJECT_NAME} удален${NC}"
fi
if [ -f "${ROOT_BINARY_NAME}" ]; then
rm -f "${ROOT_BINARY_NAME}"
echo -e "${GREEN}✓ Файл ${ROOT_BINARY_NAME} удален${NC}"
fi
echo -e "${GREEN}✓ Очистка завершена${NC}"
}
# Функция установки
install_project() {
echo -e "${YELLOW}Установка ${PROJECT_NAME}...${NC}"
# Проверяем, существует ли бинарный файл в корне
if [ ! -f "$ROOT_BINARY_NAME" ]; then
echo -e "${YELLOW}Бинарный файл не найден в корне. Выполняется сборка...${NC}"
build_project
if [ $? -ne 0 ]; then
echo -e "${RED}error: Ошибка сборки. Установка прервана.${NC}"
return 1
fi
fi
# Копируем в системную директорию
if [ -w "/usr/local/bin" ]; then
cp "$ROOT_BINARY_NAME" /usr/local/bin/
echo -e "${GREEN}✓ Установлен в /usr/local/bin/${PROJECT_NAME}${NC}"
else
echo -e "${YELLOW}Нет прав на запись в /usr/local/bin. Используем sudo...${NC}"
sudo cp "$ROOT_BINARY_NAME" /usr/local/bin/
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Установлен в /usr/local/bin/${PROJECT_NAME}${NC}"
else
echo -e "${RED}error: Не удалось установить в /usr/local/bin/${PROJECT_NAME}${NC}"
return 1
fi
fi
# Создание директорий конфигурации
if [ ! -d ~/.config/fush ]; then
mkdir -p ~/.config/fush
if [ -f "config/fush.toml" ]; then
cp config/fush.toml ~/.config/fush/
echo -e "${GREEN}✓ Конфигурация скопирована в ~/.config/fush/${NC}"
fi
fi
# Создание директории для Lua скриптов
if [ ! -d ~/.local/share/fush/lua ]; then
mkdir -p ~/.local/share/fush/lua
if [ -f "lua/example.lua" ]; then
cp lua/example.lua ~/.local/share/fush/lua/
echo -e "${GREEN}✓ Пример Lua скрипта скопирован в ~/.local/share/fush/lua/${NC}"
fi
fi
echo -e "${GREEN}✓ Установка завершена${NC}"
}
# Функция запуска тестов
test_project() {
echo -e "${YELLOW}Запуск тестов в ${FUSH_DIR}...${NC}"
# Проверяем наличие go.mod
if [ ! -f "go.mod" ]; then
echo -e "${RED}error: Файл go.mod не найден${NC}"
return 1
fi
TEST_OUTPUT=$($GO test -v ./... 2>&1)
TEST_EXIT_CODE=$?
echo "$TEST_OUTPUT" | while IFS= read -r line; do
if [[ "$line" == *"FAIL"* ]] || [[ "$line" == *"error"* ]] || [[ "$line" == *"Error"* ]]; then
echo -e "${RED}$line${NC}"
elif [[ "$line" == *"PASS"* ]] || [[ "$line" == *"ok"* ]]; then
echo -e "${GREEN}$line${NC}"
else
echo "$line"
fi
done
if [ $TEST_EXIT_CODE -eq 0 ]; then
echo -e "${GREEN}Все тесты пройдены${NC}"
return 0
else
echo -e "${RED}error: Некоторые тесты не пройдены${NC}"
return 1
fi
}
# Функция запуска
run_project() {
echo -e "${YELLOW}Запуск ${PROJECT_NAME}...${NC}"
# Проверяем, существует ли бинарный файл в корне
if [ ! -f "$ROOT_BINARY_NAME" ]; then
echo -e "${YELLOW}Бинарный файл не найден. Выполняется сборка...${NC}"
build_project
if [ $? -ne 0 ]; then
echo -e "${RED}error: Ошибка сборки. Запуск невозможен.${NC}"
return 1
fi
fi
# Запускаем shell
"./$ROOT_BINARY_NAME"
}
# Функция полной сборки (очистка + сборка)
all_build() {
clean_project
install_deps
build_project
}
# Основная логика
main() {
echo -e "${CYAN}================================${NC}"
echo -e "${CYAN}fush Shell - Скрипт сборки${NC}"
echo -e "${CYAN}================================${NC}"
echo -e "${YELLOW}Директория проекта fush: ${FUSH_DIR}${NC}"
# Проверяем наличие файлов проекта
check_project_files
# Проверяем окружение
check_os
check_go_version
# Определяем команду
COMMAND="${1:-all}"
case "$COMMAND" in
all)
all_build
;;
build)
install_deps
build_project
;;
clean)
clean_project
;;
install)
install_deps
build_project
install_project
;;
test)
install_deps
test_project
;;
run)
install_deps
build_project
run_project
;;
help|--help|-h)
show_help
;;
*)
echo -e "${RED}error: Неизвестная команда: $COMMAND${NC}"
show_help
exit 1
;;
esac
if [ $? -eq 0 ] && [ "$COMMAND" != "help" ]; then
echo -e "${BLUE}================================${NC}"
echo -e "${GREEN}Операция '${COMMAND}' успешно завершена!${NC}"
echo -e "${BLUE}================================${NC}"
fi
}
# Запуск основной функции
main "$@"