Compare commits

..

18 Commits
1.2.1 ... 1.4.0

Author SHA1 Message Date
Max Howell
9c6f807b0a Merge pull request #77 from ConfusedVorlon/find_hidden_modifier
Find hidden modifier
2021-07-30 12:28:04 -04:00
Rob Jonson
dad3d84040 don't implement hidden(false) for swift < 5
and provide a warning
2021-07-30 17:09:37 +01:00
Rob Jonson
5377bceb5f Update linux test list 2021-07-28 22:29:02 +01:00
Rob Jonson
f593437cf5 make find() configurable to ignore hidden files & directories 2021-07-28 15:12:09 +01:00
Rob Jonson
6e8a42f01d Fix assert error message 2021-07-28 15:06:20 +01:00
Max Howell
13d62c3068 Merge pull request #75 from mxcl/ci/macos-11
[ci] can has macos-11
2021-06-23 12:48:10 -04:00
Max Howell
99a0474b0f [ci] can has macos-11 2021-06-23 12:32:23 -04:00
Max Howell
82640e629d Merge pull request #74 from mxcl/ci/5.5
ci/5.5
2021-06-17 12:00:29 -04:00
Max Howell
f49e5c82c7 This seems more correct 2021-06-17 11:55:53 -04:00
Max Howell
287afe3783 Fix docs for ls(.a) 2021-06-17 11:55:52 -04:00
Max Howell
bb449ff412 Merge pull request #73 from mxcl/fixes/55
typealias PathStruct and add Swift 5.5 niceness
2021-06-16 11:11:18 -04:00
Max Howell
14f03abaad typealias PathStruct and add Swift 5.5 niceness
Fixes #55
2021-06-16 11:05:17 -04:00
Max Howell
ecbb3a60fe Merge pull request #71 from mxcl/ci/warnings-as-errors
[ci] warnings as errors
2021-06-07 10:45:37 -04:00
Max Howell
3af771f543 [ci] warnings as errors 2021-06-07 10:14:36 -04:00
Max Howell
0b68e5c011 Merge pull request #70 from mxcl/ci/mxcl/xcodebuild
use mxcl/xcodebuild
2021-06-05 13:45:31 -04:00
Max Howell
fec4ed25de use mxcl/xcodebuild 2021-06-05 10:55:16 -04:00
Max Howell
6e78d9317e Merge pull request #69 from mxcl/continuous-resilience
#continuous-resilience
2021-05-29 15:12:58 -04:00
Max Howell
3035c45808 #continuous-resilience 2021-05-29 15:10:17 -04:00
10 changed files with 164 additions and 74 deletions

View File

