Skip to content

Commit d30088c

Browse files
p4checomluisbrown
authored andcommitted
Fix CI and Linux build
## Changes - Fix `ci.yml` to pass in config and be in sync with upstream. - Add missing Linux compile time checks. - Fix `@testable imports` for Release test runs.
1 parent e970ae6 commit d30088c

20 files changed

+223
-142
lines changed

.github/workflows/ci.yml

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,34 @@ concurrency:
1616

1717
jobs:
1818
library:
19+
runs-on: macos-12
20+
strategy:
21+
matrix:
22+
xcode:
23+
- '14.1'
24+
config: ['debug', 'release']
25+
scheme: ['Dependencies', 'ComposableArchitecture']
26+
steps:
27+
- uses: actions/checkout@v2
28+
- name: Select Xcode ${{ matrix.xcode }}
29+
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
30+
- name: Run ${{ matrix.scheme }} ${{ matrix.config }} tests
31+
run: CONFIG=${{ matrix.config }} SCHEME=${{ matrix.scheme }} make test-library
32+
33+
library-evolution:
34+
runs-on: macos-12
35+
strategy:
36+
matrix:
37+
xcode:
38+
- '14.1'
39+
steps:
40+
- uses: actions/checkout@v2
41+
- name: Select Xcode ${{ matrix.xcode }}
42+
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
43+
- name: Build for library evolution
44+
run: make build-for-library-evolution
45+
46+
benchmarks:
1947
runs-on: macos-12
2048
strategy:
2149
matrix:
@@ -25,11 +53,6 @@ jobs:
2553
- uses: actions/checkout@v2
2654
- name: Select Xcode ${{ matrix.xcode }}
2755
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
28-
- name: Run tests
29-
run: make test-library
30-
- name: Compile documentation
31-
if: ${{ matrix.xcode == '14.1' }}
32-
run: make test-docs
3356
- name: Run benchmark
3457
run: make benchmark
3558

