forked from I2P_Developers/i2p.i2p
Mac OS X Launcher:
* In general bugfixes * Introduced event manager for better control flow * Splitted RouterStatusView to own file * Added shell script to setup and produce dmg file
This commit is contained in:
@ -43,6 +43,9 @@
|
||||
BFBDCB0021505BEE0014EB07 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFBDCAFF21505BED0014EB07 /* AppKit.framework */; };
|
||||
BFBDCB02215060190014EB07 /* DetectJava.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCB01215060190014EB07 /* DetectJava.swift */; };
|
||||
BFBDCB04215060970014EB07 /* StatusBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFBDCB03215060970014EB07 /* StatusBarController.swift */; };
|
||||
BFDD81DA2156B3E30014EB07 /* RouterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD81D92156B3E30014EB07 /* RouterManager.swift */; };
|
||||
BFE16BF82156C61E0014EB07 /* RouterStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE16BF72156C61E0014EB07 /* RouterStatusView.swift */; };
|
||||
BFE16BFA2156DAED0014EB07 /* EventManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE16BF92156DAED0014EB07 /* EventManager.swift */; };
|
||||
BFE1CBAD2151908F0014EB07 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */; };
|
||||
BFF4581C213C48EA0014EB07 /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF4581B213C48EA0014EB07 /* EventMonitor.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -94,6 +97,10 @@
|
||||
BFBDCAFF21505BED0014EB07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
BFBDCB01215060190014EB07 /* DetectJava.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectJava.swift; sourceTree = "<group>"; };
|
||||
BFBDCB03215060970014EB07 /* StatusBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusBarController.swift; sourceTree = "<group>"; };
|
||||
BFDD81D92156B3E30014EB07 /* RouterManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterManager.swift; sourceTree = "<group>"; };
|
||||
BFE16BF72156C61E0014EB07 /* RouterStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RouterStatusView.swift; sourceTree = "<group>"; };
|
||||
BFE16BF92156DAED0014EB07 /* EventManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventManager.swift; sourceTree = "<group>"; };
|
||||
BFE16BFB2156E94E0014EB07 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = ../../../Sparkle/build/Release/Sparkle.framework; sourceTree = "<group>"; };
|
||||
BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||
BFF45818213C428E0014EB07 /* I2PLauncher-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "I2PLauncher-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
BFF4581B213C48EA0014EB07 /* EventMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventMonitor.swift; sourceTree = "<group>"; };
|
||||
@ -134,6 +141,7 @@
|
||||
BF07789C21506D2B0014EB07 /* PopoverViewController.swift */,
|
||||
BFBDCB03215060970014EB07 /* StatusBarController.swift */,
|
||||
BF531514215105B40014EB07 /* LogViewController.swift */,
|
||||
BFE16BF72156C61E0014EB07 /* RouterStatusView.swift */,
|
||||
);
|
||||
path = userinterface;
|
||||
sourceTree = "<group>";
|
||||
@ -191,6 +199,7 @@
|
||||
BF5061922113C6ED0014EB07 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BFE16BFB2156E94E0014EB07 /* Sparkle.framework */,
|
||||
BFE1CBAC2151908F0014EB07 /* CoreFoundation.framework */,
|
||||
BF865416215182820014EB07 /* Foundation.framework */,
|
||||
BF865414215180F60014EB07 /* libswiftDarwin.tbd */,
|
||||
@ -209,6 +218,7 @@
|
||||
BF5315062150C55B0014EB07 /* RouterRunner.swift */,
|
||||
BF5315082150C6760014EB07 /* RouterDeployer.swift */,
|
||||
BF53150A2150C6E80014EB07 /* I2PSubprocess.swift */,
|
||||
BFDD81D92156B3E30014EB07 /* RouterManager.swift */,
|
||||
);
|
||||
path = routermgmt;
|
||||
sourceTree = "<group>";
|
||||
@ -221,6 +231,7 @@
|
||||
BFBDCAF52150428D0014EB07 /* StringExtensions.swift */,
|
||||
BFBDCAF7215047FE0014EB07 /* ArrayExtensions.swift */,
|
||||
BF53150C2150CE310014EB07 /* DateTimeUtils.swift */,
|
||||
BFE16BF92156DAED0014EB07 /* EventManager.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
@ -334,8 +345,10 @@
|
||||
BFBDCB04215060970014EB07 /* StatusBarController.swift in Sources */,
|
||||
BFBDCAF8215047FE0014EB07 /* ArrayExtensions.swift in Sources */,
|
||||
BF5315072150C55B0014EB07 /* RouterRunner.swift in Sources */,
|
||||
BFE16BFA2156DAED0014EB07 /* EventManager.swift in Sources */,
|
||||
BFBDCAF12150420C0014EB07 /* ExecutionResult.swift in Sources */,
|
||||
BF5315092150C6760014EB07 /* RouterDeployer.swift in Sources */,
|
||||
BFE16BF82156C61E0014EB07 /* RouterStatusView.swift in Sources */,
|
||||
BFBDCAEF215041E30014EB07 /* Error.swift in Sources */,
|
||||
BF1EFA41215141110014EB07 /* RouterTask.mm in Sources */,
|
||||
BF7506CB21509CFD0014EB07 /* RouterProcessStatus.swift in Sources */,
|
||||
@ -350,6 +363,7 @@
|
||||
BF531515215105B40014EB07 /* LogViewController.swift in Sources */,
|
||||
BF5315132150EB510014EB07 /* RouterProcessStatus+ObjectiveC.swift in Sources */,
|
||||
BFBDCAFE2150567D0014EB07 /* SwiftMainDelegate.swift in Sources */,
|
||||
BFDD81DA2156B3E30014EB07 /* RouterManager.swift in Sources */,
|
||||
BF53150B2150C6E80014EB07 /* I2PSubprocess.swift in Sources */,
|
||||
BFF4581C213C48EA0014EB07 /* EventMonitor.swift in Sources */,
|
||||
BF1EFA3A215140E60014EB07 /* SBridge.mm in Sources */,
|
||||
|
@ -11,10 +11,9 @@ import Cocoa
|
||||
|
||||
@objc class SwiftMainDelegate : NSObject {
|
||||
|
||||
//let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength )
|
||||
let statusBarController = StatusBarController()
|
||||
let sharedRouterMgmr = RouterManager.shared()
|
||||
static let javaDetector = DetectJava()
|
||||
static let objCBridge = SBridge()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
@ -37,10 +36,7 @@ import Cocoa
|
||||
} else {
|
||||
RouterProcessStatus.isRouterRunning = false
|
||||
print("I2P Router seems to NOT be running")
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // End of init()
|
||||
|
||||
@objc func findInstalledI2PVersion() {
|
||||
@ -63,13 +59,12 @@ import Cocoa
|
||||
let sub:Subprocess = Subprocess.init(executablePath: "/bin/sh", arguments: cmdArgs)
|
||||
let results:ExecutionResult = sub.execute(captureOutput: true)!
|
||||
if (results.didCaptureOutput) {
|
||||
print("captured output")
|
||||
let i2pVersion = results.outputLines.first?.replace(target: "I2P Core version: ", withString: "")
|
||||
NSLog("I2P version detected: %@",i2pVersion ?? "Unknown")
|
||||
RouterProcessStatus.routerVersion = i2pVersion
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_version", information: i2pVersion)
|
||||
} else {
|
||||
print("did NOT captured output")
|
||||
|
||||
print("Warning: Version Detection did NOT captured output")
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,21 +73,11 @@ import Cocoa
|
||||
var i2pPath = NSHomeDirectory()
|
||||
i2pPath += "/Library/I2P"
|
||||
|
||||
let fileManager = FileManager()
|
||||
var ok = ObjCBool(true)
|
||||
let doesI2PDirExists = fileManager.fileExists(atPath: i2pPath, isDirectory: &ok)
|
||||
|
||||
if (!doesI2PDirExists) {
|
||||
// Deploy
|
||||
}
|
||||
|
||||
//let i2pJarPath = i2pPath + "/lib/i2p.jar"
|
||||
|
||||
findInstalledI2PVersion()
|
||||
}
|
||||
|
||||
@objc static func openLink(url: String) {
|
||||
objCBridge.openUrl(url)
|
||||
SBridge.sharedInstance().openUrl(url)
|
||||
}
|
||||
|
||||
@objc func applicationWillTerminate() {
|
||||
|
83
launchers/macosx/I2PLauncher/Utils/EventManager.swift
Normal file
83
launchers/macosx/I2PLauncher/Utils/EventManager.swift
Normal file
@ -0,0 +1,83 @@
|
||||
//
|
||||
// EventManager.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 22/09/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class EventManager {
|
||||
var listeners = Dictionary<String, NSMutableArray>();
|
||||
|
||||
// Create a new event listener, not expecting information from the trigger
|
||||
// @param eventName: Matching trigger eventNames will cause this listener to fire
|
||||
// @param action: The function/lambda you want executed when the event triggers
|
||||
func listenTo(eventName:String, action: @escaping (()->())) {
|
||||
let newListener = EventListenerAction(callback: action)
|
||||
addListener(eventName: eventName, newEventListener: newListener)
|
||||
}
|
||||
|
||||
// Create a new event listener, expecting information from the trigger
|
||||
// @param eventName: Matching trigger eventNames will cause this listener to fire
|
||||
// @param action: The function/lambda you want executed when the event triggers
|
||||
func listenTo(eventName:String, action: @escaping ((Any?)->())) {
|
||||
let newListener = EventListenerAction(callback: action)
|
||||
addListener(eventName: eventName, newEventListener: newListener)
|
||||
}
|
||||
|
||||
internal func addListener(eventName:String, newEventListener:EventListenerAction) {
|
||||
if let listenerArray = self.listeners[eventName] {
|
||||
listenerArray.add(newEventListener)
|
||||
} else {
|
||||
self.listeners[eventName] = [newEventListener] as NSMutableArray
|
||||
}
|
||||
}
|
||||
|
||||
// Removes all listeners by default, or specific listeners through paramters
|
||||
// @param eventName: If an event name is passed, only listeners for that event will be removed
|
||||
func removeListeners(eventNameToRemoveOrNil:String?) {
|
||||
if let eventNameToRemove = eventNameToRemoveOrNil {
|
||||
if let actionArray = self.listeners[eventNameToRemove] {
|
||||
actionArray.removeAllObjects()
|
||||
}
|
||||
} else {
|
||||
self.listeners.removeAll(keepingCapacity: false)
|
||||
}
|
||||
}
|
||||
|
||||
// Triggers an event
|
||||
// @param eventName: Matching listener eventNames will fire when this is called
|
||||
// @param information: pass values to your listeners
|
||||
func trigger(eventName:String, information:Any? = nil) {
|
||||
if let actionObjects = self.listeners[eventName] {
|
||||
for actionObject in actionObjects {
|
||||
if let actionToPerform = actionObject as? EventListenerAction {
|
||||
if let methodToCall = actionToPerform.actionExpectsInfo {
|
||||
methodToCall(information)
|
||||
}
|
||||
else if let methodToCall = actionToPerform.action {
|
||||
methodToCall()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Class to hold actions to live in NSMutableArray
|
||||
class EventListenerAction {
|
||||
let action:(() -> ())?
|
||||
let actionExpectsInfo:((Any?) -> ())?
|
||||
|
||||
init(callback: @escaping (() -> ()) ) {
|
||||
self.action = callback
|
||||
self.actionExpectsInfo = nil
|
||||
}
|
||||
|
||||
init(callback: @escaping ((Any?) -> ()) ) {
|
||||
self.actionExpectsInfo = callback
|
||||
self.action = nil
|
||||
}
|
||||
}
|
99
launchers/macosx/I2PLauncher/routermgmt/RouterManager.swift
Normal file
99
launchers/macosx/I2PLauncher/routermgmt/RouterManager.swift
Normal file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// RouterManager.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 22/09/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class RouterManager : NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
static let packedVersion : String = "0.9.36"
|
||||
|
||||
let eventManager = EventManager()
|
||||
|
||||
var logViewStorage: NSTextStorage?
|
||||
|
||||
private static func handleRouterStart(information:Any?) {
|
||||
NSLog("event! - handle router start")
|
||||
RouterProcessStatus.routerStartedAt = Date()
|
||||
RouterProcessStatus.isRouterChildProcess = true
|
||||
RouterProcessStatus.isRouterRunning = true
|
||||
}
|
||||
private static func handleRouterStop(information:Any?) {
|
||||
NSLog("event! - handle router stop")
|
||||
RouterProcessStatus.routerStartedAt = nil
|
||||
RouterProcessStatus.isRouterChildProcess = false
|
||||
RouterProcessStatus.isRouterRunning = false
|
||||
}
|
||||
private static func handleRouterPid(information:Any?) {
|
||||
Swift.print("event! - handle router pid: %s", information ?? "")
|
||||
}
|
||||
private static func handleRouterVersion(information:Any?) {
|
||||
Swift.print("event! - handle router version: %s", information ?? "")
|
||||
let currentVersion : String = information as! String
|
||||
if (packedVersion.compare(currentVersion, options: .numeric) == .orderedDescending) {
|
||||
Swift.print("event! - router version: Packed version is newer, gonna re-deploy")
|
||||
} else {
|
||||
Swift.print("event! - router version: No update needed")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: "all ok")
|
||||
}
|
||||
}
|
||||
|
||||
private static var sharedRouterManager: RouterManager = {
|
||||
let inst = DetectJava()
|
||||
let routerManager = RouterManager(detectJavaInstance: inst)
|
||||
|
||||
// Configuration
|
||||
// ...
|
||||
routerManager.updateState()
|
||||
|
||||
routerManager.eventManager.listenTo(eventName: "router_start", action: handleRouterStart)
|
||||
routerManager.eventManager.listenTo(eventName: "router_stop", action: handleRouterStop)
|
||||
routerManager.eventManager.listenTo(eventName: "router_pid", action: handleRouterPid)
|
||||
routerManager.eventManager.listenTo(eventName: "router_version", action: handleRouterVersion)
|
||||
return routerManager
|
||||
}()
|
||||
|
||||
// MARK: -
|
||||
|
||||
let detectJava: DetectJava
|
||||
private var routerInstance: I2PRouterTask?{
|
||||
//Called after the change
|
||||
didSet{
|
||||
print("RouterManager.routerInstance did change to ", self.routerInstance ?? "null")
|
||||
if (self.routerInstance != nil) {
|
||||
RouterProcessStatus.isRouterRunning = (self.routerInstance?.isRouterRunning)!
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialization
|
||||
|
||||
private init(detectJavaInstance: DetectJava) {
|
||||
self.detectJava = detectJavaInstance
|
||||
}
|
||||
|
||||
// MARK: - Accessors
|
||||
|
||||
class func shared() -> RouterManager {
|
||||
return sharedRouterManager
|
||||
}
|
||||
|
||||
func setRouterTask(router: I2PRouterTask) {
|
||||
self.routerInstance = router
|
||||
}
|
||||
|
||||
func getRouterTask() -> I2PRouterTask? {
|
||||
return self.routerInstance
|
||||
}
|
||||
|
||||
func updateState() {
|
||||
self.routerInstance = SBridge.sharedInstance()?.currentRouterInstance
|
||||
}
|
||||
|
||||
}
|
@ -9,10 +9,15 @@
|
||||
import Foundation
|
||||
|
||||
extension RouterProcessStatus {
|
||||
|
||||
static func createNewRouterProcess(i2pPath: String, javaBinPath: String) {
|
||||
let bridge = SBridge()
|
||||
let timeWhenStarted = Date()
|
||||
RouterProcessStatus.routerStartedAt = timeWhenStarted
|
||||
bridge.startupI2PRouter(i2pPath, javaBinPath: javaBinPath)
|
||||
SBridge.sharedInstance().startupI2PRouter(i2pPath, javaBinPath: javaBinPath)
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
static func shutdownRouterChildProcess() {
|
||||
RouterManager.shared().getRouterTask()?.requestShutdown()
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ import AppKit
|
||||
@objc func getJavaHome() -> String {
|
||||
return RouterProcessStatus.knownJavaBinPath!
|
||||
}
|
||||
|
||||
@objc func triggerEvent(en: String, details: String? = nil) {
|
||||
RouterManager.shared().eventManager.trigger(eventName: en, information: details)
|
||||
}
|
||||
}
|
||||
|
||||
extension RouterProcessStatus {
|
||||
|
@ -14,11 +14,43 @@ class LogViewerViewController : NSTabViewItem {
|
||||
@IBOutlet var scrollView: NSScrollView?
|
||||
@IBOutlet var textFieldView: NSTextView?
|
||||
|
||||
private var outputPipe : Pipe?
|
||||
|
||||
override init(identifier: Any?) {
|
||||
super.init(identifier: identifier)
|
||||
self.captureStandardOutputAndRouteToTextView()
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
self.captureStandardOutputAndRouteToTextView()
|
||||
}
|
||||
|
||||
|
||||
func captureStandardOutputAndRouteToTextView() {
|
||||
outputPipe = RouterManager.shared().getRouterTask()?.processPipe
|
||||
outputPipe?.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
|
||||
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, object: outputPipe?.fileHandleForReading , queue: nil) {
|
||||
notification in
|
||||
|
||||
let output = self.outputPipe?.fileHandleForReading.availableData
|
||||
let outputString = String(data: output!, encoding: String.Encoding.utf8) ?? ""
|
||||
|
||||
DispatchQueue.main.async(execute: {
|
||||
let previousOutput = self.textFieldView?.string ?? ""
|
||||
let nextOutput = previousOutput + "\n" + outputString
|
||||
self.textFieldView?.string = nextOutput
|
||||
|
||||
let range = NSRange(location:nextOutput.characters.count,length:0)
|
||||
self.textFieldView?.scrollRangeToVisible(range)
|
||||
|
||||
})
|
||||
|
||||
self.outputPipe?.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class LogViewController {
|
||||
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,6 @@ class PopoverViewController: NSViewController {
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
//super.init(nibName: "UserInterfaces", bundle: Bundle.main)!
|
||||
//let nib = NSNib(nibNamed: "UserInterfaces", bundle: Bundle.main)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -22,83 +19,6 @@ class PopoverViewController: NSViewController {
|
||||
super.viewDidLoad()
|
||||
// Do view setup here.
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@objc class RouterStatusView : NSView {
|
||||
static var instance: RouterStatusView?
|
||||
|
||||
static func getInstance() -> RouterStatusView? {
|
||||
if (self.instance != Optional.none) {
|
||||
return RouterStatusView.instance
|
||||
}
|
||||
return Optional.none
|
||||
}
|
||||
|
||||
@IBOutlet var routerStatusLabel: NSTextField?
|
||||
@IBOutlet var routerVersionLabel: NSTextField?
|
||||
@IBOutlet var routerStartedByLabel: NSTextField?
|
||||
@IBOutlet var routerUptimeLabel: NSTextField?
|
||||
|
||||
@IBOutlet var quickControlView: NSView?
|
||||
@IBOutlet var routerStartStopButton: NSButton?
|
||||
|
||||
|
||||
@objc func actionBtnStartRouter(_ sender: Any?) {
|
||||
NSLog("START ROUTER")
|
||||
(sender as! NSButton).cell?.stringValue = "Stop Router"
|
||||
let timeWhenStarted = Date()
|
||||
RouterProcessStatus.routerStartedAt = timeWhenStarted
|
||||
SwiftMainDelegate.objCBridge.startupI2PRouter(RouterProcessStatus.i2pDirectoryPath, javaBinPath: RouterProcessStatus.knownJavaBinPath!)
|
||||
}
|
||||
@objc func actionBtnStopRouter(_ sender: Any?) {
|
||||
NSLog("STOP ROUTER")
|
||||
}
|
||||
@objc func actionBtnRestartRouter(sender: Any?) {}
|
||||
|
||||
override func viewWillDraw() {
|
||||
super.viewWillDraw()
|
||||
if (RouterStatusView.instance != nil) {
|
||||
RouterStatusView.instance = self
|
||||
}
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
func setRouterStatusLabelText() {
|
||||
if (RouterProcessStatus.isRouterRunning) {
|
||||
routerStatusLabel?.cell?.stringValue = "Router status: Running"
|
||||
routerStartStopButton?.action = #selector(self.actionBtnStopRouter(_:))
|
||||
} else {
|
||||
routerStatusLabel?.cell?.stringValue = "Router status: Not running"
|
||||
routerStartStopButton?.action = #selector(self.actionBtnStartRouter(_:))
|
||||
}
|
||||
routerStartStopButton?.needsDisplay = true
|
||||
routerStartStopButton?.target = self
|
||||
quickControlView?.needsDisplay = true
|
||||
|
||||
if let version = RouterProcessStatus.routerVersion {
|
||||
routerVersionLabel?.cell?.stringValue = "Router version: " + version
|
||||
} else {
|
||||
routerVersionLabel?.cell?.stringValue = "Router version: Still unknown"
|
||||
}
|
||||
if let routerStartTime = RouterProcessStatus.routerStartedAt {
|
||||
routerUptimeLabel?.cell?.stringValue = "Router has runned for " + DateTimeUtils.timeAgoSinceDate(date: NSDate(date: routerStartTime), numericDates: false)
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
let c = NSCoder()
|
||||
super.init(coder: c)!
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
required init?(coder decoder: NSCoder) {
|
||||
super.init(coder: decoder)
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,113 @@
|
||||
//
|
||||
// RouterStatusView.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 22/09/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@objc class RouterStatusView : NSView {
|
||||
static var instance: RouterStatusView?
|
||||
|
||||
static func getInstance() -> RouterStatusView? {
|
||||
if (self.instance != Optional.none) {
|
||||
return RouterStatusView.instance
|
||||
}
|
||||
return Optional.none
|
||||
}
|
||||
|
||||
@IBOutlet var routerStatusLabel: NSTextField?
|
||||
@IBOutlet var routerVersionLabel: NSTextField?
|
||||
@IBOutlet var routerStartedByLabel: NSTextField?
|
||||
@IBOutlet var routerUptimeLabel: NSTextField?
|
||||
|
||||
@IBOutlet var quickControlView: NSView?
|
||||
@IBOutlet var routerStartStopButton: NSButton?
|
||||
|
||||
@objc func actionBtnStartRouter(_ sender: Any?) {
|
||||
NSLog("START ROUTER")
|
||||
if (!(RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
SBridge.sharedInstance().startupI2PRouter(RouterProcessStatus.i2pDirectoryPath, javaBinPath: RouterProcessStatus.knownJavaBinPath!)
|
||||
}
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
|
||||
@objc func actionBtnStopRouter(_ sender: Any?) {
|
||||
NSLog("STOP ROUTER")
|
||||
if ((RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
NSLog("Found running router")
|
||||
RouterManager.shared().getRouterTask()?.requestShutdown()
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func actionBtnRestartRouter(sender: Any?) {
|
||||
if ((RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
RouterManager.shared().getRouterTask()?.requestRestart()
|
||||
} else {
|
||||
NSLog("Can't restart a non running router, start it however...")
|
||||
SBridge.sharedInstance().startupI2PRouter(RouterProcessStatus.i2pDirectoryPath, javaBinPath: RouterProcessStatus.knownJavaBinPath!)
|
||||
}
|
||||
RouterManager.shared().updateState()
|
||||
}
|
||||
|
||||
|
||||
|
||||
override func viewWillDraw() {
|
||||
super.viewWillDraw()
|
||||
if (RouterStatusView.instance != nil) {
|
||||
RouterStatusView.instance = self
|
||||
}
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
func setRouterStatusLabelText() {
|
||||
if (RouterProcessStatus.isRouterRunning) {
|
||||
routerStatusLabel?.cell?.stringValue = "Router status: Running"
|
||||
routerStartStopButton?.title = "Stop Router"
|
||||
routerStartStopButton?.action = #selector(self.actionBtnStopRouter(_:))
|
||||
} else {
|
||||
routerStatusLabel?.cell?.stringValue = "Router status: Not running"
|
||||
routerStartStopButton?.title = "Start Router"
|
||||
routerStartStopButton?.action = #selector(self.actionBtnStartRouter(_:))
|
||||
}
|
||||
routerStartStopButton?.needsDisplay = true
|
||||
routerStartStopButton?.target = self
|
||||
quickControlView?.needsDisplay = true
|
||||
|
||||
let staticStartedByLabelText = "Router started by launcher?"
|
||||
if RouterProcessStatus.isRouterChildProcess {
|
||||
routerStartedByLabel?.cell?.stringValue = staticStartedByLabelText+" Yes"
|
||||
} else {
|
||||
routerStartedByLabel?.cell?.stringValue = staticStartedByLabelText+" No"
|
||||
}
|
||||
routerStartedByLabel?.needsDisplay = true
|
||||
|
||||
if let version = RouterProcessStatus.routerVersion {
|
||||
routerVersionLabel?.cell?.stringValue = "Router version: " + version
|
||||
} else {
|
||||
routerVersionLabel?.cell?.stringValue = "Router version: Still unknown"
|
||||
}
|
||||
if let routerStartTime = RouterProcessStatus.routerStartedAt {
|
||||
routerUptimeLabel?.cell?.stringValue = "Uptime: Router started " + DateTimeUtils.timeAgoSinceDate(date: NSDate(date: routerStartTime), numericDates: false)
|
||||
} else {
|
||||
routerUptimeLabel?.cell?.stringValue = "Uptime: Router isn't running"
|
||||
}
|
||||
routerUptimeLabel?.needsDisplay = true
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
let c = NSCoder()
|
||||
super.init(coder: c)!
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
required init?(coder decoder: NSCoder) {
|
||||
super.init(coder: decoder)
|
||||
self.setRouterStatusLabelText()
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,6 @@ import Cocoa
|
||||
|
||||
@objc func constructMenu() -> NSMenu {
|
||||
let menu = NSMenu()
|
||||
//let sb = SwiftMainDelegate.objCBridge
|
||||
|
||||
menu.addItem(NSMenuItem(title: "Open I2P Console", action: #selector(self.handleOpenConsole(_:)), keyEquivalent: "O"))
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
@ -33,17 +32,12 @@ import Cocoa
|
||||
|
||||
|
||||
override init() {
|
||||
super.init()//(xib: "UserInterface", bundle: nil)
|
||||
super.init()
|
||||
popover.contentViewController = PopoverViewController.freshController()
|
||||
|
||||
if let button = statusItem.button {
|
||||
button.image = NSImage(named:"StatusBarButtonImage")
|
||||
//button.title = "I2P"
|
||||
button.toolTip = "I2P Launch Manager"
|
||||
//button.isVisible = true
|
||||
//button.action = #selector(self.statusBarButtonClicked)
|
||||
//button.sendAction(on: [.leftMouseUp, .rightMouseUp])
|
||||
//button.doubleAction = #selector(self.systemBarIconDoubleClick)
|
||||
button.target = self
|
||||
button.action = #selector(self.statusBarButtonClicked(sender:))
|
||||
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
|
||||
@ -97,6 +91,7 @@ import Cocoa
|
||||
if popover.isShown {
|
||||
closePopover(sender: sender)
|
||||
} else {
|
||||
RouterManager.shared().updateState()
|
||||
showPopover(sender: sender)
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,16 @@ const std::vector<std::string> defaultFlagsForExtractorJob {
|
||||
@class I2PRouterTask;
|
||||
@interface I2PRouterTask : NSObject
|
||||
@property (strong) NSTask* routerTask;
|
||||
|
||||
// TODO: Not in use, remove?
|
||||
/*
|
||||
@property (strong) NSUserDefaults *userPreferences;
|
||||
@property (strong) NSFileHandle *readLogHandle;
|
||||
@property (strong) NSMutableData *totalLogData;
|
||||
@property (strong) NSPipe *processPipe;
|
||||
@property (strong) NSFileHandle *input;
|
||||
*/
|
||||
|
||||
@property (strong) NSPipe *processPipe;
|
||||
@property (atomic) BOOL isRouterRunning;
|
||||
@property (atomic) BOOL userRequestedRestart;
|
||||
- (instancetype) initWithOptions : (RTaskOptions*) options;
|
||||
|
@ -31,7 +31,7 @@
|
||||
{
|
||||
self.userRequestedRestart = NO;
|
||||
self.isRouterRunning = NO;
|
||||
self.input = [NSFileHandle fileHandleWithStandardInput];
|
||||
//self.input = [NSFileHandle fileHandleWithStandardInput];
|
||||
self.routerTask = [NSTask new];
|
||||
self.processPipe = [NSPipe new];
|
||||
[self.routerTask setLaunchPath:options.binPath];
|
||||
@ -44,13 +44,41 @@
|
||||
[self.routerTask setStandardOutput:self.processPipe];
|
||||
[self.routerTask setStandardError:self.processPipe];
|
||||
|
||||
NSFileHandle *stdoutFileHandle = [self.processPipe fileHandleForReading];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(routerStdoutData:)
|
||||
name:NSFileHandleDataAvailableNotification
|
||||
object:stdoutFileHandle];
|
||||
/*
|
||||
NSFileHandle *stdoutFileHandle = [self.processPipe fileHandleForReading];
|
||||
dup2([[self.processPipe fileHandleForWriting] fileDescriptor], fileno(stdout));
|
||||
auto source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [stdoutFileHandle fileDescriptor], 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
dispatch_source_set_event_handler(source, ^{
|
||||
void* data = malloc(4096);
|
||||
ssize_t readResult = 0;
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
readResult = read([stdoutFileHandle fileDescriptor], data, 4096);
|
||||
} while (readResult == -1 && errno == EINTR);
|
||||
if (readResult > 0)
|
||||
{
|
||||
//AppKit UI should only be updated from the main thread
|
||||
dispatch_async(dispatch_get_main_queue(),^{
|
||||
NSString* stdOutString = [[NSString alloc] initWithBytesNoCopy:data length:readResult encoding:NSUTF8StringEncoding freeWhenDone:YES];
|
||||
NSAttributedString* stdOutAttributedString = [[NSAttributedString alloc] initWithString:stdOutString];
|
||||
NSLog(@"Router stdout: %@", stdOutString);
|
||||
//auto logForwarder = new LogForwarder();
|
||||
//[logForwarder appendLogViewWithLogLine:stdOutAttributedString];
|
||||
});
|
||||
}
|
||||
else{free(data);}
|
||||
});
|
||||
dispatch_resume(source);
|
||||
*/
|
||||
/*
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(routerStdoutData:)
|
||||
name:NSFileHandleDataAvailableNotification
|
||||
object:stdoutFileHandle];
|
||||
|
||||
[stdoutFileHandle waitForDataInBackgroundAndNotify];
|
||||
*/
|
||||
|
||||
[self.routerTask setTerminationHandler:^(NSTask* task) {
|
||||
// Cleanup
|
||||
@ -58,6 +86,8 @@
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus setRouterStatus: false];
|
||||
[swiftRouterStatus setRouterRanByUs: false];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_stop" details:@"normal shutdown"];
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
sendUserNotification(APP_IDSTR, @"I2P Router has stopped");
|
||||
}];
|
||||
return self;
|
||||
@ -82,8 +112,9 @@
|
||||
- (int) execute
|
||||
{
|
||||
@try {
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_start" details:@"normal start"];
|
||||
[self.routerTask launch];
|
||||
watchPid([self.routerTask processIdentifier]);
|
||||
self.isRouterRunning = YES;
|
||||
return 1;
|
||||
}
|
||||
@ -91,8 +122,11 @@
|
||||
{
|
||||
NSLog(@"Expection occurred %@", [e reason]);
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
self.isRouterRunning = NO;
|
||||
[swiftRouterStatus setRouterStatus: false];
|
||||
[swiftRouterStatus setRouterRanByUs: false];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_stop" details:@"error shutdown"];
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
sendUserNotification(@"An error occured, can't start the I2P Router", [e reason]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "RouterTask.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <memory>
|
||||
#include <future>
|
||||
@ -54,7 +56,9 @@ inline std::string buildClassPathForObjC(std::string basePath)
|
||||
#endif
|
||||
|
||||
@interface SBridge : NSObject
|
||||
@property (nonatomic, assign) I2PRouterTask* currentRouterInstance;
|
||||
- (NSString*) buildClassPath:(NSString*)i2pPath;
|
||||
- (void) startupI2PRouter:(NSString*)i2pRootPath javaBinPath:(NSString*)javaBinPath;
|
||||
- (void) openUrl:(NSString*)url;
|
||||
+ (instancetype)sharedInstance; // this makes it a singleton
|
||||
@end
|
||||
|
@ -33,9 +33,16 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
options.arguments = arguments;
|
||||
options.i2pBaseDir = i2pBaseDir;
|
||||
auto instance = [[I2PRouterTask alloc] initWithOptions: options];
|
||||
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:instance];
|
||||
[instance execute];
|
||||
sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
|
||||
auto pid = [instance getPID];
|
||||
NSLog(@"Got pid: %d", pid);
|
||||
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
|
||||
|
||||
return std::async(std::launch::async, [&pid]{
|
||||
return pid;
|
||||
});
|
||||
@ -45,6 +52,13 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
auto errStr = [NSString stringWithFormat:@"Expection occurred %@",[e reason]];
|
||||
NSLog(@"%@", errStr);
|
||||
sendUserNotification(APP_IDSTR, errStr);
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus setRouterStatus: false];
|
||||
[swiftRouterStatus setRouterRanByUs: false];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_exception" details:errStr];
|
||||
|
||||
return std::async(std::launch::async, [&]{
|
||||
return 0;
|
||||
});
|
||||
@ -55,6 +69,16 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
|
||||
@implementation SBridge
|
||||
|
||||
// this makes it a singleton
|
||||
+ (instancetype)sharedInstance {
|
||||
static SBridge *sharedInstance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedInstance = [[SBridge alloc] init];
|
||||
});
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
- (void) openUrl:(NSString*)url
|
||||
{
|
||||
@ -125,6 +149,7 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
sendUserNotification(APP_IDSTR, [NSString stringWithFormat:@"Error: %@", errMsg]);
|
||||
[routerStatus setRouterStatus: false];
|
||||
[routerStatus setRouterRanByUs: false];
|
||||
[routerStatus triggerEventWithEn:@"router_exception" details:[NSString stringWithFormat:@"Error: %@", errMsg]];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
@ -204,7 +204,6 @@ using namespace subprocess;
|
||||
|
||||
|
||||
NSBundle *launcherBundle = [NSBundle mainBundle];
|
||||
auto sBridge = [[SBridge alloc] init];
|
||||
|
||||
// Helper object to hold statefull path information
|
||||
self.metaInfo = [[ExtractMetaInfo alloc] init];
|
||||
@ -237,7 +236,7 @@ using namespace subprocess;
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
if (shouldAutoStartRouter) {
|
||||
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
}
|
||||
}];
|
||||
@ -248,7 +247,7 @@ using namespace subprocess;
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
|
||||
if (shouldAutoStartRouter) {
|
||||
[sBridge startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
}
|
||||
}
|
||||
|
107
launchers/macosx/osx_create_dmg.sh
Executable file
107
launchers/macosx/osx_create_dmg.sh
Executable file
@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
APP_NAME="I2PLauncher"
|
||||
VERSION="0.9.36"
|
||||
DMG_BACKGROUND_IMG="Background.png"
|
||||
|
||||
APP_EXE="${APP_NAME}.app/Contents/MacOS/${APP_NAME}"
|
||||
VOL_NAME="${APP_NAME} ${VERSION}"
|
||||
DMG_TMP="${VOL_NAME}-temp.dmg"
|
||||
DMG_FINAL="${VOL_NAME}.dmg"
|
||||
STAGING_DIR="/tmp/mkdmg$$"
|
||||
|
||||
# Check the background image DPI and convert it if it isn't 72x72
|
||||
_BACKGROUND_IMAGE_DPI_H=`sips -g dpiHeight ${DMG_BACKGROUND_IMG} | grep -Eo '[0-9]+\.[0-9]+'`
|
||||
_BACKGROUND_IMAGE_DPI_W=`sips -g dpiWidth ${DMG_BACKGROUND_IMG} | grep -Eo '[0-9]+\.[0-9]+'`
|
||||
|
||||
if [ $(echo " $_BACKGROUND_IMAGE_DPI_H != 72.0 " | bc) -eq 1 -o $(echo " $_BACKGROUND_IMAGE_DPI_W != 72.0 " | bc) -eq 1 ]; then
|
||||
echo "WARNING: The background image's DPI is not 72. This will result in distorted backgrounds on Mac OS X 10.7+."
|
||||
echo " I will convert it to 72 DPI for you."
|
||||
|
||||
_DMG_BACKGROUND_TMP="${DMG_BACKGROUND_IMG%.*}"_dpifix."${DMG_BACKGROUND_IMG##*.}"
|
||||
|
||||
sips -s dpiWidth 72 -s dpiHeight 72 ${DMG_BACKGROUND_IMG} --out ${_DMG_BACKGROUND_TMP}
|
||||
|
||||
DMG_BACKGROUND_IMG="${_DMG_BACKGROUND_TMP}"
|
||||
fi
|
||||
|
||||
# clear out any old data
|
||||
rm -rf "${STAGING_DIR}" "${DMG_TMP}" "${DMG_FINAL}"
|
||||
|
||||
# copy over the stuff we want in the final disk image to our staging dir
|
||||
mkdir -p "${STAGING_DIR}"
|
||||
cp -rpf "${APP_NAME}.app" "${STAGING_DIR}"
|
||||
# ... cp anything else you want in the DMG - documentation, etc.
|
||||
|
||||
# figure out how big our DMG needs to be
|
||||
# assumes our contents are at least 1M!
|
||||
SIZE=`du -sh "${STAGING_DIR}" | sed 's/\([0-9\.]*\)M\(.*\)/\1/'`
|
||||
SIZE=`echo "${SIZE} + 1.0" | bc | awk '{print int($1+0.5)}'`
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Cannot compute size of staging dir"
|
||||
exit
|
||||
fi
|
||||
|
||||
# create the temp DMG file
|
||||
hdiutil create -srcfolder "${STAGING_DIR}" -volname "${VOL_NAME}" -fs HFS+ \
|
||||
-fsargs "-c c=64,a=16,e=16" -format UDRW -size ${SIZE}M "${DMG_TMP}"
|
||||
|
||||
echo "Created DMG: ${DMG_TMP}"
|
||||
|
||||
# mount it and save the device
|
||||
DEVICE=$(hdiutil attach -readwrite -noverify "${DMG_TMP}" | \
|
||||
egrep '^/dev/' | sed 1q | awk '{print $1}')
|
||||
|
||||
sleep 2
|
||||
|
||||
# add a link to the Applications dir
|
||||
echo "Add link to /Applications"
|
||||
pushd /Volumes/"${VOL_NAME}"
|
||||
ln -s /Applications
|
||||
popd
|
||||
|
||||
# add a background image
|
||||
mkdir /Volumes/"${VOL_NAME}"/.background
|
||||
cp "${DMG_BACKGROUND_IMG}" /Volumes/"${VOL_NAME}"/.background/
|
||||
|
||||
# tell the Finder to resize the window, set the background,
|
||||
# change the icon size, place the icons in the right position, etc.
|
||||
echo '
|
||||
tell application "Finder"
|
||||
tell disk "'${VOL_NAME}'"
|
||||
open
|
||||
set current view of container window to icon view
|
||||
set toolbar visible of container window to false
|
||||
set statusbar visible of container window to false
|
||||
set the bounds of container window to {400, 100, 920, 440}
|
||||
set viewOptions to the icon view options of container window
|
||||
set arrangement of viewOptions to not arranged
|
||||
set icon size of viewOptions to 72
|
||||
set background picture of viewOptions to file ".background:'${DMG_BACKGROUND_IMG}'"
|
||||
set position of item "'${APP_NAME}'.app" of container window to {160, 205}
|
||||
set position of item "Applications" of container window to {360, 205}
|
||||
close
|
||||
open
|
||||
update without registering applications
|
||||
delay 2
|
||||
end tell
|
||||
end tell
|
||||
' | osascript
|
||||
|
||||
sync
|
||||
|
||||
# unmount it
|
||||
hdiutil detach "${DEVICE}"
|
||||
|
||||
# now make the final image a compressed disk image
|
||||
echo "Creating compressed image"
|
||||
hdiutil convert "${DMG_TMP}" -format UDZO -imagekey zlib-level=9 -o "${DMG_FINAL}"
|
||||
|
||||
# clean up
|
||||
rm -rf "${DMG_TMP}"
|
||||
rm -rf "${STAGING_DIR}"
|
||||
|
||||
echo 'Done.'
|
||||
|
||||
exit
|
Reference in New Issue
Block a user