• 
      

    Add empty file handling in JujutsuPatcher.

    Review Request #14760 — Created Jan. 6, 2026 and submitted

    Information

    RBTools
    master

    Reviewers

    In my previous change that updated the patching infrastructure to add
    support for patching binary files, I changed the top-level Patcher class
    so it would (when supported) call apply_patch_for_empty_files. This
    caused a regression with Jujutsu, where we had no implementation of
    that. I didn't catch this because it was hidden behind a conditional
    which was false in the case of unit tests, since we weren't
    instantiating the client with a capabilities object.

    This change adds an implementation of that method for Jujutsu which
    works similar to the SVN and Perforce implementations. Mercurial and Git
    are otherwise immune because they use SCM-native patching which handles
    empty files itself (hg import and git apply, respectively).

    Some of the jj unit tests were incorrectly named, saying they included
    empty files when they didn't. I've fixed those up, deleted a test which
    did not do anything unique, and added two new tests similar to ones we
    have in GitPatcherTests for ensuring that empty files work correctly.

    To be complete, I've also added the default capabilities object to the
    Git, Mercurial, and Perforce tests, just to ensure that the result of
    supports_empty_files() will be correct when running the tests.

    Ran unit tests.

    Summary ID
    Add empty file handling in JujutsuPatcher.
    In my previous change that updated the patching infrastructure to add support for patching binary files, I changed the top-level Patcher class so it would (when supported) call `apply_patch_for_empty_files`. This caused a regression with Jujutsu, where we had no implementation of that. I didn't catch this because it was hidden behind a conditional which was false in the case of unit tests, since we weren't instantiating the client with a capabilities object. This change adds an implementation of that method for Jujutsu which works similar to the SVN and Perforce implementations. Mercurial and Git are otherwise immune because they use SCM-native patching which handles empty files itself (`hg import` and `git apply`, respectively). Some of the jj unit tests were incorrectly named, saying they included empty files when they didn't. I've fixed those up, deleted a test which did not do anything unique, and added two new tests similar to ones we have in `GitPatcherTests` for ensuring that empty files work correctly. To be complete, I've also added the default capabilities object to the Git, Mercurial, and Perforce tests, just to ensure that the result of `supports_empty_files()` will be correct when running the tests. Testing Done: Ran unit tests.
    zyloxzouusozptwmwyrvtswmorwxovus
    Description From Last Updated

    continuation line over-indented for visual indent Column: 64 Error code: E127

    reviewbotreviewbot

    blank line at end of file Column: 1 Error code: W391

    reviewbotreviewbot

    This should say "deleted empty files"

    chipx86chipx86

    What raises this?

    chipx86chipx86

    Blank line between these.

    chipx86chipx86

    We're decoding multiple times, which is a bit wasteful. We should decode in a separate step, or an internal comprehension: …

    chipx86chipx86

    Blank line here.

    chipx86chipx86

    Blank line here.

    chipx86chipx86

    This log should probably include the filename in quotes followed by the error message.

    chipx86chipx86

    No trailing period here.

    chipx86chipx86

    Blank line between statements and blocks.

    chipx86chipx86

    We don't normally do an explicit mode=, just leaving it as positional. Here and below.

    chipx86chipx86

    The second keyword argument should be on its own line.

    chipx86chipx86

    No trailing period here.

    chipx86chipx86

    Blank line between statements and blocks.

    chipx86chipx86

    Same comment re: one keyword argument per line.

    chipx86chipx86

    Blank line here.

    chipx86chipx86

    Is there a chance that one file deletion fails, but the others succeed? In that case we'd return True from …

    maubinmaubin
    Checks run (1 failed, 1 succeeded)
    flake8 failed.
    JSHint passed.

    flake8

    david
    chipx86
    1. 
        
    2. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
      Show all issues

      This should say "deleted empty files"

    3. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
       
      Show all issues

      What raises this?

      1. Copy/paste from the parent class docstring.

    4. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line between these.

    5. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
       
       
       
       
       
       
       
       
      Show all issues

      We're decoding multiple times, which is a bit wasteful. We should decode in a separate step, or an internal comprehension:

      added_files = [
          filename
          for filename in (
              filename.decode('utf-8')
              for filename in added_files_re.findall(patch_content)
          )
          if filename not in binary_file_paths
      ]
      
    6. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line here.

    7. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line here.

    8. rbtools/clients/jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      This log should probably include the filename in quotes followed by the error message.

    9. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
      Show all issues

      No trailing period here.

    10. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line between statements and blocks.

    11. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
      Show all issues

      We don't normally do an explicit mode=, just leaving it as positional. Here and below.

      1. When adding the encoding argument, I've been turning mode into a kwarg for clarity. I think it reads much better than just a stringly-typed positional arg.

    12. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      The second keyword argument should be on its own line.

    13. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
      Show all issues

      No trailing period here.

    14. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line between statements and blocks.

    15. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Same comment re: one keyword argument per line.

    16. rbtools/clients/tests/test_jujutsu.py (Diff revision 2)
       
       
       
      Show all issues

      Blank line here.

    17. 
        
    david
    maubin
    1. 
        
    2. rbtools/clients/jujutsu.py (Diff revision 3)
       
       
       
       
       
       
       
       
       
      Show all issues

      Is there a chance that one file deletion fails, but the others succeed? In that case we'd return True from this. Is that what we want? Or do we want to return False if at least one file fails.

      1. It's possible. Other SCM backends that implement this return True if at least one thing succeeds, so I matched that behavior. In the case that one fails the user will see that error, but the patch as a whole will be semi-applied.

    3. 
        
    maubin
    1. Ship It!
    2. 
        
    david
    Review request changed
    Status:
    Completed
    Change Summary:
    Pushed to master (eb1cac0)