mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-26 01:27:42 +00:00
feat(mac): replaced print statements with OSLog calls
This commit is contained in:
parent
18b19ee280
commit
5250a84c04
21 changed files with 209 additions and 273 deletions
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
|
||||
struct AddKeyboardView: View {
|
||||
@EnvironmentObject var settings: SettingsContainer
|
||||
|
|
@ -52,7 +53,7 @@ struct AddKeyboardView: View {
|
|||
// Placement determines where on the bar it sits
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Close") {
|
||||
print("close button clicked")
|
||||
Logger.app.debug("AddKeyboardView close button clicked")
|
||||
dismissAddKeyboardView()
|
||||
if settings.isInstallationInProgress() {
|
||||
settings.userCanceledPackageInstallation()
|
||||
|
|
@ -61,7 +62,7 @@ struct AddKeyboardView: View {
|
|||
}
|
||||
}
|
||||
.onDisappear {
|
||||
print("AddKeyboardView onDisappear")
|
||||
Logger.app.debug("AddKeyboardView onDisappear")
|
||||
downloadCoordinator.cancelActiveDownload()
|
||||
}
|
||||
.alert("Package Installation Failed", isPresented: $downloadCoordinator.loadPackageFailed) {
|
||||
|
|
@ -75,11 +76,11 @@ struct AddKeyboardView: View {
|
|||
if let helper = downloadCoordinator.installHelper {
|
||||
PackageConfirmationView(installHelper: helper) { accepted in
|
||||
if accepted {
|
||||
print("installing validated package: \(helper.packageName ?? "unknown package")")
|
||||
Logger.download.info("installing validated package: \(helper.packageName ?? "unknown package", privacy: .public)")
|
||||
do {
|
||||
try settings.installPackage()
|
||||
} catch {
|
||||
print("failed to install package: \(helper.packageName ?? "unknown package") with error: \(error.localizedDescription)")
|
||||
Logger.download.error("failed to install package: \(helper.packageName ?? "unknown package") with error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
settings.userCanceledPackageInstallation()
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ import OSLog
|
|||
|
||||
extension Logger {
|
||||
private static let configSubsystem = ConfigAppUtil.configBundleId
|
||||
static let package = Logger(subsystem: configSubsystem, category: "package")
|
||||
static let app = Logger(subsystem: configSubsystem, category: "app")
|
||||
static let download = Logger(subsystem: configSubsystem, category: "download")
|
||||
static let ui = Logger(subsystem: configSubsystem, category: "ui")
|
||||
}
|
||||
|
||||
@main
|
||||
|
|
@ -24,7 +23,7 @@ struct ConfigApp: App {
|
|||
@Environment(\.openWindow) private var openWindow
|
||||
|
||||
init() {
|
||||
print("tier: \(ConfigAppUtil.appTier)")
|
||||
Logger.app.log("Starting Keyman Configuration, version: \(ConfigAppUtil.versionWithTag), versionWithTag: \(ConfigAppUtil.versionWithTag)")
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class DownloadCoordinator: NSObject, ObservableObject, WKNavigationDelega
|
|||
decisionHandler(.cancel)
|
||||
return
|
||||
}
|
||||
Logger.download.info("received url: \(urlString, privacy: .public)")
|
||||
Logger.download.log("received url: \(urlString, privacy: .public)")
|
||||
|
||||
// if the url matches the install url pattern, then cancel the request,
|
||||
// build the standard URLRequest for a package installation and send it
|
||||
|
|
@ -146,7 +146,7 @@ public class DownloadCoordinator: NSObject, ObservableObject, WKNavigationDelega
|
|||
completionHandler(helper.temporaryKmpFileLocation)
|
||||
}
|
||||
} catch {
|
||||
Logger.download.error("could not initiate package download, error: \(String(describing: error), privacy: .public)")
|
||||
Logger.download.error("could not initiate package download, error: \(error as NSError, privacy: .public)")
|
||||
self.loadPackageFailed = true
|
||||
self.loadFailureMessage = error.localizedDescription
|
||||
completionHandler(nil)
|
||||
|
|
@ -173,7 +173,7 @@ public class DownloadCoordinator: NSObject, ObservableObject, WKNavigationDelega
|
|||
}
|
||||
|
||||
public func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
|
||||
Logger.download.error("download failed with error: \(String(describing: error), privacy: .public)")
|
||||
Logger.download.error("download failed with error: \(error as NSError, privacy: .public)")
|
||||
self.isDownloading = false
|
||||
self.progressObserver = nil
|
||||
self.loadPackageFailed = true
|
||||
|
|
|
|||
|
|
@ -62,10 +62,7 @@ struct InstallDebugView: View {
|
|||
_ = installation.validateUserHasRestarted()
|
||||
}
|
||||
Button("Set Displayed Complete") {
|
||||
let beforeDisplayed = installation.getHasDisplayedInstallationComplete()
|
||||
installation.setHasDisplayedInstallationComplete()
|
||||
let afterDisplayed = installation.getHasDisplayedInstallationComplete()
|
||||
print("hasDisplayedInstallComplete = \(beforeDisplayed) -> \(afterDisplayed)")
|
||||
}
|
||||
Button("debug") {
|
||||
installation.debug()
|
||||
|
|
@ -76,9 +73,6 @@ struct InstallDebugView: View {
|
|||
Button("Kill Keyman") {
|
||||
_ = installation.killKeymanInputMethod()
|
||||
}
|
||||
Button("Uninstall") {
|
||||
installation.uninstall()
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import SwiftUI
|
|||
import Combine
|
||||
import WebKit
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
|
||||
struct KeyboardSearchView: NSViewRepresentable {
|
||||
@ObservedObject var coordinator: DownloadCoordinator
|
||||
|
|
@ -22,7 +23,8 @@ struct KeyboardSearchView: NSViewRepresentable {
|
|||
|
||||
/** Creates the underlying NSView (WKWebView) for macOS */
|
||||
func makeNSView(context: Context) -> WKWebView {
|
||||
print("makeNSView called")
|
||||
Logger.app.debug("KeyboardSearchView makeNSView called")
|
||||
|
||||
let webView = WKWebView()
|
||||
|
||||
// assign the coordinator as the navigation delegate
|
||||
|
|
@ -41,7 +43,7 @@ struct KeyboardSearchView: NSViewRepresentable {
|
|||
func updateNSView(_ nsView: WKWebView, context: Context) {
|
||||
if coordinator.settings == nil {
|
||||
coordinator.settings = self.settings
|
||||
print("updateNSView, settings intialized for coordinator")
|
||||
Logger.app.debug("KeyboardSearchView updateNSView, settings intialized for coordinator")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import SwiftUI
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
|
||||
struct MainConfigView: View {
|
||||
|
||||
|
|
@ -96,7 +97,8 @@ struct MainConfigView: View {
|
|||
) {
|
||||
Button("Delete", role: .destructive) {
|
||||
if let uuid = idToDelete {
|
||||
print("deleting package.id: \(uuid)")
|
||||
Logger.app.info("deleting package.id: \(uuid)")
|
||||
|
||||
// use multiple expanded states?
|
||||
//expandedStates.removeValue(forKey: uuid)
|
||||
|
||||
|
|
@ -156,13 +158,13 @@ struct MainConfigView: View {
|
|||
packageInstallHelper = nil
|
||||
|
||||
if accepted {
|
||||
print("installing validated package: \(helper.packageName ?? "unknown package")")
|
||||
Logger.app.info("installing validated package: \(helper.packageName ?? "unknown package", privacy: .public)")
|
||||
do {
|
||||
try settings.installPackage()
|
||||
} catch {
|
||||
self.alertMessage = error.localizedDescription
|
||||
self.isShowingDropKmpAlert = true
|
||||
print("failed to install package: \(helper.packageName ?? "unknown package") with error: \(error.localizedDescription)")
|
||||
Logger.app.error("failed to install package: \(helper.packageName ?? "unknown package", privacy: .public), error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
settings.userCanceledPackageInstallation()
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@
|
|||
|
||||
import Foundation
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
|
||||
public enum InstallationPhase {
|
||||
public enum InstallationPhase: String {
|
||||
case inputMethodMissing
|
||||
case inputMethodOutdated
|
||||
case evaluatingInstallation
|
||||
|
|
@ -37,7 +38,7 @@ public enum InstallationPhase {
|
|||
}
|
||||
}
|
||||
|
||||
enum InstallationStateCondition {
|
||||
enum InstallationStateCondition: String {
|
||||
case stale
|
||||
case new
|
||||
case inProgress
|
||||
|
|
@ -112,8 +113,8 @@ public class InstallationCheck {
|
|||
// the input method is valid, examine the installation state recorded on disk
|
||||
//
|
||||
let installationStateCondition = InstallationCheck.evaluateInstallationState(state: installState, for: keymanVersion);
|
||||
print("installationStateCondition: \(installationStateCondition)")
|
||||
|
||||
Logger.app.log("installationStateCondition: \(installationStateCondition.rawValue, privacy: .public)")
|
||||
|
||||
switch installationStateCondition {
|
||||
case .inProgress:
|
||||
self.installationState = installState // resume with the existing installation
|
||||
|
|
@ -181,7 +182,7 @@ public class InstallationCheck {
|
|||
* for testing purposes, by specifying `kTestConfigVersion` in config app's standard UserDefaults
|
||||
*/
|
||||
static func isVersionCurrent(inputMethodVersion: String, configurationVersion: String) -> Bool {
|
||||
print("isVersionCurrent, comparing input method version: \(inputMethodVersion) and config app version: \(configurationVersion)")
|
||||
Logger.app.log("isVersionCurrent, comparing input method version: \(inputMethodVersion, privacy: .public) and config app version: \(configurationVersion, privacy: .public)")
|
||||
return inputMethodVersion == configurationVersion
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +191,8 @@ public class InstallationCheck {
|
|||
* checks the current state of Accessibility permissions
|
||||
*/
|
||||
func registerObservers() {
|
||||
print("InstallationCheck registerObservers")
|
||||
Logger.app.debug("InstallationCheck registerObservers")
|
||||
|
||||
DistributedNotificationCenter.default().addObserver(
|
||||
self,
|
||||
selector: #selector(self.handleAccessibilityResponse(_:)),
|
||||
|
|
@ -206,11 +208,12 @@ public class InstallationCheck {
|
|||
@objc func handleAccessibilityResponse(_ notification: Notification) {
|
||||
var installCompleted = false
|
||||
|
||||
print("handleAccessibilityResponse")
|
||||
// Extract message from the notification if available
|
||||
if let message = notification.object as? String {
|
||||
let permissionGranted = self.processAccessibilityResponse(with: message)
|
||||
|
||||
Logger.app.debug("handleAccessibilityResponse, message: \(message, privacy: .public)")
|
||||
|
||||
if let state = self.installationState {
|
||||
installCompleted = state.isComplete
|
||||
}
|
||||
|
|
@ -231,7 +234,7 @@ public class InstallationCheck {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
print("accessibilityStateResponse received but did not include message")
|
||||
Logger.app.debug("handleAccessibilityResponse, received but did not include message")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,8 +247,8 @@ public class InstallationCheck {
|
|||
.minute(.twoDigits)
|
||||
.second(.twoDigits)
|
||||
.secondFraction(.fractional(3))
|
||||
print("processAccessibilityResponse received message: \(message), time: \(Date().formatted(timeStyle))")
|
||||
|
||||
Logger.app.debug("processAccessibilityResponse received message: \(message, privacy: .public), time: \(Date().formatted(timeStyle), privacy: .public)")
|
||||
|
||||
// if the message indicates that access was granted, then return true
|
||||
return !message.isEmpty && message == kAccessibilityPermissionGrantedMessage
|
||||
}
|
||||
|
|
@ -313,8 +316,9 @@ public class InstallationCheck {
|
|||
* Creates a InstallationState object describing a new installation
|
||||
*/
|
||||
func createNewInstallationState(with neededTasks: Set<InstallationTask>) -> InstallationState {
|
||||
print("completeNewInstallationEvaluation: created new installation state")
|
||||
var fullTaskList = neededTasks
|
||||
Logger.app.debug("completeNewInstallationEvaluation: created new installation state")
|
||||
|
||||
var fullTaskList = neededTasks
|
||||
|
||||
// add prepareNewInstall InstallationTask
|
||||
fullTaskList.insert(InstallationTask.createNewInstallationTask(type: .prepareNewInstall))
|
||||
|
|
@ -331,10 +335,10 @@ public class InstallationCheck {
|
|||
func checkForRepair(accessibilityPermissionGranted: Bool) {
|
||||
// check whether the installation requires repair
|
||||
if let state = self.createRepairInstallationState(accessibilityPermissionGranted: accessibilityPermissionGranted) {
|
||||
print("checkForRepair completed: repair is required")
|
||||
Logger.app.log("checkForRepair completed: repair is required")
|
||||
self.applyRepairedInstallationState(state: state)
|
||||
} else {
|
||||
print("checkForRepair completed: no repair needed")
|
||||
Logger.app.log("checkForRepair completed: no repair needed")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
import SwiftUI
|
||||
import Combine
|
||||
import KeymanSettings
|
||||
import OSLog
|
||||
|
||||
// in-app notifications sent
|
||||
public extension Notification.Name {
|
||||
|
|
@ -40,10 +41,12 @@ public class InstallationContainer : ObservableObject {
|
|||
// create the settings repository, gaining access to the app group UserDefaults
|
||||
do {
|
||||
defaultsRepo = try DefaultsRepository(suiteName: InputMethodUtil.groupId)
|
||||
print("Found group container")
|
||||
Logger.app.log("found group container")
|
||||
} catch UserDefaultsError.unknownSuite {
|
||||
Logger.app.error("group container not found: \(UserDefaultsError.unknownSuite)")
|
||||
fatalError("Group container not found.")
|
||||
} catch {
|
||||
Logger.app.error("unable to access settings in group container: \(error as NSError, privacy: .public)")
|
||||
fatalError("Unable to access settings in group container.")
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +73,8 @@ public class InstallationContainer : ObservableObject {
|
|||
* register observers to learn of results of InstallationState evaluation
|
||||
*/
|
||||
func registerObservers() {
|
||||
print("InstallationContainer registerObservers")
|
||||
Logger.app.debug("InstallationContainer registerObservers")
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(self.handleStartNewInstallation(_:)),
|
||||
|
|
@ -101,7 +105,8 @@ public class InstallationContainer : ObservableObject {
|
|||
* called when `NSNotification.Name.startNewInstallation` is received
|
||||
*/
|
||||
@objc func handleStartNewInstallation(_ notification: Notification) {
|
||||
print("handleStartNewInstallation received")
|
||||
Logger.app.debug("handleStartNewInstallation received")
|
||||
|
||||
// the evaluation is done
|
||||
self.installationCheck.isEvaluatingNewInstallation = false
|
||||
}
|
||||
|
|
@ -110,7 +115,7 @@ public class InstallationContainer : ObservableObject {
|
|||
* called when `NSNotification.Name.startInstallationRepair` is received
|
||||
*/
|
||||
@objc func handleStartInstallationRepair(_ notification: Notification) {
|
||||
print("handleStartInstallationRepair received")
|
||||
Logger.app.debug("handleStartInstallationRepair received")
|
||||
|
||||
// notify observers
|
||||
NotificationCenter.default.post(name: .installationRepairStarted, object: nil, userInfo: nil)
|
||||
|
|
@ -180,7 +185,7 @@ public class InstallationContainer : ObservableObject {
|
|||
public func currentTask() -> InstallationTask? {
|
||||
guard let state = self.installationState else { return nil }
|
||||
guard self.installationPhase.hasTasks else {
|
||||
print("the installation phase \(self.installationPhase) has no tasks");
|
||||
Logger.app.error("the installation phase \(self.installationPhase.rawValue, privacy: .public) has no tasks")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +216,7 @@ public class InstallationContainer : ObservableObject {
|
|||
func executeTask(_ task: InstallationTask) {
|
||||
guard self.installationState != nil else { return }
|
||||
guard self.installationPhase.hasTasks else {
|
||||
print("the installation phase \(self.installationPhase) has no tasks");
|
||||
Logger.app.error("executeTask: the installation phase \(self.installationPhase.rawValue) has no tasks")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +252,7 @@ public class InstallationContainer : ObservableObject {
|
|||
* the property in InstallationCheck with the new reference.
|
||||
*/
|
||||
public func updateTaskAsCompleted(taskType: InstallationTaskType) {
|
||||
print("executeTask: \(taskType.rawValue) completed")
|
||||
Logger.app.debug("executeTask: \(taskType.rawValue, privacy: .public) completed")
|
||||
if let existingState = self.installationState {
|
||||
let updatedState = InstallationState.createCopyWithCompletedTask(from: existingState, with: taskType)
|
||||
self.installationCheck.installationState = updatedState
|
||||
|
|
@ -269,8 +274,8 @@ public class InstallationContainer : ObservableObject {
|
|||
*/
|
||||
public func migrateData() -> Bool {
|
||||
let success = self.inputMethodUtil.invokeKeymanInputMethodMigration()
|
||||
print("migration suceeded: \(success)")
|
||||
|
||||
Logger.app.debug("migration suceeded: \(success)")
|
||||
|
||||
// check whether
|
||||
if success {
|
||||
NotificationCenter.default.post(name: .dataMigrated, object: nil)
|
||||
|
|
@ -348,10 +353,10 @@ public class InstallationContainer : ObservableObject {
|
|||
if let timeRestartRequested = state.dateRestartRequested {
|
||||
if let mostRecentStartupTime = self.getMostRecentRestartTime() {
|
||||
hasRestarted = mostRecentStartupTime > timeRestartRequested
|
||||
print("mostRecentStartupTime: \(mostRecentStartupTime), timeRestartRequested: \(timeRestartRequested)")
|
||||
Logger.app.debug("mostRecentStartupTime: \(mostRecentStartupTime), timeRestartRequested: \(timeRestartRequested)")
|
||||
}
|
||||
}
|
||||
print("validateRestarted: \(hasRestarted)")
|
||||
Logger.app.debug("validateRestarted: \(hasRestarted)")
|
||||
return hasRestarted
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +391,7 @@ public class InstallationContainer : ObservableObject {
|
|||
let enabled = inputMethodUtil.isKeymanInputMethodEnabled()
|
||||
let running = inputMethodUtil.isKeymanInputMethodRunning()
|
||||
|
||||
print("Keyman status, version: \(version), enabled: \(enabled), running: \(running), permissionGranted: \(permissionString)")
|
||||
Logger.app.debug("Keyman status, version: \(version, privacy: .private), enabled: \(enabled), running: \(running), permissionGranted: \(permissionString)")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -394,7 +399,7 @@ public class InstallationContainer : ObservableObject {
|
|||
*/
|
||||
public func registerKeymanInputMethod() -> Bool {
|
||||
let success = self.inputMethodUtil.registerKeymanInputMethod()
|
||||
print("registerKeymanInputMethod suceeded: \(success)")
|
||||
Logger.app.debug("registerKeymanInputMethod suceeded: \(success)")
|
||||
|
||||
return success
|
||||
}
|
||||
|
|
@ -404,8 +409,8 @@ public class InstallationContainer : ObservableObject {
|
|||
*/
|
||||
public func selectKeymanInputMethod() -> Bool {
|
||||
let success = self.inputMethodUtil.selectKeymanInputMethod()
|
||||
print("selectKeymanInputMethod suceeded: \(success)")
|
||||
|
||||
Logger.app.debug("selectKeymanInputMethod suceeded: \(success)")
|
||||
|
||||
return success
|
||||
}
|
||||
|
||||
|
|
@ -426,7 +431,7 @@ public class InstallationContainer : ObservableObject {
|
|||
success = self.inputMethodUtil.enableKeymanInputMethod()
|
||||
}
|
||||
|
||||
print("enableKeymanInputMethod suceeded: \(success)")
|
||||
Logger.app.debug("enableKeymanInputMethod suceeded: \(success)")
|
||||
return success
|
||||
}
|
||||
|
||||
|
|
@ -445,8 +450,8 @@ public class InstallationContainer : ObservableObject {
|
|||
var requested = false
|
||||
|
||||
requested = self.inputMethodUtil.invokeKeymanInputMethodRequestAccess()
|
||||
print("requestAccessibility called, requested: \(requested)")
|
||||
|
||||
Logger.app.debug("requestAccessibility called, requested: \(requested)")
|
||||
|
||||
return requested
|
||||
}
|
||||
|
||||
|
|
@ -463,12 +468,4 @@ public class InstallationContainer : ObservableObject {
|
|||
public func disableKeymanInputMethod() -> Bool {
|
||||
return self.inputMethodUtil.disableKeymanInputMethod()
|
||||
}
|
||||
|
||||
/**
|
||||
* uninstall the Keyman Input Method
|
||||
* not functional with default security settings!
|
||||
*/
|
||||
public func uninstall() {
|
||||
self.inputMethodUtil.uninstallKeyman()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import OSLog
|
|||
|
||||
extension Logger {
|
||||
private static let settingsSubsystem = "com.keyman.settings"
|
||||
static let settings = Logger(subsystem: settingsSubsystem, category: "settings")
|
||||
static let setup = Logger(subsystem: settingsSubsystem, category: "setup")
|
||||
static let data = Logger(subsystem: settingsSubsystem, category: "data")
|
||||
}
|
||||
|
||||
public struct ConfigAppUtil {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,5 @@ public protocol DefaultsRepo {
|
|||
func writeEnabledKeyboards(enabledKeyboardsArray: [String])
|
||||
func readSelectedKeyboard() -> String
|
||||
func writeSelectedKeyboard(keyboardName: String)
|
||||
func logDefaults()
|
||||
func clearDefaults()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
import Foundation
|
||||
import Carbon.HIToolbox
|
||||
import AppKit
|
||||
import OSLog
|
||||
|
||||
public enum KeymanVersionCheckError: Error {
|
||||
case inputMethodNotFound
|
||||
|
|
@ -51,7 +52,7 @@ public class InputMethodUtil {
|
|||
*/
|
||||
public func keymanInputMethodExists() -> Bool {
|
||||
guard let inputMethodUrl = pathUtil.buildInputMethodPathUrl(fileName: self.keymanInputMethodApplicationName) else {
|
||||
print("Keyman input method not found, failed to create input method url")
|
||||
Logger.setup.log("Keyman input method not found, failed to create input method url")
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -117,13 +118,13 @@ public class InputMethodUtil {
|
|||
|
||||
/**
|
||||
* uninstalls the Keyman input method
|
||||
* note: not useful to expose to users as default security systems prevent us from deleting the app
|
||||
* note: commenting out for now as default security settings prevent us from deleting the app
|
||||
*/
|
||||
public func uninstallKeyman() {
|
||||
_ = self.killKeymanInputMethod()
|
||||
_ = self.disableKeymanInputMethod()
|
||||
self.deleteKeyman()
|
||||
}
|
||||
// public func uninstallKeyman() {
|
||||
// _ = self.killKeymanInputMethod()
|
||||
// _ = self.disableKeymanInputMethod()
|
||||
// self.deleteKeyman()
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns version number string for the specifed app located at `~/Library/Input Methods`
|
||||
|
|
@ -144,7 +145,7 @@ public class InputMethodUtil {
|
|||
guard let appVersionString = infoDictionary["CFBundleShortVersionString"] as? String else {
|
||||
throw KeymanVersionCheckError.versionNotFound
|
||||
}
|
||||
|
||||
|
||||
return appVersionString
|
||||
}
|
||||
|
||||
|
|
@ -167,15 +168,13 @@ public class InputMethodUtil {
|
|||
}
|
||||
|
||||
public func invokeKeymanInputMethodMigration() -> Bool {
|
||||
print("invokeKeymanInputMethodMigration()")
|
||||
Logger.setup.log("invokeKeymanInputMethodMigration()")
|
||||
return self.invokeKeymanInputMethodAsSubProcess(argument: kMigrateCommand) == 0
|
||||
}
|
||||
|
||||
public func invokeKeymanInputMethodRequestAccess() -> Bool {
|
||||
var success = false
|
||||
do {
|
||||
print("invokeKeymanInputMethodRequestAccess()")
|
||||
|
||||
// because we are launching Keyman with a specific command line argument
|
||||
// for this request, we must kill it first
|
||||
_ = self.killKeymanInputMethod()
|
||||
|
|
@ -183,7 +182,7 @@ public class InputMethodUtil {
|
|||
try self.launchKeymanInputMethodAsSeparateProcess(argument: kAccessCommand)
|
||||
success = true
|
||||
} catch {
|
||||
print("error requesting access: \(error)")
|
||||
Logger.setup.error("error requesting Accessibility from input method: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
|
||||
return success
|
||||
|
|
@ -197,8 +196,8 @@ public class InputMethodUtil {
|
|||
* It contains a message with a value of `granted` or `not-granted`
|
||||
*/
|
||||
func invokeKeymanInputMethodCheckAccess() throws {
|
||||
print("invokeKeymanInputMethodCheckAccess()")
|
||||
|
||||
Logger.setup.info("invokeKeymanInputMethodCheckAccess()")
|
||||
|
||||
// because we are launching Keyman with a specific command line argument
|
||||
// for this request, we must kill it first
|
||||
_ = self.killKeymanInputMethod()
|
||||
|
|
@ -214,13 +213,12 @@ public class InputMethodUtil {
|
|||
let process = Process()
|
||||
if let executableUrl = self.pathUtil.buildInputMethodExecutableUrl(fileName: self.keymanInputMethodApplicationName) {
|
||||
process.executableURL = executableUrl
|
||||
print("invoking Keyman at: \(String(describing: process.executableURL))")
|
||||
Logger.setup.info("invoking Keyman at: \(String(describing: process.executableURL), privacy: .public)")
|
||||
process.arguments = [argument]
|
||||
}
|
||||
|
||||
var currentEnv = ProcessInfo.processInfo.environment
|
||||
print("current env: \(String(describing: currentEnv))")
|
||||
|
||||
|
||||
currentEnv["__CFBundleIdentifier"] = InputMethodUtil.keymanBundleId // set bundle ID to that of the Keyman input method
|
||||
process.environment = currentEnv
|
||||
|
||||
|
|
@ -229,10 +227,9 @@ public class InputMethodUtil {
|
|||
process.waitUntilExit() // wait for it to finish
|
||||
result = Int(process.terminationStatus)
|
||||
} catch {
|
||||
print("Failed to run process: \(error)")
|
||||
Logger.setup.error("Failed to run process: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
|
||||
print("invokeKeymanInputMethod() result: \(result)")
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
@ -246,16 +243,13 @@ public class InputMethodUtil {
|
|||
}
|
||||
|
||||
guard let inputMethodUrl = pathUtil.buildInputMethodPathUrl(fileName: self.keymanInputMethodApplicationName) else {
|
||||
print("launchKeymanInputMethodAsSeparateProcess, failed to create input method url")
|
||||
Logger.setup.error("launchKeymanInputMethodAsSeparateProcess, failed to create input method url")
|
||||
throw KeymanInvocationError.inputMethodNotFound
|
||||
}
|
||||
|
||||
NSWorkspace.shared.openApplication(at: inputMethodUrl, configuration: openConfig) { (app, error) in
|
||||
if let error = error {
|
||||
print("Could not launch Keyman input method at \(inputMethodUrl), due to error: \(error.localizedDescription), code: \(error._code)")
|
||||
Thread.callStackSymbols.forEach { symbol in
|
||||
print(symbol)
|
||||
}
|
||||
Logger.setup.error("Could not launch Keyman input method at \(inputMethodUrl), due to error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -268,7 +262,7 @@ public class InputMethodUtil {
|
|||
do {
|
||||
try self.invokeKeymanInputMethodCheckAccess()
|
||||
} catch {
|
||||
print("invoking Keyman failed: \(error.localizedDescription)")
|
||||
Logger.setup.error("invoking Keyman failed: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
|
||||
let timeStyle = Date.FormatStyle()
|
||||
|
|
@ -276,7 +270,7 @@ public class InputMethodUtil {
|
|||
.minute(.twoDigits)
|
||||
.second(.twoDigits)
|
||||
.secondFraction(.fractional(3))
|
||||
print("doAsyncAccessibilityCheck, listening across process boundaries, time: \(Date().formatted(timeStyle))")
|
||||
Logger.setup.log("doAsyncAccessibilityCheck, listening across process boundaries, time: \(Date().formatted(timeStyle))")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,11 +281,11 @@ public class InputMethodUtil {
|
|||
let runningApps = NSRunningApplication.runningApplications(withBundleIdentifier: bundleId)
|
||||
var didTerminate = false
|
||||
|
||||
print("Running app count for \(bundleId) = \(runningApps.count)")
|
||||
Logger.setup.debug("Running app count for \(bundleId, privacy: .public) = \(runningApps.count)")
|
||||
if let runningApp = runningApps.first {
|
||||
let processId = runningApp.processIdentifier
|
||||
didTerminate = runningApp.terminate()
|
||||
print("process \(processId) for \(bundleId) was terminated: \(didTerminate)")
|
||||
Logger.setup.log("process \(processId) for \(bundleId, privacy: .public) was terminated: \(didTerminate)")
|
||||
}
|
||||
|
||||
return didTerminate
|
||||
|
|
@ -314,8 +308,8 @@ public class InputMethodUtil {
|
|||
let inputSourceList = TISCreateInputSourceList(properties as CFDictionary, true)
|
||||
guard let sources = inputSourceList?.takeRetainedValue() as? [TISInputSource],
|
||||
let targetSource = sources.first else {
|
||||
print("Error: Could not find the specified input source.")
|
||||
return(nil)
|
||||
Logger.setup.error("Could not find the specified input source with bundleID: \(bundleId, privacy: .public)")
|
||||
return(nil)
|
||||
}
|
||||
|
||||
return targetSource
|
||||
|
|
@ -333,44 +327,19 @@ public class InputMethodUtil {
|
|||
// Bridge the CFTypeRef to an Unmanaged<AnyObject> and then to a Swift String
|
||||
if let inputMethodEnabled = Unmanaged<AnyObject>.fromOpaque(cfType).takeUnretainedValue() as? Bool {
|
||||
enabled = inputMethodEnabled
|
||||
print("is enabled: \(enabled)")
|
||||
Logger.setup.info("isInputMethodEnabled: \(enabled)")
|
||||
} else {
|
||||
print("could not read retrieved enabled property for bundleId: \(bundleId)")
|
||||
Logger.setup.error("Could not read retrieved enabled property for bundleId: \(bundleId, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
print("Failed to get enabled property for bundleId: \(bundleId)")
|
||||
Logger.setup.error("Failed to get enabled property for bundleId: \(bundleId, privacy: .public)")
|
||||
}
|
||||
} else {
|
||||
print("Failed to get input source for bundleId: \(bundleId)")
|
||||
Logger.setup.error("Failed to get input source for bundleId: \(bundleId, privacy: .public)")
|
||||
}
|
||||
return enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if the input method with the specified bundleId is capable of being enabled
|
||||
*/
|
||||
func isInputMethodEnableCapable(bundleId: String) -> Bool {
|
||||
var enableCapable = false
|
||||
|
||||
if let inputSource = self.getInputSource(bundleId: bundleId) {
|
||||
let enableCapableValue = TISGetInputSourceProperty(inputSource, kTISPropertyInputSourceIsEnableCapable)
|
||||
if let cfType = enableCapableValue {
|
||||
// Bridge the CFTypeRef to an Unmanaged<AnyObject> and then to a Swift String
|
||||
if let capable = Unmanaged<AnyObject>.fromOpaque(cfType).takeUnretainedValue() as? Bool {
|
||||
enableCapable = capable
|
||||
print("is enable capable: \(enableCapable)")
|
||||
} else {
|
||||
print("could not read retrieved enable capable property for bundleId: \(bundleId)")
|
||||
}
|
||||
} else {
|
||||
print("Failed to get enable capable property for bundleId: \(bundleId)")
|
||||
}
|
||||
} else {
|
||||
print("Failed to get input source for bundleId: \(bundleId)")
|
||||
}
|
||||
return enableCapable
|
||||
}
|
||||
|
||||
/**
|
||||
* register the newly installed input method with the specified bundleId
|
||||
* this will allow a `TISInputSourceRef` to be obtained to access the input source
|
||||
|
|
@ -379,7 +348,7 @@ public class InputMethodUtil {
|
|||
var success = false
|
||||
|
||||
guard let inputMethodUrl = pathUtil.buildInputMethodPathUrl(fileName: self.keymanInputMethodApplicationName) else {
|
||||
print("registerInputMethod, failed to create input method url")
|
||||
Logger.setup.error("registerInputMethod, failed to create input method url for bundleId: \(bundleId, privacy: .public)")
|
||||
return false
|
||||
}
|
||||
let cfUrl = inputMethodUrl as CFURL
|
||||
|
|
@ -388,9 +357,9 @@ public class InputMethodUtil {
|
|||
success = result == noErr
|
||||
|
||||
if (success) {
|
||||
print("registerInputMethod for bundle ID '\(bundleId)': success")
|
||||
Logger.setup.log("registerInputMethod for bundle ID '\(bundleId, privacy: .public)': success")
|
||||
} else {
|
||||
print("registerInputMethod for bundle ID '\(bundleId)' failed, result = \(result)")
|
||||
Logger.setup.error("registerInputMethod for bundle ID '\(bundleId, privacy: .public)' failed, result = \(result)")
|
||||
}
|
||||
|
||||
return success
|
||||
|
|
@ -405,9 +374,9 @@ public class InputMethodUtil {
|
|||
let result = TISEnableInputSource(inputSource)
|
||||
success = result == noErr
|
||||
if (success) {
|
||||
print("enableInputMethod for bundle ID '\(bundleId)': success")
|
||||
Logger.setup.log("enableInputMethod for bundle ID '\(bundleId, privacy: .public)': success")
|
||||
} else {
|
||||
print("enableInputMethod for bundle ID '\(bundleId)' failed, result = \(result)")
|
||||
Logger.setup.error("enableInputMethod for bundle ID '\(bundleId, privacy: .public)' failed, result = \(result)")
|
||||
}
|
||||
}
|
||||
return success
|
||||
|
|
@ -422,27 +391,31 @@ public class InputMethodUtil {
|
|||
let result = TISDisableInputSource(inputSource)
|
||||
success = result == noErr
|
||||
if (success) {
|
||||
print("disableInputMethod for bundle ID '\(bundleId)': success")
|
||||
Logger.setup.log("disableInputMethod for bundle ID '\(bundleId, privacy: .public)': success")
|
||||
} else {
|
||||
print("disableInputMethod for bundle ID '\(bundleId)' failed, result = \(result)")
|
||||
Logger.setup.error("disableInputMethod for bundle ID '\(bundleId, privacy: .public)' failed, result = \(result)")
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
func deleteKeyman() {
|
||||
let fileManager = FileManager.default
|
||||
if let keymanFile = self.pathUtil.buildInputMethodPathUrl(fileName: keymanInputMethodApplicationName) {
|
||||
do {
|
||||
try fileManager.removeItem(at: keymanFile)
|
||||
print("Successfully deleted Keyman.app")
|
||||
} catch {
|
||||
print("Error deleting Keyman.app: \(error)")
|
||||
}
|
||||
} else {
|
||||
print("Keyman.app not found")
|
||||
}
|
||||
}
|
||||
/**
|
||||
* deletes the Keyman input method
|
||||
* note: commenting out for now as default security settings prevent us from deleting the app
|
||||
*/
|
||||
// func deleteKeyman() {
|
||||
// let fileManager = FileManager.default
|
||||
// if let keymanFile = self.pathUtil.buildInputMethodPathUrl(fileName: keymanInputMethodApplicationName) {
|
||||
// do {
|
||||
// try fileManager.removeItem(at: keymanFile)
|
||||
// print("Successfully deleted Keyman.app")
|
||||
// } catch {
|
||||
// print("Error deleting Keyman.app: \(error)")
|
||||
// }
|
||||
// } else {
|
||||
// print("Keyman.app not found")
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* select the input source with the specified input source id and return true if successful
|
||||
|
|
@ -454,16 +427,16 @@ public class InputMethodUtil {
|
|||
let inputSourceList = TISCreateInputSourceList(properties as CFDictionary, false)
|
||||
guard let sources = inputSourceList?.takeRetainedValue() as? [TISInputSource],
|
||||
let targetSource = sources.first else {
|
||||
print("Error: Could not find the input source '\(inputSourceId)'.")
|
||||
Logger.setup.error("Error: Could not find the input source '\(inputSourceId, privacy: .public)'.")
|
||||
return false
|
||||
}
|
||||
|
||||
let result = TISSelectInputSource(targetSource)
|
||||
if result != noErr {
|
||||
print("Error selecting input source '\(inputSourceId)': \(result)")
|
||||
return false
|
||||
Logger.setup.error("Error selecting input source '\(inputSourceId, privacy: .public)'.")
|
||||
return false
|
||||
} else {
|
||||
print("Successfully selected input source '\(inputSourceId)'.")
|
||||
Logger.setup.log("Successfully selected input source '\(inputSourceId, privacy: .public)'.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
import Foundation
|
||||
import Combine
|
||||
import ZIPFoundation
|
||||
import OSLog
|
||||
|
||||
public enum InstallPackageError: LocalizedError {
|
||||
case packageInstallationAlreadyInProgress
|
||||
|
|
@ -116,7 +117,7 @@ public class SettingsContainer : ObservableObject {
|
|||
let languageQueryItem = URLQueryItem(name:"lang", value: languageString)
|
||||
searchUrl.append(queryItems:[languageQueryItem])
|
||||
}
|
||||
print("full searchUrl: \(searchUrl.absoluteString)")
|
||||
Logger.setup.info("full searchUrl: \(searchUrl.absoluteString, privacy: .public)")
|
||||
return searchUrl
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +132,7 @@ public class SettingsContainer : ObservableObject {
|
|||
var primaryLanguage: String?
|
||||
if let language = systemLanguages.first {
|
||||
primaryLanguage = language
|
||||
print("primary system language: \(String(describing: primaryLanguage))")
|
||||
Logger.setup.info("primary system language: \(language, privacy: .public)")
|
||||
}
|
||||
|
||||
return primaryLanguage
|
||||
|
|
@ -146,20 +147,24 @@ public class SettingsContainer : ObservableObject {
|
|||
// create the package repository, gaining access to the app group container directory
|
||||
do {
|
||||
try self.packageRepository = PackageRepository()
|
||||
print("Found documents group container")
|
||||
Logger.data.log("Found documents group container")
|
||||
} catch KeymanPathError.groupContainerNotFound {
|
||||
Logger.data.error("Document group container not found")
|
||||
fatalError("Document group container not found.")
|
||||
} catch {
|
||||
Logger.data.error("Unable to access documents in group container, error \(error as NSError, privacy: .public)")
|
||||
fatalError("Unable to access documents in group container.")
|
||||
}
|
||||
|
||||
// create the settings repository, gaining access to the app group UserDefaults
|
||||
do {
|
||||
try self.defaultsRepository = DefaultsRepository(suiteName: InputMethodUtil.groupId)
|
||||
print("Found defaults group container")
|
||||
Logger.data.log("Found defaults group container")
|
||||
} catch UserDefaultsError.unknownSuite {
|
||||
Logger.data.error("Defaults group container not found")
|
||||
fatalError("Defaults group container not found.")
|
||||
} catch {
|
||||
Logger.data.error("Unable to access defaults in group container, error \(error as NSError, privacy: .public)")
|
||||
fatalError("Unable to access defaults in group container: \(error.localizedDescription).")
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +251,7 @@ public class SettingsContainer : ObservableObject {
|
|||
* Called when user chooses to cancel downgrade of package
|
||||
*/
|
||||
public func userCanceledPackageInstallation() {
|
||||
print("user cancelled package installation")
|
||||
Logger.data.log("User cancelled package installation")
|
||||
self.packageInstall?.cleanupFailedInstallation()
|
||||
|
||||
self.packageInstall = nil
|
||||
|
|
@ -256,7 +261,7 @@ public class SettingsContainer : ObservableObject {
|
|||
* Called when user chooses to cancel downgrade of package
|
||||
*/
|
||||
public func packageInstallationFailed() {
|
||||
print("packageInstallationFailed")
|
||||
Logger.data.log("Package installation failed")
|
||||
self.packageInstall?.cleanupFailedInstallation()
|
||||
|
||||
self.packageInstall = nil
|
||||
|
|
@ -284,7 +289,7 @@ public class SettingsContainer : ObservableObject {
|
|||
*/
|
||||
public func findInstalledPackage(with id: UUID) -> KeymanPackage? {
|
||||
guard let package = self.installedPackages.first(where: { $0.id == id }) else {
|
||||
print ("Error: could not find package with UUID: \(id)")
|
||||
Logger.setup.error("error: could not find package with UUID: \(id)")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -297,8 +302,6 @@ public class SettingsContainer : ObservableObject {
|
|||
public func removeInstalledPackage(with id: UUID) {
|
||||
if let package = findInstalledPackage(with: id) {
|
||||
self.removeInstalledPackage(package: package)
|
||||
} else {
|
||||
print("could not find package with id: \(id)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +332,7 @@ public class SettingsContainer : ObservableObject {
|
|||
*/
|
||||
public func isKeyboardEnabled(packageId: UUID, keyboardKey: String) -> Bool {
|
||||
guard let package = self.findInstalledPackage(with: packageId) else {
|
||||
print ("Could not read keyboard state for package: \(packageId) and keyboard: \(keyboardKey)")
|
||||
Logger.setup.error("isKeyboardEnabled, not read keyboard state for package: \(packageId) and keyboard: \(keyboardKey, privacy: .public)")
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -342,11 +345,11 @@ public class SettingsContainer : ObservableObject {
|
|||
*/
|
||||
public func setKeyboardEnabled(packageId: UUID, keyboardKey: String, enabled: Bool) {
|
||||
guard let package = self.findInstalledPackage(with: packageId) else {
|
||||
print ("Could not read keyboard state for package: \(packageId) and keyboard: \(keyboardKey)")
|
||||
Logger.setup.error("setKeyboardEnabled, could not read keyboard state for package: \(packageId) and keyboard: \(keyboardKey, privacy: .public)")
|
||||
return
|
||||
}
|
||||
|
||||
print ("setKeyboardEnabled for \(keyboardKey) setting to \(enabled)")
|
||||
Logger.setup.info("setKeyboardEnabled for \(keyboardKey, privacy: .public) setting to \(enabled)")
|
||||
package.enableKeyboard(keyboardKey: keyboardKey, enabled: enabled)
|
||||
|
||||
// update persisted state in UserDefaults enabledKeyboards array
|
||||
|
|
@ -410,9 +413,9 @@ public class SettingsContainer : ObservableObject {
|
|||
let enabledKeyboardKeys = self.defaultsRepository.readEnabledKeyboards()
|
||||
|
||||
if (enabledKeyboardKeys.isSubset(of: installedKeyboardKeys)) {
|
||||
print("only installed keyboards are listed as enabled: no need to update defaults")
|
||||
Logger.setup.info("only installed keyboards are listed as enabled: no need to update defaults")
|
||||
} else {
|
||||
print("enabled keyboards list contains uninstalled keyboards: align with enabled keyboards list")
|
||||
Logger.setup.info("enabled keyboards list contains uninstalled keyboards: align with enabled keyboards list")
|
||||
let installedEnabledKeyboardKeys = enabledKeyboardKeys.intersection(installedKeyboardKeys)
|
||||
self.defaultsRepository.writeEnabledKeyboards(enabledKeyboardsArray: Array(installedEnabledKeyboardKeys))
|
||||
}
|
||||
|
|
@ -472,7 +475,7 @@ public class SettingsContainer : ObservableObject {
|
|||
* Delegates to the PackageInstallHelper instance to decide whether the package should be installed.
|
||||
*/
|
||||
public func packageDownloadComplete(kmpFileUrl: URL) throws {
|
||||
print ("packageDownloadComplete \(kmpFileUrl)")
|
||||
Logger.setup.info("packageDownloadComplete \(kmpFileUrl, privacy: .public)")
|
||||
|
||||
do {
|
||||
try self.packageInstall?.prepareToInstall(for: kmpFileUrl)
|
||||
|
|
@ -505,7 +508,7 @@ public class SettingsContainer : ObservableObject {
|
|||
self.installedPackages[index] = package
|
||||
self.addEnabledKeyboards(for: package)
|
||||
} else {
|
||||
print("Error: package '\(package.packageName)' not found for replacement")
|
||||
Logger.setup.error("Error: package '\(package.packageName, privacy: .public)' not found for replacement")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
import Foundation
|
||||
import AppKit
|
||||
import OSLog
|
||||
|
||||
public class Keyboard: Identifiable, Hashable, Equatable {
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ public class Keyboard: Identifiable, Hashable, Equatable {
|
|||
public func validateKmxFile(in packageDirectory: URL) throws {
|
||||
let kmxFilePath = self.deriveKmxFileUrl(from: packageDirectory).path
|
||||
if !FileManager.default.fileExists(atPath: kmxFilePath) {
|
||||
print("** error: could not find kmx file \(kmxFilePath)")
|
||||
Logger.data.error("error: could not find kmx file \(kmxFilePath, privacy: .public)")
|
||||
throw LoadPackageError.missingKmxFile
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import AppKit
|
|||
import Cocoa
|
||||
import CoreImage
|
||||
import CoreImage.CIFilterBuiltins
|
||||
import OSLog
|
||||
|
||||
public class KeymanPackage: Identifiable, Hashable, Equatable {
|
||||
static let defaultImage: NSImage? = {
|
||||
|
|
@ -19,7 +20,7 @@ public class KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
if let imageUrl = Bundle.module.url(forResource: "SideImage", withExtension: "bmp") {
|
||||
image = NSImage(contentsOf: imageUrl)
|
||||
} else {
|
||||
print("Error: Could not find SideImage.bmp in the module bundle.")
|
||||
Logger.setup.error("error: could not find SideImage.bmp in the module bundle")
|
||||
}
|
||||
return image
|
||||
}()
|
||||
|
|
@ -231,7 +232,7 @@ public class KeymanPackage: Identifiable, Hashable, Equatable {
|
|||
if comparisonResult == .orderedAscending {
|
||||
// keyman version is too old
|
||||
meetsRequiredVersion = false
|
||||
print("for package '\(self.packageName)' keyman version \(keymanVersion) is older than required version \(minimumKeymanVersion)")
|
||||
Logger.data.log("validateKeymanVersionForPackage for package: '\(self.packageName, privacy: .public)' keyman version \(keymanVersion, privacy: .public) is older than required version \(minimumKeymanVersion, privacy: .public)")
|
||||
} else {
|
||||
meetsRequiredVersion = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,22 +151,6 @@ public class DefaultsRepository: DefaultsRepo {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* for debugging: prints UserDefaults values to the console
|
||||
* with app group UserDefaults, there is no way to view from the command line
|
||||
* (unlike standard application-level UserDefaults)
|
||||
*/
|
||||
public func logDefaults() {
|
||||
print("UserDefaults:")
|
||||
print("\(kSelectedKeyboardKey): \(self.readSelectedKeyboard())")
|
||||
print("\(kDataModelVersionKey): \(self.readDataModelVersion())")
|
||||
print("\(kForceSentryErrorKey): \(self.readForceSentryError())")
|
||||
print("\(kShowOskOnActivateKey): \(self.readShowOskOnActivate())")
|
||||
print("\(kEnabledKeyboardsKey): \(self.readEnabledKeyboards())")
|
||||
print("\(kPersistedOptionsKey): \(self.readPersistedOptions())")
|
||||
print("\(kInstallationState): \(self.readInstallationState()?.description ?? "nil")")
|
||||
}
|
||||
|
||||
/**
|
||||
* for debugging: clear all the entries for the app group UserDefaults
|
||||
* unlike standard application-level UserDefaults, there is no way to view from the command line
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
|
||||
/**
|
||||
* Three directory trees are represented by the following properties, one in active use
|
||||
|
|
@ -52,7 +53,7 @@ public struct KeymanPaths {
|
|||
do {
|
||||
try fileManager.createDirectory(at: fontsDirectory, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
print("error: could not create fonts directory: \(error.localizedDescription)")
|
||||
Logger.setup.error("error: could not create fonts directory: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,23 +108,21 @@ public struct KeymanPaths {
|
|||
self.keyman19PackagesDirectory = KeymanPaths.buildKeyman19PackagesUrl(container: containerDir)
|
||||
self.keyman19TempDirectory = KeymanPaths.buildKeyman19TempUrl(container: containerDir)
|
||||
|
||||
//self.logPaths()
|
||||
self.logPaths()
|
||||
}
|
||||
|
||||
/*
|
||||
fileprivate func logPaths() {
|
||||
ConfigLogger.shared.testLogger.debug("documents: \(self.keyman17DocumentsDirectory!.absoluteString)")
|
||||
ConfigLogger.shared.testLogger.debug("keyman 17 packages: \(self.keyman17PackagesDirectory!.absoluteString)")
|
||||
|
||||
ConfigLogger.shared.testLogger.debug("support directory: \(self.keyman18SupportDirectory!.absoluteString)")
|
||||
ConfigLogger.shared.testLogger.debug("support keyman directory: \(self.keyman18DataDirectory!.absoluteString)")
|
||||
ConfigLogger.shared.testLogger.debug("keyman 18 packages: \(self.keyman18PackagesDirectory!.absoluteString)")
|
||||
|
||||
ConfigLogger.shared.testLogger.debug("container: \(self.keyman19ContainerDirectory!.absoluteString)")
|
||||
ConfigLogger.shared.testLogger.debug("preferences: \(self.keyman19PreferencesDirectory!.absoluteString)")
|
||||
ConfigLogger.shared.testLogger.debug("keyman 19 packages: \(self.keyman19PackagesDirectory!.absoluteString)")
|
||||
}
|
||||
*/
|
||||
fileprivate func logPaths() {
|
||||
Logger.setup.debug("documents: \(self.keyman17DocumentsDirectory!.absoluteString)")
|
||||
Logger.setup.debug("keyman 17 packages: \(self.keyman17PackagesDirectory!.absoluteString)")
|
||||
|
||||
Logger.setup.debug("support directory: \(self.keyman18SupportDirectory!.absoluteString)")
|
||||
Logger.setup.debug("support keyman directory: \(self.keyman18DataDirectory!.absoluteString)")
|
||||
Logger.setup.debug("keyman 18 packages: \(self.keyman18PackagesDirectory!.absoluteString)")
|
||||
|
||||
Logger.setup.debug("container: \(self.keyman19ContainerDirectory.absoluteString)")
|
||||
Logger.setup.debug("preferences: \(self.keyman19PreferencesDirectory.absoluteString)")
|
||||
Logger.setup.debug("keyman 19 packages: \(self.keyman19PackagesDirectory.absoluteString)")
|
||||
}
|
||||
|
||||
/**
|
||||
* build the URL to specified file in the Input Methods directory
|
||||
|
|
@ -142,8 +141,7 @@ public struct KeymanPaths {
|
|||
inputMethodUrl = inputMethodDirectoryUrl.appendingPathComponent(fileName, isDirectory: false)
|
||||
return inputMethodUrl
|
||||
} catch {
|
||||
// ConfigLogger.shared.testLogger.debug("\(error)")
|
||||
print("\(error)")
|
||||
Logger.setup.error("buildInputMethodPathUrl error: \(error as NSError, privacy: .public)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +154,7 @@ public struct KeymanPaths {
|
|||
let executableName = inputMethodUrl.deletingPathExtension().lastPathComponent
|
||||
return inputMethodUrl.appendingPathComponent("Contents/MacOS/\(executableName)")
|
||||
} else {
|
||||
Logger.setup.error("buildInputMethodExecutableUrl error: could not build input method executable directory")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -175,7 +174,7 @@ public struct KeymanPaths {
|
|||
)
|
||||
return documentsDirectoryUrl
|
||||
} catch {
|
||||
print("\(error)")
|
||||
Logger.setup.error("buildDocumentsUrl error: \(error as NSError, privacy: .public)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -187,7 +186,7 @@ public struct KeymanPaths {
|
|||
if let keyman17PackagesDirectory = documents?.appendingPathComponent(preKeyman19PackagesDirectoryName, isDirectory: true) {
|
||||
return keyman17PackagesDirectory
|
||||
} else {
|
||||
print("could not build keyman17 packages directory")
|
||||
Logger.setup.error("buildKeyman17PackagesUrl error: could not build keyman17 packages directory")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +207,7 @@ public struct KeymanPaths {
|
|||
|
||||
return supportDirectoryUrl
|
||||
} catch {
|
||||
print("\(error)")
|
||||
Logger.setup.error("buildSupportDirectory error: \(error as NSError, privacy: .public)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
import Foundation
|
||||
import CoreText
|
||||
import OSLog
|
||||
|
||||
public enum PackageInstallationType {
|
||||
case newPackage(String)
|
||||
|
|
@ -69,8 +70,8 @@ public class PackageInstallHelper: Identifiable {
|
|||
* Indicates that a package has been downloaded and can be prepared for installation
|
||||
*/
|
||||
public func packageDownloadComplete(for kmpFileUrl: URL) throws {
|
||||
print ("packageDownloadComplete \(kmpFileUrl)")
|
||||
|
||||
Logger.data.log("packageDownloadComplete \(kmpFileUrl.path, privacy: .public)")
|
||||
|
||||
try self.prepareToInstall(for: kmpFileUrl)
|
||||
}
|
||||
|
||||
|
|
@ -79,8 +80,8 @@ public class PackageInstallHelper: Identifiable {
|
|||
*
|
||||
*/
|
||||
public func prepareToInstall(for kmpFileUrl: URL) throws {
|
||||
print ("prepareToInstall \(kmpFileUrl)")
|
||||
|
||||
Logger.data.log("prepareToInstall \(kmpFileUrl.path, privacy: .public)")
|
||||
|
||||
do {
|
||||
// unzip to the temp directory
|
||||
try self.packageRepository.unzipKmpFile(at: kmpFileUrl, to: self.temporaryPackageLocation)
|
||||
|
|
@ -103,7 +104,7 @@ public class PackageInstallHelper: Identifiable {
|
|||
self.packageInstallationType = self.determinePackageInstallationType(newPackage: package)
|
||||
} catch {
|
||||
self.cleanupFailedInstallation()
|
||||
print ("package installation failed with error '\(error)' for \(kmpFileUrl)")
|
||||
Logger.data.error("package installation failed for \(kmpFileUrl) with error: \(error as NSError, privacy: .public)")
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -112,11 +113,11 @@ public class PackageInstallHelper: Identifiable {
|
|||
* Install the new package and replace existing package if necessary
|
||||
*/
|
||||
public func installPackage() throws {
|
||||
print ("installPackage \(self.packageToInstall?.packageName ?? "unknown package")")
|
||||
Logger.data.info ("installPackage \(self.packageToInstall?.packageName ?? "unknown package", privacy: .public)")
|
||||
|
||||
// prepareToInstall will always set this
|
||||
guard let installationType = self.packageInstallationType else {
|
||||
print("error: installationType not set before call to installPackage")
|
||||
Logger.data.error("error: installationType not set before call to installPackage")
|
||||
throw InstallPackageError.internalError
|
||||
}
|
||||
|
||||
|
|
@ -145,13 +146,13 @@ public class PackageInstallHelper: Identifiable {
|
|||
let comparisonResult = newVersion.compare(existingVersion, options: .numeric)
|
||||
|
||||
if comparisonResult == .orderedAscending {
|
||||
print("package downgrade: new version is older than existing version")
|
||||
Logger.data.info("package downgrade: new version is older than existing version")
|
||||
installationType = PackageInstallationType.replaceNewerPackage(newPackage.packageName, existingVersion, newVersion)
|
||||
} else if comparisonResult == .orderedDescending {
|
||||
print("package upgrade: new version is newer than existing version")
|
||||
Logger.data.info("package upgrade: new version is newer than existing version")
|
||||
installationType = PackageInstallationType.replaceOlderPackage(newPackage.packageName, existingVersion, newVersion)
|
||||
} else {
|
||||
print("new and existing package versions are identical")
|
||||
Logger.data.info("new and existing package versions are identical")
|
||||
installationType = PackageInstallationType.replaceSameVersionPackage(newPackage.packageName)
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +169,7 @@ public class PackageInstallHelper: Identifiable {
|
|||
let fileManager = FileManager.default
|
||||
|
||||
guard let installLocation = self.installPackageLocation else {
|
||||
print("error: installPackageLocation not set when installing fonts")
|
||||
Logger.data.error("error: installPackageLocation not set when installing fonts")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +180,7 @@ public class PackageInstallHelper: Identifiable {
|
|||
includingPropertiesForKeys: [.isDirectoryKey],
|
||||
options: [.skipsHiddenFiles]) }
|
||||
catch {
|
||||
print("error: unable to get contents of directory at \(installLocation.path) with error: \(String(describing: error))")
|
||||
Logger.data.error("error: unable to get contents of package fonts directory at \(installLocation.path, privacy: .public) with error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
|
||||
for fontUrl in fileUrls {
|
||||
|
|
@ -187,14 +188,14 @@ public class PackageInstallHelper: Identifiable {
|
|||
if ext == "ttf" || ext == "otf" {
|
||||
// if a font fails to install, log error and continue
|
||||
guard self.validateFont(at: fontUrl) else {
|
||||
print("error: the font \(fontUrl.lastPathComponent) is not valid")
|
||||
Logger.data.error("error: the font \(fontUrl.lastPathComponent, privacy: .public) is not valid")
|
||||
continue
|
||||
}
|
||||
do {
|
||||
try self.copyFontToFontsDirectory(at: fontUrl)
|
||||
try self.registerFontWithSystem(at: fontUrl)
|
||||
} catch {
|
||||
print("error: the font \(fontUrl.lastPathComponent) could not be installed with error: \(String(describing: error))")
|
||||
Logger.data.error("error: the font \(fontUrl.lastPathComponent, privacy: .public) could not be installed with error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -221,12 +222,12 @@ public class PackageInstallHelper: Identifiable {
|
|||
|
||||
// remove the font from the fonts directory just in case it is an old one
|
||||
if fileManager.fileExists(atPath: fontDestinationUrl.path) {
|
||||
print("removed existing font: \(fontDestinationUrl.lastPathComponent)")
|
||||
Logger.data.info("removed existing font: \(fontDestinationUrl.lastPathComponent)")
|
||||
try? fileManager.removeItem(at: fontDestinationUrl)
|
||||
}
|
||||
|
||||
try fileManager.copyItem(at: fontUrl, to: fontDestinationUrl)
|
||||
print("added font: \(fontDestinationUrl.lastPathComponent)")
|
||||
Logger.data.info("added font: \(fontDestinationUrl.lastPathComponent)")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -253,12 +254,12 @@ public class PackageInstallHelper: Identifiable {
|
|||
// code 105 = kCTFontManagerErrorAlreadyRegistered
|
||||
// It is safe to ignore because the font is
|
||||
if errorCode == 105 {
|
||||
print("font \(fontUrl.lastPathComponent) is already registered.")
|
||||
Logger.data.info("font \(fontUrl.lastPathComponent) is already registered)")
|
||||
continue
|
||||
}
|
||||
|
||||
// if it's any other error, capture it to throw later
|
||||
print("registerFontWithSystem failed for \(fontUrl.lastPathComponent), error: \(String(describing: cfError))")
|
||||
Logger.data.error("registerFontWithSystem failed for \(fontUrl.lastPathComponent), error: \(cfError as CFError, privacy: .public)")
|
||||
registrationError = InstallPackageError.fontRegistrationError
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +302,7 @@ public class PackageInstallHelper: Identifiable {
|
|||
do {
|
||||
try self.deleteDownloadedKmpFile()
|
||||
} catch {
|
||||
print("installNewPackage failed to delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent)")
|
||||
Logger.data.error("installNewPackage failed to delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent, privacy: .public), error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -318,7 +319,7 @@ public class PackageInstallHelper: Identifiable {
|
|||
do {
|
||||
try self.deleteDownloadedKmpFile()
|
||||
} catch {
|
||||
print("replaceExistingPackageWithNewPackage failed to delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent)")
|
||||
Logger.data.error("replaceExistingPackageWithNewPackage failed to delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent, privacy: .public), error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
try self.movePackageFromTemporaryToInstalled()
|
||||
|
|
@ -334,13 +335,13 @@ public class PackageInstallHelper: Identifiable {
|
|||
do {
|
||||
try self.deleteDownloadedKmpFile()
|
||||
} catch {
|
||||
print("cleanupFailedInstallation did not delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent)")
|
||||
Logger.data.error("cleanupFailedInstallation did not delete downloaded .kmp file: \(self.temporaryKmpFileLocation.lastPathComponent, privacy: .public), error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
do {
|
||||
try self.deleteUnzippedPackage()
|
||||
} catch {
|
||||
print("cleanupFailedInstallation did not delete downloaded package: \(self.temporaryPackageLocation.lastPathComponent)")
|
||||
Logger.data.error("cleanupFailedInstallation did not delete downloaded package: \(self.temporaryKmpFileLocation.lastPathComponent, privacy: .public), error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
|
||||
public enum LoadPackageError: LocalizedError {
|
||||
case invalidUrl
|
||||
|
|
@ -65,7 +66,7 @@ public class PackageRepository: PackageRepo {
|
|||
try package.validate()
|
||||
installedPackages.append(package)
|
||||
} catch {
|
||||
print("validation failed for \(url) with error: \(error)")
|
||||
Logger.data.error("validation failed for \(url) with error: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +79,8 @@ public class PackageRepository: PackageRepo {
|
|||
*
|
||||
*/
|
||||
public func loadSinglePackage(packageUrl: URL) throws -> KeymanPackage {
|
||||
print("loadSinglePackage from url: \(packageUrl)")
|
||||
Logger.data.info("loadSinglePackage from url: \(packageUrl, privacy: .public)")
|
||||
|
||||
guard let source = try readPackageFromDirectory(packageDirectoryUrl: packageUrl) else { throw LoadPackageError.invalidUrl }
|
||||
|
||||
let package = KeymanPackage(packageUrl: packageUrl, packageSource: source)
|
||||
|
|
@ -90,12 +92,12 @@ public class PackageRepository: PackageRepo {
|
|||
* delete the package from disk
|
||||
*/
|
||||
public func deletePackage(package: KeymanPackage) {
|
||||
print("deleting package: \(package.sourceDirectoryUrl)")
|
||||
Logger.data.info("deleting package: \(package.sourceDirectoryUrl, privacy: .public)")
|
||||
do {
|
||||
try FileManager.default.removeItem(at: package.sourceDirectoryUrl)
|
||||
print("deleted package: \(package.sourceDirectoryUrl)")
|
||||
Logger.data.info("deleted package: \(package.sourceDirectoryUrl, privacy: .public)")
|
||||
} catch {
|
||||
print("could not delete directory: \(error.localizedDescription)")
|
||||
Logger.data.error("could not delete directory: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,17 +112,17 @@ public class PackageRepository: PackageRepo {
|
|||
// create the keyman-packages directory if it doesn't already exist
|
||||
if !FileManager.default.fileExists(atPath: packageDirectory.path) {
|
||||
try FileManager.default.createDirectory(at: packageDirectory, withIntermediateDirectories: true, attributes: nil)
|
||||
print("Created directory: \(packageDirectory.path)")
|
||||
Logger.data.info("Created directory: \(packageDirectory.path, privacy: .public)")
|
||||
} else {
|
||||
print("Directory already exists: \(packageDirectory.path)")
|
||||
Logger.data.info("Directory already exists: \(packageDirectory.path, privacy: .public)")
|
||||
}
|
||||
|
||||
// create the temp directory if it doesn't already exist
|
||||
if !FileManager.default.fileExists(atPath: packageTempDirectory.path) {
|
||||
try FileManager.default.createDirectory(at: packageTempDirectory, withIntermediateDirectories: true, attributes: nil)
|
||||
print("Created directory: \(packageTempDirectory.path)")
|
||||
Logger.data.info("Created directory: \(packageTempDirectory.path, privacy: .public)")
|
||||
} else {
|
||||
print("Directory already exists: \(packageTempDirectory.path)")
|
||||
Logger.data.info("Directory already exists: \(packageTempDirectory.path, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,9 +143,9 @@ public class PackageRepository: PackageRepo {
|
|||
try fileManager.removeItem(at: fileURL)
|
||||
}
|
||||
|
||||
print("successfully cleared temp directory")
|
||||
Logger.data.info("successfully cleared temp directory")
|
||||
} catch {
|
||||
print("error clearing temp directory: \(error.localizedDescription)")
|
||||
Logger.data.error("error clearing temp directory: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -174,9 +176,9 @@ public class PackageRepository: PackageRepo {
|
|||
public func unzipKmpFile(at kmpFileUrl: URL, to packageDestinationUrl: URL) throws {
|
||||
do {
|
||||
try FileManager.default.unzipItem(at: kmpFileUrl, to: packageDestinationUrl)
|
||||
print("Successfully unzipped the file!")
|
||||
Logger.data.info("successfully unzipped the file")
|
||||
} catch {
|
||||
print("Extraction failed: \(error.localizedDescription)")
|
||||
Logger.data.error("extraction failed: \(error as NSError, privacy: .public)")
|
||||
throw LoadPackageError.unzipError
|
||||
}
|
||||
}
|
||||
|
|
@ -226,15 +228,15 @@ public class PackageRepository: PackageRepo {
|
|||
packageMap[itemUrl] = packageSource
|
||||
}
|
||||
} catch let error as LoadPackageError {
|
||||
print("** package at \(itemUrl) could not be loaded: \(error.localizedDescription)")
|
||||
Logger.data.error("package at \(itemUrl) could not be loaded: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Failed to read directory: \(error.localizedDescription)")
|
||||
Logger.data.error("failed to read directory: \(error as NSError, privacy: .public)")
|
||||
}
|
||||
|
||||
print("\(packageMap.count) packages read")
|
||||
Logger.data.info("readPackageSource: \(packageMap.count, privacy: .public) packages read")
|
||||
return packageMap
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +244,7 @@ public class PackageRepository: PackageRepo {
|
|||
* check the specified directory for the kmp.json file and read it if it exists
|
||||
*/
|
||||
func readPackageFromDirectory(packageDirectoryUrl: URL) throws -> PackageSource? {
|
||||
print("readPackageFromDirectory from url: \(packageDirectoryUrl)")
|
||||
Logger.data.info("readPackageFromDirectory from url: \(packageDirectoryUrl, privacy: .public)")
|
||||
var packageSource: PackageSource? = nil
|
||||
let kmpJsonFileUrl = packageDirectoryUrl.appendingPathComponent(packageFileName)
|
||||
|
||||
|
|
@ -272,7 +274,7 @@ public class PackageRepository: PackageRepo {
|
|||
throw error
|
||||
} catch {
|
||||
// otherwise convert the error to a LoadPackageError error
|
||||
print("readPackage error: \(error.localizedDescription)")
|
||||
Logger.data.error("readPackage error: \(error as NSError, privacy: .public)")
|
||||
throw LoadPackageError.kmpJsonFileUnreadable
|
||||
}
|
||||
return packageSource
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
//
|
||||
// Logger.swift
|
||||
// KeyFig
|
||||
//
|
||||
// Created by Shawn - SIL on 12/9/25.
|
||||
//
|
||||
|
||||
import OSLog
|
||||
|
||||
class ConfigLogger {
|
||||
//static let shared = ConfigLogger()
|
||||
|
||||
fileprivate let subsystem = ConfigAppUtil.configBundleId
|
||||
fileprivate let testCategory = "test"
|
||||
public let testLogger: Logger
|
||||
|
||||
fileprivate init() {
|
||||
testLogger = Logger(subsystem: subsystem, category: testCategory)
|
||||
|
||||
testLogger.debug("ConfigLogger instance created.")
|
||||
}
|
||||
}
|
||||
|
|
@ -9,12 +9,13 @@
|
|||
|
||||
import Testing
|
||||
import Foundation
|
||||
import OSLog
|
||||
@testable import KeymanSettings
|
||||
|
||||
@Suite("Settings Container") struct SettingsContainersTests {
|
||||
|
||||
fileprivate init() async throws {
|
||||
print("init")
|
||||
Logger.setup.info("init")
|
||||
}
|
||||
|
||||
@Test("Check settings creation") @MainActor func testSettingsCreation() async throws {
|
||||
|
|
@ -138,7 +139,7 @@ import Foundation
|
|||
@Suite("Check Keyman paths") struct KeymanPathsTests {
|
||||
|
||||
fileprivate init() async throws {
|
||||
print("init")
|
||||
Logger.setup.info("init")
|
||||
}
|
||||
|
||||
@Test("Check Keyman 17 documents directory") func testKeyman17DocumentsDirectory() async throws {
|
||||
|
|
@ -191,7 +192,7 @@ import Foundation
|
|||
let moabiteKeyboardKey = "/sil_extinct/moabite.kmx"
|
||||
|
||||
fileprivate init() async throws {
|
||||
print("init Settings")
|
||||
Logger.setup.info("init")
|
||||
do {
|
||||
try self.settingsRepo = DefaultsRepository(suiteName: "test.suite.name")
|
||||
} catch UserDefaultsError.unknownSuite {
|
||||
|
|
|
|||
|
|
@ -49,12 +49,6 @@ class DefaultsRepoStub: DefaultsRepo {
|
|||
}
|
||||
|
||||
|
||||
func logDefaults() {
|
||||
print("UserDefaults:")
|
||||
print("\("KMSelectedKeyboardsKey"): \(self.readSelectedKeyboard())")
|
||||
print("\("KMEnabledKeyboardsKey"): \(self.readEnabledKeyboards())")
|
||||
}
|
||||
|
||||
func clearDefaults() {
|
||||
selectedKeyboard = ""
|
||||
enabledKeyboards = []
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue