@@ -5,48 +5,48 @@ actor DMGManager {
55 private let logger : Logger
66 private var wasMounted : [ URL : Bool ] = [ : ]
77 private var mountedVolumes : [ URL ] = [ ]
8-
8+
99 init (
1010 executor: ShellExecutor ,
1111 logger: Logger
1212 ) {
1313 self . executor = executor
1414 self . logger = logger
1515 }
16-
16+
1717 /// Check if a DMG has a Software License Agreement
1818 func hasSLA( at path: URL ) async throws -> Bool {
1919 let result = try await executor. runOrThrow ( [
2020 " /usr/bin/hdiutil " , " imageinfo " , path. path, " -plist "
2121 ] )
22-
22+
2323 let plist = try PlistHandler . parse ( Data ( result. stdout. utf8) )
2424 if let properties = plist [ " Properties " ] as? [ String : Any ] ,
2525 let hasSLA = properties [ " Software License Agreement " ] as? Bool {
2626 return hasSLA
2727 }
2828 return false
2929 }
30-
30+
3131 /// Check if DMG is already mounted and return mount points
3232 func existingMountPoints( for dmgPath: URL ) async throws -> [ URL ] ? {
3333 let result = try await executor. runOrThrow ( [ " /usr/bin/hdiutil " , " info " , " -plist " ] )
34-
34+
3535 let plistData = try PlistHandler . extractFirstPlist ( from: Data ( result. stdout. utf8) )
3636 let info = try PlistHandler . parse ( plistData)
37-
37+
3838 guard let images = info [ " images " ] as? [ [ String : Any ] ] else {
3939 return nil
4040 }
41-
41+
4242 for image in images {
4343 guard let imagePath = image [ " image-path " ] as? String else { continue }
44-
44+
4545 // Check if this is our DMG (compare paths)
4646 let imageURL = URL ( filePath: imagePath)
4747 if imageURL. standardizedFileURL == dmgPath. standardizedFileURL ||
4848 FileManager . default. contentsEqual ( atPath: imageURL. path, andPath: dmgPath. path) {
49-
49+
5050 var mountPoints : [ URL ] = [ ]
5151 if let entities = image [ " system-entities " ] as? [ [ String : Any ] ] {
5252 for entity in entities {
@@ -55,7 +55,7 @@ actor DMGManager {
5555 }
5656 }
5757 }
58-
58+
5959 if !mountPoints. isEmpty {
6060 // Mark as pre-mounted so we don't detach it
6161 for mp in mountPoints {
@@ -65,24 +65,24 @@ actor DMGManager {
6565 }
6666 }
6767 }
68-
68+
6969 return nil
7070 }
71-
71+
7272 /// Attach a DMG and return mount points
7373 func attach( _ dmgPath: URL ) async throws -> [ URL ] {
7474 // First check if already mounted
7575 if let existing = try await existingMountPoints ( for: dmgPath) {
7676 logger. log ( " DMG already mounted at: \( existing. map ( \. path) . joined ( separator: " , " ) ) " , level: 1 )
7777 return existing
7878 }
79-
79+
8080 // Check for SLA
8181 let sla = try await hasSLA ( at: dmgPath)
8282 if sla {
8383 logger. log ( " NOTE: Disk image \( dmgPath. path) has a license agreement! " , level: 0 )
8484 }
85-
85+
8686 // Mount the DMG
8787 let arguments = [
8888 " /usr/bin/hdiutil " ,
@@ -92,17 +92,17 @@ actor DMGManager {
9292 " -plist " ,
9393 " -nobrowse "
9494 ]
95-
95+
9696 let result = try await executor. run ( arguments, input: sla ? " Y \n " : nil )
97-
97+
9898 guard result. exitCode == 0 else {
9999 throw QuickPkgError . dmgMountFailed ( " ( \( result. exitCode) ) \( result. stderr) " )
100100 }
101-
101+
102102 // Parse the plist output to get mount points
103103 let plistData = try PlistHandler . extractFirstPlist ( from: Data ( result. stdout. utf8) )
104104 let attachResult = try PlistHandler . parse ( plistData)
105-
105+
106106 var mountPoints: [ URL] = [ ]
107107 if let entities = attachResult [ " system-entities " ] as? [ [ String : Any ] ] {
108108 for entity in entities {
@@ -118,33 +118,33 @@ actor DMGManager {
118118 }
119119 }
120120 }
121-
121+
122122 logger. log ( " Mounted DMG at: \( mountPoints. map ( \. path) . joined ( separator: " , " ) ) " , level: 1 )
123123 return mountPoints
124124 }
125-
125+
126126 /// Detach a mounted volume
127127 func detach( _ mountPoint: URL) async throws {
128128 // Don't detach if it was already mounted before we started
129129 if wasMounted [ mountPoint] == true {
130130 logger. log ( " Skipping detach for pre-mounted volume: \( mountPoint. path) " , level: 2 )
131131 return
132132 }
133-
133+
134134 guard FileManager . default. fileExists ( atPath: mountPoint. path) else { return }
135-
135+
136136 let result = try await executor. run ( [ " /usr/bin/hdiutil " , " detach " , mountPoint. path] )
137-
137+
138138 if result. exitCode != 0 {
139139 logger. log ( " Warning: Failed to detach \( mountPoint. path) : \( result. stderr) " , level: 1 )
140140 } else {
141141 logger. log ( " Detached: \( mountPoint. path) " , level: 2 )
142142 }
143-
143+
144144 mountedVolumes. removeAll { $0 == mountPoint }
145145 wasMounted. removeValue ( forKey: mountPoint)
146146 }
147-
147+
148148 /// Detach all volumes that we mounted
149149 func detachAll( ) async {
150150 for volume in mountedVolumes {
0 commit comments