Add support for custom cache directories

This commit is contained in:
Nindi Gill 2022-09-26 13:56:25 +10:00
parent 24d0591822
commit d58bf5137a
7 changed files with 94 additions and 22 deletions

View file

@ -28,6 +28,7 @@
390451E1285740E800E0B563 /* Sequence+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E0285740E800E0B563 /* Sequence+Extension.swift */; };
390451E528574F0000E0B563 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E428574F0000E0B563 /* Catalog.swift */; };
390451E72857510C00E0B563 /* TextTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 390451E62857510B00E0B563 /* TextTag.swift */; };
39148CFC28DD55B300011FF5 /* PathControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39148CFB28DD55B300011FF5 /* PathControl.swift */; };
39252A77285A849F00956C74 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39252A76285A849F00956C74 /* AppDelegate.swift */; };
39252A79285A85AF00956C74 /* SettingsInstallersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39252A78285A85AF00956C74 /* SettingsInstallersView.swift */; };
39252A7B285AC50400956C74 /* SettingsDiskImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39252A7A285AC50400956C74 /* SettingsDiskImagesView.swift */; };
@ -175,6 +176,7 @@
390451E0285740E800E0B563 /* Sequence+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sequence+Extension.swift"; sourceTree = "<group>"; };
390451E428574F0000E0B563 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
390451E62857510B00E0B563 /* TextTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextTag.swift; sourceTree = "<group>"; };
39148CFB28DD55B300011FF5 /* PathControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathControl.swift; sourceTree = "<group>"; };
39252A76285A849F00956C74 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
39252A78285A85AF00956C74 /* SettingsInstallersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInstallersView.swift; sourceTree = "<group>"; };
39252A7A285AC50400956C74 /* SettingsDiskImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDiskImagesView.swift; sourceTree = "<group>"; };
@ -484,6 +486,7 @@
39252AA4285C463A00956C74 /* DynamicTextView.swift */,
39252A86285ACE9C00956C74 /* FooterText.swift */,
39252AA0285C2A1600956C74 /* PaddedDivider.swift */,
39148CFB28DD55B300011FF5 /* PathControl.swift */,
39252A84285ACDC800956C74 /* ResetToDefaultButton.swift */,
390451C92856F1D300E0B563 /* ScaledImage.swift */,
390451CB2856F23100E0B563 /* ScaledSystemImage.swift */,
@ -756,6 +759,7 @@
390451CA2856F1D300E0B563 /* ScaledImage.swift in Sources */,
39252A95285BF83D00956C74 /* MistTask.swift in Sources */,
39CF56272861E10F006FB5D2 /* Codesigner.swift in Sources */,
39148CFC28DD55B300011FF5 /* PathControl.swift in Sources */,
3935F4892866C68000760AB0 /* DownloadSectionHeaderView.swift in Sources */,
39252AB5285C706000956C74 /* URL+Extension.swift in Sources */,
39CF56352862D4BF006FB5D2 /* FileCompressor.swift in Sources */,

View file

