Update install_rtorrent.py
This commit is contained in:
@@ -70,8 +70,8 @@ def detect_debian():
|
|||||||
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" and "debian" not in distro_like:
|
||||||
raise InstallError(
|
raise InstallError(
|
||||||
f"Unsupported distribution: ID={data.get('ID', 'unknown')}, ID_LIKE={data.get('ID_LIKE', 'unknown')}. "
|
f"Unsupported distribution: ID={data.get('ID', 'unknown')}, "
|
||||||
"This installer currently supports Debian only."
|
f"ID_LIKE={data.get('ID_LIKE', 'unknown')}. This installer currently supports Debian only."
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"Detected Debian-compatible system: {data.get('PRETTY_NAME', distro_id)}")
|
print(f"Detected Debian-compatible system: {data.get('PRETTY_NAME', distro_id)}")
|
||||||
@@ -99,19 +99,6 @@ def parse_version(version):
|
|||||||
return tuple(parts[:3]) if parts else (0,)
|
return tuple(parts[:3]) if parts else (0,)
|
||||||
|
|
||||||
|
|
||||||
def verify_xmlrpc_environment(xmlrpc_config_path):
|
|
||||||
tool = str(xmlrpc_config_path)
|
|
||||||
if not Path(tool).exists():
|
|
||||||
raise InstallError(f"xmlrpc-c-config was not found: {tool}")
|
|
||||||
|
|
||||||
version = capture([tool, "--version"], check=True)
|
|
||||||
if parse_version(version) < (1, 11):
|
|
||||||
raise InstallError(
|
|
||||||
f"xmlrpc-c version is too old: {version}. Version 1.11 or newer is required."
|
|
||||||
)
|
|
||||||
print(f"Detected xmlrpc-c version: {version}")
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_packages(packages):
|
def ensure_packages(packages):
|
||||||
print("Updating APT metadata...")
|
print("Updating APT metadata...")
|
||||||
run(["apt-get", "update"])
|
run(["apt-get", "update"])
|
||||||
@@ -144,7 +131,6 @@ def create_system_user(user, group, home, assume_yes=False):
|
|||||||
"--gid", group,
|
"--gid", group,
|
||||||
user,
|
user,
|
||||||
])
|
])
|
||||||
print(f"Created user '{user}'.")
|
|
||||||
|
|
||||||
|
|
||||||
def clone_or_update_repo(repo_url, repo_dir, ref):
|
def clone_or_update_repo(repo_url, repo_dir, ref):
|
||||||
@@ -164,13 +150,61 @@ def download_file(url, destination):
|
|||||||
run(["curl", "-fL", url, "-o", str(destination)])
|
run(["curl", "-fL", url, "-o", str(destination)])
|
||||||
|
|
||||||
|
|
||||||
|
def find_xmlrpc_config(base_dir, preferred_install=None):
|
||||||
|
candidates = []
|
||||||
|
|
||||||
|
if preferred_install is not None:
|
||||||
|
preferred = Path(preferred_install) / "bin" / "xmlrpc-c-config"
|
||||||
|
if preferred.exists():
|
||||||
|
candidates.append(preferred.resolve())
|
||||||
|
|
||||||
|
root = Path(base_dir)
|
||||||
|
if root.exists():
|
||||||
|
for match in root.rglob("xmlrpc-c-config"):
|
||||||
|
if match.is_file():
|
||||||
|
candidates.append(match.resolve())
|
||||||
|
|
||||||
|
unique = []
|
||||||
|
seen = set()
|
||||||
|
for candidate in candidates:
|
||||||
|
if candidate not in seen:
|
||||||
|
seen.add(candidate)
|
||||||
|
unique.append(candidate)
|
||||||
|
|
||||||
|
if preferred_install is not None:
|
||||||
|
preferred_prefix = str(Path(preferred_install).resolve())
|
||||||
|
for candidate in unique:
|
||||||
|
if str(candidate).startswith(preferred_prefix):
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
return unique[0] if unique else None
|
||||||
|
|
||||||
|
|
||||||
|
def verify_xmlrpc_environment(xmlrpc_config_path):
|
||||||
|
tool = Path(xmlrpc_config_path)
|
||||||
|
if not tool.exists():
|
||||||
|
raise InstallError(f"xmlrpc-c-config was not found: {tool}")
|
||||||
|
|
||||||
|
version = capture([str(tool), "--version"], check=True)
|
||||||
|
if parse_version(version) < (1, 11):
|
||||||
|
raise InstallError(
|
||||||
|
f"xmlrpc-c version is too old: {version}. Version 1.11 or newer is required."
|
||||||
|
)
|
||||||
|
print(f"Detected xmlrpc-c version: {version} ({tool})")
|
||||||
|
|
||||||
|
|
||||||
def build_xmlrpc_c(base_dir, xmlrpc_ref):
|
def build_xmlrpc_c(base_dir, xmlrpc_ref):
|
||||||
source_root = Path(base_dir) / "xmlrpc-c-src"
|
source_root = Path(base_dir) / "xmlrpc-c-src"
|
||||||
install_dir = Path(base_dir) / "xmlrpc-c_install"
|
install_dir = Path(base_dir) / "xmlrpc-c_install"
|
||||||
build_root = Path(base_dir) / "_sources"
|
build_root = Path(base_dir) / "_sources"
|
||||||
tarball = build_root / "xmlrpc-c.tar.gz"
|
tarball = build_root / "xmlrpc-c.tar.gz"
|
||||||
|
|
||||||
ensure_dir(source_root)
|
existing_config = find_xmlrpc_config(base_dir, install_dir)
|
||||||
|
if existing_config and str(existing_config).startswith(str(install_dir.resolve())):
|
||||||
|
print(f"Reusing existing xmlrpc-c installation: {existing_config}")
|
||||||
|
verify_xmlrpc_environment(existing_config)
|
||||||
|
return install_dir
|
||||||
|
|
||||||
ensure_dir(build_root)
|
ensure_dir(build_root)
|
||||||
if source_root.exists():
|
if source_root.exists():
|
||||||
shutil.rmtree(source_root)
|
shutil.rmtree(source_root)
|
||||||
@@ -192,6 +226,14 @@ def build_xmlrpc_c(base_dir, xmlrpc_ref):
|
|||||||
run(["./configure", f"--prefix={install_dir}"], cwd=str(source_root))
|
run(["./configure", f"--prefix={install_dir}"], cwd=str(source_root))
|
||||||
run(["make", "-j", str(os.cpu_count() or 1)], cwd=str(source_root))
|
run(["make", "-j", str(os.cpu_count() or 1)], cwd=str(source_root))
|
||||||
run(["make", "install"], cwd=str(source_root))
|
run(["make", "install"], cwd=str(source_root))
|
||||||
|
|
||||||
|
xmlrpc_config = find_xmlrpc_config(base_dir, install_dir)
|
||||||
|
if not xmlrpc_config or not str(xmlrpc_config).startswith(str(install_dir.resolve())):
|
||||||
|
raise InstallError(
|
||||||
|
f"Custom xmlrpc-c build finished, but xmlrpc-c-config was not found under {install_dir}."
|
||||||
|
)
|
||||||
|
|
||||||
|
verify_xmlrpc_environment(xmlrpc_config)
|
||||||
return install_dir
|
return install_dir
|
||||||
|
|
||||||
|
|
||||||
@@ -213,6 +255,19 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install):
|
|||||||
|
|
||||||
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref)
|
clone_or_update_repo("https://github.com/rakshasa/rtorrent.git", source_dir, rtorrent_ref)
|
||||||
|
|
||||||
|
xmlrpc_config = find_xmlrpc_config(base_dir, xmlrpc_install)
|
||||||
|
if not xmlrpc_config:
|
||||||
|
raise InstallError(
|
||||||
|
f"Could not find custom xmlrpc-c-config under {base_dir}. "
|
||||||
|
"Build xmlrpc-c first or remove the broken installation and retry."
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
include_flags = f"-I{libtorrent_install}/include -I{xmlrpc_install}/include"
|
include_flags = f"-I{libtorrent_install}/include -I{xmlrpc_install}/include"
|
||||||
ld_flags = f"-L{libtorrent_install}/lib -L{xmlrpc_install}/lib"
|
ld_flags = f"-L{libtorrent_install}/lib -L{xmlrpc_install}/lib"
|
||||||
@@ -225,10 +280,18 @@ def build_rtorrent(base_dir, rtorrent_ref, libtorrent_install, xmlrpc_install):
|
|||||||
existing_pkg = env.get("PKG_CONFIG_PATH", "")
|
existing_pkg = env.get("PKG_CONFIG_PATH", "")
|
||||||
pkg_paths = [f"{libtorrent_install}/lib/pkgconfig", f"{xmlrpc_install}/lib/pkgconfig"]
|
pkg_paths = [f"{libtorrent_install}/lib/pkgconfig", f"{xmlrpc_install}/lib/pkgconfig"]
|
||||||
env["PKG_CONFIG_PATH"] = ":".join(pkg_paths + ([existing_pkg] if existing_pkg else []))
|
env["PKG_CONFIG_PATH"] = ":".join(pkg_paths + ([existing_pkg] if existing_pkg else []))
|
||||||
env["PATH"] = f"{xmlrpc_install}/bin:" + env.get("PATH", "")
|
env["PATH"] = f"{xmlrpc_config.parent}:" + env.get("PATH", "")
|
||||||
env["XMLRPC_C_CONFIG"] = str(Path(xmlrpc_install) / "bin" / "xmlrpc-c-config")
|
env["XMLRPC_C_CONFIG"] = str(xmlrpc_config)
|
||||||
|
|
||||||
|
resolved_xmlrpc_config = capture(["sh", "-c", "command -v xmlrpc-c-config"], env=env, check=False)
|
||||||
|
print(f"Resolved xmlrpc-c-config for build: {resolved_xmlrpc_config or 'not found'}")
|
||||||
|
if resolved_xmlrpc_config != str(xmlrpc_config):
|
||||||
|
raise InstallError(
|
||||||
|
f"Wrong xmlrpc-c-config selected: {resolved_xmlrpc_config or 'not found'}. Expected: {xmlrpc_config}"
|
||||||
|
)
|
||||||
|
|
||||||
run(["autoreconf", "-i"], cwd=str(source_dir), env=env)
|
run(["autoreconf", "-i"], cwd=str(source_dir), env=env)
|
||||||
|
run(["make", "distclean"], cwd=str(source_dir), env=env, check=False)
|
||||||
run([
|
run([
|
||||||
"./configure",
|
"./configure",
|
||||||
f"--prefix={install_dir}",
|
f"--prefix={install_dir}",
|
||||||
@@ -328,20 +391,29 @@ def verify_install(rtorrent_install, libtorrent_install, xmlrpc_install):
|
|||||||
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
rtorrent_bin = Path(rtorrent_install) / "bin" / "rtorrent"
|
||||||
which_rtorrent = capture(["which", "rtorrent"], check=False) or "not found in PATH"
|
which_rtorrent = capture(["which", "rtorrent"], check=False) 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)
|
linked = capture(["ldd", str(rtorrent_bin)], check=True)
|
||||||
matches = [line for line in linked.splitlines() if "libtorrent" in line]
|
libtorrent_lines = [line for line in linked.splitlines() if "libtorrent" in line]
|
||||||
print("Linked libtorrent lines:")
|
print("Linked libtorrent lines:")
|
||||||
for line in matches:
|
for line in libtorrent_lines:
|
||||||
print(line)
|
print(line)
|
||||||
expected = str(Path(libtorrent_install) / "lib")
|
expected_libtorrent = str(Path(libtorrent_install) / "lib")
|
||||||
if not any(expected in line for line in matches):
|
if not any(expected_libtorrent in line for line in libtorrent_lines):
|
||||||
raise InstallError("rtorrent does not appear to be linked against the compiled libtorrent from /opt.")
|
raise InstallError("rtorrent does not appear to be linked against the compiled libtorrent from /opt.")
|
||||||
|
|
||||||
|
xmlrpc_lines = [line for line in linked.splitlines() if "xmlrpc" in line]
|
||||||
|
print("Linked xmlrpc-c lines:")
|
||||||
|
for line in xmlrpc_lines:
|
||||||
|
print(line)
|
||||||
|
expected_xmlrpc = str(Path(xmlrpc_install) / "lib")
|
||||||
|
if not any(expected_xmlrpc in line for line in xmlrpc_lines):
|
||||||
|
raise InstallError("rtorrent does not appear to be linked against the compiled xmlrpc-c from /opt.")
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
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")
|
||||||
env["LD_LIBRARY_PATH"] = f"{Path(libtorrent_install) / "lib"}:{Path(xmlrpc_install) / "lib"}"
|
env["LD_LIBRARY_PATH"] = f"{Path(libtorrent_install) / 'lib'}:{Path(xmlrpc_install) / 'lib'}"
|
||||||
probe = subprocess.run(
|
probe = subprocess.run(
|
||||||
[str(rtorrent_bin), "-h"],
|
[str(rtorrent_bin), "-h"],
|
||||||
env=env,
|
env=env,
|
||||||
@@ -350,8 +422,8 @@ def verify_install(rtorrent_install, libtorrent_install, xmlrpc_install):
|
|||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
help_output = (probe.stdout or "") + "\n" + (probe.stderr or "")
|
help_output = ((probe.stdout or "") + "\n" + (probe.stderr or "")).lower()
|
||||||
if "xmlrpc-c" in help_output and "i8" in help_output.lower():
|
if "xmlrpc-c" in help_output and "i8" in help_output:
|
||||||
raise InstallError(
|
raise InstallError(
|
||||||
"rTorrent was built against an xmlrpc-c library without i8 support. "
|
"rTorrent was built against an xmlrpc-c library without i8 support. "
|
||||||
"Make sure the custom xmlrpc-c build is used and that no older local installation shadows it."
|
"Make sure the custom xmlrpc-c build is used and that no older local installation shadows it."
|
||||||
@@ -416,7 +488,6 @@ def main():
|
|||||||
ensure_dir(args.base_dir)
|
ensure_dir(args.base_dir)
|
||||||
|
|
||||||
xmlrpc_install = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref)
|
xmlrpc_install = build_xmlrpc_c(args.base_dir, args.xmlrpc_ref)
|
||||||
verify_xmlrpc_environment(Path(xmlrpc_install) / "bin" / "xmlrpc-c-config")
|
|
||||||
libtorrent_install = build_libtorrent(args.base_dir, args.libtorrent_ref)
|
libtorrent_install = build_libtorrent(args.base_dir, args.libtorrent_ref)
|
||||||
rtorrent_install = build_rtorrent(args.base_dir, args.rtorrent_ref, libtorrent_install, xmlrpc_install)
|
rtorrent_install = build_rtorrent(args.base_dir, args.rtorrent_ref, libtorrent_install, xmlrpc_install)
|
||||||
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install)
|
install_symlinks(rtorrent_install, libtorrent_install, xmlrpc_install)
|
||||||
@@ -426,13 +497,13 @@ def main():
|
|||||||
create_system_user(args.user, args.group, args.home, assume_yes=args.yes)
|
create_system_user(args.user, args.group, args.home, assume_yes=args.yes)
|
||||||
prepare_user_dirs(args.home, args.user)
|
prepare_user_dirs(args.home, args.user)
|
||||||
write_rtorrent_config(args.home, args.user)
|
write_rtorrent_config(args.home, args.user)
|
||||||
runtime_lib_dirs = f"{libtorrent_install / "lib"}:{xmlrpc_install / "lib"}"
|
runtime_lib_dirs = f"{libtorrent_install / 'lib'}:{xmlrpc_install / 'lib'}"
|
||||||
write_service(DEFAULT_SERVICE_PATH, "/usr/local/bin/rtorrent", runtime_lib_dirs)
|
write_service(DEFAULT_SERVICE_PATH, "/usr/local/bin/rtorrent", runtime_lib_dirs)
|
||||||
enable_service(args.user)
|
enable_service(args.user)
|
||||||
print(f"\nService status hint: systemctl status rtorrent@{args.user}.service")
|
print(f"\nService status hint: systemctl status rtorrent@{args.user}.service")
|
||||||
|
|
||||||
print("\nDone.")
|
print("\nDone.")
|
||||||
print(f"rtorrent binary: /usr/local/bin/rtorrent")
|
print("rtorrent binary: /usr/local/bin/rtorrent")
|
||||||
print(f"libtorrent path: {libtorrent_install / 'lib'}")
|
print(f"libtorrent path: {libtorrent_install / 'lib'}")
|
||||||
print(f"xmlrpc-c path: {xmlrpc_install / 'lib'}")
|
print(f"xmlrpc-c path: {xmlrpc_install / 'lib'}")
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
Reference in New Issue
Block a user