Skip to content

Commit 68c1e72

Browse files
committed
Convert XPCService to new target ExtensionService
1 parent 57bd329 commit 68c1e72

24 files changed

+348
-226
lines changed

Copilot for Xcode.xcodeproj/project.pbxproj

Lines changed: 190 additions & 163 deletions
Large diffs are not rendered by default.

Copilot for Xcode/LaunchAgentManager.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@ extension LaunchAgentManager {
66
self.init(
77
serviceIdentifier: Bundle.main
88
.object(forInfoDictionaryKey: "BUNDLE_IDENTIFIER_BASE") as! String +
9-
".XPCService",
10-
executablePath: Bundle.main.executableURL?.deletingLastPathComponent()
11-
.appendingPathComponent("CopilotForXcodeXPCService").path ?? ""
9+
".ExtensionService",
10+
executablePath: Bundle.main.bundleURL
11+
.appendingPathComponent("Contents")
12+
.appendingPathComponent("Applications")
13+
.appendingPathComponent(
14+
"CopilotForXcodeExtensionService.app/Contents/MacOS/CopilotForXcodeExtensionService"
15+
)
16+
.path
1217
)
1318
}
1419
}

Copilot for Xcode/LaunchAgentView.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ struct LaunchAgentView: View {
5757
Button(action: {
5858
Task {
5959
do {
60-
try await LaunchAgentManager().restartLaunchAgent()
60+
try await LaunchAgentManager().reloadLaunchAgent()
6161
isDidRestartLaunchAgentAlertPresented = true
6262
} catch {
6363
errorMessage = error.localizedDescription
6464
}
6565
}
6666
}) {
67-
Text("Restart XPC Service")
67+
Text("Reload Launch Agent")
6868
}.alert(isPresented: $isDidRestartLaunchAgentAlertPresented) {
6969
.init(
70-
title: Text("Launch Agent Restarted"),
70+
title: Text("Launch Agent Reloaded"),
7171
dismissButton: .default(Text("OK"))
7272
)
7373
}
@@ -91,7 +91,21 @@ struct LaunchAgentView: View {
9191
.textFieldStyle(.copilot)
9292
}
9393
}
94-
}.buttonStyle(.copilot)
94+
}
95+
.buttonStyle(.copilot)
96+
.onAppear {
97+
#if DEBUG
98+
// do not auto install on debug build
99+
#else
100+
Task {
101+
do {
102+
try await LaunchAgentManager().setupLaunchAgentForTheFirstTimeIfNeeded()
103+
} catch {
104+
errorMessage = error.localizedDescription
105+
}
106+
}
107+
#endif
108+
}
95109
}
96110
}
97111

