mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
refactor(installer): implement manifest deduplication for same installation paths
- Add Remove-OldManifestsForPath function to automatically clean old manifests - Modify Save-InstallManifest to remove old manifests before saving new one - Update Get-AllInstallManifests to return only latest manifest per installation path - Apply same strategy to both Install-Claude.ps1 (PowerShell) and Install-Claude.sh (Bash) Benefits: - Each installation location registers only once - Only latest version manifest is retained - Uninstall UI shows only latest version per location - Prevents manifest file accumulation
This commit is contained in:
@@ -818,6 +818,56 @@ function Add-ManifestEntry {
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-OldManifestsForPath {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Remove old manifest files for the same installation path
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$InstallationPath
|
||||
)
|
||||
|
||||
if (-not (Test-Path $script:ManifestDir)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
$manifestFiles = Get-ChildItem -Path $script:ManifestDir -Filter "install-*.json" -File
|
||||
$removedCount = 0
|
||||
|
||||
foreach ($file in $manifestFiles) {
|
||||
try {
|
||||
$manifestJson = Get-Content -Path $file.FullName -Raw -Encoding utf8
|
||||
$manifest = $manifestJson | ConvertFrom-Json
|
||||
|
||||
# Normalize paths for comparison (case-insensitive, handle trailing slashes)
|
||||
$manifestPath = if ($manifest.installation_path) {
|
||||
$manifest.installation_path.TrimEnd('\', '/').ToLower()
|
||||
} else {
|
||||
""
|
||||
}
|
||||
$targetPath = $InstallationPath.TrimEnd('\', '/').ToLower()
|
||||
|
||||
# If paths match, remove this old manifest
|
||||
if ($manifestPath -eq $targetPath) {
|
||||
Remove-Item -Path $file.FullName -Force
|
||||
Write-ColorOutput "Removed old manifest: $($file.Name)" $ColorInfo
|
||||
$removedCount++
|
||||
}
|
||||
} catch {
|
||||
Write-ColorOutput "WARNING: Failed to process manifest $($file.Name): $($_.Exception.Message)" $ColorWarning
|
||||
}
|
||||
}
|
||||
|
||||
if ($removedCount -gt 0) {
|
||||
Write-ColorOutput "Removed $removedCount old manifest(s) for installation path: $InstallationPath" $ColorSuccess
|
||||
}
|
||||
} catch {
|
||||
Write-ColorOutput "WARNING: Failed to clean old manifests: $($_.Exception.Message)" $ColorWarning
|
||||
}
|
||||
}
|
||||
|
||||
function Save-InstallManifest {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
@@ -829,6 +879,11 @@ function Save-InstallManifest {
|
||||
)
|
||||
|
||||
try {
|
||||
# Remove old manifests for the same installation path
|
||||
if ($Manifest.installation_path) {
|
||||
Remove-OldManifestsForPath -InstallationPath $Manifest.installation_path
|
||||
}
|
||||
|
||||
# Use manifest ID to create unique file name
|
||||
$manifestFileName = "$($Manifest.manifest_id).json"
|
||||
$manifestPath = Join-Path $script:ManifestDir $manifestFileName
|
||||
@@ -901,7 +956,7 @@ function Migrate-LegacyManifest {
|
||||
function Get-AllInstallManifests {
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get all installation manifests
|
||||
Get all installation manifests (only latest per installation path)
|
||||
#>
|
||||
|
||||
# Migrate legacy manifest if exists
|
||||
@@ -913,7 +968,7 @@ function Get-AllInstallManifests {
|
||||
|
||||
try {
|
||||
$manifestFiles = Get-ChildItem -Path $script:ManifestDir -Filter "install-*.json" -File | Sort-Object LastWriteTime -Descending
|
||||
$manifests = [System.Collections.ArrayList]::new()
|
||||
$allManifests = [System.Collections.ArrayList]::new()
|
||||
|
||||
foreach ($file in $manifestFiles) {
|
||||
try {
|
||||
@@ -957,13 +1012,52 @@ function Get-AllInstallManifests {
|
||||
directories_count = $dirsCount
|
||||
}
|
||||
|
||||
$null = $manifests.Add($manifestHash)
|
||||
$null = $allManifests.Add($manifestHash)
|
||||
} catch {
|
||||
Write-ColorOutput "WARNING: Failed to load manifest $($file.Name): $($_.Exception.Message)" $ColorWarning
|
||||
}
|
||||
}
|
||||
|
||||
return ,$manifests.ToArray()
|
||||
# Group by installation_path (normalized) and keep only the latest per path
|
||||
$pathGroups = @{}
|
||||
foreach ($manifest in $allManifests) {
|
||||
$normalizedPath = $manifest.installation_path.TrimEnd('\', '/').ToLower()
|
||||
|
||||
if (-not $pathGroups.ContainsKey($normalizedPath)) {
|
||||
$pathGroups[$normalizedPath] = @()
|
||||
}
|
||||
$pathGroups[$normalizedPath] += $manifest
|
||||
}
|
||||
|
||||
# Select the latest manifest for each path (based on installation_date)
|
||||
$latestManifests = [System.Collections.ArrayList]::new()
|
||||
foreach ($pathKey in $pathGroups.Keys) {
|
||||
$groupManifests = $pathGroups[$pathKey]
|
||||
|
||||
# Sort by installation_date descending and take the first (latest)
|
||||
$latest = $groupManifests | Sort-Object {
|
||||
try {
|
||||
[DateTime]::Parse($_.installation_date)
|
||||
} catch {
|
||||
[DateTime]::MinValue
|
||||
}
|
||||
} -Descending | Select-Object -First 1
|
||||
|
||||
if ($latest) {
|
||||
$null = $latestManifests.Add($latest)
|
||||
}
|
||||
}
|
||||
|
||||
# Sort final results by installation_date descending
|
||||
$sortedManifests = $latestManifests | Sort-Object {
|
||||
try {
|
||||
[DateTime]::Parse($_.installation_date)
|
||||
} catch {
|
||||
[DateTime]::MinValue
|
||||
}
|
||||
} -Descending
|
||||
|
||||
return ,$sortedManifests
|
||||
} catch {
|
||||
Write-ColorOutput "ERROR: Failed to list installation manifests: $($_.Exception.Message)" $ColorError
|
||||
return @()
|
||||
|
||||
@@ -627,7 +627,7 @@ function install_global() {
|
||||
create_version_json "$global_claude_dir" "Global"
|
||||
|
||||
# Save installation manifest
|
||||
save_install_manifest "$manifest_file"
|
||||
save_install_manifest "$manifest_file" "$user_home"
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -822,7 +822,7 @@ function install_path() {
|
||||
create_version_json "$global_claude_dir" "Global"
|
||||
|
||||
# Save installation manifest
|
||||
save_install_manifest "$manifest_file"
|
||||
save_install_manifest "$manifest_file" "$target_dir"
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -974,8 +974,49 @@ EOF
|
||||
mv "$temp_file" "$manifest_file"
|
||||
}
|
||||
|
||||
function remove_old_manifests_for_path() {
|
||||
local installation_path="$1"
|
||||
|
||||
if [ ! -d "$MANIFEST_DIR" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Normalize paths for comparison (lowercase, remove trailing slashes)
|
||||
local target_path=$(echo "$installation_path" | sed 's:/*$::' | tr '[:upper:]' '[:lower:]')
|
||||
local removed_count=0
|
||||
|
||||
# Find and remove old manifests for the same installation path
|
||||
while IFS= read -r -d '' file; do
|
||||
local manifest_path=$(jq -r '.installation_path // ""' "$file" 2>/dev/null)
|
||||
|
||||
if [ -n "$manifest_path" ]; then
|
||||
# Normalize manifest path
|
||||
local normalized_manifest_path=$(echo "$manifest_path" | sed 's:/*$::' | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# If paths match, remove this old manifest
|
||||
if [ "$normalized_manifest_path" = "$target_path" ]; then
|
||||
rm -f "$file"
|
||||
write_color "Removed old manifest: $(basename "$file")" "$COLOR_INFO"
|
||||
((removed_count++))
|
||||
fi
|
||||
fi
|
||||
done < <(find "$MANIFEST_DIR" -name "install-*.json" -type f -print0 2>/dev/null)
|
||||
|
||||
if [ "$removed_count" -gt 0 ]; then
|
||||
write_color "Removed $removed_count old manifest(s) for installation path: $installation_path" "$COLOR_SUCCESS"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function save_install_manifest() {
|
||||
local manifest_file="$1"
|
||||
local installation_path="$2"
|
||||
|
||||
# Remove old manifests for the same installation path
|
||||
if [ -n "$installation_path" ]; then
|
||||
remove_old_manifests_for_path "$installation_path"
|
||||
fi
|
||||
|
||||
if [ -f "$manifest_file" ]; then
|
||||
write_color "Installation manifest saved: $manifest_file" "$COLOR_SUCCESS"
|
||||
@@ -1034,14 +1075,14 @@ function get_all_install_manifests() {
|
||||
fi
|
||||
|
||||
# Collect all manifests into JSON array
|
||||
local manifests="["
|
||||
local all_manifests="["
|
||||
local first=true
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
if [ "$first" = true ]; then
|
||||
first=false
|
||||
else
|
||||
manifests+=","
|
||||
all_manifests+=","
|
||||
fi
|
||||
|
||||
# Add manifest_file field
|
||||
@@ -1054,12 +1095,31 @@ function get_all_install_manifests() {
|
||||
# Add counts to manifest
|
||||
manifest_content=$(echo "$manifest_content" | jq --argjson fc "$files_count" --argjson dc "$dirs_count" '. + {files_count: $fc, directories_count: $dc}')
|
||||
|
||||
manifests+="$manifest_content"
|
||||
all_manifests+="$manifest_content"
|
||||
done < <(find "$MANIFEST_DIR" -name "install-*.json" -type f -print0 | sort -z)
|
||||
|
||||
manifests+="]"
|
||||
all_manifests+="]"
|
||||
|
||||
echo "$manifests"
|
||||
# Group by installation_path (normalized) and keep only the latest per path
|
||||
# Use jq to process the array and keep only the latest manifest for each unique path
|
||||
local latest_manifests=$(echo "$all_manifests" | jq '
|
||||
# Normalize paths and add normalized_path field
|
||||
map(. + {
|
||||
normalized_path: (.installation_path // "" | ascii_downcase | sub("/+$"; ""))
|
||||
})
|
||||
# Group by normalized_path
|
||||
| group_by(.normalized_path)
|
||||
# For each group, sort by installation_date descending and take the first (latest)
|
||||
| map(
|
||||
sort_by(.installation_date) | reverse | .[0]
|
||||
)
|
||||
# Remove the temporary normalized_path field
|
||||
| map(del(.normalized_path))
|
||||
# Sort final results by installation_date descending
|
||||
| sort_by(.installation_date) | reverse
|
||||
')
|
||||
|
||||
echo "$latest_manifests"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user