@ -16,9 +16,10 @@ struct InstallerCreator {
/// - Parameters:
/// - installer: The selected macOS Installer that was downloaded.
/// - mountPoint: The URL of the directory mount point.
/// - cacheDirectory: The cache directory storing all macOS Installer components.
///
/// - Throws: A `MistError` if the downloaded macOS Installer fails to generate.
static func create(_ installer: Installer, mountPoint: URL) async throws {
static func create(_ installer: Installer, mountPoint: URL, cacheDirectory: String) async throws {
guard let url: URL = URL(string: installer.distributionURL) else {
throw MistError.invalidURL(installer.distributionURL)
@ -26,7 +27,7 @@ struct InstallerCreator {
try await DirectoryRemover.remove(installer.temporaryInstallerURL)
let cacheDirectoryURL: URL = URL(fileURLWithPath: .cacheDirectory)
let cacheDirectoryURL: URL = URL(fileURLWithPath: cacheDirectory)
let distributionURL: URL = cacheDirectoryURL.appendingPathComponent(installer.id).appendingPathComponent(url.lastPathComponent)
var argumentsArrays: [[String]] = [
["installer", "-pkg", distributionURL.path, "-target", mountPoint.path]

View file

@ -137,6 +137,7 @@ class TaskManager: ObservableObject {
destination destinationURL: URL?,
exports: [InstallerExportType],
cacheDownloads: Bool,
cacheDirectory: String,
retries: Int,
delay retryDelay: Int,
applicationFilename: String,
@ -150,7 +151,7 @@ class TaskManager: ObservableObject {
packageSigningIdentity: String
) throws -> [(section: MistTaskSection, tasks: [MistTask])] {
var taskGroups: [(section: MistTaskSection, tasks: [MistTask])] = []
let cacheDirectoryURL: URL = URL(fileURLWithPath: .cacheDirectory).appendingPathComponent(installer.id)
let cacheDirectoryURL: URL = URL(fileURLWithPath: cacheDirectory).appendingPathComponent(installer.id)
let temporaryDirectoryURL: URL = URL(fileURLWithPath: .temporaryDirectory)
let mountPointURL: URL = URL(fileURLWithPath: "/Volumes/\(installer.id) Temp")
@ -165,7 +166,7 @@ class TaskManager: ObservableObject {
),
(
section: .setup,
tasks: installTasks(for: installer, temporaryDirectory: temporaryDirectoryURL, mountPoint: mountPointURL)
tasks: installTasks(for: installer, temporaryDirectory: temporaryDirectoryURL, mountPoint: mountPointURL, cacheDirectory: cacheDirectory)
)
]
@ -252,7 +253,7 @@ class TaskManager: ObservableObject {
return tasks
}
private static func installTasks(for installer: Installer, temporaryDirectory temporaryDirectoryURL: URL, mountPoint mountPointURL: URL) -> [MistTask] {
private static func installTasks(for installer: Installer, temporaryDirectory temporaryDirectoryURL: URL, mountPoint mountPointURL: URL, cacheDirectory: String) -> [MistTask] {
let imageURL: URL = temporaryDirectoryURL.appendingPathComponent("\(installer.id) Temp.dmg")
let mountPointURL: URL = URL(fileURLWithPath: "/Volumes/\(installer.id) Temp")
@ -268,7 +269,7 @@ class TaskManager: ObservableObject {
try await DiskImageMounter.mount(imageURL, mountPoint: mountPointURL)
},
MistTask(type: .create, description: "macOS Installer in Disk Image") {
try await InstallerCreator.create(installer, mountPoint: mountPointURL)
try await InstallerCreator.create(installer, mountPoint: mountPointURL, cacheDirectory: cacheDirectory)
}
]
}

View file

@ -0,0 +1,27 @@
//
// PathControl.swift
// Mist
//
// Created by Nindi Gill on 23/9/2022.
//
import SwiftUI
struct PathControl: NSViewRepresentable {
@Binding var path: String
func makeNSView(context: Context) -> NSPathControl {
NSPathControl()
}
func updateNSView(_ nsView: NSPathControl, context: Context) {
nsView.url = URL(fileURLWithPath: path)
}
}
struct PathControl_Previews: PreviewProvider {
static var previews: some View {
PathControl(path: .constant(.cacheDirectory))
}
}

View file

@ -9,6 +9,7 @@ import SwiftUI
struct InstallerListRow: View {
@AppStorage("cacheDownloads") private var cacheDownloads: Bool = false
@AppStorage("cacheDirectory") private var cacheDirectory: String = .cacheDirectory
@AppStorage("applicationFilename") private var applicationFilename: String = .applicationFilenameTemplate
@AppStorage("diskImageFilename") private var diskImageFilename: String = .diskImageFilenameTemplate
@AppStorage("diskImageSign") private var diskImageSign: Bool = false
@ -83,6 +84,7 @@ struct InstallerListRow: View {
destination: openPanel.url,
exports: exports,
cacheDownloads: cacheDownloads,
cacheDirectory: cacheDirectory,
retries: retries,
delay: retryDelay,
applicationFilename: applicationFilename,

View file

@ -8,29 +8,44 @@
import SwiftUI
struct SettingsInstallersCacheView: View {
@Binding var enabled: Bool
@Binding var cacheDownloads: Bool
@Binding var cacheDirectory: String
@State private var cacheSize: String = ""
@State private var buttonClicked: Bool = false
@State private var openPanel: NSOpenPanel = NSOpenPanel()
var body: some View {
HStack {
VStack(alignment: .leading) {
Toggle(isOn: $enabled) {
HStack(alignment: .firstTextBaseline) {
VStack(alignment: .leading) {
Toggle(isOn: $cacheDownloads) {
Text("Cache downloads")
}
FooterText("Speed up future operations by caching a local copy of macOS Installer files.")
}
Spacer()
VStack {
Button("Select...") {
selectCacheDirectory()
}
.disabled(!cacheDownloads)
}
PathControl(path: $cacheDirectory)
.disabled(true)
HStack(alignment: .firstTextBaseline) {
FooterText("Cache directory currently contains \(cacheSize) of data.")
Spacer()
Button("Empty Cache...") {
buttonClicked.toggle()
}
FooterText(cacheSize)
}
.disabled(!cacheDownloads)
}
.onAppear {
getCacheSize()
}
.onChange(of: cacheDirectory) { _ in
getCacheSize()
}
.alert(isPresented: $buttonClicked) {
Alert(
title: Text("Empty Cache Directory?"),
@ -41,9 +56,28 @@ struct SettingsInstallersCacheView: View {
}
}
private func selectCacheDirectory() {
openPanel.prompt = "Select"
openPanel.canCreateDirectories = true
openPanel.canChooseFiles = false
openPanel.canChooseDirectories = true
openPanel.resolvesAliases = true
openPanel.allowsMultipleSelection = false
openPanel.isAccessoryViewDisclosed = true
let response: NSApplication.ModalResponse = openPanel.runModal()
guard response == .OK,
let url: URL = openPanel.url else {
return
}
cacheDirectory = url.path
}
private func getCacheSize() {
let url: URL = URL(fileURLWithPath: .cacheDirectory)
let url: URL = URL(fileURLWithPath: cacheDirectory)
var isDirectory: ObjCBool = false
do {
@ -61,10 +95,10 @@ struct SettingsInstallersCacheView: View {
private func emptyCache() {
do {
let paths: [String] = try FileManager.default.contentsOfDirectory(atPath: .cacheDirectory)
let paths: [String] = try FileManager.default.contentsOfDirectory(atPath: cacheDirectory)
for path in paths {
let url: URL = URL(fileURLWithPath: .cacheDirectory + "/" + path)
let url: URL = URL(fileURLWithPath: cacheDirectory + "/" + path)
try FileManager.default.removeItem(at: url)
}
} catch {
@ -75,6 +109,6 @@ struct SettingsInstallersCacheView: View {
struct SettingsInstallersCacheView_Previews: PreviewProvider {
static var previews: some View {
SettingsInstallersCacheView(enabled: .constant(true))
SettingsInstallersCacheView(cacheDownloads: .constant(true), cacheDirectory: .constant(.cacheDirectory))
}
}

View file

@ -9,9 +9,11 @@ import SwiftUI
struct SettingsInstallersView: View {
@AppStorage("cacheDownloads") private var cacheDownloads: Bool = false
@AppStorage("cacheDirectory") private var cacheDirectory: String = .cacheDirectory
@State private var catalogRows: [CatalogRow] = []
@State private var selectedCatalogRow: CatalogRow?
private let cacheDownloadsDefault: Bool = false
private let cacheDirectoryDefault: String = .cacheDirectory
private var defaultCatalogRows: [CatalogRow] = Catalog.urls.map { CatalogRow(url: $0) }
private let imageName: String = "Installer"
private let title: String = "Installers"
@ -21,7 +23,7 @@ struct SettingsInstallersView: View {
VStack(alignment: .leading) {
SettingsHeaderView(imageName: imageName, title: title, description: description, fade: .constant(false))
PaddedDivider()
SettingsInstallersCacheView(enabled: $cacheDownloads)
SettingsInstallersCacheView(cacheDownloads: $cacheDownloads, cacheDirectory: $cacheDirectory)
PaddedDivider()
SettingsInstallersCatalogsView(catalogRows: $catalogRows, selectedCatalogRow: $selectedCatalogRow)
PaddedDivider()
@ -50,6 +52,7 @@ struct SettingsInstallersView: View {
private func reset() {
cacheDownloads = cacheDownloadsDefault
cacheDirectory = cacheDirectoryDefault
catalogRows = defaultCatalogRows
}
}