mirror of
https://github.com/chenasraf/sofmani.git
synced 2026-05-17 17:28:04 +00:00
265 lines
6.6 KiB
Go
Executable File
265 lines
6.6 KiB
Go
Executable File
package platform
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"slices"
|
|
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
var osValue string = runtime.GOOS // osValue stores the current operating system.
|
|
var archValue string = runtime.GOARCH // archValue stores the current architecture.
|
|
|
|
// getOS returns the current operating system. It caches the value after the first call.
|
|
func getOS() string {
|
|
if osValue == "" {
|
|
osValue = runtime.GOOS
|
|
}
|
|
return osValue
|
|
}
|
|
|
|
// SetOS overrides the detected operating system. This is primarily used for testing.
|
|
func SetOS(v string) {
|
|
osValue = v
|
|
}
|
|
|
|
// getArch returns the current architecture. It caches the value after the first call.
|
|
func getArch() string {
|
|
if archValue == "" {
|
|
archValue = runtime.GOARCH
|
|
}
|
|
return archValue
|
|
}
|
|
|
|
// SetArch overrides the detected architecture. This is primarily used for testing.
|
|
func SetArch(v string) {
|
|
archValue = v
|
|
}
|
|
|
|
// Architecture represents a CPU architecture.
|
|
type Architecture string
|
|
|
|
// Constants for supported architectures.
|
|
const (
|
|
ArchAmd64 Architecture = "amd64" // ArchAmd64 represents x86_64 architecture.
|
|
ArchArm64 Architecture = "arm64" // ArchArm64 represents ARM64 architecture.
|
|
)
|
|
|
|
// GetArch returns the current architecture (amd64 or arm64).
|
|
func GetArch() Architecture {
|
|
switch getArch() {
|
|
case "amd64", "x86_64":
|
|
return ArchAmd64
|
|
case "arm64", "aarch64":
|
|
return ArchArm64
|
|
default:
|
|
return Architecture(getArch())
|
|
}
|
|
}
|
|
|
|
// GetArchAlias returns the architecture in common alias format (x86_64 or arm64).
|
|
func GetArchAlias() string {
|
|
switch GetArch() {
|
|
case ArchAmd64:
|
|
return "x86_64"
|
|
case ArchArm64:
|
|
return "arm64"
|
|
default:
|
|
return string(GetArch())
|
|
}
|
|
}
|
|
|
|
// GetArchGnu returns the architecture in GNU/Linux format (x86_64 or aarch64).
|
|
func GetArchGnu() string {
|
|
switch GetArch() {
|
|
case ArchAmd64:
|
|
return "x86_64"
|
|
case ArchArm64:
|
|
return "aarch64"
|
|
default:
|
|
return string(GetArch())
|
|
}
|
|
}
|
|
|
|
// GetPlatform returns the current platform (macos, linux, or windows).
|
|
func GetPlatform() Platform {
|
|
switch getOS() {
|
|
case "darwin":
|
|
return PlatformMacos
|
|
case "linux":
|
|
return PlatformLinux
|
|
case "windows":
|
|
return PlatformWindows
|
|
}
|
|
panic(fmt.Sprintf("Unsupported platform %s", getOS()))
|
|
}
|
|
|
|
// Platforms defines which platforms a configuration applies to.
|
|
type Platforms struct {
|
|
// Only specifies a list of platforms where the configuration should apply.
|
|
Only *[]Platform `json:"only" yaml:"only"`
|
|
// Except specifies a list of platforms where the configuration should not apply.
|
|
Except *[]Platform `json:"except" yaml:"except"`
|
|
}
|
|
|
|
// Platform represents an operating system platform.
|
|
type Platform string
|
|
|
|
// Constants for supported platforms.
|
|
const (
|
|
PlatformMacos Platform = "macos" // PlatformMacos represents macOS.
|
|
PlatformLinux Platform = "linux" // PlatformLinux represents Linux.
|
|
PlatformWindows Platform = "windows" // PlatformWindows represents Windows.
|
|
)
|
|
|
|
// PlatformMap is a generic type that holds platform-specific values.
|
|
type PlatformMap[T any] struct {
|
|
// MacOS is the value for macOS.
|
|
MacOS *T `json:"macos" yaml:"macos"`
|
|
// Linux is the value for Linux.
|
|
Linux *T `json:"linux" yaml:"linux"`
|
|
// Windows is the value for Windows.
|
|
Windows *T `json:"windows" yaml:"windows"`
|
|
}
|
|
|
|
// Resolve returns the value for the current platform from the PlatformMap.
|
|
// It returns nil if no value is defined for the current platform.
|
|
func (p *PlatformMap[T]) Resolve() *T {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
switch getOS() {
|
|
case "darwin":
|
|
if p.MacOS != nil {
|
|
return p.MacOS
|
|
}
|
|
return nil
|
|
case "linux":
|
|
if p.Linux != nil {
|
|
return p.Linux
|
|
}
|
|
return nil
|
|
case "windows":
|
|
if p.Windows != nil {
|
|
return p.Windows
|
|
}
|
|
return nil
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// ResolveWithFallback returns the value for the current platform from the PlatformMap.
|
|
// If no value is defined for the current platform, it falls back to the value from the provided fallback PlatformMap.
|
|
func (o *PlatformMap[T]) ResolveWithFallback(fallback PlatformMap[T]) T {
|
|
val := o.Resolve()
|
|
if val == nil {
|
|
return *fallback.Resolve()
|
|
}
|
|
return *val
|
|
}
|
|
|
|
// ContainsPlatform checks if a slice of platforms contains a specific platform.
|
|
func ContainsPlatform(platforms *[]Platform, platform Platform) bool {
|
|
return slices.Contains(*platforms, platform)
|
|
}
|
|
|
|
// GetShouldRunOnOS determines if a configuration should run on the current operating system
|
|
// based on the Only and Except fields of the Platforms struct.
|
|
func (p *Platforms) GetShouldRunOnOS(curOS Platform) bool {
|
|
if p == nil {
|
|
return true
|
|
}
|
|
|
|
if p.Only != nil {
|
|
return ContainsPlatform(p.Only, curOS)
|
|
}
|
|
if p.Except != nil {
|
|
return !ContainsPlatform(p.Except, curOS)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// DockerOSMap is a PlatformMap that defines the Docker OS for each platform.
|
|
var DockerOSMap = PlatformMap[string]{
|
|
MacOS: lo.ToPtr("linux"),
|
|
Linux: lo.ToPtr("linux"),
|
|
Windows: lo.ToPtr("windows"),
|
|
}
|
|
|
|
// ParsePlatformSingleValue creates a new PlatformMap with the value for all platforms
|
|
func ParsePlatformSingleValue[T any](value T) *PlatformMap[T] {
|
|
p := &PlatformMap[T]{}
|
|
p.MacOS = &value
|
|
p.Linux = &value
|
|
p.Windows = &value
|
|
return p
|
|
}
|
|
|
|
// ParselatformMap creates a PlatformMap from a map of platform strings to values.
|
|
func ParselatformMap[T any](values map[string]T) *PlatformMap[T] {
|
|
p := &PlatformMap[T]{}
|
|
for k, v := range values {
|
|
val := v // capture value for pointer
|
|
switch Platform(k) {
|
|
case PlatformMacos:
|
|
p.MacOS = &val
|
|
case PlatformLinux:
|
|
p.Linux = &val
|
|
case PlatformWindows:
|
|
p.Windows = &val
|
|
default:
|
|
panic(fmt.Sprintf("Unsupported platform key: %q", k))
|
|
}
|
|
}
|
|
return p
|
|
}
|
|
|
|
// NewPlatformMap creates a new PlatformMap from either a single value or a map.
|
|
func NewPlatformMap[T any](input any) *PlatformMap[T] {
|
|
switch v := input.(type) {
|
|
case nil:
|
|
return nil
|
|
case *T:
|
|
if v != nil {
|
|
return ParsePlatformSingleValue(*v)
|
|
}
|
|
return nil
|
|
case map[string]T:
|
|
return ParselatformMap(v)
|
|
case map[string]*T:
|
|
flat := make(map[string]T)
|
|
for k, ptr := range v {
|
|
if ptr != nil {
|
|
flat[k] = *ptr
|
|
}
|
|
}
|
|
return ParselatformMap(flat)
|
|
case map[any]any:
|
|
// Handle YAML unmarshaling which produces map[any]any
|
|
flat := make(map[string]T)
|
|
for k, val := range v {
|
|
if keyStr, ok := k.(string); ok {
|
|
if typedVal, ok := val.(T); ok {
|
|
flat[keyStr] = typedVal
|
|
}
|
|
}
|
|
}
|
|
return ParselatformMap(flat)
|
|
case map[string]any:
|
|
// Handle JSON unmarshaling or mixed YAML which produces map[string]interface{}
|
|
flat := make(map[string]T)
|
|
for k, val := range v {
|
|
if typedVal, ok := val.(T); ok {
|
|
flat[k] = typedVal
|
|
}
|
|
}
|
|
return ParselatformMap(flat)
|
|
case T:
|
|
return ParsePlatformSingleValue(v)
|
|
default:
|
|
panic(fmt.Sprintf("NewPlatformMap: unsupported input type %T", input))
|
|
}
|
|
}
|