From 1707d215695de756a9a51f60042a7b6191ba1b57 Mon Sep 17 00:00:00 2001 From: henderkes Date: Fri, 15 May 2026 14:30:58 +0700 Subject: [PATCH] don't extract local sources --- src/StaticPHP/Artifact/Artifact.php | 12 ++++++++---- src/StaticPHP/Artifact/ArtifactExtractor.php | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/StaticPHP/Artifact/Artifact.php b/src/StaticPHP/Artifact/Artifact.php index e241d4fe..8e2166d1 100644 --- a/src/StaticPHP/Artifact/Artifact.php +++ b/src/StaticPHP/Artifact/Artifact.php @@ -285,15 +285,19 @@ class Artifact * Get source extraction directory. * * Rules: - * 1. If extract is not specified: SOURCE_PATH/{artifact_name} - * 2. If extract is relative path: SOURCE_PATH/{value} - * 3. If extract is absolute path: {value} - * 4. If extract is array (dict): handled by extractor (selective extraction) + * 1. If cache_type is 'local': use the absolute dirname recorded at download time (no symlink/copy). + * 2. If extract is not specified: SOURCE_PATH/{artifact_name} + * 3. If extract is relative path: SOURCE_PATH/{value} + * 4. If extract is absolute path: {value} + * 5. If extract is array (dict): handled by extractor (selective extraction) */ public function getSourceDir(): string { // Prefer cache extract path, fall back to config $cache_info = ApplicationContext::get(ArtifactCache::class)->getSourceInfo($this->name); + if (($cache_info['cache_type'] ?? null) === 'local' && isset($cache_info['dirname'])) { + return FileSystem::convertPath($cache_info['dirname']); + } $extract = is_string($cache_info['extract'] ?? null) ? $cache_info['extract'] : ($this->config['source']['extract'] ?? null); diff --git a/src/StaticPHP/Artifact/ArtifactExtractor.php b/src/StaticPHP/Artifact/ArtifactExtractor.php index 987ec554..2a986246 100644 --- a/src/StaticPHP/Artifact/ArtifactExtractor.php +++ b/src/StaticPHP/Artifact/ArtifactExtractor.php @@ -136,6 +136,12 @@ class ArtifactExtractor throw new WrongUsageException("Artifact source [{$name}] not downloaded, please download it first!"); } + // Local (--custom-local): source lives in place at $cache_info['dirname']. + if (($cache_info['cache_type'] ?? null) === 'local') { + $artifact->emitAfterSourceExtract($artifact->getSourceDir()); + return SPC_STATUS_ALREADY_EXTRACTED; + } + $source_file = $this->cache->getCacheFullPath($cache_info); $target_path = $artifact->getSourceDir(); @@ -171,8 +177,12 @@ class ArtifactExtractor return SPC_STATUS_ALREADY_EXTRACTED; } - // Remove old directory if hash mismatch - if (is_dir($target_path)) { + // Remove old directory if hash mismatch. + // Guard: a symlink at $target_path (left over from older local-source handling) must be + // unlinked directly — never recurse into the link target, that would wipe the user's tree. + if (is_link($target_path)) { + @unlink($target_path); + } elseif (is_dir($target_path)) { logger()->notice("Source [{$name}] hash mismatch, re-extracting..."); FileSystem::removeDir($target_path); }