diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index c81bc07a9..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: [sharkdp, tavianator] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml deleted file mode 100644 index d6c8d3c7a..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Bug Report -description: Report a bug. -title: "[BUG] " -labels: bug -body: - - type: markdown - attributes: - value: | - Please check out the [troubleshooting section](https://github.com/sharkdp/fd#troubleshooting) first. - - type: checkboxes - attributes: - label: Checks - options: - - label: I have read the troubleshooting section and still think this is a bug. - required: true - - type: textarea - id: bug - attributes: - label: "Describe the bug you encountered:" - validations: - required: true - - type: textarea - id: expected - attributes: - label: "Describe what you expected to happen:" - - type: input - id: version - attributes: - label: "What version of `fd` are you using?" - placeholder: "paste the output of `fd --version` here" - validations: - required: true - - type: textarea - id: os - attributes: - label: Which operating system / distribution are you on? - placeholder: | - Unix: paste the output of `uname -srm` and `lsb_release -a` here. - Windows: please tell us your Windows version - render: shell - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 0086358db..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 93af6cdf3..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: Feature Request -about: Suggest an idea for this project. -title: '' -labels: feature-request -assignees: '' - ---- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index d3e875268..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: Question -about: Ask a question about 'fd'. -title: '' -labels: question -assignees: '' - ---- - - - -**What version of `fd` are you using?** -[paste the output of `fd --version` here] diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 8c6f2434f..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,10 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "cargo" - directory: "/" - schedule: - interval: "monthly" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml deleted file mode 100644 index c13435618..000000000 --- a/.github/workflows/CICD.yml +++ /dev/null @@ -1,265 +0,0 @@ -name: CICD - -env: - CICD_INTERMEDIATES_DIR: "_cicd-intermediates" - MSRV_FEATURES: "--all-features" - -on: - workflow_dispatch: - pull_request: - push: - branches: - - master - tags: - - '*' - -jobs: - crate_metadata: - name: Extract crate metadata - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: Extract crate information - id: crate_metadata - run: | - echo "name=fd" | tee -a $GITHUB_OUTPUT - cargo metadata --no-deps --format-version 1 | jq -r '"version=" + .packages[0].version' | tee -a $GITHUB_OUTPUT - cargo metadata --no-deps --format-version 1 | jq -r '"maintainer=" + .packages[0].authors[0]' | tee -a $GITHUB_OUTPUT - cargo metadata --no-deps --format-version 1 | jq -r '"homepage=" + .packages[0].homepage' | tee -a $GITHUB_OUTPUT - cargo metadata --no-deps --format-version 1 | jq -r '"msrv=" + .packages[0].rust_version' | tee -a $GITHUB_OUTPUT - outputs: - name: ${{ steps.crate_metadata.outputs.name }} - version: ${{ steps.crate_metadata.outputs.version }} - maintainer: ${{ steps.crate_metadata.outputs.maintainer }} - homepage: ${{ steps.crate_metadata.outputs.homepage }} - msrv: ${{ steps.crate_metadata.outputs.msrv }} - - ensure_cargo_fmt: - name: Ensure 'cargo fmt' has been run - runs-on: ubuntu-22.04 - steps: - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - uses: actions/checkout@v5 - - run: cargo fmt -- --check - - lint_check: - name: Ensure 'cargo clippy' has no warnings - runs-on: ubuntu-latest - steps: - - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - uses: actions/checkout@v5 - - run: cargo clippy --all-targets --all-features -- -Dwarnings - - min_version: - name: Minimum supported rust version - runs-on: ubuntu-22.04 - needs: crate_metadata - steps: - - name: Checkout source code - uses: actions/checkout@v5 - - - name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }}) - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ needs.crate_metadata.outputs.msrv }} - components: clippy - - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix) - run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }} - - name: Run tests - run: cargo test --locked ${{ env.MSRV_FEATURES }} - - build: - name: ${{ matrix.job.target }} (${{ matrix.job.os }}) - runs-on: ${{ matrix.job.os }} - needs: crate_metadata - strategy: - fail-fast: false - matrix: - job: - - { target: aarch64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true } - - { target: aarch64-unknown-linux-musl , os: ubuntu-24.04, use-cross: true } - - { target: arm-unknown-linux-gnueabihf , os: ubuntu-24.04, use-cross: true } - - { target: arm-unknown-linux-musleabihf, os: ubuntu-24.04, use-cross: true } - - { target: i686-pc-windows-msvc , os: windows-2022 } - - { target: i686-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true } - - { target: i686-unknown-linux-musl , os: ubuntu-24.04, use-cross: true } - - { target: aarch64-apple-darwin , os: macos-14 } - - { target: x86_64-pc-windows-gnu , os: windows-2022 } - - { target: x86_64-pc-windows-msvc , os: windows-2022 } - - { target: aarch64-pc-windows-msvc , os: windows-11-arm } - - { target: x86_64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true } - - { target: x86_64-unknown-linux-musl , os: ubuntu-24.04, use-cross: true } - env: - BUILD_CMD: cargo - steps: - - name: Checkout source code - uses: actions/checkout@v5 - - - name: Install prerequisites - shell: bash - run: | - case ${{ matrix.job.target }} in - arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; - aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;; - esac - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - targets: ${{ matrix.job.target }} - # On windows, for now build with 1.77.2, so that it works on windows 7. - # When we update the MSRV again, we'll need to revisit this, and probably drop support for Win7 - toolchain: "${{ contains(matrix.job.target, 'windows-') && '1.77.2' || 'stable' }}" - - - name: Install cross - if: matrix.job.use-cross - uses: taiki-e/install-action@v2 - with: - tool: cross - - - name: Overwrite build command env variable - if: matrix.job.use-cross - shell: bash - run: echo "BUILD_CMD=cross" >> $GITHUB_ENV - - - name: Show version information (Rust, cargo, GCC) - shell: bash - run: | - gcc --version || true - rustup -V - rustup toolchain list - rustup default - cargo -V - rustc -V - - - name: Build - shell: bash - run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }} - - - name: Set binary name & path - id: bin - shell: bash - run: | - # Figure out suffix of binary - EXE_suffix="" - case ${{ matrix.job.target }} in - *-pc-windows-*) EXE_suffix=".exe" ;; - esac; - - # Setup paths - BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}" - BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}" - - # Let subsequent steps know where to find the binary - echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT - echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT - - - name: Set testing options - id: test-options - shell: bash - run: | - # test only library unit tests and binary for arm-type targets - unset CARGO_TEST_OPTIONS - unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--bin ${{ needs.crate_metadata.outputs.name }}" ;; esac; - echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT - - - name: Run tests - shell: bash - run: $BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}} - - - name: Generate completions - id: completions - shell: bash - run: make completions - - - name: Create tarball - id: package - shell: bash - run: | - PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac; - PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }} - PKG_NAME=${PKG_BASENAME}${PKG_suffix} - echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT - - PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package" - ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/" - mkdir -p "${ARCHIVE_DIR}" - - # Binary - cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR" - - # README, LICENSE and CHANGELOG files - cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR" - - # Man page - cp 'doc/${{ needs.crate_metadata.outputs.name }}.1' "$ARCHIVE_DIR" - - # Autocompletion files - cp -r autocomplete "${ARCHIVE_DIR}" - - # base compressed package - pushd "${PKG_STAGING}/" >/dev/null - case ${{ matrix.job.target }} in - *-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;; - *) tar czf "${PKG_NAME}" "${PKG_BASENAME}"/* ;; - esac; - popd >/dev/null - - # Let subsequent steps know where to find the compressed package - echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT - - - name: Create Debian package - id: debian-package - shell: bash - if: startsWith(matrix.job.os, 'ubuntu') - run: bash scripts/create-deb.sh - env: - TARGET: ${{ matrix.job.target }} - DPKG_VERSION: ${{ needs.crate_metadata.version }} - BIN_PATH: ${{ steps.bin.outputs.BIN_PATH }} - - - name: "Artifact upload: tarball" - uses: actions/upload-artifact@master - with: - name: ${{ steps.package.outputs.PKG_NAME }} - path: ${{ steps.package.outputs.PKG_PATH }} - - - name: "Artifact upload: Debian package" - uses: actions/upload-artifact@master - if: steps.debian-package.outputs.DPKG_NAME - with: - name: ${{ steps.debian-package.outputs.DPKG_NAME }} - path: ${{ steps.debian-package.outputs.DPKG_PATH }} - - - name: Check for release - id: is-release - shell: bash - run: | - unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi - echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT - - - name: Publish archives and packages - uses: softprops/action-gh-release@v2 - if: steps.is-release.outputs.IS_RELEASE - with: - files: | - ${{ steps.package.outputs.PKG_PATH }} - ${{ steps.debian-package.outputs.DPKG_PATH }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - winget: - name: Publish to Winget - runs-on: ubuntu-latest - needs: build - if: startsWith(github.ref, 'refs/tags/v') - steps: - - uses: vedantmgoyal2009/winget-releaser@v2 - with: - identifier: sharkdp.fd - installers-regex: '-pc-windows-msvc\.zip$' - token: ${{ secrets.WINGET_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index 1f76c18a2..d07bbbd72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -43,29 +43,29 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "argmax" @@ -86,9 +86,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bstr" @@ -102,18 +102,19 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.29" +version = "1.2.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cfg_aliases" @@ -123,9 +124,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.46" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ "clap_builder", "clap_derive", @@ -133,9 +134,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.46" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ "anstream", "anstyle", @@ -146,18 +147,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.57" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad" +checksum = "75bf0b32ad2e152de789bb635ea4d3078f6b838ad7974143e99b99f45a04af4a" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.45" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", @@ -213,12 +214,13 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "ctrlc" -version = "3.4.7" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3" dependencies = [ + "dispatch", "nix", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -228,24 +230,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] -name = "errno" -version = "0.3.13" +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", - "windows-sys 0.60.2", + "option-ext", + "redox_users", + "windows-sys 0.61.0", ] [[package]] -name = "etcetera" -version = "0.10.0" +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "cfg-if", - "home", - "windows-sys 0.59.0", + "libc", + "windows-sys 0.61.0", ] [[package]] @@ -277,11 +295,10 @@ dependencies = [ "crossbeam-channel", "ctrlc", "diff", - "etcetera", + "dirs", "faccess", "filetime", "globset", - "home", "ignore", "jiff", "libc", @@ -298,14 +315,31 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" dependencies = [ "cfg-if", "libc", "libredox", - "windows-sys 0.59.0", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -317,7 +351,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -339,15 +373,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "ignore" version = "0.4.23" @@ -413,32 +438,32 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libredox" -version = "0.1.4" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "libc", "redox_syscall", ] [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "lscolors" @@ -462,7 +487,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "cfg-if", "cfg_aliases", "libc", @@ -470,11 +495,11 @@ dependencies = [ [[package]] name = "normpath" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" +checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -498,6 +523,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "portable-atomic" version = "1.11.1" @@ -515,9 +546,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -539,11 +570,22 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror", ] [[package]] @@ -560,9 +602,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick", "memchr", @@ -577,15 +619,15 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "rustix" -version = "1.0.7" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -599,18 +641,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.226" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", @@ -631,9 +682,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -642,25 +693,25 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.21.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom", + "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -696,6 +747,26 @@ dependencies = [ "test-case-core", ] +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tikv-jemalloc-sys" version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" @@ -718,9 +789,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "utf8parse" @@ -740,11 +811,26 @@ dependencies = [ [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] @@ -765,11 +851,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.0", ] [[package]] @@ -778,6 +864,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-sys" version = "0.52.0" @@ -802,7 +900,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +dependencies = [ + "windows-link 0.2.0", ] [[package]] @@ -823,10 +930,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.2" +version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -934,10 +1042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml index d0a92dc09..5b483a010 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ readme = "README.md" repository = "https://github.com/sharkdp/fd" version = "10.3.0" edition= "2021" -rust-version = "1.77.2" +rust-version = "1.74.0" [badges.appveyor] repository = "sharkdp/fd" @@ -40,15 +40,13 @@ regex-syntax = "0.8" ctrlc = "3.4" globset = "0.4" anyhow = "1.0" -etcetera = "0.10" +dirs = "6.0.0" normpath = "1.1.1" crossbeam-channel = "0.5.15" clap_complete = {version = "4.5.57", optional = true} faccess = "0.2.4" jiff = "0.2.14" -# For now, pin the `home` crate to less than 0.5.11, to ensure it works on older versions of rust -# TODO: when we upgrade past rust 1.85, remove this dependency -home = "=0.5.9" +tikv-jemallocator = { version = "0.6.0", optional = true } [dependencies.clap] version = "4.5.46" @@ -65,14 +63,6 @@ nix = { version = "0.30.1", default-features = false, features = ["signal", "use [target.'cfg(all(unix, not(target_os = "redox")))'.dependencies] libc = "0.2" -# FIXME: Re-enable jemalloc on macOS -# jemalloc is currently disabled on macOS due to a bug in jemalloc in combination with macOS -# Catalina. See https://github.com/sharkdp/fd/issues/498 for details. -# This has to be kept in sync with src/main.rs where the allocator for -# the program is set. -[target.'cfg(all(not(windows), not(target_os = "android"), not(target_os = "macos"), not(target_os = "freebsd"), not(target_os = "openbsd"), not(target_os = "illumos"), not(all(target_env = "musl", target_pointer_width = "32")), not(target_arch = "riscv64")))'.dependencies] -tikv-jemallocator = {version = "0.6.0", optional = true} - [dev-dependencies] diff = "0.1" tempfile = "3.21" @@ -80,12 +70,30 @@ filetime = "0.2" test-case = "3.3" [profile.release] -lto = true -strip = true -codegen-units = 1 +lto = "thin" [features] -use-jemalloc = ["tikv-jemallocator"] +default = ["completions"] +fd-no-gitversion = [] +jemalloc = ["tikv-jemallocator"] completions = ["clap_complete"] -base = ["use-jemalloc"] -default = ["use-jemalloc", "completions"] + +[package.metadata.deb] +name = "fd-wild" +section = "utils" +assets = [ + ["target/release/fd", "usr/bin/", "755"], + ["LICENSE-MIT", "usr/share/doc/fd/", "644"], + ["LICENSE-APACHE", "usr/share/doc/fd/", "644"], + ["README.md", "usr/share/doc/fd/README", "644"], + ["doc/fd.1", "usr/share/man/man1/", "644"], + ["autocomplete/fd.bash", "usr/share/bash-completion/completions/fd", "644"], + ["autocomplete/fd.fish", "usr/share/fish/vendor_completions.d/", "644"], + ["autocomplete/_fd", "usr/share/zsh/vendor-completions/", "644"], +] +extended-description = """\ +fd is a program to find entries in your filesystem. It is a simple, fast and +user-friendly alternative to find. While it does not aim to support all of +find's powerful functionality, it provides sensible (opinionated) defaults for +a majority of use cases. +""" diff --git a/Makefile b/Makefile index b35127117..7b83997f9 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,82 @@ -PROFILE=release -EXE=target/$(PROFILE)/fd -prefix=/usr/local -bindir=$(prefix)/bin -datadir=$(prefix)/share -exe_name=fd +# Makefile for fd, a wrapper for cargo plus install/dist targets -$(EXE): Cargo.toml src/**/*.rs - cargo build --profile $(PROFILE) --locked +# don't let make do anything in parallel, cargo build handles that +.NOTPARALLEL: + +# install paths +prefix ?= /usr/local +bindir ?= $(prefix)/bin +datadir ?= $(prefix)/share +mandir ?= $(datadir)/man +bashcompdir ?= $(datadir)/bash-completion/completions +fishcompdir ?= $(datadir)/fish/vendor_completions.d +zshcompdir ?= $(datadir)/zsh/site-functions + +# tools +CARGO ?= cargo +INSTALL ?= install +STRIP ?= strip +RM ?= rm -f +ifeq ($(NOSTRIP),) +INSTALL_STRIP ?= $(INSTALL) -s --strip-program=$(STRIP) +else +INSTALL_STRIP ?= $(INSTALL) +endif +TAR ?= tar + +# build configuration +# release build default for install/dist, otherwise debug build +ifneq ($(filter install dist,$(MAKECMDGOALS)),) +BUILD_TYPE ?= release +else +BUILD_TYPE ?= debug +endif +# 'make R=1' as a shortcut for 'make BUILD_TYPE=release' +ifeq ($(R),1) +BUILD_TYPE := release +endif +# set flags for release build +ifeq ($(BUILD_TYPE),release) +CARGO_BUILD_FLAGS += --release --locked --features jemalloc +endif + +# whether to run install commands with sudo +ifeq ($(SUDO_INSTALL),1) +INSTALL := sudo $(INSTALL) +RM := sudo $(RM) +endif + +ifneq ($(TARGET),) +TARGET_DIR = target/$(TARGET) +CARGO_BUILD_FLAGS += --target $(TARGET) +else +TARGET_DIR = target +TARGET := $(shell ci/default_target.bash) +endif + +ifeq ($(findstring windows,$(TARGET)),windows) +EXEEXT := .exe +else +EXEEXT := +endif + +EXE := $(TARGET_DIR)/$(BUILD_TYPE)/fd$(EXEEXT) + +# easy hack to avoid re-running cargo when not needed +SOURCES = $(shell find src -type f) build.rs Cargo.toml + +.PHONY: build +build: $(EXE) +$(EXE): $(SOURCES) + $(CARGO) build $(CARGO_BUILD_FLAGS) + +.PHONY: test +test: + $(CARGO) test $(CARGO_BUILD_FLAGS) + +.PHONY: clean +clean: + $(CARGO) clean .PHONY: completions completions: autocomplete/fd.bash autocomplete/fd.fish autocomplete/fd.ps1 autocomplete/_fd @@ -29,9 +99,33 @@ autocomplete/_fd: contrib/completion/_fd $(comp_dir) cp $< $@ -install: $(EXE) completions - install -Dm755 $(EXE) $(DESTDIR)$(bindir)/fd - install -Dm644 autocomplete/fd.bash $(DESTDIR)/$(datadir)/bash-completion/completions/$(exe_name) - install -Dm644 autocomplete/fd.fish $(DESTDIR)/$(datadir)/fish/vendor_completions.d/$(exe_name).fish - install -Dm644 autocomplete/_fd $(DESTDIR)/$(datadir)/zsh/site-functions/_$(exe_name) - install -Dm644 doc/fd.1 $(DESTDIR)/$(datadir)/man/man1/$(exe_name).1 +.PHONY: install +install: completions + $(INSTALL) -d $(DESTDIR)$(bindir) + $(INSTALL_STRIP) -m755 $(EXE) $(DESTDIR)$(bindir)/ + $(INSTALL) -Dm644 autocomplete/fd.bash $(DESTDIR)$(bashcompdir)/fd + $(INSTALL) -Dm644 autocomplete/fd.fish $(DESTDIR)$(fishcompdir)/fd.fish + $(INSTALL) -Dm644 autocomplete/_fd $(DESTDIR)$(zshcompdir)/_fd + $(INSTALL) -Dm644 doc/fd.1 $(DESTDIR)$(mandir)/man1/fd.1 + +.PHONY: uninstall +uninstall: + $(RM) $(DESTDIR)$(bindir)/$(notdir $(EXE)) + $(RM) $(DESTDIR)$(bashcompdir)/fd + $(RM) $(DESTDIR)$(fishcompdir)/fd.fish + $(RM) $(DESTDIR)$(zshcompdir)/_fd + $(RM) $(DESTDIR)$(mandir)/man1/fd.1 + +.PHONY: dist +dist: output_file = $(shell find $(TARGET_DIR)/$(BUILD_TYPE) -path '*/fd-find-*/output' -type f -exec ls -dt {} + | head -n1) +dist: fd_dist_name = fd-$(shell sed -n 's/.*FD_GIT_VERSION=\(.*\)/\1/p' '$(output_file)')-$(TARGET) +dist: $(EXE) + $(INSTALL) -d $(TARGET_DIR)/dist/$(fd_dist_name) + $(MAKE) --no-print-directory prefix= DESTDIR=$(PWD)/$(TARGET_DIR)/dist/$(fd_dist_name) install + $(TAR) -cvzf $(fd_dist_name).tar.gz --owner=root:0 --group=root:0 -C $(TARGET_DIR)/dist $(fd_dist_name) + +# this has no dependencies, the build-deb script handles building everything. +# The leading + silences jobserver warnings, since build-deb internally calls "make completions" +.PHONY: deb +deb: + +ci/build-deb diff --git a/build.rs b/build.rs new file mode 100644 index 000000000..e807ff132 --- /dev/null +++ b/build.rs @@ -0,0 +1,21 @@ +fn main() { + // determine version from "git describe", unless disabled + if !cfg!(feature = "fd-no-gitversion") { + let git_describe_out = std::process::Command::new("git") + .arg("describe") + .arg("--tags") + .arg("--dirty=+") + .stderr(std::process::Stdio::inherit()) + .output(); + if let Ok(out) = git_describe_out { + if out.status.success() { + // stringify output, strip whitespace, and strip a leading 'v' + let git_version = String::from_utf8_lossy(&out.stdout); + let git_version_trimmed = git_version.trim().trim_start_matches('v'); + println!("cargo:rustc-env=FD_GIT_VERSION={git_version_trimmed}"); + } + } + println!("cargo:rerun-if-changed=.git/index"); + println!("cargo:rerun-if-changed=.git/HEAD"); + } +} diff --git a/ci/build-deb b/ci/build-deb new file mode 100755 index 000000000..c27b8072a --- /dev/null +++ b/ci/build-deb @@ -0,0 +1,57 @@ +#!/bin/bash + +set -e + +# This script builds a binary dpkg for Debian based distros. It is based +# on the script from ripgrep. +# +# Note that this requires 'cargo deb', which can be installed with +# 'cargo install cargo-deb'. +# +# This should be run from the root of the fd repo. + +TARGET='' +INSTALL_ARG='' +while (( $# )); do + case "$1" in + --target) + if [[ -z "$2" ]]; then + echo >2 "Error: missing argument to --target" + exit 1 + fi + TARGET="$2" + shift + ;; + --install|-i) + INSTALL_ARG='--install' + ;; + esac + shift +done + +if [[ -n "$TARGET" ]]; then + TARGET_ARGS=(--target "$TARGET") +else + TARGET_ARGS=() +fi + +if ! command -V cargo-deb > /dev/null 2>&1; then + echo "cargo-deb command missing" >&2 + exit 1 +fi + +version="$(git describe --tags --dirty=+ | sed 's/^v//')" + +set -x + +# generate completions, since they're generated from the fd binary itself. +# we allow a debug build to run here, and always with the native target since +# it must be executed. +make completions + +# now build the release binary and package, for the appropriate target. Override +# the package's version to use the full git version. +export CC=clang +export CARGO_PROFILE_RELEASE_LTO=true +export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-fuse-ld=lld" +cargo deb "${TARGET_ARGS[@]}" --features jemalloc --deb-version "$version" $INSTALL_ARG diff --git a/ci/build-docker b/ci/build-docker new file mode 100755 index 000000000..86aca7742 --- /dev/null +++ b/ci/build-docker @@ -0,0 +1,33 @@ +#!/bin/bash + +run() { + echo "+ $*" >&2 + "$@" +} + +die() { + echo "Error $*" >&2 + exit 1 +} + +set -e + +if [[ ! -f Cargo.lock ]]; then + die "Please run from the root of the repo" +fi + +SUITE="${1:-}" +if [[ -z "$SUITE" ]]; then + die "Missing distro suite argument" +fi + +DOCKER_IMAGE=aswild/rust:$SUITE +_uid=$(id -u) +_gid=$(id -g) + +run docker run -ti --rm \ + --user "${_uid}:${_gid}" \ + --volume "$PWD:/build" \ + --workdir /build \ + $DOCKER_IMAGE \ + ci/build-deb --no-target diff --git a/ci/default_target.bash b/ci/default_target.bash new file mode 100755 index 000000000..ea27770ac --- /dev/null +++ b/ci/default_target.bash @@ -0,0 +1,32 @@ +#!/bin/bash + +# try to use GNU Awk +if which gawk &>/dev/null; then + AWK=gawk +else + AWK=awk +fi + +# rust doesn't give a way to dump the current target triple, +# so reconstruct it from the cfg output +# % rustc --print cfg +# debug_assertions +# target_arch="x86_64" +# target_endian="little" +# target_env="gnu" +# target_family="unix" +# target_feature="fxsr" +# target_feature="sse" +# target_feature="sse2" +# target_os="linux" +# target_pointer_width="64" +# target_vendor="unknown" +# unix + +rustc --print cfg | "$AWK" -F= ' +($1 == "target_arch") {gsub(/"/, "", $2); arch=$2} +($1 == "target_vendor") {gsub(/"/, "", $2); vendor=$2} +($1 == "target_os") {gsub(/"/, "", $2); os=$2} +($1 == "target_env") {gsub(/"/, "", $2); env=$2} +END {print arch"-"vendor"-"os"-"env} +' diff --git a/ci/make_dist.bash b/ci/make_dist.bash new file mode 100755 index 000000000..286b22f08 --- /dev/null +++ b/ci/make_dist.bash @@ -0,0 +1,33 @@ +#!/bin/bash + +set -euo pipefail + +run() { + echo "+ $*" + "$@" +} + +build_arch() { + local target="$1" + local strip="$2" + local strip_arg + if [[ -n "$strip" ]]; then + strip_arg="STRIP=$strip" + else + strip_arg="NOSTRIP=1" + fi + run make TARGET="$target" "$strip_arg" build dist +} + +if [[ "${1:-}" == "--docker" ]]; then + run docker run --rm --user "$(id -u)":"$(id -g)" -v "$PWD":/usr/src/fd -w /usr/src/fd \ + aswild/rust-multiarch ci/make_dist.bash + exit 0 +fi + +run make clean + +build_arch x86_64-unknown-linux-gnu strip +build_arch aarch64-unknown-linux-gnu aarch64-linux-gnu-strip +build_arch aarch64-unknown-linux-musl aarch64-linux-gnu-strip +build_arch x86_64-pc-windows-gnu x86_64-w64-mingw32-strip diff --git a/doc/fd.1 b/doc/fd.1 index 4a6aa0ece..7edc8d4fa 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -131,6 +131,10 @@ for '--exec-batch ls -l' with some additional 'ls' options. This can be used to see more metadata, to show symlink targets and to achieve a deterministic sort order. .TP +.B \-T, \-\-details\-sort\-time +Sort results by modification time when using -l/--list-details. This is equivalent to passing +the '-t' flag to 'ls -l'. Currently supported for GNU 'ls' only. +.TP .B \-L, \-\-follow By default, fd does not descend into symlinked directories. Using this flag, symbolic links are also traversed. The flag can be overridden with '--no-follow'. @@ -253,9 +257,7 @@ Examples: Filter search results by file extension .IR ext . This option can be used repeatedly to allow for multiple possible file extensions. - -If you want to search for files without extension, you can use the regex '^[^.]+$' -as a normal search pattern. +If the extension is empty (e.g. 'fd -e ""'), then search for files with no extension. .TP .BI "\-E, \-\-exclude " pattern Exclude files/directories that match the given glob pattern. diff --git a/src/cli.rs b/src/cli.rs index b45ef12dc..442d407f5 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -21,7 +21,7 @@ use crate::filter::SizeFilter; #[derive(Parser)] #[command( name = "fd", - version, + version = option_env!("FD_GIT_VERSION").unwrap_or(clap::crate_version!()), about = "A program to find entries in your filesystem", after_long_help = "Bugs can be reported on GitHub: https://github.com/sharkdp/fd/issues", max_term_width = 98, @@ -219,6 +219,18 @@ pub struct Opts { )] pub list_details: bool, + /// Sort results by modification time when using -l/--list-details. This + /// is equivalent to passing the '-t' flag to 'ls -l'. Currently supported + /// for GNU 'ls' only. + #[arg( + long, + short = 'T', + requires("list_details"), + help = "Sort results by modification time in -l/--list-details mode", + long_help + )] + pub details_sort_time: bool, + /// Follow symbolic links #[arg( long, @@ -652,7 +664,13 @@ pub struct Opts { /// path starting with '-' being treated as a command line option. Use /// this flag to change this behavior. If this flag is used without a value, /// it is equivalent to passing "always". - #[arg(long, conflicts_with_all(&["path", "search_path"]), value_name = "when", hide_short_help = true, require_equals = true, long_help)] + #[arg( + long, + value_name = "when", + hide_short_help = true, + require_equals = true, + long_help + )] strip_cwd_prefix: Option>, /// By default, fd will traverse the file system tree as far as other options @@ -729,9 +747,10 @@ impl Opts { } pub fn max_results(&self) -> Option { - self.max_results - .filter(|&m| m > 0) - .or_else(|| self.max_one_result.then_some(1)) + match self.max_results { + None | Some(0) => self.max_one_result.then_some(1), + Some(n) => Some(n), + } } pub fn strip_cwd_prefix bool>(&self, auto_pred: P) -> bool { diff --git a/src/filetypes.rs b/src/filetypes.rs index a10924b06..250bcc757 100644 --- a/src/filetypes.rs +++ b/src/filetypes.rs @@ -20,6 +20,12 @@ pub struct FileTypes { impl FileTypes { pub fn should_ignore(&self, entry: &dir_entry::DirEntry) -> bool { if let Some(ref entry_type) = entry.file_type() { + // When searching for files, include non-broken symlinks to files without + // needing to use -L or -tl. + if self.files && entry_type.is_symlink() && entry.path().is_file() { + return false; + } + (!self.files && entry_type.is_file()) || (!self.directories && entry_type.is_dir()) || (!self.symlinks && entry_type.is_symlink()) diff --git a/src/main.rs b/src/main.rs index 94623eb79..1086b3ecd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![allow(clippy::uninlined_format_args)] + mod cli; mod config; mod dir_entry; @@ -34,21 +36,7 @@ use crate::filter::OwnerFilter; use crate::filter::TimeFilter; use crate::regex_helper::{pattern_has_uppercase_char, pattern_matches_strings_with_leading_dot}; -// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481 -// FIXME: re-enable jemalloc on macOS, see comment in Cargo.toml file for more infos -// This has to be kept in sync with the Cargo.toml file section that declares a -// dependency on tikv-jemallocator. -#[cfg(all( - not(windows), - not(target_os = "android"), - not(target_os = "macos"), - not(target_os = "freebsd"), - not(target_os = "openbsd"), - not(target_os = "illumos"), - not(all(target_env = "musl", target_pointer_width = "32")), - not(target_arch = "riscv64"), - feature = "use-jemalloc" -))] +#[cfg(feature = "jemalloc")] #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; @@ -300,10 +288,13 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result Result Result> { +fn determine_ls_command(colored_output: bool, sort_by_time: bool) -> Result> { #[allow(unused)] let gnu_ls = |command_name| { let color_arg = if colored_output { @@ -356,13 +347,17 @@ fn determine_ls_command(colored_output: bool) -> Result> { }; // Note: we use short options here (instead of --long-options) to support more // platforms (like BusyBox). - vec![ + let mut args = vec![ command_name, "-l", // long listing format "-h", // human readable file sizes "-d", // list directories themselves, not their contents color_arg, - ] + ]; + if sort_by_time { + args.push("-t"); + } + args }; let cmd: Vec<&str> = if cfg!(unix) { if !cfg!(any( @@ -482,10 +477,9 @@ fn build_regex(pattern_regex: String, config: &Config) -> Result(stdout: &mut W, entry: &DirEntry, config: &Config) if let Some(ref format) = config.format { print_entry_format(stdout, entry, config, format)?; } else if let Some(ref ls_colors) = config.ls_colors { - print_entry_colorized(stdout, entry, config, ls_colors)?; + // When following symlinks, stat each path component so that symlinks can be highlighted + // accordingly. Normally all parent components must be directories, so we can skip that step + // for a performance boost. + if config.follow_links { + print_entry_colorized_each_component(stdout, entry, config, ls_colors)?; + } else { + print_entry_colorized(stdout, entry, config, ls_colors)?; + } } else { print_entry_uncolorized(stdout, entry, config)?; }; @@ -131,6 +138,32 @@ fn print_entry_colorized( Ok(()) } +// TODO: this function is performance critical and can probably be optimized +fn print_entry_colorized_each_component( + stdout: &mut W, + entry: &DirEntry, + config: &Config, + ls_colors: &LsColors, +) -> io::Result<()> { + let path = entry.stripped_path(config); + let default_style = nu_ansi_term::Style::default(); + + // Traverse the path and colorize each component + for (component, style) in ls_colors.style_for_path_components(path) { + let style = style + .map(Style::to_nu_ansi_term_style) + .unwrap_or(default_style); + + let mut path_string = component.to_string_lossy(); + if let Some(ref separator) = config.path_separator { + *path_string.to_mut() = replace_path_separator(&path_string, separator); + } + write!(stdout, "{}", style.paint(path_string))?; + } + + Ok(()) +} + // TODO: this function is performance critical and can probably be optimized fn print_entry_uncolorized_base( stdout: &mut W, diff --git a/src/walk.rs b/src/walk.rs index 0991e1c73..7b3d10d11 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -10,7 +10,6 @@ use std::time::{Duration, Instant}; use anyhow::{anyhow, Result}; use crossbeam_channel::{bounded, Receiver, RecvTimeoutError, SendError, Sender}; -use etcetera::BaseStrategy; use ignore::overrides::{Override, OverrideBuilder}; use ignore::{WalkBuilder, WalkParallel, WalkState}; use regex::bytes::Regex; @@ -369,17 +368,24 @@ impl WorkerState { } if config.read_global_ignore { - if let Ok(basedirs) = etcetera::choose_base_strategy() { - let global_ignore_file = basedirs.config_dir().join("fd").join("ignore"); - if global_ignore_file.is_file() { - let result = builder.add_ignore(global_ignore_file); - match result { - Some(ignore::Error::Partial(_)) => (), - Some(err) => { - print_error(format!("Malformed pattern in global ignore file. {err}.")); - } - None => (), + let global_ignore_opt = if cfg!(target_os = "macos") { + std::env::var_os("XDG_CONFIG_HOME") + .map(PathBuf::from) + .filter(|p| p.is_absolute()) + .or_else(|| dirs::home_dir().map(|d| d.join(".config"))) + } else { + dirs::config_dir() + } + .map(|p| p.join("fd").join("ignore")) + .filter(|p| p.is_file()); + + if let Some(global_ignore_file) = global_ignore_opt { + match builder.add_ignore(global_ignore_file) { + Some(ignore::Error::Partial(_)) => (), + Some(err) => { + print_error(format!("Malformed pattern in global ignore file. {err}.")); } + None => (), } } } diff --git a/tests/testenv/mod.rs b/tests/testenv/mod.rs index 04c25b5ca..94b5656ea 100644 --- a/tests/testenv/mod.rs +++ b/tests/testenv/mod.rs @@ -225,6 +225,7 @@ impl TestEnv { /// Assert that calling *fd* in the specified path under the root working directory, /// and with the specified arguments produces the expected output. + #[track_caller] pub fn assert_success_and_get_output>( &self, path: P, @@ -241,6 +242,7 @@ impl TestEnv { output } + #[track_caller] pub fn assert_success_and_get_normalized_output>( &self, path: P, @@ -255,12 +257,14 @@ impl TestEnv { } /// Assert that calling *fd* with the specified arguments produces the expected output. + #[track_caller] pub fn assert_output(&self, args: &[&str], expected: &str) { self.assert_output_subdirectory(".", args, expected) } /// Similar to assert_output, but able to handle non-utf8 output #[cfg(all(unix, not(target_os = "macos")))] + #[track_caller] pub fn assert_output_raw(&self, args: &[&str], expected: &[u8]) { let output = self.assert_success_and_get_output(".", args); @@ -269,6 +273,7 @@ impl TestEnv { /// Assert that calling *fd* in the specified path under the root working directory, /// and with the specified arguments produces the expected output. + #[track_caller] pub fn assert_output_subdirectory>( &self, path: P, @@ -287,6 +292,7 @@ impl TestEnv { /// Assert that calling *fd* with the specified arguments produces the expected error, /// and does not succeed. + #[track_caller] pub fn assert_failure_with_error(&self, args: &[&str], expected: &str) { let status = self.assert_error_subdirectory(".", args, Some(expected)); if status.success() { @@ -295,6 +301,7 @@ impl TestEnv { } /// Assert that calling *fd* with the specified arguments does not succeed. + #[track_caller] pub fn assert_failure(&self, args: &[&str]) { let status = self.assert_error_subdirectory(".", args, None); if status.success() { @@ -303,6 +310,7 @@ impl TestEnv { } /// Assert that calling *fd* with the specified arguments produces the expected error. + #[track_caller] pub fn assert_error(&self, args: &[&str], expected: &str) -> process::ExitStatus { self.assert_error_subdirectory(".", args, Some(expected)) } @@ -327,6 +335,7 @@ impl TestEnv { /// Assert that calling *fd* in the specified path under the root working directory, /// and with the specified arguments produces an error with the expected message. + #[track_caller] fn assert_error_subdirectory>( &self, path: P, diff --git a/tests/tests.rs b/tests/tests.rs index 76da9fee3..f32e8d8fa 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,3 +1,6 @@ +#![allow(clippy::uninlined_format_args)] +#![allow(clippy::items_after_test_module)] + mod testenv; #[cfg(unix)] @@ -1418,6 +1421,12 @@ fn test_extension() { let te4 = TestEnv::new(&[], &[".hidden", "test.hidden"]); te4.assert_output(&["--hidden", "--extension", ".hidden"], "test.hidden"); + + let te5 = TestEnv::new(&[], &["with_ext.txt", "no_ext", "trailing_dot."]); + + te5.assert_output(&["--type", "f", "--extension", ""], "no_ext"); + + te5.assert_output(&["--extension", "."], "trailing_dot."); } /// No file extension (test for the pattern provided in the --help text)