@@ -1,14 +1,13 @@
name: Checks
on: on:
push: push:
branches: branches:
- master - master
paths: paths:
- Sources/** - '**/*.swift'
- Tests/** - .github/workflows/checks.yml
jobs: jobs:
macOS: smoke:
runs-on: macos-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: swift --version - run: swift --version

View File

@@ -1,83 +1,87 @@
name: CI name: CI
on: pull_request on:
pull_request:
paths:
- '**/*.swift'
- .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: jobs:
smoke: verify-linuxmain:
runs-on: macos-latest runs-on: macos-10.15
steps: steps:
- uses: technote-space/auto-cancel-redundant-job@v1
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: swift test --generate-linuxmain - run: swift test --generate-linuxmain
- run: git diff --exit-code - run: git diff --exit-code
apple: apple:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
destination: os:
- platform=iOS Simulator,OS=latest,name=iPhone 12 - macos-10.15
- platform=tvOS Simulator,OS=latest,name=Apple TV - macos-11
# - platform=watchOS Simulator,OS=latest,name=Apple Watch Series 5 - 40mm platform:
# ^^ coming with Xcode 12.5 which is not yet available on GHA - iOS
- platform=macOS - tvOS
- macOS
- watchOS
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: maxim-lobanov/setup-xcode@v1 - uses: mxcl/xcodebuild@v1
with: with:
xcode-version: 12.4 platform: ${{ matrix.platform }}
- run: swift package generate-xcodeproj --enable-code-coverage code-coverage: true
- uses: sersoft-gmbh/xcodebuild-action@v1 warnings-as-errors: true
with:
project: Path.swift.xcodeproj
scheme: Path.swift-Package
destination: ${{ matrix.destination }}
action: test
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v1
linux-swift-4:
name: linux (4.2)
runs-on: ubuntu-18.04
steps:
- uses: fwal/setup-swift@v1
with:
swift-version: 4.2
- uses: actions/checkout@v2
- run: swift test --parallel
linux: linux:
runs-on: ubuntu-18.04 runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
swift: swift:
- '5.0' - swift:4.2
- '5.1' - swift:5.0
- '5.2' - swift:5.1
- '5.3' - swift:5.2
- swift:5.3
- swift:5.4
- swiftlang/swift:nightly-5.5
container:
image: ${{ matrix.swift }}
steps: steps:
- uses: fwal/setup-swift@v1 - uses: mxcl/get-swift-version@v1
with: id: swift
swift-version: ${{ matrix.swift }}
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: swift test --parallel --enable-code-coverage
- name: Generate Coverage Report - 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: 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: | run: |
sudo apt-get -qq update && sudo apt-get -qq install llvm-10 apt-get -qq update && apt-get -qq install curl
export b=$(swift build --show-bin-path) && llvm-cov-10 \ b=$(swift build --show-bin-path)
export -format lcov \ llvm-cov export \
-instr-profile=$b/codecov/default.profdata \ -format lcov \
--ignore-filename-regex='\.build/' \ -instr-profile="$b"/codecov/default.profdata \
$b/Path.swiftPackageTests.xctest \ --ignore-filename-regex='\.build|Tests' \
"$b"/*.xctest \
> info.lcov > info.lcov
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v1
if: ${{ steps.swift.outputs.marketing-version > 5 }}
with: with:
file: ./info.lcov file: ./info.lcov
# code coverage fails with 5.4 for some reason
linux-swift-5-4:
name: linux (5.4)
runs-on: ubuntu-18.04
steps:
- uses: fwal/setup-swift@v1
with:
swift-version: 5.4
- uses: actions/checkout@v2
- run: swift test --parallel

View File

@@ -227,7 +227,7 @@ We provide `find()` for recursive listing:
```swift ```swift
for path in Path.home.find() { 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` // so it behaves the same as the terminal command `find`
} }
``` ```
@@ -235,7 +235,7 @@ for path in Path.home.find() {
It is configurable: It is configurable:
```swift ```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) {
// //
} }
``` ```

View File

@@ -1,16 +1,16 @@
import Foundation import Foundation
/// The `extension` that provides static properties that are common directories. /// The `extension` that provides static properties that are common directories.
extension Path { private enum Foo {
//MARK: Common Directories //MARK: Common Directories
/// Returns a `Path` containing `FileManager.default.currentDirectoryPath`. /// Returns a `Path` containing `FileManager.default.currentDirectoryPath`.
public static var cwd: DynamicPath { static var cwd: DynamicPath {
return .init(string: FileManager.default.currentDirectoryPath) return .init(string: FileManager.default.currentDirectoryPath)
} }
/// Returns a `Path` representing the root path. /// Returns a `Path` representing the root path.
public static var root: DynamicPath { static var root: DynamicPath {
return .init(string: "/") return .init(string: "/")
} }
@@ -27,7 +27,7 @@ extension Path {
#endif #endif
/// Returns a `Path` representing the users home directory /// Returns a `Path` representing the users home directory
public static var home: DynamicPath { static var home: DynamicPath {
let string: String let string: String
#if os(macOS) #if os(macOS)
if #available(OSX 10.12, *) { 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: There is no standard location for documents on Linux, thus we return `~/Documents`.
- Note: You should create a subdirectory before creating any files. - Note: You should create a subdirectory before creating any files.
*/ */
public static var documents: DynamicPath { static var documents: DynamicPath {
return path(for: .documentDirectory) return path(for: .documentDirectory)
} }
@@ -79,7 +79,7 @@ extension Path {
- Note: On Linux this is `XDG_CACHE_HOME`. - Note: On Linux this is `XDG_CACHE_HOME`.
- Note: You should create a subdirectory before creating any files. - Note: You should create a subdirectory before creating any files.
*/ */
public static var caches: DynamicPath { static var caches: DynamicPath {
return path(for: .cachesDirectory) return path(for: .cachesDirectory)
} }
@@ -88,7 +88,7 @@ extension Path {
- Note: On Linux is `XDG_DATA_HOME`. - Note: On Linux is `XDG_DATA_HOME`.
- Note: You should create a subdirectory before creating any files. - Note: You should create a subdirectory before creating any files.
*/ */
public static var applicationSupport: DynamicPath { static var applicationSupport: DynamicPath {
return path(for: .applicationSupportDirectory) return path(for: .applicationSupportDirectory)
} }
} }
@@ -108,3 +108,35 @@ func defaultUrl(for searchPath: FileManager.SearchPathDirectory) -> DynamicPath
} }
#endif #endif
/// The `extension` that provides static properties that are common directories.
#if swift(>=5.5)
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

