~ `AppConstants` shared instance

This commit is contained in:
David Bureš 2024-10-29 20:49:20 +01:00
parent c49edcb274
commit 3ea7084764
88 changed files with 496 additions and 463 deletions

View File

@ -68,7 +68,7 @@ class AppState: ObservableObject
@Published var isLoadingTopPackages: Bool = false
@Published var failedWhileLoadingTopPackages: Bool = false
@Published var cachedDownloadsFolderSize: Int64 = AppConstants.brewCachedDownloadsPath.directorySize
@Published var cachedDownloadsFolderSize: Int64 = AppConstants.shared.brewCachedDownloadsPath.directorySize
@Published var cachedDownloads: [CachedDownload] = .init()
private var cachedDownloadsTemp: [CachedDownload] = .init()
@ -97,31 +97,31 @@ class AppState: ObservableObject
func setupNotifications() async
{
let notificationCenter: UNUserNotificationCenter = AppConstants.notificationCenter
let notificationCenter: UNUserNotificationCenter = AppConstants.shared.notificationCenter
let authStatus: UNAuthorizationStatus = await notificationCenter.authorizationStatus()
switch authStatus
{
case .notDetermined:
AppConstants.logger.debug("Notification authorization status not determined. Will request notifications again")
AppConstants.shared.logger.debug("Notification authorization status not determined. Will request notifications again")
await requestNotificationAuthorization()
case .denied:
AppConstants.logger.debug("Notifications were refused")
AppConstants.shared.logger.debug("Notifications were refused")
case .authorized:
AppConstants.logger.debug("Notifications were authorized")
AppConstants.shared.logger.debug("Notifications were authorized")
case .provisional:
AppConstants.logger.debug("Notifications are provisional")
AppConstants.shared.logger.debug("Notifications are provisional")
case .ephemeral:
AppConstants.logger.debug("Notifications are ephemeral")
AppConstants.shared.logger.debug("Notifications are ephemeral")
@unknown default:
AppConstants.logger.error("Something got really fucked up about notifications setup")
AppConstants.shared.logger.error("Something got really fucked up about notifications setup")
}
notificationAuthStatus = authStatus
@ -129,7 +129,7 @@ class AppState: ObservableObject
func requestNotificationAuthorization() async
{
let notificationCenter: UNUserNotificationCenter = AppConstants.notificationCenter
let notificationCenter: UNUserNotificationCenter = AppConstants.shared.notificationCenter
do
{
@ -139,7 +139,7 @@ class AppState: ObservableObject
}
catch let notificationPermissionsObtainingError as NSError
{
AppConstants.logger.error("Notification permissions obtaining error: \(notificationPermissionsObtainingError.localizedDescription, privacy: .public)\nError code: \(notificationPermissionsObtainingError.code, privacy: .public)")
AppConstants.shared.logger.error("Notification permissions obtaining error: \(notificationPermissionsObtainingError.localizedDescription, privacy: .public)\nError code: \(notificationPermissionsObtainingError.code, privacy: .public)")
notificationEnabledInSystemSettings = false
}
@ -160,7 +160,7 @@ class AppState: ObservableObject
var packagesThatAreTooSmallToDisplaySize: Int = 0
guard let cachedDownloadsFolderContents: [URL] = try? FileManager.default.contentsOfDirectory(at: AppConstants.brewCachedDownloadsPath, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles])
guard let cachedDownloadsFolderContents: [URL] = try? FileManager.default.contentsOfDirectory(at: AppConstants.shared.brewCachedDownloadsPath, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles])
else
{
return
@ -176,7 +176,7 @@ class AppState: ObservableObject
return
}
AppConstants.logger.debug("Temp item name: \(itemName, privacy: .public)")
AppConstants.shared.logger.debug("Temp item name: \(itemName, privacy: .public)")
if itemName.contains("--")
{
@ -208,10 +208,10 @@ class AppState: ObservableObject
cachedDownloads.append(CachedDownload(packageName: itemName, sizeInBytes: itemSize))
}
AppConstants.logger.debug("Others size: \(packagesThatAreTooSmallToDisplaySize, privacy: .public)")
AppConstants.shared.logger.debug("Others size: \(packagesThatAreTooSmallToDisplaySize, privacy: .public)")
}
AppConstants.logger.log("Cached downloads contents: \(self.cachedDownloads)")
AppConstants.shared.logger.log("Cached downloads contents: \(self.cachedDownloads)")
cachedDownloads = cachedDownloads.sorted(by: { $0.sizeInBytes < $1.sizeInBytes })
@ -233,7 +233,7 @@ extension AppState
{
var cachedDownloadsTracker: [CachedDownload] = .init()
AppConstants.logger.debug("Package tracker in cached download assignment function has \(brewData.installedFormulae.count + brewData.installedCasks.count) packages")
AppConstants.shared.logger.debug("Package tracker in cached download assignment function has \(brewData.installedFormulae.count + brewData.installedCasks.count) packages")
for cachedDownload in cachedDownloads
{
@ -241,17 +241,17 @@ extension AppState
if brewData.installedFormulae.contains(where: { $0.name.localizedCaseInsensitiveContains(normalizedCachedPackageName) })
{ /// The cached package is a formula
AppConstants.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is a formula")
AppConstants.shared.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is a formula")
cachedDownloadsTracker.append(.init(packageName: cachedDownload.packageName, sizeInBytes: cachedDownload.sizeInBytes, packageType: .formula))
}
else if brewData.installedCasks.contains(where: { $0.name.localizedCaseInsensitiveContains(normalizedCachedPackageName) })
{ /// The cached package is a cask
AppConstants.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is a cask")
AppConstants.shared.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is a cask")
cachedDownloadsTracker.append(.init(packageName: cachedDownload.packageName, sizeInBytes: cachedDownload.sizeInBytes, packageType: .cask))
}
else
{ /// The cached package cannot be found
AppConstants.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is unknown")
AppConstants.shared.logger.debug("Cached package \(cachedDownload.packageName) (\(normalizedCachedPackageName)) is unknown")
cachedDownloadsTracker.append(.init(packageName: cachedDownload.packageName, sizeInBytes: cachedDownload.sizeInBytes, packageType: .unknown))
}
}

View File

@ -79,16 +79,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject
func applicationWillTerminate(_: Notification)
{
AppConstants.logger.debug("Will die...")
AppConstants.shared.logger.debug("Will die...")
do
{
try saveTaggedIDsToDisk(appState: appState)
}
catch let dataSavingError as NSError
{
AppConstants.logger.error("Failed while trying to save data to disk: \(dataSavingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while trying to save data to disk: \(dataSavingError, privacy: .public)")
}
AppConstants.logger.debug("Died")
AppConstants.shared.logger.debug("Died")
}
func applicationDockMenu(_: NSApplication) -> NSMenu?

View File

@ -191,7 +191,7 @@ struct ContentView: View, Sendable
{
Button
{
AppConstants.logger.info("Ahoj")
AppConstants.shared.logger.info("Ahoj")
} label: {
Label
{
@ -207,55 +207,55 @@ struct ContentView: View, Sendable
}
.onAppear
{
AppConstants.logger.debug("Brew executable path: \(AppConstants.brewExecutablePath, privacy: .public)")
AppConstants.shared.logger.debug("Brew executable path: \(AppConstants.shared.brewExecutablePath, privacy: .public)")
if !customHomebrewPath.isEmpty && !FileManager.default.fileExists(atPath: AppConstants.brewExecutablePath.path)
if !customHomebrewPath.isEmpty && !FileManager.default.fileExists(atPath: AppConstants.shared.brewExecutablePath.path)
{
appState.showAlert(errorToShow: .customBrewExcutableGotDeleted)
}
AppConstants.logger.debug("Documents directory: \(AppConstants.documentsDirectoryPath.path, privacy: .public)")
AppConstants.shared.logger.debug("Documents directory: \(AppConstants.shared.documentsDirectoryPath.path, privacy: .public)")
AppConstants.logger.debug("System version: \(String(describing: AppConstants.osVersionString), privacy: .public)")
AppConstants.shared.logger.debug("System version: \(String(describing: AppConstants.shared.osVersionString), privacy: .public)")
if !FileManager.default.fileExists(atPath: AppConstants.documentsDirectoryPath.path)
if !FileManager.default.fileExists(atPath: AppConstants.shared.documentsDirectoryPath.path)
{
AppConstants.logger.info("Documents directory does not exist, creating it...")
AppConstants.shared.logger.info("Documents directory does not exist, creating it...")
do
{
try FileManager.default.createDirectory(at: AppConstants.documentsDirectoryPath, withIntermediateDirectories: true)
try FileManager.default.createDirectory(at: AppConstants.shared.documentsDirectoryPath, withIntermediateDirectories: true)
}
catch let documentDirectoryCreationError
{
AppConstants.logger.error("Failed while creating document directory: \(documentDirectoryCreationError.localizedDescription)")
AppConstants.shared.logger.error("Failed while creating document directory: \(documentDirectoryCreationError.localizedDescription)")
}
}
else
{
AppConstants.logger.info("Documents directory exists")
AppConstants.shared.logger.info("Documents directory exists")
}
if !FileManager.default.fileExists(atPath: AppConstants.metadataFilePath.path)
if !FileManager.default.fileExists(atPath: AppConstants.shared.metadataFilePath.path)
{
AppConstants.logger.info("Metadata file does not exist, creating it...")
AppConstants.shared.logger.info("Metadata file does not exist, creating it...")
do
{
try Data().write(to: AppConstants.metadataFilePath, options: .atomic)
try Data().write(to: AppConstants.shared.metadataFilePath, options: .atomic)
}
catch let metadataDirectoryCreationError
{
AppConstants.logger.error("Failed while creating metadata directory: \(metadataDirectoryCreationError.localizedDescription)")
AppConstants.shared.logger.error("Failed while creating metadata directory: \(metadataDirectoryCreationError.localizedDescription)")
}
}
else
{
AppConstants.logger.info("Metadata file exists")
AppConstants.shared.logger.info("Metadata file exists")
}
}
.task(priority: .high)
{
AppConstants.logger.info("Started Package Load startup action at \(Date())")
AppConstants.shared.logger.info("Started Package Load startup action at \(Date())")
defer
{
@ -279,7 +279,7 @@ struct ContentView: View, Sendable
{
appState.taggedPackageNames = try loadTaggedIDsFromDisk()
AppConstants.logger.info("Tagged packages in appState: \(appState.taggedPackageNames)")
AppConstants.shared.logger.info("Tagged packages in appState: \(appState.taggedPackageNames)")
do
{
@ -287,36 +287,36 @@ struct ContentView: View, Sendable
}
catch let taggedStateApplicationError as NSError
{
AppConstants.logger.error("Error while applying tagged state to packages: \(taggedStateApplicationError, privacy: .public)")
AppConstants.shared.logger.error("Error while applying tagged state to packages: \(taggedStateApplicationError, privacy: .public)")
appState.showAlert(errorToShow: .couldNotApplyTaggedStateToPackages)
}
}
catch let uuidLoadingError as NSError
{
AppConstants.logger.error("Failed while loading UUIDs from file: \(uuidLoadingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while loading UUIDs from file: \(uuidLoadingError, privacy: .public)")
appState.showAlert(errorToShow: .couldNotApplyTaggedStateToPackages)
}
}
.task(priority: .background)
{
AppConstants.logger.info("Started Analytics startup action at \(Date())")
AppConstants.shared.logger.info("Started Analytics startup action at \(Date())")
async let analyticsQueryCommand: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["analytics"])
async let analyticsQueryCommand: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["analytics"])
if await analyticsQueryCommand.standardOutput.localizedCaseInsensitiveContains("Analytics are enabled")
{
allowBrewAnalytics = true
AppConstants.logger.info("Analytics are ENABLED")
AppConstants.shared.logger.info("Analytics are ENABLED")
}
else
{
allowBrewAnalytics = false
AppConstants.logger.info("Analytics are DISABLED")
AppConstants.shared.logger.info("Analytics are DISABLED")
}
}
.task(priority: .background)
{
AppConstants.logger.info("Started Discoverability startup action at \(Date())")
AppConstants.shared.logger.info("Started Discoverability startup action at \(Date())")
if enableDiscoverability
{
@ -330,7 +330,7 @@ struct ContentView: View, Sendable
{
if appState.cachedDownloads.isEmpty
{
AppConstants.logger.info("Will calculate cached downloads")
AppConstants.shared.logger.info("Will calculate cached downloads")
await appState.loadCachedDownloadedPackages()
appState.assignPackageTypeToCachedDownloads(brewData: brewData)
}
@ -339,7 +339,7 @@ struct ContentView: View, Sendable
{ _ in
Task(priority: .background)
{
AppConstants.logger.info("Will recalculate cached downloads")
AppConstants.shared.logger.info("Will recalculate cached downloads")
appState.cachedDownloads = .init()
await appState.loadCachedDownloadedPackages()
appState.assignPackageTypeToCachedDownloads(brewData: brewData)
@ -364,12 +364,12 @@ struct ContentView: View, Sendable
}
else
{
AppConstants.logger.info("Will purge top package trackers")
AppConstants.shared.logger.info("Will purge top package trackers")
/// Clear out the package trackers so they don't take up RAM
topPackagesTracker.topFormulae = .init()
topPackagesTracker.topCasks = .init()
AppConstants.logger.info("Package tracker status: \(topPackagesTracker.topFormulae) \(topPackagesTracker.topCasks)")
AppConstants.shared.logger.info("Package tracker status: \(topPackagesTracker.topFormulae) \(topPackagesTracker.topCasks)")
}
})
.onChange(of: discoverabilityDaySpan, perform: { _ in
@ -464,11 +464,11 @@ struct ContentView: View, Sendable
{
Button(role: .destructive)
{
if FileManager.default.fileExists(atPath: AppConstants.documentsDirectoryPath.path)
if FileManager.default.fileExists(atPath: AppConstants.shared.documentsDirectoryPath.path)
{
do
{
try FileManager.default.removeItem(atPath: AppConstants.documentsDirectoryPath.path)
try FileManager.default.removeItem(atPath: AppConstants.shared.documentsDirectoryPath.path)
restartApp()
}
catch
@ -492,9 +492,9 @@ struct ContentView: View, Sendable
{
Button
{
if FileManager.default.fileExists(atPath: AppConstants.documentsDirectoryPath.path)
if FileManager.default.fileExists(atPath: AppConstants.shared.documentsDirectoryPath.path)
{
AppConstants.documentsDirectoryPath.revealInFinder(.openParentDirectoryAndHighlightTarget)
AppConstants.shared.documentsDirectoryPath.revealInFinder(.openParentDirectoryAndHighlightTarget)
}
else
{
@ -645,7 +645,7 @@ struct ContentView: View, Sendable
func loadTopPackages() async
{
AppConstants.logger.info("Initial setup finished, time to fetch the top packages")
AppConstants.shared.logger.info("Initial setup finished, time to fetch the top packages")
defer
{

View File

@ -53,8 +53,8 @@ struct CorkApp: App
let backgroundUpdateTimer: NSBackgroundActivityScheduler = {
let scheduler: NSBackgroundActivityScheduler = .init(identifier: "com.davidbures.Cork.backgroundAutoUpdate")
scheduler.repeats = true
scheduler.interval = AppConstants.backgroundUpdateInterval
scheduler.tolerance = AppConstants.backgroundUpdateIntervalTolerance
scheduler.interval = AppConstants.shared.backgroundUpdateInterval
scheduler.tolerance = AppConstants.shared.backgroundUpdateIntervalTolerance
scheduler.qualityOfService = .background
return scheduler
@ -99,7 +99,7 @@ struct CorkApp: App
let currentCorkVersion: String = "1.4.1"
#if DEBUG
AppConstants.logger.debug("There's no saved Cork version - Will save 1.4.1")
AppConstants.shared.logger.debug("There's no saved Cork version - Will save 1.4.1")
#endif
lastSubmittedCorkVersion = currentCorkVersion
@ -108,7 +108,7 @@ struct CorkApp: App
if lastSubmittedCorkVersion != String(NSApplication.appVersion!)
{ /// Submit the version if this version has not already been submitted
#if DEBUG
AppConstants.logger.debug("Last submitted version doesn't match current version")
AppConstants.shared.logger.debug("Last submitted version doesn't match current version")
#endif
try? await submitSystemVersion()
@ -116,7 +116,7 @@ struct CorkApp: App
else
{
#if DEBUG
AppConstants.logger.debug("Last submitted version matches the current version")
AppConstants.shared.logger.debug("Last submitted version matches the current version")
#endif
}
}
@ -125,7 +125,7 @@ struct CorkApp: App
print("Licensing state: \(appDelegate.appState.licensingState)")
#if SELF_COMPILED
AppConstants.logger.debug("Will set licensing state to Self Compiled")
AppConstants.shared.logger.debug("Will set licensing state to Self Compiled")
appDelegate.appState.licensingState = .selfCompiled
#else
if !hasValidatedEmail
@ -134,13 +134,13 @@ struct CorkApp: App
{
if let demoActivatedAt
{
let timeDemoWillRunOutAt: Date = demoActivatedAt + AppConstants.demoLengthInSeconds
let timeDemoWillRunOutAt: Date = demoActivatedAt + AppConstants.shared.demoLengthInSeconds
AppConstants.logger.debug("There is \(demoActivatedAt.timeIntervalSinceNow.formatted()) to go on the demo")
AppConstants.shared.logger.debug("There is \(demoActivatedAt.timeIntervalSinceNow.formatted()) to go on the demo")
AppConstants.logger.debug("Demo will time out at \(timeDemoWillRunOutAt.formatted(date: .complete, time: .complete))")
AppConstants.shared.logger.debug("Demo will time out at \(timeDemoWillRunOutAt.formatted(date: .complete, time: .complete))")
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.demoLengthInSeconds) > 0
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.shared.demoLengthInSeconds) > 0
{ // Check if there is still time on the demo
/// do stuff if there is
}
@ -158,13 +158,13 @@ struct CorkApp: App
// Start the background update scheduler when the app starts
backgroundUpdateTimer.schedule
{ (completion: NSBackgroundActivityScheduler.CompletionHandler) in
AppConstants.logger.log("Scheduled event fired at \(Date(), privacy: .auto)")
AppConstants.shared.logger.log("Scheduled event fired at \(Date(), privacy: .auto)")
Task(priority: .background)
{
var updateResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["update"])
var updateResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["update"])
AppConstants.logger.debug("Update result:\nStandard output: \(updateResult.standardOutput, privacy: .public)\nStandard error: \(updateResult.standardError, privacy: .public)")
AppConstants.shared.logger.debug("Update result:\nStandard output: \(updateResult.standardOutput, privacy: .public)\nStandard error: \(updateResult.standardError, privacy: .public)")
do
{
@ -174,11 +174,11 @@ struct CorkApp: App
var newOutdatedPackages: Set<OutdatedPackage> = await temporaryOutdatedPackageTracker.outdatedPackages
AppConstants.logger.debug("Outdated packages checker output: \(newOutdatedPackages, privacy: .public)")
AppConstants.shared.logger.debug("Outdated packages checker output: \(newOutdatedPackages, privacy: .public)")
defer
{
AppConstants.logger.log("Will purge temporary update trackers")
AppConstants.shared.logger.log("Will purge temporary update trackers")
updateResult = .init(standardOutput: "", standardError: "")
newOutdatedPackages = .init()
@ -186,13 +186,13 @@ struct CorkApp: App
if await newOutdatedPackages.count > outdatedPackageTracker.outdatedPackages.count
{
AppConstants.logger.log("New updates found")
AppConstants.shared.logger.log("New updates found")
/// Set this to `true` so the normal notification doesn't get sent
await setWhetherToSendStandardUpdatesAvailableNotification(to: false)
let differentPackages: Set<OutdatedPackage> = await newOutdatedPackages.subtracting(outdatedPackageTracker.displayableOutdatedPackages)
AppConstants.logger.debug("Changed packages: \(differentPackages, privacy: .auto)")
AppConstants.shared.logger.debug("Changed packages: \(differentPackages, privacy: .auto)")
sendNotification(title: String(localized: "notification.new-outdated-packages-found.title"), subtitle: differentPackages.map(\.package.name).formatted(.list(type: .and)))
@ -205,12 +205,12 @@ struct CorkApp: App
}
else
{
AppConstants.logger.log("No new updates found")
AppConstants.shared.logger.log("No new updates found")
}
}
catch
{
AppConstants.logger.error("Something got fucked up about checking for outdated packages")
AppConstants.shared.logger.error("Something got fucked up about checking for outdated packages")
}
}
@ -221,13 +221,13 @@ struct CorkApp: App
{ newValue in
if let newValue
{ // If the demo has not been activated, `demoActivatedAt` is nil. So, when it's not nil anymore, it means the user activated it
AppConstants.logger.debug("The user activated the demo at \(newValue.formatted(date: .complete, time: .complete), privacy: .public)")
AppConstants.shared.logger.debug("The user activated the demo at \(newValue.formatted(date: .complete, time: .complete), privacy: .public)")
hasFinishedLicensingWorkflow = true
}
}
.onChange(of: outdatedPackageTracker.displayableOutdatedPackages.count)
{ outdatedPackageCount in
AppConstants.logger.debug("Number of displayable outdated packages changed (\(outdatedPackageCount))")
AppConstants.shared.logger.debug("Number of displayable outdated packages changed (\(outdatedPackageCount))")
// TODO: Remove this once I figure out why the updating spinner sometimes doesn't disappear
withAnimation
@ -251,7 +251,7 @@ struct CorkApp: App
// TODO: Changing the package display type sends a notificaiton, which is not visible since the app is in the foreground. Once macOS 15 comes out, move `sendStandardUpdatesAvailableNotification` into the AppState and suppress it
if outdatedPackageNotificationType == .notification || outdatedPackageNotificationType == .both
{
AppConstants.logger.log("Will try to send notification")
AppConstants.shared.logger.log("Will try to send notification")
/// This needs to be checked because when the background update system finds an update, we don't want to send this normal notification.
/// Instead, we want to send a more succinct notification that includes only the new package
@ -302,9 +302,9 @@ struct CorkApp: App
switch result
{
case .success(let success):
AppConstants.logger.log("Succeeded in exporting: \(success, privacy: .public)")
AppConstants.shared.logger.log("Succeeded in exporting: \(success, privacy: .public)")
case .failure(let failure):
AppConstants.logger.error("Failed in exporting: \(failure, privacy: .public)")
AppConstants.shared.logger.error("Failed in exporting: \(failure, privacy: .public)")
}
}
.fileImporter(
@ -316,9 +316,9 @@ struct CorkApp: App
switch result
{
case .success(let success):
AppConstants.logger.debug("Succeeded in importing: \(success, privacy: .public)")
AppConstants.shared.logger.debug("Succeeded in importing: \(success, privacy: .public)")
case .failure(let failure):
AppConstants.logger.error("Failed in importing: \(failure, privacy: .public)")
AppConstants.shared.logger.error("Failed in importing: \(failure, privacy: .public)")
}
}
}
@ -532,7 +532,7 @@ struct CorkApp: App
}
catch let brewfileExportError as BrewfileDumpingError
{
AppConstants.logger.error("\(brewfileExportError)")
AppConstants.shared.logger.error("\(brewfileExportError)")
switch brewfileExportError
{
@ -570,7 +570,7 @@ struct CorkApp: App
throw BrewfileReadingError.couldNotGetBrewfileLocation
}
AppConstants.logger.debug("\(brewfileURL.path)")
AppConstants.shared.logger.debug("\(brewfileURL.path)")
do
{
@ -578,7 +578,7 @@ struct CorkApp: App
}
catch let brewfileImportingError
{
AppConstants.logger.error("\(brewfileImportingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.error("\(brewfileImportingError.localizedDescription, privacy: .public)")
appDelegate.appState.showAlert(errorToShow: .malformedBrewfile)

View File

@ -19,13 +19,13 @@ struct GetInstalledCasksIntent: AppIntent
func perform() async throws -> some ReturnsValue<[MinimalHomebrewPackage]>
{
let allowAccessToFile: Bool = AppConstants.brewCaskPath.startAccessingSecurityScopedResource()
let allowAccessToFile: Bool = AppConstants.shared.brewCaskPath.startAccessingSecurityScopedResource()
if allowAccessToFile
{
let installedFormulae: Set<BrewPackage> = await loadUpPackages(whatToLoad: .cask, appState: AppState())
AppConstants.brewCaskPath.stopAccessingSecurityScopedResource()
AppConstants.shared.brewCaskPath.stopAccessingSecurityScopedResource()
let minimalPackages: [MinimalHomebrewPackage] = installedFormulae.map
{ package in
@ -38,7 +38,7 @@ struct GetInstalledCasksIntent: AppIntent
{
print("Could not obtain access to folder")
throw FolderAccessingError.couldNotObtainPermissionToAccessFolder(formattedPath: AppConstants.brewCaskPath.absoluteString)
throw FolderAccessingError.couldNotObtainPermissionToAccessFolder(formattedPath: AppConstants.shared.brewCaskPath.absoluteString)
}
}
}

View File

@ -36,13 +36,13 @@ struct GetInstalledFormulaeIntent: AppIntent
func perform() async throws -> some ReturnsValue<[MinimalHomebrewPackage]>
{
let allowAccessToFile: Bool = AppConstants.brewCellarPath.startAccessingSecurityScopedResource()
let allowAccessToFile: Bool = AppConstants.shared.brewCellarPath.startAccessingSecurityScopedResource()
if allowAccessToFile
{
let installedFormulae: Set<BrewPackage> = await loadUpPackages(whatToLoad: .formula, appState: AppState())
AppConstants.brewCellarPath.stopAccessingSecurityScopedResource()
AppConstants.shared.brewCellarPath.stopAccessingSecurityScopedResource()
var minimalPackages: [MinimalHomebrewPackage] = installedFormulae.map
{ package in
@ -59,7 +59,7 @@ struct GetInstalledFormulaeIntent: AppIntent
else
{
print("Could not obtain access to folder")
throw FolderAccessingError.couldNotObtainPermissionToAccessFolder(formattedPath: AppConstants.brewCellarPath.absoluteString)
throw FolderAccessingError.couldNotObtainPermissionToAccessFolder(formattedPath: AppConstants.shared.brewCellarPath.absoluteString)
}
}
}

View File

@ -34,7 +34,7 @@ struct RefreshPackagesIntent: AppIntent
func perform() async throws -> some ReturnsValue<RefreshIntentResult>
{
let refreshCommandResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["update"])
let refreshCommandResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["update"])
var refreshErrorWithoutBuggedHomebrewMessages: [String] = refreshCommandResult.standardError.components(separatedBy: "\n")
refreshErrorWithoutBuggedHomebrewMessages = refreshErrorWithoutBuggedHomebrewMessages.filter { !$0.contains("Updating Homebrew") }

View File

@ -41,7 +41,7 @@ func exportBrewfile(appState: AppState) async throws -> String
let pathRawOutput: TerminalOutput = await shell(URL(string: "/bin/pwd")!, ["-L"])
let brewfileDumpingResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["bundle", "-f", "dump"], workingDirectory: brewfileParentLocation)
let brewfileDumpingResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["bundle", "-f", "dump"], workingDirectory: brewfileParentLocation)
/// Throw an error if the working directory could not be determined
if !pathRawOutput.standardError.isEmpty
@ -61,7 +61,7 @@ func exportBrewfile(appState: AppState) async throws -> String
throw BrewfileDumpingError.errorWhileDumpingBrewfile(error: brewfileDumpingResult.standardError)
}
AppConstants.logger.info("Path: \(workingDirectory, privacy: .auto)")
AppConstants.shared.logger.info("Path: \(workingDirectory, privacy: .auto)")
print("Brewfile dumping result: \(brewfileDumpingResult)")
@ -78,7 +78,7 @@ func exportBrewfile(appState: AppState) async throws -> String
}
catch let brewfileReadingError
{
AppConstants.logger.error("Error while reading contents of Brewfile: \(brewfileReadingError, privacy: .public)")
AppConstants.shared.logger.error("Error while reading contents of Brewfile: \(brewfileReadingError, privacy: .public)")
throw BrewfileDumpingError.couldNotReadBrewfile
}
}

View File

@ -31,11 +31,11 @@ func importBrewfile(from url: URL, appState: AppState, brewData: BrewDataStorage
appState.brewfileImportingStage = .importing
AppConstants.logger.info("Brewfile import path: \(url.path)")
AppConstants.shared.logger.info("Brewfile import path: \(url.path)")
let brewfileImportingResultRaw: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["bundle", "--file", url.path, "--no-lock"])
let brewfileImportingResultRaw: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["bundle", "--file", url.path, "--no-lock"])
AppConstants.logger.info("Brewfile import result:\nStandard output: \(brewfileImportingResultRaw.standardOutput, privacy: .public)\nStandard error: \(brewfileImportingResultRaw.standardError)")
AppConstants.shared.logger.info("Brewfile import result:\nStandard output: \(brewfileImportingResultRaw.standardOutput, privacy: .public)\nStandard error: \(brewfileImportingResultRaw.standardError)")
if !brewfileImportingResultRaw.standardError.isEmpty
{

View File

@ -109,13 +109,13 @@ extension TopPackagesTracker
}
catch let topFormulaeDecodingError
{
AppConstants.logger.error("Failed while decoding top formulae: \(topFormulaeDecodingError)")
AppConstants.shared.logger.error("Failed while decoding top formulae: \(topFormulaeDecodingError)")
throw TopPackageLoadingError.couldNotDecodeTopFormulae(error: topFormulaeDecodingError.localizedDescription)
}
}
catch let dataDownloadingError
{
AppConstants.logger.error("Failed while retrieving top formulae: \(dataDownloadingError.localizedDescription)")
AppConstants.shared.logger.error("Failed while retrieving top formulae: \(dataDownloadingError.localizedDescription)")
throw TopPackageLoadingError.couldNotDownloadData
}
}
@ -165,13 +165,13 @@ extension TopPackagesTracker
}
catch let topCasksDecodingError
{
AppConstants.logger.error("Failed while decoding top casks: \(topCasksDecodingError)")
AppConstants.shared.logger.error("Failed while decoding top casks: \(topCasksDecodingError)")
throw TopPackageLoadingError.couldNotDecodeTopCasks(error: topCasksDecodingError.localizedDescription)
}
}
catch let dataDownloadingError
{
AppConstants.logger.error("Failed while retrieving top casks: \(dataDownloadingError.localizedDescription)")
AppConstants.shared.logger.error("Failed while retrieving top casks: \(dataDownloadingError.localizedDescription)")
throw TopPackageLoadingError.couldNotDownloadData
}
}

View File

@ -59,12 +59,12 @@ func getContentsOfFolder(targetFolder: URL) async throws -> Set<BrewPackage>
{
if targetFolder.appendingPathComponent(item, conformingTo: .fileURL).isDirectory
{
AppConstants.logger.error("Failed while getting package version for package \(fullURLToPackageFolderCurrentlyBeingProcessed.lastPathComponent). Package does not have any version installed.")
AppConstants.shared.logger.error("Failed while getting package version for package \(fullURLToPackageFolderCurrentlyBeingProcessed.lastPathComponent). Package does not have any version installed.")
throw PackageLoadingError.packageDoesNotHaveAnyVersionsInstalled(item)
}
else
{
AppConstants.logger.error("Failed while getting package version for package \(fullURLToPackageFolderCurrentlyBeingProcessed.lastPathComponent). Package is not a folder")
AppConstants.shared.logger.error("Failed while getting package version for package \(fullURLToPackageFolderCurrentlyBeingProcessed.lastPathComponent). Package is not a folder")
throw PackageLoadingError.packageIsNotAFolder(item, targetFolder.appendingPathComponent(item, conformingTo: .fileURL))
}
}
@ -108,7 +108,7 @@ func getContentsOfFolder(targetFolder: URL) async throws -> Set<BrewPackage>
}
catch
{
AppConstants.logger.error("Failed while accessing folder: \(error)")
AppConstants.shared.logger.error("Failed while accessing folder: \(error)")
throw error
}
}
@ -154,7 +154,7 @@ private extension URL
guard localPackagePath.lastPathComponent != "Cellar"
else
{
AppConstants.logger.error("The last path component of the requested URL is the package container folder itself - perhaps a misconfigured package folder? Tried to load URL \(localPackagePath)")
AppConstants.shared.logger.error("The last path component of the requested URL is the package container folder itself - perhaps a misconfigured package folder? Tried to load URL \(localPackagePath)")
throw PackageLoadingError.failedWhileLoadingPackages(failureReason: String(localized: "error.package-loading.last-path-component-of-checked-package-url-is-folder-containing-packages-itself.formulae"))
}
@ -162,7 +162,7 @@ private extension URL
guard localPackagePath.lastPathComponent != "Caskroom"
else
{
AppConstants.logger.error("The last path component of the requested URL is the package container folder itself - perhaps a misconfigured package folder? Tried to load URL \(localPackagePath)")
AppConstants.shared.logger.error("The last path component of the requested URL is the package container folder itself - perhaps a misconfigured package folder? Tried to load URL \(localPackagePath)")
throw PackageLoadingError.failedWhileLoadingPackages(failureReason: String(localized: "error.package-loading.last-path-component-of-checked-package-url-is-folder-containing-packages-itself.casks"))
}
@ -194,14 +194,14 @@ private extension URL
}
catch let installReceiptParsingError
{
AppConstants.logger.error("Failed to decode install receipt for package \(self.lastPathComponent, privacy: .public) with error \(installReceiptParsingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.error("Failed to decode install receipt for package \(self.lastPathComponent, privacy: .public) with error \(installReceiptParsingError.localizedDescription, privacy: .public)")
throw PackageLoadingError.failedWhileLoadingCertainPackage(self.lastPathComponent, self, failureReason: String(localized: "error.package-loading.could-not-decode-installa-receipt-\(installReceiptParsingError.localizedDescription)"))
}
}
catch let installReceiptLoadingError
{
AppConstants.logger.error("Failed to load contents of install receipt for package \(self.lastPathComponent, privacy: .public) with error \(installReceiptLoadingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.error("Failed to load contents of install receipt for package \(self.lastPathComponent, privacy: .public) with error \(installReceiptLoadingError.localizedDescription, privacy: .public)")
throw PackageLoadingError.failedWhileLoadingCertainPackage(self.lastPathComponent, self, failureReason: String(localized: "error.package-loading.could-not-convert-contents-of-install-receipt-to-data-\(installReceiptLoadingError.localizedDescription)"))
}
}
@ -209,7 +209,7 @@ private extension URL
{ /// There's no install receipt for this package - silently fail and return that the packagw was not installed intentionally
// TODO: Add a setting like "Strictly check for errors" that would instead throw an error here
AppConstants.logger.error("There appears to be no install receipt for package \(localPackageInfoJSONPath.lastPathComponent, privacy: .public)")
AppConstants.shared.logger.error("There appears to be no install receipt for package \(localPackageInfoJSONPath.lastPathComponent, privacy: .public)")
let shouldStrictlyCheckForHomebrewErrors: Bool = UserDefaults.standard.bool(forKey: "strictlyCheckForHomebrewErrors")
@ -249,25 +249,25 @@ private extension URL
/// Get URLs to a package's versions
var packageVersionURLs: [URL]?
{
AppConstants.logger.debug("Will check URL \(self)")
AppConstants.shared.logger.debug("Will check URL \(self)")
do
{
let versions: [URL] = try FileManager.default.contentsOfDirectory(at: self, includingPropertiesForKeys: [.isHiddenKey], options: .skipsHiddenFiles)
if versions.isEmpty
{
AppConstants.logger.warning("Package URL \(self, privacy: .public) has no versions installed")
AppConstants.shared.logger.warning("Package URL \(self, privacy: .public) has no versions installed")
return nil
}
AppConstants.logger.debug("URL \(self) has these versions: \(versions))")
AppConstants.shared.logger.debug("URL \(self) has these versions: \(versions))")
return versions
}
catch
{
AppConstants.logger.error("Failed while loading version for package \(lastPathComponent, privacy: .public) at URL \(self, privacy: .public)")
AppConstants.shared.logger.error("Failed while loading version for package \(lastPathComponent, privacy: .public) at URL \(self, privacy: .public)")
return nil
}
@ -305,7 +305,7 @@ func getContentsOfFolder(targetFolder: URL, options: FileManager.DirectoryEnumer
}
catch let folderReadingError as NSError
{
AppConstants.logger.error("\(folderReadingError.localizedDescription)")
AppConstants.shared.logger.error("\(folderReadingError.localizedDescription)")
}
return contentsOfFolder

View File

@ -20,7 +20,7 @@ extension URL
}
catch let symlinkCheckingError
{
AppConstants.logger.error("Error checking if \(self) is symlink: \(symlinkCheckingError)")
AppConstants.shared.logger.error("Error checking if \(self) is symlink: \(symlinkCheckingError)")
return nil
}

View File

@ -11,12 +11,12 @@ import CorkShared
@MainActor
func applyUninstallationSpinner(to package: BrewPackage, brewData: BrewDataStorage)
{
AppConstants.logger.debug("""
AppConstants.shared.logger.debug("""
Brew data:
Installed Formulae: \(brewData.installedFormulae)
Installed Casks: \(brewData.installedCasks)
""")
AppConstants.logger.debug("Will try to apply uninstallation spinner to package \(package.name)")
AppConstants.shared.logger.debug("Will try to apply uninstallation spinner to package \(package.name)")
if package.type == .cask
{

View File

@ -55,23 +55,23 @@ extension BrewDataStorage
appState.isShowingUninstallationProgressView = true
}
AppConstants.logger.info("Will try to remove package \(package.name, privacy: .auto)")
AppConstants.shared.logger.info("Will try to remove package \(package.name, privacy: .auto)")
var uninstallCommandOutput: TerminalOutput
if !shouldRemoveAllAssociatedFiles
{
uninstallCommandOutput = await shell(AppConstants.brewExecutablePath, ["uninstall", package.name])
uninstallCommandOutput = await shell(AppConstants.shared.brewExecutablePath, ["uninstall", package.name])
}
else
{
uninstallCommandOutput = await shell(AppConstants.brewExecutablePath, ["uninstall", "--zap", package.name])
uninstallCommandOutput = await shell(AppConstants.shared.brewExecutablePath, ["uninstall", "--zap", package.name])
}
AppConstants.logger.warning("Uninstall process Standard error: \(uninstallCommandOutput.standardError)")
AppConstants.shared.logger.warning("Uninstall process Standard error: \(uninstallCommandOutput.standardError)")
if uninstallCommandOutput.standardError.contains("because it is required by")
{
AppConstants.logger.warning("Could not uninstall this package because it's a dependency")
AppConstants.shared.logger.warning("Could not uninstall this package because it's a dependency")
/// If the uninstallation failed, change the status back to "not being modified"
resetPackageState(package: package)
@ -82,11 +82,11 @@ extension BrewDataStorage
appState.showAlert(errorToShow: .uninstallationNotPossibleDueToDependency(packageThatTheUserIsTryingToUninstall: package, offendingDependencyProhibitingUninstallation: dependencyName))
AppConstants.logger.warning("Name of offending dependency: \(dependencyName, privacy: .public)")
AppConstants.shared.logger.warning("Name of offending dependency: \(dependencyName, privacy: .public)")
}
catch let regexError as NSError
{
AppConstants.logger.error("Failed to extract dependency name from output: \(regexError, privacy: .public)")
AppConstants.shared.logger.error("Failed to extract dependency name from output: \(regexError, privacy: .public)")
throw RegexError.regexFunctionCouldNotMatchAnything
}
}
@ -94,7 +94,7 @@ extension BrewDataStorage
{
// TODO: So far, this only stops the package from being removed from the tracker. Implement a tutorial on how to uninstall the package
AppConstants.logger.error("Could not uninstall this package because sudo is required")
AppConstants.shared.logger.error("Could not uninstall this package because sudo is required")
appState.packageTryingToBeUninstalledWithSudo = package
appState.isShowingSudoRequiredForUninstallSheet = true
@ -103,7 +103,7 @@ extension BrewDataStorage
}
else
{
AppConstants.logger.info("Uninstalling can proceed")
AppConstants.shared.logger.info("Uninstalling can proceed")
switch package.type
{
@ -132,7 +132,7 @@ extension BrewDataStorage
appState.isShowingUninstallationProgressView = false
AppConstants.logger.info("Package uninstallation process output:\nStandard output: \(uninstallCommandOutput.standardOutput, privacy: .public)\nStandard error: \(uninstallCommandOutput.standardError, privacy: .public)")
AppConstants.shared.logger.info("Package uninstallation process output:\nStandard output: \(uninstallCommandOutput.standardOutput, privacy: .public)\nStandard error: \(uninstallCommandOutput.standardError, privacy: .public)")
/// If the user removed a package that was outdated, remove it from the outdated package tracker
Task

View File

@ -13,13 +13,13 @@ func loadUpTappedTaps() async -> [BrewTap]
{
var finalAvailableTaps: [BrewTap] = .init()
let contentsOfTapFolder: [URL] = getContentsOfFolder(targetFolder: AppConstants.tapPath, options: .skipsHiddenFiles)
let contentsOfTapFolder: [URL] = getContentsOfFolder(targetFolder: AppConstants.shared.tapPath, options: .skipsHiddenFiles)
AppConstants.logger.debug("Contents of tap folder: \(contentsOfTapFolder)")
AppConstants.shared.logger.debug("Contents of tap folder: \(contentsOfTapFolder)")
for tapRepoParentURL in contentsOfTapFolder
{
AppConstants.logger.debug("Tap repo: \(tapRepoParentURL)")
AppConstants.shared.logger.debug("Tap repo: \(tapRepoParentURL)")
let contentsOfTapRepoParent: [URL] = getContentsOfFolder(targetFolder: tapRepoParentURL, options: .skipsHiddenFiles)
@ -34,7 +34,7 @@ func loadUpTappedTaps() async -> [BrewTap]
let fullTapName: String = "\(repoParentName)/\(repoName)"
AppConstants.logger.info("Full tap name: \(fullTapName)")
AppConstants.shared.logger.info("Full tap name: \(fullTapName)")
finalAvailableTaps.append(BrewTap(name: fullTapName))
}
@ -44,30 +44,30 @@ func loadUpTappedTaps() async -> [BrewTap]
{ taskGroup in
if finalAvailableTaps.filter({ $0.name == "homebrew/core" }).isEmpty
{
AppConstants.logger.warning("Couldn't find homebrew/core in local taps")
AppConstants.shared.logger.warning("Couldn't find homebrew/core in local taps")
taskGroup.addTask
{
let isCoreAdded: Bool = await checkIfTapIsAdded(tapToCheck: "homebrew/core")
if isCoreAdded
{
AppConstants.logger.info("homebrew/core is added, but not in local taps")
AppConstants.shared.logger.info("homebrew/core is added, but not in local taps")
return BrewTap(name: "homebrew/core")
}
else
{
AppConstants.logger.warning("homebrew/core is not added and not in local taps")
AppConstants.shared.logger.warning("homebrew/core is not added and not in local taps")
return nil
}
}
}
else
{
AppConstants.logger.info("Found homebrew/core in local taps")
AppConstants.shared.logger.info("Found homebrew/core in local taps")
}
if finalAvailableTaps.filter({ $0.name == "homebrew/cask" }).isEmpty
{
AppConstants.logger.warning("Couldn't find homebrew/cask in local taps")
AppConstants.shared.logger.warning("Couldn't find homebrew/cask in local taps")
taskGroup.addTask
{
let isCaskAdded: Bool = await checkIfTapIsAdded(tapToCheck: "homebrew/cask")
@ -77,14 +77,14 @@ func loadUpTappedTaps() async -> [BrewTap]
}
else
{
AppConstants.logger.warning("homebrew/cask is not added and not in local taps")
AppConstants.shared.logger.warning("homebrew/cask is not added and not in local taps")
return nil
}
}
}
else
{
AppConstants.logger.info("Found homebrew/cask in local taps")
AppConstants.shared.logger.info("Found homebrew/cask in local taps")
}
var nonLocalBasicTapsInternal: [BrewTap] = .init()

View File

@ -11,7 +11,7 @@ import CorkShared
func deleteCachedDownloads()
{
/// This folder has the symlinks, so we have do **delete ONLY THE SYMLINKS**
for url in getContentsOfFolder(targetFolder: AppConstants.brewCachedFormulaeDownloadsPath)
for url in getContentsOfFolder(targetFolder: AppConstants.shared.brewCachedFormulaeDownloadsPath)
{
if let isSymlink = url.isSymlink()
{
@ -21,17 +21,17 @@ func deleteCachedDownloads()
}
else
{
AppConstants.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
AppConstants.shared.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
}
}
else
{
AppConstants.logger.warning("Could not check symlink status of \(url)")
AppConstants.shared.logger.warning("Could not check symlink status of \(url)")
}
}
/// This folder has the symlinks, so we have to **delete ONLY THE SYMLINKS**
for url in getContentsOfFolder(targetFolder: AppConstants.brewCachedCasksDownloadsPath)
for url in getContentsOfFolder(targetFolder: AppConstants.shared.brewCachedCasksDownloadsPath)
{
if let isSymlink = url.isSymlink()
{
@ -41,23 +41,23 @@ func deleteCachedDownloads()
}
else
{
AppConstants.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
AppConstants.shared.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
}
}
else
{
AppConstants.logger.warning("Could not check symlink status of \(url)")
AppConstants.shared.logger.warning("Could not check symlink status of \(url)")
}
}
/// This folder has the downloads themselves, so we have do **DELETE EVERYTHING THAT IS NOT A SYMLINK**
for url in getContentsOfFolder(targetFolder: AppConstants.brewCachedDownloadsPath)
for url in getContentsOfFolder(targetFolder: AppConstants.shared.brewCachedDownloadsPath)
{
if let isSymlink = url.isSymlink()
{
if isSymlink
{
AppConstants.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
AppConstants.shared.logger.info("Ignoring cached download at location \(url, privacy: .auto)")
}
else
{
@ -66,7 +66,7 @@ func deleteCachedDownloads()
}
else
{
AppConstants.logger.warning("Could not check symlink status of \(url)")
AppConstants.shared.logger.warning("Could not check symlink status of \(url)")
}
}
}

View File

@ -24,7 +24,7 @@ enum HealthCheckError: LocalizedError
func performBrewHealthCheck() async throws -> TerminalOutput
{
async let commandResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["doctor"])
async let commandResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["doctor"])
await print(commandResult)

View File

@ -15,7 +15,7 @@ import CorkShared
func purgeBrewCache() async throws -> TerminalOutput
{
async let commandResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["cleanup"])
async let commandResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["cleanup"])
return await commandResult
}

View File

@ -24,7 +24,7 @@ enum OrphanUninstallationError: LocalizedError
func uninstallOrphanedPackages() async throws -> TerminalOutput
{
let commandResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["autoremove"])
let commandResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["autoremove"])
if !commandResult.standardOutput.contains("Autoremoving")
{
@ -34,7 +34,7 @@ func uninstallOrphanedPackages() async throws -> TerminalOutput
}
else
{
AppConstants.logger.error("Unexpected orphan package removal output:\nStandard output: \(commandResult.standardOutput, privacy: .public)\nStandard error: \(commandResult.standardError, privacy: .public)")
AppConstants.shared.logger.error("Unexpected orphan package removal output:\nStandard output: \(commandResult.standardOutput, privacy: .public)\nStandard error: \(commandResult.standardError, privacy: .public)")
throw OrphanUninstallationError.unexpectedCommandOutput
}
}

View File

@ -31,7 +31,7 @@ func purgeHomebrewCacheUtility() async throws -> [String]
{
let cachePurgeOutput: TerminalOutput = try await purgeBrewCache()
AppConstants.logger.debug("Cache purge output:\nStandard output: \(cachePurgeOutput.standardOutput, privacy: .auto)\nStandard error: \(cachePurgeOutput.standardError, privacy: .public)")
AppConstants.shared.logger.debug("Cache purge output:\nStandard output: \(cachePurgeOutput.standardOutput, privacy: .auto)\nStandard error: \(cachePurgeOutput.standardError, privacy: .public)")
var packagesHoldingBackCachePurgeTracker: [String] = .init()
@ -44,7 +44,7 @@ func purgeHomebrewCacheUtility() async throws -> [String]
for blockingPackageRaw in packagesHoldingBackCachePurgeInitialArray
{
AppConstants.logger.log("Blocking package: \(blockingPackageRaw, privacy: .public)")
AppConstants.shared.logger.log("Blocking package: \(blockingPackageRaw, privacy: .public)")
guard let packageHoldingBackCachePurgeName = try? blockingPackageRaw.regexMatch("(?<=Skipping ).*?(?=:)")
else
@ -55,14 +55,14 @@ func purgeHomebrewCacheUtility() async throws -> [String]
packagesHoldingBackCachePurgeTracker.append(packageHoldingBackCachePurgeName)
}
AppConstants.logger.info("These packages are holding back cache purge: \(packagesHoldingBackCachePurgeTracker, privacy: .public)")
AppConstants.shared.logger.info("These packages are holding back cache purge: \(packagesHoldingBackCachePurgeTracker, privacy: .public)")
}
return packagesHoldingBackCachePurgeTracker
}
catch let purgingCommandError
{
AppConstants.logger.error("Homebrew cache purging command failed: \(purgingCommandError, privacy: .public)")
AppConstants.shared.logger.error("Homebrew cache purging command failed: \(purgingCommandError, privacy: .public)")
throw HomebrewCachePurgeError.purgingCommandFailed
}
}

View File

@ -31,11 +31,11 @@ func uninstallOrphansUtility() async throws -> Int
{
let orphanUninstallationOutput: TerminalOutput = try await uninstallOrphanedPackages()
AppConstants.logger.debug("Orphan removal output:\nStandard output: \(orphanUninstallationOutput.standardOutput, privacy: .public)\nStandard error: \(orphanUninstallationOutput.standardError, privacy: .public)")
AppConstants.shared.logger.debug("Orphan removal output:\nStandard output: \(orphanUninstallationOutput.standardOutput, privacy: .public)\nStandard error: \(orphanUninstallationOutput.standardError, privacy: .public)")
if orphanUninstallationOutput.standardError.isEmpty && orphanUninstallationOutput.standardOutput.isEmpty
{
AppConstants.logger.info("No orphans found")
AppConstants.shared.logger.info("No orphans found")
return 0
}
else
@ -51,7 +51,7 @@ func uninstallOrphansUtility() async throws -> Int
}
catch let orphanUninstallatioError
{
AppConstants.logger.error("Orphan uninstallation error: \(orphanUninstallatioError, privacy: .public)")
AppConstants.shared.logger.error("Orphan uninstallation error: \(orphanUninstallatioError, privacy: .public)")
throw OrphanRemovalError.couldNotUninstallOrphans(output: orphanUninstallatioError.localizedDescription)
}
}

View File

@ -31,18 +31,18 @@ enum CorkLicenseRetrievalError: LocalizedError
func checkIfUserBoughtCork(for email: String) async throws -> Bool
{
let sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default
if AppConstants.proxySettings != nil
if AppConstants.shared.proxySettings != nil
{
sessionConfiguration.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: 1,
kCFNetworkProxiesHTTPPort: AppConstants.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.proxySettings!.host
kCFNetworkProxiesHTTPPort: AppConstants.shared.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.shared.proxySettings!.host
] as [AnyHashable: Any]
}
let session: URLSession = .init(configuration: sessionConfiguration)
var urlComponents: URLComponents? = .init(url: AppConstants.authorizationEndpointURL, resolvingAgainstBaseURL: false)
var urlComponents: URLComponents? = .init(url: AppConstants.shared.authorizationEndpointURL, resolvingAgainstBaseURL: false)
urlComponents?.queryItems = [URLQueryItem(name: "requestedEmail", value: email)]
guard let modifiedURL = urlComponents?.url
else
@ -54,7 +54,7 @@ func checkIfUserBoughtCork(for email: String) async throws -> Bool
request.httpMethod = "GET"
let authorizationComplex: String = "\(AppConstants.licensingAuthorization.username):\(AppConstants.licensingAuthorization.passphrase)"
let authorizationComplex: String = "\(AppConstants.shared.licensingAuthorization.username):\(AppConstants.shared.licensingAuthorization.passphrase)"
guard let authorizationComplexAsData: Data = authorizationComplex.data(using: .utf8, allowLossyConversion: false)
else

View File

@ -36,12 +36,12 @@ enum DataDownloadingError: LocalizedError
func downloadDataFromURL(_ url: URL, parameters: [URLQueryItem]? = nil) async throws -> Data
{
let sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default
if AppConstants.proxySettings != nil
if AppConstants.shared.proxySettings != nil
{
sessionConfiguration.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: 1,
kCFNetworkProxiesHTTPPort: AppConstants.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.proxySettings!.host
kCFNetworkProxiesHTTPPort: AppConstants.shared.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.shared.proxySettings!.host
] as [AnyHashable: Any]
}
@ -64,7 +64,7 @@ func downloadDataFromURL(_ url: URL, parameters: [URLQueryItem]? = nil) async th
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200
else
{
AppConstants.logger.error("Received invalid networking response: \(response)")
AppConstants.shared.logger.error("Received invalid networking response: \(response)")
let responseCast: HTTPURLResponse? = response as? HTTPURLResponse
throw DataDownloadingError.invalidResponseCode(responseCode: responseCast?.statusCode)

View File

@ -62,10 +62,10 @@ extension OutdatedPackageTracker
func getOutdatedPackages(brewData: BrewDataStorage) async throws
{
// First, we have to pull the newest updates
await shell(AppConstants.brewExecutablePath, ["update"])
await shell(AppConstants.shared.brewExecutablePath, ["update"])
// Then we can get the updating under way
let rawOutput: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["outdated", "--json=v2"])
let rawOutput: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["outdated", "--json=v2"])
print("Outdated package function oputput: \(rawOutput)")
@ -73,13 +73,13 @@ extension OutdatedPackageTracker
if rawOutput.standardError.contains("HOME must be set")
{
AppConstants.logger.error("Encountered HOME error")
AppConstants.shared.logger.error("Encountered HOME error")
throw OutdatedPackageRetrievalError.homeNotSet
}
if !rawOutput.standardError.isEmpty
{
AppConstants.logger.error("Standard error for package updating is not empty: \(rawOutput.standardError)")
AppConstants.shared.logger.error("Standard error for package updating is not empty: \(rawOutput.standardError)")
throw OutdatedPackageRetrievalError.otherError(rawOutput.standardError)
}
@ -97,7 +97,7 @@ extension OutdatedPackageTracker
guard let decodableOutput: Data = rawOutput.standardOutput.data(using: .utf8, allowLossyConversion: false)
else
{
AppConstants.logger.error("Could not convert raw output of decoding function to data for the decoder")
AppConstants.shared.logger.error("Could not convert raw output of decoding function to data for the decoder")
throw OutdatedPackageRetrievalError.otherError("There was a failure encoding data")
}
@ -112,7 +112,7 @@ extension OutdatedPackageTracker
}
catch let decodingError
{
AppConstants.logger.error("There was an error decoding the outdated package retrieval output: \(decodingError.localizedDescription, privacy: .public)\n\(decodingError, privacy: .public)")
AppConstants.shared.logger.error("There was an error decoding the outdated package retrieval output: \(decodingError.localizedDescription, privacy: .public)\n\(decodingError, privacy: .public)")
throw OutdatedPackageRetrievalError.couldNotDecodeCommandOutput(decodingError.localizedDescription)
}
}

View File

@ -11,7 +11,7 @@ import CorkShared
@MainActor
func loadUpPackages(whatToLoad: PackageType, appState: AppState) async -> Set<BrewPackage>
{
AppConstants.logger.info("Started \(whatToLoad == .formula ? "Formula" : "Cask", privacy: .public) loading task at \(Date(), privacy: .public)")
AppConstants.shared.logger.info("Started \(whatToLoad == .formula ? "Formula" : "Cask", privacy: .public) loading task at \(Date(), privacy: .public)")
var contentsOfFolder: Set<BrewPackage> = .init()
@ -20,9 +20,9 @@ func loadUpPackages(whatToLoad: PackageType, appState: AppState) async -> Set<Br
switch whatToLoad
{
case .formula:
contentsOfFolder = try await getContentsOfFolder(targetFolder: AppConstants.brewCellarPath)
contentsOfFolder = try await getContentsOfFolder(targetFolder: AppConstants.shared.brewCellarPath)
case .cask:
contentsOfFolder = try await getContentsOfFolder(targetFolder: AppConstants.brewCaskPath)
contentsOfFolder = try await getContentsOfFolder(targetFolder: AppConstants.shared.brewCaskPath)
}
}
catch let packageLoadingError as PackageLoadingError
@ -44,7 +44,7 @@ func loadUpPackages(whatToLoad: PackageType, appState: AppState) async -> Set<Br
print("Something got completely fucked up while loading packages")
}
AppConstants.logger.info("Finished \(whatToLoad == .formula ? "Formula" : "Cask", privacy: .public) loading task at \(Date(), privacy: .auto)")
AppConstants.shared.logger.info("Finished \(whatToLoad == .formula ? "Formula" : "Cask", privacy: .public) loading task at \(Date(), privacy: .auto)")
return contentsOfFolder
}

View File

@ -134,14 +134,14 @@ extension BrewPackage
{
for compatibleSystem in bottle.stable.files.keys
{
if compatibleSystem.contains(AppConstants.osVersionString.lookupName)
if compatibleSystem.contains(AppConstants.shared.osVersionString.lookupName)
{
AppConstants.logger.debug("Package \(name) is compatible")
AppConstants.shared.logger.debug("Package \(name) is compatible")
return true
}
}
AppConstants.logger.debug("Package \(name) is NOT compatible")
AppConstants.shared.logger.debug("Package \(name) is NOT compatible")
return false
}
}
@ -221,10 +221,10 @@ extension BrewPackage
switch type
{
case .formula:
rawOutput = await shell(AppConstants.brewExecutablePath, ["info", "--json=v2", name])
rawOutput = await shell(AppConstants.shared.brewExecutablePath, ["info", "--json=v2", name])
case .cask:
rawOutput = await shell(AppConstants.brewExecutablePath, ["info", "--json=v2", "--cask", name])
rawOutput = await shell(AppConstants.shared.brewExecutablePath, ["info", "--json=v2", "--cask", name])
}
// MARK: - Error checking
@ -232,33 +232,33 @@ extension BrewPackage
guard !rawOutput.standardOutput.isEmpty
else
{
AppConstants.logger.error("Did not get any terminal output from the package details loading function")
AppConstants.shared.logger.error("Did not get any terminal output from the package details loading function")
throw BrewPackageInfoLoadingError.didNotGetAnyTerminalOutput
}
if !rawOutput.standardError.isEmpty
{
AppConstants.logger.warning("Standard error of the package details loading function is not empty. Will investigate if the error can be ignored.")
AppConstants.shared.logger.warning("Standard error of the package details loading function is not empty. Will investigate if the error can be ignored.")
if rawOutput.standardError.range(of: "(T|t)reating.*as a (formula|cask)", options: .regularExpression) != nil
{
AppConstants.logger.notice("The error of package details loading function was not serious enough to throw an error. Ignoring.")
AppConstants.shared.logger.notice("The error of package details loading function was not serious enough to throw an error. Ignoring.")
}
else
{
AppConstants.logger.error("Error was serious enough to throw an error")
AppConstants.shared.logger.error("Error was serious enough to throw an error")
throw BrewPackageInfoLoadingError.standardErrorNotEmpty(presentError: rawOutput.standardError)
}
}
AppConstants.logger.debug("JSON output: \(rawOutput.standardOutput)")
AppConstants.shared.logger.debug("JSON output: \(rawOutput.standardOutput)")
guard let decodableData: Data = rawOutput.standardOutput.data(using: .utf8, allowLossyConversion: false)
else
{
AppConstants.logger.error("Could not convert string of package details loading function to data")
AppConstants.shared.logger.error("Could not convert string of package details loading function to data")
throw BrewPackageInfoLoadingError.couldNotConvertOutputToData
}
@ -275,7 +275,7 @@ extension BrewPackage
guard let formulaInfo: PackageCommandOutput.Formulae = rawDecodedPackageInfo.formulae?.first
else
{
AppConstants.logger.error("Could not retrieve the relevant formula during formula details loading")
AppConstants.shared.logger.error("Could not retrieve the relevant formula during formula details loading")
throw BrewPackageInfoLoadingError.couldNotRetrievePackageFromOutput
}
@ -297,7 +297,7 @@ extension BrewPackage
guard let caskInfo: PackageCommandOutput.Casks = rawDecodedPackageInfo.casks?.first
else
{
AppConstants.logger.error("Could not retrieve the relevant cask during formula details loading")
AppConstants.shared.logger.error("Could not retrieve the relevant cask during formula details loading")
throw BrewPackageInfoLoadingError.couldNotRetrievePackageFromOutput
}
@ -318,7 +318,7 @@ extension BrewPackage
}
catch let brewDetailsLoadingError
{
AppConstants.logger.error("Failed while decoding package info: \(brewDetailsLoadingError)")
AppConstants.shared.logger.error("Failed while decoding package info: \(brewDetailsLoadingError)")
throw BrewPackageInfoLoadingError.couldNotDecodeOutput(presentError: brewDetailsLoadingError.localizedDescription)
}

View File

@ -12,19 +12,19 @@ func pinAndUnpinPackage(package: BrewPackage, pinned: Bool) async
{
if pinned
{
let pinResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["pin", package.name])
let pinResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["pin", package.name])
if !pinResult.standardError.isEmpty
{
AppConstants.logger.error("Error pinning: \(pinResult.standardError, privacy: .public)")
AppConstants.shared.logger.error("Error pinning: \(pinResult.standardError, privacy: .public)")
}
}
else
{
let unpinResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["unpin", package.name])
let unpinResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["unpin", package.name])
if !unpinResult.standardError.isEmpty
{
AppConstants.logger.error("Error unpinning: \(unpinResult.standardError, privacy: .public)")
AppConstants.shared.logger.error("Error unpinning: \(unpinResult.standardError, privacy: .public)")
}
}
}

View File

@ -29,8 +29,8 @@ extension UUID
{
var filteredPackage: BrewPackage?
AppConstants.logger.log("Formula tracker: \(tracker.foundFormulae.count)")
AppConstants.logger.log("Cask tracker: \(tracker.foundCasks.count)")
AppConstants.shared.logger.log("Formula tracker: \(tracker.foundFormulae.count)")
AppConstants.shared.logger.log("Cask tracker: \(tracker.foundCasks.count)")
if !tracker.foundFormulae.isEmpty
{

View File

@ -15,19 +15,19 @@ func searchForPackage(packageName: String, packageType: PackageType) async throw
switch packageType
{
case .formula:
let foundFormulae: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["search", "--formulae", packageName])
let foundFormulae: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["search", "--formulae", packageName])
finalPackageArray = foundFormulae.standardOutput.components(separatedBy: "\n")
case .cask:
let foundCasks: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["search", "--casks", packageName])
let foundCasks: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["search", "--casks", packageName])
finalPackageArray = foundCasks.standardOutput.components(separatedBy: "\n")
}
finalPackageArray.removeLast()
AppConstants.logger.info("Search found these packages: \(finalPackageArray, privacy: .auto)")
AppConstants.shared.logger.info("Search found these packages: \(finalPackageArray, privacy: .auto)")
return finalPackageArray
}

View File

@ -62,13 +62,13 @@ extension ServicesTracker
return decoder
}()
let rawOutput: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["services", "list", "--json"])
let rawOutput: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["services", "list", "--json"])
// MARK: - Error checking
if !rawOutput.standardError.isEmpty
{
AppConstants.logger.error("Failed while loading up services: Standard Error not empty")
AppConstants.shared.logger.error("Failed while loading up services: Standard Error not empty")
if rawOutput.standardError.contains("brew update")
{
throw HomebrewServiceLoadingError.homebrewOutdated
@ -84,7 +84,7 @@ extension ServicesTracker
guard let decodableData: Data = rawOutput.standardOutput.data(using: .utf8, allowLossyConversion: false)
else
{
AppConstants.logger.error("Failed while converting services string to data")
AppConstants.shared.logger.error("Failed while converting services string to data")
throw HomebrewServiceLoadingError.otherError("There was a failure encoding Services data")
}
@ -107,7 +107,7 @@ extension ServicesTracker
}
catch let servicesParsingError
{
AppConstants.logger.error("Parsing of Homebrew services failed: \(servicesParsingError)")
AppConstants.shared.logger.error("Parsing of Homebrew services failed: \(servicesParsingError)")
throw HomebrewServiceLoadingError.servicesParsingFailed
}

View File

@ -12,14 +12,14 @@ extension ServicesTracker
{
func killService(_ serviceToKill: HomebrewService, servicesState: ServicesState, serviceModificationProgress: ServiceModificationProgress) async
{
for await output in shell(AppConstants.brewExecutablePath, ["services", "kill", serviceToKill.name])
for await output in shell(AppConstants.shared.brewExecutablePath, ["services", "kill", serviceToKill.name])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.debug("Service killing output: \(outputLine)")
AppConstants.shared.logger.debug("Service killing output: \(outputLine)")
case .standardError(let errorLine):
AppConstants.logger.error("Service killing error: \(errorLine)")
AppConstants.shared.logger.error("Service killing error: \(errorLine)")
}
}
@ -31,7 +31,7 @@ extension ServicesTracker
}
catch let servicesSynchronizationError
{
AppConstants.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
AppConstants.shared.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
servicesState.showError(.couldNotSynchronizeServices(errorThrown: servicesSynchronizationError.localizedDescription))
}

View File

@ -12,18 +12,18 @@ extension ServicesTracker
{
func startService(_ serviceToStart: HomebrewService, servicesState: ServicesState, serviceModificationProgress: ServiceModificationProgress) async
{
for await output in shell(AppConstants.brewExecutablePath, ["services", "start", serviceToStart.name])
for await output in shell(AppConstants.shared.brewExecutablePath, ["services", "start", serviceToStart.name])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.debug("Services startup output line: \(outputLine)")
AppConstants.shared.logger.debug("Services startup output line: \(outputLine)")
switch outputLine
{
case _ where outputLine.contains("Successfully started"):
AppConstants.logger.debug("Started \(serviceToStart.name) with no problems")
AppConstants.shared.logger.debug("Started \(serviceToStart.name) with no problems")
default:
AppConstants.logger.debug("Service started, but there were some problems")
AppConstants.shared.logger.debug("Service started, but there were some problems")
}
serviceModificationProgress.progress += 1
@ -32,12 +32,12 @@ extension ServicesTracker
switch errorLine
{
case _ where errorLine.contains("must be run as root"):
AppConstants.logger.debug("Service must be run as root")
AppConstants.shared.logger.debug("Service must be run as root")
servicesState.showError(.couldNotStartService(offendingService: serviceToStart.name, errorThrown: String(localized: "services.error.must-be-run-as-root")))
default:
AppConstants.logger.warning("Could not start service: \(errorLine)")
AppConstants.shared.logger.warning("Could not start service: \(errorLine)")
servicesState.showError(.couldNotStartService(offendingService: serviceToStart.name, errorThrown: errorLine))
}
@ -52,7 +52,7 @@ extension ServicesTracker
}
catch let servicesSynchronizationError
{
AppConstants.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
AppConstants.shared.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
servicesState.showError(.couldNotSynchronizeServices(errorThrown: servicesSynchronizationError.localizedDescription))
}

View File

@ -26,29 +26,29 @@ extension ServicesTracker
{
func stopService(_ serviceToStop: HomebrewService, servicesState: ServicesState, serviceModificationProgress: ServiceModificationProgress) async
{
for await output in shell(AppConstants.brewExecutablePath, ["services", "stop", serviceToStop.name])
for await output in shell(AppConstants.shared.brewExecutablePath, ["services", "stop", serviceToStop.name])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.debug("Service stopping output: \(outputLine)")
AppConstants.shared.logger.debug("Service stopping output: \(outputLine)")
switch outputLine
{
case _ where outputLine.contains("Stopping"):
AppConstants.logger.debug("Stopping \(serviceToStop.name)")
AppConstants.shared.logger.debug("Stopping \(serviceToStop.name)")
case _ where outputLine.contains("Successfully stopped"):
AppConstants.logger.debug("Stopped \(serviceToStop.name)")
AppConstants.shared.logger.debug("Stopped \(serviceToStop.name)")
default:
AppConstants.logger.debug("Unknown step in stopping \(serviceToStop.name)")
AppConstants.shared.logger.debug("Unknown step in stopping \(serviceToStop.name)")
}
serviceModificationProgress.progress += 1
case .standardError(let errorLine):
AppConstants.logger.error("Service stopping error: \(errorLine)")
AppConstants.shared.logger.error("Service stopping error: \(errorLine)")
servicesState.showError(.couldNotStopService(offendingService: serviceToStop.name, errorThrown: errorLine))
}
@ -62,7 +62,7 @@ extension ServicesTracker
}
catch let servicesSynchronizationError
{
AppConstants.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
AppConstants.shared.logger.error("Could not synchronize services: \(servicesSynchronizationError.localizedDescription)")
servicesState.showError(.couldNotSynchronizeServices(errorThrown: servicesSynchronizationError.localizedDescription))
}

View File

@ -13,9 +13,9 @@ extension HomebrewService
@MainActor
func loadDetails() async throws -> ServiceDetails?
{
AppConstants.logger.debug("Will try to load up service details for service \(name)")
AppConstants.shared.logger.debug("Will try to load up service details for service \(name)")
let rawOutput: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["services", "info", name, "--json"])
let rawOutput: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["services", "info", name, "--json"])
let decoder: JSONDecoder = {
let decoder: JSONDecoder = .init()
@ -28,7 +28,7 @@ extension HomebrewService
if !rawOutput.standardError.isEmpty
{
AppConstants.logger.error("Failed while loading up service details: Standard Error not empty")
AppConstants.shared.logger.error("Failed while loading up service details: Standard Error not empty")
throw HomebrewServiceLoadingError.standardErrorNotEmpty(standardError: rawOutput.standardError)
}
@ -50,7 +50,7 @@ extension HomebrewService
}
catch let parsingError
{
AppConstants.logger.error("Parsing of service details of service \(self.name) failed: \(parsingError)")
AppConstants.shared.logger.error("Parsing of service details of service \(self.name) failed: \(parsingError)")
throw HomebrewServiceLoadingError.servicesParsingFailed
}

View File

@ -18,7 +18,7 @@ struct SearchResults
func getListOfFoundPackages(searchWord: String) async -> String
{
var parsedResponse: String?
parsedResponse = await shell(AppConstants.brewExecutablePath, ["search", searchWord]).standardOutput
parsedResponse = await shell(AppConstants.shared.brewExecutablePath, ["search", searchWord]).standardOutput
return parsedResponse!
}

View File

@ -36,7 +36,7 @@ func shell(
}
/// # Usage:
/// for await output in shell(AppConstants.brewExecutablePath, ["install", package.name])
/// for await output in shell(AppConstants.shared.brewExecutablePath, ["install", package.name])
/// {
/// switch output
/// {
@ -82,9 +82,9 @@ func shell(
// MARK: - Set up proxy if it's enabled
if let proxySettings = AppConstants.proxySettings
if let proxySettings = AppConstants.shared.proxySettings
{
AppConstants.logger.info("Proxy is enabled")
AppConstants.shared.logger.info("Proxy is enabled")
finalEnvironment["ALL_PROXY"] = "\(proxySettings.host):\(proxySettings.port)"
}
@ -95,13 +95,13 @@ func shell(
finalEnvironment["HOMEBREW_NO_INSTALL_CLEANUP"] = "TRUE"
}
AppConstants.logger.debug("Final environment: \(finalEnvironment)")
AppConstants.shared.logger.debug("Final environment: \(finalEnvironment)")
// MARK: - Set working directory if provided
if let workingDirectory
{
AppConstants.logger.info("Working directory configured: \(workingDirectory)")
AppConstants.shared.logger.info("Working directory configured: \(workingDirectory)")
task.currentDirectoryURL = workingDirectory
}
@ -125,7 +125,7 @@ func shell(
}
catch
{
AppConstants.logger.error("\(String(describing: error))")
AppConstants.shared.logger.error("\(String(describing: error))")
}
return AsyncStream

View File

@ -14,12 +14,12 @@ func submitSystemVersion() async throws
let corkVersion: String = await String(NSApplication.appVersion!)
let sessionConfiguration: URLSessionConfiguration = .default
if AppConstants.proxySettings != nil
if AppConstants.shared.proxySettings != nil
{
sessionConfiguration.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: 1,
kCFNetworkProxiesHTTPPort: AppConstants.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.proxySettings!.host
kCFNetworkProxiesHTTPPort: AppConstants.shared.proxySettings!.port,
kCFNetworkProxiesHTTPProxy: AppConstants.shared.proxySettings!.host
] as [AnyHashable: Any]
}
@ -30,7 +30,7 @@ func submitSystemVersion() async throws
isSelfCompiled = true
#endif
var urlComponents: URLComponents? = .init(url: AppConstants.osSubmissionEndpointURL, resolvingAgainstBaseURL: false)
var urlComponents: URLComponents? = .init(url: AppConstants.shared.osSubmissionEndpointURL, resolvingAgainstBaseURL: false)
urlComponents?.queryItems = [
URLQueryItem(name: "systemVersion", value: String(ProcessInfo.processInfo.operatingSystemVersion.majorVersion)),
URLQueryItem(name: "corkVersion", value: corkVersion),
@ -46,7 +46,7 @@ func submitSystemVersion() async throws
request.httpMethod = "GET"
let authorizationComplex: String = "\(AppConstants.licensingAuthorization.username):\(AppConstants.licensingAuthorization.passphrase)"
let authorizationComplex: String = "\(AppConstants.shared.licensingAuthorization.username):\(AppConstants.shared.licensingAuthorization.passphrase)"
guard let authorizationComplexAsData: Data = authorizationComplex.data(using: .utf8, allowLossyConversion: false)
else
@ -61,7 +61,7 @@ func submitSystemVersion() async throws
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200
{
#if DEBUG
AppConstants.logger.debug("Sucessfully submitted system version")
AppConstants.shared.logger.debug("Sucessfully submitted system version")
#endif
UserDefaults.standard.setValue(corkVersion, forKey: "lastSubmittedCorkVersion")

View File

@ -13,7 +13,7 @@ func applyTagsToPackageTrackingArray(appState: AppState, brewData: BrewDataStora
{
for taggedName in appState.taggedPackageNames
{
AppConstants.logger.log("Will attempt to place package name \(taggedName, privacy: .public)")
AppConstants.shared.logger.log("Will attempt to place package name \(taggedName, privacy: .public)")
brewData.installedFormulae = Set(brewData.installedFormulae.map
{ formula in
var copyFormula: BrewPackage = formula

View File

@ -45,7 +45,7 @@ func changePackageTagStatus(package: BrewPackage, brewData: BrewDataStorage, app
appState.taggedPackageNames.insert(package.name)
}
AppConstants.logger.debug("Tagged package with ID \(package.id, privacy: .public): \(package.name, privacy: .public)")
AppConstants.shared.logger.debug("Tagged package with ID \(package.id, privacy: .public): \(package.name, privacy: .public)")
AppConstants.logger.debug("Tagged packages: \(appState.taggedPackageNames, privacy: .public)")
AppConstants.shared.logger.debug("Tagged packages: \(appState.taggedPackageNames, privacy: .public)")
}

View File

@ -14,7 +14,7 @@ func loadTaggedIDsFromDisk() throws -> Set<String>
do
{
let rawPackageNamesFromFile: String = try String(contentsOf: AppConstants.metadataFilePath, encoding: .utf8)
let rawPackageNamesFromFile: String = try String(contentsOf: AppConstants.shared.metadataFilePath, encoding: .utf8)
let packageNamesAsArray: [String] = rawPackageNamesFromFile.components(separatedBy: ":")
for packageNameAsString in packageNamesAsArray
@ -24,10 +24,10 @@ func loadTaggedIDsFromDisk() throws -> Set<String>
}
catch let dataReadingError as NSError
{
AppConstants.logger.error("Failed while reading data from disk: \(dataReadingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while reading data from disk: \(dataReadingError, privacy: .public)")
}
AppConstants.logger.debug("Loaded name set: \(nameSet, privacy: .public)")
AppConstants.shared.logger.debug("Loaded name set: \(nameSet, privacy: .public)")
return nameSet
}

View File

@ -12,14 +12,14 @@ import CorkShared
func saveTaggedIDsToDisk(appState: AppState) throws
{
let namesAsString: String = appState.taggedPackageNames.compactMap { $0 }.joined(separator: ":")
AppConstants.logger.debug("Names as string: \(namesAsString, privacy: .public)")
AppConstants.shared.logger.debug("Names as string: \(namesAsString, privacy: .public)")
do
{
try namesAsString.write(to: AppConstants.metadataFilePath, atomically: true, encoding: .utf8)
try namesAsString.write(to: AppConstants.shared.metadataFilePath, atomically: true, encoding: .utf8)
}
catch let writingError as NSError
{
AppConstants.logger.error("Error while writing to file: \(writingError, privacy: .public)")
AppConstants.shared.logger.error("Error while writing to file: \(writingError, privacy: .public)")
}
}

View File

@ -14,14 +14,14 @@ func addTap(name: String, forcedRepoAddress: String? = nil) async -> String
if let forcedRepoAddress
{
tapResult = await shell(AppConstants.brewExecutablePath, ["tap", name, forcedRepoAddress]).standardError
tapResult = await shell(AppConstants.shared.brewExecutablePath, ["tap", name, forcedRepoAddress]).standardError
}
else
{
tapResult = await shell(AppConstants.brewExecutablePath, ["tap", name]).standardError
tapResult = await shell(AppConstants.shared.brewExecutablePath, ["tap", name]).standardError
}
AppConstants.logger.debug("Tapping result: \(tapResult, privacy: .public)")
AppConstants.shared.logger.debug("Tapping result: \(tapResult, privacy: .public)")
return tapResult
}

View File

@ -22,7 +22,7 @@ func parseTapInfo(from rawJSON: String) async throws -> TapInfo?
guard let jsonAsData: Data = rawJSON.data(using: .utf8, allowLossyConversion: false)
else
{
AppConstants.logger.error("Could not convert tap JSON string into data")
AppConstants.shared.logger.error("Could not convert tap JSON string into data")
throw JSONParsingError.couldNotConvertStringToData(failureReason: nil)
}
@ -30,7 +30,7 @@ func parseTapInfo(from rawJSON: String) async throws -> TapInfo?
}
catch let decodingError
{
AppConstants.logger.error("Failed while decoding tap info: \(decodingError.localizedDescription, privacy: .public)\n-\(decodingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while decoding tap info: \(decodingError.localizedDescription, privacy: .public)\n-\(decodingError, privacy: .public)")
throw JSONParsingError.couldNotDecode(failureReason: decodingError.localizedDescription)
}

View File

@ -45,8 +45,8 @@ func removeTap(name: String, availableTaps: AvailableTaps, appState: AppState, s
appState.isShowingUninstallationProgressView = true
}
let untapResult: String = await shell(AppConstants.brewExecutablePath, ["untap", name]).standardError
AppConstants.logger.debug("Untapping result: \(untapResult)")
let untapResult: String = await shell(AppConstants.shared.brewExecutablePath, ["untap", name]).standardError
AppConstants.shared.logger.debug("Untapping result: \(untapResult)")
defer
{
@ -55,7 +55,7 @@ func removeTap(name: String, availableTaps: AvailableTaps, appState: AppState, s
if untapResult.contains("Untapped")
{
AppConstants.logger.info("Untapping was successful")
AppConstants.shared.logger.info("Untapping was successful")
DispatchQueue.main.async
{
withAnimation
@ -75,7 +75,7 @@ func removeTap(name: String, availableTaps: AvailableTaps, appState: AppState, s
}
else
{
AppConstants.logger.warning("Untapping failed")
AppConstants.shared.logger.warning("Untapping failed")
if untapResult.contains("because it contains the following installed formulae or casks")
{
@ -88,7 +88,7 @@ func removeTap(name: String, availableTaps: AvailableTaps, appState: AppState, s
}
else
{
AppConstants.logger.warning("Could not get index for that tap. Will loop over all of them")
AppConstants.shared.logger.warning("Could not get index for that tap. Will loop over all of them")
for index in availableTaps.addedTaps.indices
{

View File

@ -14,12 +14,12 @@ func refreshPackages(_ updateProgressTracker: UpdateProgressTracker, outdatedPac
{
let showRealTimeTerminalOutputs: Bool = UserDefaults.standard.bool(forKey: "showRealTimeTerminalOutputOfOperations")
for await output in shell(AppConstants.brewExecutablePath, ["update"])
for await output in shell(AppConstants.shared.brewExecutablePath, ["update"])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.log("Update function output: \(outputLine, privacy: .public)")
AppConstants.shared.logger.log("Update function output: \(outputLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
@ -32,7 +32,7 @@ func refreshPackages(_ updateProgressTracker: UpdateProgressTracker, outdatedPac
{
if outputLine.starts(with: "Already up-to-date")
{
AppConstants.logger.info("Inside update function: No updates available")
AppConstants.shared.logger.info("Inside update function: No updates available")
return .noUpdatesAvailable
}
}
@ -47,7 +47,7 @@ func refreshPackages(_ updateProgressTracker: UpdateProgressTracker, outdatedPac
if errorLine.starts(with: "Another active Homebrew update process is already in progress") || errorLine == "Error: " || errorLine.contains("Updated [0-9]+ tap") || errorLine == "Already up-to-date" || errorLine.contains("No checksum defined")
{
updateProgressTracker.updateProgress = updateProgressTracker.updateProgress + 0.1
AppConstants.logger.log("Ignorable update function error: \(errorLine, privacy: .public)")
AppConstants.shared.logger.log("Ignorable update function error: \(errorLine, privacy: .public)")
return .noUpdatesAvailable
}
@ -55,7 +55,7 @@ func refreshPackages(_ updateProgressTracker: UpdateProgressTracker, outdatedPac
{
if !errorLine.contains("==> Updating Homebrew...")
{
AppConstants.logger.warning("Update function error: \(errorLine, privacy: .public)")
AppConstants.shared.logger.warning("Update function error: \(errorLine, privacy: .public)")
updateProgressTracker.errors.append("Update error: \(errorLine)")
}
}

View File

@ -14,12 +14,12 @@ func updatePackages(updateProgressTracker: UpdateProgressTracker, detailStage: U
{
let showRealTimeTerminalOutputs: Bool = UserDefaults.standard.bool(forKey: "showRealTimeTerminalOutputOfOperations")
for await output in shell(AppConstants.brewExecutablePath, ["upgrade"])
for await output in shell(AppConstants.shared.brewExecutablePath, ["upgrade"])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.log("Upgrade function output: \(outputLine, privacy: .public)")
AppConstants.shared.logger.log("Upgrade function output: \(outputLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
@ -51,7 +51,7 @@ func updatePackages(updateProgressTracker: UpdateProgressTracker, detailStage: U
detailStage.currentStage = .cleanup
}
AppConstants.logger.info("Current updating stage: \(detailStage.currentStage.description, privacy: .public)")
AppConstants.shared.logger.info("Current updating stage: \(detailStage.currentStage.description, privacy: .public)")
updateProgressTracker.updateProgress = updateProgressTracker.updateProgress + 0.1
@ -66,11 +66,11 @@ func updatePackages(updateProgressTracker: UpdateProgressTracker, detailStage: U
{
updateProgressTracker.updateProgress = updateProgressTracker.updateProgress + 0.1
AppConstants.logger.log("Ignorable upgrade function error: \(errorLine, privacy: .public)")
AppConstants.shared.logger.log("Ignorable upgrade function error: \(errorLine, privacy: .public)")
}
else
{
AppConstants.logger.warning("Upgrade function error: \(errorLine, privacy: .public)")
AppConstants.shared.logger.warning("Upgrade function error: \(errorLine, privacy: .public)")
updateProgressTracker.errors.append("Upgrade error: \(errorLine)")
}
}

View File

@ -26,13 +26,13 @@ class InstallationProgressTracker: ObservableObject
{
let package: BrewPackage = packageBeingInstalled.package
AppConstants.logger.debug("Installing package \(package.name, privacy: .auto)")
AppConstants.shared.logger.debug("Installing package \(package.name, privacy: .auto)")
var installationResult: TerminalOutput = .init(standardOutput: "", standardError: "")
if package.type == .formula
{
AppConstants.logger.info("Package \(package.name, privacy: .public) is Formula")
AppConstants.shared.logger.info("Package \(package.name, privacy: .public) is Formula")
let output: String = try await installFormula(using: brewData).joined(separator: "")
@ -44,7 +44,7 @@ class InstallationProgressTracker: ObservableObject
}
else
{
AppConstants.logger.info("Package is Cask")
AppConstants.shared.logger.info("Package is Cask")
try await installCask(using: brewData)
}
@ -62,22 +62,22 @@ class InstallationProgressTracker: ObservableObject
var hasAlreadyMatchedLineAboutInstallingPackageItself: Bool = false
var installOutput: [String] = .init()
AppConstants.logger.info("Package \(package.name, privacy: .public) is Formula")
AppConstants.shared.logger.info("Package \(package.name, privacy: .public) is Formula")
for await output in shell(AppConstants.brewExecutablePath, ["install", package.name])
for await output in shell(AppConstants.shared.brewExecutablePath, ["install", package.name])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.debug("Package instrall line out: \(outputLine, privacy: .public)")
AppConstants.shared.logger.debug("Package instrall line out: \(outputLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
packageBeingInstalled.realTimeTerminalOutput.append(RealTimeTerminalLine(line: outputLine))
}
AppConstants.logger.info("Does the line contain an element from the array? \(outputLine.containsElementFromArray(packageDependencies), privacy: .public)")
AppConstants.shared.logger.info("Does the line contain an element from the array? \(outputLine.containsElementFromArray(packageDependencies), privacy: .public)")
if outputLine.contains("Fetching dependencies")
{
@ -85,13 +85,13 @@ class InstallationProgressTracker: ObservableObject
var matchedDependencies: String = try outputLine.regexMatch("(?<=\(package.name): ).*?(.*)")
matchedDependencies = matchedDependencies.replacingOccurrences(of: " and", with: ",") // The last dependency is different, because it's preceded by "and" instead of "," so let's replace that "and" with "," so we can split it nicely
AppConstants.logger.debug("Matched Dependencies: \(matchedDependencies, privacy: .auto)")
AppConstants.shared.logger.debug("Matched Dependencies: \(matchedDependencies, privacy: .auto)")
packageDependencies = matchedDependencies.components(separatedBy: ", ") // Make the dependency list into an array
AppConstants.logger.debug("Package Dependencies: \(packageDependencies)")
AppConstants.shared.logger.debug("Package Dependencies: \(packageDependencies)")
AppConstants.logger.debug("Will fetch \(packageDependencies.count) dependencies!")
AppConstants.shared.logger.debug("Will fetch \(packageDependencies.count) dependencies!")
numberOfPackageDependencies = packageDependencies.count // Assign the number of dependencies to the tracker for the user to see
@ -100,12 +100,12 @@ class InstallationProgressTracker: ObservableObject
else if outputLine.contains("Installing dependencies") || outputLine.contains("Installing \(package.name) dependency")
{
AppConstants.logger.info("Will install dependencies!")
AppConstants.shared.logger.info("Will install dependencies!")
packageBeingInstalled.installationStage = .installingDependencies
// Increment by 1 for each package that finished installing
numberInLineOfPackageCurrentlyBeingInstalled = numberInLineOfPackageCurrentlyBeingInstalled + 1
AppConstants.logger.info("Installing dependency \(self.numberInLineOfPackageCurrentlyBeingInstalled) of \(packageDependencies.count)")
AppConstants.shared.logger.info("Installing dependency \(self.numberInLineOfPackageCurrentlyBeingInstalled) of \(packageDependencies.count)")
// TODO: Add a math formula for advancing the stepper
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + Double(Double(10) / (Double(3) * Double(numberOfPackageDependencies)))
@ -113,12 +113,12 @@ class InstallationProgressTracker: ObservableObject
else if outputLine.contains("Already downloaded") || (outputLine.contains("Fetching") && outputLine.containsElementFromArray(packageDependencies))
{
AppConstants.logger.info("Will fetch dependencies!")
AppConstants.shared.logger.info("Will fetch dependencies!")
packageBeingInstalled.installationStage = .fetchingDependencies
numberInLineOfPackageCurrentlyBeingFetched = numberInLineOfPackageCurrentlyBeingFetched + 1
AppConstants.logger.info("Fetching dependency \(self.numberInLineOfPackageCurrentlyBeingFetched) of \(packageDependencies.count)")
AppConstants.shared.logger.info("Fetching dependency \(self.numberInLineOfPackageCurrentlyBeingFetched) of \(packageDependencies.count)")
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + Double(Double(10) / (Double(3) * (Double(numberOfPackageDependencies) * Double(5))))
}
@ -127,17 +127,17 @@ class InstallationProgressTracker: ObservableObject
{
if hasAlreadyMatchedLineAboutInstallingPackageItself
{ /// Only the second line about the package being installed is valid
AppConstants.logger.info("Will install the package itself!")
AppConstants.shared.logger.info("Will install the package itself!")
packageBeingInstalled.installationStage = .installingPackage
// TODO: Add a math formula for advancing the stepper
packageBeingInstalled.packageInstallationProgress = Double(packageBeingInstalled.packageInstallationProgress) + Double((Double(10) - Double(packageBeingInstalled.packageInstallationProgress)) / Double(2))
AppConstants.logger.info("Stepper value: \(Double(Double(10) / (Double(3) * Double(self.numberOfPackageDependencies))))")
AppConstants.shared.logger.info("Stepper value: \(Double(Double(10) / (Double(3) * Double(self.numberOfPackageDependencies))))")
}
else
{ /// When it appears for the first time, ignore it
AppConstants.logger.info("Matched the dud line about the package itself being installed!")
AppConstants.shared.logger.info("Matched the dud line about the package itself being installed!")
hasAlreadyMatchedLineAboutInstallingPackageItself = true
packageBeingInstalled.packageInstallationProgress = Double(packageBeingInstalled.packageInstallationProgress) + Double((Double(10) - Double(packageBeingInstalled.packageInstallationProgress)) / Double(2))
}
@ -145,10 +145,10 @@ class InstallationProgressTracker: ObservableObject
installOutput.append(outputLine)
AppConstants.logger.debug("Current installation stage: \(self.packageBeingInstalled.installationStage.description, privacy: .public)")
AppConstants.shared.logger.debug("Current installation stage: \(self.packageBeingInstalled.installationStage.description, privacy: .public)")
case .standardError(let errorLine):
AppConstants.logger.error("Errored out: \(errorLine, privacy: .public)")
AppConstants.shared.logger.error("Errored out: \(errorLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
@ -157,7 +157,7 @@ class InstallationProgressTracker: ObservableObject
if errorLine.contains("a password is required")
{
AppConstants.logger.warning("Install requires sudo")
AppConstants.shared.logger.warning("Install requires sudo")
packageBeingInstalled.installationStage = .requiresSudoPassword
}
@ -176,15 +176,15 @@ class InstallationProgressTracker: ObservableObject
{
let package: BrewPackage = packageBeingInstalled.package
AppConstants.logger.info("Package is Cask")
AppConstants.logger.debug("Installing package \(package.name, privacy: .public)")
AppConstants.shared.logger.info("Package is Cask")
AppConstants.shared.logger.debug("Installing package \(package.name, privacy: .public)")
for await output in shell(AppConstants.brewExecutablePath, ["install", "--no-quarantine", package.name])
for await output in shell(AppConstants.shared.brewExecutablePath, ["install", "--no-quarantine", package.name])
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.info("Output line: \(outputLine, privacy: .public)")
AppConstants.shared.logger.info("Output line: \(outputLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
@ -193,7 +193,7 @@ class InstallationProgressTracker: ObservableObject
if outputLine.contains("Downloading")
{
AppConstants.logger.info("Will download Cask")
AppConstants.shared.logger.info("Will download Cask")
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + 2
@ -201,7 +201,7 @@ class InstallationProgressTracker: ObservableObject
}
else if outputLine.contains("Installing Cask")
{
AppConstants.logger.info("Will install Cask")
AppConstants.shared.logger.info("Will install Cask")
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + 2
@ -209,7 +209,7 @@ class InstallationProgressTracker: ObservableObject
}
else if outputLine.contains("Moving App")
{
AppConstants.logger.info("Moving App")
AppConstants.shared.logger.info("Moving App")
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + 2
@ -217,7 +217,7 @@ class InstallationProgressTracker: ObservableObject
}
else if outputLine.contains("Linking binary")
{
AppConstants.logger.info("Linking Binary")
AppConstants.shared.logger.info("Linking Binary")
packageBeingInstalled.packageInstallationProgress = packageBeingInstalled.packageInstallationProgress + 2
@ -225,7 +225,7 @@ class InstallationProgressTracker: ObservableObject
}
else if outputLine.contains("Purging files")
{
AppConstants.logger.info("Purging old version of cask \(package.name)")
AppConstants.shared.logger.info("Purging old version of cask \(package.name)")
packageBeingInstalled.installationStage = .installingCask
@ -233,7 +233,7 @@ class InstallationProgressTracker: ObservableObject
}
else if outputLine.contains("was successfully installed")
{
AppConstants.logger.info("Finished installing app")
AppConstants.shared.logger.info("Finished installing app")
packageBeingInstalled.installationStage = .finished
@ -241,7 +241,7 @@ class InstallationProgressTracker: ObservableObject
}
case .standardError(let errorLine):
AppConstants.logger.error("Line had error: \(errorLine, privacy: .public)")
AppConstants.shared.logger.error("Line had error: \(errorLine, privacy: .public)")
if showRealTimeTerminalOutputs
{
@ -250,19 +250,19 @@ class InstallationProgressTracker: ObservableObject
if errorLine.contains("a password is required")
{
AppConstants.logger.warning("Install requires sudo")
AppConstants.shared.logger.warning("Install requires sudo")
packageBeingInstalled.installationStage = .requiresSudoPassword
}
else if errorLine.contains("there is already an App at")
{
AppConstants.logger.warning("The app already exists")
AppConstants.shared.logger.warning("The app already exists")
packageBeingInstalled.installationStage = .binaryAlreadyExists
}
else if errorLine.contains(/depends on hardware architecture being.+but you are running/)
{
AppConstants.logger.warning("Package is wrong architecture")
AppConstants.shared.logger.warning("Package is wrong architecture")
packageBeingInstalled.installationStage = .wrongArchitecture
}

View File

@ -67,12 +67,12 @@ class BrewPackageDetails: ObservableObject
func loadDependents() async
{
AppConstants.logger.debug("Will load dependents for \(self.name)")
let packageDependentsRaw: String = await shell(AppConstants.brewExecutablePath, ["uses", "--installed", name]).standardOutput
AppConstants.shared.logger.debug("Will load dependents for \(self.name)")
let packageDependentsRaw: String = await shell(AppConstants.shared.brewExecutablePath, ["uses", "--installed", name]).standardOutput
let finalDependents: [String] = packageDependentsRaw.components(separatedBy: "\n").dropLast()
AppConstants.logger.debug("Dependents loaded: \(finalDependents)")
AppConstants.shared.logger.debug("Dependents loaded: \(finalDependents)")
dependents = finalDependents
}
@ -81,20 +81,20 @@ class BrewPackageDetails: ObservableObject
{
if pinned
{
let pinResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["unpin", name])
let pinResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["unpin", name])
if !pinResult.standardError.isEmpty
{
AppConstants.logger.error("Error pinning: \(pinResult.standardError, privacy: .public)")
AppConstants.shared.logger.error("Error pinning: \(pinResult.standardError, privacy: .public)")
throw PinningUnpinningError.failedWhileChangingPinnedStatus
}
}
else
{
let unpinResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["pin", name])
let unpinResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["pin", name])
if !unpinResult.standardError.isEmpty
{
AppConstants.logger.error("Error unpinning: \(unpinResult.standardError, privacy: .public)")
AppConstants.shared.logger.error("Error unpinning: \(unpinResult.standardError, privacy: .public)")
throw PinningUnpinningError.failedWhileChangingPinnedStatus
}
}

View File

@ -103,11 +103,11 @@ struct BrewPackage: Identifiable, Equatable, Hashable, Codable
{
if type == .formula
{
return AppConstants.brewCellarPath
return AppConstants.shared.brewCellarPath
}
else
{
return AppConstants.brewCaskPath
return AppConstants.shared.brewCaskPath
}
}
@ -130,7 +130,7 @@ struct BrewPackage: Identifiable, Equatable, Hashable, Codable
}
catch let finderRevealError
{
AppConstants.logger.error("Failed while revealing package: \(finderRevealError.localizedDescription)")
AppConstants.shared.logger.error("Failed while revealing package: \(finderRevealError.localizedDescription)")
/// Play the error sound
NSSound(named: "ping")?.play()
}

View File

@ -86,7 +86,7 @@ struct AddFormulaView: View
}
.onAppear
{
appState.cachedDownloadsFolderSize = AppConstants.brewCachedDownloadsPath.directorySize
appState.cachedDownloadsFolderSize = AppConstants.shared.brewCachedDownloadsPath.directorySize
if notifyAboutPackageInstallationResults
{

View File

@ -55,7 +55,7 @@ struct SearchResultRow: View, Sendable
HStack(alignment: .center, spacing: 4)
{
Image(systemName: "exclamationmark.circle")
Text("add-package.result.not-optimized-for-\(AppConstants.osVersionString.fullName)")
Text("add-package.result.not-optimized-for-\(AppConstants.shared.osVersionString.fullName)")
}
.font(.subheadline)
.foregroundColor(.red)
@ -99,7 +99,7 @@ struct SearchResultRow: View, Sendable
{
if showDescriptionsInSearchResults
{
AppConstants.logger.info("\(searchedForPackage.name, privacy: .auto) came into view")
AppConstants.shared.logger.info("\(searchedForPackage.name, privacy: .auto) came into view")
if description == nil
{
@ -108,7 +108,7 @@ struct SearchResultRow: View, Sendable
isLoadingDescription = false
}
AppConstants.logger.info("\(searchedForPackage.name, privacy: .auto) does not have its description loaded")
AppConstants.shared.logger.info("\(searchedForPackage.name, privacy: .auto) does not have its description loaded")
do
{
@ -124,7 +124,7 @@ struct SearchResultRow: View, Sendable
}
catch let descriptionParsingError
{ // This happens when a package doesn' have any description at all, hence why we don't display an error
AppConstants.logger.error("Failed while parsing searched-for package info: \(descriptionParsingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.error("Failed while parsing searched-for package info: \(descriptionParsingError.localizedDescription, privacy: .public)")
descriptionParsingFailed = true
}
@ -132,7 +132,7 @@ struct SearchResultRow: View, Sendable
}
else
{
AppConstants.logger.info("\(searchedForPackage.name, privacy: .auto) already has its description loaded")
AppConstants.shared.logger.info("\(searchedForPackage.name, privacy: .auto) already has its description loaded")
}
}
}

View File

@ -85,7 +85,7 @@ struct InstallationInitialView: View
{
guard let packageToPreview: BrewPackage = getTopPackageFromTracker() else
{
AppConstants.logger.error("Could not retrieve top package to preview")
AppConstants.shared.logger.error("Could not retrieve top package to preview")
return
}
@ -98,14 +98,14 @@ struct InstallationInitialView: View
{
guard let packageToInstall: BrewPackage = getTopPackageFromTracker() else
{
AppConstants.logger.error("Could not retrieve top package to install")
AppConstants.shared.logger.error("Could not retrieve top package to install")
return
}
installationProgressTracker.packageBeingInstalled = PackageInProgressOfBeingInstalled(package: packageToInstall, installationStage: .ready, packageInstallationProgress: 0)
AppConstants.logger.debug("Packages to install: \(installationProgressTracker.packageBeingInstalled.package.name, privacy: .public)")
AppConstants.shared.logger.debug("Packages to install: \(installationProgressTracker.packageBeingInstalled.package.name, privacy: .public)")
packageInstallationProcessStep = .installing
@ -136,7 +136,7 @@ struct InstallationInitialView: View
{
if let foundPackageSelection
{
AppConstants.logger.debug("Would try to find package \(foundPackageSelection)")
AppConstants.shared.logger.debug("Would try to find package \(foundPackageSelection)")
let topCasksSet: Set<TopPackage> = Set(topPackagesTracker.topCasks)
@ -159,7 +159,7 @@ struct InstallationInitialView: View
}
catch let topPackageInstallationError
{
AppConstants.logger.error("Failed while trying to get top package to install: \(topPackageInstallationError, privacy: .public)")
AppConstants.shared.logger.error("Failed while trying to get top package to install: \(topPackageInstallationError, privacy: .public)")
dismiss()
@ -170,7 +170,7 @@ struct InstallationInitialView: View
}
else
{
AppConstants.logger.warning("Could not find the UUID in the package list")
AppConstants.shared.logger.warning("Could not find the UUID in the package list")
return nil
}

View File

@ -116,20 +116,20 @@ struct InstallingPackageView: View
do
{
let installationResult: TerminalOutput = try await installationProgressTracker.installPackage(using: brewData)
AppConstants.logger.debug("Installation result:\nStandard output: \(installationResult.standardOutput, privacy: .public)\nStandard error: \(installationResult.standardError, privacy: .public)")
AppConstants.shared.logger.debug("Installation result:\nStandard output: \(installationResult.standardOutput, privacy: .public)\nStandard error: \(installationResult.standardError, privacy: .public)")
/// Check if the package installation stag at the end of the install process was something unexpected. Normal package installations go through multiple steps, and the three listed below are not supposed to be the end state. This means that something went wrong during the installation
let installationStage: PackageInstallationStage = installationProgressTracker.packageBeingInstalled.installationStage
if [.installingCask, .installingPackage, .ready].contains(installationStage)
{
AppConstants.logger.warning("The installation process quit before it was supposed to")
AppConstants.shared.logger.warning("The installation process quit before it was supposed to")
installationProgressTracker.packageBeingInstalled.installationStage = .terminatedUnexpectedly
}
}
catch let fatalInstallationError
{
AppConstants.logger.error("Fatal error occurred during installing a package: \(fatalInstallationError, privacy: .public)")
AppConstants.shared.logger.error("Fatal error occurred during installing a package: \(fatalInstallationError, privacy: .public)")
dismiss()

View File

@ -56,13 +56,13 @@ struct LiveTerminalOutputView: View
{
if !forceKeepTerminalOutputInMemory
{
AppConstants.logger.debug("Purging saved real time output")
AppConstants.shared.logger.debug("Purging saved real time output")
lineArray = .init()
}
else
{
AppConstants.logger.debug("Forced to keep previous output in memory")
AppConstants.shared.logger.debug("Forced to keep previous output in memory")
}
}
}

View File

@ -67,7 +67,7 @@ struct PresentingSearchResultsView: View
openWindow(value: requestedPackageToPreview)
AppConstants.logger.debug("Would preview package \(requestedPackageToPreview.name)")
AppConstants.shared.logger.debug("Would preview package \(requestedPackageToPreview.name)")
}
catch {}
}
@ -112,13 +112,13 @@ struct PresentingSearchResultsView: View
installationProgressTracker.packageBeingInstalled = PackageInProgressOfBeingInstalled(package: packageToInstall, installationStage: .ready, packageInstallationProgress: 0)
#if DEBUG
AppConstants.logger.info("Packages to install: \(installationProgressTracker.packageBeingInstalled.package.name, privacy: .public)")
AppConstants.shared.logger.info("Packages to install: \(installationProgressTracker.packageBeingInstalled.package.name, privacy: .public)")
#endif
}
catch let packageByUUIDRetrievalError
{
#if DEBUG
AppConstants.logger.error("Failed while associating package with its ID: \(packageByUUIDRetrievalError, privacy: .public)")
AppConstants.shared.logger.error("Failed while associating package with its ID: \(packageByUUIDRetrievalError, privacy: .public)")
#endif
dismiss()

View File

@ -37,7 +37,7 @@ struct LicensingView: View
appState.licensingState = .selfCompiled
#else
AppConstants.logger.debug("Has validated email? \(hasValidatedEmail ? "YES" : "NO")")
AppConstants.shared.logger.debug("Has validated email? \(hasValidatedEmail ? "YES" : "NO")")
if hasValidatedEmail
{
@ -47,7 +47,7 @@ struct LicensingView: View
{
if let demoActivatedAt
{
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.demoLengthInSeconds) > 0
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.shared.demoLengthInSeconds) > 0
{ // Check if there is still time on the demo
appState.licensingState = .demo
}

View File

@ -25,7 +25,7 @@ struct Licensing_DemoView: View
Text("licensing.demo-activated.title")
.font(.title)
Text("licensing.demo.time-until-\((demoActivatedAt + AppConstants.demoLengthInSeconds).formatted(date: .complete, time: .complete))")
Text("licensing.demo.time-until-\((demoActivatedAt + AppConstants.shared.demoLengthInSeconds).formatted(date: .complete, time: .complete))")
HStack
{

View File

@ -27,7 +27,7 @@ struct Licensing_NotBoughtOrActivatedView: View
{
let timeIntervalSinceDemoWasActivated: TimeInterval = demoActivatedAt.timeIntervalSinceNow
if timeIntervalSinceDemoWasActivated < AppConstants.demoLengthInSeconds
if timeIntervalSinceDemoWasActivated < AppConstants.shared.demoLengthInSeconds
{
return true
}
@ -107,7 +107,7 @@ struct Licensing_NotBoughtOrActivatedView: View
if let demoActivatedAt
{
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.demoLengthInSeconds) > 0
if ((demoActivatedAt.timeIntervalSinceNow) + AppConstants.shared.demoLengthInSeconds) > 0
{ // Check if there is still time on the demo
Button
{
@ -164,7 +164,7 @@ struct Licensing_NotBoughtOrActivatedView: View
{
let hasSpecifiedUserBoughtCork: Bool = try await checkIfUserBoughtCork(for: emailFieldContents)
AppConstants.logger.debug("Has \(emailFieldContents) bought Cork? \(hasSpecifiedUserBoughtCork ? "YES" : "NO")")
AppConstants.shared.logger.debug("Has \(emailFieldContents) bought Cork? \(hasSpecifiedUserBoughtCork ? "YES" : "NO")")
if hasSpecifiedUserBoughtCork
{
@ -180,7 +180,7 @@ struct Licensing_NotBoughtOrActivatedView: View
}
catch let licenseCheckingError as CorkLicenseRetrievalError
{
AppConstants.logger.error("\(licenseCheckingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.error("\(licenseCheckingError.localizedDescription, privacy: .public)")
switch licenseCheckingError
{
@ -211,7 +211,7 @@ struct Licensing_NotBoughtOrActivatedView: View
if let demoActivatedAt
{
let timeIntervalSinceDemoWasActivated: TimeInterval = demoActivatedAt.timeIntervalSinceNow
AppConstants.logger.debug("Time interval since demo was activated: \(timeIntervalSinceDemoWasActivated, privacy: .public)")
AppConstants.shared.logger.debug("Time interval since demo was activated: \(timeIntervalSinceDemoWasActivated, privacy: .public)")
}
}
}

View File

@ -165,7 +165,7 @@ struct MaintenanceFinishedView: View
{
dismiss()
appState.cachedDownloadsFolderSize = AppConstants.brewCachedDownloadsPath.directorySize
appState.cachedDownloadsFolderSize = AppConstants.shared.brewCachedDownloadsPath.directorySize
} label: {
Text("action.close")
}

View File

@ -43,12 +43,12 @@ struct MaintenanceRunningView: View
}
catch let orphanUninstallatioError
{
AppConstants.logger.error("Orphan uninstallation error: \(orphanUninstallatioError.localizedDescription, privacy: .public))")
AppConstants.shared.logger.error("Orphan uninstallation error: \(orphanUninstallatioError.localizedDescription, privacy: .public))")
}
}
else
{
AppConstants.logger.info("Will not uninstall orphans")
AppConstants.shared.logger.info("Will not uninstall orphans")
}
if shouldPurgeCache
@ -59,21 +59,21 @@ struct MaintenanceRunningView: View
{
packagesHoldingBackCachePurge = try await purgeHomebrewCacheUtility()
AppConstants.logger.info("Length of array of packages that are holding back cache purge: \(packagesHoldingBackCachePurge.count)")
AppConstants.shared.logger.info("Length of array of packages that are holding back cache purge: \(packagesHoldingBackCachePurge.count)")
}
catch let homebrewCachePurgingError
{
AppConstants.logger.error("Homebrew cache purging error: \(homebrewCachePurgingError.localizedDescription, privacy: .public))")
AppConstants.shared.logger.error("Homebrew cache purging error: \(homebrewCachePurgingError.localizedDescription, privacy: .public))")
}
}
else
{
AppConstants.logger.info("Will not purge cache")
AppConstants.shared.logger.info("Will not purge cache")
}
if shouldDeleteDownloads
{
AppConstants.logger.info("Will delete downloads")
AppConstants.shared.logger.info("Will delete downloads")
currentMaintenanceStepText = "maintenance.step.deleting-cached-downloads"
@ -87,7 +87,7 @@ struct MaintenanceRunningView: View
}
else
{
AppConstants.logger.info("Will not delete downloads")
AppConstants.shared.logger.info("Will not delete downloads")
}
if shouldPerformHealthCheck
@ -97,18 +97,18 @@ struct MaintenanceRunningView: View
do
{
let healthCheckOutput: TerminalOutput = try await performBrewHealthCheck()
AppConstants.logger.log("Health check output:\nStandard output: \(healthCheckOutput.standardOutput)\nStandard error: \(healthCheckOutput.standardError)")
AppConstants.shared.logger.log("Health check output:\nStandard output: \(healthCheckOutput.standardOutput)\nStandard error: \(healthCheckOutput.standardError)")
brewHealthCheckFoundNoProblems = true
}
catch let healthCheckError
{
AppConstants.logger.error("Health check error: \(healthCheckError, privacy: .public)")
AppConstants.shared.logger.error("Health check error: \(healthCheckError, privacy: .public)")
}
}
else
{
AppConstants.logger.info("Will not perform health check")
AppConstants.shared.logger.info("Will not perform health check")
}
maintenanceSteps = .finished

View File

@ -81,7 +81,7 @@ struct MaintenanceReadyView: View
Button
{
AppConstants.logger.debug("Start")
AppConstants.shared.logger.debug("Start")
maintenanceSteps = .maintenanceRunning
} label: {

View File

@ -21,7 +21,7 @@ struct MenuBar_CacheCleanup: View
{
Task(priority: .userInitiated)
{
AppConstants.logger.log("Will purge cache")
AppConstants.shared.logger.log("Will purge cache")
isPurgingHomebrewCache = true
@ -52,7 +52,7 @@ struct MenuBar_CacheCleanup: View
}
catch let cachePurgingError
{
AppConstants.logger.warning("There were errors while purging Homebrew cache: \(cachePurgingError.localizedDescription, privacy: .public)")
AppConstants.shared.logger.warning("There were errors while purging Homebrew cache: \(cachePurgingError.localizedDescription, privacy: .public)")
sendNotification(
title: String(localized: "maintenance.results.package-cache.failure"),

View File

@ -21,7 +21,7 @@ struct MenuBar_CachedDownloadsCleanup: View
{
Button(appState.cachedDownloadsFolderSize != 0 ? "maintenance.steps.downloads.delete-cached-downloads" : "navigation.menu.maintenance.no-cached-downloads")
{
AppConstants.logger.log("Will delete cached downloads")
AppConstants.shared.logger.log("Will delete cached downloads")
isDeletingCachedDownloads = true
@ -37,7 +37,7 @@ struct MenuBar_CachedDownloadsCleanup: View
isDeletingCachedDownloads = false
appState.cachedDownloadsFolderSize = AppConstants.brewCachedDownloadsPath.directorySize
appState.cachedDownloadsFolderSize = AppConstants.shared.brewCachedDownloadsPath.directorySize
}
.disabled(appState.cachedDownloadsFolderSize == 0)
}

View File

@ -23,7 +23,7 @@ struct MenuBar_OrphanCleanup: View
{
Task(priority: .userInitiated)
{
AppConstants.logger.log("Will delete orphans")
AppConstants.shared.logger.log("Will delete orphans")
do
{
@ -37,7 +37,7 @@ struct MenuBar_OrphanCleanup: View
}
catch let orphanUninstallationError
{
AppConstants.logger.error("Failed while uninstalling orphans: \(orphanUninstallationError, privacy: .public)")
AppConstants.shared.logger.error("Failed while uninstalling orphans: \(orphanUninstallationError, privacy: .public)")
sendNotification(
title: String(localized: "maintenance.results.orphans.failure"),

View File

@ -153,7 +153,7 @@ struct OnboardingView: View
showRealTimeTerminalOutputOfOperations = true
}
AppConstants.logger.info("Onboarding finished")
AppConstants.shared.logger.info("Onboarding finished")
dismiss()
} label: {

View File

@ -62,7 +62,7 @@ struct OnboardingDefaultsSlider: View
}
.onChange(of: sliderValue)
{ _ in
AppConstants.logger.debug("New slider value: \(sliderValue, privacy: .public)")
AppConstants.shared.logger.debug("New slider value: \(sliderValue, privacy: .public)")
if sliderValue == 0
{
setupLevel = .basic
@ -84,7 +84,7 @@ struct OnboardingDefaultsSlider: View
setupLevel = .advanced
}
AppConstants.logger.debug("\(String(describing: setupLevel.name.stringValue()))")
AppConstants.shared.logger.debug("\(String(describing: setupLevel.name.stringValue()))")
}
})
}

View File

@ -133,7 +133,7 @@ struct PackageDetailView: View, Sendable
}
catch let packageInfoDecodingError
{
AppConstants.logger.error("Failed while parsing package info: \(packageInfoDecodingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while parsing package info: \(packageInfoDecodingError, privacy: .public)")
erroredOut = (true, packageInfoDecodingError.localizedDescription)
}

View File

@ -58,7 +58,7 @@ struct PackageModificationButtons: View
}
catch let pinningUnpinningError
{
AppConstants.logger.error("Failed while pinning/unpinning package \(package.name): \(pinningUnpinningError)")
AppConstants.shared.logger.error("Failed while pinning/unpinning package \(package.name): \(pinningUnpinningError)")
}
}
} label: {
@ -104,7 +104,7 @@ struct PackageModificationButtons: View
{
Task
{
AppConstants.logger.debug("Confirmation of package removal NOT needed")
AppConstants.shared.logger.debug("Confirmation of package removal NOT needed")
try await brewData.uninstallSelectedPackage(
package: package,
@ -117,7 +117,7 @@ struct PackageModificationButtons: View
}
else
{
AppConstants.logger.debug("Confirmation of package removal needed")
AppConstants.shared.logger.debug("Confirmation of package removal needed")
uninstallationConfirmationTracker.showConfirmationDialog(packageThatNeedsConfirmation: package, shouldPurge: false, isCalledFromSidebar: false)
}
}

View File

@ -31,8 +31,8 @@ struct ReinstallCorruptedPackageView: View
.padding()
.task(priority: .userInitiated)
{
let reinstallationResult: TerminalOutput = await shell(AppConstants.brewExecutablePath, ["reinstall", corruptedPackageToReinstall.name])
AppConstants.logger.debug("Reinstallation result:\nStandard output: \(reinstallationResult.standardOutput, privacy: .public)\nStandard error:\(reinstallationResult.standardError, privacy: .public)")
let reinstallationResult: TerminalOutput = await shell(AppConstants.shared.brewExecutablePath, ["reinstall", corruptedPackageToReinstall.name])
AppConstants.shared.logger.debug("Reinstallation result:\nStandard output: \(reinstallationResult.standardOutput, privacy: .public)\nStandard error:\(reinstallationResult.standardError, privacy: .public)")
corruptedPackageReinstallationStage = .finished
}

View File

@ -60,7 +60,7 @@ struct PathControl: NSViewRepresentable
case .OK:
self.parent.urlToShow = openPanel.url!
default:
AppConstants.logger.warning("Didn't select a proper Homebrew executable")
AppConstants.shared.logger.warning("Didn't select a proper Homebrew executable")
}
}
}

View File

@ -55,7 +55,7 @@ private struct RemovePackageButton: View
{
Task
{
AppConstants.logger.debug("Confirmation of package removal NOT needed")
AppConstants.shared.logger.debug("Confirmation of package removal NOT needed")
try await brewData.uninstallSelectedPackage(
package: package,
@ -68,7 +68,7 @@ private struct RemovePackageButton: View
}
else
{
AppConstants.logger.debug("Confirmation of package removal needed")
AppConstants.shared.logger.debug("Confirmation of package removal needed")
uninstallationConfirmationTracker.showConfirmationDialog(packageThatNeedsConfirmation: package, shouldPurge: shouldPurge, isCalledFromSidebar: isCalledFromSidebar)
}
} label: {

View File

@ -63,7 +63,7 @@ struct ServiceDetailView: View
}
.task(id: service.id, priority: .userInitiated)
{
AppConstants.logger.log("Service details pane for service \(service.name) appeared; will try to load details")
AppConstants.shared.logger.log("Service details pane for service \(service.name) appeared; will try to load details")
defer
{
@ -76,13 +76,13 @@ struct ServiceDetailView: View
}
catch let servicesLoadingError
{
AppConstants.logger.error("Failed while loading services: \(servicesLoadingError.localizedDescription)")
AppConstants.shared.logger.error("Failed while loading services: \(servicesLoadingError.localizedDescription)")
erroredOutWhileLoadingServiceDetails = true
}
}
.onDisappear
{
AppConstants.logger.log("Service details pane for \(service.name) disappeared; will purge details tracker")
AppConstants.shared.logger.log("Service details pane for \(service.name) disappeared; will purge details tracker")
serviceDetails = nil
}

View File

@ -57,8 +57,8 @@ struct BrewPane: View
{
isPerformingBrewAnalyticsChangeCommand = true
AppConstants.logger.debug("Will ENABLE analytics")
await shell(AppConstants.brewExecutablePath, ["analytics", "on"])
AppConstants.shared.logger.debug("Will ENABLE analytics")
await shell(AppConstants.shared.brewExecutablePath, ["analytics", "on"])
isPerformingBrewAnalyticsChangeCommand = false
}
@ -69,8 +69,8 @@ struct BrewPane: View
{
isPerformingBrewAnalyticsChangeCommand = true
AppConstants.logger.debug("Will DISABLE analytics")
await shell(AppConstants.brewExecutablePath, ["analytics", "off"])
AppConstants.shared.logger.debug("Will DISABLE analytics")
await shell(AppConstants.shared.brewExecutablePath, ["analytics", "off"])
isPerformingBrewAnalyticsChangeCommand = false
}

View File

@ -35,23 +35,23 @@ struct NotificationsPane: View
.toggleStyle(.switch)
.task
{
AppConstants.logger.debug("Will re-check notification authorization status")
AppConstants.shared.logger.debug("Will re-check notification authorization status")
await appState.requestNotificationAuthorization()
switch appState.notificationAuthStatus
{
case .notDetermined:
AppConstants.logger.info("Not determined")
AppConstants.shared.logger.info("Not determined")
case .denied:
AppConstants.logger.info("Denied")
AppConstants.shared.logger.info("Denied")
case .authorized:
AppConstants.logger.info("Authorized")
AppConstants.shared.logger.info("Authorized")
case .provisional:
AppConstants.logger.info("Provisional")
AppConstants.shared.logger.info("Provisional")
case .ephemeral:
AppConstants.logger.info("Ephemeral")
AppConstants.shared.logger.info("Ephemeral")
default:
AppConstants.logger.info("TF")
AppConstants.shared.logger.info("TF")
}
if appState.notificationAuthStatus == .denied

View File

@ -30,7 +30,7 @@ struct CustomHomebrewExecutableView: View
{
GroupBox
{
PathControl(urlToShow: URL(filePath: AppConstants.brewExecutablePath.path), style: .standard, width: 295)
PathControl(urlToShow: URL(filePath: AppConstants.shared.brewExecutablePath.path), style: .standard, width: 295)
.disabled(true)
}
@ -82,19 +82,19 @@ struct CustomHomebrewExecutableView: View
case .success(let success):
if success.first!.lastPathComponent == "brew"
{
AppConstants.logger.info("Valid brew executable: \(success.first!.path)")
AppConstants.shared.logger.info("Valid brew executable: \(success.first!.path)")
customHomebrewPath = success.first!.path
}
else
{
AppConstants.logger.error("Not a valid brew executable")
AppConstants.shared.logger.error("Not a valid brew executable")
settingsState.alertType = .customHomebrewLocationNotABrewExecutable(executablePath: success.first!.path)
settingsState.isShowingAlert = true
}
case .failure(let failure):
AppConstants.logger.error("Failure: \(failure)")
AppConstants.shared.logger.error("Failure: \(failure)")
settingsState.alertType = .customHomebrewLocationNotAnExecutableAtAll
settingsState.isShowingAlert = true

View File

@ -42,7 +42,7 @@ struct TapsSection: View
{
Task(priority: .userInitiated)
{
AppConstants.logger.debug("Would remove \(tap.name, privacy: .public)")
AppConstants.shared.logger.debug("Would remove \(tap.name, privacy: .public)")
try await removeTap(name: tap.name, availableTaps: availableTaps, appState: appState, shouldApplyUninstallSpinnerToRelevantItemInSidebar: true)
}

View File

@ -114,13 +114,13 @@ struct StartPage: View
case .homeNotSet:
appState.showAlert(errorToShow: .homePathNotSet)
default:
AppConstants.logger.error("Could not decode outdated package command output: \(outdatedPackageRetrievalError.localizedDescription)")
AppConstants.shared.logger.error("Could not decode outdated package command output: \(outdatedPackageRetrievalError.localizedDescription)")
errorOutReason = outdatedPackageRetrievalError.localizedDescription
}
}
catch
{
AppConstants.logger.error("Unspecified error while pulling package updates")
AppConstants.shared.logger.error("Unspecified error while pulling package updates")
}
}
}
@ -133,7 +133,7 @@ struct StartPage: View
Button
{
AppConstants.logger.info("Would perform maintenance")
AppConstants.shared.logger.info("Would perform maintenance")
appState.isShowingMaintenanceSheet.toggle()
} label: {
Text("start-page.open-maintenance")
@ -145,7 +145,7 @@ struct StartPage: View
}
.onAppear
{
AppConstants.logger.debug("Cached downloads path: \(AppConstants.brewCachedDownloadsPath)")
AppConstants.shared.logger.debug("Cached downloads path: \(AppConstants.shared.brewCachedDownloadsPath)")
}
.onDrop(of: [.fileURL], isTargeted: $dragOver)
{ providers -> Bool in
@ -154,7 +154,7 @@ struct StartPage: View
{
if url.pathExtension == "brewbak" || url.pathExtension.isEmpty
{
AppConstants.logger.debug("Correct File Format")
AppConstants.shared.logger.debug("Correct File Format")
Task(priority: .userInitiated)
{
@ -163,7 +163,7 @@ struct StartPage: View
}
else
{
AppConstants.logger.error("Incorrect file format")
AppConstants.shared.logger.error("Incorrect file format")
}
}
})

View File

@ -29,7 +29,7 @@ struct PackageAndTapOverviewBox: View
{
Button
{
AppConstants.brewCellarPath.revealInFinder(.openTargetItself)
AppConstants.shared.brewCellarPath.revealInFinder(.openTargetItself)
} label: {
Text("action.reveal-in-finder")
}
@ -47,7 +47,7 @@ struct PackageAndTapOverviewBox: View
{
Button
{
AppConstants.brewCaskPath.revealInFinder(.openTargetItself)
AppConstants.shared.brewCaskPath.revealInFinder(.openTargetItself)
} label: {
Text("action.reveal-in-finder")
}
@ -65,7 +65,7 @@ struct PackageAndTapOverviewBox: View
{
Button
{
AppConstants.tapPath.revealInFinder(.openTargetItself)
AppConstants.shared.tapPath.revealInFinder(.openTargetItself)
} label: {
Text("action.reveal-in-finder")
}

View File

@ -35,11 +35,11 @@ struct AddTapAddingView: View
tapResult = await addTap(name: requestedTap, forcedRepoAddress: forcedRepoAddress)
}
AppConstants.logger.debug("Result: \(tapResult, privacy: .public)")
AppConstants.shared.logger.debug("Result: \(tapResult, privacy: .public)")
if tapResult.contains("Tapped")
{
AppConstants.logger.info("Tapping was successful!")
AppConstants.shared.logger.info("Tapping was successful!")
progress = .finished
}
else
@ -49,7 +49,7 @@ struct AddTapAddingView: View
if tapResult.contains("Repository not found")
{
AppConstants.logger.error("Repository was not found")
AppConstants.shared.logger.error("Repository was not found")
tappingError = .repositoryNotFound
}

View File

@ -36,12 +36,12 @@ struct AddTapFinishedView: View
/// Remove that one element of the array that's empty for some reason
availableTaps.addedTaps.removeAll(where: { $0.name == "" })
AppConstants.logger.info("Available taps: \(availableTaps.addedTaps, privacy: .public)")
AppConstants.shared.logger.info("Available taps: \(availableTaps.addedTaps, privacy: .public)")
}
.task(priority: .background)
{ // Force-load the packages from the new tap
AppConstants.logger.info("Will update packages")
await shell(AppConstants.brewExecutablePath, ["update"])
AppConstants.shared.logger.info("Will update packages")
await shell(AppConstants.shared.brewExecutablePath, ["update"])
}
}
}

View File

@ -101,7 +101,7 @@ struct TapDetailView: View, Sendable
isLoadingTapInfo = false
}
async let tapInfoRaw: String = await shell(AppConstants.brewExecutablePath, ["tap-info", "--json", tap.name]).standardOutput
async let tapInfoRaw: String = await shell(AppConstants.shared.brewExecutablePath, ["tap-info", "--json", tap.name]).standardOutput
do
{
@ -109,7 +109,7 @@ struct TapDetailView: View, Sendable
}
catch let parsingError
{
AppConstants.logger.error("Failed while parsing package info: \(parsingError, privacy: .public)")
AppConstants.shared.logger.error("Failed while parsing package info: \(parsingError, privacy: .public)")
errorOutReason = parsingError.localizedDescription

View File

@ -57,7 +57,7 @@ struct ErroredOutStageView: View
.fixedSize()
.onAppear
{
AppConstants.logger.error("Update errors: \(updateProgressTracker.errors)")
AppConstants.shared.logger.error("Update errors: \(updateProgressTracker.errors)")
}
}
.onAppear

View File

@ -35,11 +35,11 @@ struct CheckingForUpdatesStateView: View
{
updateAvailability = await refreshPackages(updateProgressTracker, outdatedPackageTracker: outdatedPackageTracker)
AppConstants.logger.debug("Update availability result: \(updateAvailability.description, privacy: .public)")
AppConstants.shared.logger.debug("Update availability result: \(updateAvailability.description, privacy: .public)")
if updateAvailability == .noUpdatesAvailable
{
AppConstants.logger.debug("Outside update function: No updates available")
AppConstants.shared.logger.debug("Outside update function: No updates available")
updateProgressTracker.realTimeOutput = .init()
@ -47,7 +47,7 @@ struct CheckingForUpdatesStateView: View
}
else
{
AppConstants.logger.debug("Outside update function: Updates available")
AppConstants.shared.logger.debug("Outside update function: Updates available")
packageUpdatingStep = .updatingPackages
}
}

View File

@ -52,14 +52,14 @@ struct UpdatingPackageTrackerStateView: View
appState.showAlert(errorToShow: .homePathNotSet)
case .couldNotDecodeCommandOutput(let decodingError):
// TODO: Swallow the error for now so that I don't have to bother the translators. Add alert later
AppConstants.logger.error("Could not decode outdated package command output: \(decodingError)")
AppConstants.shared.logger.error("Could not decode outdated package command output: \(decodingError)")
case .otherError:
AppConstants.logger.error("Something went wrong")
AppConstants.shared.logger.error("Something went wrong")
}
}
catch
{
AppConstants.logger.error("IDK what just happened")
AppConstants.shared.logger.error("IDK what just happened")
}
}
}

View File

@ -54,18 +54,18 @@ struct UpdateSomePackagesView: View
updateCommandArguments = ["reinstall", "--cask", packageBeingCurrentlyUpdated.name]
}
AppConstants.logger.info("Update command: \(updateCommandArguments)")
AppConstants.shared.logger.info("Update command: \(updateCommandArguments)")
for await output in shell(AppConstants.brewExecutablePath, updateCommandArguments)
for await output in shell(AppConstants.shared.brewExecutablePath, updateCommandArguments)
{
switch output
{
case .standardOutput(let outputLine):
AppConstants.logger.info("Individual package updating output: \(outputLine)")
AppConstants.shared.logger.info("Individual package updating output: \(outputLine)")
updateProgress = updateProgress + (Double(selectedPackages.count) / 100)
case .standardError(let errorLine):
AppConstants.logger.info("Individual package updating error: \(errorLine)")
AppConstants.shared.logger.info("Individual package updating error: \(errorLine)")
updateProgress = updateProgress + (Double(selectedPackages.count) / 100)
if !errorLine.contains("The post-install step did not complete successfully")
@ -76,7 +76,7 @@ struct UpdateSomePackagesView: View
}
updateProgress = Double(index) + 1
AppConstants.logger.info("Update progress index: \(updateProgress)")
AppConstants.shared.logger.info("Update progress index: \(updateProgress)")
}
if !packageUpdatingErrors.isEmpty
@ -90,12 +90,12 @@ struct UpdateSomePackagesView: View
do
{
AppConstants.logger.debug("Will synchronize outdated packages")
AppConstants.shared.logger.debug("Will synchronize outdated packages")
try await outdatedPackageTracker.getOutdatedPackages(brewData: brewData)
}
catch let packageSynchronizationError
{
AppConstants.logger.error("Could not synchronize packages: \(packageSynchronizationError, privacy: .public)")
AppConstants.shared.logger.error("Could not synchronize packages: \(packageSynchronizationError, privacy: .public)")
appState.showAlert(errorToShow: .couldNotSynchronizePackages(error: packageSynchronizationError.localizedDescription))
}
}

View File

@ -36,10 +36,10 @@ public func sendNotification(title: String, body: String? = nil, subtitle: Strin
let request: UNNotificationRequest = .init(identifier: UUID().uuidString, content: notification, trigger: nil)
AppConstants.notificationCenter.add(request)
AppConstants.shared.notificationCenter.add(request)
}
else
{
AppConstants.logger.info("Will not send notification because they're disabled")
AppConstants.shared.logger.info("Will not send notification because they're disabled")
}
}

View File

@ -9,42 +9,72 @@ import Foundation
import OSLog
@preconcurrency import UserNotifications
public struct AppConstants
public struct AppConstants: Sendable
{
// MARK: - Initializer
init()
{
let internalLogger: Logger = .init(subsystem: "com.davidbures.cork", category: "Cork")
// MARK: - Initialize proxy settings
self.proxySettings = {
let proxySettings: [String: Any]? = CFNetworkCopySystemProxySettings()?.takeUnretainedValue() as? [String: Any]
guard let httpProxyHost = proxySettings?[kCFNetworkProxiesHTTPProxy as String] as? String
else
{
internalLogger.error("Could not get proxy host")
return nil
}
guard let httpProxyPort = proxySettings?[kCFNetworkProxiesHTTPPort as String] as? Int
else
{
internalLogger.error("Could not get proxy port")
return nil
}
return (host: httpProxyHost, port: httpProxyPort)
}()
// MARK: -
self.documentsDirectoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appending(component: "Cork", directoryHint: .isDirectory)
self.metadataFilePath = self.documentsDirectoryPath.appending(component: "Metadata", directoryHint: .notDirectory).appendingPathExtension("brewmeta")
self.brewCachePath = URL.libraryDirectory.appending(component: "Caches", directoryHint: .isDirectory).appending(component: "Homebrew", directoryHint: .isDirectory)
self.brewCachedFormulaeDownloadsPath = brewCachePath
self.brewCachedCasksDownloadsPath = brewCachePath.appending(component: "Cask", directoryHint: .isDirectory)
self.brewCachedDownloadsPath = brewCachePath.appending(component: "downloads", directoryHint: .isDirectory)
self.logger = internalLogger
}
// MARK: - Shared Instance
public static let shared: AppConstants = .init()
// MARK: - Logging
public static let logger: Logger = .init(subsystem: "com.davidbures.cork", category: "Cork")
public let logger: Logger
// MARK: - Notification stuff
public static let notificationCenter: UNUserNotificationCenter = UNUserNotificationCenter.current()
public let notificationCenter: UNUserNotificationCenter = UNUserNotificationCenter.current()
// MARK: - Proxy settings
public static let proxySettings: (host: String, port: Int)? = {
let proxySettings: [String: Any]? = CFNetworkCopySystemProxySettings()?.takeUnretainedValue() as? [String: Any]
guard let httpProxyHost = proxySettings?[kCFNetworkProxiesHTTPProxy as String] as? String
else
{
AppConstants.logger.error("Could not get proxy host")
return nil
}
guard let httpProxyPort = proxySettings?[kCFNetworkProxiesHTTPPort as String] as? Int
else
{
AppConstants.logger.error("Could not get proxy port")
return nil
}
return (host: httpProxyHost, port: httpProxyPort)
}()
public let proxySettings: (host: String, port: Int)?
// MARK: - Basic executables and file locations
public static let brewExecutablePath: URL = {
public let brewExecutablePath: URL = {
/// If a custom Homebrew path is defined, use it. Otherwise, use the default paths
if let homebrewPath = UserDefaults.standard.string(forKey: "customHomebrewPath"), !homebrewPath.isEmpty
{
@ -65,7 +95,7 @@ public struct AppConstants
}
}()
public static let brewCellarPath: URL = {
public let brewCellarPath: URL = {
if FileManager.default.fileExists(atPath: "/opt/homebrew/Cellar")
{ // Apple Sillicon
return URL(filePath: "/opt/homebrew/Cellar")
@ -76,7 +106,7 @@ public struct AppConstants
}
}()
public static let brewCaskPath: URL = {
public let brewCaskPath: URL = {
if FileManager.default.fileExists(atPath: "/opt/homebrew/Caskroom")
{ // Apple Sillicon
return URL(filePath: "/opt/homebrew/Caskroom")
@ -87,7 +117,7 @@ public struct AppConstants
}
}()
public static let tapPath: URL = {
public let tapPath: URL = {
if FileManager.default.fileExists(atPath: "/opt/homebrew/Library/Taps")
{ // Apple Sillicon
return URL(filePath: "/opt/homebrew/Library/Taps")
@ -100,37 +130,40 @@ public struct AppConstants
// MARK: - Storage for tagging
public static let documentsDirectoryPath: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appending(component: "Cork", directoryHint: .isDirectory)
public static let metadataFilePath: URL = documentsDirectoryPath.appending(component: "Metadata", directoryHint: .notDirectory).appendingPathExtension("brewmeta")
public let documentsDirectoryPath: URL
public let metadataFilePath: URL
// MARK: - Brew Cache
public static let brewCachePath: URL = URL.libraryDirectory.appending(component: "Caches", directoryHint: .isDirectory).appending(component: "Homebrew", directoryHint: .isDirectory) // /Users/david/Library/Caches/Homebrew
/// Path to the cached downloads
/// `/Users/david/Library/Caches/Homebrew`
public let brewCachePath: URL
/// These two have the symlinks to the actual downloads
public static let brewCachedFormulaeDownloadsPath: URL = brewCachePath
public static let brewCachedCasksDownloadsPath: URL = brewCachePath.appending(component: "Cask", directoryHint: .isDirectory)
/// Has symlinks to the cached downloads
/// `/Users/david/Library/Caches/Homebrew`
public let brewCachedFormulaeDownloadsPath: URL
public let brewCachedCasksDownloadsPath: URL
/// This one has all the downloaded files themselves
public static let brewCachedDownloadsPath: URL = brewCachePath.appending(component: "downloads", directoryHint: .isDirectory)
public let brewCachedDownloadsPath: URL
// MARK: - Licensing
public static let demoLengthInSeconds: Double = 604_800 // 7 days
public let demoLengthInSeconds: Double = 604_800 // 7 days
public static let authorizationEndpointURL: URL = .init(string: "https://automation.tomoserver.eu/webhook/38aacca6-5da8-453c-a001-804b15751319")!
public static let licensingAuthorization: (username: String, passphrase: String) = ("cork-authorization", "choosy-defame-neon-resume-cahoots")
public let authorizationEndpointURL: URL = .init(string: "https://automation.tomoserver.eu/webhook/38aacca6-5da8-453c-a001-804b15751319")!
public let licensingAuthorization: (username: String, passphrase: String) = ("cork-authorization", "choosy-defame-neon-resume-cahoots")
// MARK: - Temporary OS version submission
public static let osSubmissionEndpointURL: URL = .init(string: "https://automation.tomoserver.eu/webhook/3a971576-fa96-479e-9dc4-e052fe33270b")!
public let osSubmissionEndpointURL: URL = .init(string: "https://automation.tomoserver.eu/webhook/3a971576-fa96-479e-9dc4-e052fe33270b")!
// MARK: - Misc Stuff
public static let backgroundUpdateInterval: TimeInterval = 10 * 60
public static let backgroundUpdateIntervalTolerance: TimeInterval = 1 * 60
public let backgroundUpdateInterval: TimeInterval = 10 * 60
public let backgroundUpdateIntervalTolerance: TimeInterval = 1 * 60
public static let osVersionString: (lookupName: String, fullName: String) = {
public let osVersionString: (lookupName: String, fullName: String) = {
let versionDictionary: [Int: (lookupName: String, fullName: String)] = [
15: ("sequoia", "Sequoia"),
14: ("sonoma", "Sonoma"),

View File

@ -67,7 +67,7 @@ struct TapDecodingTest
private func parseTapInfoForSpeficiedTap(tapName: String) async -> TapInfo?
{
let coreTapRawOutput: String = await shell(AppConstants.brewExecutablePath, ["tap-info", "--json", tapName]).standardOutput
let coreTapRawOutput: String = await shell(AppConstants.shared.brewExecutablePath, ["tap-info", "--json", tapName]).standardOutput
return try? await parseTapInfo(from: coreTapRawOutput)
}