Show file list and contents
This commit is contained in:
@ -7,6 +7,30 @@ enum SecurityScopeBookmark: String {
|
||||
case contentPath = "contentPathBookmark"
|
||||
}
|
||||
|
||||
enum StorageAccessError: Error {
|
||||
|
||||
case noBookmarkData
|
||||
|
||||
case bookmarkDataCorrupted(Error)
|
||||
|
||||
case folderAccessFailed(URL)
|
||||
|
||||
}
|
||||
|
||||
extension StorageAccessError: CustomStringConvertible {
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .noBookmarkData:
|
||||
return "No bookmark data to access resources in folder"
|
||||
case .bookmarkDataCorrupted(let error):
|
||||
return "Failed to resolve bookmark: \(error)"
|
||||
case .folderAccessFailed(let url):
|
||||
return "Failed to access folder: \(url.path())"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A class that handles the storage of the website data.
|
||||
|
||||
@ -218,6 +242,9 @@ final class Storage {
|
||||
filesFolder.appending(path: file, directoryHint: .notDirectory)
|
||||
}
|
||||
|
||||
/**
|
||||
Copy an external file to the content folder
|
||||
*/
|
||||
@discardableResult
|
||||
func copyFile(at url: URL, fileId: String) -> Bool {
|
||||
let contentUrl = fileUrl(file: fileId)
|
||||
@ -234,6 +261,15 @@ final class Storage {
|
||||
try deleteFiles(in: filesFolder, notIn: Set(fileSet))
|
||||
}
|
||||
|
||||
func fileContent(for file: String) throws -> String {
|
||||
try operate(in: .contentPath) { folder in
|
||||
let fileUrl = folder
|
||||
.appending(path: "files", directoryHint: .isDirectory)
|
||||
.appending(path: file, directoryHint: .notDirectory)
|
||||
return try String(contentsOf: fileUrl, encoding: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Website data
|
||||
|
||||
private var settingsDataUrl: URL {
|
||||
@ -284,18 +320,25 @@ final class Storage {
|
||||
}
|
||||
|
||||
func write(in scope: SecurityScopeBookmark, operation: (URL) -> Bool) -> Bool {
|
||||
guard let bookmarkData = UserDefaults.standard.data(forKey: scope.rawValue) else {
|
||||
print("No bookmark data to access folder")
|
||||
do {
|
||||
return try operate(in: scope, operation: operation)
|
||||
} catch {
|
||||
print(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func operate<T>(in scope: SecurityScopeBookmark, operation: (URL) throws -> T) throws -> T {
|
||||
guard let bookmarkData = UserDefaults.standard.data(forKey: scope.rawValue) else {
|
||||
throw StorageAccessError.noBookmarkData
|
||||
}
|
||||
var isStale = false
|
||||
let folderURL: URL
|
||||
let folderUrl: URL
|
||||
do {
|
||||
// Resolve the bookmark to get the folder URL
|
||||
folderURL = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
|
||||
folderUrl = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
|
||||
} catch {
|
||||
print("Failed to resolve bookmark: \(error)")
|
||||
return false
|
||||
throw StorageAccessError.bookmarkDataCorrupted(error)
|
||||
}
|
||||
|
||||
if isStale {
|
||||
@ -303,14 +346,11 @@ final class Storage {
|
||||
}
|
||||
|
||||
// Start accessing the security-scoped resource
|
||||
if folderURL.startAccessingSecurityScopedResource() {
|
||||
let result = operation(folderURL)
|
||||
folderURL.stopAccessingSecurityScopedResource()
|
||||
return result
|
||||
} else {
|
||||
print("Failed to access folder: \(folderURL.path)")
|
||||
return false
|
||||
guard folderUrl.startAccessingSecurityScopedResource() else {
|
||||
throw StorageAccessError.folderAccessFailed(folderUrl)
|
||||
}
|
||||
defer { folderUrl.stopAccessingSecurityScopedResource() }
|
||||
return try operation(folderUrl)
|
||||
}
|
||||
|
||||
// MARK: Writing files
|
||||
|
Reference in New Issue
Block a user