mirror of
https://github.com/munki/munki.git
synced 2026-05-12 15:28:51 -05:00
386 lines
14 KiB
Swift
386 lines
14 KiB
Swift
//
|
|
// MSCStatusController.swift
|
|
// Managed Software Center
|
|
//
|
|
// Created by Greg Neagle on 7/11/18.
|
|
// Copyright © 2018-2019 The Munki Project. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
import WebKit
|
|
|
|
class MSCStatusController: NSObject {
|
|
|
|
@IBOutlet weak var statusWindowController: MainWindowController!
|
|
|
|
// Handles status messages from managedsoftwareupdate
|
|
var session_started = false
|
|
var got_status_update = false
|
|
var timer: Timer? = nil
|
|
|
|
var _status_restartAlertDismissed = false
|
|
var _status_stopBtnDisabled = false
|
|
var _status_stopBtnHidden = false
|
|
var _status_stopBtnState = 0
|
|
var _status_message = ""
|
|
var _status_detail = ""
|
|
var _status_percent = -1.0
|
|
var _status_stopBtnPressed = false
|
|
var receiving_notifications = false
|
|
var timeout_counter = 0
|
|
var saw_process = false
|
|
|
|
func registerForNotifications() {
|
|
// Register for notification messages
|
|
let center = DistributedNotificationCenter.default()
|
|
center.addObserver(self,
|
|
selector: #selector(self.updateStatus),
|
|
name: NSNotification.Name(
|
|
rawValue: "com.googlecode.munki.managedsoftwareupdate.statusUpdate"),
|
|
object: nil,
|
|
suspensionBehavior: .deliverImmediately)
|
|
receiving_notifications = true
|
|
}
|
|
|
|
func unregisterForNotifications() {
|
|
// Tell the DistributedNotificationCenter to stop sending us notifications
|
|
DistributedNotificationCenter.default().removeObserver(self)
|
|
// set self.receiving_notifications to False so our process monitoring
|
|
// thread will exit
|
|
receiving_notifications = false
|
|
}
|
|
|
|
func startMunkiStatusSession() {
|
|
// Initialize things for monitoring a managedsoftwareupdate session
|
|
initStatusSession()
|
|
session_started = true
|
|
// start our process monitor timer so we can be notified about
|
|
// process failure
|
|
timeout_counter = 6
|
|
saw_process = false
|
|
timer = Timer.scheduledTimer(timeInterval: 5.0,
|
|
target: self,
|
|
selector: #selector(self.checkProcess),
|
|
userInfo: nil,
|
|
repeats: true)
|
|
}
|
|
|
|
@objc func checkProcess() {
|
|
// Monitors managedsoftwareupdate process for failure to start
|
|
// or unexpected exit, so we're not waiting around forever if
|
|
// managedsoftwareupdate isn't running.
|
|
let PYTHON_SCRIPT_NAME = "managedsoftwareupdate"
|
|
let NEVER_STARTED = -2
|
|
let UNEXPECTEDLY_QUIT = -1
|
|
if !session_started {
|
|
return
|
|
}
|
|
if got_status_update {
|
|
// we got a status update since we last checked; no need to
|
|
// check the process table
|
|
timeout_counter = 6
|
|
saw_process = true
|
|
// clear the flag so we have to get another status update
|
|
got_status_update = false
|
|
} else if pythonScriptRunning(PYTHON_SCRIPT_NAME) {
|
|
timeout_counter = 6
|
|
saw_process = true
|
|
} else {
|
|
msc_debug_log("managedsoftwareupdate not running...")
|
|
timeout_counter -= 1
|
|
}
|
|
if timeout_counter == 0 {
|
|
msc_debug_log("Timed out waiting for managedsoftwareupdate.")
|
|
if saw_process {
|
|
sessionEnded(UNEXPECTEDLY_QUIT)
|
|
} else {
|
|
sessionEnded(NEVER_STARTED)
|
|
}
|
|
}
|
|
}
|
|
|
|
func sessionStarted() -> Bool {
|
|
// Accessor method
|
|
return session_started
|
|
}
|
|
|
|
func sessionEnded(_ result: Int) {
|
|
// clean up after a managesoftwareupdate session ends
|
|
if let uTimer = timer {
|
|
uTimer.invalidate()
|
|
timer = nil
|
|
}
|
|
cleanUpStatusSession()
|
|
// tell the window controller the update session is done
|
|
statusWindowController.munkiStatusSessionEnded(withStatus: result, errorMessage: "")
|
|
}
|
|
|
|
@objc func updateStatus(_ notification: NSUserNotification) {
|
|
// Got update status notification from managedsoftwareupdate
|
|
msc_debug_log("Got munkistatus update notification")
|
|
got_status_update = true
|
|
guard let info = notification.userInfo else {
|
|
msc_debug_log("No userInfo in notification")
|
|
return
|
|
}
|
|
msc_debug_log("\(info)")
|
|
if let message = info["message"] as? String {
|
|
setMessage(message)
|
|
}
|
|
if let detail = info["detail"] as? String {
|
|
setDetail(detail)
|
|
}
|
|
if let percent = info["percent"] as? String {
|
|
setPercentageDone(percent)
|
|
}
|
|
if let stop_button_visible = info["stop_button_visible"] as? Bool {
|
|
if stop_button_visible {
|
|
showStopButton()
|
|
} else {
|
|
hideStopButton()
|
|
}
|
|
}
|
|
if let stop_button_enabled = info["stop_button_enabled"] as? Bool {
|
|
if stop_button_enabled {
|
|
enableStopButton()
|
|
} else {
|
|
disableStopButton()
|
|
}
|
|
}
|
|
let command = info["command"] as? String ?? ""
|
|
if !session_started && !["showRestartAlert", "quit"].contains(command) {
|
|
// we got a status message but we didn't start the session
|
|
// so switch to the right mode
|
|
startMunkiStatusSession()
|
|
}
|
|
if !command.isEmpty {
|
|
msc_debug_log("Received command: \(command)")
|
|
}
|
|
if command == "activate" {
|
|
// do nothing
|
|
} else if command == "shoeRestartAlert" {
|
|
if session_started {
|
|
sessionEnded(0)
|
|
}
|
|
doRestartAlert()
|
|
} else if command == "quit" {
|
|
sessionEnded(0)
|
|
}
|
|
}
|
|
|
|
// required status methods
|
|
|
|
func initStatusSession() {
|
|
// Initialize the main window for update status
|
|
statusWindowController._update_in_progress = true
|
|
if statusWindowController.currentPageIsUpdatesPage() {
|
|
statusWindowController.load_page("updates.html")
|
|
statusWindowController.displayUpdateCount()
|
|
}
|
|
}
|
|
|
|
func cleanUpStatusSession() {
|
|
// Clean up after status session ends
|
|
session_started = false
|
|
// reset all our status variables
|
|
statusWindowController._update_in_progress = false
|
|
_status_stopBtnDisabled = false
|
|
_status_stopBtnHidden = false
|
|
_status_stopBtnState = 0
|
|
_status_message = ""
|
|
_status_detail = ""
|
|
_status_percent = -1.0
|
|
}
|
|
|
|
func doRestartAlert() {
|
|
// Display a restart alert -- some item just installed or removed
|
|
// requires a restart
|
|
msc_log("MSC", "restart_required")
|
|
_status_restartAlertDismissed = false
|
|
let alert = NSAlert()
|
|
alert.messageText = NSLocalizedString("Restart Required", comment: "Restart Required title")
|
|
alert.informativeText = NSLocalizedString(
|
|
"Software installed or removed requires a restart. You will have a chance to save open documents.",
|
|
comment:"Restart Required alert detail")
|
|
alert.addButton(withTitle: NSLocalizedString("Restart", comment:"Restart button title"))
|
|
alert.beginSheetModal(for: statusWindowController.window!) { (_) in
|
|
msc_log("MSC", "restart_confirmed")
|
|
self._status_restartAlertDismissed = true
|
|
restartNow()
|
|
}
|
|
}
|
|
|
|
func setPercentageDone(_ percentish: Any?) {
|
|
// Display percentage done
|
|
var percent = -1.0
|
|
// TO-DO: there's got to be a more elegant way of doing this
|
|
if percentish != nil {
|
|
if percentish! is String {
|
|
percent = Double(percentish! as! String) ?? -1.0
|
|
} else if percentish! is Double {
|
|
percent = percentish! as! Double
|
|
}
|
|
}
|
|
if percent > 100.0 {
|
|
percent = 100.0
|
|
}
|
|
_status_percent = percent
|
|
// tell JavaScript to update the percentage done
|
|
msc_debug_log("Calling JavaScript updateProgress")
|
|
statusWindowController.webView.evaluateJavaScript("updateProgress(\(percent))")
|
|
}
|
|
|
|
func setMessage(_ text: String) {
|
|
// Display main status message
|
|
var messageText = Bundle.main.localizedString(forKey: text, value: text, table: nil)
|
|
_status_message = messageText
|
|
if messageText.isEmpty {
|
|
messageText = " "
|
|
}
|
|
statusWindowController.setInnerHTML(messageText, elementID: "primary-status-text")
|
|
}
|
|
|
|
func setDetail(_ text: String) {
|
|
// Display status detail
|
|
var detailText = Bundle.main.localizedString(forKey: text, value: text, table: nil)
|
|
_status_detail = detailText
|
|
if detailText.isEmpty {
|
|
detailText = " "
|
|
}
|
|
statusWindowController.setInnerHTML(detailText, elementID: "secondary-status-text")
|
|
}
|
|
|
|
func getStopButtonState() -> Bool {
|
|
// Get the state (pressed or not) of the stop button
|
|
// Returns true if pressed; false if not
|
|
return _status_stopBtnPressed
|
|
}
|
|
|
|
func hideStopButton() {
|
|
// Hide the stop button
|
|
if _status_stopBtnPressed {
|
|
// if the button is pressed, don't hide it
|
|
return
|
|
}
|
|
_status_stopBtnHidden = true
|
|
statusWindowController.webView.evaluateJavaScript("hideStopButton()")
|
|
}
|
|
|
|
func showStopButton() {
|
|
// Show the stop button
|
|
if _status_stopBtnPressed {
|
|
// if the button is pressed, just exit
|
|
return
|
|
}
|
|
_status_stopBtnHidden = false
|
|
statusWindowController.webView.evaluateJavaScript("showStopButton()")
|
|
}
|
|
|
|
func disableStopButton() {
|
|
// Disable the stop button
|
|
if _status_stopBtnPressed {
|
|
// if the button is pressed, just exit
|
|
return
|
|
}
|
|
_status_stopBtnHidden = true
|
|
statusWindowController.webView.evaluateJavaScript("disableStopButton()")
|
|
}
|
|
|
|
func enableStopButton() {
|
|
// Enable the stop button
|
|
if _status_stopBtnPressed {
|
|
// if the button is pressed, just exit
|
|
return
|
|
}
|
|
_status_stopBtnDisabled = false
|
|
statusWindowController.webView.evaluateJavaScript("enableStopButton()")
|
|
}
|
|
|
|
func getRestartAlertDismissed() -> Bool {
|
|
// Was the restart alert dimissed?'
|
|
return _status_restartAlertDismissed
|
|
}
|
|
|
|
func morelocalizedstrings() {
|
|
// Some strings that are sent to us from managedsoftwareupdate. By putting
|
|
// them here, genstrings can add them to the Localizable.strings file
|
|
// so localizers will be able to discover them
|
|
|
|
var _ = "" // we don't actually use these values at all
|
|
|
|
// Munki messages
|
|
_ = NSLocalizedString(
|
|
"Starting...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Finishing...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Performing preflight tasks...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Performing postflight tasks...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Checking for available updates...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Checking for additional changes...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Software installed or removed requires a restart.",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Waiting for network...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString("Done.", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Retrieving list of software for this machine...",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Verifying package integrity...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"The software was successfully installed.",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Gathering information on installed packages",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Determining which filesystem items to remove",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Removing receipt info", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Nothing to remove.", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Package removal complete.", comment: "managedsoftwareupdate message")
|
|
|
|
// apple update messages
|
|
_ = NSLocalizedString(
|
|
"Checking for available Apple Software Updates...",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Checking Apple Software Update catalog...",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Downloading available Apple Software Updates...",
|
|
comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Installing available Apple Software Updates...",
|
|
comment: "managedsoftwareupdate message")
|
|
|
|
// Adobe install/uninstall messages
|
|
_ = NSLocalizedString(
|
|
"Running Adobe Setup", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Running Adobe Uninstall", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Starting Adobe installer...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Running Adobe Patch Installer", comment: "managedsoftwareupdate message")
|
|
|
|
// macOS install/upgrade messages
|
|
_ = NSLocalizedString(
|
|
"Starting macOS upgrade...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"Preparing to run macOS Installer...", comment: "managedsoftwareupdate message")
|
|
_ = NSLocalizedString(
|
|
"System will restart and begin upgrade of macOS.",
|
|
comment: "managedsoftwareupdate message")
|
|
}
|
|
|
|
}
|