From 8226398cbccbb2d8240db53de9f92eb41b77a6b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:44:49 +0000 Subject: [PATCH 01/13] Initial plan From 70d604c00ad10c12ccf035f73a327586809efab8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:50:20 +0000 Subject: [PATCH 02/13] Add unsorted option to ls() to improve performance Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- Sources/Path+ls.swift | 43 +++++++++++++++++++--- Tests/PathTests/PathTests+ls().swift | 53 +++++++++++++++++++++++++++ Tests/PathTests/XCTestManifests.swift | 2 + 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index 30462ae..8a24f2a 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -165,23 +165,47 @@ public extension Pathish { //MARK: Directory Listing /** - Same as the `ls` command ∴ output is ”shallow” and unsorted. + Same as the `ls` command ∴ output is "shallow". + - Note: as per `ls`, by default we do *not* return hidden files. Specify `.a` for hidden files. - Parameter options: Configure the listing. - Important: On Linux the listing is always `ls -a` - - WARNING: we actually sort the output :( sorry. Will fix in a major version bump. + - WARNING: ⚠️ **PERFORMANCE**: By default, output is sorted using locale-specific sorting which can be **VERY EXPENSIVE** + for large directories (0.5+ seconds). For better performance, use `.unsorted` or `.a_unsorted` options. + - Note: Sorting will be removed by default in the next major version bump. */ func ls(_ options: ListDirectoryOptions? = nil) -> [Path] { guard let urls = try? FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil) else { fputs("warning: could not list: \(self)\n", stderr) return [] } - return urls.compactMap { url in + + let shouldSort: Bool + let includeHidden: Bool + + switch options { + case .a: + shouldSort = true + includeHidden = true + case .a_unsorted: + shouldSort = false + includeHidden = true + case .unsorted: + shouldSort = false + includeHidden = false + case .none: + shouldSort = true + includeHidden = false + } + + let paths = urls.compactMap { url -> Path? in guard let path = Path(url.path) else { return nil } - if options != .a, path.basename().hasPrefix(".") { return nil } - // ^^ we don’t use the Foundation `skipHiddenFiles` because it considers weird things hidden and we are mirroring `ls` + if !includeHidden, path.basename().hasPrefix(".") { return nil } + // ^^ we don't use the Foundation `skipHiddenFiles` because it considers weird things hidden and we are mirroring `ls` return path - }.sorted() + } + + return shouldSort ? paths.sorted() : paths } /// Recursively find files under this path. If the path is a file, no files will be found. @@ -217,4 +241,11 @@ public extension Array where Element == Path { public enum ListDirectoryOptions { /// Lists hidden files also case a + /// Lists hidden files also without sorting + case a_unsorted + /// Disables sorting for better performance + /// - WARNING: Sorting is locale-specific and can be expensive for large directories. + /// Use this option when you don't need sorted output and performance is critical. + /// - Note: In the next major version, sorting will be removed by default. + case unsorted } diff --git a/Tests/PathTests/PathTests+ls().swift b/Tests/PathTests/PathTests+ls().swift index 58072d3..b33b6e3 100644 --- a/Tests/PathTests/PathTests+ls().swift +++ b/Tests/PathTests/PathTests+ls().swift @@ -248,4 +248,57 @@ extension PathTests { XCTAssertNil(tmpdir.a.find().next()) } } + + func testLsUnsortedOption() throws { + try Path.mktemp { tmpdir in + // Create files with names that would be sorted differently + try tmpdir.join("zebra.txt").touch() + try tmpdir.join("apple.txt").touch() + try tmpdir.join("banana.txt").touch() + + // Test default (sorted) behavior + let sortedResults = tmpdir.ls() + XCTAssertEqual(sortedResults.count, 3) + XCTAssertEqual(sortedResults[0].basename(), "apple.txt") + XCTAssertEqual(sortedResults[1].basename(), "banana.txt") + XCTAssertEqual(sortedResults[2].basename(), "zebra.txt") + + // Test unsorted behavior - just verify we get all files, order doesn't matter + let unsortedResults = tmpdir.ls(.unsorted) + XCTAssertEqual(unsortedResults.count, 3) + XCTAssertTrue(unsortedResults.contains(tmpdir.join("apple.txt"))) + XCTAssertTrue(unsortedResults.contains(tmpdir.join("banana.txt"))) + XCTAssertTrue(unsortedResults.contains(tmpdir.join("zebra.txt"))) + } + } + + func testLsUnsortedWithHidden() throws { + try Path.mktemp { tmpdir in + // Create regular and hidden files + try tmpdir.join("visible.txt").touch() + try tmpdir.join(".hidden.txt").touch() + try tmpdir.join("another.txt").touch() + + // Test .a (sorted with hidden) + let sortedWithHidden = tmpdir.ls(.a) + XCTAssertEqual(sortedWithHidden.count, 3) + XCTAssertEqual(sortedWithHidden[0].basename(), ".hidden.txt") + XCTAssertEqual(sortedWithHidden[1].basename(), "another.txt") + XCTAssertEqual(sortedWithHidden[2].basename(), "visible.txt") + + // Test .a_unsorted (unsorted with hidden) + let unsortedWithHidden = tmpdir.ls(.a_unsorted) + XCTAssertEqual(unsortedWithHidden.count, 3) + XCTAssertTrue(unsortedWithHidden.contains(tmpdir.join("visible.txt"))) + XCTAssertTrue(unsortedWithHidden.contains(tmpdir.join(".hidden.txt"))) + XCTAssertTrue(unsortedWithHidden.contains(tmpdir.join("another.txt"))) + + // Test .unsorted (unsorted without hidden) + let unsortedNoHidden = tmpdir.ls(.unsorted) + XCTAssertEqual(unsortedNoHidden.count, 2) + XCTAssertTrue(unsortedNoHidden.contains(tmpdir.join("visible.txt"))) + XCTAssertTrue(unsortedNoHidden.contains(tmpdir.join("another.txt"))) + XCTAssertFalse(unsortedNoHidden.contains(tmpdir.join(".hidden.txt"))) + } + } } diff --git a/Tests/PathTests/XCTestManifests.swift b/Tests/PathTests/XCTestManifests.swift index 74d1eb5..cce6468 100644 --- a/Tests/PathTests/XCTestManifests.swift +++ b/Tests/PathTests/XCTestManifests.swift @@ -42,6 +42,8 @@ extension PathTests { ("testKind", testKind), ("testLock", testLock), ("testLsOnNonexistentDirectoryReturnsEmptyArray", testLsOnNonexistentDirectoryReturnsEmptyArray), + ("testLsUnsortedOption", testLsUnsortedOption), + ("testLsUnsortedWithHidden", testLsUnsortedWithHidden), ("testMkpathIfExists", testMkpathIfExists), ("testMktemp", testMktemp), ("testMoveInto", testMoveInto), From cfdb728b4eee11805ec76091259be5038bd8df04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:51:26 +0000 Subject: [PATCH 03/13] Fix naming convention: a_unsorted -> aUnsorted Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- Sources/Path+ls.swift | 6 +++--- Tests/PathTests/PathTests+ls().swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index 8a24f2a..8059407 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -171,7 +171,7 @@ public extension Pathish { - Parameter options: Configure the listing. - Important: On Linux the listing is always `ls -a` - WARNING: ⚠️ **PERFORMANCE**: By default, output is sorted using locale-specific sorting which can be **VERY EXPENSIVE** - for large directories (0.5+ seconds). For better performance, use `.unsorted` or `.a_unsorted` options. + for large directories (0.5+ seconds). For better performance, use `.unsorted` or `.aUnsorted` options. - Note: Sorting will be removed by default in the next major version bump. */ func ls(_ options: ListDirectoryOptions? = nil) -> [Path] { @@ -187,7 +187,7 @@ public extension Pathish { case .a: shouldSort = true includeHidden = true - case .a_unsorted: + case .aUnsorted: shouldSort = false includeHidden = true case .unsorted: @@ -242,7 +242,7 @@ public enum ListDirectoryOptions { /// Lists hidden files also case a /// Lists hidden files also without sorting - case a_unsorted + case aUnsorted /// Disables sorting for better performance /// - WARNING: Sorting is locale-specific and can be expensive for large directories. /// Use this option when you don't need sorted output and performance is critical. diff --git a/Tests/PathTests/PathTests+ls().swift b/Tests/PathTests/PathTests+ls().swift index b33b6e3..6d5ac3f 100644 --- a/Tests/PathTests/PathTests+ls().swift +++ b/Tests/PathTests/PathTests+ls().swift @@ -286,8 +286,8 @@ extension PathTests { XCTAssertEqual(sortedWithHidden[1].basename(), "another.txt") XCTAssertEqual(sortedWithHidden[2].basename(), "visible.txt") - // Test .a_unsorted (unsorted with hidden) - let unsortedWithHidden = tmpdir.ls(.a_unsorted) + // Test .aUnsorted (unsorted with hidden) + let unsortedWithHidden = tmpdir.ls(.aUnsorted) XCTAssertEqual(unsortedWithHidden.count, 3) XCTAssertTrue(unsortedWithHidden.contains(tmpdir.join("visible.txt"))) XCTAssertTrue(unsortedWithHidden.contains(tmpdir.join(".hidden.txt"))) From 0e66a27a69be052e2c1ab884e4c25e5a1c04d7cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:52:06 +0000 Subject: [PATCH 04/13] Improve documentation placement for enum warnings Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- Sources/Path+ls.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index 8059407..fcd868f 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -238,14 +238,15 @@ public extension Array where Element == Path { } /// Options for `Path.ls(_:)` +/// +/// - WARNING: Sorting is locale-specific and can be expensive for large directories (0.5+ seconds). +/// Use `.unsorted` or `.aUnsorted` when you don't need sorted output and performance is critical. +/// - Note: In the next major version, sorting will be removed by default. public enum ListDirectoryOptions { - /// Lists hidden files also + /// Lists hidden files also (sorted) case a - /// Lists hidden files also without sorting + /// Lists hidden files also (unsorted for better performance) case aUnsorted /// Disables sorting for better performance - /// - WARNING: Sorting is locale-specific and can be expensive for large directories. - /// Use this option when you don't need sorted output and performance is critical. - /// - Note: In the next major version, sorting will be removed by default. case unsorted } From c1ccda4f7a24c835aaee607defe2b9296753aa6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 18:19:48 +0000 Subject: [PATCH 05/13] Remove restrictive paths filters to enable tests in CI Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/checks.yml | 3 --- .github/workflows/ci.yml | 3 --- 2 files changed, 6 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index da4236d..741b4f8 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -2,9 +2,6 @@ on: push: branches: - master - paths: - - '**/*.swift' - - .github/workflows/checks.yml jobs: smoke: runs-on: ubuntu-latest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce494ba..2d52aba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,9 +1,6 @@ name: CI on: pull_request: - paths: - - '**/*.swift' - - .github/workflows/ci.yml schedule: - cron: '3 3 * * 5' # 3:03 AM, every Friday From 58b7dc9b79746df53613fe07092b14a2739b73c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:44:49 +0000 Subject: [PATCH 06/13] Initial plan From 987cfb4416ecbd410ed01f5a4626feeec9cf56c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 11:53:26 +0000 Subject: [PATCH 07/13] Fix CI: Replace mxcl/get-swift-version with inline script to avoid glibc issues Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d52aba..b526009 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,15 +52,20 @@ jobs: container: image: ${{ matrix.swift }} steps: - - uses: mxcl/get-swift-version@v1 - id: swift - - uses: actions/checkout@v2 - run: useradd -ms /bin/bash mxcl - run: chown -R mxcl . # ^^ we need to be a normal user and not root for the tests to be valid + - name: Get Swift Version + id: swift + run: | + version=$(swift --version | head -n1 | sed 's/.*Swift version \([0-9.]*\).*/\1/') + marketing_version=$(echo $version | cut -d. -f1) + echo "marketing-version=$marketing_version" >> $GITHUB_OUTPUT + echo "Swift version: $version (marketing: $marketing_version)" + - run: echo ARGS=--enable-code-coverage >> $GITHUB_ENV if: ${{ steps.swift.outputs.marketing-version > 5 }} From 369e2a7e8e7eb2c8c9aff37ea1e153ddb2b47b73 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:54:14 +0000 Subject: [PATCH 08/13] Update CI matrix: use current macOS runners and extend Linux Swift versions Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b526009..9b759d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ concurrency: jobs: verify-linuxmain: - runs-on: macos-10.15 + runs-on: macos-13 steps: - uses: actions/checkout@v2 - run: swift test --generate-linuxmain @@ -21,8 +21,9 @@ jobs: strategy: matrix: os: - - macos-10.15 - - macos-11 + - macos-13 + - macos-14 + - macos-15 platform: - iOS - tvOS @@ -48,7 +49,12 @@ jobs: - swift:5.2 - swift:5.3 - swift:5.4 - - swiftlang/swift:nightly-5.5 + - swift:5.5 + - swift:5.6 + - swift:5.7 + - swift:5.8 + - swift:5.9 + - swift:5.10 container: image: ${{ matrix.swift }} steps: From d1563301f466c8d944e1871626e4cec427670641 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:18:19 +0000 Subject: [PATCH 09/13] Fix CI: update to actions/checkout@v4, remove macos-15, separate legacy Swift versions Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b759d6..eb5f0d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: verify-linuxmain: runs-on: macos-13 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: swift test --generate-linuxmain - run: git diff --exit-code @@ -23,14 +23,13 @@ jobs: os: - macos-13 - macos-14 - - macos-15 platform: - iOS - tvOS - macOS - watchOS steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: mxcl/xcodebuild@v1 with: platform: ${{ matrix.platform }} @@ -43,10 +42,6 @@ jobs: strategy: matrix: swift: - - swift:4.2 - - swift:5.0 - - swift:5.1 - - swift:5.2 - swift:5.3 - swift:5.4 - swift:5.5 @@ -58,7 +53,7 @@ jobs: container: image: ${{ matrix.swift }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: useradd -ms /bin/bash mxcl - run: chown -R mxcl . @@ -93,3 +88,25 @@ jobs: if: ${{ steps.swift.outputs.marketing-version > 5 }} with: file: ./info.lcov + + linux-legacy: + runs-on: ubuntu-latest + strategy: + matrix: + swift: + - swift:4.2 + - swift:5.0 + - swift:5.1 + - swift:5.2 + container: + image: ${{ matrix.swift }} + steps: + - uses: actions/checkout@v3 + # Using v3 instead of v4 because v4 requires node20 which needs glibc 2.28+ + # These old Swift containers (Ubuntu 18.04) only have glibc 2.27 + + - run: useradd -ms /bin/bash mxcl + - run: chown -R mxcl . + # ^^ we need to be a normal user and not root for the tests to be valid + + - run: su mxcl -c "swift test --parallel" From be3f1c5b5ca40e52242773d846734d23cd51edd4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 18:50:30 +0000 Subject: [PATCH 10/13] Fix CI: manual git checkout for legacy Swift, move 5.3 to legacy, remove macOS 14 Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb5f0d6..387b098 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,12 +17,9 @@ jobs: - run: git diff --exit-code apple: - runs-on: ${{ matrix.os }} + runs-on: macos-13 strategy: matrix: - os: - - macos-13 - - macos-14 platform: - iOS - tvOS @@ -42,7 +39,6 @@ jobs: strategy: matrix: swift: - - swift:5.3 - swift:5.4 - swift:5.5 - swift:5.6 @@ -98,11 +94,23 @@ jobs: - swift:5.0 - swift:5.1 - swift:5.2 + - swift:5.3 container: image: ${{ matrix.swift }} steps: - - uses: actions/checkout@v3 - # Using v3 instead of v4 because v4 requires node20 which needs glibc 2.28+ + - name: Checkout code + run: | + apt-get update && apt-get install -y git + git clone --depth 1 --branch ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} https://github.com/$GITHUB_REPOSITORY .git-tmp || \ + git clone --depth 1 https://github.com/$GITHUB_REPOSITORY .git-tmp + cd .git-tmp + git fetch origin $GITHUB_SHA + git checkout $GITHUB_SHA + cd .. + mv .git-tmp/* . + mv .git-tmp/.git . + rm -rf .git-tmp + # Manual checkout because actions/checkout@v3 and v4 both require node20 with glibc 2.28+ # These old Swift containers (Ubuntu 18.04) only have glibc 2.27 - run: useradd -ms /bin/bash mxcl From efa8cbe6aaa750500705c08ede7cb0bfcf6665bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:52:29 +0000 Subject: [PATCH 11/13] Merge latest master (117d402) into PR - use master's CI configuration Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 41 +++++++++++++++++++++++++++++---- Sources/Extensions.swift | 11 +++++++++ Tests/PathTests/PathTests.swift | 7 ++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 387b098..83eb473 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,18 @@ name: CI on: pull_request: +<<<<<<< HEAD schedule: - cron: '3 3 * * 5' # 3:03 AM, every Friday +======= +>>>>>>> origin/master concurrency: group: ${{ github.head_ref || 'push' }} cancel-in-progress: true jobs: +<<<<<<< HEAD verify-linuxmain: runs-on: macos-13 steps: @@ -18,6 +22,12 @@ jobs: apple: runs-on: macos-13 +======= + # we want to test more macOS versions but GitHub make that difficult without + # constant maintenance because runners are deprecated and removed + apple: + runs-on: macos-latest +>>>>>>> origin/master strategy: matrix: platform: @@ -26,16 +36,21 @@ jobs: - macOS - watchOS steps: +<<<<<<< HEAD - uses: actions/checkout@v4 - uses: mxcl/xcodebuild@v1 +======= + - uses: actions/checkout@v6 + - uses: mxcl/xcodebuild@latest +>>>>>>> origin/master with: platform: ${{ matrix.platform }} code-coverage: true - warnings-as-errors: true - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v5 linux: runs-on: ubuntu-latest + continue-on-error: true strategy: matrix: swift: @@ -46,10 +61,26 @@ jobs: - swift:5.8 - swift:5.9 - swift:5.10 +<<<<<<< HEAD container: image: ${{ matrix.swift }} steps: - uses: actions/checkout@v4 +======= + # - swift:6.0 strangely fails + - swift:6.1 + - swift:6.2 + container: + image: ${{ matrix.swift }} + steps: + - uses: actions/checkout@v1 + + - name: Get Swift version + id: swift + run: | + ver=$(swift --version | head -1 | sed 's/.*Swift version \([0-9]*\).*/\1/') + echo "marketing-version=$ver" >> $GITHUB_OUTPUT +>>>>>>> origin/master - run: useradd -ms /bin/bash mxcl - run: chown -R mxcl . @@ -64,12 +95,12 @@ jobs: echo "Swift version: $version (marketing: $marketing_version)" - run: echo ARGS=--enable-code-coverage >> $GITHUB_ENV - if: ${{ steps.swift.outputs.marketing-version > 5 }} + if: ${{ steps.swift.outputs.marketing-version > 6.1 }} - run: su mxcl -c "swift test --parallel $ARGS" - name: Generate `.lcov` - if: ${{ steps.swift.outputs.marketing-version > 5 }} + if: ${{ steps.swift.outputs.marketing-version > 6.1 }} run: | apt-get -qq update && apt-get -qq install curl b=$(swift build --show-bin-path) @@ -81,7 +112,7 @@ jobs: > info.lcov - uses: codecov/codecov-action@v1 - if: ${{ steps.swift.outputs.marketing-version > 5 }} + if: ${{ steps.swift.outputs.marketing-version > 6.1 }} with: file: ./info.lcov diff --git a/Sources/Extensions.swift b/Sources/Extensions.swift index 27f84b8..c0e05f2 100644 --- a/Sources/Extensions.swift +++ b/Sources/Extensions.swift @@ -44,11 +44,22 @@ public extension Bundle { /// Extensions on `String` that work with `Path` rather than `String` or `URL` public extension String { /// Initializes this `String` with the contents of the provided path. + /// - SeeAlso: `init(contentsOf:encoding:)` + @available(macOS, deprecated: 15, message: "Use `init(contentsOf:encoding:)` instead") + @available(iOS, deprecated: 18, message: "Use `init(contentsOf:encoding:)` instead") + @available(tvOS, deprecated: 18, message: "Use `init(contentsOf:encoding:)` instead") + @available(watchOS, deprecated: 11, message: "Use `init(contentsOf:encoding:)` instead") @inlinable init(contentsOf path: P) throws { try self.init(contentsOfFile: path.string) } + /// Initializes this `String` with the contents of the provided path interpreted using a given encoding. + @inlinable + init(contentsOf path: P, encoding: String.Encoding) throws { + try self.init(contentsOfFile: path.string, encoding: encoding) + } + /// - Returns: `to` to allow chaining @inlinable @discardableResult diff --git a/Tests/PathTests/PathTests.swift b/Tests/PathTests/PathTests.swift index 65a5ada..5e0f7ab 100644 --- a/Tests/PathTests/PathTests.swift +++ b/Tests/PathTests/PathTests.swift @@ -496,6 +496,13 @@ class PathTests: XCTestCase { } } + func testStringEncodingExtensions() throws { + let string = try String(contentsOf: Path(#file)!, encoding: .utf8) + try Path.mktemp { tmpdir in + _ = try string.write(to: tmpdir.foo, encoding: .utf8) + } + } + func testFileHandleExtensions() throws { _ = try FileHandle(forReadingAt: Path(#file)!) _ = try FileHandle(forWritingAt: Path(#file)!) From 8c2d3e09e7ff54d636408f0d7d11ff6c4ddd724e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 17:54:17 +0000 Subject: [PATCH 12/13] Fix merge conflict - use master's CI configuration completely Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- .github/workflows/ci.yml | 76 +++------------------------------------- 1 file changed, 5 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83eb473..87b0086 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,33 +1,16 @@ name: CI on: pull_request: -<<<<<<< HEAD - schedule: - - cron: '3 3 * * 5' # 3:03 AM, every Friday -======= ->>>>>>> origin/master concurrency: group: ${{ github.head_ref || 'push' }} cancel-in-progress: true jobs: -<<<<<<< HEAD - verify-linuxmain: - runs-on: macos-13 - steps: - - uses: actions/checkout@v4 - - run: swift test --generate-linuxmain - - run: git diff --exit-code - - apple: - runs-on: macos-13 -======= # we want to test more macOS versions but GitHub make that difficult without # constant maintenance because runners are deprecated and removed apple: runs-on: macos-latest ->>>>>>> origin/master strategy: matrix: platform: @@ -36,13 +19,8 @@ jobs: - macOS - watchOS steps: -<<<<<<< HEAD - - uses: actions/checkout@v4 - - uses: mxcl/xcodebuild@v1 -======= - uses: actions/checkout@v6 - uses: mxcl/xcodebuild@latest ->>>>>>> origin/master with: platform: ${{ matrix.platform }} code-coverage: true @@ -54,6 +32,11 @@ jobs: strategy: matrix: swift: + - swift:4.2 + - swift:5.0 + - swift:5.1 + - swift:5.2 + - swift:5.3 - swift:5.4 - swift:5.5 - swift:5.6 @@ -61,12 +44,6 @@ jobs: - swift:5.8 - swift:5.9 - swift:5.10 -<<<<<<< HEAD - container: - image: ${{ matrix.swift }} - steps: - - uses: actions/checkout@v4 -======= # - swift:6.0 strangely fails - swift:6.1 - swift:6.2 @@ -80,20 +57,11 @@ jobs: run: | ver=$(swift --version | head -1 | sed 's/.*Swift version \([0-9]*\).*/\1/') echo "marketing-version=$ver" >> $GITHUB_OUTPUT ->>>>>>> origin/master - run: useradd -ms /bin/bash mxcl - run: chown -R mxcl . # ^^ we need to be a normal user and not root for the tests to be valid - - name: Get Swift Version - id: swift - run: | - version=$(swift --version | head -n1 | sed 's/.*Swift version \([0-9.]*\).*/\1/') - marketing_version=$(echo $version | cut -d. -f1) - echo "marketing-version=$marketing_version" >> $GITHUB_OUTPUT - echo "Swift version: $version (marketing: $marketing_version)" - - run: echo ARGS=--enable-code-coverage >> $GITHUB_ENV if: ${{ steps.swift.outputs.marketing-version > 6.1 }} @@ -115,37 +83,3 @@ jobs: if: ${{ steps.swift.outputs.marketing-version > 6.1 }} with: file: ./info.lcov - - linux-legacy: - runs-on: ubuntu-latest - strategy: - matrix: - swift: - - swift:4.2 - - swift:5.0 - - swift:5.1 - - swift:5.2 - - swift:5.3 - container: - image: ${{ matrix.swift }} - steps: - - name: Checkout code - run: | - apt-get update && apt-get install -y git - git clone --depth 1 --branch ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} https://github.com/$GITHUB_REPOSITORY .git-tmp || \ - git clone --depth 1 https://github.com/$GITHUB_REPOSITORY .git-tmp - cd .git-tmp - git fetch origin $GITHUB_SHA - git checkout $GITHUB_SHA - cd .. - mv .git-tmp/* . - mv .git-tmp/.git . - rm -rf .git-tmp - # Manual checkout because actions/checkout@v3 and v4 both require node20 with glibc 2.28+ - # These old Swift containers (Ubuntu 18.04) only have glibc 2.27 - - - run: useradd -ms /bin/bash mxcl - - run: chown -R mxcl . - # ^^ we need to be a normal user and not root for the tests to be valid - - - run: su mxcl -c "swift test --parallel" From e40e4ec0224a349061bd74e14226cf79dffd2a44 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 18:03:05 +0000 Subject: [PATCH 13/13] Fix Swift 4.2/5.0 compilation: use .some() for optional enum cases Co-authored-by: mxcl <58962+mxcl@users.noreply.github.com> --- Sources/Path+ls.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Path+ls.swift b/Sources/Path+ls.swift index fcd868f..66008b9 100644 --- a/Sources/Path+ls.swift +++ b/Sources/Path+ls.swift @@ -184,13 +184,13 @@ public extension Pathish { let includeHidden: Bool switch options { - case .a: + case .some(.a): shouldSort = true includeHidden = true - case .aUnsorted: + case .some(.aUnsorted): shouldSort = false includeHidden = true - case .unsorted: + case .some(.unsorted): shouldSort = false includeHidden = false case .none: