Skip to content

Commit b9d3945

Browse files
Refactors
1 parent c827108 commit b9d3945

11 files changed

+212
-207
lines changed

CodeEdit/Features/LSP/Registry/PackageManagerFactory.swift

Lines changed: 0 additions & 67 deletions
This file was deleted.

CodeEdit/Features/LSP/Registry/PackageManagers/CargoPackageManager.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class CargoPackageManager: PackageManagerProtocol {
3737
let packagePath = installationDirectory.appending(path: source.name)
3838
print("Installing \(source.name)@\(source.version) in \(packagePath.path)")
3939

40+
try await initialize(in: packagePath)
41+
4042
do {
4143
var cargoArgs = ["cargo", "install", "--root", "."]
4244

@@ -50,7 +52,7 @@ class CargoPackageManager: PackageManagerProtocol {
5052
cargoArgs.append(contentsOf: ["--rev", rev])
5153
}
5254
} else {
53-
cargoArgs.append(contentsOf: ["--version", source.version])
55+
cargoArgs.append("\(source.name)@\(source.version)")
5456
}
5557

5658
if let features = source.options["features"] {
@@ -59,7 +61,6 @@ class CargoPackageManager: PackageManagerProtocol {
5961
if source.options["locked"] == "true" {
6062
cargoArgs.append("--locked")
6163
}
62-
cargoArgs.append(source.name)
6364

6465
_ = try await executeInDirectory(in: packagePath.path, cargoArgs)
6566
print("Successfully installed \(source.name)@\(source.version)")

CodeEdit/Features/LSP/Registry/PackageManagers/GithubPackageManager.swift

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,32 @@ class GithubPackageManager: PackageManagerProtocol {
1717
self.shellClient = .live()
1818
}
1919

20-
func initialize(in packagePath: URL) async throws { }
20+
func initialize(in packagePath: URL) async throws {
21+
guard await isInstalled() else {
22+
throw PackageManagerError.packageManagerNotInstalled
23+
}
24+
25+
do {
26+
try createDirectoryStructure(for: packagePath)
27+
} catch {
28+
throw PackageManagerError.initializationFailed(error.localizedDescription)
29+
}
30+
}
2131

2232
func install(method: InstallationMethod) async throws {
33+
guard case .standardPackage(let source) = method else {
34+
throw PackageManagerError.invalidConfiguration
35+
}
36+
37+
let packagePath = installationDirectory.appending(path: source.name)
38+
try await initialize(in: packagePath)
39+
2340
switch method {
2441
case let .binaryDownload(source, url):
25-
downloadBinary(source, url)
42+
try await downloadBinary(source, url)
2643
break
2744
case let .sourceBuild(source, command):
28-
installFromSource(source, command)
45+
try await installFromSource(source, command)
2946
break
3047
case .standardPackage(_), .unknown:
3148
throw PackageManagerError.invalidConfiguration
@@ -48,12 +65,34 @@ class GithubPackageManager: PackageManagerProtocol {
4865
return false
4966
}
5067
}
51-
52-
private func downloadBinary(_ source: PackageSource, _ url: String) {
53-
68+
69+
private func downloadBinary(_ source: PackageSource, _ url: URL) async throws {
70+
let (data, _) = try await URLSession.shared.data(from: url)
71+
let fileName = url.lastPathComponent
72+
let downloadPath = installationDirectory.appending(path: source.name)
73+
let packagePath = downloadPath.appending(path: fileName)
74+
75+
if !FileManager.default.fileExists(atPath: packagePath.path) {
76+
throw RegistryManagerError.downloadFailed(
77+
url: url,
78+
error: NSError(domain: "Coould not download package", code: -1)
79+
)
80+
}
81+
82+
if fileName.hasSuffix(".tar") || fileName.hasSuffix(".zip") {
83+
try FileManager.default.unzipItem(at: packagePath, to: downloadPath)
84+
}
5485
}
55-
56-
private func installFromSource(_ source: PackageSource, _ command: String) {
57-
86+
87+
private func installFromSource(_ source: PackageSource, _ command: String) async throws {
88+
let installPath = installationDirectory.appending(path: source.name, directoryHint: .isDirectory)
89+
do {
90+
_ = try await executeInDirectory(in: installPath.path, ["git", "clone", source.repositoryUrl!])
91+
let repoPath = installPath.appending(path: source.name, directoryHint: .isDirectory)
92+
_ = try await executeInDirectory(in: repoPath.path, [command])
93+
} catch {
94+
print("Failed to build from source: \(error)")
95+
throw PackageManagerError.installationFailed("Source build failed.")
96+
}
5897
}
5998
}

CodeEdit/Features/LSP/Registry/PackageManagers/GolangPackageManager.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class GolangPackageManager: PackageManagerProtocol {
2525
try createDirectoryStructure(for: packagePath)
2626

2727
// For Go, we need to set up a proper module structure
28-
let goModPath = packagePath.appendingPathComponent("go.mod")
28+
let goModPath = packagePath.appending(path: "go.mod")
2929
if !FileManager.default.fileExists(atPath: goModPath.path) {
3030
let moduleName = "codeedit.temp/placeholder"
3131
_ = try await executeInDirectory(
@@ -48,6 +48,9 @@ class GolangPackageManager: PackageManagerProtocol {
4848
try await initialize(in: packagePath)
4949

5050
do {
51+
let gobinPath = packagePath.appending(path: "bin", directoryHint: .isDirectory).path
52+
var goInstallCommand = ["env", "GOBIN=\(gobinPath)", "go", "install"]
53+
5154
if let gitRef = source.gitReference, let repoUrl = source.repositoryUrl {
5255
// Check if this is a Git-based package
5356
var packageName = source.name
@@ -63,17 +66,11 @@ class GolangPackageManager: PackageManagerProtocol {
6366
gitVersion = rev
6467
}
6568

66-
let versionedPackage = "\(packageName)@\(gitVersion)"
67-
_ = try await executeInDirectory(
68-
in: packagePath.path, ["go get \(versionedPackage)"]
69-
)
69+
goInstallCommand.append("\(packageName)@\(gitVersion)")
7070
} else {
71-
// Standard package installation
72-
let versionedPackage = "\(source.name)@\(source.version)"
73-
_ = try await executeInDirectory(
74-
in: packagePath.path, ["go get \(versionedPackage)"]
75-
)
71+
goInstallCommand.append("\(source.name)@\(source.version)")
7672
}
73+
_ = try await executeInDirectory(in: packagePath.path, goInstallCommand)
7774

7875
// If there's a subpath, build the binary
7976
if let subpath = source.options["subpath"] {

CodeEdit/Features/LSP/Registry/PackageManagers/PackageManagerProtocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ enum InstallationMethod: Equatable {
130130
/// For packages that need to be built from source with custom build steps
131131
case sourceBuild(source: PackageSource, command: String)
132132
/// For direct binary downloads
133-
case binaryDownload(source: PackageSource, url: String)
133+
case binaryDownload(source: PackageSource, url: URL)
134134
/// For installations that aren't recognized
135135
case unknown
136136

CodeEdit/Features/LSP/Registry/PackageManagers/PackageSourceParser.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ enum PackageSourceParser {
345345
let gitReference: GitReference = isCommitHash ? .revision(version) : .tag(version)
346346

347347
// Is this going to be built from source or downloaded
348-
let isSourceBuild = if case .none? = entry.source.asset {
348+
let isSourceBuild = if entry.source.asset == nil {
349349
true
350350
} else {
351351
false
@@ -390,7 +390,7 @@ enum PackageSourceParser {
390390
return .unknown
391391
}
392392

393-
let downloadURL = "\(repoURL)/releases/download/\(gitTag)/\(fileName)"
393+
let downloadURL = URL(string: "\(repoURL)/releases/download/\(gitTag)/\(fileName)")!
394394
return .binaryDownload(source: pkgSource, url: downloadURL)
395395
}
396396

@@ -399,7 +399,7 @@ enum PackageSourceParser {
399399
_ entry: RegistryItem
400400
) -> InstallationMethod {
401401
guard let build = entry.source.build,
402-
var command = build.getUnixBuildCommand()
402+
let command = build.getUnixBuildCommand()
403403
else {
404404
return .unknown
405405
}

CodeEdit/Features/LSP/Registry/PackageManagers/PipPackageManager.swift

Lines changed: 19 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ class PipPackageManager: PackageManagerProtocol {
6565
}
6666

6767
_ = try await executeInDirectory(in: packagePath.path, installArgs)
68-
try updateRequirements(
69-
packagePath: packagePath,
70-
package: source.name,
71-
version: source.version,
72-
extras: extras
73-
)
68+
try await updateRequirements(packagePath: packagePath)
7469
try await verifyInstallation(packagePath: packagePath, package: source.name)
7570

7671
print("Successfully installed \(source.name)@\(source.version)")
@@ -119,46 +114,35 @@ class PipPackageManager: PackageManagerProtocol {
119114
}
120115

121116
/// Update the requirements.txt file with the installed package and extras
122-
private func updateRequirements(packagePath: URL, package: String, version: String, extras: String? = nil) throws {
117+
private func updateRequirements(packagePath: URL) async throws {
118+
let pipCommand = getPipCommand(in: packagePath)
123119
let requirementsPath = packagePath.appendingPathComponent("requirements.txt")
124-
var requirementsContent = ""
125120

126-
if FileManager.default.fileExists(atPath: requirementsPath.path),
127-
let existingContent = try? String(contentsOf: requirementsPath, encoding: .utf8) {
128-
requirementsContent = existingContent
129-
}
130-
131-
var packageLine = "\(package)"
132-
if let extras = extras {
133-
packageLine += "[\(extras)]"
134-
}
135-
packageLine += "==\(version)"
136-
137-
let packagePattern = "^\\s*\(package)(\\[.*\\])?\\s*==.*$"
138-
if let range = requirementsContent.range(of: packagePattern, options: .regularExpression) {
139-
// Replace existing version
140-
requirementsContent.replaceSubrange(range, with: packageLine)
141-
} else {
142-
// Add package to requirements
143-
if !requirementsContent.isEmpty && !requirementsContent.hasSuffix("\n") {
144-
requirementsContent += "\n"
145-
}
146-
requirementsContent += "\(packageLine)\n"
147-
}
121+
let freezeOutput = try await executeInDirectory(
122+
in: packagePath.path,
123+
["\(pipCommand)", "freeze"]
124+
)
148125

126+
let requirementsContent = freezeOutput.joined(separator: "\n") + "\n"
149127
try requirementsContent.write(to: requirementsPath, atomically: true, encoding: .utf8)
150128
}
151129

152130
private func verifyInstallation(packagePath: URL, package: String) async throws {
153131
let pipCommand = getPipCommand(in: packagePath)
154132
let output = try await executeInDirectory(
155-
in: packagePath.path, ["\(pipCommand) list"]
133+
in: packagePath.path, ["\(pipCommand)", "list", "--format=freeze"]
156134
)
157135

158-
// Check if the package appears in pip list
159-
let packagePattern = "^\(package)\\s+.*$"
160-
let packageFound = output.contains { line in
161-
line.range(of: packagePattern, options: .regularExpression) != nil
136+
// Normalize package names for comparison
137+
let normalizedPackageHyphen = package.replacingOccurrences(of: "_", with: "-").lowercased()
138+
let normalizedPackageUnderscore = package.replacingOccurrences(of: "-", with: "_").lowercased()
139+
140+
// Check if the package name appears in requirements.txt
141+
let installedPackages = output.map { line in
142+
line.lowercased().split(separator: "=").first?.trimmingCharacters(in: .whitespacesAndNewlines)
143+
}
144+
let packageFound = installedPackages.contains { installedPackage in
145+
installedPackage == normalizedPackageHyphen || installedPackage == normalizedPackageUnderscore
162146
}
163147

164148
guard packageFound else {

CodeEdit/Features/LSP/Registry/RegistryItemTemplateParser.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ enum RegistryItemTemplateParser {
5454
// Find all {{ ... }} patterns
5555
let pattern = "\\{\\{([^\\}]+)\\}\\}"
5656
let regex = try NSRegularExpression(pattern: pattern, options: [])
57-
let matches = regex.matches(in: template, options: [], range: NSRange(location: 0, length: template.utf16.count))
57+
let matches = regex.matches(
58+
in: template,
59+
options: [],
60+
range: NSRange(location: 0, length: template.utf16.count)
61+
)
5862

5963
// Process matches in reverse order to not invalidate ranges
6064
for match in matches.reversed() {
@@ -72,8 +76,8 @@ enum RegistryItemTemplateParser {
7276
// Apply filters
7377
var processedValue = value
7478
if components.count > 1 {
75-
for i in 1..<components.count {
76-
let filterString = components[i].trimmingCharacters(in: .whitespaces)
79+
for item in 1..<components.count {
80+
let filterString = components[item].trimmingCharacters(in: .whitespaces)
7781
let filter = try Filter.parse(filterString)
7882
processedValue = filter.apply(to: processedValue)
7983
}

0 commit comments

Comments
 (0)