Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e355c28e9 | ||
|
|
46b0cd883b | ||
|
|
9c6f807b0a | ||
|
|
dad3d84040 | ||
|
|
5377bceb5f | ||
|
|
f593437cf5 | ||
|
|
6e8a42f01d | ||
|
|
13d62c3068 | ||
|
|
99a0474b0f | ||
|
|
82640e629d | ||
|
|
f49e5c82c7 | ||
|
|
287afe3783 |
62
.github/workflows/ci.yml
vendored
62
.github/workflows/ci.yml
vendored
@@ -6,26 +6,31 @@ on:
|
||||
- .github/workflows/ci.yml
|
||||
schedule:
|
||||
- cron: '3 3 * * 5' # 3:03 AM, every Friday
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.head_ref || 'push' }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
smoke:
|
||||
runs-on: macos-latest
|
||||
verify-linuxmain:
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: swift test --generate-linuxmain
|
||||
- run: git diff --exit-code
|
||||
|
||||
apple:
|
||||
runs-on: macos-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- macos-10.15
|
||||
- macos-11
|
||||
platform:
|
||||
- iOS
|
||||
- tvOS
|
||||
- macOS
|
||||
- watchOS
|
||||
- iOS
|
||||
- tvOS
|
||||
- macOS
|
||||
- watchOS
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: mxcl/xcodebuild@v1
|
||||
@@ -35,38 +40,37 @@ jobs:
|
||||
warnings-as-errors: true
|
||||
- uses: codecov/codecov-action@v1
|
||||
|
||||
linux-swift-4:
|
||||
name: linux (${{ matrix.swift }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
swift: ['4.2', '5.0']
|
||||
container:
|
||||
image: swift:${{ matrix.swift }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: useradd -ms /bin/bash mxcl
|
||||
- run: chown -R mxcl .
|
||||
- run: su mxcl -c 'swift test --parallel'
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
swift:
|
||||
- '5.1'
|
||||
- '5.2'
|
||||
- '5.3'
|
||||
- '5.4'
|
||||
- swift:4.2
|
||||
- swift:5.0
|
||||
- swift:5.1
|
||||
- swift:5.2
|
||||
- swift:5.3
|
||||
- swift:5.4
|
||||
- swiftlang/swift:nightly-5.5
|
||||
container:
|
||||
image: swift:${{ matrix.swift }}
|
||||
image: ${{ matrix.swift }}
|
||||
steps:
|
||||
- uses: mxcl/get-swift-version@v1
|
||||
id: swift
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- run: useradd -ms /bin/bash mxcl
|
||||
# ^^ we need to be a normal user and not root for the tests to be valid
|
||||
- run: chown -R mxcl .
|
||||
- run: su mxcl -c 'swift test --parallel --enable-code-coverage'
|
||||
# ^^ we need to be a normal user and not root for the tests to be valid
|
||||
|
||||
- run: echo ARGS=--enable-code-coverage >> $GITHUB_ENV
|
||||
if: ${{ steps.swift.outputs.marketing-version > 5 }}
|
||||
|
||||
- run: su mxcl -c "swift test --parallel $ARGS"
|
||||
|
||||
- name: Generate `.lcov`
|
||||
if: ${{ steps.swift.outputs.marketing-version > 5 }}
|
||||
run: |
|
||||
apt-get -qq update && apt-get -qq install curl
|
||||
b=$(swift build --show-bin-path)
|
||||
@@ -76,6 +80,8 @@ jobs:
|
||||
--ignore-filename-regex='\.build|Tests' \
|
||||
"$b"/*.xctest \
|
||||
> info.lcov
|
||||
|
||||
- uses: codecov/codecov-action@v1
|
||||
if: ${{ steps.swift.outputs.marketing-version > 5 }}
|
||||
with:
|
||||
file: ./info.lcov
|
||||
|
||||
10
README.md
10
README.md
@@ -227,7 +227,7 @@ We provide `find()` for recursive listing:
|
||||
|
||||
```swift
|
||||
for path in Path.home.find() {
|
||||
// descends all directories, and includes hidden files
|
||||
// descends all directories, and includes hidden files by default
|
||||
// so it behaves the same as the terminal command `find`
|
||||
}
|
||||
```
|
||||
@@ -235,7 +235,7 @@ for path in Path.home.find() {
|
||||
It is configurable:
|
||||
|
||||
```swift
|
||||
for path in Path.home.find().depth(max: 1).extension("swift").type(.file) {
|
||||
for path in Path.home.find().depth(max: 1).extension("swift").type(.file).hidden(false) {
|
||||
//…
|
||||
}
|
||||
```
|
||||
@@ -426,6 +426,10 @@ Carthage:
|
||||
|
||||
> Waiting on: [@Carthage#1945](https://github.com/Carthage/Carthage/pull/1945).
|
||||
|
||||
# Naming Conflicts with `SwiftUI.Path`, etc.
|
||||
|
||||
We have a typealias of `PathStruct` you can use instead.
|
||||
|
||||
# Alternatives
|
||||
|
||||
* [Pathos](https://github.com/dduan/Pathos) by Daniel Duan
|
||||
@@ -444,4 +448,4 @@ Carthage:
|
||||
[codecov]: https://codecov.io/gh/mxcl/Path.swift
|
||||
[badge-version]: https://img.shields.io/cocoapods/v/Path.swift.svg?label=version
|
||||
[cocoapods]: https://cocoapods.org/pods/Path.swift
|
||||
[Sponsor @mxcl]: https://github.com/sponsors/mxcl
|
||||
[Sponsor @mxcl]: https://github.com/sponsors/mxcl
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import Foundation
|
||||
|
||||
/// The `extension` that provides static properties that are common directories.
|
||||
extension Path {
|
||||
private enum Foo {
|
||||
//MARK: Common Directories
|
||||
|
||||
/// Returns a `Path` containing `FileManager.default.currentDirectoryPath`.
|
||||
public static var cwd: DynamicPath {
|
||||
static var cwd: DynamicPath {
|
||||
return .init(string: FileManager.default.currentDirectoryPath)
|
||||
}
|
||||
|
||||
/// Returns a `Path` representing the root path.
|
||||
public static var root: DynamicPath {
|
||||
static var root: DynamicPath {
|
||||
return .init(string: "/")
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ extension Path {
|
||||
#endif
|
||||
|
||||
/// Returns a `Path` representing the user’s home directory
|
||||
public static var home: DynamicPath {
|
||||
static var home: DynamicPath {
|
||||
let string: String
|
||||
#if os(macOS)
|
||||
if #available(OSX 10.12, *) {
|
||||
@@ -70,7 +70,7 @@ extension Path {
|
||||
- Note: There is no standard location for documents on Linux, thus we return `~/Documents`.
|
||||
- Note: You should create a subdirectory before creating any files.
|
||||
*/
|
||||
public static var documents: DynamicPath {
|
||||
static var documents: DynamicPath {
|
||||
return path(for: .documentDirectory)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ extension Path {
|
||||
- Note: On Linux this is `XDG_CACHE_HOME`.
|
||||
- Note: You should create a subdirectory before creating any files.
|
||||
*/
|
||||
public static var caches: DynamicPath {
|
||||
static var caches: DynamicPath {
|
||||
return path(for: .cachesDirectory)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ extension Path {
|
||||
- Note: On Linux is `XDG_DATA_HOME`.
|
||||
- Note: You should create a subdirectory before creating any files.
|
||||
*/
|
||||
public static var applicationSupport: DynamicPath {
|
||||
static var applicationSupport: DynamicPath {
|
||||
return path(for: .applicationSupportDirectory)
|
||||
}
|
||||
}
|
||||
@@ -108,13 +108,35 @@ func defaultUrl(for searchPath: FileManager.SearchPathDirectory) -> DynamicPath
|
||||
}
|
||||
#endif
|
||||
|
||||
/// The `extension` that provides static properties that are common directories.
|
||||
#if swift(>=5.5)
|
||||
extension Pathish where Self == Path {
|
||||
static var home: DynamicPath { Path.home }
|
||||
static var root: DynamicPath { Path.root }
|
||||
static var cwd: DynamicPath { Path.cwd }
|
||||
static var documents: DynamicPath { Path.documents }
|
||||
static var caches: DynamicPath { Path.caches }
|
||||
static var applicationSupport: DynamicPath { Path.applicationSupport }
|
||||
public extension Pathish where Self == Path {
|
||||
static var home: DynamicPath { return Foo.home }
|
||||
static var root: DynamicPath { return Foo.root }
|
||||
static var cwd: DynamicPath { return Foo.cwd }
|
||||
static var documents: DynamicPath { return Foo.documents }
|
||||
static var caches: DynamicPath { return Foo.caches }
|
||||
static var applicationSupport: DynamicPath { return Foo.applicationSupport }
|
||||
static func source(for filePath: String = #filePath) -> (file: DynamicPath, directory: DynamicPath) {
|
||||
return Foo.source(for: filePath)
|
||||
}
|
||||
}
|
||||
#else
|
||||
public extension Path {
|
||||
static var home: DynamicPath { return Foo.home }
|
||||
static var root: DynamicPath { return Foo.root }
|
||||
static var cwd: DynamicPath { return Foo.cwd }
|
||||
static var documents: DynamicPath { return Foo.documents }
|
||||
static var caches: DynamicPath { return Foo.caches }
|
||||
static var applicationSupport: DynamicPath { return Foo.applicationSupport }
|
||||
#if swift(>=5.3)
|
||||
static func source(for filePath: String = #filePath) -> (file: DynamicPath, directory: DynamicPath) {
|
||||
return Foo.source(for: filePath)
|
||||
}
|
||||
#else
|
||||
static func source(for file: String = #file) -> (file: DynamicPath, directory: DynamicPath) {
|
||||
return Foo.source(for: file)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,9 @@ public extension Path {
|
||||
|
||||
/// The file extensions find operations will return. Files *and* directories unless you filter for `kinds`.
|
||||
private(set) public var extensions: Set<String>?
|
||||
|
||||
/// Whether to return hidden files
|
||||
public var hidden:Bool = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +53,12 @@ extension Path.Finder: Sequence, IteratorProtocol {
|
||||
if enumerator.level < depth.lowerBound {
|
||||
continue
|
||||
}
|
||||
|
||||
if !hidden, path.basename().hasPrefix(".") {
|
||||
enumerator.skipDescendants()
|
||||
continue
|
||||
}
|
||||
#endif
|
||||
|
||||
if let type = path.type, !types.contains(type) { continue }
|
||||
if let exts = extensions, !exts.contains(path.extension) { continue }
|
||||
return path
|
||||
@@ -114,6 +121,15 @@ public extension Path.Finder {
|
||||
extensions!.insert(ext)
|
||||
return self
|
||||
}
|
||||
|
||||
/// Whether to skip hidden files and folders.
|
||||
func hidden(_ hidden: Bool) -> Path.Finder {
|
||||
#if os(Linux) && !swift(>=5.0)
|
||||
fputs("warning: hidden not implemented for Swift < 5\n", stderr)
|
||||
#endif
|
||||
self.hidden = hidden
|
||||
return self
|
||||
}
|
||||
|
||||
/// The return type for `Path.Finder`
|
||||
enum ControlFlow {
|
||||
@@ -198,6 +214,6 @@ public extension Array where Element == Path {
|
||||
|
||||
/// Options for `Path.ls(_:)`
|
||||
public enum ListDirectoryOptions {
|
||||
/// Creates intermediary directories; works the same as `mkdir -p`.
|
||||
/// Lists hidden files also
|
||||
case a
|
||||
}
|
||||
|
||||
@@ -136,6 +136,28 @@ extension PathTests {
|
||||
}
|
||||
}
|
||||
|
||||
func testFindHidden() throws {
|
||||
try Path.mktemp { tmpdir in
|
||||
let dotFoo = try tmpdir.join(".foo.txt").touch()
|
||||
let tmpDotA = try tmpdir.join(".a").mkdir()
|
||||
let tmpDotAFoo = try tmpdir.join(".a").join("foo.txt").touch()
|
||||
let tmpB = try tmpdir.b.mkdir()
|
||||
let tmpBFoo = try tmpdir.b.join("foo.txt").touch()
|
||||
|
||||
XCTAssertEqual(
|
||||
Set(tmpdir.find().hidden(true)),
|
||||
Set([dotFoo,tmpDotA,tmpDotAFoo,tmpB,tmpBFoo]),
|
||||
relativeTo: tmpdir)
|
||||
|
||||
#if !os(Linux) || swift(>=5)
|
||||
XCTAssertEqual(
|
||||
Set(tmpdir.find().hidden(false)),
|
||||
Set([tmpB,tmpBFoo]),
|
||||
relativeTo: tmpdir)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
func testFindExtension() throws {
|
||||
try Path.mktemp { tmpdir in
|
||||
try tmpdir.join("foo.json").touch()
|
||||
|
||||
@@ -29,6 +29,7 @@ extension PathTests {
|
||||
("testFindDepthRange", testFindDepthRange),
|
||||
("testFindExecute", testFindExecute),
|
||||
("testFindExtension", testFindExtension),
|
||||
("testFindHidden", testFindHidden),
|
||||
("testFindMaxDepth1", testFindMaxDepth1),
|
||||
("testFindMaxDepth2", testFindMaxDepth2),
|
||||
("testFindMinDepth", testFindMinDepth),
|
||||
|
||||
@@ -19,7 +19,7 @@ private func logic<P: Pathish>(_ set1: Set<Path>, _ set2: Set<Path>, relativeTo:
|
||||
if set1 != set2 {
|
||||
let cvt: (Path) -> String = { $0.relative(to: relativeTo) }
|
||||
let out1 = set1.map(cvt).sorted()
|
||||
let out2 = set1.map(cvt).sorted()
|
||||
let out2 = set2.map(cvt).sorted()
|
||||
fail("Set(\(out1)) is not equal to Set(\(out2))")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user