buzsh / SwiftDiffusion

SwiftUI Stable Diffusion implementation using CoreML and PyTorch
GNU General Public License v3.0
158 stars 4 forks source link

refactor: app file structure setup #15

Closed buzsh closed 7 months ago

buzsh commented 7 months ago

For generalized implementation, see: https://gist.github.com/buzsh/8d8a9a55b63f129e564265fa44c21892

/// App directories and their associated URLs
enum AppDirectory: String, CaseIterable {
  // UserFiles: models, loras, embeddings, etc.
  case userFiles    = "UserFiles"
  case models       = "UserFiles/Models"
  case coreMl       = "UserFiles/Models/CoreML"
  case python       = "UserFiles/Models/Python"
  // UserData: local database, saved prompt media, etc.
  case userData     = "UserData"
  case promptMedia  = "UserData/PromptMedia"
}
extension AppDirectory {
  /// `URL` to the AppDirectory case (if it exists)
  var url: URL? {
    guard let appSupportUrl = Constants.FileStructure.AppSupportUrl else {
      Debug.log("Error: Unable to find Application Support directory.")
      return nil
    }
    let baseFolderUrl = appSupportUrl.appendingPathComponent(Constants.FileStructure.AppSupportFolderName)
    return baseFolderUrl.appendingPathComponent(self.rawValue)
  }
}

AppFileStructure Setup

/// Core app file-folder structure setup and configuration.
struct AppFileStructure {
  /// Attempts to ensure that the required directory structure for the application exists.
  /// Calls the completion handler with an error and the URL of the directory that failed to be created, if applicable.
  ///
  /// ## Usage
  /// ```swift
  /// FileUtility.AppFileStructure.setup { error, failedUrl in
  /// if let error = error, let failedUrl = failedUrl {
  ///   print("Failed to create directory at \(failedUrl): \(error)")
  /// } else if let error = error {
  ///   print("Error: \(error)")
  /// } else {
  ///   print("Success")
  /// }
  /// ```
  static func setup(completion: @escaping (Error?, URL?) -> Void) {
    for directoryPath in AppDirectory.allCases {
      guard let directoryUrl = directoryPath.url else {
        completion(FileUtilityError.urlConstructionFailed, nil)
        return
      }
      do {
        try FileUtility.ensureDirectoryExists(at: directoryUrl)
      } catch {
        completion(error, directoryUrl)
        return
      }
    }
    // indicate success if all directories were ensured without errors
    completion(nil, nil)
  }
}

ensureDirectoryExists(at url:)

extension FileStructure {
  /// Ensures a directory exists at the specified URL, throwing an error if creation fails.
  ///
  /// - If the directory exists: return the URL to said directory
  /// - If the directory does not exist: create the directory and return the URL to the newly created directory
  ///
  /// # Usage
  /// ```swift
  /// do {
  ///   try FileUtility.ensureDirectoryExists(at: directoryUrl)
  /// } catch {
  ///   completion(error, directoryUrl)
  /// }
  /// ```
  static func ensureDirectoryExists(at url: URL) throws {
    let fileManager = FileManager.default
    if !fileManager.fileExists(atPath: url.path) {
      do {
        try fileManager.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
      } catch {
        throw FileUtilityError.directoryCreationFailed(url: url, underlyingError: error)
      }
    }
  }
}