Skip to content

Fix incomplete plugin directory deletion on uninstall#4250

Open
Jack251970 wants to merge 7 commits intoFlow-Launcher:devfrom
Jack251970:dev
Open

Fix incomplete plugin directory deletion on uninstall#4250
Jack251970 wants to merge 7 commits intoFlow-Launcher:devfrom
Jack251970:dev

Conversation

@Jack251970
Copy link
Member

@Jack251970 Jack251970 commented Feb 4, 2026

  • Added TryDeleteDirectoryRobust to delete directories with retries and remove read-only attributes; returns whether deletion fully succeeded.
  • Updated PluginConfig to use the robust deletion; if partial, recreates the NeedDelete marker and logs a warning so deletion retries on next startup.
  • Added unit tests for non-existent, empty, nested, files-present, and read-only scenarios.

Test:

  • A plugin with one locked file in its plugin directory will be delete after lock is released.

Copilot AI and others added 5 commits February 4, 2026 04:19
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
Refactored the process for recreating the marker file when a plugin directory is not fully deleted. Removed unnecessary try-catch and nested checks, now directly checking for file existence and creating it if missing. This streamlines the code and removes redundant error handling.
…letion

Fix incomplete plugin directory deletion on uninstall
Copilot AI review requested due to automatic review settings February 4, 2026 04:53
@prlabeler prlabeler bot added the bug Something isn't working label Feb 4, 2026
@github-actions github-actions bot added this to the 2.1.0 milestone Feb 4, 2026
@github-actions

This comment has been minimized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Adds a robust directory-deletion routine and switches plugin cleanup to use it; if deletion partially fails, a marker file is written and a warning is logged to retry cleanup on next startup.

Changes

Cohort / File(s) Summary
Plugin deletion flow
Flow.Launcher.Core/Plugin/PluginConfig.cs
Replaces direct Directory.Delete(directory, true) with FilesFolders.TryDeleteDirectoryRobust(directory, maxRetries: 3, retryDelayMs: 200); logs a warning and writes DataLocation.PluginDeleteFile marker when deletion is incomplete.
Deletion utility
Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
Adds public TryDeleteDirectoryRobust(string path, int maxRetries = 3, int retryDelayMs = 100) that retries per-file deletion (handles read-only attributes, IO/Unauthorized exceptions), removes empty subdirectories deep→shallow, and returns bool indicating full deletion success.
Tests
Flow.Launcher.Test/FilesFoldersTest.cs
Adds tests covering non-existent dirs, empty dirs, files, nested structures, and read-only file handling to validate TryDeleteDirectoryRobust.

Sequence Diagram

sequenceDiagram
    participant PC as PluginConfig
    participant FD as FilesFolders.TryDeleteDirectoryRobust
    participant FS as File System
    participant DL as DataLocation
    participant PA as PublicApi (Logger)

    PC->>FD: request delete directory(path)
    FD->>FS: enumerate files & subdirs
    loop per-file retries
        FD->>FS: remove read-only attr if present
        FD->>FS: attempt delete file
        alt delete succeeds
            FS-->>FD: file removed
        else retryable failure
            FD-->>FS: wait retryDelay and retry
        else non-retryable failure
            FS-->>FD: failure
        end
    end
    FD->>FS: delete empty subdirectories (deep → shallow)
    FD->>FS: delete root directory
    alt all deleted
        FS-->>FD: success
        FD-->>PC: return true
    else partial/failure
        FS-->>FD: partial/failure
        FD-->>PC: return false
    end

    alt deletion returned false
        PC->>DL: create PluginDeleteFile marker in directory (if missing)
        PC->>PA: LogWarn about deferred deletion
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • jjw24
  • taooceros
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Fix incomplete plugin directory deletion on uninstall' accurately summarizes the main change—implementing robust directory deletion to handle incomplete plugin directory removal during uninstallation.
Description check ✅ Passed The description clearly relates to the changeset, detailing the addition of TryDeleteDirectoryRobust, its integration into PluginConfig, comprehensive unit tests, and expected behavior with locked files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request enhances plugin directory deletion in Flow Launcher by introducing a robust deletion mechanism that handles locked and read-only files more gracefully. The changes ensure that incomplete deletions are retried on subsequent application startups.

Changes:

  • Added TryDeleteDirectoryRobust method with retry logic for handling locked/read-only files during deletion
  • Updated plugin configuration to use the new robust deletion method and implement marker file recreation for retry logic
  • Added comprehensive unit tests covering various deletion scenarios

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs Implements new TryDeleteDirectoryRobust method with retry logic and read-only file handling
Flow.Launcher.Core/Plugin/PluginConfig.cs Updates deletion logic to use robust method, adds marker file recreation and warning logging for incomplete deletions
Flow.Launcher.Test/FilesFoldersTest.cs Adds unit tests for various deletion scenarios including empty directories, files, nested structures, and read-only files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs">

<violation number="1" location="Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs:209">
P2: `Directory.Delete` will throw an `IOException` if the directory itself is marked ReadOnly. The current implementation clears the ReadOnly attribute for files but not for directories. If a directory is ReadOnly, this method will permanently fail to delete it, causing infinite retries on subsequent startups.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Jack251970 and others added 2 commits February 7, 2026 18:31
Simplified the warning log when a directory is not fully deleted, removing extra details about remaining files and retrying deletion. Marker file recreation logic is unchanged.
@github-actions

This comment has been minimized.

@github-actions
Copy link

github-actions bot commented Feb 7, 2026

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors and Warnings Count
❌ forbidden-pattern 1
⚠️ non-alpha-in-dictionary 2

See ❌ Event descriptions for more information.

Forbidden patterns 🙅 (1)

In order to address this, you could change the content to not match the forbidden patterns (comments before forbidden patterns may help explain why they're forbidden), add patterns for acceptable instances, or adjust the forbidden patterns themselves.

These forbidden patterns matched content:

Pattern

\b[Nn]o[nt][- ]existent\b
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants