paramiko's SSHClient.open_sftp() allocates an exec channel before the SFTP subsystem request, which Synology DSM closes immediately with 'Channel closed'. Manual sftp(1) and WinSCP avoid this by going straight to the SFTP subsystem on a fresh channel. Replaced SSHClient with direct paramiko.Transport + SFTPClient.from_transport, matching the OpenSSH/WinSCP flow. Larger flow-control windows (128 MB) too since Synology has been observed to bail mid-handshake with the default 1 MB. test_connection_verbose now reports per-step status (connect+auth, open_sftp, listdir /, stat base_path, write probe). API returns the steps array so the UI can show exactly which step failed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
146 lines
7.8 KiB
Bash
146 lines
7.8 KiB
Bash
#!/bin/bash
|
|
# Build dupfinder.deb and upload it to the Gitea package registry.
|
|
# Run this on the NAS / any Linux machine with dpkg-deb and curl installed.
|
|
#
|
|
# Usage:
|
|
# ./debian/build-deb.sh
|
|
# ./debian/build-deb.sh --no-upload # build only, skip Gitea upload
|
|
set -e
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
DEBIAN_DIR="$REPO_ROOT/debian"
|
|
BUILD_DIR="$REPO_ROOT/build/deb"
|
|
|
|
# ── Config ────────────────────────────────────────────────────────────────────
|
|
PKG_NAME="dupfinder"
|
|
PKG_VERSION="1.1.2"
|
|
PKG_ARCH="amd64"
|
|
DEB_FILE="${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}.deb"
|
|
|
|
GITEA_URL="http://192.168.1.64:3000"
|
|
GITEA_OWNER="tocmo0nlord"
|
|
GITEA_TOKEN="${GITEA_TOKEN:-7f8d32ca83f2af6047e78cba0e13b5d63269c104}"
|
|
DISTRO="bookworm"
|
|
COMPONENT="main"
|
|
|
|
NO_UPLOAD=false
|
|
[[ "${1}" == "--no-upload" ]] && NO_UPLOAD=true
|
|
|
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
info() { echo -e "\033[0;36m==> $*\033[0m"; }
|
|
ok() { echo -e "\033[0;32m OK $*\033[0m"; }
|
|
fail() { echo -e "\033[0;31m !! $*\033[0m"; exit 1; }
|
|
|
|
# ── Check dependencies ────────────────────────────────────────────────────────
|
|
command -v dpkg-deb &>/dev/null || fail "dpkg-deb not found. Run: sudo apt install dpkg-dev"
|
|
command -v curl &>/dev/null || fail "curl not found. Run: sudo apt install curl"
|
|
|
|
# ── Prepare staging area ──────────────────────────────────────────────────────
|
|
info "Preparing build directory..."
|
|
PKG_STAGE="$BUILD_DIR/${PKG_NAME}_${PKG_VERSION}_${PKG_ARCH}"
|
|
rm -rf "$PKG_STAGE"
|
|
mkdir -p "$PKG_STAGE/DEBIAN"
|
|
|
|
# ── Copy DEBIAN control files ─────────────────────────────────────────────────
|
|
info "Copying control files..."
|
|
cp "$DEBIAN_DIR/control" "$PKG_STAGE/DEBIAN/control"
|
|
cp "$DEBIAN_DIR/postinst" "$PKG_STAGE/DEBIAN/postinst"
|
|
cp "$DEBIAN_DIR/prerm" "$PKG_STAGE/DEBIAN/prerm"
|
|
cp "$DEBIAN_DIR/postrm" "$PKG_STAGE/DEBIAN/postrm"
|
|
|
|
# Inject current version into control file
|
|
sed -i "s/^Version:.*/Version: $PKG_VERSION/" "$PKG_STAGE/DEBIAN/control"
|
|
|
|
# Fix permissions — maintainer scripts must be executable
|
|
chmod 755 "$PKG_STAGE/DEBIAN/postinst" \
|
|
"$PKG_STAGE/DEBIAN/prerm" \
|
|
"$PKG_STAGE/DEBIAN/postrm"
|
|
|
|
# ── Copy payload files ────────────────────────────────────────────────────────
|
|
info "Copying payload files..."
|
|
cp -r "$DEBIAN_DIR/files/." "$PKG_STAGE/"
|
|
|
|
# Copy the docker-compose.yml from repo root into the package
|
|
mkdir -p "$PKG_STAGE/opt/dupfinder"
|
|
cp "$REPO_ROOT/docker-compose.yml" "$PKG_STAGE/opt/dupfinder/docker-compose.yml"
|
|
|
|
# Copy source as fallback build path. Preserve the app/ subdirectory layout
|
|
# so the Dockerfile's `COPY app/ /app/` resolves correctly when building from
|
|
# this staged source dir.
|
|
SRC_STAGE="$PKG_STAGE/opt/dupfinder/source"
|
|
mkdir -p "$SRC_STAGE"
|
|
cp -r "$REPO_ROOT/app" "$SRC_STAGE/app"
|
|
cp -r "$REPO_ROOT/templates" "$SRC_STAGE/templates"
|
|
cp "$REPO_ROOT/Dockerfile" "$SRC_STAGE/Dockerfile"
|
|
cp "$REPO_ROOT/requirements.txt" "$SRC_STAGE/requirements.txt"
|
|
|
|
# ── Fix file permissions ──────────────────────────────────────────────────────
|
|
find "$PKG_STAGE" -type f -name "*.sh" -exec chmod 755 {} \;
|
|
chmod 755 "$PKG_STAGE/usr/local/bin/dupfinder" 2>/dev/null || true
|
|
# Directories must be 755, files 644 (except executables)
|
|
find "$PKG_STAGE" -type d -exec chmod 755 {} \;
|
|
find "$PKG_STAGE" -type f ! -name "*.sh" \
|
|
! -path "*/DEBIAN/*" \
|
|
! -name "dupfinder" \
|
|
-exec chmod 644 {} \;
|
|
|
|
ok "Staging area ready: $PKG_STAGE"
|
|
|
|
# ── Build .deb ────────────────────────────────────────────────────────────────
|
|
info "Building $DEB_FILE ..."
|
|
mkdir -p "$BUILD_DIR"
|
|
dpkg-deb --build --root-owner-group "$PKG_STAGE" "$BUILD_DIR/$DEB_FILE"
|
|
|
|
DEB_SIZE=$(du -sh "$BUILD_DIR/$DEB_FILE" | cut -f1)
|
|
ok "Built: $BUILD_DIR/$DEB_FILE ($DEB_SIZE)"
|
|
|
|
# ── Upload to Gitea ───────────────────────────────────────────────────────────
|
|
if [[ "$NO_UPLOAD" == "true" ]]; then
|
|
echo ""
|
|
echo "Skipping upload (--no-upload). File is at:"
|
|
echo " $BUILD_DIR/$DEB_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
info "Uploading to Gitea package registry..."
|
|
# Gitea's Debian registry requires HTTP basic auth (user + token-as-password)
|
|
# and the literal /upload endpoint — token-bearer auth returns 405.
|
|
UPLOAD_URL="$GITEA_URL/api/packages/$GITEA_OWNER/debian/pool/$DISTRO/$COMPONENT/upload"
|
|
|
|
HTTP_STATUS=$(curl -s -o /tmp/gitea_upload_response.txt -w "%{http_code}" \
|
|
-u "$GITEA_OWNER:$GITEA_TOKEN" \
|
|
--upload-file "$BUILD_DIR/$DEB_FILE" \
|
|
"$UPLOAD_URL")
|
|
|
|
if [[ "$HTTP_STATUS" == "201" || "$HTTP_STATUS" == "200" ]]; then
|
|
ok "Uploaded successfully (HTTP $HTTP_STATUS)"
|
|
elif [[ "$HTTP_STATUS" == "409" ]]; then
|
|
echo " Package version $PKG_VERSION already exists in registry."
|
|
echo " Bump PKG_VERSION in this script to publish a new version."
|
|
else
|
|
echo " Upload failed (HTTP $HTTP_STATUS):"
|
|
cat /tmp/gitea_upload_response.txt
|
|
exit 1
|
|
fi
|
|
|
|
# ── Print install instructions ────────────────────────────────────────────────
|
|
echo ""
|
|
echo "╔══════════════════════════════════════════════════════════════════╗"
|
|
echo "║ Package published! Install on any Ubuntu/Debian machine with: ║"
|
|
echo "╠══════════════════════════════════════════════════════════════════╣"
|
|
echo "║ ║"
|
|
echo "║ 1. Add the repo: ║"
|
|
echo "║ echo \"deb [trusted=yes] \\ ║"
|
|
echo "║ $GITEA_URL/api/packages/$GITEA_OWNER/debian \\ ║"
|
|
echo "║ $DISTRO $COMPONENT\" \\ ║"
|
|
echo "║ | sudo tee /etc/apt/sources.list.d/dupfinder.list ║"
|
|
echo "║ ║"
|
|
echo "║ 2. Install: ║"
|
|
echo "║ sudo apt update && sudo apt install dupfinder ║"
|
|
echo "║ ║"
|
|
echo "║ 3. Configure: ║"
|
|
echo "║ sudo dupfinder setup ║"
|
|
echo "║ ║"
|
|
echo "╚══════════════════════════════════════════════════════════════════╝"
|
|
echo ""
|