Skip to content

Commit 685c7b7

Browse files
committed
Fix package install detection for packages that are partially installed.
On Debian/Ubuntu Linux that use the dpkg/apt package manager there is a possibility that a package is not in a fully installed state. It can be removed, leaving its configuration files, or the install could have failed. Check rigorously that the package is fully installed without error before producing the command-line. Also, correct the install command to use apt-get instead of apt since that command-line is guaranteed to be stable.
1 parent 826ac66 commit 685c7b7

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

Sources/LinuxPlatform/Linux.swift

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,11 @@ public struct Linux: Platform {
164164

165165
let manager: String? = switch platformName {
166166
case "ubuntu1804":
167-
"apt"
167+
"apt-get"
168168
case "ubuntu2004":
169-
"apt"
169+
"apt-get"
170170
case "ubuntu2204":
171-
"apt"
171+
"apt-get"
172172
case "amazonlinux2":
173173
"yum"
174174
case "ubi9":
@@ -216,21 +216,38 @@ public struct Linux: Platform {
216216
return nil
217217
}
218218

219-
let missingPackages = packages.filter { !self.isSystemPackageInstalled(manager, $0) }.joined(separator: " ")
219+
var missingPackages: [String] = []
220+
221+
for pkg in packages {
222+
if case let pkgInstalled = await self.isSystemPackageInstalled(manager, pkg), !pkgInstalled {
223+
missingPackages.append(pkg)
224+
}
225+
}
220226

221227
guard !missingPackages.isEmpty else {
222228
return nil
223229
}
224230

225-
return "\(manager) -y install \(missingPackages)"
231+
return "\(manager) -y install \(missingPackages.joined(separator: " "))"
226232
}
227233

228-
public func isSystemPackageInstalled(_ manager: String?, _ package: String) -> Bool {
234+
public func isSystemPackageInstalled(_ manager: String?, _ package: String) async -> Bool {
229235
do {
230236
switch manager {
231-
case "apt":
232-
try self.runProgram("dpkg", "-l", package, quiet: true)
233-
return true
237+
case "apt-get":
238+
if let pkgList = try await self.runProgramOutput("dpkg", "-l", package) {
239+
// The package might be listed but not in an installed non-error state.
240+
//
241+
// Look for something like this:
242+
//
243+
// Desired=Unknown/Install/Remove/Purge/Hold
244+
// | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
245+
// |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
246+
// ||/
247+
// ii pkgfoo 1.0.0ubuntu12 My description goes here....
248+
return pkgList.contains("\nii ")
249+
}
250+
return false
234251
case "yum":
235252
try self.runProgram("yum", "list", "installed", package, quiet: true)
236253
return true

0 commit comments

Comments
 (0)