Skip to content

Commit 1dd5ac4

Browse files
authored
make Platform::darwinCacheDirectories thread shafe (#178)
motivation: clients like swift-pm use Platform::darwinCacheDirectories in concurrent settings changes: * add lock around the internal caching of darwinCacheDirectories * make several public functions internal since they are only supposed to be exposed for tests * format code
1 parent 6f0ae42 commit 1dd5ac4

File tree

2 files changed

+47
-40
lines changed

2 files changed

+47
-40
lines changed

Sources/TSCUtility/Platform.swift

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
See http://swift.org/LICENSE.txt for license information
88
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
9-
*/
9+
*/
1010

1111
import TSCBasic
1212
import Foundation
@@ -25,45 +25,50 @@ public enum Platform: Equatable {
2525
}
2626

2727
/// Lazily checked current platform.
28-
public static var currentPlatform = Platform._findCurrentPlatform(localFileSystem)
28+
public static var currentPlatform = Platform.findCurrentPlatform(localFileSystem)
29+
30+
/// Returns the cache directories used in Darwin.
31+
private static var darwinCacheDirectoriesLock = Lock()
32+
private static var _darwinCacheDirectories: [AbsolutePath]? = .none
33+
2934
/// Attempt to match `uname` with recognized platforms.
30-
public static func _findCurrentPlatform(_ fs: FileSystem) -> Platform? {
31-
#if os(Windows)
35+
internal static func findCurrentPlatform(_ fileSystem: FileSystem) -> Platform? {
36+
#if os(Windows)
3237
return .windows
33-
#else
38+
#else
3439
guard let uname = try? Process.checkNonZeroExit(args: "uname").spm_chomp().lowercased() else { return nil }
3540
switch uname {
3641
case "darwin":
3742
return .darwin
3843
case "linux":
39-
return Platform._findCurrentPlatformLinux(fs)
44+
return Platform.findCurrentPlatformLinux(fileSystem)
4045
default:
4146
return nil
4247
}
43-
#endif
48+
#endif
4449
}
4550

46-
public static func _findCurrentPlatformLinux(_ fs: FileSystem) -> Platform? {
47-
if fs.isFile(AbsolutePath("/etc/debian_version")) {
51+
internal static func findCurrentPlatformLinux(_ fileSystem: FileSystem) -> Platform? {
52+
if fileSystem.isFile(AbsolutePath("/etc/debian_version")) {
4853
return .linux(.debian)
4954
}
50-
if fs.isFile(AbsolutePath("/system/bin/toolbox")) ||
51-
fs.isFile(AbsolutePath("/system/bin/toybox")) {
55+
if fileSystem.isFile(AbsolutePath("/system/bin/toolbox")) ||
56+
fileSystem.isFile(AbsolutePath("/system/bin/toybox")) {
5257
return .android
5358
}
54-
if fs.isFile(AbsolutePath("/etc/redhat-release")) ||
55-
fs.isFile(AbsolutePath("/etc/centos-release")) ||
56-
fs.isFile(AbsolutePath("/etc/fedora-release")) ||
57-
Platform.isAmazonLinux2(fs) {
59+
if fileSystem.isFile(AbsolutePath("/etc/redhat-release")) ||
60+
fileSystem.isFile(AbsolutePath("/etc/centos-release")) ||
61+
fileSystem.isFile(AbsolutePath("/etc/fedora-release")) ||
62+
Platform.isAmazonLinux2(fileSystem) {
5863
return .linux(.fedora)
5964
}
6065

6166
return nil
6267
}
6368

64-
private static func isAmazonLinux2(_ fs: FileSystem) -> Bool {
69+
private static func isAmazonLinux2(_ fileSystem: FileSystem) -> Bool {
6570
do {
66-
let release = try fs.readFileContents(AbsolutePath("/etc/system-release")).cString
71+
let release = try fileSystem.readFileContents(AbsolutePath("/etc/system-release")).cString
6772
return release.hasPrefix("Amazon Linux release 2")
6873
} catch {
6974
return false
@@ -72,23 +77,25 @@ public enum Platform: Equatable {
7277

7378
/// Returns the cache directories used in Darwin.
7479
public static func darwinCacheDirectories() -> [AbsolutePath] {
75-
if let value = Platform._darwinCacheDirectories {
76-
return value
80+
Self.darwinCacheDirectoriesLock.withLock {
81+
if let darwinCacheDirectories = Self._darwinCacheDirectories {
82+
return darwinCacheDirectories
83+
}
84+
var directories = [AbsolutePath]()
85+
// Compute the directories.
86+
directories.append(AbsolutePath("/private/var/tmp"))
87+
(try? TSCBasic.determineTempDirectory()).map{ directories.append($0) }
88+
#if os(macOS)
89+
getConfstr(_CS_DARWIN_USER_TEMP_DIR).map({ directories.append($0) })
90+
getConfstr(_CS_DARWIN_USER_CACHE_DIR).map({ directories.append($0) })
91+
#endif
92+
Self._darwinCacheDirectories = directories
93+
return directories
7794
}
78-
var directories = [AbsolutePath]()
79-
// Compute the directories.
80-
directories.append(AbsolutePath("/private/var/tmp"))
81-
(try? TSCBasic.determineTempDirectory()).map{ directories.append($0) }
82-
#if os(macOS)
83-
getConfstr(_CS_DARWIN_USER_TEMP_DIR).map({ directories.append($0) })
84-
getConfstr(_CS_DARWIN_USER_CACHE_DIR).map({ directories.append($0) })
85-
#endif
86-
Platform._darwinCacheDirectories = directories
87-
return directories
8895
}
89-
private static var _darwinCacheDirectories: [AbsolutePath]?
9096

91-
#if os(macOS)
97+
98+
#if os(macOS)
9299
/// Returns the value of given path variable using `getconf` utility.
93100
///
94101
/// - Note: This method returns `nil` if the value is an invalid path.
@@ -101,5 +108,5 @@ public enum Platform: Equatable {
101108
guard value.hasSuffix(AbsolutePath.root.pathString) else { return nil }
102109
return resolveSymlinks(AbsolutePath(value))
103110
}
104-
#endif
111+
#endif
105112
}

Tests/TSCUtilityTests/PlatformTests.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,33 @@ import XCTest
1212
import TSCBasic
1313
import TSCTestSupport
1414

15-
import TSCUtility
15+
@testable import TSCUtility
1616

1717
final class PlatformTests: XCTestCase {
1818
func testFindCurrentPlatformDebian() {
1919
let fs = InMemoryFileSystem(files: ["/etc/debian_version": "xxx"])
20-
XCTAssertEqual(Platform.linux(.debian), Platform._findCurrentPlatformLinux(fs))
20+
XCTAssertEqual(Platform.linux(.debian), Platform.findCurrentPlatformLinux(fs))
2121
}
2222

2323
func testFindCurrentPlatformAndroid() {
2424
var fs = InMemoryFileSystem(files: ["/system/bin/toolbox": "xxx"])
25-
XCTAssertEqual(Platform.android, Platform._findCurrentPlatformLinux(fs))
25+
XCTAssertEqual(Platform.android, Platform.findCurrentPlatformLinux(fs))
2626

2727
fs = InMemoryFileSystem(files: ["/system/bin/toybox": "xxx"])
28-
XCTAssertEqual(Platform.android, Platform._findCurrentPlatformLinux(fs))
28+
XCTAssertEqual(Platform.android, Platform.findCurrentPlatformLinux(fs))
2929
}
3030

3131
func testFindCurrentPlatformFedora() {
3232
var fs = InMemoryFileSystem(files: ["/etc/fedora-release": "xxx"])
33-
XCTAssertEqual(Platform.linux(.fedora), Platform._findCurrentPlatformLinux(fs))
33+
XCTAssertEqual(Platform.linux(.fedora), Platform.findCurrentPlatformLinux(fs))
3434

3535
fs = InMemoryFileSystem(files: ["/etc/redhat-release": "xxx"])
36-
XCTAssertEqual(Platform.linux(.fedora), Platform._findCurrentPlatformLinux(fs))
36+
XCTAssertEqual(Platform.linux(.fedora), Platform.findCurrentPlatformLinux(fs))
3737

3838
fs = InMemoryFileSystem(files: ["/etc/centos-release": "xxx"])
39-
XCTAssertEqual(Platform.linux(.fedora), Platform._findCurrentPlatformLinux(fs))
39+
XCTAssertEqual(Platform.linux(.fedora), Platform.findCurrentPlatformLinux(fs))
4040

4141
fs = InMemoryFileSystem(files: ["/etc/system-release": "Amazon Linux release 2 (Karoo)"])
42-
XCTAssertEqual(Platform.linux(.fedora), Platform._findCurrentPlatformLinux(fs))
42+
XCTAssertEqual(Platform.linux(.fedora), Platform.findCurrentPlatformLinux(fs))
4343
}
4444
}

0 commit comments

Comments
 (0)