226 строки
7.3 KiB
Bash
226 строки
7.3 KiB
Bash
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
APP_NAME="devconsole"
|
|
APP_USER="devconsole"
|
|
APP_DIR="/opt/devconsole"
|
|
DATA_DIR="/var/lib/devconsole"
|
|
LOG_DIR="/var/log/devconsole"
|
|
USB_DIR="/mnt/devconsole-usb"
|
|
SERVICE_FILE="/etc/systemd/system/devconsole.service"
|
|
REPO_URL="${DEVCONSOLE_REPO_URL:-https://github.com/viktor138irk/DevConsole.git}"
|
|
BRANCH="${DEVCONSOLE_BRANCH:-main}"
|
|
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
HOST="${DEVCONSOLE_HOST:-0.0.0.0}"
|
|
PORT="${DEVCONSOLE_PORT:-8077}"
|
|
|
|
info() { echo -e "\033[1;34m[DevConsole]\033[0m $*"; }
|
|
warn() { echo -e "\033[1;33m[DevConsole]\033[0m $*"; }
|
|
err() { echo -e "\033[1;31m[DevConsole]\033[0m $*"; }
|
|
|
|
require_root() {
|
|
if [[ "${EUID}" -ne 0 ]]; then
|
|
err "Запусти установщик от root: sudo bash scripts/install_ubuntu.sh"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
install_docker() {
|
|
info "Устанавливаю Docker"
|
|
|
|
if command -v docker >/dev/null 2>&1; then
|
|
warn "Docker уже установлен"
|
|
else
|
|
apt-get install -y ca-certificates curl gnupg lsb-release
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
|
|
UBUNTU_CODENAME="$(. /etc/os-release && echo "${VERSION_CODENAME:-jammy}")"
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ${UBUNTU_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
|
|
|
|
if apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
|
|
info "Docker установлен из официального репозитория"
|
|
else
|
|
warn "Официальный репозиторий Docker не сработал, ставлю docker.io из Ubuntu repo"
|
|
rm -f /etc/apt/sources.list.d/docker.list
|
|
apt-get update
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io
|
|
fi
|
|
fi
|
|
|
|
if ! docker compose version >/dev/null 2>&1; then
|
|
warn "Docker Compose plugin недоступен, ставлю standalone docker-compose"
|
|
COMPOSE_VERSION="v2.27.0"
|
|
mkdir -p /usr/local/lib/docker/cli-plugins
|
|
curl -fsSL "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-linux-$(uname -m)" -o /usr/local/lib/docker/cli-plugins/docker-compose
|
|
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
|
|
ln -sf /usr/local/lib/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose
|
|
fi
|
|
|
|
systemctl enable docker || true
|
|
systemctl restart docker || true
|
|
}
|
|
|
|
install_packages() {
|
|
info "Устанавливаю системные пакеты"
|
|
apt-get update
|
|
DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
|
ca-certificates curl git unzip zip rsync jq lsof gnupg lsb-release \
|
|
build-essential pkg-config \
|
|
python3 python3-venv python3-pip \
|
|
sqlite3 \
|
|
adb fastboot \
|
|
openjdk-17-jdk \
|
|
udev
|
|
|
|
install_docker
|
|
}
|
|
|
|
create_user_and_dirs() {
|
|
info "Готовлю пользователя и каталоги"
|
|
if ! id -u "${APP_USER}" >/dev/null 2>&1; then
|
|
useradd --system --create-home --shell /bin/bash "${APP_USER}"
|
|
fi
|
|
|
|
mkdir -p "${APP_DIR}" "${DATA_DIR}" "${LOG_DIR}" "${USB_DIR}"
|
|
mkdir -p "${DATA_DIR}/projects" "${DATA_DIR}/snapshots" "${DATA_DIR}/artifacts" "${DATA_DIR}/apk" "${DATA_DIR}/tmp" "${DATA_DIR}/usb"
|
|
chown -R "${APP_USER}:${APP_USER}" "${APP_DIR}" "${DATA_DIR}" "${LOG_DIR}"
|
|
chmod 755 "${APP_DIR}"
|
|
}
|
|
|
|
clone_or_update_repo() {
|
|
info "Загружаю DevConsole из GitHub"
|
|
if [[ -d "${APP_DIR}/.git" ]]; then
|
|
git -C "${APP_DIR}" fetch origin "${BRANCH}"
|
|
git -C "${APP_DIR}" reset --hard "origin/${BRANCH}"
|
|
git -C "${APP_DIR}" clean -fd
|
|
else
|
|
rm -rf "${APP_DIR:?}/"*
|
|
git clone --branch "${BRANCH}" "${REPO_URL}" "${APP_DIR}"
|
|
fi
|
|
chown -R "${APP_USER}:${APP_USER}" "${APP_DIR}"
|
|
}
|
|
|
|
setup_python() {
|
|
info "Создаю Python venv"
|
|
sudo -u "${APP_USER}" "${PYTHON_BIN}" -m venv "${APP_DIR}/venv"
|
|
sudo -u "${APP_USER}" "${APP_DIR}/venv/bin/pip" install --upgrade pip wheel setuptools
|
|
sudo -u "${APP_USER}" "${APP_DIR}/venv/bin/pip" install -r "${APP_DIR}/requirements.txt"
|
|
}
|
|
|
|
setup_env() {
|
|
info "Создаю .env при необходимости"
|
|
if [[ ! -f "${APP_DIR}/.env" ]]; then
|
|
cat > "${APP_DIR}/.env" <<EOF
|
|
# DevConsole runtime
|
|
DEVCONSOLE_HOST=${HOST}
|
|
DEVCONSOLE_PORT=${PORT}
|
|
DEVCONSOLE_DATA_DIR=${DATA_DIR}
|
|
DEVCONSOLE_LOG_DIR=${LOG_DIR}
|
|
DEVCONSOLE_USB_DIR=${USB_DIR}
|
|
DEVCONSOLE_DATABASE_URL=sqlite+aiosqlite:///${DATA_DIR}/devconsole.db
|
|
|
|
# Insert your OpenAI API key here
|
|
OPENAI_API_KEY=
|
|
OPENAI_MODEL=gpt-5
|
|
|
|
# Security
|
|
DEVCONSOLE_ALLOW_SHELL=1
|
|
DEVCONSOLE_ALLOW_DOCKER=1
|
|
DEVCONSOLE_ALLOW_ANDROID=1
|
|
EOF
|
|
chown "${APP_USER}:${APP_USER}" "${APP_DIR}/.env"
|
|
chmod 600 "${APP_DIR}/.env"
|
|
fi
|
|
}
|
|
|
|
setup_usb_debug() {
|
|
info "Готовлю USB debug-зону"
|
|
cat > "${APP_DIR}/scripts/usb_debug_prepare.sh" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
USB_DIR="${DEVCONSOLE_USB_DIR:-/mnt/devconsole-usb}"
|
|
DATA_USB_DIR="${DEVCONSOLE_DATA_USB_DIR:-/var/lib/devconsole/usb}"
|
|
mkdir -p "${USB_DIR}" "${DATA_USB_DIR}"
|
|
echo "USB debug path: ${USB_DIR}"
|
|
echo "Data USB mirror: ${DATA_USB_DIR}"
|
|
lsblk -o NAME,SIZE,FSTYPE,LABEL,MOUNTPOINTS
|
|
EOF
|
|
chmod +x "${APP_DIR}/scripts/usb_debug_prepare.sh"
|
|
chown "${APP_USER}:${APP_USER}" "${APP_DIR}/scripts/usb_debug_prepare.sh"
|
|
|
|
cat > "/etc/udev/rules.d/99-devconsole-android.rules" <<'EOF'
|
|
# Android/ADB debug access for DevConsole host.
|
|
SUBSYSTEM=="usb", MODE="0666", GROUP="plugdev"
|
|
EOF
|
|
udevadm control --reload-rules || true
|
|
udevadm trigger || true
|
|
}
|
|
|
|
setup_systemd() {
|
|
info "Создаю systemd service"
|
|
cat > "${SERVICE_FILE}" <<EOF
|
|
[Unit]
|
|
Description=DevConsole AI Development Orchestrator
|
|
After=network-online.target docker.service
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
User=${APP_USER}
|
|
Group=${APP_USER}
|
|
WorkingDirectory=${APP_DIR}
|
|
EnvironmentFile=${APP_DIR}/.env
|
|
ExecStart=${APP_DIR}/venv/bin/uvicorn backend.main:app --host ${HOST} --port ${PORT}
|
|
Restart=always
|
|
RestartSec=3
|
|
StandardOutput=append:${LOG_DIR}/devconsole.log
|
|
StandardError=append:${LOG_DIR}/devconsole.err.log
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
systemctl enable devconsole
|
|
systemctl restart devconsole
|
|
}
|
|
|
|
setup_docker_permissions() {
|
|
info "Добавляю пользователя в docker/plugdev, если группы есть"
|
|
getent group docker >/dev/null && usermod -aG docker "${APP_USER}" || true
|
|
getent group plugdev >/dev/null && usermod -aG plugdev "${APP_USER}" || true
|
|
systemctl enable docker || true
|
|
systemctl restart docker || true
|
|
}
|
|
|
|
print_result() {
|
|
info "Установка завершена"
|
|
echo ""
|
|
echo "DevConsole: http://$(hostname -I | awk '{print $1}'):${PORT}"
|
|
echo "Local: http://127.0.0.1:${PORT}"
|
|
echo "Service: systemctl status devconsole"
|
|
echo "Logs: journalctl -u devconsole -f"
|
|
echo "App dir: ${APP_DIR}"
|
|
echo "Data dir: ${DATA_DIR}"
|
|
echo "USB dir: ${USB_DIR}"
|
|
echo ""
|
|
warn "Не забудь прописать OPENAI_API_KEY в ${APP_DIR}/.env и перезапустить: systemctl restart devconsole"
|
|
}
|
|
|
|
main() {
|
|
require_root
|
|
install_packages
|
|
create_user_and_dirs
|
|
clone_or_update_repo
|
|
setup_python
|
|
setup_env
|
|
setup_usb_debug
|
|
setup_docker_permissions
|
|
setup_systemd
|
|
print_result
|
|
}
|
|
|
|
main "$@"
|