forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRefactInstallationManager.swift
More file actions
108 lines (89 loc) · 3.91 KB
/
Copy pathRefactInstallationManager.swift
File metadata and controls
108 lines (89 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import Foundation
import Terminal
public struct RefactInstallationManager {
private static var isInstalling = false
public init() {}
public enum InstallationStatus {
case notInstalled
case installed
}
public func checkInstallation() -> InstallationStatus {
guard let urls = try? RefactSuggestionService.createFoldersIfNeeded()
else { return .notInstalled }
let executableFolderURL = urls.executableURL
let binaryURL = executableFolderURL.appendingPathComponent("refact-lsp")
if !FileManager.default.fileExists(atPath: binaryURL.path) {
return .notInstalled
} else {
return .installed
}
}
public enum InstallationStep {
case downloading
case uninstalling
case decompressing
case done
}
public func installLatestVersion() -> AsyncThrowingStream<InstallationStep, Error> {
AsyncThrowingStream<InstallationStep, Error> { continuation in
Task {
guard !RefactInstallationManager.isInstalling else {
continuation.finish(throwing: RefactError.languageServiceIsInstalling)
return
}
RefactInstallationManager.isInstalling = true
defer { RefactInstallationManager.isInstalling = false }
do {
continuation.yield(.downloading)
let urls = try RefactSuggestionService.createFoldersIfNeeded()
let file = isAppleSilicon() ? "dist-aarch64-apple-darwin": "dist-x86_64-apple-darwin"
let urlString = "https://nightly.link/smallcloudai/refact-lsp/workflows/build/main/\(file).zip"
guard let url = URL(string: urlString) else { return }
// download
let (fileURL, _) = try await URLSession.shared.download(from: url)
let targetURL = urls.executableURL.appendingPathComponent(file).appendingPathExtension("zip")
try FileManager.default.copyItem(at: fileURL, to: targetURL)
defer { try? FileManager.default.removeItem(at: targetURL) }
// uninstall
continuation.yield(.uninstalling)
try await uninstall()
// extract file
continuation.yield(.decompressing)
let terminal = Terminal()
_ = try await terminal.runCommand(
"/usr/bin/unzip",
arguments: [targetURL.path],
currentDirectoryURL: urls.executableURL,
environment: [:]
)
let executableURL = targetURL.deletingLastPathComponent().appendingPathComponent("refact-lsp")
// update permission 755
try FileManager.default.setAttributes(
[.posixPermissions: 0o755],
ofItemAtPath: executableURL.path
)
continuation.yield(.done)
continuation.finish()
} catch {
continuation.finish(throwing: error)
}
}
}
}
public func uninstall() async throws {
guard let urls = try? RefactSuggestionService.createFoldersIfNeeded()
else { return }
let executableFolderURL = urls.executableURL
let binaryURL = executableFolderURL.appendingPathComponent("refact-lsp")
if FileManager.default.fileExists(atPath: binaryURL.path) {
try FileManager.default.removeItem(at: binaryURL)
}
}
}
func isAppleSilicon() -> Bool {
var result = false
#if arch(arm64)
result = true
#endif
return result
}