Skip to content

Commit 7c9c162

Browse files
bsneedalanjcharles
andauthored
Storage Additions & Refactoring (#304)
* Storage Refactoring * Standardized things a little more * fixed build issue * tweaked some tests * Ramp up some test values for linux * Package rename --------- Co-authored-by: Alan Charles <[email protected]>
1 parent 40ec9ac commit 7c9c162

22 files changed

+1398
-625
lines changed

.github/workflows/swift.yml

Lines changed: 93 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,119 +2,135 @@ name: Swift
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [main]
66
pull_request:
7-
branches: [ main ]
7+
branches: [main]
88

99
jobs:
1010
cancel_previous:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: styfle/cancel-workflow-action@0.9.1
14-
with:
15-
workflow_id: ${{ github.event.workflow.id }}
16-
13+
- uses: styfle/cancel-workflow-action@0.12.0
14+
with:
15+
workflow_id: ${{ github.event.workflow.id }}
16+
1717
build_and_test_spm_mac:
1818
needs: cancel_previous
19-
runs-on: macos-latest
19+
runs-on: macos-14
2020
steps:
21-
- uses: maxim-lobanov/setup-xcode@v1
22-
with:
23-
xcode-version: latest-stable
24-
- uses: actions/checkout@v2
25-
- uses: webfactory/ssh-agent@v0.5.3
26-
with:
27-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
28-
- name: Build
29-
run: swift build
30-
- name: Run tests
31-
run: swift test
21+
- uses: maxim-lobanov/setup-xcode@v1
22+
with:
23+
xcode-version: "15.2"
24+
- uses: actions/checkout@v2
25+
- uses: webfactory/ssh-agent@v0.8.0
26+
with:
27+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
28+
- name: Build
29+
run: swift build
30+
- name: Run tests
31+
run: swift test
3232

3333
build_and_test_spm_linux:
3434
needs: cancel_previous
3535
runs-on: ubuntu-latest
3636
steps:
37-
- uses: fwal/[email protected]
38-
with:
39-
swift-version: "5.7.2"
40-
- uses: actions/checkout@v2
41-
- uses: webfactory/[email protected]
42-
with:
43-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
44-
- name: Build
45-
run: swift build
46-
- name: Run tests
47-
run: swift test --enable-test-discovery
37+
- uses: sersoft-gmbh/swifty-linux-action@v3
38+
with:
39+
release-version: "5.9.2"
40+
github-token: ${{secrets.GITHUB_TOKEN}}
41+
- uses: actions/checkout@v2
42+
- uses: webfactory/[email protected]
43+
with:
44+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
45+
- name: Build
46+
run: swift build
47+
- name: Run tests
48+
run: swift test --enable-test-discovery
4849

4950
build_and_test_ios:
5051
needs: cancel_previous
51-
runs-on: macos-latest
52+
runs-on: macos-14
5253
steps:
53-
- uses: maxim-lobanov/setup-xcode@v1
54-
with:
55-
xcode-version: latest-stable
56-
- uses: actions/checkout@v2
57-
- uses: webfactory/[email protected]
58-
with:
59-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
60-
- run: xcodebuild -scheme Segment test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 13'
61-
54+
- uses: maxim-lobanov/setup-xcode@v1
55+
with:
56+
xcode-version: "15.2"
57+
- uses: actions/checkout@v2
58+
- uses: webfactory/[email protected]
59+
with:
60+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
61+
- run: xcodebuild -scheme Segment test -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 15'
6262

6363
build_and_test_tvos:
6464
needs: cancel_previous
65-
runs-on: macos-latest
65+
runs-on: macos-14
6666
steps:
67-
- uses: maxim-lobanov/setup-xcode@v1
68-
with:
69-
xcode-version: latest-stable
70-
- uses: actions/checkout@v2
71-
- uses: webfactory/ssh-agent@v0.5.3
72-
with:
73-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
74-
- run: xcodebuild -scheme Segment test -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV'
67+
- uses: maxim-lobanov/setup-xcode@v1
68+
with:
69+
xcode-version: "15.2"
70+
- uses: actions/checkout@v2
71+
- uses: webfactory/ssh-agent@v0.8.0
72+
with:
73+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
74+
- run: xcodebuild -scheme Segment test -sdk appletvsimulator -destination 'platform=tvOS Simulator,name=Apple TV'
7575

7676
build_and_test_watchos:
7777
needs: cancel_previous
78-
runs-on: macos-latest
78+
runs-on: macos-14
79+
steps:
80+
- uses: maxim-lobanov/setup-xcode@v1
81+
with:
82+
xcode-version: "15.2"
83+
- uses: actions/checkout@v2
84+
- uses: webfactory/[email protected]
85+
with:
86+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
87+
- run: xcodebuild -scheme Segment test -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch Series 9 (45mm)'
88+
89+
build_and_test_visionos:
90+
needs: cancel_previous
91+
runs-on: macos-14
7992
steps:
80-
- uses: maxim-lobanov/setup-xcode@v1
81-
with:
82-
xcode-version: latest-stable
83-
- uses: actions/checkout@v2
84-
- uses: webfactory/[email protected]
85-
with:
86-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
87-
- run: xcodebuild -scheme Segment test -sdk watchsimulator -destination 'platform=watchOS Simulator,name=Apple Watch Series 8 (45mm)'
88-
93+
- uses: maxim-lobanov/setup-xcode@v1
94+
with:
95+
xcode-version: "15.2"
96+
- uses: actions/checkout@v2
97+
- uses: webfactory/[email protected]
98+
with:
99+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
100+
- run: defaults write com.apple.dt.Xcode AllowUnsupportedVisionOSHost -bool YES
101+
- run: defaults write com.apple.CoreSimulator AllowUnsupportedVisionOSHost -bool YES
102+
- run: xcodebuild -downloadPlatform visionOS
103+
- run: echo - skip until apple fixes this - xcodebuild -scheme Segment test -sdk xrsimulator -destination 'platform=visionOS Simulator,name=Apple Vision Pro'
104+
- run: xcodebuild -scheme Segment -sdk xrsimulator -destination 'platform=visionOS Simulator,name=Apple Vision Pro'
105+
89106
build_and_test_examples:
90107
needs: cancel_previous
91-
runs-on: macos-latest
108+
runs-on: macos-14
92109
steps:
93-
- uses: maxim-lobanov/setup-xcode@v1
94-
with:
95-
xcode-version: latest-stable
96-
- uses: actions/checkout@v2
97-
- uses: webfactory/ssh-agent@v0.5.3
98-
with:
99-
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
100-
- name: build for ios simulator
101-
run: |
110+
- uses: maxim-lobanov/setup-xcode@v1
111+
with:
112+
xcode-version: "15.2"
113+
- uses: actions/checkout@v2
114+
- uses: webfactory/ssh-agent@v0.8.0
115+
with:
116+
ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }}
117+
- name: build for ios simulator
118+
run: |
102119
cd Examples/apps/BasicExample
103120
xcodebuild -workspace "BasicExample.xcworkspace" -scheme "BasicExample" -sdk iphonesimulator
104-
- name: build for ios simulator
105-
run: |
121+
- name: build for ios simulator
122+
run: |
106123
cd Examples/apps/ObjCExample
107124
xcodebuild -workspace "ObjCExample.xcworkspace" -scheme "ObjCExample" -sdk iphonesimulator
108-
- name: build for ios simulator
109-
run: |
125+
- name: build for ios simulator
126+
run: |
110127
cd Examples/apps/SegmentUIKitExample
111128
xcodebuild -workspace "SegmentUIKitExample.xcworkspace" -scheme "SegmentUIKitExample" -sdk iphonesimulator
112-
- name: build for ios simulator
113-
run: |
129+
- name: build for ios simulator
130+
run: |
114131
cd Examples/apps/SegmentWeatherWidget
115132
xcodebuild -workspace "SegmentWeatherWidget.xcworkspace" -scheme "SegmentWeatherWidget" -sdk iphonesimulator
116-
- name: build for mac catalyst
117-
run: |
133+
- name: build for mac catalyst
134+
run: |
118135
cd Examples/apps/SegmentUIKitExample
119136
xcodebuild -workspace "SegmentUIKitExample.xcworkspace" -scheme "SegmentUIKitExample" -destination 'platform=macOS,variant=Mac Catalyst'
120-

Package.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.7
1+
// swift-tools-version:5.9
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -9,7 +9,8 @@ let package = Package(
99
.macOS("10.15"),
1010
.iOS("13.0"),
1111
.tvOS("11.0"),
12-
.watchOS("7.1")
12+
.watchOS("7.1"),
13+
.visionOS("1.0")
1314
],
1415
products: [
1516
// Products define the executables and libraries a package produces, and make them visible to other packages.

[email protected]

Lines changed: 0 additions & 41 deletions
This file was deleted.

Sources/Segment/Analytics.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,20 @@ public class Analytics {
6060
/// - configuration: The configuration to use
6161
public init(configuration: Configuration) {
6262
if Self.isActiveWriteKey(configuration.values.writeKey) {
63+
// If you're hitting this in testing, it could be a memory leak, or something async is still running
64+
// and holding a reference. You can use XCTest.waitUntilFinished(...) to wait for things to complete.
6365
fatalError("Cannot initialize multiple instances of Analytics with the same write key")
6466
} else {
6567
Self.addActiveWriteKey(configuration.values.writeKey)
6668
}
6769

6870
store = Store()
69-
storage = Storage(store: self.store, writeKey: configuration.values.writeKey)
71+
storage = Storage(
72+
store: self.store,
73+
writeKey: configuration.values.writeKey,
74+
storageMode: configuration.values.storageMode,
75+
operatingMode: configuration.values.operatingMode
76+
)
7077
timeline = Timeline()
7178

7279
// provide our default state
@@ -330,32 +337,25 @@ extension Analytics {
330337
}
331338
}
332339

333-
if let files = storage.read(Storage.Constants.events) {
334-
if files.count > 0 {
335-
return true
336-
}
337-
}
338-
339-
return false
340+
return storage.dataStore.hasData
340341
}
341342

342343
/// Provides a list of finished, but unsent events.
343344
public var pendingUploads: [URL]? {
344-
return storage.read(Storage.Constants.events)
345+
return storage.read(Storage.Constants.events)?.dataFiles
345346
}
346347

347348
/// Purge all pending event upload files.
348349
public func purgeStorage() {
349-
if let files = pendingUploads {
350-
for file in files {
351-
purgeStorage(fileURL: file)
352-
}
353-
}
350+
storage.dataStore.reset()
354351
}
355352

356353
/// Purge a single event upload file.
357354
public func purgeStorage(fileURL: URL) {
358-
try? FileManager.default.removeItem(at: fileURL)
355+
guard let dataFiles = storage.read(Storage.Constants.events)?.dataFiles else { return }
356+
if dataFiles.contains(fileURL) {
357+
try? FileManager.default.removeItem(at: fileURL)
358+
}
359359
}
360360

361361
/// Wait until the Analytics object has completed startup.

Sources/Segment/Configuration.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ public enum OperatingMode {
2222
static internal let defaultQueue = DispatchQueue(label: "com.segment.operatingModeQueue", qos: .utility)
2323
}
2424

25+
// MARK: - Storage Mode
26+
/// Specifies the storage mode to be used for events
27+
public enum StorageMode {
28+
/// Store events to disk (default).
29+
case disk
30+
/// Store events to disk in the given a directory URL.
31+
case diskAtURL(URL)
32+
/// Store events to memory and specify a max count before they roll off.
33+
case memory(Int)
34+
/// Some custom, user-defined storage mechanism conforming to `DataStore`.
35+
case custom(any DataStore)
36+
}
37+
2538
// MARK: - Internal Configuration
2639

2740
public class Configuration {
@@ -42,6 +55,7 @@ public class Configuration {
4255
var flushQueue: DispatchQueue = OperatingMode.defaultQueue
4356
var userAgent: String? = nil
4457
var jsonNonConformingNumberStrategy: JSONSafeEncoder.NonConformingFloatEncodingStrategy = .zero
58+
var storageMode: StorageMode = .disk
4559
}
4660

4761
internal var values: Values
@@ -233,6 +247,12 @@ public extension Configuration {
233247
JSON.jsonNonConformingNumberStrategy = values.jsonNonConformingNumberStrategy
234248
return self
235249
}
250+
251+
@discardableResult
252+
func storageMode(_ mode: StorageMode) -> Configuration {
253+
values.storageMode = mode
254+
return self
255+
}
236256
}
237257

238258
extension Analytics {

Sources/Segment/Plugins/Platforms/Vendors/AppleUtils.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,11 @@ internal class MacOSVendorSystem: VendorSystem {
249249
// It has to be fetched on the main thread, so we've spun it off
250250
// async and cache it when it comes back.
251251
if Self.asyncUserAgent == nil {
252-
DispatchQueue.main.async {
253-
Self.asyncUserAgent = WKWebView().value(forKey: "userAgent") as? String
252+
// it's failing tests because it never comes back; they get stuck.
253+
if isUnitTesting == false {
254+
DispatchQueue.main.async {
255+
Self.asyncUserAgent = WKWebView().value(forKey: "userAgent") as? String
256+
}
254257
}
255258
}
256259
return Self.asyncUserAgent

Sources/Segment/Plugins/Platforms/iOS/iOSLifecycleMonitor.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,9 @@ extension SegmentDestination: iOSLifecycle {
186186
}
187187

188188
extension SegmentDestination.UploadTaskInfo {
189-
init(url: URL, task: URLSessionDataTask) {
189+
init(url: URL?, data: Data?, task: URLSessionDataTask) {
190190
self.url = url
191+
self.data = data
191192
self.task = task
192193

193194
if let application = UIApplication.safeShared {

0 commit comments

Comments
 (0)