install scrpts
This commit is contained in:
+33
-9
@@ -19,6 +19,7 @@ The bootstrap script downloads the current pyTorrent repository, detects the ope
|
|||||||
|
|
||||||
- Debian / Ubuntu: `scripts/stack_installers/install_stack_debian_ubuntu.sh`
|
- Debian / Ubuntu: `scripts/stack_installers/install_stack_debian_ubuntu.sh`
|
||||||
- RHEL-compatible systems: `scripts/stack_installers/install_stack_rhel.sh`
|
- RHEL-compatible systems: `scripts/stack_installers/install_stack_rhel.sh`
|
||||||
|
- Arch Linux: `scripts/stack_installers/install_stack_arch.sh`
|
||||||
|
|
||||||
Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora-like systems where `dnf` or `yum` is available.
|
Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora-like systems where `dnf` or `yum` is available.
|
||||||
|
|
||||||
@@ -26,9 +27,9 @@ Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS S
|
|||||||
|
|
||||||
Default installation includes:
|
Default installation includes:
|
||||||
|
|
||||||
- rTorrent `v0.16.11`
|
- Debian/Ubuntu/RHEL: rTorrent `v0.16.11` and libtorrent `v0.16.11` built from source with tinyxml2 XML-RPC
|
||||||
- libtorrent `v0.16.11`
|
- Arch Linux: current `rtorrent` package from the official repositories through `pacman`
|
||||||
- minimal rTorrent build without c-ares/custom curl
|
- minimal source build without c-ares/custom curl on Debian/Ubuntu/RHEL
|
||||||
- rTorrent system user: `rtorrent`
|
- rTorrent system user: `rtorrent`
|
||||||
- rTorrent SCGI endpoint: `scgi://127.0.0.1:5000`
|
- rTorrent SCGI endpoint: `scgi://127.0.0.1:5000`
|
||||||
- rTorrent incoming BitTorrent port: `51300`
|
- rTorrent incoming BitTorrent port: `51300`
|
||||||
@@ -83,11 +84,14 @@ These variables are used by both stack installers.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. |
|
| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. |
|
||||||
| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. |
|
| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. |
|
||||||
| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build and install directory for xmlrpc-c, libtorrent and rTorrent. |
|
| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build and install directory for libtorrent and rTorrent. On Arch this is used only when source build is requested. |
|
||||||
| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port for rTorrent XMLRPC/SCGI. |
|
| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port for rTorrent XMLRPC/SCGI. |
|
||||||
| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent listen port. |
|
| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent listen port. |
|
||||||
| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch, or commit. |
|
| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch, or commit. Ignored by default on Arch unless source build is requested. |
|
||||||
| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch, or commit. |
|
| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch, or commit. Ignored by default on Arch unless source build is requested. |
|
||||||
|
| `RTORRENT_WITH_XMLRPC_C` | `0` | Set to `1` to compile rTorrent with classic xmlrpc-c instead of the default tinyxml2 XML-RPC backend. On Arch this also switches from repo package to source build. |
|
||||||
|
| `RTORRENT_BUILD_FROM_SOURCE` | `0` on Arch, source build on Debian/Ubuntu/RHEL | On Arch, set to `1` or pass `--build-rtorrent` to compile instead of using the `pacman` package. |
|
||||||
|
| `RTORRENT_FORCE_CONFIG` | `1` | On Arch repo-package install, overwrite generated `.rtorrent.rc`; set to `0` to keep an existing config. |
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -96,6 +100,13 @@ curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/inst
|
|||||||
| sudo RTORRENT_USER=rtorrent RTORRENT_SCGI_PORT=5001 RTORRENT_TORRENT_PORT=51400 bash
|
| sudo RTORRENT_USER=rtorrent RTORRENT_SCGI_PORT=5001 RTORRENT_TORRENT_PORT=51400 bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Classic xmlrpc-c backend instead of default tinyxml2. On Arch this forces source build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \
|
||||||
|
| sudo RTORRENT_WITH_XMLRPC_C=1 bash
|
||||||
|
```
|
||||||
|
|
||||||
## pyTorrent parameters
|
## pyTorrent parameters
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
@@ -154,6 +165,18 @@ RHEL-compatible systems:
|
|||||||
sudo bash scripts/stack_installers/install_stack_rhel.sh
|
sudo bash scripts/stack_installers/install_stack_rhel.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Arch Linux, using the repository rTorrent package by default:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash scripts/stack_installers/install_stack_arch.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Arch Linux, forcing source build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash scripts/stack_installers/install_stack_arch.sh --build-rtorrent
|
||||||
|
```
|
||||||
|
|
||||||
## Installed service hints
|
## Installed service hints
|
||||||
|
|
||||||
Check services:
|
Check services:
|
||||||
@@ -173,16 +196,17 @@ journalctl -u rtorrent@rtorrent.service -f
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- The default rTorrent build is intentionally minimal.
|
- Debian/Ubuntu/RHEL source builds are intentionally minimal by default.
|
||||||
|
- Arch Linux uses the current repository `rtorrent` package by default and does not compile rTorrent unless `--build-rtorrent`, `RTORRENT_BUILD_FROM_SOURCE=1`, or `--with-xmlrpc-c` is used.
|
||||||
- c-ares and custom curl are not enabled by the stack installer defaults.
|
- c-ares and custom curl are not enabled by the stack installer defaults.
|
||||||
- The rTorrent installer overwrites the generated `.rtorrent.rc` because the stack installer passes `--force-config`.
|
- The rTorrent installer overwrites the generated `.rtorrent.rc` by default.
|
||||||
- pyTorrent is configured through the HTTP API after the service starts.
|
- pyTorrent is configured through the HTTP API after the service starts.
|
||||||
- If API authentication is enabled before profile configuration, pass `PYTORRENT_API_TOKEN`.
|
- If API authentication is enabled before profile configuration, pass `PYTORRENT_API_TOKEN`.
|
||||||
|
|
||||||
|
|
||||||
## Build logs and troubleshooting
|
## Build logs and troubleshooting
|
||||||
|
|
||||||
The stack installer writes quiet build output to `/var/log/pytorrent-installer` by default.
|
Source-build installers write quiet build output to `/var/log/pytorrent-installer` by default.
|
||||||
Override it with:
|
Override it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ prepare_downloader() {
|
|||||||
dnf install -y ca-certificates curl tar gzip python3 sudo
|
dnf install -y ca-certificates curl tar gzip python3 sudo
|
||||||
elif command_exists yum; then
|
elif command_exists yum; then
|
||||||
yum install -y ca-certificates curl tar gzip python3 sudo
|
yum install -y ca-certificates curl tar gzip python3 sudo
|
||||||
|
elif command_exists pacman; then
|
||||||
|
pacman -Sy --noconfirm --needed ca-certificates curl tar gzip python sudo
|
||||||
fi
|
fi
|
||||||
if command_exists curl; then DOWNLOADER="curl"; return; fi
|
if command_exists curl; then DOWNLOADER="curl"; return; fi
|
||||||
if command_exists wget; then DOWNLOADER="wget"; return; fi
|
if command_exists wget; then DOWNLOADER="wget"; return; fi
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ RT_PROXY_USER="${RTORRENT_SCGI_PROXY_USER:-rtproxy}"
|
|||||||
RT_PROXY_LISTEN="${RTORRENT_SCGI_PROXY_LISTEN:-127.0.0.1:5050}"
|
RT_PROXY_LISTEN="${RTORRENT_SCGI_PROXY_LISTEN:-127.0.0.1:5050}"
|
||||||
RT_PROXY_TOKEN="${RTORRENT_SCGI_PROXY_TOKEN:-}"
|
RT_PROXY_TOKEN="${RTORRENT_SCGI_PROXY_TOKEN:-}"
|
||||||
RT_PROXY_ALLOW_NET="${RTORRENT_SCGI_PROXY_ALLOW_NET:-127.0.0.1}"
|
RT_PROXY_ALLOW_NET="${RTORRENT_SCGI_PROXY_ALLOW_NET:-127.0.0.1}"
|
||||||
|
RT_PROXY_TARGET_NETWORK_EXPLICIT="${RTORRENT_SCGI_PROXY_TARGET_NETWORK+x}"
|
||||||
RT_PROXY_TARGET_NETWORK="${RTORRENT_SCGI_PROXY_TARGET_NETWORK:-tcp}"
|
RT_PROXY_TARGET_NETWORK="${RTORRENT_SCGI_PROXY_TARGET_NETWORK:-tcp}"
|
||||||
RT_PROXY_TARGET_ADDRESS="${RTORRENT_SCGI_PROXY_TARGET_ADDRESS:-127.0.0.1:5000}"
|
RT_PROXY_TARGET_ADDRESS="${RTORRENT_SCGI_PROXY_TARGET_ADDRESS:-127.0.0.1:5000}"
|
||||||
RT_PROXY_BINARY_URL="${RTORRENT_SCGI_PROXY_BINARY_URL:-https://git.linuxiarz.pl/gru/rtorrent-scgi-proxy/raw/branch/master/dist/rtorrent-scgi-proxy-linux-amd64}"
|
RT_PROXY_BINARY_URL="${RTORRENT_SCGI_PROXY_BINARY_URL:-https://git.linuxiarz.pl/gru/rtorrent-scgi-proxy/raw/branch/master/dist/rtorrent-scgi-proxy-linux-amd64}"
|
||||||
@@ -157,7 +158,7 @@ parse_args() {
|
|||||||
--proxy-listen) RT_PROXY_LISTEN="$2"; shift 2 ;;
|
--proxy-listen) RT_PROXY_LISTEN="$2"; shift 2 ;;
|
||||||
--proxy-token) RT_PROXY_TOKEN="$2"; shift 2 ;;
|
--proxy-token) RT_PROXY_TOKEN="$2"; shift 2 ;;
|
||||||
--proxy-allow-net) RT_PROXY_ALLOW_NET="$2"; shift 2 ;;
|
--proxy-allow-net) RT_PROXY_ALLOW_NET="$2"; shift 2 ;;
|
||||||
--proxy-target-network) RT_PROXY_TARGET_NETWORK="$2"; shift 2 ;;
|
--proxy-target-network) RT_PROXY_TARGET_NETWORK="$2"; RT_PROXY_TARGET_NETWORK_EXPLICIT=1; shift 2 ;;
|
||||||
--proxy-target-address) RT_PROXY_TARGET_ADDRESS="$2"; shift 2 ;;
|
--proxy-target-address) RT_PROXY_TARGET_ADDRESS="$2"; shift 2 ;;
|
||||||
--skip-profile) SKIP_PROFILE=1; shift ;;
|
--skip-profile) SKIP_PROFILE=1; shift ;;
|
||||||
-h|--help) usage; exit 0 ;;
|
-h|--help) usage; exit 0 ;;
|
||||||
@@ -174,6 +175,7 @@ detect_os_family() {
|
|||||||
case "${ID:-} ${ID_LIKE:-}" in
|
case "${ID:-} ${ID_LIKE:-}" in
|
||||||
*debian*|*ubuntu*) echo "debian" ;;
|
*debian*|*ubuntu*) echo "debian" ;;
|
||||||
*rhel*|*fedora*|*centos*|*rocky*|*almalinux*) echo "rhel" ;;
|
*rhel*|*fedora*|*centos*|*rocky*|*almalinux*) echo "rhel" ;;
|
||||||
|
*arch*) echo "arch" ;;
|
||||||
*) fail "Unsupported OS: ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown}." ;;
|
*) fail "Unsupported OS: ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown}." ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -193,6 +195,10 @@ install_prerequisites() {
|
|||||||
[[ -n "${manager}" ]] || fail "dnf or yum is required."
|
[[ -n "${manager}" ]] || fail "dnf or yum is required."
|
||||||
"${manager}" install -y ca-certificates curl git rsync sudo python3 python3-devel python3-pip gcc pkgconf-pkg-config
|
"${manager}" install -y ca-certificates curl git rsync sudo python3 python3-devel python3-pip gcc pkgconf-pkg-config
|
||||||
;;
|
;;
|
||||||
|
arch)
|
||||||
|
command -v pacman >/dev/null 2>&1 || fail "pacman is required on Arch Linux."
|
||||||
|
pacman -Sy --noconfirm --needed ca-certificates curl git rsync sudo python python-pip gcc pkgconf
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +219,22 @@ ask_configuration() {
|
|||||||
INSTALL_SCGI_PROXY="$(normalize_yes_no "${INSTALL_SCGI_PROXY}")"
|
INSTALL_SCGI_PROXY="$(normalize_yes_no "${INSTALL_SCGI_PROXY}")"
|
||||||
fi
|
fi
|
||||||
if [[ "${INSTALL_SCGI_PROXY}" == "yes" ]]; then
|
if [[ "${INSTALL_SCGI_PROXY}" == "yes" ]]; then
|
||||||
prompt RT_PROXY_LISTEN "SCGI proxy listen address" "127.0.0.1:5050"
|
if [[ -n "${RTORRENT_SOCKET}" ]]; then
|
||||||
|
RT_PROXY_TARGET_NETWORK="unix"
|
||||||
|
RT_PROXY_TARGET_ADDRESS="${RTORRENT_SOCKET}"
|
||||||
|
elif [[ -z "${RT_PROXY_TARGET_NETWORK_EXPLICIT}" ]]; then
|
||||||
|
RT_PROXY_TARGET_NETWORK="unix"
|
||||||
|
fi
|
||||||
|
prompt RT_PROXY_TARGET_NETWORK "rTorrent SCGI backend: tcp or unix" "${RT_PROXY_TARGET_NETWORK}"
|
||||||
|
if [[ "${RT_PROXY_TARGET_NETWORK}" == "unix" ]]; then
|
||||||
|
prompt RT_PROXY_TARGET_ADDRESS "rTorrent Unix socket path" "${RTORRENT_SOCKET:-/run/rtorrent/rtorrent.sock}"
|
||||||
|
elif [[ "${RT_PROXY_TARGET_NETWORK}" == "tcp" ]]; then
|
||||||
|
prompt RT_PROXY_TARGET_ADDRESS "rTorrent SCGI TCP address" "${RT_PROXY_TARGET_ADDRESS}"
|
||||||
|
else
|
||||||
|
fail "Invalid SCGI proxy backend network: ${RT_PROXY_TARGET_NETWORK}"
|
||||||
|
fi
|
||||||
|
prompt RT_PROXY_ALLOW_NET "SCGI proxy allowed client network/IP/CIDR" "127.0.0.1"
|
||||||
|
prompt RT_PROXY_LISTEN "SCGI proxy TCP listen address for pyTorrent" "127.0.0.1:5050"
|
||||||
if [[ -z "${RT_PROXY_TOKEN}" ]]; then
|
if [[ -z "${RT_PROXY_TOKEN}" ]]; then
|
||||||
RT_PROXY_TOKEN="$(python3 - <<'PY'
|
RT_PROXY_TOKEN="$(python3 - <<'PY'
|
||||||
import secrets
|
import secrets
|
||||||
@@ -221,16 +242,10 @@ print(secrets.token_urlsafe(32))
|
|||||||
PY
|
PY
|
||||||
)"
|
)"
|
||||||
fi
|
fi
|
||||||
prompt RT_PROXY_ALLOW_NET "SCGI proxy allowed client network/IP/CIDR" "127.0.0.1"
|
|
||||||
if [[ -n "${RTORRENT_SOCKET}" ]]; then
|
|
||||||
RT_PROXY_TARGET_NETWORK="unix"
|
|
||||||
RT_PROXY_TARGET_ADDRESS="${RTORRENT_SOCKET}"
|
|
||||||
fi
|
|
||||||
prompt RT_PROXY_TARGET_NETWORK "SCGI proxy backend network: tcp or unix" "${RT_PROXY_TARGET_NETWORK}"
|
|
||||||
prompt RT_PROXY_TARGET_ADDRESS "SCGI proxy backend address" "${RT_PROXY_TARGET_ADDRESS}"
|
|
||||||
SCGI_URL="scgi://${RT_PROXY_LISTEN}/proxy/${RT_PROXY_TOKEN}"
|
SCGI_URL="scgi://${RT_PROXY_LISTEN}/proxy/${RT_PROXY_TOKEN}"
|
||||||
|
else
|
||||||
|
prompt SCGI_URL "rTorrent SCGI URL for pyTorrent profile" "${SCGI_URL}"
|
||||||
fi
|
fi
|
||||||
prompt SCGI_URL "rTorrent SCGI URL for pyTorrent profile" "${SCGI_URL}"
|
|
||||||
|
|
||||||
if [[ "${AUTH_MODE}" == "ask" ]]; then
|
if [[ "${AUTH_MODE}" == "ask" ]]; then
|
||||||
prompt AUTH_MODE "Enable pyTorrent authentication? yes/no" "no"
|
prompt AUTH_MODE "Enable pyTorrent authentication? yes/no" "no"
|
||||||
@@ -271,6 +286,7 @@ ensure_app_user() {
|
|||||||
if ! id -u "${APP_USER}" >/dev/null 2>&1; then
|
if ! id -u "${APP_USER}" >/dev/null 2>&1; then
|
||||||
local shell_path="/usr/sbin/nologin"
|
local shell_path="/usr/sbin/nologin"
|
||||||
[[ -x "${shell_path}" ]] || shell_path="/sbin/nologin"
|
[[ -x "${shell_path}" ]] || shell_path="/sbin/nologin"
|
||||||
|
[[ -x "${shell_path}" ]] || shell_path="/usr/bin/nologin"
|
||||||
useradd --system --create-home --home-dir "/var/lib/${APP_USER}" --shell "${shell_path}" "${APP_USER}"
|
useradd --system --create-home --home-dir "/var/lib/${APP_USER}" --shell "${shell_path}" "${APP_USER}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -521,6 +537,7 @@ install_scgi_proxy() {
|
|||||||
if ! id -u "${RT_PROXY_USER}" >/dev/null 2>&1; then
|
if ! id -u "${RT_PROXY_USER}" >/dev/null 2>&1; then
|
||||||
local shell_path="/usr/sbin/nologin"
|
local shell_path="/usr/sbin/nologin"
|
||||||
[[ -x "${shell_path}" ]] || shell_path="/sbin/nologin"
|
[[ -x "${shell_path}" ]] || shell_path="/sbin/nologin"
|
||||||
|
[[ -x "${shell_path}" ]] || shell_path="/usr/bin/nologin"
|
||||||
useradd --system --no-create-home --shell "${shell_path}" "${RT_PROXY_USER}"
|
useradd --system --no-create-home --shell "${shell_path}" "${RT_PROXY_USER}"
|
||||||
fi
|
fi
|
||||||
curl -fL "${RT_PROXY_BINARY_URL}" -o /usr/local/bin/rtorrent-scgi-proxy
|
curl -fL "${RT_PROXY_BINARY_URL}" -o /usr/local/bin/rtorrent-scgi-proxy
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ prepare_downloader() {
|
|||||||
DOWNLOADER="curl"
|
DOWNLOADER="curl"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
if command_exists pacman; then
|
||||||
|
pacman -Sy --noconfirm --needed curl ca-certificates tar gzip python sudo
|
||||||
|
DOWNLOADER="curl"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
fail "curl or wget is required and no supported package manager was found."
|
fail "curl or wget is required and no supported package manager was found."
|
||||||
}
|
}
|
||||||
@@ -103,6 +108,9 @@ detect_os_family() {
|
|||||||
*rhel*|*fedora*|*centos*|*rocky*|*almalinux*)
|
*rhel*|*fedora*|*centos*|*rocky*|*almalinux*)
|
||||||
echo "rhel"
|
echo "rhel"
|
||||||
;;
|
;;
|
||||||
|
*arch*)
|
||||||
|
echo "arch"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
fail "Unsupported OS: ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown}."
|
fail "Unsupported OS: ID=${ID:-unknown}, ID_LIKE=${ID_LIKE:-unknown}."
|
||||||
;;
|
;;
|
||||||
@@ -129,6 +137,7 @@ if ! download_file "${ARCHIVE_URL}" "${ARCHIVE_PATH}"; then
|
|||||||
for file in \
|
for file in \
|
||||||
install_stack_debian_ubuntu.sh \
|
install_stack_debian_ubuntu.sh \
|
||||||
install_stack_rhel.sh \
|
install_stack_rhel.sh \
|
||||||
|
install_stack_arch.sh \
|
||||||
install_pytorrent_rhel.sh \
|
install_pytorrent_rhel.sh \
|
||||||
install_rtorrent.py \
|
install_rtorrent.py \
|
||||||
install_rtorrent_rhel.py \
|
install_rtorrent_rhel.py \
|
||||||
@@ -153,6 +162,9 @@ case "${OS_FAMILY}" in
|
|||||||
rhel)
|
rhel)
|
||||||
INSTALLER="${PROJECT_DIR}/scripts/stack_installers/install_stack_rhel.sh"
|
INSTALLER="${PROJECT_DIR}/scripts/stack_installers/install_stack_rhel.sh"
|
||||||
;;
|
;;
|
||||||
|
arch)
|
||||||
|
INSTALLER="${PROJECT_DIR}/scripts/stack_installers/install_stack_arch.sh"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
fail "Unsupported OS family: ${OS_FAMILY}."
|
fail "Unsupported OS family: ${OS_FAMILY}."
|
||||||
;;
|
;;
|
||||||
@@ -160,4 +172,4 @@ esac
|
|||||||
|
|
||||||
chmod +x "${PROJECT_DIR}/scripts/stack_installers/"*.sh || true
|
chmod +x "${PROJECT_DIR}/scripts/stack_installers/"*.sh || true
|
||||||
log "Running ${INSTALLER}"
|
log "Running ${INSTALLER}"
|
||||||
bash "${INSTALLER}"
|
bash "${INSTALLER}" "$@"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ The bootstrap script downloads the current pyTorrent repository, detects the ope
|
|||||||
|
|
||||||
- Debian / Ubuntu: `scripts/stack_installers/install_stack_debian_ubuntu.sh`
|
- Debian / Ubuntu: `scripts/stack_installers/install_stack_debian_ubuntu.sh`
|
||||||
- RHEL-compatible systems: `scripts/stack_installers/install_stack_rhel.sh`
|
- RHEL-compatible systems: `scripts/stack_installers/install_stack_rhel.sh`
|
||||||
|
- Arch Linux: `scripts/stack_installers/install_stack_arch.sh`
|
||||||
|
|
||||||
Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora-like systems where `dnf` or `yum` is available.
|
Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS Stream, and Fedora-like systems where `dnf` or `yum` is available.
|
||||||
|
|
||||||
@@ -26,9 +27,9 @@ Supported RHEL-compatible systems include RHEL, Rocky Linux, AlmaLinux, CentOS S
|
|||||||
|
|
||||||
Default installation includes:
|
Default installation includes:
|
||||||
|
|
||||||
- rTorrent `v0.16.11`
|
- Debian/Ubuntu/RHEL: rTorrent `v0.16.11` and libtorrent `v0.16.11` built from source with tinyxml2 XML-RPC
|
||||||
- libtorrent `v0.16.11`
|
- Arch Linux: current `rtorrent` package from the official repositories through `pacman`
|
||||||
- minimal rTorrent build without c-ares/custom curl
|
- minimal source build without c-ares/custom curl on Debian/Ubuntu/RHEL
|
||||||
- rTorrent system user: `rtorrent`
|
- rTorrent system user: `rtorrent`
|
||||||
- rTorrent SCGI endpoint: `scgi://127.0.0.1:5000`
|
- rTorrent SCGI endpoint: `scgi://127.0.0.1:5000`
|
||||||
- rTorrent incoming BitTorrent port: `51300`
|
- rTorrent incoming BitTorrent port: `51300`
|
||||||
@@ -83,11 +84,14 @@ These variables are used by both stack installers.
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. |
|
| `RTORRENT_USER` | `rtorrent` | System user used to run rTorrent. |
|
||||||
| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. |
|
| `RTORRENT_HOME` | `/home/${RTORRENT_USER}` | Home directory for the rTorrent user. |
|
||||||
| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build and install directory for xmlrpc-c, libtorrent and rTorrent. |
|
| `RTORRENT_BASE_DIR` | `/opt/rtorrent_build` | Build and install directory for libtorrent and rTorrent. On Arch this is used only when source build is requested. |
|
||||||
| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port for rTorrent XMLRPC/SCGI. |
|
| `RTORRENT_SCGI_PORT` | `5000` | Local SCGI port for rTorrent XMLRPC/SCGI. |
|
||||||
| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent listen port. |
|
| `RTORRENT_TORRENT_PORT` | `51300` | Incoming BitTorrent listen port. |
|
||||||
| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch, or commit. |
|
| `RTORRENT_REF` | `v0.16.11` | rTorrent Git tag, branch, or commit. Ignored by default on Arch unless source build is requested. |
|
||||||
| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch, or commit. |
|
| `LIBTORRENT_REF` | `v0.16.11` | libtorrent Git tag, branch, or commit. Ignored by default on Arch unless source build is requested. |
|
||||||
|
| `RTORRENT_WITH_XMLRPC_C` | `0` | Set to `1` to compile rTorrent with classic xmlrpc-c instead of the default tinyxml2 XML-RPC backend. On Arch this also switches from repo package to source build. |
|
||||||
|
| `RTORRENT_BUILD_FROM_SOURCE` | `0` on Arch, source build on Debian/Ubuntu/RHEL | On Arch, set to `1` or pass `--build-rtorrent` to compile instead of using the `pacman` package. |
|
||||||
|
| `RTORRENT_FORCE_CONFIG` | `1` | On Arch repo-package install, overwrite generated `.rtorrent.rc`; set to `0` to keep an existing config. |
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -96,6 +100,13 @@ curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/inst
|
|||||||
| sudo RTORRENT_USER=rtorrent RTORRENT_SCGI_PORT=5001 RTORRENT_TORRENT_PORT=51400 bash
|
| sudo RTORRENT_USER=rtorrent RTORRENT_SCGI_PORT=5001 RTORRENT_TORRENT_PORT=51400 bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Classic xmlrpc-c backend instead of default tinyxml2. On Arch this forces source build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://git.linuxiarz.pl/gru/pyTorrent/raw/branch/master/scripts/install_stack.sh \
|
||||||
|
| sudo RTORRENT_WITH_XMLRPC_C=1 bash
|
||||||
|
```
|
||||||
|
|
||||||
## pyTorrent parameters
|
## pyTorrent parameters
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
@@ -154,6 +165,18 @@ RHEL-compatible systems:
|
|||||||
sudo bash scripts/stack_installers/install_stack_rhel.sh
|
sudo bash scripts/stack_installers/install_stack_rhel.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Arch Linux, using the repository rTorrent package by default:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash scripts/stack_installers/install_stack_arch.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Arch Linux, forcing source build:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bash scripts/stack_installers/install_stack_arch.sh --build-rtorrent
|
||||||
|
```
|
||||||
|
|
||||||
## Installed service hints
|
## Installed service hints
|
||||||
|
|
||||||
Check services:
|
Check services:
|
||||||
@@ -173,16 +196,17 @@ journalctl -u rtorrent@rtorrent.service -f
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- The default rTorrent build is intentionally minimal.
|
- Debian/Ubuntu/RHEL source builds are intentionally minimal by default.
|
||||||
|
- Arch Linux uses the current repository `rtorrent` package by default and does not compile rTorrent unless `--build-rtorrent`, `RTORRENT_BUILD_FROM_SOURCE=1`, or `--with-xmlrpc-c` is used.
|
||||||
- c-ares and custom curl are not enabled by the stack installer defaults.
|
- c-ares and custom curl are not enabled by the stack installer defaults.
|
||||||
- The rTorrent installer overwrites the generated `.rtorrent.rc` because the stack installer passes `--force-config`.
|
- The rTorrent installer overwrites the generated `.rtorrent.rc` by default.
|
||||||
- pyTorrent is configured through the HTTP API after the service starts.
|
- pyTorrent is configured through the HTTP API after the service starts.
|
||||||
- If API authentication is enabled before profile configuration, pass `PYTORRENT_API_TOKEN`.
|
- If API authentication is enabled before profile configuration, pass `PYTORRENT_API_TOKEN`.
|
||||||
|
|
||||||
|
|
||||||
## Build logs and troubleshooting
|
## Build logs and troubleshooting
|
||||||
|
|
||||||
The stack installer writes quiet build output to `/var/log/pytorrent-installer` by default.
|
Source-build installers write quiet build output to `/var/log/pytorrent-installer` by default.
|
||||||
Override it with:
|
Override it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ DEFAULT_BASE_DIR = "/opt/rtorrent_build"
|
|||||||
DEFAULT_LIBTORRENT_REF = "v0.16.11"
|
DEFAULT_LIBTORRENT_REF = "v0.16.11"
|
||||||
DEFAULT_RTORRENT_REF = "v0.16.11"
|
DEFAULT_RTORRENT_REF = "v0.16.11"
|
||||||
DEFAULT_XMLRPC_REF = "latest-stable"
|
DEFAULT_XMLRPC_REF = "latest-stable"
|
||||||
|
DEFAULT_RPC_BACKEND = "tinyxml2"
|
||||||
DEFAULT_CARES_REF = "1.34.6"
|
DEFAULT_CARES_REF = "1.34.6"
|
||||||
DEFAULT_CURL_REF = "8.19.0"
|
DEFAULT_CURL_REF = "8.19.0"
|
||||||
DEFAULT_SERVICE_PATH = "/etc/systemd/system/rtorrent@.service"
|
DEFAULT_SERVICE_PATH = "/etc/systemd/system/rtorrent@.service"
|
||||||
@@ -137,18 +138,21 @@ def is_ubuntu_2604():
|
|||||||
return data.get("ID", "").lower() == "ubuntu" and data.get("VERSION_ID", "") == "26.04"
|
return data.get("ID", "").lower() == "ubuntu" and data.get("VERSION_ID", "") == "26.04"
|
||||||
|
|
||||||
|
|
||||||
def detect_debian():
|
def detect_os_family():
|
||||||
data = read_os_release()
|
data = read_os_release()
|
||||||
|
|
||||||
distro_id = data.get("ID", "").lower()
|
distro_id = data.get("ID", "").lower()
|
||||||
distro_like = data.get("ID_LIKE", "").lower()
|
distro_like = data.get("ID_LIKE", "").lower()
|
||||||
if distro_id != "debian" and "debian" not in distro_like:
|
if distro_id == "debian" or "debian" in distro_like or distro_id == "ubuntu":
|
||||||
|
family = "debian"
|
||||||
|
elif distro_id == "arch" or "arch" in distro_like:
|
||||||
|
family = "arch"
|
||||||
|
else:
|
||||||
raise InstallError(
|
raise InstallError(
|
||||||
f"Unsupported distribution: ID={data.get('ID', 'unknown')}, "
|
f"Unsupported distribution: ID={data.get('ID', 'unknown')}, "
|
||||||
f"ID_LIKE={data.get('ID_LIKE', 'unknown')}. This installer currently supports Debian only."
|
f"ID_LIKE={data.get('ID_LIKE', 'unknown')}. This installer supports Debian/Ubuntu and Arch Linux."
|
||||||
)
|
)
|
||||||
|
print(f"Detected {family}-compatible system: {data.get('PRETTY_NAME', distro_id)}")
|
||||||
print(f"Detected Debian-compatible system: {data.get('PRETTY_NAME', distro_id)}")
|
return family
|
||||||
|
|
||||||
|
|
||||||
def prompt_yes_no(question, default=True, assume_yes=False):
|
def prompt_yes_no(question, default=True, assume_yes=False):
|
||||||
@@ -173,7 +177,11 @@ def parse_version(version):
|
|||||||
return tuple(parts[:3]) if parts else (0,)
|
return tuple(parts[:3]) if parts else (0,)
|
||||||
|
|
||||||
|
|
||||||
def ensure_packages(packages, *, debug=False):
|
def ensure_packages(packages, *, family="debian", debug=False):
|
||||||
|
if family == "arch":
|
||||||
|
print("Installing build and runtime dependencies with pacman...")
|
||||||
|
run(["pacman", "-Sy", "--noconfirm", "--needed", *packages], debug=debug, log_name="pacman_install_rtorrent_deps")
|
||||||
|
return
|
||||||
print("Updating APT metadata...")
|
print("Updating APT metadata...")
|
||||||
run(["apt-get", "update"], debug=debug)
|
run(["apt-get", "update"], debug=debug)
|
||||||
print("Installing build and runtime dependencies...")
|
print("Installing build and runtime dependencies...")
|
||||||
@@ -196,12 +204,13 @@ def create_system_user(user, group, home, assume_yes=False, debug=False):
|
|||||||
if not prompt_yes_no(f"Create system user '{user}' with home '{home}'?", default=True, assume_yes=assume_yes):
|
if not prompt_yes_no(f"Create system user '{user}' with home '{home}'?", default=True, assume_yes=assume_yes):
|
||||||
raise InstallError("User creation declined.")
|
raise InstallError("User creation declined.")
|
||||||
run(["groupadd", "--system", group], check=False, debug=debug)
|
run(["groupadd", "--system", group], check=False, debug=debug)
|
||||||
|
shell_path = next((p for p in ["/usr/sbin/nologin", "/sbin/nologin", "/usr/bin/nologin"] if Path(p).exists()), "/usr/bin/false")
|
||||||
run([
|
run([
|
||||||
"useradd",
|
"useradd",
|
||||||
"--system",
|
"--system",
|
||||||
"--home-dir", home,
|
"--home-dir", home,
|
||||||
"--create-home",
|
"--create-home",
|
||||||
"--shell", "/usr/sbin/nologin",
|
"--shell", shell_path,
|
||||||
"--gid", group,
|
"--gid", group,
|
||||||
user,
|
user,
|
||||||
], debug=debug)
|
], debug=debug)
|
||||||
@@ -457,34 +466,40 @@ def build_libtorrent(base_dir, libtorrent_ref, curl_install=None, cares_install=
|
|||||||
return install_dir, version
|
return install_dir, version
|
||||||
|
|
||||||
|
|
||||||
def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, rpc_backend, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
source_dir = Path(base_dir) / "rtorrent"
|
source_dir = Path(base_dir) / "rtorrent"
|
||||||
install_dir = Path(base_dir) / "rtorrent_install"
|
install_dir = Path(base_dir) / "rtorrent_install"
|
||||||
|
|
||||||
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref, debug=debug)
|
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref, debug=debug)
|
||||||
|
|
||||||
xmlrpc_config = find_xmlrpc_config(base_dir, xmlrpc_install)
|
prefixes = [libtorrent_install]
|
||||||
if not xmlrpc_config:
|
xmlrpc_config = None
|
||||||
raise InstallError(f"Could not find custom xmlrpc-c-config under {base_dir}.")
|
if rpc_backend == "xmlrpc-c":
|
||||||
if not str(xmlrpc_config).startswith(str(Path(xmlrpc_install).resolve())):
|
xmlrpc_config = find_xmlrpc_config(base_dir, xmlrpc_install)
|
||||||
raise InstallError(f"Wrong xmlrpc-c-config selected: {xmlrpc_config}. Expected one under: {xmlrpc_install}")
|
if not xmlrpc_config:
|
||||||
|
raise InstallError(f"Could not find custom xmlrpc-c-config under {base_dir}.")
|
||||||
|
if not str(xmlrpc_config).startswith(str(Path(xmlrpc_install).resolve())):
|
||||||
|
raise InstallError(f"Wrong xmlrpc-c-config selected: {xmlrpc_config}. Expected one under: {xmlrpc_install}")
|
||||||
|
verify_xmlrpc_environment(xmlrpc_config, debug=debug)
|
||||||
|
prefixes.append(xmlrpc_install)
|
||||||
|
elif rpc_backend != "tinyxml2":
|
||||||
|
raise InstallError(f"Unsupported RPC backend: {rpc_backend}")
|
||||||
|
|
||||||
verify_xmlrpc_environment(xmlrpc_config, debug=debug)
|
|
||||||
|
|
||||||
prefixes = [libtorrent_install, xmlrpc_install]
|
|
||||||
if curl_install:
|
if curl_install:
|
||||||
prefixes.append(curl_install)
|
prefixes.append(curl_install)
|
||||||
if cares_install:
|
if cares_install:
|
||||||
prefixes.append(cares_install)
|
prefixes.append(cares_install)
|
||||||
env = build_env(*prefixes)
|
env = build_env(*prefixes)
|
||||||
env["PATH"] = f"{xmlrpc_config.parent}:" + env.get("PATH", "")
|
if xmlrpc_config:
|
||||||
env["XMLRPC_C_CONFIG"] = str(xmlrpc_config)
|
env["PATH"] = f"{xmlrpc_config.parent}:" + env.get("PATH", "")
|
||||||
|
env["XMLRPC_C_CONFIG"] = str(xmlrpc_config)
|
||||||
|
|
||||||
with Spinner("Preparing rTorrent build system", enabled=not debug):
|
with Spinner("Preparing rTorrent build system", enabled=not debug):
|
||||||
run(["autoreconf", "-i"], cwd=str(source_dir), env=env, debug=debug)
|
run(["autoreconf", "-i"], cwd=str(source_dir), env=env, debug=debug)
|
||||||
run(["make", "distclean"], cwd=str(source_dir), env=env, check=False, debug=debug)
|
run(["make", "distclean"], cwd=str(source_dir), env=env, check=False, debug=debug)
|
||||||
|
|
||||||
configure_cmd = ["./configure", f"--prefix={install_dir}", "--with-xmlrpc-c"]
|
rpc_flag = "--with-xmlrpc-c" if rpc_backend == "xmlrpc-c" else "--with-xmlrpc-tinyxml2"
|
||||||
|
configure_cmd = ["./configure", f"--prefix={install_dir}", rpc_flag]
|
||||||
with Spinner("Configuring rTorrent", enabled=not debug):
|
with Spinner("Configuring rTorrent", enabled=not debug):
|
||||||
run(configure_cmd, cwd=str(source_dir), env=env, debug=debug)
|
run(configure_cmd, cwd=str(source_dir), env=env, debug=debug)
|
||||||
with Spinner("Building rTorrent", enabled=not debug):
|
with Spinner("Building rTorrent", enabled=not debug):
|
||||||
@@ -492,7 +507,9 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, c
|
|||||||
with Spinner("Installing rTorrent", enabled=not debug):
|
with Spinner("Installing rTorrent", enabled=not debug):
|
||||||
run(["make", "install"], cwd=str(source_dir), env=env, debug=debug, log_name=f"make_install_{Path(source_dir).name}")
|
run(["make", "install"], cwd=str(source_dir), env=env, debug=debug, log_name=f"make_install_{Path(source_dir).name}")
|
||||||
|
|
||||||
runtime_prefixes = [libtorrent_install, xmlrpc_install]
|
runtime_prefixes = [libtorrent_install]
|
||||||
|
if rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
runtime_prefixes.append(xmlrpc_install)
|
||||||
if curl_install:
|
if curl_install:
|
||||||
runtime_prefixes.append(curl_install)
|
runtime_prefixes.append(curl_install)
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -503,7 +520,7 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, c
|
|||||||
return install_dir, version
|
return install_dir, version
|
||||||
|
|
||||||
|
|
||||||
def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
||||||
if not rtorrent_bin.exists():
|
if not rtorrent_bin.exists():
|
||||||
raise InstallError(f"Compiled rtorrent binary not found: {rtorrent_bin}")
|
raise InstallError(f"Compiled rtorrent binary not found: {rtorrent_bin}")
|
||||||
@@ -514,7 +531,9 @@ def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_
|
|||||||
usr_local_bin.symlink_to(rtorrent_bin)
|
usr_local_bin.symlink_to(rtorrent_bin)
|
||||||
print(f"Symlinked {usr_local_bin} -> {rtorrent_bin}")
|
print(f"Symlinked {usr_local_bin} -> {rtorrent_bin}")
|
||||||
|
|
||||||
lib_dirs = [f"{libtorrent_install}/lib", f"{xmlrpc_install}/lib"]
|
lib_dirs = [f"{libtorrent_install}/lib"]
|
||||||
|
if xmlrpc_install:
|
||||||
|
lib_dirs.append(f"{xmlrpc_install}/lib")
|
||||||
if curl_install:
|
if curl_install:
|
||||||
lib_dirs.append(f"{curl_install}/lib")
|
lib_dirs.append(f"{curl_install}/lib")
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -661,7 +680,7 @@ def print_optional_libs_explanation():
|
|||||||
print("Optional libraries:")
|
print("Optional libraries:")
|
||||||
print(" - c-ares: asynchronous DNS resolver. It helps avoid blocking DNS lookups and can improve tracker/DHT-heavy workloads when curl is built with AsynchDNS support.")
|
print(" - c-ares: asynchronous DNS resolver. It helps avoid blocking DNS lookups and can improve tracker/DHT-heavy workloads when curl is built with AsynchDNS support.")
|
||||||
print(" - curl: HTTP/HTTPS transfer library used by libtorrent for tracker/web requests. Building a fresh curl can provide newer TLS/HTTP fixes and c-ares based async DNS.")
|
print(" - curl: HTTP/HTTPS transfer library used by libtorrent for tracker/web requests. Building a fresh curl can provide newer TLS/HTTP fixes and c-ares based async DNS.")
|
||||||
print(" - minimal build: builds only xmlrpc-c, libtorrent and rTorrent; it uses the system libraries already available on Debian.")
|
print(" - minimal build: builds only libtorrent and rTorrent; it uses the system libraries already available on Debian/RHEL.")
|
||||||
|
|
||||||
|
|
||||||
def resolve_optional_build_mode(args):
|
def resolve_optional_build_mode(args):
|
||||||
@@ -739,26 +758,36 @@ def verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_instal
|
|||||||
print("c-ares is not visible in libtorrent ldd; this can still be valid when libcurl is resolved differently.")
|
print("c-ares is not visible in libtorrent ldd; this can still be valid when libcurl is resolved differently.")
|
||||||
|
|
||||||
|
|
||||||
def verify_install(base_dir, rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def verify_install(base_dir, rtorrent_install, libtorrent_install, rpc_backend, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
||||||
which_rtorrent = capture(["which", "rtorrent"], check=False, debug=debug) or "not found in PATH"
|
which_rtorrent = capture(["which", "rtorrent"], check=False, debug=debug) or "not found in PATH"
|
||||||
print(f"Resolved rtorrent from PATH: {which_rtorrent}")
|
print(f"Resolved rtorrent from PATH: {which_rtorrent}")
|
||||||
|
|
||||||
linked = capture(["ldd", str(rtorrent_bin)], check=True, debug=debug)
|
linked = capture(["ldd", str(rtorrent_bin)], check=True, debug=debug)
|
||||||
for libname, expected in [("libtorrent", str(Path(libtorrent_install) / "lib")), ("xmlrpc", str(Path(xmlrpc_install) / "lib"))]:
|
checks = [("libtorrent", str(Path(libtorrent_install) / "lib"))]
|
||||||
|
if rpc_backend == "xmlrpc-c":
|
||||||
|
checks.append(("xmlrpc", str(Path(xmlrpc_install) / "lib")))
|
||||||
|
for libname, expected in checks:
|
||||||
lines = [line for line in linked.splitlines() if libname in line]
|
lines = [line for line in linked.splitlines() if libname in line]
|
||||||
print_link_lines(f"Linked {libname} lines:", lines)
|
print_link_lines(f"Linked {libname} lines:", lines)
|
||||||
if not any(expected in line for line in lines):
|
if not any(expected in line for line in lines):
|
||||||
raise InstallError(f"rtorrent does not appear to be linked against the compiled {libname} from {expected}.")
|
raise InstallError(f"rtorrent does not appear to be linked against the compiled {libname} from {expected}.")
|
||||||
|
if rpc_backend == "tinyxml2":
|
||||||
|
tinyxml_lines = [line for line in linked.splitlines() if "tinyxml2" in line.lower()]
|
||||||
|
print_link_lines("Linked tinyxml2 lines:", tinyxml_lines)
|
||||||
|
if not tinyxml_lines:
|
||||||
|
raise InstallError("rTorrent does not appear to be linked against tinyxml2.")
|
||||||
|
|
||||||
if curl_install:
|
if curl_install:
|
||||||
verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_install, cares_install, debug=debug)
|
verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_install, cares_install, debug=debug)
|
||||||
|
|
||||||
env = build_env(libtorrent_install, xmlrpc_install, curl_install, cares_install)
|
env = build_env(libtorrent_install, xmlrpc_install if rpc_backend == "xmlrpc-c" else None, curl_install, cares_install)
|
||||||
env["LANG"] = "C"
|
env["LANG"] = "C"
|
||||||
env["LC_ALL"] = "C"
|
env["LC_ALL"] = "C"
|
||||||
env["TERM"] = env.get("TERM", "xterm")
|
env["TERM"] = env.get("TERM", "xterm")
|
||||||
ld_paths = [str(Path(libtorrent_install) / "lib"), str(Path(xmlrpc_install) / "lib")]
|
ld_paths = [str(Path(libtorrent_install) / "lib")]
|
||||||
|
if rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
ld_paths.append(str(Path(xmlrpc_install) / "lib"))
|
||||||
if curl_install:
|
if curl_install:
|
||||||
ld_paths.append(str(Path(curl_install) / "lib"))
|
ld_paths.append(str(Path(curl_install) / "lib"))
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -775,11 +804,12 @@ def verify_install(base_dir, rtorrent_install, libtorrent_install, xmlrpc_instal
|
|||||||
|
|
||||||
|
|
||||||
def build_parser():
|
def build_parser():
|
||||||
parser = argparse.ArgumentParser(description="Debian installer for xmlrpc-c + libtorrent + rTorrent under /opt with optional c-ares/custom curl support.")
|
parser = argparse.ArgumentParser(description="Installer for libtorrent + rTorrent under /opt. RPC defaults to tinyxml2; xmlrpc-c is optional.")
|
||||||
parser.add_argument("--base-dir", default=DEFAULT_BASE_DIR, help=f"Base build/install directory (default: {DEFAULT_BASE_DIR})")
|
parser.add_argument("--base-dir", default=DEFAULT_BASE_DIR, help=f"Base build/install directory (default: {DEFAULT_BASE_DIR})")
|
||||||
parser.add_argument("--libtorrent-ref", default=DEFAULT_LIBTORRENT_REF, help=f"Git branch, tag or commit for libtorrent (default: {DEFAULT_LIBTORRENT_REF})")
|
parser.add_argument("--libtorrent-ref", default=DEFAULT_LIBTORRENT_REF, help=f"Git branch, tag or commit for libtorrent (default: {DEFAULT_LIBTORRENT_REF})")
|
||||||
parser.add_argument("--rtorrent-ref", default=DEFAULT_RTORRENT_REF, help=f"Git branch, tag or commit for rtorrent (default: {DEFAULT_RTORRENT_REF})")
|
parser.add_argument("--rtorrent-ref", default=DEFAULT_RTORRENT_REF, help=f"Git branch, tag or commit for rtorrent (default: {DEFAULT_RTORRENT_REF})")
|
||||||
parser.add_argument("--xmlrpc-ref", default=DEFAULT_XMLRPC_REF, help="xmlrpc-c source version or URL (default: latest-stable)")
|
parser.add_argument("--xmlrpc-ref", default=DEFAULT_XMLRPC_REF, help="xmlrpc-c source version or URL. Used only with --with-xmlrpc-c (default: latest-stable)")
|
||||||
|
parser.add_argument("--with-xmlrpc-c", action="store_true", help="Build rTorrent with classic xmlrpc-c instead of the default tinyxml2 XML-RPC backend.")
|
||||||
parser.add_argument("--cares-ref", default=DEFAULT_CARES_REF, help=f"c-ares release version (default: {DEFAULT_CARES_REF})")
|
parser.add_argument("--cares-ref", default=DEFAULT_CARES_REF, help=f"c-ares release version (default: {DEFAULT_CARES_REF})")
|
||||||
parser.add_argument("--curl-ref", default=DEFAULT_CURL_REF, help=f"curl release version (default: {DEFAULT_CURL_REF})")
|
parser.add_argument("--curl-ref", default=DEFAULT_CURL_REF, help=f"curl release version (default: {DEFAULT_CURL_REF})")
|
||||||
parser.add_argument("--user", default=DEFAULT_USER, help=f"System user for the service (default: {DEFAULT_USER})")
|
parser.add_argument("--user", default=DEFAULT_USER, help=f"System user for the service (default: {DEFAULT_USER})")
|
||||||
@@ -791,7 +821,7 @@ def build_parser():
|
|||||||
parser.add_argument("--only-build", action="store_true", help="Only build and install libtorrent/rTorrent under /opt. Skip user, config and systemd.")
|
parser.add_argument("--only-build", action="store_true", help="Only build and install libtorrent/rTorrent under /opt. Skip user, config and systemd.")
|
||||||
parser.add_argument("--yes", action="store_true", help="Assume yes for interactive prompts; optional c-ares/curl remain disabled unless --with-curl or --with-cares is used.")
|
parser.add_argument("--yes", action="store_true", help="Assume yes for interactive prompts; optional c-ares/curl remain disabled unless --with-curl or --with-cares is used.")
|
||||||
parser.add_argument("--debug", action="store_true", help="Show full command output during build steps.")
|
parser.add_argument("--debug", action="store_true", help="Show full command output during build steps.")
|
||||||
parser.add_argument("--minimal", "--core-only", action="store_true", help="Build only xmlrpc-c, libtorrent and rTorrent. Do not build c-ares or custom curl.")
|
parser.add_argument("--minimal", "--core-only", action="store_true", help="Build only libtorrent and rTorrent. Do not build c-ares or custom curl.")
|
||||||
parser.add_argument("--no-cares", "--without-cares", dest="no_cares", action="store_true", help="Do not build c-ares. This also disables custom curl integration.")
|
parser.add_argument("--no-cares", "--without-cares", dest="no_cares", action="store_true", help="Do not build c-ares. This also disables custom curl integration.")
|
||||||
parser.add_argument("--no-curl", "--without-curl", dest="no_curl", action="store_true", help="Do not build custom curl. Implies no c-ares integration for libtorrent.")
|
parser.add_argument("--no-curl", "--without-curl", dest="no_curl", action="store_true", help="Do not build custom curl. Implies no c-ares integration for libtorrent.")
|
||||||
parser.add_argument("--with-cares", action="store_true", help="Build c-ares and custom curl with asynchronous DNS support.")
|
parser.add_argument("--with-cares", action="store_true", help="Build c-ares and custom curl with asynchronous DNS support.")
|
||||||
@@ -805,19 +835,34 @@ def main():
|
|||||||
args.use_cares = resolve_optional_build_mode(args)
|
args.use_cares = resolve_optional_build_mode(args)
|
||||||
|
|
||||||
require_root()
|
require_root()
|
||||||
detect_debian()
|
os_family = detect_os_family()
|
||||||
|
|
||||||
packages = [
|
if os_family == "arch":
|
||||||
"build-essential", "pkg-config", "libtool", "autoconf", "automake", "git", "ca-certificates",
|
packages = [
|
||||||
"libssl-dev", "libncurses-dev", "libncurses5-dev", "libncursesw5-dev", "libexpat1-dev",
|
"base-devel", "pkgconf", "libtool", "autoconf", "automake", "git", "ca-certificates",
|
||||||
"libcurl4-openssl-dev", "libxml2-dev", "libreadline-dev", "curl", "tar", "gzip", "xz-utils",
|
"openssl", "ncurses", "expat", "curl", "libxml2", "tinyxml2", "readline", "tar", "gzip", "xz",
|
||||||
"zlib1g-dev", "bison", "flex", "m4", "gettext", "texinfo", "patch", "diffutils", "file", "procps"
|
"zlib", "bison", "flex", "m4", "gettext", "texinfo", "patch", "diffutils", "file", "procps-ng"
|
||||||
]
|
]
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
packages.extend(["cmake", "libpsl-dev", "libbrotli-dev", "libzstd-dev"])
|
packages.extend(["cmake", "libpsl", "brotli", "zstd"])
|
||||||
|
else:
|
||||||
|
packages = [
|
||||||
|
"build-essential", "pkg-config", "libtool", "autoconf", "automake", "git", "ca-certificates",
|
||||||
|
"libssl-dev", "libncurses-dev", "libncurses5-dev", "libncursesw5-dev", "libexpat1-dev",
|
||||||
|
"libcurl4-openssl-dev", "libxml2-dev", "libtinyxml2-dev", "libreadline-dev", "curl", "tar", "gzip", "xz-utils",
|
||||||
|
"zlib1g-dev", "bison", "flex", "m4", "gettext", "texinfo", "patch", "diffutils", "file", "procps"
|
||||||
|
]
|
||||||
|
if args.use_cares:
|
||||||
|
packages.extend(["cmake", "libpsl-dev", "libbrotli-dev", "libzstd-dev"])
|
||||||
|
|
||||||
print("This script will:")
|
print("This script will:")
|
||||||
print(f" - build xmlrpc-c from '{args.xmlrpc_ref}'")
|
args.rpc_backend = "xmlrpc-c" if args.with_xmlrpc_c else DEFAULT_RPC_BACKEND
|
||||||
|
|
||||||
|
print(f" - use rTorrent RPC backend: {args.rpc_backend}")
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
print(f" - build xmlrpc-c from '{args.xmlrpc_ref}'")
|
||||||
|
else:
|
||||||
|
print(" - use system tinyxml2 for XML-RPC")
|
||||||
print(f" - build libtorrent from '{args.libtorrent_ref}'")
|
print(f" - build libtorrent from '{args.libtorrent_ref}'")
|
||||||
print(f" - build rtorrent from '{args.rtorrent_ref}'")
|
print(f" - build rtorrent from '{args.rtorrent_ref}'")
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
@@ -826,7 +871,7 @@ def main():
|
|||||||
print(" - benefit: async DNS via c-ares and newer curl for HTTP/HTTPS tracker requests")
|
print(" - benefit: async DNS via c-ares and newer curl for HTTP/HTTPS tracker requests")
|
||||||
else:
|
else:
|
||||||
print(" - minimal build: skip c-ares/custom curl")
|
print(" - minimal build: skip c-ares/custom curl")
|
||||||
print(" - build only xmlrpc-c, libtorrent and rTorrent; use Debian system libraries")
|
print(" - build only libtorrent and rTorrent; use Debian system libraries")
|
||||||
print(f" - install everything under '{args.base_dir}'")
|
print(f" - install everything under '{args.base_dir}'")
|
||||||
if args.only_build:
|
if args.only_build:
|
||||||
print(" - skip service user, config and systemd setup")
|
print(" - skip service user, config and systemd setup")
|
||||||
@@ -838,10 +883,13 @@ def main():
|
|||||||
print("Aborted by user.")
|
print("Aborted by user.")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
ensure_packages(packages, debug=args.debug)
|
ensure_packages(packages, family=os_family, debug=args.debug)
|
||||||
ensure_dir(args.base_dir)
|
ensure_dir(args.base_dir)
|
||||||
|
|
||||||
xmlrpc_install, xmlrpc_version = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref, debug=args.debug)
|
xmlrpc_install = None
|
||||||
|
xmlrpc_version = None
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
xmlrpc_install, xmlrpc_version = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref, debug=args.debug)
|
||||||
|
|
||||||
cares_install = None
|
cares_install = None
|
||||||
cares_version = None
|
cares_version = None
|
||||||
@@ -856,12 +904,12 @@ def main():
|
|||||||
args.base_dir, args.libtorrent_ref, curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
args.base_dir, args.libtorrent_ref, curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
||||||
)
|
)
|
||||||
rtorrent_install, rtorrent_version = build_rtorrent(
|
rtorrent_install, rtorrent_version = build_rtorrent(
|
||||||
args.base_dir, args.rtorrent_ref, libtorrent_install, xmlrpc_install, curl_install=curl_install,
|
args.base_dir, args.rtorrent_ref, libtorrent_install, args.rpc_backend, xmlrpc_install=xmlrpc_install,
|
||||||
cares_install=cares_install, debug=args.debug
|
curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
||||||
)
|
)
|
||||||
|
|
||||||
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install=xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
||||||
verify_install(args.base_dir, rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
verify_install(args.base_dir, rtorrent_install, libtorrent_install, args.rpc_backend, xmlrpc_install=xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
||||||
|
|
||||||
if not args.only_build:
|
if not args.only_build:
|
||||||
create_system_user(args.user, args.group, args.home, assume_yes=args.yes, debug=args.debug)
|
create_system_user(args.user, args.group, args.home, assume_yes=args.yes, debug=args.debug)
|
||||||
@@ -869,7 +917,9 @@ def main():
|
|||||||
bind_address_directive = rtorrent_bind_address_directive(args.rtorrent_ref, rtorrent_version)
|
bind_address_directive = rtorrent_bind_address_directive(args.rtorrent_ref, rtorrent_version)
|
||||||
print(f"Using rTorrent bind address directive: {bind_address_directive}")
|
print(f"Using rTorrent bind address directive: {bind_address_directive}")
|
||||||
write_rtorrent_config(args.home, args.user, args.scgi_port, args.torrent_port, bind_address_directive, force_config=args.force_config)
|
write_rtorrent_config(args.home, args.user, args.scgi_port, args.torrent_port, bind_address_directive, force_config=args.force_config)
|
||||||
runtime_lib_dirs = [f"{libtorrent_install}/lib", f"{xmlrpc_install}/lib"]
|
runtime_lib_dirs = [f"{libtorrent_install}/lib"]
|
||||||
|
if args.rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
runtime_lib_dirs.append(f"{xmlrpc_install}/lib")
|
||||||
if curl_install:
|
if curl_install:
|
||||||
runtime_lib_dirs.append(f"{curl_install}/lib")
|
runtime_lib_dirs.append(f"{curl_install}/lib")
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -880,7 +930,9 @@ def main():
|
|||||||
|
|
||||||
print("\nBuild summary")
|
print("\nBuild summary")
|
||||||
print("-------------")
|
print("-------------")
|
||||||
print(f"xmlrpc-c: {xmlrpc_version}")
|
print(f"rpc: {args.rpc_backend}")
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
print(f"xmlrpc-c: {xmlrpc_version}")
|
||||||
print(f"libtorrent: {libtorrent_version}")
|
print(f"libtorrent: {libtorrent_version}")
|
||||||
print(f"rtorrent: {rtorrent_version.splitlines()[0] if rtorrent_version else args.rtorrent_ref}")
|
print(f"rtorrent: {rtorrent_version.splitlines()[0] if rtorrent_version else args.rtorrent_ref}")
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ DEFAULT_BASE_DIR = "/opt/rtorrent_build"
|
|||||||
DEFAULT_LIBTORRENT_REF = "v0.16.11"
|
DEFAULT_LIBTORRENT_REF = "v0.16.11"
|
||||||
DEFAULT_RTORRENT_REF = "v0.16.11"
|
DEFAULT_RTORRENT_REF = "v0.16.11"
|
||||||
DEFAULT_XMLRPC_REF = "latest-stable"
|
DEFAULT_XMLRPC_REF = "latest-stable"
|
||||||
|
DEFAULT_RPC_BACKEND = "tinyxml2"
|
||||||
DEFAULT_CARES_REF = "1.34.6"
|
DEFAULT_CARES_REF = "1.34.6"
|
||||||
DEFAULT_CURL_REF = "8.19.0"
|
DEFAULT_CURL_REF = "8.19.0"
|
||||||
DEFAULT_SERVICE_PATH = "/etc/systemd/system/rtorrent@.service"
|
DEFAULT_SERVICE_PATH = "/etc/systemd/system/rtorrent@.service"
|
||||||
@@ -458,34 +459,40 @@ def build_libtorrent(base_dir, libtorrent_ref, curl_install=None, cares_install=
|
|||||||
return install_dir, version
|
return install_dir, version
|
||||||
|
|
||||||
|
|
||||||
def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, rpc_backend, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
source_dir = Path(base_dir) / "rtorrent"
|
source_dir = Path(base_dir) / "rtorrent"
|
||||||
install_dir = Path(base_dir) / "rtorrent_install"
|
install_dir = Path(base_dir) / "rtorrent_install"
|
||||||
|
|
||||||
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref, debug=debug)
|
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref, debug=debug)
|
||||||
|
|
||||||
xmlrpc_config = find_xmlrpc_config(base_dir, xmlrpc_install)
|
prefixes = [libtorrent_install]
|
||||||
if not xmlrpc_config:
|
xmlrpc_config = None
|
||||||
raise InstallError(f"Could not find custom xmlrpc-c-config under {base_dir}.")
|
if rpc_backend == "xmlrpc-c":
|
||||||
if not str(xmlrpc_config).startswith(str(Path(xmlrpc_install).resolve())):
|
xmlrpc_config = find_xmlrpc_config(base_dir, xmlrpc_install)
|
||||||
raise InstallError(f"Wrong xmlrpc-c-config selected: {xmlrpc_config}. Expected one under: {xmlrpc_install}")
|
if not xmlrpc_config:
|
||||||
|
raise InstallError(f"Could not find custom xmlrpc-c-config under {base_dir}.")
|
||||||
|
if not str(xmlrpc_config).startswith(str(Path(xmlrpc_install).resolve())):
|
||||||
|
raise InstallError(f"Wrong xmlrpc-c-config selected: {xmlrpc_config}. Expected one under: {xmlrpc_install}")
|
||||||
|
verify_xmlrpc_environment(xmlrpc_config, debug=debug)
|
||||||
|
prefixes.append(xmlrpc_install)
|
||||||
|
elif rpc_backend != "tinyxml2":
|
||||||
|
raise InstallError(f"Unsupported RPC backend: {rpc_backend}")
|
||||||
|
|
||||||
verify_xmlrpc_environment(xmlrpc_config, debug=debug)
|
|
||||||
|
|
||||||
prefixes = [libtorrent_install, xmlrpc_install]
|
|
||||||
if curl_install:
|
if curl_install:
|
||||||
prefixes.append(curl_install)
|
prefixes.append(curl_install)
|
||||||
if cares_install:
|
if cares_install:
|
||||||
prefixes.append(cares_install)
|
prefixes.append(cares_install)
|
||||||
env = build_env(*prefixes)
|
env = build_env(*prefixes)
|
||||||
env["PATH"] = f"{xmlrpc_config.parent}:" + env.get("PATH", "")
|
if xmlrpc_config:
|
||||||
env["XMLRPC_C_CONFIG"] = str(xmlrpc_config)
|
env["PATH"] = f"{xmlrpc_config.parent}:" + env.get("PATH", "")
|
||||||
|
env["XMLRPC_C_CONFIG"] = str(xmlrpc_config)
|
||||||
|
|
||||||
with Spinner("Preparing rTorrent build system", enabled=not debug):
|
with Spinner("Preparing rTorrent build system", enabled=not debug):
|
||||||
run(["autoreconf", "-i"], cwd=str(source_dir), env=env, debug=debug)
|
run(["autoreconf", "-i"], cwd=str(source_dir), env=env, debug=debug)
|
||||||
run(["make", "distclean"], cwd=str(source_dir), env=env, check=False, debug=debug)
|
run(["make", "distclean"], cwd=str(source_dir), env=env, check=False, debug=debug)
|
||||||
|
|
||||||
configure_cmd = ["./configure", f"--prefix={install_dir}", "--with-xmlrpc-c"]
|
rpc_flag = "--with-xmlrpc-c" if rpc_backend == "xmlrpc-c" else "--with-xmlrpc-tinyxml2"
|
||||||
|
configure_cmd = ["./configure", f"--prefix={install_dir}", rpc_flag]
|
||||||
with Spinner("Configuring rTorrent", enabled=not debug):
|
with Spinner("Configuring rTorrent", enabled=not debug):
|
||||||
run(configure_cmd, cwd=str(source_dir), env=env, debug=debug)
|
run(configure_cmd, cwd=str(source_dir), env=env, debug=debug)
|
||||||
with Spinner("Building rTorrent", enabled=not debug):
|
with Spinner("Building rTorrent", enabled=not debug):
|
||||||
@@ -493,7 +500,9 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, c
|
|||||||
with Spinner("Installing rTorrent", enabled=not debug):
|
with Spinner("Installing rTorrent", enabled=not debug):
|
||||||
run(["make", "install"], cwd=str(source_dir), env=env, debug=debug, log_name=f"make_install_{Path(source_dir).name}")
|
run(["make", "install"], cwd=str(source_dir), env=env, debug=debug, log_name=f"make_install_{Path(source_dir).name}")
|
||||||
|
|
||||||
runtime_prefixes = [libtorrent_install, xmlrpc_install]
|
runtime_prefixes = [libtorrent_install]
|
||||||
|
if rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
runtime_prefixes.append(xmlrpc_install)
|
||||||
if curl_install:
|
if curl_install:
|
||||||
runtime_prefixes.append(curl_install)
|
runtime_prefixes.append(curl_install)
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -504,7 +513,7 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install, c
|
|||||||
return install_dir, version
|
return install_dir, version
|
||||||
|
|
||||||
|
|
||||||
def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
||||||
if not rtorrent_bin.exists():
|
if not rtorrent_bin.exists():
|
||||||
raise InstallError(f"Compiled rtorrent binary not found: {rtorrent_bin}")
|
raise InstallError(f"Compiled rtorrent binary not found: {rtorrent_bin}")
|
||||||
@@ -515,7 +524,9 @@ def install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_
|
|||||||
usr_local_bin.symlink_to(rtorrent_bin)
|
usr_local_bin.symlink_to(rtorrent_bin)
|
||||||
print(f"Symlinked {usr_local_bin} -> {rtorrent_bin}")
|
print(f"Symlinked {usr_local_bin} -> {rtorrent_bin}")
|
||||||
|
|
||||||
lib_dirs = [f"{libtorrent_install}/lib", f"{xmlrpc_install}/lib"]
|
lib_dirs = [f"{libtorrent_install}/lib"]
|
||||||
|
if xmlrpc_install:
|
||||||
|
lib_dirs.append(f"{xmlrpc_install}/lib")
|
||||||
if curl_install:
|
if curl_install:
|
||||||
lib_dirs.append(f"{curl_install}/lib")
|
lib_dirs.append(f"{curl_install}/lib")
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -663,7 +674,7 @@ def print_optional_libs_explanation():
|
|||||||
print("Optional libraries:")
|
print("Optional libraries:")
|
||||||
print(" - c-ares: asynchronous DNS resolver. It helps avoid blocking DNS lookups and can improve tracker/DHT-heavy workloads when curl is built with AsynchDNS support.")
|
print(" - c-ares: asynchronous DNS resolver. It helps avoid blocking DNS lookups and can improve tracker/DHT-heavy workloads when curl is built with AsynchDNS support.")
|
||||||
print(" - curl: HTTP/HTTPS transfer library used by libtorrent for tracker/web requests. Building a fresh curl can provide newer TLS/HTTP fixes and c-ares based async DNS.")
|
print(" - curl: HTTP/HTTPS transfer library used by libtorrent for tracker/web requests. Building a fresh curl can provide newer TLS/HTTP fixes and c-ares based async DNS.")
|
||||||
print(" - minimal build: builds only xmlrpc-c, libtorrent and rTorrent; it uses the system libraries already available on Debian.")
|
print(" - minimal build: builds only libtorrent and rTorrent; it uses the system libraries already available on Debian/RHEL.")
|
||||||
|
|
||||||
|
|
||||||
def resolve_optional_build_mode(args):
|
def resolve_optional_build_mode(args):
|
||||||
@@ -741,26 +752,36 @@ def verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_instal
|
|||||||
print("c-ares is not visible in libtorrent ldd; this can still be valid when libcurl is resolved differently.")
|
print("c-ares is not visible in libtorrent ldd; this can still be valid when libcurl is resolved differently.")
|
||||||
|
|
||||||
|
|
||||||
def verify_install(base_dir, rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=None, cares_install=None, *, debug=False):
|
def verify_install(base_dir, rtorrent_install, libtorrent_install, rpc_backend, xmlrpc_install=None, curl_install=None, cares_install=None, *, debug=False):
|
||||||
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
||||||
which_rtorrent = capture(["which", "rtorrent"], check=False, debug=debug) or "not found in PATH"
|
which_rtorrent = capture(["which", "rtorrent"], check=False, debug=debug) or "not found in PATH"
|
||||||
print(f"Resolved rtorrent from PATH: {which_rtorrent}")
|
print(f"Resolved rtorrent from PATH: {which_rtorrent}")
|
||||||
|
|
||||||
linked = capture(["ldd", str(rtorrent_bin)], check=True, debug=debug)
|
linked = capture(["ldd", str(rtorrent_bin)], check=True, debug=debug)
|
||||||
for libname, expected in [("libtorrent", str(Path(libtorrent_install) / "lib")), ("xmlrpc", str(Path(xmlrpc_install) / "lib"))]:
|
checks = [("libtorrent", str(Path(libtorrent_install) / "lib"))]
|
||||||
|
if rpc_backend == "xmlrpc-c":
|
||||||
|
checks.append(("xmlrpc", str(Path(xmlrpc_install) / "lib")))
|
||||||
|
for libname, expected in checks:
|
||||||
lines = [line for line in linked.splitlines() if libname in line]
|
lines = [line for line in linked.splitlines() if libname in line]
|
||||||
print_link_lines(f"Linked {libname} lines:", lines)
|
print_link_lines(f"Linked {libname} lines:", lines)
|
||||||
if not any(expected in line for line in lines):
|
if not any(expected in line for line in lines):
|
||||||
raise InstallError(f"rtorrent does not appear to be linked against the compiled {libname} from {expected}.")
|
raise InstallError(f"rtorrent does not appear to be linked against the compiled {libname} from {expected}.")
|
||||||
|
if rpc_backend == "tinyxml2":
|
||||||
|
tinyxml_lines = [line for line in linked.splitlines() if "tinyxml2" in line.lower()]
|
||||||
|
print_link_lines("Linked tinyxml2 lines:", tinyxml_lines)
|
||||||
|
if not tinyxml_lines:
|
||||||
|
raise InstallError("rTorrent does not appear to be linked against tinyxml2.")
|
||||||
|
|
||||||
if curl_install:
|
if curl_install:
|
||||||
verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_install, cares_install, debug=debug)
|
verify_libtorrent_curl_integration(base_dir, libtorrent_install, curl_install, cares_install, debug=debug)
|
||||||
|
|
||||||
env = build_env(libtorrent_install, xmlrpc_install, curl_install, cares_install)
|
env = build_env(libtorrent_install, xmlrpc_install if rpc_backend == "xmlrpc-c" else None, curl_install, cares_install)
|
||||||
env["LANG"] = "C"
|
env["LANG"] = "C"
|
||||||
env["LC_ALL"] = "C"
|
env["LC_ALL"] = "C"
|
||||||
env["TERM"] = env.get("TERM", "xterm")
|
env["TERM"] = env.get("TERM", "xterm")
|
||||||
ld_paths = [str(Path(libtorrent_install) / "lib"), str(Path(xmlrpc_install) / "lib")]
|
ld_paths = [str(Path(libtorrent_install) / "lib")]
|
||||||
|
if rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
ld_paths.append(str(Path(xmlrpc_install) / "lib"))
|
||||||
if curl_install:
|
if curl_install:
|
||||||
ld_paths.append(str(Path(curl_install) / "lib"))
|
ld_paths.append(str(Path(curl_install) / "lib"))
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -777,11 +798,12 @@ def verify_install(base_dir, rtorrent_install, libtorrent_install, xmlrpc_instal
|
|||||||
|
|
||||||
|
|
||||||
def build_parser():
|
def build_parser():
|
||||||
parser = argparse.ArgumentParser(description="RHEL-compatible installer for xmlrpc-c + libtorrent + rTorrent under /opt with optional c-ares/custom curl support.")
|
parser = argparse.ArgumentParser(description="RHEL-compatible installer for libtorrent + rTorrent under /opt. RPC defaults to tinyxml2; xmlrpc-c is optional.")
|
||||||
parser.add_argument("--base-dir", default=DEFAULT_BASE_DIR, help=f"Base build/install directory (default: {DEFAULT_BASE_DIR})")
|
parser.add_argument("--base-dir", default=DEFAULT_BASE_DIR, help=f"Base build/install directory (default: {DEFAULT_BASE_DIR})")
|
||||||
parser.add_argument("--libtorrent-ref", default=DEFAULT_LIBTORRENT_REF, help=f"Git branch, tag or commit for libtorrent (default: {DEFAULT_LIBTORRENT_REF})")
|
parser.add_argument("--libtorrent-ref", default=DEFAULT_LIBTORRENT_REF, help=f"Git branch, tag or commit for libtorrent (default: {DEFAULT_LIBTORRENT_REF})")
|
||||||
parser.add_argument("--rtorrent-ref", default=DEFAULT_RTORRENT_REF, help=f"Git branch, tag or commit for rtorrent (default: {DEFAULT_RTORRENT_REF})")
|
parser.add_argument("--rtorrent-ref", default=DEFAULT_RTORRENT_REF, help=f"Git branch, tag or commit for rtorrent (default: {DEFAULT_RTORRENT_REF})")
|
||||||
parser.add_argument("--xmlrpc-ref", default=DEFAULT_XMLRPC_REF, help="xmlrpc-c source version or URL (default: latest-stable)")
|
parser.add_argument("--xmlrpc-ref", default=DEFAULT_XMLRPC_REF, help="xmlrpc-c source version or URL. Used only with --with-xmlrpc-c (default: latest-stable)")
|
||||||
|
parser.add_argument("--with-xmlrpc-c", action="store_true", help="Build rTorrent with classic xmlrpc-c instead of the default tinyxml2 XML-RPC backend.")
|
||||||
parser.add_argument("--cares-ref", default=DEFAULT_CARES_REF, help=f"c-ares release version (default: {DEFAULT_CARES_REF})")
|
parser.add_argument("--cares-ref", default=DEFAULT_CARES_REF, help=f"c-ares release version (default: {DEFAULT_CARES_REF})")
|
||||||
parser.add_argument("--curl-ref", default=DEFAULT_CURL_REF, help=f"curl release version (default: {DEFAULT_CURL_REF})")
|
parser.add_argument("--curl-ref", default=DEFAULT_CURL_REF, help=f"curl release version (default: {DEFAULT_CURL_REF})")
|
||||||
parser.add_argument("--user", default=DEFAULT_USER, help=f"System user for the service (default: {DEFAULT_USER})")
|
parser.add_argument("--user", default=DEFAULT_USER, help=f"System user for the service (default: {DEFAULT_USER})")
|
||||||
@@ -793,7 +815,7 @@ def build_parser():
|
|||||||
parser.add_argument("--only-build", action="store_true", help="Only build and install libtorrent/rTorrent under /opt. Skip user, config and systemd.")
|
parser.add_argument("--only-build", action="store_true", help="Only build and install libtorrent/rTorrent under /opt. Skip user, config and systemd.")
|
||||||
parser.add_argument("--yes", action="store_true", help="Assume yes for interactive prompts; optional c-ares/curl remain disabled unless --with-curl or --with-cares is used.")
|
parser.add_argument("--yes", action="store_true", help="Assume yes for interactive prompts; optional c-ares/curl remain disabled unless --with-curl or --with-cares is used.")
|
||||||
parser.add_argument("--debug", action="store_true", help="Show full command output during build steps.")
|
parser.add_argument("--debug", action="store_true", help="Show full command output during build steps.")
|
||||||
parser.add_argument("--minimal", "--core-only", action="store_true", help="Build only xmlrpc-c, libtorrent and rTorrent. Do not build c-ares or custom curl.")
|
parser.add_argument("--minimal", "--core-only", action="store_true", help="Build only libtorrent and rTorrent. Do not build c-ares or custom curl.")
|
||||||
parser.add_argument("--no-cares", "--without-cares", dest="no_cares", action="store_true", help="Do not build c-ares. This also disables custom curl integration.")
|
parser.add_argument("--no-cares", "--without-cares", dest="no_cares", action="store_true", help="Do not build c-ares. This also disables custom curl integration.")
|
||||||
parser.add_argument("--no-curl", "--without-curl", dest="no_curl", action="store_true", help="Do not build custom curl. Implies no c-ares integration for libtorrent.")
|
parser.add_argument("--no-curl", "--without-curl", dest="no_curl", action="store_true", help="Do not build custom curl. Implies no c-ares integration for libtorrent.")
|
||||||
parser.add_argument("--with-cares", action="store_true", help="Build c-ares and custom curl with asynchronous DNS support.")
|
parser.add_argument("--with-cares", action="store_true", help="Build c-ares and custom curl with asynchronous DNS support.")
|
||||||
@@ -811,14 +833,20 @@ def main():
|
|||||||
|
|
||||||
packages = [
|
packages = [
|
||||||
"gcc", "gcc-c++", "make", "pkgconf-pkg-config", "libtool", "autoconf", "automake", "git", "ca-certificates",
|
"gcc", "gcc-c++", "make", "pkgconf-pkg-config", "libtool", "autoconf", "automake", "git", "ca-certificates",
|
||||||
"openssl-devel", "ncurses-devel", "expat-devel", "curl", "libcurl-devel", "tar", "gzip", "zlib-devel", "which",
|
"openssl-devel", "ncurses-devel", "expat-devel", "tinyxml2-devel", "curl", "libcurl-devel", "tar", "gzip", "zlib-devel", "which",
|
||||||
"patch", "diffutils", "findutils", "file", "redhat-rpm-config", "libstdc++-devel"
|
"patch", "diffutils", "findutils", "file", "redhat-rpm-config", "libstdc++-devel"
|
||||||
]
|
]
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
packages.extend(["cmake", "libpsl-devel", "brotli-devel", "libzstd-devel"])
|
packages.extend(["cmake", "libpsl-devel", "brotli-devel", "libzstd-devel"])
|
||||||
|
|
||||||
print("This script will:")
|
print("This script will:")
|
||||||
print(f" - build xmlrpc-c from '{args.xmlrpc_ref}'")
|
args.rpc_backend = "xmlrpc-c" if args.with_xmlrpc_c else DEFAULT_RPC_BACKEND
|
||||||
|
|
||||||
|
print(f" - use rTorrent RPC backend: {args.rpc_backend}")
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
print(f" - build xmlrpc-c from '{args.xmlrpc_ref}'")
|
||||||
|
else:
|
||||||
|
print(" - use system tinyxml2 for XML-RPC")
|
||||||
print(f" - build libtorrent from '{args.libtorrent_ref}'")
|
print(f" - build libtorrent from '{args.libtorrent_ref}'")
|
||||||
print(f" - build rtorrent from '{args.rtorrent_ref}'")
|
print(f" - build rtorrent from '{args.rtorrent_ref}'")
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
@@ -827,7 +855,7 @@ def main():
|
|||||||
print(" - benefit: async DNS via c-ares and newer curl for HTTP/HTTPS tracker requests")
|
print(" - benefit: async DNS via c-ares and newer curl for HTTP/HTTPS tracker requests")
|
||||||
else:
|
else:
|
||||||
print(" - minimal build: skip c-ares/custom curl")
|
print(" - minimal build: skip c-ares/custom curl")
|
||||||
print(" - build only xmlrpc-c, libtorrent and rTorrent; use RHEL system libraries")
|
print(" - build only libtorrent and rTorrent; use RHEL system libraries")
|
||||||
print(f" - install everything under '{args.base_dir}'")
|
print(f" - install everything under '{args.base_dir}'")
|
||||||
if args.only_build:
|
if args.only_build:
|
||||||
print(" - skip service user, config and systemd setup")
|
print(" - skip service user, config and systemd setup")
|
||||||
@@ -842,7 +870,10 @@ def main():
|
|||||||
ensure_packages(packages, debug=args.debug)
|
ensure_packages(packages, debug=args.debug)
|
||||||
ensure_dir(args.base_dir)
|
ensure_dir(args.base_dir)
|
||||||
|
|
||||||
xmlrpc_install, xmlrpc_version = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref, debug=args.debug)
|
xmlrpc_install = None
|
||||||
|
xmlrpc_version = None
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
xmlrpc_install, xmlrpc_version = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref, debug=args.debug)
|
||||||
|
|
||||||
cares_install = None
|
cares_install = None
|
||||||
cares_version = None
|
cares_version = None
|
||||||
@@ -857,12 +888,12 @@ def main():
|
|||||||
args.base_dir, args.libtorrent_ref, curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
args.base_dir, args.libtorrent_ref, curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
||||||
)
|
)
|
||||||
rtorrent_install, rtorrent_version = build_rtorrent(
|
rtorrent_install, rtorrent_version = build_rtorrent(
|
||||||
args.base_dir, args.rtorrent_ref, libtorrent_install, xmlrpc_install, curl_install=curl_install,
|
args.base_dir, args.rtorrent_ref, libtorrent_install, args.rpc_backend, xmlrpc_install=xmlrpc_install,
|
||||||
cares_install=cares_install, debug=args.debug
|
curl_install=curl_install, cares_install=cares_install, debug=args.debug
|
||||||
)
|
)
|
||||||
|
|
||||||
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install=xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
||||||
verify_install(args.base_dir, rtorrent_install, libtorrent_install, xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
verify_install(args.base_dir, rtorrent_install, libtorrent_install, args.rpc_backend, xmlrpc_install=xmlrpc_install, curl_install=curl_install, cares_install=cares_install, debug=args.debug)
|
||||||
|
|
||||||
if not args.only_build:
|
if not args.only_build:
|
||||||
create_system_user(args.user, args.group, args.home, assume_yes=args.yes, debug=args.debug)
|
create_system_user(args.user, args.group, args.home, assume_yes=args.yes, debug=args.debug)
|
||||||
@@ -870,7 +901,9 @@ def main():
|
|||||||
bind_address_directive = rtorrent_bind_address_directive(args.rtorrent_ref, rtorrent_version)
|
bind_address_directive = rtorrent_bind_address_directive(args.rtorrent_ref, rtorrent_version)
|
||||||
print(f"Using rTorrent bind address directive: {bind_address_directive}")
|
print(f"Using rTorrent bind address directive: {bind_address_directive}")
|
||||||
write_rtorrent_config(args.home, args.user, args.scgi_port, args.torrent_port, bind_address_directive, force_config=args.force_config)
|
write_rtorrent_config(args.home, args.user, args.scgi_port, args.torrent_port, bind_address_directive, force_config=args.force_config)
|
||||||
runtime_lib_dirs = [f"{libtorrent_install}/lib", f"{xmlrpc_install}/lib"]
|
runtime_lib_dirs = [f"{libtorrent_install}/lib"]
|
||||||
|
if args.rpc_backend == "xmlrpc-c" and xmlrpc_install:
|
||||||
|
runtime_lib_dirs.append(f"{xmlrpc_install}/lib")
|
||||||
if curl_install:
|
if curl_install:
|
||||||
runtime_lib_dirs.append(f"{curl_install}/lib")
|
runtime_lib_dirs.append(f"{curl_install}/lib")
|
||||||
if cares_install:
|
if cares_install:
|
||||||
@@ -881,7 +914,9 @@ def main():
|
|||||||
|
|
||||||
print("\nBuild summary")
|
print("\nBuild summary")
|
||||||
print("-------------")
|
print("-------------")
|
||||||
print(f"xmlrpc-c: {xmlrpc_version}")
|
print(f"rpc: {args.rpc_backend}")
|
||||||
|
if args.rpc_backend == "xmlrpc-c":
|
||||||
|
print(f"xmlrpc-c: {xmlrpc_version}")
|
||||||
print(f"libtorrent: {libtorrent_version}")
|
print(f"libtorrent: {libtorrent_version}")
|
||||||
print(f"rtorrent: {rtorrent_version.splitlines()[0] if rtorrent_version else args.rtorrent_ref}")
|
print(f"rtorrent: {rtorrent_version.splitlines()[0] if rtorrent_version else args.rtorrent_ref}")
|
||||||
if args.use_cares:
|
if args.use_cares:
|
||||||
|
|||||||
+208
@@ -0,0 +1,208 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# One-command installer for rTorrent + pyTorrent on Arch Linux.
|
||||||
|
# Arch uses current repository packages by default. Source build is opt-in.
|
||||||
|
|
||||||
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
|
echo "Run as root: sudo $0" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
|
||||||
|
RTORRENT_USER="${RTORRENT_USER:-rtorrent}"
|
||||||
|
RTORRENT_HOME="${RTORRENT_HOME:-/home/${RTORRENT_USER}}"
|
||||||
|
RTORRENT_BASE_DIR="${RTORRENT_BASE_DIR:-/opt/rtorrent_build}"
|
||||||
|
RTORRENT_SCGI_PORT="${RTORRENT_SCGI_PORT:-5000}"
|
||||||
|
RTORRENT_TORRENT_PORT="${RTORRENT_TORRENT_PORT:-51300}"
|
||||||
|
RTORRENT_REF="${RTORRENT_REF:-v0.16.11}"
|
||||||
|
LIBTORRENT_REF="${LIBTORRENT_REF:-v0.16.11}"
|
||||||
|
PYTORRENT_APP_DIR="${PYTORRENT_APP_DIR:-/opt/pytorrent}"
|
||||||
|
PYTORRENT_PORT="${PYTORRENT_PORT:-8090}"
|
||||||
|
PYTORRENT_BASE_URL="${PYTORRENT_BASE_URL:-http://127.0.0.1:${PYTORRENT_PORT}}"
|
||||||
|
PYTORRENT_PROFILE_NAME="${PYTORRENT_PROFILE_NAME:-Local rTorrent}"
|
||||||
|
PYTORRENT_API_TOKEN="${PYTORRENT_API_TOKEN:-}"
|
||||||
|
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME:-pytorrent}"
|
||||||
|
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL:-scgi://127.0.0.1:${RTORRENT_SCGI_PORT}}"
|
||||||
|
RTORRENT_BUILD_FROM_SOURCE="${RTORRENT_BUILD_FROM_SOURCE:-0}"
|
||||||
|
RTORRENT_FORCE_CONFIG="${RTORRENT_FORCE_CONFIG:-1}"
|
||||||
|
|
||||||
|
RTORRENT_EXTRA_ARGS=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--build-rtorrent|--build-from-source|--compile-rtorrent)
|
||||||
|
RTORRENT_BUILD_FROM_SOURCE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--with-xmlrpc-c)
|
||||||
|
RTORRENT_BUILD_FROM_SOURCE=1
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
echo "Supported options: --build-rtorrent, --with-xmlrpc-c" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ "${RTORRENT_WITH_XMLRPC_C:-0}" == "1" ]]; then
|
||||||
|
RTORRENT_BUILD_FROM_SOURCE=1
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
fi
|
||||||
|
|
||||||
|
command -v pacman >/dev/null 2>&1 || { echo "pacman is required on Arch Linux." >&2; exit 1; }
|
||||||
|
pacman -Sy --noconfirm --needed ca-certificates curl tar gzip sudo python python-pip git rsync rtorrent
|
||||||
|
|
||||||
|
ensure_rtorrent_user() {
|
||||||
|
if ! getent group "${RTORRENT_USER}" >/dev/null; then
|
||||||
|
groupadd --system "${RTORRENT_USER}"
|
||||||
|
fi
|
||||||
|
if ! id "${RTORRENT_USER}" >/dev/null 2>&1; then
|
||||||
|
local shell="/usr/bin/nologin"
|
||||||
|
[[ -x "${shell}" ]] || shell="/sbin/nologin"
|
||||||
|
useradd --system --gid "${RTORRENT_USER}" --home-dir "${RTORRENT_HOME}" --create-home --shell "${shell}" "${RTORRENT_USER}"
|
||||||
|
fi
|
||||||
|
mkdir -p "${RTORRENT_HOME}/downloads" "${RTORRENT_HOME}/.session" "${RTORRENT_HOME}/watch"
|
||||||
|
chown -R "${RTORRENT_USER}:${RTORRENT_USER}" "${RTORRENT_HOME}"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_rtorrent_config() {
|
||||||
|
local config="${RTORRENT_HOME}/.rtorrent.rc"
|
||||||
|
if [[ -f "${config}" && "${RTORRENT_FORCE_CONFIG}" != "1" ]]; then
|
||||||
|
echo "Keeping existing config: ${config}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
cat > "${config}" <<EOF_CONFIG
|
||||||
|
directory.default.set = ${RTORRENT_HOME}/downloads
|
||||||
|
session.path.set = ${RTORRENT_HOME}/.session
|
||||||
|
encoding.add = UTF-8
|
||||||
|
|
||||||
|
network.scgi.open_port = 127.0.0.1:${RTORRENT_SCGI_PORT}
|
||||||
|
network.port_range.set = ${RTORRENT_TORRENT_PORT}-${RTORRENT_TORRENT_PORT}
|
||||||
|
network.port_random.set = no
|
||||||
|
network.bind_address.ipv4.set = 0.0.0.0
|
||||||
|
|
||||||
|
system.file.allocate.set = 0
|
||||||
|
system.umask.set = 0022
|
||||||
|
|
||||||
|
dht.mode.set = disable
|
||||||
|
protocol.pex.set = no
|
||||||
|
trackers.use_udp.set = no
|
||||||
|
protocol.encryption.set = allow_incoming,enable_retry,prefer_plaintext
|
||||||
|
|
||||||
|
schedule2 = session_save,300,300,((session.save))
|
||||||
|
schedule2 = watch_directory,60,60,load.normal=${RTORRENT_HOME}/watch/*.torrent
|
||||||
|
|
||||||
|
ratio.max.set = -1
|
||||||
|
network.xmlrpc.size_limit.set = 33554432
|
||||||
|
|
||||||
|
network.http.max_open.set = 64
|
||||||
|
network.max_open_sockets.set = 1024
|
||||||
|
network.max_open_files.set = 8192
|
||||||
|
network.http.dns_cache_timeout.set = 25
|
||||||
|
network.http.ssl_verify_peer.set = 0
|
||||||
|
|
||||||
|
network.send_buffer.size.set = 4M
|
||||||
|
network.receive_buffer.size.set = 4M
|
||||||
|
|
||||||
|
throttle.min_peers.normal.set = 30
|
||||||
|
throttle.max_peers.normal.set = 150
|
||||||
|
throttle.min_peers.seed.set = -1
|
||||||
|
throttle.max_peers.seed.set = -1
|
||||||
|
throttle.max_downloads.global.set = 300
|
||||||
|
throttle.max_uploads.global.set = 300
|
||||||
|
throttle.max_downloads.set = 20
|
||||||
|
throttle.max_uploads.set = 20
|
||||||
|
|
||||||
|
trackers.numwant.set = 80
|
||||||
|
pieces.hash.on_completion.set = 0
|
||||||
|
EOF_CONFIG
|
||||||
|
chown "${RTORRENT_USER}:${RTORRENT_USER}" "${config}"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_rtorrent_service() {
|
||||||
|
cat > /etc/systemd/system/rtorrent@.service <<EOF_SERVICE
|
||||||
|
[Unit]
|
||||||
|
Description=rTorrent for %I
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=%I
|
||||||
|
Group=%I
|
||||||
|
KillMode=process
|
||||||
|
WorkingDirectory=${RTORRENT_HOME}
|
||||||
|
ExecStartPre=-/bin/rm -f ${RTORRENT_HOME}/.session/rtorrent.lock
|
||||||
|
ExecStart=/usr/bin/rtorrent -o system.daemon.set=true -n -o import=${RTORRENT_HOME}/.rtorrent.rc
|
||||||
|
KillSignal=SIGTERM
|
||||||
|
TimeoutStopSec=300
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
LimitNOFILE=1048576
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF_SERVICE
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now "rtorrent@${RTORRENT_USER}.service"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${RTORRENT_BUILD_FROM_SOURCE}" == "1" ]]; then
|
||||||
|
pacman -Sy --noconfirm --needed gcc pkgconf base-devel automake autoconf libtool make patch diffutils file openssl ncurses expat curl tinyxml2 readline libxml2
|
||||||
|
RTORRENT_INSTALL_ARGS=(
|
||||||
|
--yes
|
||||||
|
--minimal
|
||||||
|
"${RTORRENT_EXTRA_ARGS[@]}"
|
||||||
|
)
|
||||||
|
if [[ "${PYTORRENT_DEBUG_INSTALL:-0}" == "1" ]]; then
|
||||||
|
RTORRENT_INSTALL_ARGS+=(--debug)
|
||||||
|
fi
|
||||||
|
|
||||||
|
python "${SCRIPT_DIR}/install_rtorrent.py" \
|
||||||
|
"${RTORRENT_INSTALL_ARGS[@]}" \
|
||||||
|
--force-config \
|
||||||
|
--base-dir "${RTORRENT_BASE_DIR}" \
|
||||||
|
--user "${RTORRENT_USER}" \
|
||||||
|
--group "${RTORRENT_USER}" \
|
||||||
|
--home "${RTORRENT_HOME}" \
|
||||||
|
--scgi-port "${RTORRENT_SCGI_PORT}" \
|
||||||
|
--torrent-port "${RTORRENT_TORRENT_PORT}" \
|
||||||
|
--rtorrent-ref "${RTORRENT_REF}" \
|
||||||
|
--libtorrent-ref "${LIBTORRENT_REF}"
|
||||||
|
else
|
||||||
|
ensure_rtorrent_user
|
||||||
|
write_rtorrent_config
|
||||||
|
write_rtorrent_service
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "${PROJECT_DIR}"
|
||||||
|
PYTORRENT_APP_DIR="${PYTORRENT_APP_DIR}" \
|
||||||
|
PYTORRENT_PORT="${PYTORRENT_PORT}" \
|
||||||
|
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME}" \
|
||||||
|
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL}" \
|
||||||
|
bash "${PROJECT_DIR}/scripts/install_pytorrent_only.sh" \
|
||||||
|
--yes \
|
||||||
|
--app-dir "${PYTORRENT_APP_DIR}" \
|
||||||
|
--port "${PYTORRENT_PORT}" \
|
||||||
|
--service-name "${PYTORRENT_SERVICE_NAME}" \
|
||||||
|
--profile-name "${PYTORRENT_PROFILE_NAME}" \
|
||||||
|
--scgi-url "${PYTORRENT_RTORRENT_SCGI_URL}"
|
||||||
|
|
||||||
|
if [[ -n "${PYTORRENT_API_TOKEN}" ]]; then
|
||||||
|
"${PYTORRENT_APP_DIR}/venv/bin/python" "${PYTORRENT_APP_DIR}/scripts/stack_installers/configure_pytorrent_api.py" \
|
||||||
|
--base-url "${PYTORRENT_BASE_URL}" \
|
||||||
|
--profile-name "${PYTORRENT_PROFILE_NAME}" \
|
||||||
|
--scgi-url "${PYTORRENT_RTORRENT_SCGI_URL}" \
|
||||||
|
--api-token "${PYTORRENT_API_TOKEN}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${RTORRENT_BUILD_FROM_SOURCE}" == "1" ]]; then
|
||||||
|
RTORRENT_MODE="source build"
|
||||||
|
else
|
||||||
|
RTORRENT_MODE="Arch pacman package"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Done. pyTorrent: ${PYTORRENT_BASE_URL} | rTorrent SCGI: ${PYTORRENT_RTORRENT_SCGI_URL} | rTorrent: ${RTORRENT_MODE}"
|
||||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
# One-command installer for rTorrent + pyTorrent on Debian/Ubuntu.
|
# One-command installer for rTorrent + pyTorrent on Debian/Ubuntu.
|
||||||
# Notes:
|
# Notes:
|
||||||
# - rTorrent is built as a minimal v0.16.11 install by default.
|
# - rTorrent is built as a minimal v0.16.11 install with tinyxml2 XML-RPC by default.
|
||||||
# - pyTorrent is configured through its HTTP API after the service starts.
|
# - pyTorrent is configured through its HTTP API after the service starts.
|
||||||
|
|
||||||
if [[ "${EUID}" -ne 0 ]]; then
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
@@ -29,6 +29,23 @@ PYTORRENT_API_TOKEN="${PYTORRENT_API_TOKEN:-}"
|
|||||||
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME:-pytorrent}"
|
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME:-pytorrent}"
|
||||||
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL:-scgi://127.0.0.1:${RTORRENT_SCGI_PORT}}"
|
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL:-scgi://127.0.0.1:${RTORRENT_SCGI_PORT}}"
|
||||||
|
|
||||||
|
RTORRENT_EXTRA_ARGS=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--with-xmlrpc-c)
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ "${RTORRENT_WITH_XMLRPC_C:-0}" == "1" ]]; then
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
fi
|
||||||
|
|
||||||
export PYTORRENT_APP_DIR PYTORRENT_PORT PYTORRENT_SERVICE_NAME PYTORRENT_API_TOKEN
|
export PYTORRENT_APP_DIR PYTORRENT_PORT PYTORRENT_SERVICE_NAME PYTORRENT_API_TOKEN
|
||||||
|
|
||||||
install_debian_stack_prerequisites() {
|
install_debian_stack_prerequisites() {
|
||||||
@@ -59,6 +76,7 @@ install_debian_stack_prerequisites() {
|
|||||||
libexpat1-dev \
|
libexpat1-dev \
|
||||||
libcurl4-openssl-dev \
|
libcurl4-openssl-dev \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
|
libtinyxml2-dev \
|
||||||
libreadline-dev \
|
libreadline-dev \
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
bison \
|
bison \
|
||||||
@@ -78,6 +96,7 @@ install_debian_stack_prerequisites
|
|||||||
RTORRENT_INSTALL_ARGS=(
|
RTORRENT_INSTALL_ARGS=(
|
||||||
--yes
|
--yes
|
||||||
--minimal
|
--minimal
|
||||||
|
"${RTORRENT_EXTRA_ARGS[@]}"
|
||||||
)
|
)
|
||||||
if [[ "${PYTORRENT_DEBUG_INSTALL:-0}" == "1" ]]; then
|
if [[ "${PYTORRENT_DEBUG_INSTALL:-0}" == "1" ]]; then
|
||||||
RTORRENT_INSTALL_ARGS+=(--debug)
|
RTORRENT_INSTALL_ARGS+=(--debug)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
# One-command installer for rTorrent + pyTorrent on RHEL-compatible systems.
|
# One-command installer for rTorrent + pyTorrent on RHEL-compatible systems.
|
||||||
# Notes:
|
# Notes:
|
||||||
# - rTorrent is built as a minimal v0.16.11 install by default.
|
# - rTorrent is built as a minimal v0.16.11 install with tinyxml2 XML-RPC by default.
|
||||||
# - pyTorrent is configured through its HTTP API after the service starts.
|
# - pyTorrent is configured through its HTTP API after the service starts.
|
||||||
|
|
||||||
if [[ "${EUID}" -ne 0 ]]; then
|
if [[ "${EUID}" -ne 0 ]]; then
|
||||||
@@ -29,6 +29,23 @@ PYTORRENT_API_TOKEN="${PYTORRENT_API_TOKEN:-}"
|
|||||||
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME:-pytorrent}"
|
PYTORRENT_SERVICE_NAME="${PYTORRENT_SERVICE_NAME:-pytorrent}"
|
||||||
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL:-scgi://127.0.0.1:${RTORRENT_SCGI_PORT}}"
|
PYTORRENT_RTORRENT_SCGI_URL="${PYTORRENT_RTORRENT_SCGI_URL:-scgi://127.0.0.1:${RTORRENT_SCGI_PORT}}"
|
||||||
|
|
||||||
|
RTORRENT_EXTRA_ARGS=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--with-xmlrpc-c)
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [[ "${RTORRENT_WITH_XMLRPC_C:-0}" == "1" ]]; then
|
||||||
|
RTORRENT_EXTRA_ARGS+=(--with-xmlrpc-c)
|
||||||
|
fi
|
||||||
|
|
||||||
export PYTORRENT_APP_DIR PYTORRENT_PORT PYTORRENT_SERVICE_NAME PYTORRENT_API_TOKEN
|
export PYTORRENT_APP_DIR PYTORRENT_PORT PYTORRENT_SERVICE_NAME PYTORRENT_API_TOKEN
|
||||||
|
|
||||||
install_rhel_stack_prerequisites() {
|
install_rhel_stack_prerequisites() {
|
||||||
@@ -65,6 +82,7 @@ install_rhel_stack_prerequisites() {
|
|||||||
ncurses-devel \
|
ncurses-devel \
|
||||||
openssl-devel \
|
openssl-devel \
|
||||||
expat-devel \
|
expat-devel \
|
||||||
|
tinyxml2-devel \
|
||||||
zlib-devel \
|
zlib-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
redhat-rpm-config \
|
redhat-rpm-config \
|
||||||
@@ -81,6 +99,7 @@ install_rhel_stack_prerequisites
|
|||||||
RTORRENT_INSTALL_ARGS=(
|
RTORRENT_INSTALL_ARGS=(
|
||||||
--yes
|
--yes
|
||||||
--minimal
|
--minimal
|
||||||
|
"${RTORRENT_EXTRA_ARGS[@]}"
|
||||||
--force-config
|
--force-config
|
||||||
)
|
)
|
||||||
if [[ "${PYTORRENT_DEBUG_INSTALL:-0}" == "1" ]]; then
|
if [[ "${PYTORRENT_DEBUG_INSTALL:-0}" == "1" ]]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user