Skip to content

Conversation

@o-l-a-v
Copy link
Contributor

@o-l-a-v o-l-a-v commented Oct 13, 2025

Description

Fix #6515 by simply deleting what's left after $ExtractDir has been moved, unless there is a directory name conflict as in #6011.

This is a third idea to a fix, also see

Motivation and Context

Closes #6515.

How Has This Been Tested?

scoop uninstall amber; scoop install extras/amber
scoop uninstall foxit-reader; scoop install extras/foxit-reader
scoop uninstall tor-browser; scoop install extras/tor-browser

Checklist:

  • I have read the Contributing Guide.
  • I have ensured that I am targeting the develop branch.
  • I have updated the documentation accordingly.
  • I have updated the tests accordingly.
  • I have added an entry in the CHANGELOG.

Summary by CodeRabbit

  • Bug Fixes

    • Improves reliability when extracting non-tar archives with accurate path handling.
    • Correctly moves extracted content to the destination, reducing unwanted top-level folders.
    • Safer cleanup that only removes temporary directories when appropriate, preventing accidental deletions.
    • Preserves existing behavior for tar archives.
  • Refactor

    • Streamlines post-extraction workflow with clearer path-based operations and logging.

@o-l-a-v o-l-a-v changed the title Fix #6515 "Expand-7zipArchive won't remove top folder if $ExtractDir depth exceeds 2" - Attempt 3 Fix #6515 "Expand-7zipArchive won't remove top folder if $ExtractDir depth exceeds 2" - Idea 3 Oct 13, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

Updates non-tar extraction cleanup in lib/decompress.ps1: resolves absolute paths, derives the extracted top-level directory, compares against destination contents to decide if it’s safe to remove, switches move operation to explicit -from/-to parameters, conditionally deletes the top-level folder, and preserves existing tar handling and log cleanup.

Changes

Cohort / File(s) Summary
Extraction cleanup and path handling
lib/decompress.ps1
Reworked path resolution for ExtractDir and top-level path; added logic to determine safe removal of the extracted top directory by inspecting destination contents; replaced move operation with explicit -from/-to; conditionally removes leftover top directory; tar flow unchanged; improved robustness for deep ExtractDir cases.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Caller
  participant D as decompress.ps1
  participant Z as 7-Zip
  participant FS as FileSystem

  C->>D: Expand-7zipArchive(archive, dest, ExtractDir)
  D->>D: Resolve full paths<br/>(dest, ExtractDir, topPath)
  D->>Z: Extract archive to temp/extract path
  Z-->>D: Extraction complete
  D->>FS: Inspect dest to detect existing dirs/files
  D->>D: Compute shouldRemoveTop flag
  D->>FS: Move contents (-from topPath -to dest)
  alt shouldRemoveTop == true
    D->>FS: Remove topPath
  else
    D->>D: Skip removal
  end
  D-->>C: Return

  note over D,FS: Tar handling and log cleanup remain as before
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I tug a thread of folders deep,
Hop-hop through paths I keenly keep.
Move the bits, then tidy tops—
only when the footprint stops.
Burrow neat, my work discrete—
unzip, unroot, then softly retreat. 🐇📦✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title is overly verbose and includes noise such as the issue number and “Idea 3” rather than providing a concise summary of the core change itself. Rename the title to a concise summary of the primary fix, for example “Fix Expand-7zipArchive top folder removal for deep ExtractDir,” and remove unnecessary references to issue numbers and attempt identifiers.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues Check ✅ Passed The changes implement recursive top-level directory detection and safe removal logic for multi-depth ExtractDir folders exactly as described in issue #6515, ensuring the top folder is cleaned up when appropriate.
Out of Scope Changes Check ✅ Passed All modifications are focused on enhancing the decompression cleanup logic in decompress.ps1 to address the linked issue and no unrelated features or files have been modified.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@o-l-a-v
Copy link
Contributor Author

o-l-a-v commented Oct 13, 2025

@z-Fng: If Scoop does not want the potential breaking changes in #6516, I prefer this PR over #6517.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/decompress.ps1 (1)

152-154: Consider logging cleanup failures.

Using -ErrorAction 'Ignore' silently suppresses all errors during directory removal. While this prevents installation failures due to cleanup issues (locked files, permissions), it also hides potential problems from users.