View File

@@ -31,6 +31,9 @@ public extension Path {
/// The file extensions find operations will return. Files *and* directories unless you filter for `kinds`. /// The file extensions find operations will return. Files *and* directories unless you filter for `kinds`.
private(set) public var extensions: Set<String>? 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 { if enumerator.level < depth.lowerBound {
continue continue
} }
if !hidden, path.basename().hasPrefix(".") {
enumerator.skipDescendants()
continue
}
#endif #endif
if let type = path.type, !types.contains(type) { continue } if let type = path.type, !types.contains(type) { continue }
if let exts = extensions, !exts.contains(path.extension) { continue } if let exts = extensions, !exts.contains(path.extension) { continue }
return path return path
@@ -114,6 +121,15 @@ public extension Path.Finder {
extensions!.insert(ext) extensions!.insert(ext)
return self 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` /// The return type for `Path.Finder`
enum ControlFlow { enum ControlFlow {
@@ -198,6 +214,6 @@ public extension Array where Element == Path {
/// Options for `Path.ls(_:)` /// Options for `Path.ls(_:)`
public enum ListDirectoryOptions { public enum ListDirectoryOptions {
/// Creates intermediary directories; works the same as `mkdir -p`. /// Lists hidden files also
case a case a
} }

View File

@@ -7,6 +7,8 @@ import func Glibc.realpath
let _realpath = Glibc.realpath let _realpath = Glibc.realpath
#endif #endif
public typealias PathStruct = Path
/** /**
A `Path` represents an absolute path on a filesystem. A `Path` represents an absolute path on a filesystem.

View File

@@ -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 { func testFindExtension() throws {
try Path.mktemp { tmpdir in try Path.mktemp { tmpdir in
try tmpdir.join("foo.json").touch() try tmpdir.join("foo.json").touch()

View File

@@ -3,7 +3,20 @@ import func XCTest.XCTAssertEqual
import Foundation import Foundation
import XCTest import XCTest
extension PathStruct {
var foo: Int { fatalError()}
}
class PathTests: XCTestCase { class PathTests: XCTestCase {
func testNewStuff() {
#if swift(>=5.5)
func foo<P: Pathish>(_ path: P) {}
foo(.home)
foo(.root)
#endif
}
func testConcatenation() { func testConcatenation() {
XCTAssertEqual((Path.root/"bar").string, "/bar") XCTAssertEqual((Path.root/"bar").string, "/bar")
XCTAssertEqual(Path.cwd.string, FileManager.default.currentDirectoryPath) XCTAssertEqual(Path.cwd.string, FileManager.default.currentDirectoryPath)

View File

@@ -29,6 +29,7 @@ extension PathTests {
("testFindDepthRange", testFindDepthRange), ("testFindDepthRange", testFindDepthRange),
("testFindExecute", testFindExecute), ("testFindExecute", testFindExecute),
("testFindExtension", testFindExtension), ("testFindExtension", testFindExtension),
("testFindHidden", testFindHidden),
("testFindMaxDepth1", testFindMaxDepth1), ("testFindMaxDepth1", testFindMaxDepth1),
("testFindMaxDepth2", testFindMaxDepth2), ("testFindMaxDepth2", testFindMaxDepth2),
("testFindMinDepth", testFindMinDepth), ("testFindMinDepth", testFindMinDepth),
@@ -45,6 +46,7 @@ extension PathTests {
("testMktemp", testMktemp), ("testMktemp", testMktemp),
("testMoveInto", testMoveInto), ("testMoveInto", testMoveInto),
("testMoveTo", testMoveTo), ("testMoveTo", testMoveTo),
("testNewStuff", testNewStuff),
("testNoUndesiredSymlinkResolution", testNoUndesiredSymlinkResolution), ("testNoUndesiredSymlinkResolution", testNoUndesiredSymlinkResolution),
("testOptionalInitializer", testOptionalInitializer), ("testOptionalInitializer", testOptionalInitializer),
("testParent", testParent), ("testParent", testParent),

View File

@@ -19,7 +19,7 @@ private func logic<P: Pathish>(_ set1: Set<Path>, _ set2: Set<Path>, relativeTo:
if set1 != set2 { if set1 != set2 {
let cvt: (Path) -> String = { $0.relative(to: relativeTo) } let cvt: (Path) -> String = { $0.relative(to: relativeTo) }
let out1 = set1.map(cvt).sorted() 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))") fail("Set(\(out1)) is not equal to Set(\(out2))")
} }
} }