Skip to content

Commit 9494d4b

Browse files
authored
Remove ProcessInfo in favor of swift-foundation's implementation (#4945)
1 parent 595a0d5 commit 9494d4b

File tree

3 files changed

+3
-393
lines changed

3 files changed

+3
-393
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ let package = Package(
7878
from: "0.0.5"),
7979
.package(
8080
url: "https://github.com/apple/swift-foundation",
81-
revision: "512befd01fc17c2c9cfe2ecdfec568f342c19d36"
81+
revision: "7eb8b598ad8f77ac743b2decc97d56bf350aedee"
8282
),
8383
],
8484
targets: [

Sources/Foundation/ProcessInfo.swift

Lines changed: 1 addition & 360 deletions
Original file line numberDiff line numberDiff line change
@@ -1,372 +1,13 @@
11
// This source file is part of the Swift.org open source project
22
//
3-
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
3+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
44
// Licensed under Apache License v2.0 with Runtime Library Exception
55
//
66
// See http://swift.org/LICENSE.txt for license information
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

1010
@_implementationOnly import _CoreFoundation
11-
#if os(Windows)
12-
import WinSDK
13-
#endif
14-
15-
public struct OperatingSystemVersion {
16-
public var majorVersion: Int
17-
public var minorVersion: Int
18-
public var patchVersion: Int
19-
public init() {
20-
self.init(majorVersion: 0, minorVersion: 0, patchVersion: 0)
21-
}
22-
23-
public init(majorVersion: Int, minorVersion: Int, patchVersion: Int) {
24-
self.majorVersion = majorVersion
25-
self.minorVersion = minorVersion
26-
self.patchVersion = patchVersion
27-
}
28-
}
29-
30-
31-
32-
open class ProcessInfo: NSObject {
33-
34-
public static let processInfo = ProcessInfo()
35-
36-
internal override init() {
37-
38-
}
39-
40-
open var environment: [String : String] {
41-
let equalSign = Character("=")
42-
let strEncoding = String.defaultCStringEncoding
43-
let envp = _CFEnviron()
44-
var env: [String : String] = [:]
45-
var idx = 0
46-
47-
while let entry = envp.advanced(by: idx).pointee {
48-
if let entry = String(cString: entry, encoding: strEncoding),
49-
let i = entry.firstIndex(of: equalSign) {
50-
let key = String(entry.prefix(upTo: i))
51-
let value = String(entry.suffix(from: i).dropFirst())
52-
env[key] = value
53-
}
54-
idx += 1
55-
}
56-
return env
57-
}
58-
59-
open var arguments: [String] {
60-
return CommandLine.arguments // seems reasonable to flip the script here...
61-
}
62-
63-
open var hostName: String {
64-
if let name = Host.current().name {
65-
return name
66-
} else {
67-
return "localhost"
68-
}
69-
}
70-
71-
open var processName: String = _CFProcessNameString()._swiftObject
72-
73-
open var processIdentifier: Int32 {
74-
#if os(Windows)
75-
return Int32(GetProcessId(GetCurrentProcess()))
76-
#else
77-
return Int32(getpid())
78-
#endif
79-
}
80-
81-
open var globallyUniqueString: String {
82-
let uuid = CFUUIDCreate(kCFAllocatorSystemDefault)
83-
return CFUUIDCreateString(kCFAllocatorSystemDefault, uuid)._swiftObject
84-
}
85-
86-
#if os(Windows)
87-
internal var _rawOperatingSystemVersionInfo: RTL_OSVERSIONINFOEXW? {
88-
guard let ntdll = ("ntdll.dll".withCString(encodedAs: UTF16.self) {
89-
LoadLibraryExW($0, nil, DWORD(LOAD_LIBRARY_SEARCH_SYSTEM32))
90-
}) else {
91-
return nil
92-
}
93-
defer { FreeLibrary(ntdll) }
94-
typealias RTLGetVersionTy = @convention(c) (UnsafeMutablePointer<RTL_OSVERSIONINFOEXW>) -> NTSTATUS
95-
guard let pfnRTLGetVersion = unsafeBitCast(GetProcAddress(ntdll, "RtlGetVersion"), to: Optional<RTLGetVersionTy>.self) else {
96-
return nil
97-
}
98-
var osVersionInfo = RTL_OSVERSIONINFOEXW()
99-
osVersionInfo.dwOSVersionInfoSize = DWORD(MemoryLayout<RTL_OSVERSIONINFOEXW>.size)
100-
guard pfnRTLGetVersion(&osVersionInfo) == 0 else {
101-
return nil
102-
}
103-
return osVersionInfo
104-
}
105-
#endif
106-
107-
internal lazy var _operatingSystemVersionString: String = {
108-
#if canImport(Darwin)
109-
// Just use CoreFoundation on Darwin
110-
return CFCopySystemVersionString()?._swiftObject ?? "Darwin"
111-
#elseif os(Linux)
112-
// Try to parse a `PRETTY_NAME` out of `/etc/os-release`.
113-
if let osReleaseContents = try? String(contentsOf: URL(fileURLWithPath: "/etc/os-release", isDirectory: false)),
114-
let name = osReleaseContents.split(separator: "\n").first(where: { $0.hasPrefix("PRETTY_NAME=") })
115-
{
116-
// This is extremely simplistic but manages to work for all known cases.
117-
return String(name.dropFirst("PRETTY_NAME=".count).trimmingCharacters(in: .init(charactersIn: "\"")))
118-
}
119-
120-
// Okay, we can't get a distro name, so try for generic info.
121-
var versionString = "Linux"
122-
123-
// Try to get a release version number from `uname -r`.
124-
var utsNameBuffer = utsname()
125-
if uname(&utsNameBuffer) == 0 {
126-
let release = withUnsafePointer(to: &utsNameBuffer.release.0) { String(cString: $0) }
127-
if !release.isEmpty {
128-
versionString += " \(release)"
129-
}
130-
}
131-
132-
return versionString
133-
#elseif os(Windows)
134-
var versionString = "Windows"
135-
136-
guard let osVersionInfo = self._rawOperatingSystemVersionInfo else {
137-
return versionString
138-
}
139-
140-
// Windows has no canonical way to turn the fairly complex `RTL_OSVERSIONINFOW` version info into a string. We
141-
// do our best here to construct something consistent. Unfortunately, to provide a useful result, this requires
142-
// hardcoding several of the somewhat ambiguous values in the table provided here:
143-
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw#remarks
144-
switch (osVersionInfo.dwMajorVersion, osVersionInfo.dwMinorVersion) {
145-
case (5, 0): versionString += " 2000"
146-
case (5, 1): versionString += " XP"
147-
case (5, 2) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " XP Professional x64"
148-
case (5, 2) where osVersionInfo.wSuiteMask == VER_SUITE_WH_SERVER: versionString += " Home Server"
149-
case (5, 2): versionString += " Server 2003"
150-
case (6, 0) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " Vista"
151-
case (6, 0): versionString += " Server 2008"
152-
case (6, 1) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " 7"
153-
case (6, 1): versionString += " Server 2008 R2"
154-
case (6, 2) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " 8"
155-
case (6, 2): versionString += " Server 2012"
156-
case (6, 3) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " 8.1"
157-
case (6, 3): versionString += " Server 2012 R2" // We assume the "10,0" numbers in the table for this are a typo
158-
case (10, 0) where osVersionInfo.wProductType == VER_NT_WORKSTATION: versionString += " 10"
159-
case (10, 0): versionString += " Server 2019" // The table gives identical values for 2016 and 2019, so we just assume 2019 here
160-
case let (maj, min): versionString += " \(maj).\(min)" // If all else fails, just give the raw version number
161-
}
162-
versionString += " (build \(osVersionInfo.dwBuildNumber))"
163-
// For now we ignore the `szCSDVersion`, `wServicePackMajor`, and `wServicePackMinor` values.
164-
return versionString
165-
#elseif os(FreeBSD)
166-
// Try to get a release version from `uname -r`.
167-
var versionString = "FreeBSD"
168-
var utsNameBuffer = utsname()
169-
if uname(&utsNameBuffer) == 0 {
170-
let release = withUnsafePointer(to: &utsNameBuffer.release.0) { String(cString: $0) }
171-
if !release.isEmpty {
172-
versionString += " \(release)"
173-
}
174-
}
175-
return versionString
176-
#elseif os(OpenBSD)
177-
// TODO: `uname -r` probably works here too.
178-
return "OpenBSD"
179-
#elseif os(Android)
180-
/// In theory, we need to do something like this:
181-
///
182-
/// var versionString = "Android"
183-
/// let property = String(unsafeUninitializedCapacity: PROP_VALUE_MAX) { buf in
184-
/// __system_property_get("ro.build.description", buf.baseAddress!)
185-
/// }
186-
/// if !property.isEmpty {
187-
/// versionString += " \(property)"
188-
/// }
189-
/// return versionString
190-
return "Android"
191-
#elseif os(PS4)
192-
return "PS4"
193-
#elseif os(Cygwin)
194-
// TODO: `uname -r` probably works here too.
195-
return "Cygwin"
196-
#elseif os(Haiku)
197-
return "Haiku"
198-
#elseif os(WASI)
199-
return "WASI"
200-
#else
201-
// On other systems at least return something.
202-
return "Unknown"
203-
#endif
204-
}()
205-
open var operatingSystemVersionString: String { return _operatingSystemVersionString }
206-
207-
open var operatingSystemVersion: OperatingSystemVersion {
208-
// The following fallback values match Darwin Foundation
209-
let fallbackMajor = -1
210-
let fallbackMinor = 0
211-
let fallbackPatch = 0
212-
let versionString: String
213-
214-
#if canImport(Darwin)
215-
guard let systemVersionDictionary = _CFCopySystemVersionDictionary() else {
216-
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
217-
}
218-
219-
let productVersionKey = unsafeBitCast(_kCFSystemVersionProductVersionKey, to: UnsafeRawPointer.self)
220-
guard let productVersion = unsafeBitCast(CFDictionaryGetValue(systemVersionDictionary, productVersionKey), to: NSString?.self) else {
221-
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
222-
}
223-
versionString = productVersion._swiftObject
224-
#elseif os(Windows)
225-
guard let osVersionInfo = self._rawOperatingSystemVersionInfo else {
226-
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
227-
}
228-
229-
return OperatingSystemVersion(
230-
majorVersion: Int(osVersionInfo.dwMajorVersion),
231-
minorVersion: Int(osVersionInfo.dwMinorVersion),
232-
patchVersion: Int(osVersionInfo.dwBuildNumber)
233-
)
234-
#elseif os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android)
235-
var utsNameBuffer = utsname()
236-
guard uname(&utsNameBuffer) == 0 else {
237-
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
238-
}
239-
let release = withUnsafePointer(to: &utsNameBuffer.release.0) {
240-
return String(cString: $0)
241-
}
242-
let idx = release.firstIndex(of: "-") ?? release.endIndex
243-
versionString = String(release[..<idx])
244-
#else
245-
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
246-
#endif
247-
let versionComponents = versionString.split(separator: ".").map(String.init).compactMap({ Int($0) })
248-
let majorVersion = versionComponents.dropFirst(0).first ?? fallbackMajor
249-
let minorVersion = versionComponents.dropFirst(1).first ?? fallbackMinor
250-
let patchVersion = versionComponents.dropFirst(2).first ?? fallbackPatch
251-
return OperatingSystemVersion(majorVersion: majorVersion, minorVersion: minorVersion, patchVersion: patchVersion)
252-
}
253-
254-
internal let _processorCount: Int = Int(__CFProcessorCount())
255-
open var processorCount: Int { _processorCount }
256-
257-
#if os(Linux)
258-
// coreCount takes into account cgroup information eg if running under Docker
259-
// __CFActiveProcessorCount uses sched_getaffinity() and sysconf(_SC_NPROCESSORS_ONLN)
260-
internal let _activeProcessorCount: Int = ProcessInfo.coreCount() ?? Int(__CFActiveProcessorCount())
261-
#else
262-
internal let _activeProcessorCount: Int = Int(__CFActiveProcessorCount())
263-
#endif
264-
265-
open var activeProcessorCount: Int { _activeProcessorCount }
266-
267-
internal let _physicalMemory = __CFMemorySize()
268-
open var physicalMemory: UInt64 {
269-
return _physicalMemory
270-
}
271-
272-
open func isOperatingSystemAtLeast(_ version: OperatingSystemVersion) -> Bool {
273-
let ourVersion = operatingSystemVersion
274-
if ourVersion.majorVersion < version.majorVersion {
275-
return false
276-
}
277-
if ourVersion.majorVersion > version.majorVersion {
278-
return true
279-
}
280-
if ourVersion.minorVersion < version.minorVersion {
281-
return false
282-
}
283-
if ourVersion.minorVersion > version.minorVersion {
284-
return true
285-
}
286-
if ourVersion.patchVersion < version.patchVersion {
287-
return false
288-
}
289-
if ourVersion.patchVersion > version.patchVersion {
290-
return true
291-
}
292-
return true
293-
}
294-
295-
open var systemUptime: TimeInterval {
296-
return CFGetSystemUptime()
297-
}
298-
299-
open var userName: String {
300-
return NSUserName()
301-
}
302-
303-
open var fullUserName: String {
304-
return NSFullUserName()
305-
}
306-
307-
308-
#if os(Linux)
309-
// Support for CFS quotas for cpu count as used by Docker.
310-
// Based on swift-nio code, https://github.com/apple/swift-nio/pull/1518
311-
private static let cfsQuotaPath = "/sys/fs/cgroup/cpu/cpu.cfs_quota_us"
312-
private static let cfsPeriodPath = "/sys/fs/cgroup/cpu/cpu.cfs_period_us"
313-
private static let cpuSetPath = "/sys/fs/cgroup/cpuset/cpuset.cpus"
314-
315-
private static func firstLineOfFile(path: String) throws -> Substring {
316-
// TODO: Replace with URL version once that is available in FoundationEssentials
317-
let data = try Data(contentsOf: path)
318-
if let string = String(data: data, encoding: .utf8), let line = string.split(separator: "\n").first {
319-
return line
320-
} else {
321-
return ""
322-
}
323-
}
324-
325-
// These are internal access for testing
326-
static func countCoreIds(cores: Substring) -> Int? {
327-
let ids = cores.split(separator: "-", maxSplits: 1)
328-
guard let first = ids.first.flatMap({ Int($0, radix: 10) }),
329-
let last = ids.last.flatMap({ Int($0, radix: 10) }),
330-
last >= first
331-
else {
332-
return nil
333-
}
334-
return 1 + last - first
335-
}
336-
337-
static func coreCount(cpuset cpusetPath: String) -> Int? {
338-
guard let cpuset = try? firstLineOfFile(path: cpusetPath).split(separator: ","),
339-
!cpuset.isEmpty
340-
else { return nil }
341-
if let first = cpuset.first, let count = countCoreIds(cores: first) {
342-
return count
343-
} else {
344-
return nil
345-
}
346-
}
347-
348-
static func coreCount(quota quotaPath: String, period periodPath: String) -> Int? {
349-
guard let quota = try? Int(firstLineOfFile(path: quotaPath)),
350-
quota > 0
351-
else { return nil }
352-
guard let period = try? Int(firstLineOfFile(path: periodPath)),
353-
period > 0
354-
else { return nil }
355-
356-
return (quota - 1 + period) / period // always round up if fractional CPU quota requested
357-
}
358-
359-
private static func coreCount() -> Int? {
360-
if let quota = coreCount(quota: cfsQuotaPath, period: cfsPeriodPath) {
361-
return quota
362-
} else if let cpusetCount = coreCount(cpuset: cpuSetPath) {
363-
return cpusetCount
364-
} else {
365-
return nil
366-
}
367-
}
368-
#endif
369-
}
37011

37112
// SPI for TestFoundation
37213
internal extension ProcessInfo {

0 commit comments

Comments
 (0)