Files

203 lines
7.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# iCloud Drive for Linux — installer
# Installs icloud-linux (backend) + icloud-gui (GTK3 frontend) on ElementaryOS / Ubuntu / Debian.
set -euo pipefail
REPO_URL="https://github.com/IsmaeelAkram/icloud-linux"
INSTALL_DIR="$HOME/.local/lib/icloud-linux"
GUI_INSTALL="$HOME/.local/lib/icloud-gui"
BIN_DIR="$HOME/.local/bin"
DESKTOP_DIR="$HOME/.local/share/applications"
ICONS_DIR="$HOME/.local/share/icons/hicolor/scalable/apps"
BOLD="\033[1m"
GREEN="\033[0;32m"
YELLOW="\033[0;33m"
CYAN="\033[0;36m"
RED="\033[0;31m"
RESET="\033[0m"
info() { echo -e "${CYAN} →${RESET} $*"; }
success() { echo -e "${GREEN} ✓${RESET} $*"; }
warn() { echo -e "${YELLOW} !${RESET} $*"; }
die() { echo -e "${RED} ✗ ERROR:${RESET} $*" >&2; exit 1; }
header() { echo -e "\n${BOLD}$*${RESET}"; }
# ── Detect distro ─────────────────────────────────────────────────────────────
if ! command -v apt-get &>/dev/null; then
die "This installer requires apt (Debian/Ubuntu/ElementaryOS). For other distros, install deps manually."
fi
header "iCloud Drive for Linux — Installer"
echo " Target install: $INSTALL_DIR"
echo " GUI install: $GUI_INSTALL"
echo ""
# ── System dependencies ───────────────────────────────────────────────────────
header "1/6 Installing system dependencies"
PKGS=(
python3
python3-venv
python3-pip
python3-gi
python3-gi-cairo
gir1.2-gtk-3.0
python3-yaml
fuse
git
libfuse2
heif-gdk-pixbuf # HEIC/HEIF support for GNOME Photos
)
# Elementary/Ubuntu 22+ ships libfuse3 but icloud-linux may need libfuse2
sudo apt-get update -qq
sudo apt-get install -y "${PKGS[@]}" 2>&1 | grep -E "(install|already)" || true
success "Dependencies installed"
# ── Clone / update icloud-linux backend ───────────────────────────────────────
header "2/6 Installing icloud-linux backend"
if [ -d "$INSTALL_DIR/.git" ]; then
info "Already cloned — pulling latest"
git -C "$INSTALL_DIR" pull --ff-only
else
info "Cloning $REPO_URL"
git clone "$REPO_URL" "$INSTALL_DIR"
fi
# Set up Python venv and install requirements
info "Setting up Python environment"
python3 -m venv "$INSTALL_DIR/venv"
"$INSTALL_DIR/venv/bin/pip" install -q --upgrade pip
"$INSTALL_DIR/venv/bin/pip" install -q -r "$INSTALL_DIR/requirements.txt"
success "Backend ready at $INSTALL_DIR"
# ── Install the GUI ───────────────────────────────────────────────────────────
header "3/6 Installing iCloud Drive GUI"
mkdir -p "$GUI_INSTALL"
# Copy the GUI script alongside this installer script
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SCRIPT_DIR/icloud_gui.py" ]; then
cp "$SCRIPT_DIR/icloud_gui.py" "$GUI_INSTALL/icloud_gui.py"
success "Copied GUI from $SCRIPT_DIR"
else
die "icloud_gui.py not found next to install.sh — make sure you run install.sh from the icloud-gui directory."
fi
# ── Wrapper script in PATH ────────────────────────────────────────────────────
header "4/6 Creating launcher"
mkdir -p "$BIN_DIR"
cat > "$BIN_DIR/icloud-drive" <<EOF
#!/usr/bin/env bash
# Auto-generated by icloud-gui installer
exec python3 "$GUI_INSTALL/icloud_gui.py" "\$@"
EOF
chmod +x "$BIN_DIR/icloud-drive"
success "Launcher: $BIN_DIR/icloud-drive"
# Ensure ~/.local/bin is in PATH
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
warn "~/.local/bin is not in your PATH."
echo " Add this to ~/.bashrc or ~/.profile and re-login:"
echo ' export PATH="$HOME/.local/bin:$PATH"'
fi
# ── Desktop entry & icon ──────────────────────────────────────────────────────
mkdir -p "$DESKTOP_DIR" "$ICONS_DIR"
# Minimal cloud SVG icon (no external deps)
cat > "$ICONS_DIR/com.elementary.icloud-linux.svg" <<'SVGEOF'
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<defs>
<linearGradient id="g" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#64a6e0"/>
<stop offset="100%" stop-color="#1a6eb0"/>
</linearGradient>
</defs>
<path fill="url(#g)"
d="M50 30a14 14 0 0 0-26.5-6A10 10 0 1 0 14 44h36a10 10 0 0 0 0-14z"/>
</svg>
SVGEOF
cat > "$DESKTOP_DIR/com.elementary.icloud-linux.desktop" <<EOF
[Desktop Entry]
Name=iCloud Drive
Comment=Sync iCloud Drive on Linux
Exec=$BIN_DIR/icloud-drive
Icon=com.elementary.icloud-linux
Terminal=false
Type=Application
Categories=Network;FileManager;
Keywords=iCloud;Apple;Sync;Drive;Cloud;
StartupNotify=true
StartupWMClass=icloud_gui
EOF
gtk-update-icon-cache -f -t "$HOME/.local/share/icons/hicolor" 2>/dev/null || true
update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
success "App menu entry installed"
# ── Update GUI config to point at correct icloudctl ──────────────────────────
# Patch the ICLOUDCTL path in the installed GUI script
ICLOUDCTL_PATH="$INSTALL_DIR/icloudctl"
sed -i "s|ICLOUDCTL = .*|ICLOUDCTL = \"$ICLOUDCTL_PATH\"|" "$GUI_INSTALL/icloud_gui.py"
success "GUI configured to use $ICLOUDCTL_PATH"
# ── Enable service at boot ─────────────────────────────────────────────────────
header "6/6 Enabling iCloud service at boot"
SERVICE_DIR="$HOME/.config/systemd/user"
mkdir -p "$SERVICE_DIR"
# Only write the service file if icloud-linux provides one; otherwise create it
if [ -f "$INSTALL_DIR/icloud-linux/icloud.service" ]; then
cp "$INSTALL_DIR/icloud-linux/icloud.service" "$SERVICE_DIR/icloud.service"
elif [ ! -f "$SERVICE_DIR/icloud.service" ]; then
cat > "$SERVICE_DIR/icloud.service" <<SVCEOF
[Unit]
Description=iCloud Linux FUSE filesystem (user)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStartPre=-/usr/bin/fusermount -uz "%h/iCloud"
ExecStop=-/usr/bin/fusermount -uz "%h/iCloud"
ExecStart="$INSTALL_DIR/icloud-linux/.venv/bin/python" "$INSTALL_DIR/icloud-linux/driver.py" -f -c "%h/.config/icloud-linux/config.yaml" "%h/iCloud"
Restart=on-failure
RestartSec=15
TimeoutStopSec=10
KillMode=control-group
ExecStopPost=-/usr/bin/fusermount -uz "%h/iCloud"
Environment=ICLOUD_LOG_PATH=%h/.local/state/icloud-linux/icloud.log
[Install]
WantedBy=default.target
SVCEOF
info "Created systemd service file"
fi
systemctl --user daemon-reload
systemctl --user enable icloud.service
# Enable linger so the service starts at boot even before graphical login
loginctl enable-linger "$USER" 2>/dev/null || true
success "iCloud service enabled at boot (systemctl --user enable icloud.service)"
# ── Done ──────────────────────────────────────────────────────────────────────
header "Installation complete!"
echo ""
echo -e " ${BOLD}Next steps:${RESET}"
echo " 1. Open ${BOLD}iCloud Drive${RESET} from your app menu (Slingshot)"
echo " or run: icloud-drive"
echo ""
echo " 2. Go to ${BOLD}Settings${RESET} and enter your Apple ID + password"
echo ""
echo " 3. Go to ${BOLD}Sign In${RESET} and authenticate (handles 2FA)"
echo ""
echo " 4. On ${BOLD}Dashboard${RESET}, press ${BOLD}Start${RESET} to begin syncing"
echo ""
echo " The iCloud service will start automatically at every login."
echo ""
echo " To uninstall, run: $SCRIPT_DIR/uninstall.sh"
echo ""