Skip to content

Fix package install detection for packages that are partially installed #178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions Sources/LinuxPlatform/Linux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,11 @@ public struct Linux: Platform {

let manager: String? = switch platformName {
case "ubuntu1804":
"apt"
"apt-get"
case "ubuntu2004":
"apt"
"apt-get"
case "ubuntu2204":
"apt"
"apt-get"
case "amazonlinux2":
"yum"
case "ubi9":
Expand Down Expand Up @@ -216,21 +216,38 @@ public struct Linux: Platform {
return nil
}

let missingPackages = packages.filter { !self.isSystemPackageInstalled(manager, $0) }.joined(separator: " ")
var missingPackages: [String] = []

for pkg in packages {
if case let pkgInstalled = await self.isSystemPackageInstalled(manager, pkg), !pkgInstalled {
missingPackages.append(pkg)
}
}

guard !missingPackages.isEmpty else {
return nil
}

return "\(manager) -y install \(missingPackages)"
return "\(manager) -y install \(missingPackages.joined(separator: " "))"
}

public func isSystemPackageInstalled(_ manager: String?, _ package: String) -> Bool {
public func isSystemPackageInstalled(_ manager: String?, _ package: String) async -> Bool {
do {
switch manager {
case "apt":
try self.runProgram("dpkg", "-l", package, quiet: true)
return true
case "apt-get":
if let pkgList = try await self.runProgramOutput("dpkg", "-l", package) {
// The package might be listed but not in an installed non-error state.
//
// Look for something like this:
//
// Desired=Unknown/Install/Remove/Purge/Hold
// | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
// |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
// ||/
// ii pkgfoo 1.0.0ubuntu12 My description goes here....
return pkgList.contains("\nii ")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works, but is there something we could look for which is more indicative of an error than \nii? 🤔 If not, LGTM

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the dpkg -l command fails then that is treated as an indication that the package isn't installed, which throws an error caught below. It's just that this output can be that the package is partially installed, which requires this output check here. I don't think that there's much else we can do.

}
return false
case "yum":
try self.runProgram("yum", "list", "installed", package, quiet: true)
return true
Expand Down