Consider using SilentlyContinue instead and checking if the directory still exists afterward, logging a warning if cleanup failed:

     # Remove leftovers after movedir
     if ($DeleteExtractDirTopPath) {
-        Remove-Item -Path $ExtractDirTopPath -Recurse -Force -ErrorAction 'Ignore'
+        Remove-Item -Path $ExtractDirTopPath -Recurse -Force -ErrorAction 'SilentlyContinue'
+        if (Test-Path $ExtractDirTopPath) {
+            warn "Failed to remove temporary extraction directory: $(friendly_path $ExtractDirTopPath)"
+        }
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20a178b and e939ebc.

📒 Files selected for processing (1)
  • lib/decompress.ps1 (1 hunks)
🔇 Additional comments (2)
lib/decompress.ps1 (2)

126-138: LGTM: Path resolution logic is correct.

The path manipulation correctly derives both the full extraction path and the top-level directory path. The split regex [\\/] handles both Windows and Unix-style separators, and filtering empty strings ensures trailing slashes don't cause issues.


150-150: movedir supports named parameters
The movedir function is defined with parameters ($from, $to), so using -from and -to works as intended.

Comment on lines +140 to +148
$DeleteExtractDirTopPath = [bool](
([System.IO.DirectoryInfo]($ExtractDirTopPath)).'Name' -notin [System.IO.Directory]::GetDirectories(
$ExtractDirPath
).ForEach{
$_.Split(
[System.IO.Path]::DirectorySeparatorChar
)[-1]
}
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for directory enumeration.

If $ExtractDirPath doesn't exist or is inaccessible, GetDirectories() will throw an exception and halt the extraction. Consider wrapping this in a try-catch or checking path existence first.

Apply this diff to add error handling:

         )
     )
-    # Check if $ExtractDirPath contains a directory with the same name as $ExtractDirTopPath
-    $DeleteExtractDirTopPath = [bool](
-        ([System.IO.DirectoryInfo]($ExtractDirTopPath)).'Name' -notin [System.IO.Directory]::GetDirectories(
-            $ExtractDirPath
-        ).ForEach{
-            $_.Split(
-                [System.IO.Path]::DirectorySeparatorChar
-            )[-1]
-        }
-    )
+    # Check if $ExtractDirPath contains a directory with the same name as $ExtractDirTopPath
+    $DeleteExtractDirTopPath = $true
+    if (Test-Path -Path $ExtractDirPath -PathType Container) {
+        $DeleteExtractDirTopPath = [bool](
+            ([System.IO.DirectoryInfo]($ExtractDirTopPath)).'Name' -notin [System.IO.Directory]::GetDirectories(
+                $ExtractDirPath
+            ).ForEach{
+                $_.Split(
+                    [System.IO.Path]::DirectorySeparatorChar
+                )[-1]
+            }
+        )
+    }
     # Move content of $ExtractDir to destination
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$DeleteExtractDirTopPath = [bool](
([System.IO.DirectoryInfo]($ExtractDirTopPath)).'Name' -notin [System.IO.Directory]::GetDirectories(
$ExtractDirPath
).ForEach{
$_.Split(
[System.IO.Path]::DirectorySeparatorChar
)[-1]
}
)
# Check if $ExtractDirPath contains a directory with the same name as $ExtractDirTopPath
$DeleteExtractDirTopPath = $true
if (Test-Path -Path $ExtractDirPath -PathType Container) {
$DeleteExtractDirTopPath = [bool](
([System.IO.DirectoryInfo]($ExtractDirTopPath)).'Name' -notin [System.IO.Directory]::GetDirectories(
$ExtractDirPath
).ForEach{
$_.Split(
[System.IO.Path]::DirectorySeparatorChar
)[-1]
}
)
}
# Move content of $ExtractDir to destination
🤖 Prompt for AI Agents
In lib/decompress.ps1 around lines 140 to 148, the call to
[System.IO.Directory]::GetDirectories($ExtractDirPath) can throw if
$ExtractDirPath doesn't exist or is inaccessible; wrap the directory enumeration
in a check/try-catch: first verify Test-Path -Path $ExtractDirPath -PathType
Container and only enumerate if true, otherwise set the result to an empty
array; alternatively wrap the GetDirectories call in try { ... } catch { log the
error (or set empty array) } so $DeleteExtractDirTopPath calculation never
throws and proceeds safely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant