Skip to content

fix: recursively remove empty parent dirs after file delete#5

Merged
Go1c merged 1 commit intomainfrom
fix/recursive-empty-dir-cleanup
Apr 14, 2026
Merged

fix: recursively remove empty parent dirs after file delete#5
Go1c merged 1 commit intomainfrom
fix/recursive-empty-dir-cleanup

Conversation

@Go1c
Copy link
Copy Markdown
Owner

@Go1c Go1c commented Apr 14, 2026

Problem

_try_remove_empty_parent only walked up one directory level after deleting a file. This left ancestor directories (e.g. diagrams/, notes/, 笔记同步助手/) as empty shells on disk even after all their contents were deleted via pull sync.

Root cause: if a file at diagrams/subdir/file.png was deleted, the code would clean up diagrams/subdir/ but never check whether diagrams/ itself was now empty.

Fix

Changed the single-shot check to a while loop that walks up the tree, removing each empty directory in turn, stopping at vault_path or the first non-empty directory.

Affects both FileSync and NoteSync.

Test plan

  • Delete files/directories on the server
  • Stop CLI, delete .fns_state.json, run pull
  • Confirm previously-stranded empty directories (diagrams/, notes/, 笔记同步助手/) are cleaned up after sync

Summary by Sourcery

Bug Fixes:

  • Ensure file and note sync recursively remove empty ancestor directories up to the vault root after deleting a file, stopping at the first non-empty directory or on error.

_try_remove_empty_parent previously only checked one level up,
leaving ancestor directories (e.g. diagrams/, notes/) as empty
shells after all their contents were deleted via pull sync.

Now walks up the tree until vault_path, removing each empty
directory in turn.
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 14, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR updates the empty-parent-directory cleanup logic in both file and note syncing so that, after a file is deleted, all ancestor directories up to the vault root are removed if empty rather than only the immediate parent.

Sequence diagram for recursive empty-parent directory removal

sequenceDiagram
    participant FileSync
    participant FileSystem

    FileSync->>FileSystem: delete file_path
    activate FileSync
    FileSync->>FileSystem: get parent = file_path.parent

    loop while parent != vault_path
        FileSync->>FileSystem: exists(parent)?
        alt parent exists and is empty
            FileSystem-->>FileSync: true, empty
            FileSync->>FileSystem: rmdir(parent)
            FileSystem-->>FileSync: success or OSError
            alt OSError raised
                FileSync-->>FileSystem: break loop
            else no error
                FileSync->>FileSystem: parent = parent.parent
            end
        else parent nonempty or missing
            FileSystem-->>FileSync: false or nonempty
            FileSync-->>FileSystem: break loop
        end
    end

    deactivate FileSync
Loading

File-Level Changes

Change Details Files
Make empty-parent-directory cleanup recursive up to vault root with early exit on non-empty or error.
  • Replace single-level parent check with a while loop that walks up parent directories until reaching the vault path.
  • On each step, remove the directory if it exists and is empty; otherwise stop walking further up the tree.
  • Stop traversal on OSError instead of silently swallowing and continuing, to avoid repeated failing operations.
fns_cli/file_sync.py
fns_cli/note_sync.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@Go1c Go1c merged commit b6f6f84 into main Apr 14, 2026
4 checks passed
@Go1c Go1c deleted the fix/recursive-empty-dir-cleanup branch April 14, 2026 07:52
Copy link
Copy Markdown

@sourcery-ai sourcery-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.

Hey - I've left some high level feedback:

  • The _try_remove_empty_parent implementations in FileSync and NoteSync are now identical; consider extracting this into a shared helper to avoid duplication and keep the behavior consistent in one place.
  • You now break on OSError instead of silently returning; if certain filesystem errors should be ignored (e.g., permission issues vs. real problems), it may be worth distinguishing/logging the exception to make debugging unexpected behavior easier.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `_try_remove_empty_parent` implementations in `FileSync` and `NoteSync` are now identical; consider extracting this into a shared helper to avoid duplication and keep the behavior consistent in one place.
- You now break on `OSError` instead of silently returning; if certain filesystem errors should be ignored (e.g., permission issues vs. real problems), it may be worth distinguishing/logging the exception to make debugging unexpected behavior easier.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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