From 10869c695e10e88262243d3339c2a6f2ae9c7f68 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Mon, 11 May 2026 20:00:02 +0200 Subject: [PATCH] No longer use ~/solidlsp_tmp for storing temporary files Use tempfile-based files instead. Resolves #1468 --- CHANGELOG.md | 3 +++ .../language_servers/pascal_server.py | 14 ++++------ src/solidlsp/ls_utils.py | 26 +++++++++++-------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21fd058a..18bea251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Status of the `main` branch. Changes prior to the next official version change will appear here. +* Language Servers: + - No longer store temporary files (e.g. downloads) in `~/solidlsp_tmp`; instead, use OS-specific temporary directories + # v1.3.0 (2026-05-11) * General: diff --git a/src/solidlsp/language_servers/pascal_server.py b/src/solidlsp/language_servers/pascal_server.py index 34c6ff73..1f1488e7 100644 --- a/src/solidlsp/language_servers/pascal_server.py +++ b/src/solidlsp/language_servers/pascal_server.py @@ -53,6 +53,7 @@ import pathlib import platform import shutil import tarfile +import tempfile import threading import time import urllib.error @@ -535,7 +536,7 @@ class PascalLanguageServer(SolidLanguageServer): """Atomic update: download -> verify checksum -> extract -> replace.""" temp_dir = pasls_dir + ".tmp" backup_dir = pasls_dir + ".backup" - temp_archive_dir = os.path.join(os.path.expanduser("~"), "solidlsp_tmp") + temp_archive_dir = tempfile.mkdtemp(prefix="solidlsp_") try: dep = deps.get_single_dep_for_current_platform() @@ -548,8 +549,6 @@ class PascalLanguageServer(SolidLanguageServer): # 1. Clean up any existing temp directory if os.path.exists(temp_dir): shutil.rmtree(temp_dir) - os.makedirs(temp_archive_dir, exist_ok=True) - # 2. Download archive log.info(f"Downloading pasls archive: {archive_filename}") if not cls._download_archive(dep.url, archive_path): @@ -605,11 +604,7 @@ class PascalLanguageServer(SolidLanguageServer): shutil.copytree(backup_meta, target_meta) # 9. Clean up downloaded archive and temp directory - try: - os.remove(archive_path) - os.rmdir(temp_archive_dir) - except OSError: - pass + shutil.rmtree(temp_archive_dir, ignore_errors=True) log.info("pasls installation completed successfully") return True @@ -625,12 +620,13 @@ class PascalLanguageServer(SolidLanguageServer): except Exception as rollback_error: log.error(f"Rollback failed: {rollback_error}") - # Clean up temp directory + # Clean up temp directories if os.path.exists(temp_dir): try: shutil.rmtree(temp_dir) except Exception: pass + shutil.rmtree(temp_archive_dir, ignore_errors=True) return False diff --git a/src/solidlsp/ls_utils.py b/src/solidlsp/ls_utils.py index 73066e12..b5e41ad7 100644 --- a/src/solidlsp/ls_utils.py +++ b/src/solidlsp/ls_utils.py @@ -10,6 +10,7 @@ import platform import shutil import subprocess import tarfile +import tempfile import uuid import zipfile from enum import Enum @@ -288,15 +289,15 @@ class FileUtils: """ Downloads an archive from ``url`` and extracts it safely into ``target_path``. """ + tmp_dir: str | None = None try: # preparing the temporary download location - tmp_files: list[str] = [] - tmp_file_name = str(PurePath(os.path.expanduser("~"), "solidlsp_tmp", uuid.uuid4().hex)) - os.makedirs(os.path.dirname(tmp_file_name), exist_ok=True) + external_tmp_files: list[str] = [] + tmp_dir = tempfile.mkdtemp(prefix="solidlsp_") + tmp_file_name = os.path.join(tmp_dir, uuid.uuid4().hex) # downloading the archive with optional verification FileUtils.download_file_verified(url, tmp_file_name, expected_sha256=expected_sha256, allowed_hosts=allowed_hosts) - tmp_files.append(tmp_file_name) # extracting the archive according to its format if archive_type in ["tar", "gztar", "bztar", "xztar"]: @@ -308,7 +309,6 @@ class FileUtils: elif archive_type == "zip.gz": os.makedirs(target_path, exist_ok=True) tmp_file_name_ungzipped = tmp_file_name + ".zip" - tmp_files.append(tmp_file_name_ungzipped) with gzip.open(tmp_file_name, "rb") as f_in, open(tmp_file_name_ungzipped, "wb") as f_out: shutil.copyfileobj(f_in, f_out) FileUtils._extract_zip_archive(tmp_file_name_ungzipped, target_path) @@ -316,7 +316,7 @@ class FileUtils: target_directory = os.path.dirname(target_path) or "." os.makedirs(target_directory, exist_ok=True) temp_output_path = str(PurePath(target_directory, f".{Path(target_path).name}.{uuid.uuid4().hex}.extract")) - tmp_files.append(temp_output_path) + external_tmp_files.append(temp_output_path) with gzip.open(tmp_file_name, "rb") as f_in, open(temp_output_path, "wb") as f_out: shutil.copyfileobj(f_in, f_out) os.replace(temp_output_path, target_path) @@ -324,17 +324,21 @@ class FileUtils: target_directory = os.path.dirname(target_path) or "." os.makedirs(target_directory, exist_ok=True) shutil.move(tmp_file_name, target_path) - tmp_files.remove(tmp_file_name) else: log.error(f"Unknown archive type '{archive_type}' for extraction") raise SolidLSPException(f"Unknown archive type '{archive_type}'") except Exception as exc: - log.error(f"Error extracting archive '{tmp_file_name}' obtained from '{url}': {exc}") + log.error(f"Error extracting archive obtained from '{url}': {exc}") raise SolidLSPException("Error extracting archive.") from exc finally: - for tmp_file_name in tmp_files: - if os.path.exists(tmp_file_name): - Path.unlink(Path(tmp_file_name)) + # cleaning up any temporary files outside the temporary directory + for tmp_file in external_tmp_files: + if os.path.exists(tmp_file): + Path.unlink(Path(tmp_file)) + + # removing the temporary directory + if tmp_dir is not None: + shutil.rmtree(tmp_dir, ignore_errors=True) @staticmethod def calculate_sha256(file_path: str) -> str: