Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fzf for openSUSE:Factory checked in at 2024-07-22 17:17:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fzf (Old) and /work/SRC/openSUSE:Factory/.fzf.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "fzf" Mon Jul 22 17:17:48 2024 rev:55 rq:1188813 version:0.54.1 Changes: -------- --- /work/SRC/openSUSE:Factory/fzf/fzf.changes 2024-07-08 19:09:46.538065309 +0200 +++ /work/SRC/openSUSE:Factory/.fzf.new.17339/fzf.changes 2024-07-22 17:19:30.884907761 +0200 @@ -1,0 +2,10 @@ +Sat Jul 20 14:14:23 UTC 2024 - Joshua Smith <smolsheep@opensuse.org> + +- Update to 0.54.1: + * fastwalk: add optional sorting and improve documentation + * Reverted ALT-C binding of fish to use cd instead of builtin + cd. builtin cd was introduced to work around a bug of cd coming + from zoxide init --cmd cd fish where it cannot handle -- + argument. + +------------------------------------------------------------------- Old: ---- fzf-0.54.0.tar.gz New: ---- fzf-0.54.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fzf.spec ++++++ --- /var/tmp/diff_new_pack.Lkkspo/_old 2024-07-22 17:19:31.564935102 +0200 +++ /var/tmp/diff_new_pack.Lkkspo/_new 2024-07-22 17:19:31.568935262 +0200 @@ -18,7 +18,7 @@ %global _lto_cflags %{nil} Name: fzf -Version: 0.54.0 +Version: 0.54.1 Release: 0 Summary: A command-line fuzzy finder License: MIT ++++++ fzf-0.54.0.tar.gz -> fzf-0.54.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/.github/workflows/winget.yml new/fzf-0.54.1/.github/workflows/winget.yml --- old/fzf-0.54.0/.github/workflows/winget.yml 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/.github/workflows/winget.yml 2024-07-19 10:10:49.000000000 +0200 @@ -10,6 +10,5 @@ - uses: vedantmgoyal2009/winget-releaser@v2 with: identifier: junegunn.fzf - version: ${{ github.event.release.tag_name }} installers-regex: '-windows_(armv7|arm64|amd64)\.zip$' token: ${{ secrets.WINGET_TOKEN }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/CHANGELOG.md new/fzf-0.54.1/CHANGELOG.md --- old/fzf-0.54.0/CHANGELOG.md 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/CHANGELOG.md 2024-07-19 10:10:49.000000000 +0200 @@ -1,6 +1,17 @@ CHANGELOG ========= +0.54.1 +------ +- Updated [fastwalk](https://github.com/charlievieth/fastwalk) dependency for built-in directory walker + - [fastwalk: add optional sorting and improve documentation](https://github.com/charlievieth/fastwalk/pull/27) + - [fastwalk: only check if MSYSTEM is set during MSYS/MSYS2](https://github.com/charlievieth/fastwalk/pull/28) + - Thanks to @charlievieth +- Reverted ALT-C binding of fish to use `cd` instead of `builtin cd` + - `builtin cd` was introduced to work around a bug of `cd` coming from `zoxide init --cmd cd fish` where it cannot handle `--` argument. + - However, the default `cd` of fish is actually a wrapper function for supporting `cd -`, so we want to use it instead. + - See [#3928](https://github.com/junegunn/fzf/pull/3928) for more information and consider helping zoxide fix the bug. + 0.54.0 ------ _Release highlights: https://junegunn.github.io/fzf/releases/0.54.0/_ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/README.md new/fzf-0.54.1/README.md --- old/fzf-0.54.0/README.md 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/README.md 2024-07-19 10:10:49.000000000 +0200 @@ -44,7 +44,7 @@ If you'd like to sponsor this project, please visit https://github.com/sponsors/junegunn. -<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden -Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav Marohnić" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/sbryngelson"><img src="https://github.com/sbryngelson.png" width="60px" alt="Spencer Bryngelson" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://gi thub.com/benelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/pawelduda"><img src="https://github.com/pawelduda.png" width="60px" alt="Paweł Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href=" https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https://github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><img src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeege r"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="https://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="Guillaume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="" /></a
<a href="https://github.com/mrcnski"><img src="https://github.com/mrcnski.png" width="60px" alt="Marcin S." /></a><a href="https://github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="Rob Levy" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="Gloria Zhao" /></a><a href="https://github.com/wjt"><img src="https://github.com/wjt.png" width="60px" alt="Will Thompson" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="" /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="James O'Beirne" /></a><a href="https://github.com/jlebray"><img src="https://github.com/jlebray.png" width="60px" alt="Johan Le Bray" /></a><a href="https://github.com/panosl1"><img src="https://github.com/panosl1.png" width="60px" alt="Panos Lampropoulos" /></a><a href="https://github.com/bespinian"><img src="https://github.com/bespinian.png" width="60px" alt="bespinian" /></a><a href="https://github.com/mirzahilmi"><img src="https://github.com/mirzahilmi.png" width="60px" alt="Mirza Hilmi Shodiq" /></a><!-- sponsors --> +<!-- sponsors --><a href="https://github.com/miyanokomiya"><img src="https://github.com/miyanokomiya.png" width="60px" alt="miyanokomiya" /></a><a href="https://github.com/jonhoo"><img src="https://github.com/jonhoo.png" width="60px" alt="Jon Gjengset" /></a><a href="https://github.com/AceofSpades5757"><img src="https://github.com/AceofSpades5757.png" width="60px" alt="Kyle L. Davis" /></a><a href="https://github.com/Frederick888"><img src="https://github.com/Frederick888.png" width="60px" alt="Frederick Zhang" /></a><a href="https://github.com/moritzdietz"><img src="https://github.com/moritzdietz.png" width="60px" alt="Moritz Dietz" /></a><a href="https://github.com/mikker"><img src="https://github.com/mikker.png" width="60px" alt="Mikkel Malmberg" /></a><a href="https://github.com/pldubouilh"><img src="https://github.com/pldubouilh.png" width="60px" alt="Pierre Dubouilh" /></a><a href="https://github.com/rcorre"><img src="https://github.com/rcorre.png" width="60px" alt="Ryan Roden -Corrent" /></a><a href="https://github.com/blissdev"><img src="https://github.com/blissdev.png" width="60px" alt="Jordan Arentsen" /></a><a href="https://github.com/mislav"><img src="https://github.com/mislav.png" width="60px" alt="Mislav Marohnić" /></a><a href="https://github.com/aexvir"><img src="https://github.com/aexvir.png" width="60px" alt="Alex Viscreanu" /></a><a href="https://github.com/dbalatero"><img src="https://github.com/dbalatero.png" width="60px" alt="David Balatero" /></a><a href="https://github.com/comatory"><img src="https://github.com/comatory.png" width="60px" alt="Ondrej Synacek" /></a><a href="https://github.com/moobar"><img src="https://github.com/moobar.png" width="60px" alt="" /></a><a href="https://github.com/majjoha"><img src="https://github.com/majjoha.png" width="60px" alt="Mathias Jean Johansen" /></a><a href="https://github.com/benelan"><img src="https://github.com/benelan.png" width="60px" alt="Ben Elan" /></a><a href="https://github.com/pawelduda "><img src="https://github.com/pawelduda.png" width="60px" alt="Paweł Duda" /></a><a href="https://github.com/slezica"><img src="https://github.com/slezica.png" width="60px" alt="Santiago Lezica" /></a><a href="https://github.com/pbwn"><img src="https://github.com/pbwn.png" width="60px" alt="" /></a><a href="https://github.com/timgluz"><img src="https://github.com/timgluz.png" width="60px" alt="Timo Sulg" /></a><a href="https://github.com/pyrho"><img src="https://github.com/pyrho.png" width="60px" alt="Damien Rajon" /></a><a href="https://github.com/ArtBIT"><img src="https://github.com/ArtBIT.png" width="60px" alt="ArtBIT" /></a><a href="https://github.com/da-moon"><img src="https://github.com/da-moon.png" width="60px" alt="" /></a><a href="https://github.com/hovissimo"><img src="https://github.com/hovissimo.png" width="60px" alt="Hovis" /></a><a href="https://github.com/dariusjonda"><img src="https://github.com/dariusjonda.png" width="60px" alt="Darius Jonda" /></a><a href="https: //github.com/cristiand391"><img src="https://github.com/cristiand391.png" width="60px" alt="Cristian Dominguez" /></a><a href="https://github.com/eliangcs"><img src="https://github.com/eliangcs.png" width="60px" alt="Chang-Hung Liang" /></a><a href="https://github.com/asphaltbuffet"><img src="https://github.com/asphaltbuffet.png" width="60px" alt="Ben Lechlitner" /></a><a href="https://github.com/yash1th"><img src="https://github.com/yash1th.png" width="60px" alt="yash" /></a><a href="https://github.com/looshch"><img src="https://github.com/looshch.png" width="60px" alt="george looshch" /></a><a href="https://github.com/kg8m"><img src="https://github.com/kg8m.png" width="60px" alt="Takumi KAGIYAMA" /></a><a href="https://github.com/polm"><img src="https://github.com/polm.png" width="60px" alt="Paul O'Leary McCann" /></a><a href="https://github.com/rbeeger"><img src="https://github.com/rbeeger.png" width="60px" alt="Robert Beeger" /></a><a href="https://github.com/veebch"><img src="h ttps://github.com/veebch.png" width="60px" alt="VEEB Projects" /></a><a href="https://github.com/yowayb"><img src="https://github.com/yowayb.png" width="60px" alt="Yoway Buorn" /></a><a href="https://github.com/scalisi"><img src="https://github.com/scalisi.png" width="60px" alt="Josh Scalisi" /></a><a href="https://github.com/alecbcs"><img src="https://github.com/alecbcs.png" width="60px" alt="Alec Scott" /></a><a href="https://github.com/thnxdev"><img src="https://github.com/thnxdev.png" width="60px" alt="thanks.dev" /></a><a href="https://github.com/artursapek"><img src="https://github.com/artursapek.png" width="60px" alt="Artur Sapek" /></a><a href="https://github.com/ramnes"><img src="https://github.com/ramnes.png" width="60px" alt="Guillaume Gelin" /></a><a href="https://github.com/jyc"><img src="https://github.com/jyc.png" width="60px" alt="" /></a><a href="https://github.com/mrcnski"><img src="https://github.com/mrcnski.png" width="60px" alt="Marcin S." /></a><a href="https:/ /github.com/roblevy"><img src="https://github.com/roblevy.png" width="60px" alt="Rob Levy" /></a><a href="https://github.com/glozow"><img src="https://github.com/glozow.png" width="60px" alt="Gloria Zhao" /></a><a href="https://github.com/wjt"><img src="https://github.com/wjt.png" width="60px" alt="Will Thompson" /></a><a href="https://github.com/toupeira"><img src="https://github.com/toupeira.png" width="60px" alt="Markus Koller" /></a><a href="https://github.com/rkpatel33"><img src="https://github.com/rkpatel33.png" width="60px" alt="" /></a><a href="https://github.com/jamesob"><img src="https://github.com/jamesob.png" width="60px" alt="James O'Beirne" /></a><a href="https://github.com/jlebray"><img src="https://github.com/jlebray.png" width="60px" alt="Johan Le Bray" /></a><a href="https://github.com/panosl1"><img src="https://github.com/panosl1.png" width="60px" alt="Panos Lampropoulos" /></a><a href="https://github.com/bespinian"><img src="https://github.com/bespinian.png" widt h="60px" alt="bespinian" /></a><a href="https://github.com/mirzahilmi"><img src="https://github.com/mirzahilmi.png" width="60px" alt="Mirza Hilmi Shodiq" /></a><!-- sponsors -->
Table of Contents ----------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/go.mod new/fzf-0.54.1/go.mod --- old/fzf-0.54.0/go.mod 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/go.mod 2024-07-19 10:10:49.000000000 +0200 @@ -1,7 +1,7 @@ module github.com/junegunn/fzf require ( - github.com/charlievieth/fastwalk v1.0.7-0.20240703190418-87029d931815 + github.com/charlievieth/fastwalk v1.0.8 github.com/gdamore/tcell/v2 v2.7.4 github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-shellwords v1.0.12 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/go.sum new/fzf-0.54.1/go.sum --- old/fzf-0.54.0/go.sum 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/go.sum 2024-07-19 10:10:49.000000000 +0200 @@ -1,5 +1,5 @@ -github.com/charlievieth/fastwalk v1.0.7-0.20240703190418-87029d931815 h1:4PRbYm9OMgH0bcdZZqMXA/AoOvpGy4l0H6g9Au/kgGA= -github.com/charlievieth/fastwalk v1.0.7-0.20240703190418-87029d931815/go.mod h1:rV19+IF9Y2TYQNy4MqEk5M/spNHjKsA0i71yrsv2p4E= +github.com/charlievieth/fastwalk v1.0.8 h1:uaoH6cAKSk73aK7aKXqs0+bL+J3Txzd3NGH8tRXgHko= +github.com/charlievieth/fastwalk v1.0.8/go.mod h1:yGy1zbxog41ZVMcKA/i8ojXLFsuayX5VvwhQVoj9PBI= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/install new/fzf-0.54.1/install --- old/fzf-0.54.0/install 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/install 2024-07-19 10:10:49.000000000 +0200 @@ -2,7 +2,7 @@ set -u -version=0.54.0 +version=0.54.1 auto_completion= key_bindings= update_config=2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/install.ps1 new/fzf-0.54.1/install.ps1 --- old/fzf-0.54.0/install.ps1 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/install.ps1 2024-07-19 10:10:49.000000000 +0200 @@ -1,4 +1,4 @@ -$version="0.54.0" +$version="0.54.1" $fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/man/man1/fzf-tmux.1 new/fzf-0.54.1/man/man1/fzf-tmux.1 --- old/fzf-0.54.0/man/man1/fzf-tmux.1 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/man/man1/fzf-tmux.1 2024-07-19 10:10:49.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf\-tmux 1 "Jul 2024" "fzf 0.54.0" "fzf\-tmux - open fzf in tmux split pane" +.TH fzf\-tmux 1 "Jul 2024" "fzf 0.54.1" "fzf\-tmux - open fzf in tmux split pane" .SH NAME fzf\-tmux - open fzf in tmux split pane diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/man/man1/fzf.1 new/fzf-0.54.1/man/man1/fzf.1 --- old/fzf-0.54.0/man/man1/fzf.1 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/man/man1/fzf.1 2024-07-19 10:10:49.000000000 +0200 @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Jul 2024" "fzf 0.54.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Jul 2024" "fzf 0.54.1" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/shell/key-bindings.fish new/fzf-0.54.1/shell/key-bindings.fish --- old/fzf-0.54.0/shell/key-bindings.fish 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/shell/key-bindings.fish 2024-07-19 10:10:49.000000000 +0200 @@ -104,7 +104,7 @@ eval (__fzfcmd)' +m --query "'$fzf_query'"' | read -l result if [ -n "$result" ] - builtin cd -- $result + cd -- $result # Remove last token from commandline. commandline -t "" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fzf-0.54.0/src/reader.go new/fzf-0.54.1/src/reader.go --- old/fzf-0.54.0/src/reader.go 2024-07-08 15:51:48.000000000 +0200 +++ new/fzf-0.54.1/src/reader.go 2024-07-19 10:10:49.000000000 +0200 @@ -253,6 +253,7 @@ Follow: opts.follow, // Use forward slashes when running a Windows binary under WSL or MSYS ToSlash: fastwalk.DefaultToSlash(), + Sort: fastwalk.SortFilesFirst, } fn := func(path string, de os.DirEntry, err error) error { if err != nil { ++++++ vendor.tar.zst ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/Makefile new/vendor/github.com/charlievieth/fastwalk/Makefile --- old/vendor/github.com/charlievieth/fastwalk/Makefile 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/Makefile 2024-07-20 16:16:46.000000000 +0200 @@ -47,7 +47,9 @@ .PHONY: test_build_wasip1_wasm test_build_wasip1_wasm: - GOOS=wasip1 GOARCH=wasm go test -c -o /dev/null + @# Ignore versions before 1.21 + go version | grep -qE 'go1\.(20|1[0-9])' || \ + GOOS=wasip1 GOARCH=wasm go test -c -o /dev/null .PHONY: test_build_aix_ppc64 test_build_aix_ppc64: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/adapters.go new/vendor/github.com/charlievieth/fastwalk/adapters.go --- old/vendor/github.com/charlievieth/fastwalk/adapters.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/adapters.go 2024-07-20 16:16:46.000000000 +0200 @@ -18,18 +18,17 @@ return false } -// IgnoreDuplicateDirs wraps fs.WalkDirFunc walkFn to make it follow symbolic +// IgnoreDuplicateDirs wraps [fs.WalkDirFunc] walkFn to make it follow symbolic // links and ignore duplicate directories (if a symlink points to a directory // that has already been traversed it is skipped). The walkFn is called for // for skipped directories, but the directory is not traversed (this is // required for error handling). // -// The Config.Follow setting has no effect on the behavior of Walk when +// The Follow [Config] setting has no effect on the behavior of Walk when // this wrapper is used. // -// In most use cases, the returned fs.WalkDirFunc should not be reused between -// in another call to Walk. If it is reused, any previously visited file will -// be skipped. +// In most use cases, the returned [fs.WalkDirFunc] should not be reused. +// If it is reused, any previously visited file will be skipped. // // NOTE: The order of traversal is undefined. Given an "example" directory // like the one below where "dir" is a directory and "smydir1" and "smydir2" @@ -68,9 +67,8 @@ // files are ignored. If a symlink resolves to a file that has already been // visited it will be skipped. // -// In most use cases, the returned fs.WalkDirFunc should not be reused between -// in another call to Walk. If it is reused, any previously visited file will -// be skipped. +// In most use cases, the returned [fs.WalkDirFunc] should not be reused. +// If it is reused, any previously visited file will be skipped. // // This can significantly slow Walk as os.Stat() is called for each path // (on Windows, os.Stat() is only needed for symlinks). @@ -92,8 +90,8 @@ } } -// IgnorePermissionErrors wraps walkFn so that permission errors are ignored. -// The returned fs.WalkDirFunc may be reused. +// IgnorePermissionErrors wraps walkFn so that [fs.ErrPermission] permission +// errors are ignored. The returned [fs.WalkDirFunc] may be reused. func IgnorePermissionErrors(walkFn fs.WalkDirFunc) fs.WalkDirFunc { return func(path string, d fs.DirEntry, err error) error { if err != nil && os.IsPermission(err) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/dirent.go new/vendor/github.com/charlievieth/fastwalk/dirent.go --- old/vendor/github.com/charlievieth/fastwalk/dirent.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/dirent.go 2024-07-20 16:16:46.000000000 +0200 @@ -31,11 +31,16 @@ return fi } -// StatDirEntry returns the fs.FileInfo for the file or subdirectory described -// by the entry. If the entry is a symbolic link, StatDirEntry returns the -// fs.FileInfo for the file the line references (os.Stat). -// If fs.DirEntry de is a fastwalk.DirEntry it's Stat() method is used and the -// returned fs.FileInfo may be a previously cached result. +// StatDirEntry returns a [fs.FileInfo] describing the named file ([os.Stat]). +// If de is a [fastwalk.DirEntry] its Stat method is used and the returned +// FileInfo may be cached from a prior call to Stat. If a cached result is not +// desired, users should just call [os.Stat] directly. +// +// This is a helper function for calling Stat on the DirEntry passed to the +// walkFn argument to [Walk]. +// +// The path argument is only used if de is not of type [fastwalk.DirEntry]. +// Therefore, de should be the DirEntry describing path. func StatDirEntry(path string, de fs.DirEntry) (fs.FileInfo, error) { if de == nil { return nil, &os.PathError{Op: "stat", Path: path, Err: syscall.EINVAL} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/dirent_portable.go new/vendor/github.com/charlievieth/fastwalk/dirent_portable.go --- old/vendor/github.com/charlievieth/fastwalk/dirent_portable.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/dirent_portable.go 2024-07-20 16:16:46.000000000 +0200 @@ -1,37 +1,128 @@ //go:build !darwin && !(aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris) +// TODO: add a "portable_dirent" build tag so that we can test this +// on non-Windows platforms + package fastwalk import ( "io/fs" "os" + "sort" + "sync" + + "github.com/charlievieth/fastwalk/internal/fmtdirent" ) +var _ DirEntry = (*portableDirent)(nil) + type portableDirent struct { fs.DirEntry - path string - stat *fileInfo + parent string + stat *fileInfo +} + +func (d *portableDirent) String() string { + return fmtdirent.FormatDirEntry(d) } -// TODO: cache the result of Stat func (d *portableDirent) Stat() (fs.FileInfo, error) { if d.DirEntry.Type()&os.ModeSymlink == 0 { return d.DirEntry.Info() } stat := loadFileInfo(&d.stat) stat.once.Do(func() { - stat.FileInfo, stat.err = os.Stat(d.path) + stat.FileInfo, stat.err = os.Stat(d.parent + string(os.PathSeparator) + d.Name()) }) return stat.FileInfo, stat.err } -func newDirEntry(dirName string, info fs.DirEntry) fs.DirEntry { +func newDirEntry(dirName string, info fs.DirEntry) DirEntry { return &portableDirent{ DirEntry: info, - path: dirName + string(os.PathSeparator) + info.Name(), + parent: dirName, } } -func fileInfoToDirEntry(dirname string, fi fs.FileInfo) fs.DirEntry { +func fileInfoToDirEntry(dirname string, fi fs.FileInfo) DirEntry { return newDirEntry(dirname, fs.FileInfoToDirEntry(fi)) } + +var direntSlicePool = sync.Pool{ + New: func() any { + a := make([]DirEntry, 0, 32) + return &a + }, +} + +func putDirentSlice(p *[]DirEntry) { + // max is half as many as Unix because twice the size + if p != nil && cap(*p) <= 16*1024 { + a := *p + for i := range a { + a[i] = nil + } + *p = a[:0] + direntSlicePool.Put(p) + } +} + +func sortDirents(mode SortMode, dents []DirEntry) { + if len(dents) <= 1 { + return + } + switch mode { + case SortLexical: + sort.Slice(dents, func(i, j int) bool { + return dents[i].Name() < dents[j].Name() + }) + case SortFilesFirst: + sort.Slice(dents, func(i, j int) bool { + d1 := dents[i] + d2 := dents[j] + r1 := d1.Type().IsRegular() + r2 := d2.Type().IsRegular() + switch { + case r1 && !r2: + return true + case !r1 && r2: + return false + case !r1 && !r2: + // Both are not regular files: sort directories last + dd1 := d1.Type().IsDir() + dd2 := d2.Type().IsDir() + switch { + case !dd1 && dd2: + return true + case dd1 && !dd2: + return false + } + } + return d1.Name() < d2.Name() + }) + case SortDirsFirst: + sort.Slice(dents, func(i, j int) bool { + d1 := dents[i] + d2 := dents[j] + dd1 := d1.Type().IsDir() + dd2 := d2.Type().IsDir() + switch { + case dd1 && !dd2: + return true + case !dd1 && dd2: + return false + case !dd1 && !dd2: + // Both are not directories: sort regular files first + r1 := d1.Type().IsRegular() + r2 := d2.Type().IsRegular() + switch { + case r1 && !r2: + return true + case !r1 && r2: + return false + } + } + return d1.Name() < d2.Name() + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/dirent_unix.go new/vendor/github.com/charlievieth/fastwalk/dirent_unix.go --- old/vendor/github.com/charlievieth/fastwalk/dirent_unix.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/dirent_unix.go 2024-07-20 16:16:46.000000000 +0200 @@ -5,19 +5,24 @@ import ( "io/fs" "os" + "sort" + "sync" + + "github.com/charlievieth/fastwalk/internal/fmtdirent" ) type unixDirent struct { parent string name string - typ os.FileMode + typ fs.FileMode info *fileInfo stat *fileInfo } func (d *unixDirent) Name() string { return d.name } func (d *unixDirent) IsDir() bool { return d.typ.IsDir() } -func (d *unixDirent) Type() os.FileMode { return d.typ } +func (d *unixDirent) Type() fs.FileMode { return d.typ } +func (d *unixDirent) String() string { return fmtdirent.FormatDirEntry(d) } func (d *unixDirent) Info() (fs.FileInfo, error) { info := loadFileInfo(&d.info) @@ -38,7 +43,7 @@ return stat.FileInfo, stat.err } -func newUnixDirent(parent, name string, typ os.FileMode) *unixDirent { +func newUnixDirent(parent, name string, typ fs.FileMode) *unixDirent { return &unixDirent{ parent: parent, name: name, @@ -46,7 +51,7 @@ } } -func fileInfoToDirEntry(dirname string, fi fs.FileInfo) fs.DirEntry { +func fileInfoToDirEntry(dirname string, fi fs.FileInfo) DirEntry { info := &fileInfo{ FileInfo: fi, } @@ -58,3 +63,81 @@ info: info, } } + +var direntSlicePool = sync.Pool{ + New: func() any { + a := make([]*unixDirent, 0, 32) + return &a + }, +} + +func putDirentSlice(p *[]*unixDirent) { + if p != nil && cap(*p) <= 32*1024 /* 256Kb */ { + a := *p + for i := range a { + a[i] = nil + } + *p = a[:0] + direntSlicePool.Put(p) + } +} + +func sortDirents(mode SortMode, dents []*unixDirent) { + if len(dents) <= 1 { + return + } + switch mode { + case SortLexical: + sort.Slice(dents, func(i, j int) bool { + return dents[i].name < dents[j].name + }) + case SortFilesFirst: + sort.Slice(dents, func(i, j int) bool { + d1 := dents[i] + d2 := dents[j] + r1 := d1.typ.IsRegular() + r2 := d2.typ.IsRegular() + switch { + case r1 && !r2: + return true + case !r1 && r2: + return false + case !r1 && !r2: + // Both are not regular files: sort directories last + dd1 := d1.typ.IsDir() + dd2 := d2.typ.IsDir() + switch { + case !dd1 && dd2: + return true + case dd1 && !dd2: + return false + } + } + return d1.name < d2.name + }) + case SortDirsFirst: + sort.Slice(dents, func(i, j int) bool { + d1 := dents[i] + d2 := dents[j] + dd1 := d1.typ.IsDir() + dd2 := d2.typ.IsDir() + switch { + case dd1 && !dd2: + return true + case !dd1 && dd2: + return false + case !dd1 && !dd2: + // Both are not directories: sort regular files first + r1 := d1.typ.IsRegular() + r2 := d2.typ.IsRegular() + switch { + case r1 && !r2: + return true + case !r1 && r2: + return false + } + } + return d1.name < d2.name + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/entry_filter_unix.go new/vendor/github.com/charlievieth/fastwalk/entry_filter_unix.go --- old/vendor/github.com/charlievieth/fastwalk/entry_filter_unix.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/entry_filter_unix.go 2024-07-20 16:16:46.000000000 +0200 @@ -48,7 +48,7 @@ // TODO: this name is confusing and should be fixed -// Entry returns if path and fs.DirEntry have been seen before. +// Entry returns if path and [fs.DirEntry] have been seen before. func (e *EntryFilter) Entry(path string, de fs.DirEntry) (seen bool) { fi, err := StatDirEntry(path, de) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/fastwalk.go new/vendor/github.com/charlievieth/fastwalk/fastwalk.go --- old/vendor/github.com/charlievieth/fastwalk/fastwalk.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/fastwalk.go 2024-07-20 16:16:46.000000000 +0200 @@ -1,5 +1,5 @@ -// Package fastwalk provides a faster version of filepath.Walk for file system -// scanning tools. +// Package fastwalk provides a faster version of [filepath.WalkDir] for file +// system scanning tools. package fastwalk /* @@ -45,8 +45,9 @@ "sync" ) -// ErrTraverseLink is used as a return value from WalkFuncs to indicate that the -// symlink named in the call may be traversed. +// ErrTraverseLink is used as a return value from WalkDirFuncs to indicate that +// the symlink named in the call may be traversed. This error is ignored if +// the Follow [Config] option is true. var ErrTraverseLink = errors.New("fastwalk: traverse symlink, assuming target is a directory") // ErrSkipFiles is a used as a return value from WalkFuncs to indicate that the @@ -59,8 +60,10 @@ // as an error by any function. var SkipDir = fs.SkipDir +// TODO: add fs.SkipAll + // DefaultNumWorkers returns the default number of worker goroutines to use in -// [fastwalk.Walk] and is the value of [runtime.GOMAXPROCS](-1) clamped to a range +// [Walk] and is the value of [runtime.GOMAXPROCS](-1) clamped to a range // of 4 to 32 except on Darwin where it is either 4 (8 cores or less) or 6 // (more than 8 cores). This is because Walk / IO performance on Darwin // degrades with more concurrency. @@ -88,44 +91,163 @@ } // DefaultToSlash returns true if this is a Go program compiled for Windows -// running in an environment ([WSL] or [MSYS/MSYS2]) that uses forward slashes -// as the path separator instead of the native backslash. -// On all other platforms this is a no-op and returns false since the native -// path separator is a forward slash and does not need to be converted. -// -// This check does not apply to programs compiled in [WSL] [MSYS/MSYS2] or for -// Linux (GOOS=linux). It only applies to Go programs compiled for Windows -// (GOOS=windows) that are executed from [WSL] or [MSYS/MSYS2]. +// running in an environment ([MSYS/MSYS2] or [Git for Windows]) that uses +// forward slashes as the path separator instead of the native backslash. // -// To detect if we're running in [MSYS/MSYS2] we check that "MSYSTEM" environment -// variable is either "MINGW64", "MINGW32", or "MSYS". +// On non-Windows OSes this is a no-op and always returns false. // -// The following heuristics are used to detect if we're running in [WSL]: +// To detect if we're running in [MSYS/MSYS2] we check if the "MSYSTEM" +// environment variable exists. // -// - Existence of "/proc/sys/fs/binfmt_misc/WSLInterop". -// - If the "WSL_DISTRO_NAME" environment variable is set. -// - If "/proc/version" contains either "Microsoft" or "microsoft". +// DefaultToSlash does not detect if this is a Windows executable running in [WSL]. +// Instead, users should (ideally) use programs compiled for Linux in WSL. // -// The result of the WSL check is cached for performance reasons. +// See: [github.com/junegunn/fzf/issues/3859] // -// See: https://github.com/junegunn/fzf/issues/3859 +// NOTE: The reason that we do not check if we're running in WSL is that the +// test was inconsistent since it depended on the working directory (it seems +// that "/proc" cannot be accessed when programs are ran from a mounted Windows +// directory) and what environment variables are shared between WSL and Win32 +// (this requires explicit [configuration]). // -// [WSL]: https://learn.microsoft.com/en-us/windows/wsl/about // [MSYS/MSYS2]: https://www.msys2.org/ +// [WSL]: https://learn.microsoft.com/en-us/windows/wsl/about +// [Git for Windows]: https://gitforwindows.org/ +// [github.com/junegunn/fzf/issues/3859]: https://github.com/junegunn/fzf/issues/3859 +// [configuration]: https://devblogs.microsoft.com/commandline/share-environment-vars-between-ws... func DefaultToSlash() bool { if runtime.GOOS != "windows" { return false } - return useForwardSlash() + // Previously this function attempted to determine if this is a Windows exe + // running in WSL. The check was: + // + // * File /proc/sys/fs/binfmt_misc/WSLInterop exist + // * Env var "WSL_DISTRO_NAME" exits + // * /proc/version contains "Microsoft" or "microsoft" + // + // Below are my notes explaining why that check was flaky: + // + // NOTE: This appears to fail when ran from WSL when the current working + // directory is a Windows directory that is mounted ("/mnt/c/...") since + // "/proc" is not accessible. It works if ran from a directory that is not + // mounted. Additionally, the "WSL_DISTRO_NAME" environment variable is not + // set when ran from WSL. + // + // I'm not sure what causes this, but it would be great to find a solution. + // My guess is that when ran from a Windows directory it uses the native + // Windows path syscalls (for example os.Getwd reports the canonical Windows + // path when a Go exe is ran from a mounted directory in WSL, but reports the + // WSL path when ran from outside a mounted Windows directory). + // + // That said, the real solution here is to use programs compiled for Linux + // when running in WSL. + _, ok := os.LookupEnv("MSYSTEM") + return ok +} + +// SortMode determines the order that a directory's entries are visited by +// [Walk]. Sorting applies only at the directory level and since we process +// directories in parallel the order in which all files are visited is still +// non-deterministic. +// +// Sorting is mostly useful for programs that print the output of Walk since +// it makes it slightly more ordered compared to the default directory order. +// Sorting may also help some programs that wish to change the order in which +// a directory is processed by either processing all files first or enqueuing +// all directories before processing files. +// +// All lexical sorting is case-sensitive. +// +// The overhead of sorting is minimal compared to the syscalls needed to +// walk directories. The impact on performance due to changing the order +// in which directory entries are processed will be dependent on the workload +// and the structure of the file tree being visited (it might also have no +// impact). +type SortMode uint32 + +const ( + // Perform no sorting. Files will be visited in directory order. + // This is the default. + SortNone SortMode = iota + + // Directory entries are sorted by name before being visited. + SortLexical + + // Sort the directory entries so that regular files and non-directories + // (e.g. symbolic links) are visited before directories. Within each + // group (regular files, other files, directories) the entries are sorted + // by name. + // + // This is likely the mode that programs that print the output of Walk + // want to use. Since by processing all files before enqueuing + // sub-directories the output is slightly more grouped. + // + // Example order: + // - file: "a.txt" + // - file: "b.txt" + // - link: "a.link" + // - link: "b.link" + // - dir: "d1/" + // - dir: "d2/" + // + SortFilesFirst + + // Sort the directory entries so that directories are visited first, then + // regular files are visited, and finally everything else is visited + // (e.g. symbolic links). Within each group (directories, regular files, + // other files) the entries are sorted by name. + // + // This mode is might be useful at preventing other walk goroutines from + // stalling due to lack of work since it immediately enqueues all of a + // directory's sub-directories for processing. The impact on performance + // will be dependent on the workload and the structure of the file tree + // being visited - it might also have no (or even a negative) impact on + // performance so testing/benchmarking is recommend. + // + // An example workload that might cause this is: processing one directory + // takes a long time, that directory has sub-directories we want to walk, + // while processing that directory all other Walk goroutines have finished + // processing their directories, those goroutines are now stalled waiting + // for more work (waiting on the one running goroutine to enqueue its + // sub-directories for processing). + // + // This might also be beneficial if processing files is expensive. + // + // Example order: + // - dir: "d1/" + // - dir: "d2/" + // - file: "a.txt" + // - file: "b.txt" + // - link: "a.link" + // - link: "b.link" + // + SortDirsFirst +) + +var sortModeStrs = [...]string{ + SortNone: "None", + SortLexical: "Lexical", + SortDirsFirst: "DirsFirst", + SortFilesFirst: "FilesFirst", +} + +func (s SortMode) String() string { + if 0 <= int(s) && int(s) < len(sortModeStrs) { + return sortModeStrs[s] + } + return "SortMode(" + itoa(uint64(s)) + ")" } -// DefaultConfig is the default Config used when none is supplied. +// DefaultConfig is the default [Config] used when none is supplied. var DefaultConfig = Config{ Follow: false, ToSlash: DefaultToSlash(), NumWorkers: DefaultNumWorkers(), + Sort: SortNone, } +// A Config controls the behavior of [Walk]. type Config struct { // TODO: do we want to pass a sentinel error to WalkFunc if // a symlink loop is detected? @@ -154,56 +276,105 @@ // See FZF issue: https://github.com/junegunn/fzf/issues/3859 ToSlash bool + // Sort a directory's entries by SortMode before visiting them. + // The order that files are visited is deterministic only at the directory + // level, but not generally deterministic because we process directories + // in parallel. The performance impact of sorting entries is generally + // negligible compared to the syscalls required to read directories. + // + // This option mostly exists for programs that print the output of Walk + // (like FZF) since it provides some order and thus makes the output much + // nicer compared to the default directory order, which is basically random. + Sort SortMode + // Number of parallel workers to use. If NumWorkers if ≤ 0 then - // [DefaultNumWorkers] is used. + // DefaultNumWorkers is used. NumWorkers int } -// A DirEntry extends the fs.DirEntry interface to add a Stat() method -// that returns the result of calling os.Stat() on the underlying file. +// Copy returns a copy of c. If c is nil an empty [Config] is returned. +func (c *Config) Copy() *Config { + dupe := new(Config) + if c != nil { + *dupe = *c + } + return dupe +} + +// A DirEntry extends the [fs.DirEntry] interface to add a Stat() method +// that returns the result of calling [os.Stat] on the underlying file. // The results of Info() and Stat() are cached. // -// The fs.DirEntry argument passed to the fs.WalkDirFunc by Walk is -// always a DirEntry. The only exception is the root directory with -// with Walk is called. +// The [fs.DirEntry] argument passed to the [fs.WalkDirFunc] by [Walk] is +// always a DirEntry. type DirEntry interface { fs.DirEntry - // Stat returns the FileInfo for the file or subdirectory described + // Stat returns the fs.FileInfo for the file or subdirectory described // by the entry. The returned FileInfo may be from the time of the - // original directory read or from the time of the call to Stat. + // original directory read or from the time of the call to os.Stat. // If the entry denotes a symbolic link, Stat reports the information // about the target itself, not the link. Stat() (fs.FileInfo, error) } -// Walk is a faster implementation of filepath.Walk. -// -// filepath.Walk's design necessarily calls os.Lstat on each file, even if -// the caller needs less info. Many tools need only the type of each file. -// On some platforms, this information is provided directly by the readdir -// system call, avoiding the need to stat each file individually. -// fastwalk_unix.go contains a fork of the syscall routines. +// Walk is a faster implementation of [filepath.WalkDir] that walks the file +// tree rooted at root in parallel, calling walkFn for each file or directory +// in the tree, including root. +// +// All errors that arise visiting files and directories are filtered by walkFn +// see the [fs.WalkDirFunc] documentation for details. +// The [IgnorePermissionErrors] adapter is provided to handle to common case of +// ignoring [fs.ErrPermission] errors. +// +// By default files are walked in directory order, which makes the output +// non-deterministic. The Sort [Config] option can be used to control the order +// in which directory entries are visited, but since we walk the file tree in +// parallel the output is still non-deterministic (it's just slightly more +// sorted). +// +// When a symbolic link is encountered, by default Walk will not follow it +// unless walkFn returns [ErrTraverseLink] or the Follow [Config] setting is +// true. See below for a more detailed explanation. +// +// Walk calls walkFn with paths that use the separator character appropriate +// for the operating system unless the ToSlash [Config] setting is true which +// will cause all paths to be joined with a forward slash. +// +// If walkFn returns the [SkipDir] sentinel error, the directory is skipped. +// If walkFn returns the [ErrSkipFiles] sentinel error, the callback will not +// be called for any other files in the current directory. // -// See golang.org/issue/16399 +// Unlike [filepath.WalkDir]: // -// Walk walks the file tree rooted at root, calling walkFn for each file or -// directory in the tree, including root. +// - Multiple goroutines stat the filesystem concurrently. The provided +// walkFn must be safe for concurrent use. // -// If walkFn returns filepath.SkipDir, the directory is skipped. +// - The order that directories are visited is non-deterministic. // -// Unlike filepath.WalkDir: // - File stat calls must be done by the user and should be done via -// the DirEntry argument to walkFn since it caches the results of -// Stat and Lstat. -// - The fs.DirEntry argument is always a fastwalk.DirEntry, which has -// a Stat() method that returns the result of calling os.Stat() on the -// file. The result of Stat() may be cached. -// - Multiple goroutines stat the filesystem concurrently. The provided -// walkFn must be safe for concurrent use. -// - Walk can follow symlinks if walkFn returns the ErrTraverseLink -// sentinel error. It is the walkFn's responsibility to prevent -// Walk from going into symlink cycles. +// the [DirEntry] argument to walkFn. The [DirEntry] caches the result +// of both Info() and Stat(). The Stat() method is a fastwalk specific +// extension and can be called by casting the [fs.DirEntry] to a +// [fastwalk.DirEntry] or via the [StatDirEntry] helper. The [fs.DirEntry] +// argument to walkFn will always be convertible to a [fastwalk.DirEntry]. +// +// - The [fs.DirEntry] argument is always a [fastwalk.DirEntry], which has +// a Stat() method that returns the result of calling [os.Stat] on the +// file. The result of Stat() and Info() are cached. The [StatDirEntry] +// helper can be used to call Stat() on the returned [fastwalk.DirEntry]. +// +// - Walk can follow symlinks in two ways: the fist, and simplest, is to +// set Follow [Config] option to true - this will cause Walk to follow +// symlinks and detect/ignore any symlink loops; the second, is for walkFn +// to return the sentinel [ErrTraverseLink] error. +// When using [ErrTraverseLink] to follow symlinks it is walkFn's +// responsibility to prevent Walk from going into symlink cycles. +// By default Walk does not follow symbolic links. +// +// - When walking a directory, walkFn will be called for each non-directory +// entry and directories will be enqueued and visited at a later time or +// by another goroutine. func Walk(conf *Config, root string, walkFn fs.WalkDirFunc) error { fi, err := os.Stat(root) if err != nil { @@ -229,7 +400,10 @@ } w := &walker{ - fn: walkFn, + fn: walkFn, + // TODO: Increase the size of enqueuec so that we don't stall + // while processing a directory. Increasing the size of workc + // doesn't help as much (needs more testing). enqueuec: make(chan walkItem, numWorkers), // buffered for performance workc: make(chan walkItem, numWorkers), // buffered for performance donec: make(chan struct{}), @@ -237,8 +411,10 @@ // buffered for correctness & not leaking goroutines: resc: make(chan error, numWorkers), - follow: conf.Follow, - toSlash: conf.ToSlash, + // TODO: we should just pass the Config + follow: conf.Follow, + toSlash: conf.ToSlash, + sortMode: conf.Sort, } if w.follow { w.ignoredDirs = append(w.ignoredDirs, fi) @@ -252,6 +428,8 @@ } root = cleanRootPath(root) + // NOTE: in BenchmarkFastWalk the size of todo averages around + // 170 and can be in the ~250 range at max. todo := []walkItem{{dir: root, info: fileInfoToDirEntry(filepath.Dir(root), fi)}} out := 0 for { @@ -267,6 +445,8 @@ todo = todo[:len(todo)-1] out++ case it := <-w.enqueuec: + // TODO: consider appending to todo directly and using a + // mutext this might help with contention around select todo = append(todo, it) case err := <-w.resc: out-- @@ -317,14 +497,15 @@ enqueuec chan walkItem // from workers resc chan error // from workers - ignoredDirs []os.FileInfo + ignoredDirs []fs.FileInfo follow bool toSlash bool + sortMode SortMode } type walkItem struct { dir string - info fs.DirEntry + info DirEntry callbackDone bool // callback already called; don't do it again } @@ -335,7 +516,7 @@ } } -func (w *walker) shouldSkipDir(fi os.FileInfo) bool { +func (w *walker) shouldSkipDir(fi fs.FileInfo) bool { for _, ignored := range w.ignoredDirs { if os.SameFile(ignored, fi) { return true @@ -344,9 +525,8 @@ return false } -func (w *walker) shouldTraverse(path string, de fs.DirEntry) bool { - // TODO: do we need to use filepath.EvalSymlinks() here? - ts, err := StatDirEntry(path, de) +func (w *walker) shouldTraverse(path string, de DirEntry) bool { + ts, err := de.Stat() if err != nil { return false } @@ -381,13 +561,14 @@ } return dir + "/" + base } + // TODO: handle the above case of the argument to Walk being "/" if w.toSlash { return dir + "/" + base } return dir + string(os.PathSeparator) + base } -func (w *walker) onDirEnt(dirName, baseName string, de fs.DirEntry) error { +func (w *walker) onDirEnt(dirName, baseName string, de DirEntry) error { joined := w.joinPaths(dirName, baseName) typ := de.Type() if typ == os.ModeDir { @@ -418,7 +599,7 @@ return err } -func (w *walker) walk(root string, info fs.DirEntry, runUserCallback bool) error { +func (w *walker) walk(root string, info DirEntry, runUserCallback bool) error { if runUserCallback { err := w.fn(root, info, nil) if err == filepath.SkipDir { @@ -429,7 +610,7 @@ } } - err := readDir(root, w.onDirEnt) + err := w.readDir(root) if err != nil { // Second call, to report ReadDir error. return w.fn(root, info, err) @@ -448,3 +629,17 @@ } return root } + +// Avoid the dependency on strconv since it pulls in a large number of other +// dependencies which bloats the size of this package. +func itoa(val uint64) string { + buf := make([]byte, 20) + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return string(buf[i:]) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/fastwalk_darwin.go new/vendor/github.com/charlievieth/fastwalk/fastwalk_darwin.go --- old/vendor/github.com/charlievieth/fastwalk/fastwalk_darwin.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/fastwalk_darwin.go 2024-07-20 16:16:46.000000000 +0200 @@ -3,16 +3,12 @@ package fastwalk import ( - "io/fs" "os" "syscall" "unsafe" ) -//sys closedir(dir uintptr) (err error) -//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno) - -func readDir(dirName string, fn func(dirName, entName string, de fs.DirEntry) error) (err error) { +func (w *walker) readDir(dirName string) (err error) { var fd uintptr for { fd, err = opendir(dirName) @@ -25,6 +21,12 @@ } defer closedir(fd) //nolint:errcheck + var p *[]*unixDirent + if w.sortMode != SortNone { + p = direntSlicePool.Get().(*[]*unixDirent) + } + defer putDirentSlice(p) + skipFiles := false var dirent syscall.Dirent var entptr *syscall.Dirent @@ -66,14 +68,36 @@ continue } nm := string(name) - if err := fn(dirName, nm, newUnixDirent(dirName, nm, typ)); err != nil { + de := newUnixDirent(dirName, nm, typ) + if w.sortMode == SortNone { + if err := w.onDirEnt(dirName, nm, de); err != nil { + if err != ErrSkipFiles { + return err + } + skipFiles = true + } + } else { + *p = append(*p, de) + } + } + if w.sortMode == SortNone { + return nil + } + + dents := *p + sortDirents(w.sortMode, dents) + for _, d := range dents { + d := d + if skipFiles && d.typ.IsRegular() { + continue + } + if err := w.onDirEnt(dirName, d.Name(), d); err != nil { if err != ErrSkipFiles { return err } skipFiles = true } } - return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/fastwalk_portable.go new/vendor/github.com/charlievieth/fastwalk/fastwalk_portable.go --- old/vendor/github.com/charlievieth/fastwalk/fastwalk_portable.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/fastwalk_portable.go 2024-07-20 16:16:46.000000000 +0200 @@ -3,7 +3,6 @@ package fastwalk import ( - "io/fs" "os" ) @@ -11,7 +10,7 @@ // It does not descend into directories or follow symlinks. // If fn returns a non-nil error, readDir returns with that error // immediately. -func readDir(dirName string, fn func(dirName, entName string, de fs.DirEntry) error) error { +func (w *walker) readDir(dirName string) error { f, err := os.Open(dirName) if err != nil { return err @@ -22,6 +21,12 @@ return readErr } + var p *[]DirEntry + if w.sortMode != SortNone { + p = direntSlicePool.Get().(*[]DirEntry) + } + defer putDirentSlice(p) + var skipFiles bool for _, d := range des { if skipFiles && d.Type().IsRegular() { @@ -29,13 +34,34 @@ } // Need to use FileMode.Type().Type() for fs.DirEntry e := newDirEntry(dirName, d) - if err := fn(dirName, d.Name(), e); err != nil { + if w.sortMode == SortNone { + if err := w.onDirEnt(dirName, d.Name(), e); err != nil { + if err != ErrSkipFiles { + return err + } + skipFiles = true + } + } else { + *p = append(*p, e) + } + } + if w.sortMode == SortNone { + return readErr + } + + dents := *p + sortDirents(w.sortMode, dents) + for _, d := range dents { + d := d + if skipFiles && d.Type().IsRegular() { + continue + } + if err := w.onDirEnt(dirName, d.Name(), d); err != nil { if err != ErrSkipFiles { return err } skipFiles = true } } - return readErr } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/fastwalk_unix.go new/vendor/github.com/charlievieth/fastwalk/fastwalk_unix.go --- old/vendor/github.com/charlievieth/fastwalk/fastwalk_unix.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/fastwalk_unix.go 2024-07-20 16:16:46.000000000 +0200 @@ -7,7 +7,6 @@ package fastwalk import ( - "io/fs" "os" "syscall" @@ -21,13 +20,19 @@ // value used to represent a syscall.DT_UNKNOWN Dirent.Type. const unknownFileMode os.FileMode = ^os.FileMode(0) -func readDir(dirName string, fn func(dirName, entName string, de fs.DirEntry) error) error { +func (w *walker) readDir(dirName string) error { fd, err := open(dirName, 0, 0) if err != nil { return &os.PathError{Op: "open", Path: dirName, Err: err} } defer syscall.Close(fd) + var p *[]*unixDirent + if w.sortMode != SortNone { + p = direntSlicePool.Get().(*[]*unixDirent) + } + defer putDirentSlice(p) + // The buffer must be at least a block long. buf := make([]byte, blockSize) // stack-allocated; doesn't escape bufp := 0 // starting read position in buf @@ -41,7 +46,7 @@ return os.NewSyscallError("readdirent", err) } if nbuf <= 0 { - return nil + break // exit loop } } consumed, name, typ := dirent.Parse(buf[bufp:nbuf]) @@ -68,14 +73,37 @@ continue } de := newUnixDirent(dirName, name, typ) - if err := fn(dirName, name, de); err != nil { - if err == ErrSkipFiles { - skipFiles = true - continue + if w.sortMode == SortNone { + if err := w.onDirEnt(dirName, name, de); err != nil { + if err == ErrSkipFiles { + skipFiles = true + continue + } + return err + } + } else { + *p = append(*p, de) + } + } + if w.sortMode == SortNone { + return nil + } + + dents := *p + sortDirents(w.sortMode, dents) + for _, d := range dents { + d := d + if skipFiles && d.typ.IsRegular() { + continue + } + if err := w.onDirEnt(dirName, d.Name(), d); err != nil { + if err != ErrSkipFiles { + return err } - return err + skipFiles = true } } + return nil } // According to https://golang.org/doc/go1.14#runtime diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go120.go new/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go120.go --- old/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go120.go 1970-01-01 01:00:00.000000000 +0100 +++ new/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go120.go 2024-07-20 16:16:46.000000000 +0200 @@ -0,0 +1,31 @@ +//go:build !go1.21 + +package fmtdirent + +import "io/fs" + +// Backport fs.FormatDirEntry from go1.21 + +// FormatDirEntry returns a formatted version of dir for human readability. +// Implementations of [DirEntry] can call this from a String method. +// The outputs for a directory named subdir and a file named hello.go are: +// +// d subdir/ +// - hello.go +func FormatDirEntry(dir fs.DirEntry) string { + name := dir.Name() + b := make([]byte, 0, 5+len(name)) + + // The Type method does not return any permission bits, + // so strip them from the string. + mode := dir.Type().String() + mode = mode[:len(mode)-9] + + b = append(b, mode...) + b = append(b, ' ') + b = append(b, name...) + if dir.IsDir() { + b = append(b, '/') + } + return string(b) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go121.go new/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go121.go --- old/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go121.go 1970-01-01 01:00:00.000000000 +0100 +++ new/vendor/github.com/charlievieth/fastwalk/internal/fmtdirent/fmtdirent_go121.go 2024-07-20 16:16:46.000000000 +0200 @@ -0,0 +1,15 @@ +//go:build go1.21 + +package fmtdirent + +import "io/fs" + +// FormatDirEntry returns a formatted version of dir for human readability. +// Implementations of [DirEntry] can call this from a String method. +// The outputs for a directory named subdir and a file named hello.go are: +// +// d subdir/ +// - hello.go +func FormatDirEntry(dir fs.DirEntry) string { + return fs.FormatDirEntry(dir) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/path_portable.go new/vendor/github.com/charlievieth/fastwalk/path_portable.go --- old/vendor/github.com/charlievieth/fastwalk/path_portable.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/path_portable.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -//go:build !windows - -package fastwalk - -func useForwardSlash() bool { - return false -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/path_windows.go new/vendor/github.com/charlievieth/fastwalk/path_windows.go --- old/vendor/github.com/charlievieth/fastwalk/path_windows.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/path_windows.go 1970-01-01 01:00:00.000000000 +0100 @@ -1,62 +0,0 @@ -//go:build windows - -package fastwalk - -import ( - "bytes" - "os" - "runtime" - "sync" -) - -func useForwardSlash() bool { - // Use a forward slash as the path separator if this a Windows executable - // running in either MSYS/MSYS2 or WSL. - return runningUnderMSYS() || runningUnderWSL() -} - -// runningUnderMSYS reports if we're running in a MSYS/MSYS2 enviroment. -// -// See: https://github.com/sharkdp/fd/pull/730 -func runningUnderMSYS() bool { - switch os.Getenv("MSYSTEM") { - case "MINGW64", "MINGW32", "MSYS": - return true - } - return false -} - -var underWSL struct { - once sync.Once - wsl bool -} - -// runningUnderWSL returns if we're a Widows executable running in WSL. -// See [DefaultToSlash] for an explanation of the heuristics used here. -func runningUnderWSL() bool { - if runtime.GOOS != "windows" { - return false - } - w := &underWSL - w.once.Do(func() { - w.wsl = func() bool { - // Best check (but not super fast) - if _, err := os.Lstat("/proc/sys/fs/binfmt_misc/WSLInterop"); err == nil { - return true - } - // Fast check, but could provide a false positive if the user sets - // this on the Windows side. - if os.Getenv("WSL_DISTRO_NAME") != "" { - return true - } - // If the binary is compiled for Windows and we're running under Linux - // then honestly just the presence of "/proc/version" should be enough - // to determine that we're running under WSL, but check the version - // string just to be pedantic. - data, _ := os.ReadFile("/proc/version") - return bytes.Contains(data, []byte("microsoft")) || - bytes.Contains(data, []byte("Microsoft")) - }() - }) - return w.wsl -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/github.com/charlievieth/fastwalk/zsyscall_darwin.go new/vendor/github.com/charlievieth/fastwalk/zsyscall_darwin.go --- old/vendor/github.com/charlievieth/fastwalk/zsyscall_darwin.go 2024-07-08 16:14:30.000000000 +0200 +++ new/vendor/github.com/charlievieth/fastwalk/zsyscall_darwin.go 2024-07-20 16:16:46.000000000 +0200 @@ -44,7 +44,9 @@ // We implent opendir so that we don't have to open a file, duplicate // it's FD, then call fdopendir with it. - var buf [1024]byte // Tested by TestFastWalk_LongPath + const maxPath = len(syscall.Dirent{}.Name) // Tested by TestFastWalk_LongPath + + var buf [maxPath]byte if len(path) >= len(buf) { return 0, errEINVAL } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt --- old/vendor/modules.txt 2024-07-08 16:14:31.000000000 +0200 +++ new/vendor/modules.txt 2024-07-20 16:16:46.000000000 +0200 @@ -1,7 +1,8 @@ -# github.com/charlievieth/fastwalk v1.0.7-0.20240703190418-87029d931815 +# github.com/charlievieth/fastwalk v1.0.8 ## explicit; go 1.20 github.com/charlievieth/fastwalk github.com/charlievieth/fastwalk/internal/dirent +github.com/charlievieth/fastwalk/internal/fmtdirent # github.com/gdamore/encoding v1.0.0 ## explicit; go 1.9 github.com/gdamore/encoding
participants (1)
-
Source-Sync