Skip to content

Commit 486b0fd

Browse files
committed
Merge branch 'feature/stop-embedding-githubcopilot-lsp' into develop
2 parents 4a218bf + f118d86 commit 486b0fd

9 files changed

Lines changed: 176 additions & 63 deletions

File tree

.gitmodules

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +0,0 @@
1-
[submodule "copilot.vim"]
2-
path = copilot.vim
3-
url = git@github.com:github/copilot.vim.git

Copilot for Xcode.xcodeproj/project.pbxproj

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
C8009BFF2941C551007AA7E8 /* ToggleRealtimeSuggestionsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8009BFE2941C551007AA7E8 /* ToggleRealtimeSuggestionsCommand.swift */; };
1111
C8009C032941C576007AA7E8 /* RealtimeSuggestionCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8009C022941C576007AA7E8 /* RealtimeSuggestionCommand.swift */; };
1212
C800DBB1294C624D00B04CAC /* PrefetchSuggestionsCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = C800DBB0294C624D00B04CAC /* PrefetchSuggestionsCommand.swift */; };
13-
C81291AE2994F8A000196E12 /* copilot in Copy CopilotLSP */ = {isa = PBXBuildFile; fileRef = C832A47B2940C71D000989F2 /* copilot */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
1413
C81291D72994FE6900196E12 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C81291D52994FE6900196E12 /* Main.storyboard */; };
1514
C814588F2939EFDC00135263 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C814588E2939EFDC00135263 /* Cocoa.framework */; };
1615
C81458942939EFDC00135263 /* SourceEditorExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C81458932939EFDC00135263 /* SourceEditorExtension.swift */; };
@@ -68,17 +67,6 @@
6867
/* End PBXContainerItemProxy section */
6968

7069
/* Begin PBXCopyFilesBuildPhase section */
71-
C81291AD2994F88D00196E12 /* Copy CopilotLSP */ = {
72-
isa = PBXCopyFilesBuildPhase;
73-
buildActionMask = 2147483647;
74-
dstPath = "";
75-
dstSubfolderSpec = 7;
76-
files = (
77-
C81291AE2994F8A000196E12 /* copilot in Copy CopilotLSP */,
78-
);
79-
name = "Copy CopilotLSP";
80-
runOnlyForDeploymentPostprocessing = 0;
81-
};
8270
C814589F2939EFDC00135263 /* Embed Foundation Extensions */ = {
8371
isa = PBXCopyFilesBuildPhase;
8472
buildActionMask = 2147483647;
@@ -159,7 +147,6 @@
159147
C8216B70298036EC00AD38C7 /* Helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Helper; sourceTree = BUILT_PRODUCTS_DIR; };
160148
C8216B72298036EC00AD38C7 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
161149
C8216B772980370100AD38C7 /* ReloadLaunchAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReloadLaunchAgent.swift; sourceTree = "<group>"; };
162-
C832A47B2940C71D000989F2 /* copilot */ = {isa = PBXFileReference; lastKnownFileType = folder; name = copilot; path = copilot.vim/copilot; sourceTree = "<group>"; };
163150
C8520300293C4D9000460097 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
164151
C8520308293D805800460097 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
165152
C861A6A229E5503F005C41A3 /* PromptToCodeCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PromptToCodeCommand.swift; sourceTree = "<group>"; };
@@ -259,7 +246,6 @@
259246
C81458AD293A009600135263 /* Config.xcconfig */,
260247
C81458AE293A009800135263 /* Config.debug.xcconfig */,
261248
C8CD828229B88006008D044D /* TestPlan.xctestplan */,
262-
C832A47B2940C71D000989F2 /* copilot */,
263249
C8189B282938979000C9DCDA /* Core */,
264250
C8189B182938972F00C9DCDA /* Copilot for Xcode */,
265251
C81458922939EFDC00135263 /* EditorExtension */,
@@ -400,7 +386,6 @@
400386
C861E60A2994F6070056CB02 /* Sources */,
401387
C861E60B2994F6070056CB02 /* Frameworks */,
402388
C861E60C2994F6070056CB02 /* Resources */,
403-
C81291AD2994F88D00196E12 /* Copy CopilotLSP */,
404389
);
405390
buildRules = (
406391
);

