Skip to content

Commit 4e5a73e

Browse files
committed
formatting and replaced URL(fileURLWithPath:)
1 parent 076e2ef commit 4e5a73e

4 files changed

Lines changed: 147 additions & 144 deletions

File tree

Sources/quickpkg/DMGManager.swift

Lines changed: 143 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,156 @@
11
import Foundation
22

33
actor DMGManager {
4-
private let executor: ShellExecutor
5-
private let logger: Logger
6-
private var wasMounted: [URL: Bool] = [:]
7-
private var mountedVolumes: [URL] = []
8-
9-
init(executor: ShellExecutor, logger: Logger) {
10-
self.executor = executor
11-
self.logger = logger
4+
private let executor: ShellExecutor
5+
private let logger: Logger
6+
private var wasMounted: [URL: Bool] = [:]
7+
private var mountedVolumes: [URL] = []
8+
9+
init(
10+
executor: ShellExecutor,
11+
logger: Logger
12+
) {
13+
self.executor = executor
14+
self.logger = logger
15+
}
16+
17+
/// Check if a DMG has a Software License Agreement
18+
func hasSLA(at path: URL) async throws -> Bool {
19+
let result = try await executor.runOrThrow([
20+
"/usr/bin/hdiutil", "imageinfo", path.path, "-plist"
21+
])
22+
23+
let plist = try PlistHandler.parse(Data(result.stdout.utf8))
24+
if let properties = plist["Properties"] as? [String: Any],
25+
let hasSLA = properties["Software License Agreement"] as? Bool {
26+
return hasSLA
1227
}
13-
14-
/// Check if a DMG has a Software License Agreement
15-
func hasSLA(at path: URL) async throws -> Bool {
16-
let result = try await executor.runOrThrow([
17-
"/usr/bin/hdiutil", "imageinfo", path.path, "-plist"
18-
])
19-
20-
let plist = try PlistHandler.parse(Data(result.stdout.utf8))
21-
if let properties = plist["Properties"] as? [String: Any],
22-
let hasSLA = properties["Software License Agreement"] as? Bool {
23-
return hasSLA
24-
}
25-
return false
28+
return false
29+
}
30+
31+
/// Check if DMG is already mounted and return mount points
32+
func existingMountPoints(for dmgPath: URL) async throws -> [URL]? {
33+
let result = try await executor.runOrThrow(["/usr/bin/hdiutil", "info", "-plist"])
34+
35+
let plistData = try PlistHandler.extractFirstPlist(from: Data(result.stdout.utf8))
36+
let info = try PlistHandler.parse(plistData)
37+
38+
guard let images = info["images"] as? [[String: Any]] else {
39+
return nil
2640
}
27-
28-
/// Check if DMG is already mounted and return mount points
29-
func existingMountPoints(for dmgPath: URL) async throws -> [URL]? {
30-
let result = try await executor.runOrThrow(["/usr/bin/hdiutil", "info", "-plist"])
31-
32-
let plistData = try PlistHandler.extractFirstPlist(from: Data(result.stdout.utf8))
33-
let info = try PlistHandler.parse(plistData)
34-
35-
guard let images = info["images"] as? [[String: Any]] else {
36-
return nil
37-
}
38-
39-
for image in images {
40-
guard let imagePath = image["image-path"] as? String else { continue }
41-
42-
// Check if this is our DMG (compare paths)
43-
let imageURL = URL(fileURLWithPath: imagePath)
44-
if imageURL.standardizedFileURL == dmgPath.standardizedFileURL ||
45-
FileManager.default.contentsEqual(atPath: imageURL.path, andPath: dmgPath.path) {
46-
47-
var mountPoints: [URL] = []
48-
if let entities = image["system-entities"] as? [[String: Any]] {
49-
for entity in entities {
50-
if let mountPoint = entity["mount-point"] as? String {
51-
mountPoints.append(URL(fileURLWithPath: mountPoint))
52-
}
53-
}
54-
}
55-
56-
if !mountPoints.isEmpty {
57-
// Mark as pre-mounted so we don't detach it
58-
for mp in mountPoints {
59-
wasMounted[mp] = true
60-
}
61-
return mountPoints
62-
}
63-
}
64-
}
65-
66-
return nil
67-
}
68-
69-
/// Attach a DMG and return mount points
70-
func attach(_ dmgPath: URL) async throws -> [URL] {
71-
// First check if already mounted
72-
if let existing = try await existingMountPoints(for: dmgPath) {
73-
logger.log("DMG already mounted at: \(existing.map(\.path).joined(separator: ", "))", level: 1)
74-
return existing
75-
}
76-
77-
// Check for SLA
78-
let sla = try await hasSLA(at: dmgPath)
79-
if sla {
80-
logger.log("NOTE: Disk image \(dmgPath.path) has a license agreement!", level: 0)
81-
}
82-
83-
// Mount the DMG
84-
let arguments = [
85-
"/usr/bin/hdiutil",
86-
"attach",
87-
dmgPath.path,
88-
"-mountrandom", "/private/tmp",
89-
"-plist",
90-
"-nobrowse"
91-
]
92-
93-
let result = try await executor.run(arguments, input: sla ? "Y\n" : nil)
94-
95-
guard result.exitCode == 0 else {
96-
throw QuickPkgError.dmgMountFailed("(\(result.exitCode)) \(result.stderr)")
97-
}
98-
99-
// Parse the plist output to get mount points
100-
let plistData = try PlistHandler.extractFirstPlist(from: Data(result.stdout.utf8))
101-
let attachResult = try PlistHandler.parse(plistData)
102-
41+
42+
for image in images {
43+
guard let imagePath = image["image-path"] as? String else { continue }
44+
45+
// Check if this is our DMG (compare paths)
46+
let imageURL = URL(filePath: imagePath)
47+
if imageURL.standardizedFileURL == dmgPath.standardizedFileURL ||
48+
FileManager.default.contentsEqual(atPath: imageURL.path, andPath: dmgPath.path) {
49+
10350
var mountPoints: [URL] = []
104-
if let entities = attachResult["system-entities"] as? [[String: Any]] {
105-
for entity in entities {
106-
if let potentiallyMountable = entity["potentially-mountable"] as? Bool,
107-
potentiallyMountable,
108-
let volumeKind = entity["volume-kind"] as? String,
109-
volumeKind == "hfs" || volumeKind == "apfs",
110-
let mountPoint = entity["mount-point"] as? String {
111-
let url = URL(fileURLWithPath: mountPoint)
112-
mountPoints.append(url)
113-
mountedVolumes.append(url)
114-
wasMounted[url] = false
115-
}
51+
if let entities = image["system-entities"] as? [[String: Any]] {
52+
for entity in entities {
53+
if let mountPoint = entity["mount-point"] as? String {
54+
mountPoints.append(URL(filePath: mountPoint))
11655
}
56+
}
11757
}
118-
119-
logger.log("Mounted DMG at: \(mountPoints.map(\.path).joined(separator: ", "))", level: 1)
120-
return mountPoints
121-
}
122-
123-
/// Detach a mounted volume
124-
func detach(_ mountPoint: URL) async throws {
125-
// Don't detach if it was already mounted before we started
126-
if wasMounted[mountPoint] == true {
127-
logger.log("Skipping detach for pre-mounted volume: \(mountPoint.path)", level: 2)
128-
return
58+
59+
if !mountPoints.isEmpty {
60+
// Mark as pre-mounted so we don't detach it
61+
for mp in mountPoints {
62+
wasMounted[mp] = true
63+
}
64+
return mountPoints
12965
}
130-
131-
guard FileManager.default.fileExists(atPath: mountPoint.path) else { return }
132-
133-
let result = try await executor.run(["/usr/bin/hdiutil", "detach", mountPoint.path])
134-
135-
if result.exitCode != 0 {
136-
logger.log("Warning: Failed to detach \(mountPoint.path): \(result.stderr)", level: 1)
137-
} else {
138-
logger.log("Detached: \(mountPoint.path)", level: 2)
139-
}
140-
141-
mountedVolumes.removeAll { $0 == mountPoint }
142-
wasMounted.removeValue(forKey: mountPoint)
66+
}
14367
}
144-
145-
/// Detach all volumes that we mounted
146-
func detachAll() async {
147-
for volume in mountedVolumes {
148-
if wasMounted[volume] != true {
149-
try? await detach(volume)
150-
}
68+
69+
return nil
70+
}
71+
72+
/// Attach a DMG and return mount points
73+
func attach(_ dmgPath: URL) async throws -> [URL] {
74+
// First check if already mounted
75+
if let existing = try await existingMountPoints(for: dmgPath) {
76+
logger.log("DMG already mounted at: \(existing.map(\.path).joined(separator: ", "))", level: 1)
77+
return existing
78+
}
79+
80+
// Check for SLA
81+
let sla = try await hasSLA(at: dmgPath)
82+
if sla {
83+
logger.log("NOTE: Disk image \(dmgPath.path) has a license agreement!", level: 0)
84+
}
85+
86+
// Mount the DMG
87+
let arguments = [
88+
"/usr/bin/hdiutil",
89+
"attach",
90+
dmgPath.path,
91+
"-mountrandom", "/private/tmp",
92+
"-plist",
93+
"-nobrowse"
94+
]
95+
96+
let result = try await executor.run(arguments, input: sla ? "Y\n" : nil)
97+
98+
guard result.exitCode == 0 else {
99+
throw QuickPkgError.dmgMountFailed("(\(result.exitCode)) \(result.stderr)")
100+
}
101+
102+
// Parse the plist output to get mount points
103+
let plistData = try PlistHandler.extractFirstPlist(from: Data(result.stdout.utf8))
104+
let attachResult = try PlistHandler.parse(plistData)
105+
106+
var mountPoints: [URL] = []
107+
if let entities = attachResult["system-entities"] as? [[String: Any]] {
108+
for entity in entities {
109+
if let potentiallyMountable = entity["potentially-mountable"] as? Bool,
110+
potentiallyMountable,
111+
let volumeKind = entity["volume-kind"] as? String,
112+
volumeKind == "hfs" || volumeKind == "apfs",
113+
let mountPoint = entity["mount-point"] as? String {
114+
let url = URL(filePath: mountPoint)
115+
mountPoints.append(url)
116+
mountedVolumes.append(url)
117+
wasMounted[url] = false
151118
}
119+
}
120+
}
121+
122+
logger.log("Mounted DMG at: \(mountPoints.map(\.path).joined(separator: ", "))", level: 1)
123+
return mountPoints
124+
}
125+
126+
/// Detach a mounted volume
127+
func detach(_ mountPoint: URL) async throws {
128+
// Don't detach if it was already mounted before we started
129+
if wasMounted[mountPoint] == true {
130+
logger.log("Skipping detach for pre-mounted volume: \(mountPoint.path)", level: 2)
131+
return
132+
}
133+
134+
guard FileManager.default.fileExists(atPath: mountPoint.path) else { return }
135+
136+
let result = try await executor.run(["/usr/bin/hdiutil", "detach", mountPoint.path])
137+
138+
if result.exitCode != 0 {
139+
logger.log("Warning: Failed to detach \(mountPoint.path): \(result.stderr)", level: 1)
140+
} else {
141+
logger.log("Detached: \(mountPoint.path)", level: 2)
142+
}
143+
144+
mountedVolumes.removeAll { $0 == mountPoint }
145+
wasMounted.removeValue(forKey: mountPoint)
146+
}
147+
148+
/// Detach all volumes that we mounted
149+
func detachAll() async {
150+
for volume in mountedVolumes {
151+
if wasMounted[volume] != true {
152+
try? await detach(volume)
153+
}
152154
}
155+
}
153156
}

Sources/quickpkg/InputType.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ enum InputType: String, CaseIterable {
88
case xip
99

1010
static func from(path: String) -> InputType? {
11-
let ext = URL(fileURLWithPath: path).pathExtension.lowercased()
11+
let ext = URL(filePath: path).pathExtension.lowercased()
1212
return InputType(rawValue: ext)
1313
}
1414
}

Sources/quickpkg/QuickPkg.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ struct QuickPkg: AsyncParsableCommand {
187187
// Prepare scripts if needed
188188
var scriptsDir: URL?
189189
if let scriptsPath = scripts {
190-
let scriptsURL = URL(fileURLWithPath: scriptsPath)
190+
let scriptsURL = URL(filePath: scriptsPath)
191191
guard FileManager.default.fileExists(atPath: scriptsPath) else {
192192
throw QuickPkgError.scriptNotFound(scriptsPath)
193193
}
@@ -207,7 +207,7 @@ struct QuickPkg: AsyncParsableCommand {
207207

208208
// Add preinstall script
209209
if let preinstallPath = preinstall {
210-
let preinstallURL = URL(fileURLWithPath: preinstallPath)
210+
let preinstallURL = URL(filePath: preinstallPath)
211211
guard FileManager.default.fileExists(atPath: preinstallPath) else {
212212
throw QuickPkgError.scriptNotFound(preinstallPath)
213213
}
@@ -222,7 +222,7 @@ struct QuickPkg: AsyncParsableCommand {
222222

223223
// Add postinstall script
224224
if let postinstallPath = postinstall {
225-
let postinstallURL = URL(fileURLWithPath: postinstallPath)
225+
let postinstallURL = URL(filePath: postinstallPath)
226226
guard FileManager.default.fileExists(atPath: postinstallPath) else {
227227
throw QuickPkgError.scriptNotFound(postinstallPath)
228228
}

0 commit comments

Comments
 (0)