Package.resolved

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ let package = Package(
4949
name: "Dependencies",
5050
dependencies: [
5151
"ReactiveSwift",
52-
.product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay")
52+
.product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
5353
]
5454
),
5555
.testTarget(

Sources/ComposableArchitecture/Reducer/Reducers/BindingReducer.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import SwiftUI
1+
#if canImport(SwiftUI)
2+
import SwiftUI
3+
#endif
24

35
/// A reducer that updates bindable state when it receives binding actions.
46
public struct BindingReducer<State, Action>: ReducerProtocol
Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,78 @@
1-
import OSLog
1+
#if canImport(OSLog)
2+
import OSLog
23

3-
extension ReducerProtocol {
4-
/// Instruments a reducer with
5-
/// [signposts](https://developer.apple.com/documentation/os/logging/recording_performance_data).
6-
///
7-
/// Each invocation of the reducer will be measured by an interval, and the lifecycle of its
8-
/// effects will be measured with interval and event signposts.
9-
///
10-
/// To use, build your app for profiling, create a blank instrument, and add the signpost
11-
/// instrument. Start recording your app you will see timing information for every action sent to
12-
/// the store, as well as every effect executed.
13-
///
14-
/// Effect instrumentation can be particularly useful for inspecting the lifecycle of long-living
15-
/// effects. For example, if you start an effect (_e.g._, a location manager) in `onAppear` and
16-
/// forget to tear down the effect in `onDisappear`, the instrument will show that the effect
17-
/// never completed.
18-
///
19-
/// - Parameters:
20-
/// - prefix: A string to print at the beginning of the formatted message for the signpost.
21-
/// - log: An `OSLog` to use for signposts.
22-
/// - Returns: A reducer that has been enhanced with instrumentation.
23-
@inlinable
24-
public func signpost(
25-
_ prefix: String = "",
26-
log: OSLog = OSLog(
27-
subsystem: "co.pointfree.ComposableArchitecture",
28-
category: "Reducer Instrumentation"
29-
)
30-
) -> _SignpostReducer<Self> {
31-
_SignpostReducer(base: self, prefix: prefix, log: log)
4+
extension ReducerProtocol {
5+
/// Instruments a reducer with
6+
/// [signposts](https://developer.apple.com/documentation/os/logging/recording_performance_data).
7+
///
8+
/// Each invocation of the reducer will be measured by an interval, and the lifecycle of its
9+
/// effects will be measured with interval and event signposts.
10+
///
11+
/// To use, build your app for profiling, create a blank instrument, and add the signpost
12+
/// instrument. Start recording your app you will see timing information for every action sent to
13+
/// the store, as well as every effect executed.
14+
///
15+
/// Effect instrumentation can be particularly useful for inspecting the lifecycle of long-living
16+
/// effects. For example, if you start an effect (_e.g._, a location manager) in `onAppear` and
17+
/// forget to tear down the effect in `onDisappear`, the instrument will show that the effect
18+
/// never completed.
19+
///
20+
/// - Parameters:
21+
/// - prefix: A string to print at the beginning of the formatted message for the signpost.
22+
/// - log: An `OSLog` to use for signposts.
23+
/// - Returns: A reducer that has been enhanced with instrumentation.
24+
@inlinable
25+
public func signpost(
26+
_ prefix: String = "",
27+
log: OSLog = OSLog(
28+
subsystem: "co.pointfree.ComposableArchitecture",
29+
category: "Reducer Instrumentation"
30+
)
31+
) -> _SignpostReducer<Self> {
32+
_SignpostReducer(base: self, prefix: prefix, log: log)
33+
}
3234
}
33-
}
34-
35-
public struct _SignpostReducer<Base: ReducerProtocol>: ReducerProtocol {
36-
@usableFromInline
37-
let base: Base
3835

39-
@usableFromInline
40-
let prefix: String
36+
public struct _SignpostReducer<Base: ReducerProtocol>: ReducerProtocol {
37+
@usableFromInline
38+
let base: Base
4139

42-
@usableFromInline
43-
let log: OSLog
40+
@usableFromInline
41+
let prefix: String
4442

45-
@usableFromInline
46-
init(
47-
base: Base,
48-
prefix: String,
49-
log: OSLog
50-
) {
51-
self.base = base
52-
// NB: Prevent rendering as "N/A" in Instruments
53-
let zeroWidthSpace = "\u{200B}"
54-
self.prefix = prefix.isEmpty ? zeroWidthSpace : "[\(prefix)] "
55-
self.log = log
56-
}
43+
@usableFromInline
44+
let log: OSLog
5745

58-
@inlinable
59-
public func reduce(
60-
into state: inout Base.State, action: Base.Action
61-
) -> Effect<Base.Action, Never> {
62-
var actionOutput: String!
63-
if self.log.signpostsEnabled {
64-
actionOutput = debugCaseOutput(action)
65-
os_signpost(.begin, log: log, name: "Action", "%s%s", self.prefix, actionOutput)
46+
@usableFromInline
47+
init(
48+
base: Base,
49+
prefix: String,
50+
log: OSLog
51+
) {
52+
self.base = base
53+
// NB: Prevent rendering as "N/A" in Instruments
54+
let zeroWidthSpace = "\u{200B}"
55+
self.prefix = prefix.isEmpty ? zeroWidthSpace : "[\(prefix)] "
56+
self.log = log
6657
}
67-
let effects = self.base.reduce(into: &state, action: action)
68-
if self.log.signpostsEnabled {
69-
os_signpost(.end, log: self.log, name: "Action")
70-
return
71-
effects
72-
.effectSignpost(self.prefix, log: self.log, actionOutput: actionOutput)
58+
59+
@inlinable
60+
public func reduce(
61+
into state: inout Base.State, action: Base.Action
62+
) -> Effect<Base.Action, Never> {
63+
var actionOutput: String!
64+
if self.log.signpostsEnabled {
65+
actionOutput = debugCaseOutput(action)
66+
os_signpost(.begin, log: log, name: "Action", "%s%s", self.prefix, actionOutput)
67+
}
68+
let effects = self.base.reduce(into: &state, action: action)
69+
if self.log.signpostsEnabled {
70+
os_signpost(.end, log: self.log, name: "Action")
71+
return
72+
effects
73+
.effectSignpost(self.prefix, log: self.log, actionOutput: actionOutput)
74+
}
75+
return effects
7376
}
74-
return effects
7577
}
76-
}
78+
#endif

Sources/Dependencies/Dependencies/OpenURL.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Foundation
12
import XCTestDynamicOverlay
23

34
#if canImport(AppKit)

Sources/Dependencies/Dependencies/RandomNumberGenerator.swift

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -73,30 +73,48 @@ extension DependencyValues {
7373
}
7474
}
7575

76-
/// A dependency that yields a random number generator to a closure.
77-
///
78-
/// See ``DependencyValues/withRandomNumberGenerator`` for more information.
79-
public final class WithRandomNumberGenerator: @unchecked Sendable {
80-
private var generator: RandomNumberGenerator
81-
private let lock: os_unfair_lock_t
76+
#if canImport(os)
77+
/// A dependency that yields a random number generator to a closure.
78+
///
79+
/// See ``DependencyValues/withRandomNumberGenerator`` for more information.
80+
public final class WithRandomNumberGenerator: @unchecked Sendable {
81+
private var generator: RandomNumberGenerator
82+
private let lock: os_unfair_lock_t
8283

83-
public init<T: RandomNumberGenerator & Sendable>(_ generator: T) {
84-
self.generator = generator
85-
self.lock = os_unfair_lock_t.allocate(capacity: 1)
86-
self.lock.initialize(to: os_unfair_lock())
87-
}
84+
public init<T: RandomNumberGenerator & Sendable>(_ generator: T) {
85+
self.generator = generator
86+
self.lock = os_unfair_lock_t.allocate(capacity: 1)
87+
self.lock.initialize(to: os_unfair_lock())
88+
}
8889

89-
deinit {
90-
self.lock.deinitialize(count: 1)
91-
self.lock.deallocate()
90+
deinit {
91+
self.lock.deinitialize(count: 1)
92+
self.lock.deallocate()
93+
}
94+
95+
public func callAsFunction<R>(_ work: (inout RandomNumberGenerator) -> R) -> R {
96+
os_unfair_lock_lock(self.lock)
97+
defer { os_unfair_lock_unlock(self.lock) }
98+
return work(&self.generator)
99+
}
92100
}
101+
#else
102+
public final class WithRandomNumberGenerator: @unchecked Sendable {
103+
private var generator: RandomNumberGenerator
104+
private let lock: NSLock
105+
106+
public init<T: RandomNumberGenerator & Sendable>(_ generator: T) {
107+
self.generator = generator
108+
self.lock = NSLock()
109+
}
93110

94-
public func callAsFunction<R>(_ work: (inout RandomNumberGenerator) -> R) -> R {
95-
os_unfair_lock_lock(self.lock)
96-
defer { os_unfair_lock_unlock(self.lock) }
97-
return work(&self.generator)
111+
public func callAsFunction<R>(_ work: (inout RandomNumberGenerator) -> R) -> R {
112+
self.lock.lock()
113+
defer { self.lock.unlock() }
114+
return work(&self.generator)
115+
}
98116
}
99-
}
117+
#endif
100118

101119
private struct UnimplementedRandomNumberGenerator: RandomNumberGenerator {
102120
var generator = SystemRandomNumberGenerator()

Sources/Dependencies/Dependencies/URLSession.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import Foundation
22
import XCTestDynamicOverlay
33

4+
#if os(Linux)
5+
import FoundationNetworking
6+
#endif
7+
48
extension DependencyValues {
59
/// The URL session that features should use to make URL requests.
610
///

Sources/Dependencies/Dependencies/UUID.swift

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -125,26 +125,46 @@ public struct UUIDGenerator: Sendable {
125125
}
126126
}
127127

128-
private final class IncrementingUUIDGenerator: @unchecked Sendable {
129-
private let lock: os_unfair_lock_t
130-
private var sequence = 0
128+
#if canImport(os)
129+
private final class IncrementingUUIDGenerator: @unchecked Sendable {
130+
private let lock: os_unfair_lock_t
131+
private var sequence = 0
131132

132-
init() {
133-
self.lock = os_unfair_lock_t.allocate(capacity: 1)
134-
self.lock.initialize(to: os_unfair_lock())
135-
}
133+
init() {
134+
self.lock = os_unfair_lock_t.allocate(capacity: 1)
135+
self.lock.initialize(to: os_unfair_lock())
136+
}
137+
138+
deinit {
139+
self.lock.deinitialize(count: 1)
140+
self.lock.deallocate()
141+
}
136142

137-
deinit {
138-
self.lock.deinitialize(count: 1)
139-
self.lock.deallocate()
143+
func callAsFunction() -> UUID {
144+
os_unfair_lock_lock(self.lock)
145+
defer {
146+
self.sequence += 1
147+
os_unfair_lock_unlock(self.lock)
148+
}
149+
return UUID(uuidString: "00000000-0000-0000-0000-\(String(format: "%012x", self.sequence))")!
150+
}
140151
}
152+
#else
153+
private final class IncrementingUUIDGenerator: @unchecked Sendable {
154+
private let lock: NSLock
155+
private var sequence = 0
156+
157+
init() {
158+
self.lock = NSLock()
159+
}
141160

142-
func callAsFunction() -> UUID {
143-
os_unfair_lock_lock(self.lock)
144-
defer {
145-
self.sequence += 1
146-
os_unfair_lock_unlock(self.lock)
161+
func callAsFunction() -> UUID {
162+
self.lock.lock()
163+
defer {
164+
self.sequence += 1
165+
self.lock.unlock()
166+
}
167+
return UUID(uuidString: "00000000-0000-0000-0000-\(String(format: "%012x", self.sequence))")!
147168
}
148-
return UUID(uuidString: "00000000-0000-0000-0000-\(String(format: "%012x", self.sequence))")!
149169
}
150-
}
170+
#endif

0 commit comments

Comments
 (0)