Core/Package.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,13 @@ let package = Package(
255255

256256
.target(
257257
name: "GitHubCopilotService",
258-
dependencies: ["LanguageClient", "SuggestionModel", "XPCShared", "Preferences"]
258+
dependencies: [
259+
"LanguageClient",
260+
"SuggestionModel",
261+
"XPCShared",
262+
"Preferences",
263+
"Terminal",
264+
]
259265
),
260266
.testTarget(
261267
name: "GitHubCopilotServiceTests",

Core/Sources/CodeiumService/CodeiumInstallationManager.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Terminal
33

44
public struct CodeiumInstallationManager {
55
private static var isInstalling = false
6-
static let latestSupportedVersion: String = "1.2.17"
6+
static let latestSupportedVersion = "1.2.17"
77

88
public init() {}
99

@@ -72,11 +72,12 @@ public struct CodeiumInstallationManager {
7272
try FileManager.default.copyItem(at: fileURL, to: targetURL)
7373
defer { try? FileManager.default.removeItem(at: targetURL) }
7474

75+
// uninstall
7576
continuation.yield(.uninstalling)
7677
try await uninstall()
7778

78-
continuation.yield(.decompressing)
7979
// extract file
80+
continuation.yield(.decompressing)
8081
let terminal = Terminal()
8182
_ = try await terminal.runCommand(
8283
"/usr/bin/gunzip",

Core/Sources/GitHubCopilotService/GitHubCopilotInstallationManager.swift

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,49 @@ import Terminal
44
public struct GitHubCopilotInstallationManager {
55
private static var isInstalling = false
66

7+
static var downloadURL: URL {
8+
let commitHash = "1358e8e45ecedc53daf971924a0541ddf6224faf"
9+
let link = "https://github.com/github/copilot.vim/archive/\(commitHash).zip"
10+
return URL(string: link)!
11+
}
12+
13+
static let latestSupportedVersion = "1.8.4"
14+
715
public init() {}
816

917
public enum InstallationStatus {
1018
case notInstalled
11-
case installed
19+
case installed(String)
20+
case outdated(current: String, latest: String)
21+
case unsupported(current: String, latest: String)
1222
}
1323

1424
public func checkInstallation() -> InstallationStatus {
1525
guard let urls = try? GitHubCopilotBaseService.createFoldersIfNeeded()
1626
else { return .notInstalled }
1727
let executableFolderURL = urls.executableURL
1828
let binaryURL = executableFolderURL.appendingPathComponent("copilot")
29+
let versionFileURL = executableFolderURL.appendingPathComponent("version")
1930

2031
if !FileManager.default.fileExists(atPath: binaryURL.path) {
2132
return .notInstalled
2233
}
2334

24-
return .installed
35+
if FileManager.default.fileExists(atPath: versionFileURL.path),
36+
let versionData = try? Data(contentsOf: versionFileURL),
37+
let version = String(data: versionData, encoding: .utf8)
38+
{
39+
switch version.compare(Self.latestSupportedVersion) {
40+
case .orderedAscending:
41+
return .outdated(current: version, latest: Self.latestSupportedVersion)
42+
case .orderedSame:
43+
return .installed(version)
44+
case .orderedDescending:
45+
return .unsupported(current: version, latest: Self.latestSupportedVersion)
46+
}
47+
}
48+
49+
return .outdated(current: "Unknown", latest: Self.latestSupportedVersion)
2550
}
2651

2752
public enum InstallationStep {
@@ -34,13 +59,16 @@ public struct GitHubCopilotInstallationManager {
3459
public enum Error: Swift.Error, LocalizedError {
3560
case isInstalling
3661
case failedToFindLanguageServer
62+
case failedToInstallLanguageServer
3763

3864
public var errorDescription: String? {
3965
switch self {
4066
case .isInstalling:
4167
return "Language server is installing."
4268
case .failedToFindLanguageServer:
4369
return "Failed to find language server. Please open an issue on GitHub."
70+
case .failedToInstallLanguageServer:
71+
return "Failed to install language server. Please open an issue on GitHub."
4472
}
4573
}
4674
}
@@ -57,22 +85,63 @@ public struct GitHubCopilotInstallationManager {
5785
do {
5886
continuation.yield(.downloading)
5987
let urls = try GitHubCopilotBaseService.createFoldersIfNeeded()
60-
let executable = Bundle.main.bundleURL.appendingPathComponent("Contents/Applications/CopilotForXcodeExtensionService.app/Contents/Resources/copilot")
61-
guard FileManager.default.fileExists(atPath: executable.path) else {
62-
throw Error.failedToFindLanguageServer
63-
}
64-
65-
let targetURL = urls.executableURL.appendingPathComponent("copilot")
6688

67-
try FileManager.default.copyItem(
68-
at: executable,
69-
to: targetURL
89+
// download
90+
let (fileURL, _) = try await URLSession.shared.download(from: Self.downloadURL)
91+
let targetURL = urls.executableURL.appendingPathComponent("archive")
92+
.appendingPathExtension("zip")
93+
try FileManager.default.copyItem(at: fileURL, to: targetURL)
94+
defer { try? FileManager.default.removeItem(at: targetURL) }
95+
96+
// uninstall
97+
continuation.yield(.uninstalling)
98+
try await uninstall()
99+
100+
// decompress
101+
continuation.yield(.decompressing)
102+
let terminal = Terminal()
103+
104+
_ = try await terminal.runCommand(
105+
"/usr/bin/unzip",
106+
arguments: [targetURL.path],
107+
currentDirectoryPath: urls.executableURL.path,
108+
environment: [:]
70109
)
71110

111+
let contentURLs = try FileManager.default.contentsOfDirectory(
112+
at: urls.executableURL,
113+
includingPropertiesForKeys: nil,
114+
options: []
115+
)
116+
117+
defer {
118+
for url in contentURLs {
119+
try? FileManager.default.removeItem(at: url)
120+
}
121+
}
122+
123+
guard let gitFolderURL = contentURLs
124+
.first(where: { $0.lastPathComponent.hasPrefix("copilot.vim") })
125+
else {
126+
continuation.finish(throwing: Error.failedToInstallLanguageServer)
127+
return
128+
}
129+
130+
let lspURL = gitFolderURL.appendingPathComponent("copilot")
131+
let installationURL = urls.executableURL.appendingPathComponent("copilot")
132+
try FileManager.default.copyItem(at: lspURL, to: installationURL)
133+
72134
// update permission 755
73135
try FileManager.default.setAttributes(
74136
[.posixPermissions: 0o755],
75-
ofItemAtPath: targetURL.path
137+
ofItemAtPath: installationURL.path
138+
)
139+
140+
// create version file
141+
let data = Self.latestSupportedVersion.data(using: .utf8)
142+
FileManager.default.createFile(
143+
atPath: urls.executableURL.appendingPathComponent("version").path,
144+
contents: data
76145
)
77146

78147
continuation.yield(.done)
@@ -89,8 +158,13 @@ public struct GitHubCopilotInstallationManager {
89158
else { return }
90159
let executableFolderURL = urls.executableURL
91160
let binaryURL = executableFolderURL.appendingPathComponent("copilot")
161+
let versionFileURL = executableFolderURL.appendingPathComponent("version")
92162
if FileManager.default.fileExists(atPath: binaryURL.path) {
93163
try FileManager.default.removeItem(at: binaryURL)
94164
}
165+
if FileManager.default.fileExists(atPath: versionFileURL.path) {
166+
try FileManager.default.removeItem(at: versionFileURL)
167+
}
95168
}
96169
}
170+

Core/Sources/HostApp/AccountSettings/CopilotView.swift

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ struct CopilotView: View {
1616

1717
init() {}
1818
}
19-
19+
2020
class ViewModel: ObservableObject {
2121
let installationManager = GitHubCopilotInstallationManager()
22-
22+
2323
@Published var installationStatus: GitHubCopilotInstallationManager.InstallationStatus
2424
@Published var installationStep: GitHubCopilotInstallationManager.InstallationStep?
25-
25+
2626
init() {
2727
installationStatus = installationManager.checkInstallation()
2828
}
29-
29+
3030
init(
3131
installationStatus: GitHubCopilotInstallationManager.InstallationStatus,
3232
installationStep: GitHubCopilotInstallationManager.InstallationStep?
@@ -35,13 +35,13 @@ struct CopilotView: View {
3535
self.installationStatus = installationStatus
3636
self.installationStep = installationStep
3737
}
38-
38+
3939
func refreshInstallationStatus() {
4040
Task { @MainActor in
4141
installationStatus = installationManager.checkInstallation()
4242
}
4343
}
44-
44+
4545
func install() async throws {
4646
defer { refreshInstallationStatus() }
4747
do {
@@ -92,7 +92,7 @@ struct CopilotView: View {
9292
Self.copilotAuthService = service
9393
return service
9494
}
95-
95+
9696
var installButton: some View {
9797
Button(action: {
9898
Task {
@@ -108,6 +108,21 @@ struct CopilotView: View {
108108
.disabled(viewModel.installationStep != nil)
109109
}
110110

111+
var updateButton: some View {
112+
Button(action: {
113+
Task {
114+
do {
115+
try await viewModel.install()
116+
} catch {
117+
toast(Text(error.localizedDescription), .error)
118+
}
119+
}
120+
}) {
121+
Text("Update")
122+
}
123+
.disabled(viewModel.installationStep != nil)
124+
}
125+
111126
var uninstallButton: some View {
112127
Button(action: {
113128
viewModel.uninstall()
@@ -150,14 +165,26 @@ struct CopilotView: View {
150165

151166
VStack(alignment: .leading) {
152167
HStack {
153-
Text("Language Server Version: \(version ?? "Loading..")")
154168
switch viewModel.installationStatus {
155169
case .notInstalled:
170+
Text("Copilot.Vim Version: Not Installed")
156171
installButton
157-
case .installed:
172+
case let .installed(version):
173+
Text("Copilot.Vim Version: \(version)")
174+
uninstallButton
175+
case let .outdated(version, latest):
176+
Text("Copilot.Vim Version: \(version) (Update Available: \(latest))")
177+
updateButton
178+
uninstallButton
179+
case let .unsupported(version, latest):
180+
Text("Copilot.Vim Version: \(version) (Supported Version: \(latest))")
181+
updateButton
158182
uninstallButton
159183
}
160184
}
185+
186+
Text("Language Server Version: \(version ?? "Loading..")")
187+
161188
Text("Status: \(status?.description ?? "Loading..")")
162189

163190
HStack(alignment: .center) {
@@ -208,6 +235,20 @@ struct CopilotView: View {
208235
Self.copilotAuthService = nil
209236
}.onChange(of: settings.nodePath) { _ in
210237
Self.copilotAuthService = nil
238+
}.onChange(of: viewModel.installationStep) { newValue in
239+
if let step = newValue {
240+
switch step {
241+
case .downloading:
242+
toast(Text("Downloading.."), .info)
243+
case .uninstalling:
244+
toast(Text("Uninstalling old version.."), .info)
245+
case .decompressing:
246+
toast(Text("Decompressing.."), .info)
247+
case .done:
248+
toast(Text("Done!"), .info)
249+
checkStatus()
250+
}
251+
}
211252
}
212253
}
213254

0 commit comments

Comments
 (0)