fix(get_wine): handle symlinks too
All checks were successful
Code check / Check code (push) Successful in 1m32s
All checks were successful
Code check / Check code (push) Successful in 1m32s
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
@@ -214,7 +214,10 @@ class ExtractionThread(QThread):
|
||||
last_emit_time = start_time
|
||||
last_progress = -1
|
||||
|
||||
# Direct extraction to destination without flattening
|
||||
# Collect hard links to process after all files are extracted
|
||||
hard_links_to_create = []
|
||||
|
||||
# First pass: extract all regular files and directories, collect hard links
|
||||
with libarchive.file_reader(self.archive_path) as archive:
|
||||
for entry in archive:
|
||||
if self._should_stop():
|
||||
@@ -230,6 +233,21 @@ class ExtractionThread(QThread):
|
||||
os.makedirs(target_path, exist_ok=True)
|
||||
continue
|
||||
|
||||
# Handle symbolic links
|
||||
if entry.issym:
|
||||
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
||||
# Create the symbolic link
|
||||
# Remove the target path if it already exists (to handle overwrites)
|
||||
if os.path.exists(target_path) or os.path.islink(target_path):
|
||||
os.unlink(target_path)
|
||||
os.symlink(entry.linkname, target_path)
|
||||
continue
|
||||
|
||||
# Collect hard links to create later
|
||||
if entry.islnk:
|
||||
hard_links_to_create.append((entry.linkname, target_path))
|
||||
continue
|
||||
|
||||
os.makedirs(os.path.dirname(target_path), exist_ok=True)
|
||||
|
||||
with open(target_path, "wb", buffering=1024 * 1024) as f:
|
||||
@@ -265,6 +283,23 @@ class ExtractionThread(QThread):
|
||||
|
||||
last_emit_time = now
|
||||
|
||||
# Second pass: create all hard links now that all target files exist
|
||||
for link_source, link_target in hard_links_to_create:
|
||||
if self._should_stop():
|
||||
return
|
||||
# The link source should be the full path to the target file in the extraction directory
|
||||
full_link_source = os.path.join(self.extract_dir, link_source)
|
||||
|
||||
# Ensure the directory for the hard link exists
|
||||
os.makedirs(os.path.dirname(link_target), exist_ok=True)
|
||||
|
||||
# Remove the target path if it already exists (to handle overwrites)
|
||||
if os.path.exists(link_target) or os.path.islink(link_target):
|
||||
os.unlink(link_target)
|
||||
|
||||
# Create the hard link
|
||||
os.link(full_link_source, link_target)
|
||||
|
||||
# Final progress update
|
||||
self.progress.emit(100)
|
||||
self.speed.emit(0.0)
|
||||
@@ -762,35 +797,78 @@ class ProtonManager(QDialog):
|
||||
|
||||
def download_asset(self, asset_data):
|
||||
"""Download and then extract the archive"""
|
||||
# Create a temporary file path for download
|
||||
temp_dir = tempfile.mkdtemp(prefix="portproton_wine_")
|
||||
filename = os.path.join(temp_dir, asset_data['asset_name'])
|
||||
download_url = asset_data['download_url']
|
||||
|
||||
download_info = f"{asset_data['source_name'].upper()} - {asset_data['asset_name']}"
|
||||
if len(download_info) > 80:
|
||||
download_info = download_info[:77] + "..."
|
||||
self.download_progress.setValue(0)
|
||||
self.download_frame.setVisible(True)
|
||||
self.download_btn.setEnabled(False)
|
||||
self.clear_btn.setEnabled(False)
|
||||
# DEBUG FEATURE: Check if proton_downloads folder exists in repo root and contains the file
|
||||
# This is a debug feature to use local files instead of downloading - remember to remove for production
|
||||
repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Go up from portprotonqt/
|
||||
proton_downloads_path = os.path.join(repo_root, "proton_downloads")
|
||||
|
||||
# Create and start download thread
|
||||
self.current_download_thread = DownloadThread(download_url, filename)
|
||||
local_file_path = None
|
||||
if os.path.exists(proton_downloads_path) and os.path.isdir(proton_downloads_path):
|
||||
# Look for the asset file in proton_downloads
|
||||
for filename in os.listdir(proton_downloads_path):
|
||||
if filename == asset_data['asset_name']:
|
||||
local_file_path = os.path.join(proton_downloads_path, filename)
|
||||
logger.info(f"DEBUG: Using local file instead of downloading: {local_file_path}")
|
||||
break
|
||||
|
||||
def update_download_progress(progress):
|
||||
self.download_progress.setValue(progress)
|
||||
self.download_info_label.setText(_("Downloading: {0} ({1}%)").format(asset_data['asset_name'], progress))
|
||||
if local_file_path and os.path.exists(local_file_path):
|
||||
# Use local file, skip download
|
||||
logger.info(f"DEBUG: Skipping download, using local file: {local_file_path}")
|
||||
download_info = f"{asset_data['source_name'].upper()} - {asset_data['asset_name']} (DEBUG: local)"
|
||||
if len(download_info) > 80:
|
||||
download_info = download_info[:77] + "..."
|
||||
self.download_progress.setValue(0)
|
||||
self.download_frame.setVisible(True)
|
||||
self.download_btn.setEnabled(False)
|
||||
self.clear_btn.setEnabled(False)
|
||||
self.download_info_label.setText(_("Using local file: {0}").format(asset_data['asset_name']))
|
||||
|
||||
def download_finished(filepath, success):
|
||||
if success:
|
||||
logger.info(f"Successfully downloaded: {filepath}")
|
||||
# Now start extraction
|
||||
self.start_extraction_for_asset(asset_data, filepath)
|
||||
else:
|
||||
logger.error(f"Failed to download: {filepath}")
|
||||
# Simulate download completion and start extraction immediately
|
||||
QTimer.singleShot(100, lambda: self.start_extraction_for_asset(asset_data, local_file_path))
|
||||
else:
|
||||
# Normal download process
|
||||
# Create a temporary file path for download
|
||||
temp_dir = tempfile.mkdtemp(prefix="portproton_wine_")
|
||||
filename = os.path.join(temp_dir, asset_data['asset_name'])
|
||||
download_url = asset_data['download_url']
|
||||
|
||||
download_info = f"{asset_data['source_name'].upper()} - {asset_data['asset_name']}"
|
||||
if len(download_info) > 80:
|
||||
download_info = download_info[:77] + "..."
|
||||
self.download_progress.setValue(0)
|
||||
self.download_frame.setVisible(True)
|
||||
self.download_btn.setEnabled(False)
|
||||
self.clear_btn.setEnabled(False)
|
||||
|
||||
# Create and start download thread
|
||||
self.current_download_thread = DownloadThread(download_url, filename)
|
||||
|
||||
def update_download_progress(progress):
|
||||
self.download_progress.setValue(progress)
|
||||
self.download_info_label.setText(_("Downloading: {0} ({1}%)").format(asset_data['asset_name'], progress))
|
||||
|
||||
def download_finished(filepath, success):
|
||||
if success:
|
||||
logger.info(f"Successfully downloaded: {filepath}")
|
||||
# Now start extraction
|
||||
self.start_extraction_for_asset(asset_data, filepath)
|
||||
else:
|
||||
logger.error(f"Failed to download: {filepath}")
|
||||
# Clean up temp directory
|
||||
temp_dir = os.path.dirname(filepath)
|
||||
try:
|
||||
shutil.rmtree(temp_dir)
|
||||
except (OSError, FileNotFoundError):
|
||||
pass
|
||||
self.current_download_index += 1
|
||||
QTimer.singleShot(100, self.start_next_download)
|
||||
|
||||
def download_error(error_msg):
|
||||
logger.error(f"Download error: {error_msg}")
|
||||
QMessageBox.critical(self, "Download Error", f"Failed to download archive: {error_msg}")
|
||||
# Clean up temp directory
|
||||
temp_dir = os.path.dirname(filepath)
|
||||
temp_dir = os.path.dirname(filename)
|
||||
try:
|
||||
shutil.rmtree(temp_dir)
|
||||
except (OSError, FileNotFoundError):
|
||||
@@ -798,22 +876,10 @@ class ProtonManager(QDialog):
|
||||
self.current_download_index += 1
|
||||
QTimer.singleShot(100, self.start_next_download)
|
||||
|
||||
def download_error(error_msg):
|
||||
logger.error(f"Download error: {error_msg}")
|
||||
QMessageBox.critical(self, "Download Error", f"Failed to download archive: {error_msg}")
|
||||
# Clean up temp directory
|
||||
temp_dir = os.path.dirname(filename)
|
||||
try:
|
||||
shutil.rmtree(temp_dir)
|
||||
except (OSError, FileNotFoundError):
|
||||
pass
|
||||
self.current_download_index += 1
|
||||
QTimer.singleShot(100, self.start_next_download)
|
||||
|
||||
self.current_download_thread.progress.connect(update_download_progress)
|
||||
self.current_download_thread.finished.connect(download_finished)
|
||||
self.current_download_thread.error.connect(download_error)
|
||||
self.current_download_thread.start()
|
||||
self.current_download_thread.progress.connect(update_download_progress)
|
||||
self.current_download_thread.finished.connect(download_finished)
|
||||
self.current_download_thread.error.connect(download_error)
|
||||
self.current_download_thread.start()
|
||||
|
||||
def start_extraction_for_asset(self, asset_data, filepath):
|
||||
"""Start extraction for a downloaded asset"""
|
||||
|
||||
Reference in New Issue
Block a user