Restructured the folder structure in the library and test targets.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
public protocol BundleServicing {
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
func url(forResource name: String?, withExtension ext: String?, subdirectory subpath: String?) -> URL?
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import Foundation
|
||||
|
||||
public protocol FileServicing {
|
||||
|
||||
// MARK: Computed
|
||||
|
||||
var currentFolder: URL { get async }
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
func copyFile(from source: URL, to destination: URL) async throws (FileServiceError)
|
||||
func createFolder(at location: URL) async throws (FileServiceError)
|
||||
func deleteItem(at location: URL) async throws (FileServiceError)
|
||||
func isItemExists(at location: URL) async throws (FileServiceError) -> Bool
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Errors
|
||||
|
||||
public enum FileServiceError: Error, Equatable {
|
||||
case folderNotCreated
|
||||
case itemAlreadyExists
|
||||
case itemEmptyData
|
||||
case itemNotCopied
|
||||
case itemNotDeleted
|
||||
case itemNotExists
|
||||
case itemNotFileURL
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import Foundation
|
||||
|
||||
public struct FileService: FileServicing {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private let fileManager: FileManager
|
||||
|
||||
// MARK: Initialisers
|
||||
|
||||
public init(fileManager: FileManager = .default) {
|
||||
self.fileManager = fileManager
|
||||
}
|
||||
|
||||
// MARK: Computed
|
||||
|
||||
public var currentFolder: URL {
|
||||
get async {
|
||||
.init(at: fileManager.currentDirectoryPath)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
public func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) {
|
||||
guard try await !isItemExists(at: destination) else {
|
||||
throw FileServiceError.itemAlreadyExists
|
||||
}
|
||||
|
||||
var itemData: Data?
|
||||
|
||||
do {
|
||||
itemData = try Data(contentsOf: source)
|
||||
} catch {
|
||||
throw FileServiceError.itemEmptyData
|
||||
}
|
||||
|
||||
do {
|
||||
try itemData?.write(to: destination, options: .atomic)
|
||||
} catch {
|
||||
throw FileServiceError.itemNotCopied
|
||||
}
|
||||
}
|
||||
|
||||
public func createFolder(at location: URL) async throws (FileServiceError) {
|
||||
guard try await !isItemExists(at: location) else {
|
||||
throw FileServiceError.itemAlreadyExists
|
||||
}
|
||||
|
||||
do {
|
||||
try fileManager.createDirectory(at: location, withIntermediateDirectories: true)
|
||||
} catch {
|
||||
throw FileServiceError.folderNotCreated
|
||||
}
|
||||
}
|
||||
|
||||
public func deleteItem(at location: URL) async throws (FileServiceError) {
|
||||
guard try await isItemExists(at: location) else {
|
||||
throw FileServiceError.itemNotExists
|
||||
}
|
||||
|
||||
do {
|
||||
try fileManager.removeItem(at: location)
|
||||
} catch {
|
||||
throw FileServiceError.itemNotDeleted
|
||||
}
|
||||
}
|
||||
|
||||
public func isItemExists(at location: URL) async throws (FileServiceError) -> Bool {
|
||||
guard location.isFileURL else {
|
||||
throw FileServiceError.itemNotFileURL
|
||||
}
|
||||
|
||||
let filePath = location.pathString
|
||||
|
||||
return fileManager.fileExists(atPath: filePath)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import Foundation
|
||||
|
||||
public struct CopyFilesTask {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private let bundleService: BundleServicing
|
||||
private let fileService: FileServicing
|
||||
|
||||
// MARK: Initialisers
|
||||
|
||||
public init(
|
||||
bundleService: BundleServicing? = nil,
|
||||
fileService: FileServicing
|
||||
) {
|
||||
self.bundleService = bundleService ?? Bundle.module
|
||||
self.fileService = fileService
|
||||
}
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
public func callAsFunction(to rootFolder: URL) async throws (FileServiceError) {
|
||||
for resource in ResourceFile.allCases {
|
||||
guard let source = bundleService.url(
|
||||
forResource: resource.rawValue,
|
||||
withExtension: nil,
|
||||
subdirectory: "Resources/Files"
|
||||
) else {
|
||||
assertionFailure("URL should have been initialized.")
|
||||
return
|
||||
}
|
||||
|
||||
let destination = rootFolder.appendingPath(resource.fileName)
|
||||
|
||||
try await fileService.copyFile(from: source, to: destination)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import Foundation
|
||||
|
||||
public struct CreateFoldersTask {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private let fileService: FileServicing
|
||||
|
||||
// MARK: Initialisers
|
||||
|
||||
public init(fileService: FileServicing) {
|
||||
self.fileService = fileService
|
||||
}
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
public func callAsFunction(at rootFolder: URL) async throws {
|
||||
let folders = Self.foldersToCreate.map { rootFolder.appendingPath($0) }
|
||||
|
||||
for folder in folders {
|
||||
try await fileService.createFolder(at: folder)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
extension CreateFoldersTask {
|
||||
|
||||
// MARK: Constants
|
||||
|
||||
static let foldersToCreate: [String] = [
|
||||
"Sources/App",
|
||||
"Sources/AppInfrastructure",
|
||||
"Tests/App/Cases",
|
||||
"Tests/App/Sources"
|
||||
]
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import Foundation
|
||||
|
||||
public struct CreateRootFolderTask {
|
||||
|
||||
// MARK: Properties
|
||||
|
||||
private let fileService: FileServicing
|
||||
|
||||
// MARK: Initialisers
|
||||
|
||||
public init(fileService: FileServicing) {
|
||||
self.fileService = fileService
|
||||
}
|
||||
|
||||
// MARK: Functions
|
||||
|
||||
public func callAsFunction(
|
||||
name: String,
|
||||
at location: URL? = nil
|
||||
) async throws -> URL {
|
||||
guard !name.isEmpty else {
|
||||
throw CreateRootFolderError.nameIsEmpty
|
||||
}
|
||||
|
||||
let rootFolder = if let location {
|
||||
location
|
||||
} else {
|
||||
await fileService.currentFolder
|
||||
}
|
||||
|
||||
let newFolder = rootFolder.appendingPath(name)
|
||||
|
||||
try await fileService.createFolder(at: newFolder)
|
||||
|
||||
return newFolder
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Errors
|
||||
|
||||
public enum CreateRootFolderError: Error {
|
||||
case nameIsEmpty
|
||||
}
|
||||
Reference in New Issue
Block a user