-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·195 lines (165 loc) · 6.39 KB
/
install.sh
File metadata and controls
executable file
·195 lines (165 loc) · 6.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/bin/bash
set -Eeuo pipefail
# KlipperFleet Installer
log_info() { echo "KlipperFleet: $*"; }
log_warn() { echo "KlipperFleet: WARNING: $*" >&2; }
log_error() { echo "KlipperFleet: ERROR: $*" >&2; }
on_error() {
local exit_code=$?
log_error "Install failed at line ${BASH_LINENO[0]} while running: ${BASH_COMMAND}"
log_error "See log: ${LOG_FILE:-/tmp/klipperfleet-install.log}"
exit "$exit_code"
}
trap on_error ERR
if [ "$EUID" -ne 0 ]; then
log_info "Not running as root; re-running with sudo."
exec sudo bash "$0" "$@"
fi
# 1. Environment & Path Discovery
if [ -n "${SUDO_USER:-}" ]; then
USER=$SUDO_USER
elif [ "$EUID" -eq 0 ]; then
# If running as root but no SUDO_USER (e.g. Moonraker update),
# use the owner of the script directory.
if [ -n "${BASH_SOURCE[0]:-}" ]; then
USER=$(stat -c '%U' "$(dirname "${BASH_SOURCE[0]}")")
else
USER=$(stat -c '%U' "$(pwd)")
fi
else
USER=$(whoami)
fi
USER_HOME=$(getent passwd $USER | cut -d: -f6)
USER_GROUP=$(id -gn $USER)
# Log for debugging automated installs
LOG_FILE="/tmp/klipperfleet-install.log"
echo "--- Install started at $(date) ---" > "$LOG_FILE"
echo "EUID: $EUID" >> "$LOG_FILE"
echo "USER: $USER" >> "$LOG_FILE"
echo "USER_HOME: $USER_HOME" >> "$LOG_FILE"
# Detect if we are running from within a KlipperFleet directory
if [ -n "${BASH_SOURCE[0]:-}" ]; then
SRCDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
else
SRCDIR="$(pwd)"
fi
if [ -d "${SRCDIR}/.git" ]; then
KF_PATH="${SRCDIR}"
else
KF_PATH="${USER_HOME}/KlipperFleet"
fi
MOONRAKER_CONFIG_DIR="${USER_HOME}/printer_data/config"
KF_DATA_DIR="${MOONRAKER_CONFIG_DIR}/klipperfleet"
log_info "Starting installation for user $USER..."
# 2. Self-Clone Support (for wget | bash)
if [ ! -d "${KF_PATH}/.git" ]; then
log_info "Repository not found at ${KF_PATH}. Cloning..."
apt-get update && apt-get install -y git
sudo -u $USER git clone https://github.com/JohnBaumb/KlipperFleet.git "${KF_PATH}"
fi
# Switch to the repo directory
cd "${KF_PATH}"
SRCDIR=$(pwd)
# Fix ownership of the repository to ensure the user can access it
log_info "Fixing repository ownership..."
chown -R "$USER:$USER_GROUP" "$KF_PATH"
# Ensure all scripts are executable
chmod +x *.sh
# 3. Install System Dependencies
log_info "Installing system dependencies..."
DEPS=$(python3 -c "import json; print(' '.join(json.load(open('${SRCDIR}/install_scripts/system-dependencies.json'))['debian']))")
apt-get update && apt-get install -y $DEPS
# Setup udev rules for DFU devices
log_info "Setting up udev rules for DFU devices..."
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666"' | sudo tee /etc/udev/rules.d/99-stm32-dfu.rules
sudo udevadm control --reload-rules
sudo udevadm trigger
# Setup passwordless sudo for commands KlipperFleet needs at runtime
# This is required on Ubuntu and other distros where the user doesn't have NOPASSWD by default.
log_info "Configuring sudoers for runtime commands..."
python3 "${SRCDIR}/install_scripts/setup_sudoers.py" "$USER"
# 4. Setup Python Virtual Environment
log_info "Setting up Python virtual environment..."
KF_VENV="${SRCDIR}/venv"
if [ ! -d "$KF_VENV" ]; then
sudo -u $USER python3 -m venv "$KF_VENV"
fi
# Install Python dependencies
log_info "Installing Python dependencies from requirements.txt..."
sudo -u $USER "$KF_VENV/bin/pip" install -r "${SRCDIR}/backend/requirements.txt"
# Explicitly uninstall pip kconfiglib in production installs.
# KlipperFleet should prefer Klipper's bundled lib/kconfiglib at runtime.
sudo -u $USER "$KF_VENV/bin/pip" uninstall -y kconfiglib || true
# 5. Setup Data Directories
log_info "Setting up data directories..."
sudo -u $USER mkdir -p "$KF_DATA_DIR/profiles"
sudo -u $USER mkdir -p "$KF_DATA_DIR/ui"
# 6. Deploy UI
log_info "Deploying UI files..."
echo "Deploying UI from ${SRCDIR}/ui to $KF_DATA_DIR/ui/" >> "$LOG_FILE"
if [ -d "${SRCDIR}/ui" ]; then
if [ -L "$KF_DATA_DIR/ui/index.html" ]; then
echo "UI is symlinked; skipping copy." >> "$LOG_FILE"
else
sudo -u $USER cp -r "${SRCDIR}/ui/"* "$KF_DATA_DIR/ui/"
echo "UI deployment command executed." >> "$LOG_FILE"
fi
else
echo "UI directory not found in SRCDIR!" >> "$LOG_FILE"
log_warn "UI directory not found at ${SRCDIR}/ui (continuing)."
fi
# 7. Moonraker Integration (Update Manager)
log_info "Integrating with Moonraker..."
python3 "${SRCDIR}/install_scripts/setup_moonraker.py" "${USER_HOME}/printer_data/config/moonraker.conf" "$KF_PATH"
# 8. Mainsail Navigation Integration
log_info "Integrating with Mainsail navigation..."
NAVI_JSON="${MOONRAKER_CONFIG_DIR}/.theme/navi.json"
mkdir -p "${MOONRAKER_CONFIG_DIR}/.theme"
python3 "${SRCDIR}/install_scripts/setup_mainsail_navi.py" "$NAVI_JSON"
# Deploy redirect shim so the navi link preserves the user's hostname/IP.
MAINSAIL_ROOT="/home/${USER}/mainsail"
if [ -d "$MAINSAIL_ROOT" ]; then
cp "${SRCDIR}/install_scripts/klipperfleet.html" "$MAINSAIL_ROOT/klipperfleet.html"
chown "$USER:$USER_GROUP" "$MAINSAIL_ROOT/klipperfleet.html"
chmod 644 "$MAINSAIL_ROOT/klipperfleet.html"
else
log_warn "Mainsail web root not found at $MAINSAIL_ROOT; redirect shim not deployed."
fi
# Ensure mainsail theme paths are writable by the runtime user.
if ! chown -R "$USER:$USER_GROUP" "${MOONRAKER_CONFIG_DIR}/.theme"; then
log_warn "Could not set owner on ${MOONRAKER_CONFIG_DIR}/.theme."
fi
if ! chmod 755 "${MOONRAKER_CONFIG_DIR}/.theme"; then
log_warn "Could not set permissions on ${MOONRAKER_CONFIG_DIR}/.theme."
fi
if [ -f "$NAVI_JSON" ]; then
if ! chown "$USER:$USER_GROUP" "$NAVI_JSON"; then
log_warn "Could not set owner on ${NAVI_JSON}."
fi
if ! chmod 664 "$NAVI_JSON"; then
log_warn "Could not set permissions on ${NAVI_JSON}."
fi
fi
# 9. Systemd Service
log_info "Creating systemd service..."
SERVICE_FILE="/etc/systemd/system/klipperfleet.service"
cat > "$SERVICE_FILE" << EOF
[Unit]
Description=KlipperFleet Backend Service
After=network.target
[Service]
Type=simple
User=$USER
WorkingDirectory=${SRCDIR}
ExecStart=${KF_VENV}/bin/python3 -m uvicorn backend.main:app --host 0.0.0.0 --port 8321
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable klipperfleet
systemctl restart klipperfleet
echo ""
log_info "Installation complete!"
echo "Access the UI at: http://$(hostname -I | awk '{print $1}'):8321"
echo "Or check your Mainsail sidebar!"