Core/Sources/Client/XPCService.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class XPCService {
3030
private func buildConnection() -> NSXPCConnection {
3131
let connection = NSXPCConnection(
3232
machServiceName: Bundle(for: XPCService.self)
33-
.object(forInfoDictionaryKey: "BUNDLE_IDENTIFIER_BASE") as! String + ".XPCService"
33+
.object(forInfoDictionaryKey: "BUNDLE_IDENTIFIER_BASE") as! String + ".ExtensionService"
3434
)
3535
connection.remoteObjectInterface =
3636
NSXPCInterface(with: XPCServiceProtocol.self)

Core/Sources/LaunchAgentManager/LaunchAgentManager.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public struct LaunchAgentManager {
1818
self.executablePath = executablePath
1919
}
2020

21+
public func setupLaunchAgentForTheFirstTimeIfNeeded() async throws {
22+
guard !FileManager.default.fileExists(atPath: launchAgentPath) else {
23+
return
24+
}
25+
try await setupLaunchAgent()
26+
await removeObsoleteLaunchAgent()
27+
}
28+
2129
public func setupLaunchAgent() async throws {
2230
let content = """
2331
<?xml version="1.0" encoding="UTF-8"?>
@@ -54,9 +62,16 @@ public struct LaunchAgentManager {
5462
try FileManager.default.removeItem(atPath: launchAgentPath)
5563
}
5664

57-
public func restartLaunchAgent() async throws {
65+
public func reloadLaunchAgent() async throws {
5866
try await helper("reload-launch-agent", "--service-identifier", serviceIdentifier)
5967
}
68+
69+
public func removeObsoleteLaunchAgent() async {
70+
let path = launchAgentPath.replacingOccurrences(of: "ExtensionService", with: "XPCService")
71+
if FileManager.default.fileExists(atPath: path) {
72+
try? FileManager.default.removeItem(atPath: path)
73+
}
74+
}
6075
}
6176

6277
private func process(_ launchPath: String, _ args: [String]) async throws {
@@ -98,8 +113,11 @@ private func process(_ launchPath: String, _ args: [String]) async throws {
98113
}
99114

100115
private func helper(_ args: String...) async throws {
116+
// TODO: A more robust way to locate the executable.
101117
guard let url = Bundle.main.executableURL?
102118
.deletingLastPathComponent()
119+
.deletingLastPathComponent()
120+
.appendingPathComponent("Applications")
103121
.appendingPathComponent("Helper")
104122
else { throw E(errorDescription: "Unable to locate Helper.") }
105123
return try await process(url.path, args)

EditorExtension/EditorExtension.entitlements

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</array>
1111
<key>com.apple.security.temporary-exception.mach-lookup.global-name</key>
1212
<array>
13-
<string>$(BUNDLE_IDENTIFIER_BASE).XPCService</string>
13+
<string>$(BUNDLE_IDENTIFIER_BASE).ExtensionService</string>
1414
</array>
1515
</dict>
1616
</plist>
Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,27 @@ import SwiftUI
88
import UserNotifications
99
import XPCShared
1010

11+
let bundleIdentifierBase = Bundle.main
12+
.object(forInfoDictionaryKey: "BUNDLE_IDENTIFIER_BASE") as! String
13+
let serviceIdentifier = bundleIdentifierBase + ".ExtensionService"
14+
15+
@main
1116
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
1217
let scheduledCleaner = ScheduledCleaner()
1318
private let userDefaultsObserver = UserDefaultsObserver()
1419
private var statusBarItem: NSStatusItem!
15-
20+
private var xpcListener: (NSXPCListener, ServiceDelegate)?
21+
1622
func applicationDidFinishLaunching(_: Notification) {
1723
// setup real-time suggestion controller
1824
_ = RealtimeSuggestionController.shared
19-
setupRestartOnUpdate()
25+
setupQuitOnUpdate()
2026
setupQuitOnUserTerminated()
21-
27+
xpcListener = setupXPCListener()
28+
os_log(.info, "XPC Service started.")
2229
NSApp.setActivationPolicy(.accessory)
2330
buildStatusBarMenu()
31+
AXIsProcessTrustedWithOptions(nil)
2432
}
2533

2634
@objc private func buildStatusBarMenu() {
@@ -107,13 +115,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
107115
UserDefaults.shared.set(isOn, forKey: SettingsKey.realtimeSuggestionToggle)
108116
}
109117

110-
func setupRestartOnUpdate() {
118+
func setupQuitOnUpdate() {
111119
Task {
112120
guard let url = Bundle.main.executableURL else { return }
113121
let checker = await FileChangeChecker(fileURL: url)
114122

115123
// If Xcode or Copilot for Xcode is made active, check if the executable of this program
116-
// is changed. If changed, restart the launch agent.
124+
// is changed. If changed, quit this program.
117125

118126
let sequence = NSWorkspace.shared.notificationCenter
119127
.notifications(named: NSWorkspace.didActivateApplicationNotification)
@@ -124,25 +132,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
124132
app.isUserOfService
125133
else { continue }
126134
guard await checker.checkIfChanged() else {
127-
os_log(.info, "XPC Service is not updated, no need to restart.")
135+
os_log(.info, "Extension Service is not updated, no need to quit.")
128136
continue
129137
}
130-
os_log(.info, "XPC Service will be restarted.")
138+
os_log(.info, "Extension Service will quit.")
131139
#if DEBUG
132140
#else
133-
let manager = LaunchAgentManager(
134-
serviceIdentifier: serviceIdentifier,
135-
executablePath: Bundle.main.executablePath ?? ""
136-
)
137-
do {
138-
try await manager.restartLaunchAgent()
139-
} catch {
140-
os_log(
141-
.error,
142-
"XPC Service failed to restart. %{public}s",
143-
error.localizedDescription
144-
)
145-
}
141+
exit(0)
146142
#endif
147143
}
148144
}
@@ -170,6 +166,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
170166
}
171167
}
172168
}
169+
170+
func setupXPCListener() -> (NSXPCListener, ServiceDelegate) {
171+
let listener = NSXPCListener(machServiceName: serviceIdentifier)
172+
let delegate = ServiceDelegate()
173+
listener.delegate = delegate
174+
listener.resume()
175+
return (listener, delegate)
176+
}
173177
}
174178

175179
private class UserDefaultsObserver: NSObject {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"colors" : [
3+
{
4+
"idiom" : "universal"
5+
}
6+
],
7+
"info" : {
8+
"author" : "xcode",
9+
"version" : 1
10+
}
11+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
{
2+
"images" : [
3+
{
4+
"filename" : "app-icon-realistic-materials_2x 9.png",
5+
"idiom" : "mac",
6+
"scale" : "1x",
7+
"size" : "16x16"
8+
},
9+
{
10+
"filename" : "app-icon-realistic-materials_2x 8.png",
11+
"idiom" : "mac",
12+
"scale" : "2x",
13+
"size" : "16x16"
14+
},
15+
{
16+
"filename" : "app-icon-realistic-materials_2x 7.png",
17+
"idiom" : "mac",
18+
"scale" : "1x",
19+
"size" : "32x32"
20+
},
21+
{
22+
"filename" : "app-icon-realistic-materials_2x 6.png",
23+
"idiom" : "mac",
24+
"scale" : "2x",
25+
"size" : "32x32"
26+
},
27+
{
28+
"filename" : "app-icon-realistic-materials_2x 5.png",
29+
"idiom" : "mac",
30+
"scale" : "1x",
31+
"size" : "128x128"
32+
},
33+
{
34+
"filename" : "app-icon-realistic-materials_2x 4.png",
35+
"idiom" : "mac",
36+
"scale" : "2x",
37+
"size" : "128x128"
38+
},
39+
{
40+
"filename" : "app-icon-realistic-materials_2x 3.png",
41+
"idiom" : "mac",
42+
"scale" : "1x",
43+
"size" : "256x256"
44+
},
45+
{
46+
"filename" : "app-icon-realistic-materials_2x 2.png",
47+
"idiom" : "mac",
48+
"scale" : "2x",
49+
"size" : "256x256"
50+
},
51+
{
52+
"filename" : "app-icon-realistic-materials_2x 1.png",
53+
"idiom" : "mac",
54+
"scale" : "1x",
55+
"size" : "512x512"
56+
},
57+
{
58+
"filename" : "app-icon-realistic-materials_2x.png",
59+
"idiom" : "mac",
60+
"scale" : "2x",
61+
"size" : "512x512"
62+
}
63+
],
64+
"info" : {
65+
"author" : "xcode",
66+
"version" : 1
67+
}
68+
}
306 KB
Loading

0 commit comments

Comments
 (0)