@@ -100,52 +100,71 @@ open class ProcessInfo: NSObject {
100
100
return osVersionInfo
101
101
}
102
102
#endif
103
-
104
- open var operatingSystemVersionString : String {
105
- let fallback = " Unknown "
106
- #if os(Linux)
103
+
104
+ internal lazy var _operatingSystemVersionString : String = {
105
+ #if canImport(Darwin)
106
+ // Just use CoreFoundation on Darwin
107
+ return CFCopySystemVersionString ( ) ? . _swiftObject ?? " Darwin "
108
+ #elseif os(Linux)
109
+ // Try to parse a `PRETTY_NAME` out of `/etc/os-release`.
110
+ if let osReleaseContents = try ? String ( contentsOf: URL ( fileURLWithPath: " /etc/os-release " , isDirectory: false ) ) ,
111
+ let name = osReleaseContents. split ( separator: " \n " ) . first ( where: { $0. hasPrefix ( " PRETTY_NAME= " ) } )
112
+ {
113
+ // This is extremely simplistic but manages to work for all known cases.
114
+ return String ( name. dropFirst ( " PRETTY_NAME= " . count) . trimmingCharacters ( in: . init( charactersIn: " \" " ) ) )
115
+ }
116
+
117
+ // Okay, we can't get a distro name, so try for generic info.
118
+ var versionString = " Linux "
119
+
120
+ // Try to get a release version number from `uname -r`.
107
121
var utsNameBuffer = utsname ( )
108
- guard uname ( & utsNameBuffer) == 0 else {
109
- return fallback
122
+ if uname ( & utsNameBuffer) == 0 {
123
+ let release = withUnsafePointer ( to: & utsNameBuffer. release. 0 ) { String ( cString: $0) }
124
+ if !release. isEmpty {
125
+ versionString += " \( release) "
126
+ }
110
127
}
111
- let release = withUnsafePointer ( to: & utsNameBuffer. release. 0 ) { String ( cString: $0) }
112
-
113
- return release
128
+
129
+ return versionString
114
130
#elseif os(Windows)
131
+ var versionString = " Windows "
132
+
115
133
guard let osVersionInfo = self . _rawOperatingSystemVersionInfo else {
116
- return fallback
134
+ return versionString
117
135
}
118
136
119
137
// Windows has no canonical way to turn the fairly complex `RTL_OSVERSIONINFOW` version info into a string. We
120
138
// do our best here to construct something consistent. Unfortunately, to provide a useful result, this requires
121
139
// hardcoding several of the somewhat ambiguous values in the table provided here:
122
140
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks
123
- var versionString = " "
124
141
switch ( osVersionInfo. dwMajorVersion, osVersionInfo. dwMinorVersion) {
125
- case ( 5 , 0 ) : versionString += " Windows 2000"
126
- case ( 5 , 1 ) : versionString += " Windows XP"
127
- case ( 5 , 2 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows XP Professional x64"
128
- case ( 5 , 2 ) where osVersionInfo. wSuiteMask == VER_SUITE_WH_SERVER: versionString += " Windows Home Server"
129
- case ( 5 , 2 ) : versionString += " Windows Server 2003"
130
- case ( 6 , 0 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows Vista"
131
- case ( 6 , 0 ) : versionString += " Windows Server 2008"
132
- case ( 6 , 1 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows 7"
133
- case ( 6 , 1 ) : versionString += " Windows Server 2008 R2"
134
- case ( 6 , 2 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows 8"
135
- case ( 6 , 2 ) : versionString += " Windows Server 2012"
136
- case ( 6 , 3 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows 8.1"
137
- case ( 6 , 3 ) : versionString += " Windows Server 2012 R2" // We assume the "10,0" numbers in the table for this are a typo
138
- case ( 10 , 0 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Windows 10"
139
- case ( 10 , 0 ) : versionString += " Windows Server 2019" // The table gives identical values for 2016 and 2019, so we just assume 2019 here
140
- default : return fallback
142
+ case ( 5 , 0 ) : versionString += " 2000 "
143
+ case ( 5 , 1 ) : versionString += " XP "
144
+ case ( 5 , 2 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " XP Professional x64 "
145
+ case ( 5 , 2 ) where osVersionInfo. wSuiteMask == VER_SUITE_WH_SERVER: versionString += " Home Server "
146
+ case ( 5 , 2 ) : versionString += " Server 2003 "
147
+ case ( 6 , 0 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " Vista "
148
+ case ( 6 , 0 ) : versionString += " Server 2008 "
149
+ case ( 6 , 1 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " 7 "
150
+ case ( 6 , 1 ) : versionString += " Server 2008 R2 "
151
+ case ( 6 , 2 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " 8 "
152
+ case ( 6 , 2 ) : versionString += " Server 2012 "
153
+ case ( 6 , 3 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " 8.1 "
154
+ case ( 6 , 3 ) : versionString += " Server 2012 R2 " // We assume the "10,0" numbers in the table for this are a typo
155
+ case ( 10 , 0 ) where osVersionInfo. wProductType == VER_NT_WORKSTATION: versionString += " 10 "
156
+ case ( 10 , 0 ) : versionString += " Server 2019 " // The table gives identical values for 2016 and 2019, so we just assume 2019 here
157
+ case let ( maj , min ) : versionString += " \( maj ) . \( min ) " // If all else fails, just give the raw version number
141
158
}
142
159
versionString += " (build \( osVersionInfo. dwBuildNumber) ) "
143
160
// For now we ignore the `szCSDVersion`, `wServicePackMajor`, and `wServicePackMinor` values.
144
161
return versionString
145
162
#else
146
- return CFCopySystemVersionString ( ) ? . _swiftObject ?? fallback
163
+ // On other systems at least return something.
164
+ return " Unknown "
147
165
#endif
148
- }
166
+ } ( )
167
+ open var operatingSystemVersionString : String { return _operatingSystemVersionString }
149
168
150
169
open var operatingSystemVersion : OperatingSystemVersion {
151
170
// The following fallback values match Darwin Foundation
@@ -174,7 +193,7 @@ open class ProcessInfo: NSObject {
174
193
minorVersion: Int ( osVersionInfo. dwMinorVersion) ,
175
194
patchVersion: Int ( osVersionInfo. dwBuildNumber)
176
195
)
177
- #else
196
+ #elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
178
197
var utsNameBuffer = utsname ( )
179
198
guard uname ( & utsNameBuffer) == 0 else {
180
199
return OperatingSystemVersion ( majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
@@ -184,6 +203,8 @@ open class ProcessInfo: NSObject {
184
203
}
185
204
let idx = release. firstIndex ( of: " - " ) ?? release. endIndex
186
205
versionString = String ( release [ ..< idx] )
206
+ #else
207
+ return OperatingSystemVersion ( majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
187
208
#endif
188
209
let versionComponents = versionString. split ( separator: " . " ) . map ( String . init) . compactMap ( { Int ( $0) } )
189
210
let majorVersion = versionComponents. dropFirst ( 0 ) . first ?? fallbackMajor
0 commit comments