This commit is contained in:
Sami Samhuri 2024-04-24 20:22:13 -07:00
parent 8227e5ee7b
commit c74842ef76
4 changed files with 180 additions and 0 deletions

View file

@ -11,6 +11,9 @@
7B5064BF2BD9F236009CEFF9 /* FileOtter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B5064B42BD9F236009CEFF9 /* FileOtter.framework */; };
7B5064C42BD9F236009CEFF9 /* FileOtterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5064C32BD9F236009CEFF9 /* FileOtterTests.swift */; };
7B5064C52BD9F236009CEFF9 /* FileOtter.h in Headers */ = {isa = PBXBuildFile; fileRef = 7B5064B72BD9F236009CEFF9 /* FileOtter.h */; settings = {ATTRIBUTES = (Public, ); }; };
7B5064CF2BD9F2C0009CEFF9 /* Readme.md in Resources */ = {isa = PBXBuildFile; fileRef = 7B5064CE2BD9F2C0009CEFF9 /* Readme.md */; };
7B5064D12BD9F322009CEFF9 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5064D02BD9F322009CEFF9 /* File.swift */; };
7B5064D32BD9F339009CEFF9 /* Dir.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5064D22BD9F339009CEFF9 /* Dir.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -29,6 +32,9 @@
7B5064B82BD9F236009CEFF9 /* FileOtter.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = FileOtter.docc; sourceTree = "<group>"; };
7B5064BE2BD9F236009CEFF9 /* FileOtterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FileOtterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7B5064C32BD9F236009CEFF9 /* FileOtterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileOtterTests.swift; sourceTree = "<group>"; };
7B5064CE2BD9F2C0009CEFF9 /* Readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = "<group>"; };
7B5064D02BD9F322009CEFF9 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
7B5064D22BD9F339009CEFF9 /* Dir.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dir.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -53,6 +59,7 @@
7B5064AA2BD9F235009CEFF9 = {
isa = PBXGroup;
children = (
7B5064CE2BD9F2C0009CEFF9 /* Readme.md */,
7B5064B62BD9F236009CEFF9 /* FileOtter */,
7B5064C22BD9F236009CEFF9 /* FileOtterTests */,
7B5064B52BD9F236009CEFF9 /* Products */,
@ -73,6 +80,8 @@
children = (
7B5064B72BD9F236009CEFF9 /* FileOtter.h */,
7B5064B82BD9F236009CEFF9 /* FileOtter.docc */,
7B5064D02BD9F322009CEFF9 /* File.swift */,
7B5064D22BD9F339009CEFF9 /* Dir.swift */,
);
path = FileOtter;
sourceTree = "<group>";
@ -177,6 +186,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7B5064CF2BD9F2C0009CEFF9 /* Readme.md in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -195,6 +205,8 @@
buildActionMask = 2147483647;
files = (
7B5064B92BD9F236009CEFF9 /* FileOtter.docc in Sources */,
7B5064D12BD9F322009CEFF9 /* File.swift in Sources */,
7B5064D32BD9F339009CEFF9 /* Dir.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -423,6 +435,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = X45WPY5JFZ;
@ -444,6 +457,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = X45WPY5JFZ;

150
FileOtter/Dir.swift Normal file
View file

@ -0,0 +1,150 @@
//
// Dir.swift
// FileOtter
//
// Created by Sami Samhuri on 2024-04-24.
//
import Foundation
public struct Dir: Equatable, Hashable, RandomAccessCollection {
public let startIndex: Int
public let endIndex: Int
public let url: URL
public init(url: URL) throws {
self.init(url: url, children: try Dir.children(url))
}
private let children: [URL]
private init(url: URL, children: [URL]) {
self.url = url
self.children = children
startIndex = children.startIndex
endIndex = children.endIndex
}
}
// MARK: - Well-known Directories
extension Dir {
public static var caches: URL {
URL.cachesDirectory
}
public static var current: URL {
URL.currentDirectory()
}
public static var documents: URL {
URL.documentsDirectory
}
public static var home: URL {
URL.homeDirectory
}
public static var library: URL {
URL.libraryDirectory
}
public static var pwd: URL {
.currentDirectory()
}
public static var getwd: URL {
.currentDirectory()
}
}
// MARK: - Mutations
extension Dir {
@discardableResult
public static func chdir(_ url: URL) -> Bool {
FileManager.default.changeCurrentDirectoryPath(url.path)
}
@discardableResult
public static func chdir<T>(_ url: URL, block: (URL) -> T) -> T {
let previousDir = pwd
FileManager.default.changeCurrentDirectoryPath(url.path)
defer {
FileManager.default.changeCurrentDirectoryPath(previousDir.path)
}
return block(url)
}
@discardableResult
public static func unlink(_ url: URL) -> Bool {
do {
try FileManager.default.removeItem(at: url)
return true
} catch {
return false
}
}
@discardableResult
public static func rmdir(_ url: URL) -> Bool {
unlink(url)
}
@discardableResult
public static func delete(_ url: URL) -> Bool {
unlink(url)
}
}
// MARK: - Reading Contents
extension Dir {
public static func children(_ url: URL) throws -> [URL] {
try FileManager.default
.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
}
public static func entries(_ url: URL) throws -> [String] {
#warning("TODO: implement this ... maybe, it's dumb")
return []
}
public static func exists(_ url: URL) throws -> Bool {
var isDirectory: ObjCBool = false
let exists = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
return exists && isDirectory.boolValue
}
public static func isEmpty(_ url: URL) throws -> Bool {
try FileManager.default
.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
.isEmpty
}
}
// MARK: - Globbing
extension Dir {
public static func glob(base: URL? = nil, _ patterns: String...) -> [URL] {
_glob(base: base, patterns: patterns)
}
public static subscript(base: URL? = nil, _ patterns: String...) -> [URL] {
_glob(base: base, patterns: patterns)
}
private static func _glob(base: URL?, patterns: [String]) -> [URL] {
#warning("TODO: implement me")
return []
}
}
// MARK: - RandomAccessCollection
extension Dir {
public func makeIterator() -> any IteratorProtocol<URL> {
children.makeIterator()
}
public subscript(position: Int) -> URL {
children[position]
}
}

10
FileOtter/File.swift Normal file
View file

@ -0,0 +1,10 @@
//
// File.swift
// FileOtter
//
// Created by Sami Samhuri on 2024-04-24.
//
import Foundation
public struct File {}

6
Readme.md Normal file
View file

@ -0,0 +1,6 @@
# FileOtter
A sleek way to interact with the filesystem in Swift. Heavily inspired by Ruby's `[Dir][]` and `[File][]` classes from the standard library.
[Dir]: https://docs.ruby-lang.org/en/3.3/Dir.html
[File]: https://docs.ruby-lang.org/en/3.3/File.html