Files
soft_quay/core/domain/status_resolver.go
T

74 lines
1.7 KiB
Go
Raw Normal View History

2026-07-16 17:00:06 +08:00
package domain
import (
"errors"
"fmt"
)
var ErrInvalidStatusFacts = errors.New("invalid app status facts")
// AppStatusFacts are IO-free observations used to derive one visible state.
type AppStatusFacts struct {
Operation AppStatus
Running bool
RecoveryPending bool
Incompatible bool
InstalledVersion string
CatalogVersion string
}
// ResolveAppStatus derives the single user-visible state from local and
// background-operation facts.
func ResolveAppStatus(facts AppStatusFacts) (AppStatus, error) {
if facts.RecoveryPending {
return StatusRollbackPending, nil
}
if facts.Operation != "" {
if !validOperationStatus(facts.Operation) {
return "", fmt.Errorf(
"%w: operation %q",
ErrInvalidStatusFacts,
facts.Operation,
)
}
return facts.Operation, nil
}
if facts.Running {
return StatusRunning, nil
}
if facts.Incompatible {
return StatusIncompatible, nil
}
if facts.InstalledVersion == "" {
return StatusNotInstalled, nil
}
if _, err := ParseSemVer(facts.InstalledVersion); err != nil {
return "", fmt.Errorf("%w: installed version: %v", ErrInvalidStatusFacts, err)
}
if facts.CatalogVersion == "" {
return StatusInstalled, nil
}
comparison, err := CompareSemVer(facts.InstalledVersion, facts.CatalogVersion)
if err != nil {
return "", fmt.Errorf("%w: catalog version: %v", ErrInvalidStatusFacts, err)
}
if comparison < 0 {
return StatusUpdateAvailable, nil
}
return StatusInstalled, nil
}
func validOperationStatus(status AppStatus) bool {
switch status {
case StatusQueued,
StatusDownloading,
StatusVerifying,
StatusExtracting,
StatusInstalling,
StatusFailed:
return true
default:
return false
}
}