Skip to content

Commit 44cab1e

Browse files
bsneedbrianmichelalanjcharles
authored
Add Windows support (#348)
* Everything compiles * Remove SSH agent * Add windows vendor and tests * Update windows ci and leave comment * Disable testing and leave comment * Use spaces * Update json encoder version * Make `shared()` public. * disable windows test suite temporarily * Updated tests for windows compat * another test update * turn win test runner back on * try dynamic lib on windows. * try a different build runner * try some settings-fu * and again ... * disable tests for Windows. * Added link to issue. * Update gitignore. --------- Co-authored-by: Brian Michel <[email protected]> Co-authored-by: Alan <[email protected]>
1 parent 944c3c4 commit 44cab1e

25 files changed

+633
-519
lines changed

.github/workflows/swift.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ jobs:
4747
- name: Run tests
4848
run: swift test --enable-test-discovery
4949

50+
build_and_test_spm_windows:
51+
needs: cancel_previous
52+
runs-on: windows-latest
53+
steps:
54+
- uses: SwiftyLab/setup-swift@latest
55+
with:
56+
swift-version: "5.10"
57+
- uses: actions/checkout@v2
58+
- name: Build
59+
run: swift build
60+
#
61+
# Disable tests right now. There's an SPM issue where link errors generate
62+
# a bad exit code even though the tests run/work properly.
63+
#
64+
# See: https://forums.swift.org/t/linker-warnings-on-windows-with-swift-argument-parser/71443/2
65+
#
66+
# - name: Run tests
67+
# run: swift test --enable-test-discovery
68+
5069
build_and_test_ios:
5170
needs: cancel_previous
5271
runs-on: macos-14

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@ iOSInjectionProject/
9292
Package.resolved
9393
*.xcuserdatad
9494
/.swiftpm/xcode/xcshareddata
95-
96-
# XCFramework
9795
Segment-Package_XCFramework
9896
*.zip
9997
Segment.xcframework.zip
10098
Segment.xcframework
10199
XCFrameworkOutput
102100
*.sha256
101+
.fleet
102+
.idea
103+
.vscode
104+
.editorconfig

Examples/other_plugins/NotificationTracking.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@
3333

3434
// MARK: Common
3535

36-
#if !os(Linux) && !os(macOS)
36+
#if !os(Linux) && !os(macOS) && !os(Windows)
3737

3838
import Foundation
3939
import Segment
4040

4141
class NotificationTracking: Plugin {
4242
var type: PluginType = .utility
4343
weak var analytics: Analytics?
44-
44+
4545
func trackNotification(_ properties: [String: Codable], fromLaunch launch: Bool) {
4646
if launch {
4747
analytics?.track(name: "Push Notification Tapped", properties: properties)
@@ -95,4 +95,3 @@ extension NotificationTracking: iOSLifecycle {
9595
}
9696

9797
#endif
98-

Package.resolved

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
{
1313
"identity" : "sovran-swift",
1414
"kind" : "remoteSourceControl",
15-
"location" : "https://github.com/segmentio/Sovran-Swift.git",
15+
"location" : "https://github.com/segmentio/sovran-swift.git",
1616
"state" : {
1717
"revision" : "a342b905f6baa64499cabdf61ccc185ec476b7b2",
1818
"version" : "1.1.1"
1919
}
2020
}
2121
],
2222
"version" : 2
23-
}
23+
}

Package.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ let package = Package(
3333
.product(name: "Sovran", package: "sovran-swift"),
3434
.product(name: "JSONSafeEncoding", package: "jsonsafeencoding-swift")
3535
],
36-
resources: [.process("Resources")]),
36+
resources: [.process("Resources")]
37+
),
3738
.testTarget(
3839
name: "Segment-Tests",
39-
dependencies: ["Segment"]),
40+
dependencies: ["Segment"]
41+
),
4042
]
4143
)

Sources/Segment/Analytics.swift

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,23 @@ public class Analytics {
2020
}
2121
internal var store: Store
2222
internal var storage: Storage
23-
23+
2424
/// Enabled/disables debug logging to trace your data going through the SDK.
2525
public static var debugLogsEnabled = false
26-
26+
2727
public var timeline: Timeline
28-
28+
2929
static internal let deadInstance = "DEADINSTANCE"
3030
static internal weak var firstInstance: Analytics? = nil
31+
3132
@Atomic static internal var activeWriteKeys = [String]()
32-
33+
3334
/**
3435
This method isn't a traditional singleton implementation. It's provided here
3536
to ease migration from analytics-ios to analytics-swift. Rather than return a
3637
singleton, it returns the first instance of Analytics created, OR an instance
3738
who's writekey is "DEADINSTANCE".
38-
39+
3940
In the case of a dead instance, an assert will be thrown when in DEBUG builds to
4041
assist developers in knowning that `shared()` is being called too soon.
4142
*/
@@ -45,16 +46,16 @@ public class Analytics {
4546
return a
4647
}
4748
}
48-
49+
4950
#if DEBUG
5051
if isUnitTesting == false {
5152
assert(true == false, "An instance of Analytice does not exist!")
5253
}
5354
#endif
54-
55+
5556
return Analytics(configuration: Configuration(writeKey: deadInstance))
5657
}
57-
58+
5859
/// Initialize this instance of Analytics with a given configuration setup.
5960
/// - Parameters:
6061
/// - configuration: The configuration to use
@@ -75,40 +76,40 @@ public class Analytics {
7576
operatingMode: configuration.values.operatingMode
7677
)
7778
timeline = Timeline()
78-
79+
7980
// provide our default state
8081
store.provide(state: System.defaultState(configuration: configuration, from: storage))
8182
store.provide(state: UserInfo.defaultState(from: storage, anonIdGenerator: configuration.values.anonymousIdGenerator))
8283

8384
storage.analytics = self
84-
85+
8586
checkSharedInstance()
86-
87+
8788
// Get everything running
8889
platformStartup()
8990
}
9091

9192
deinit {
9293
Self.removeActiveWriteKey(configuration.values.writeKey)
9394
}
94-
95+
9596
internal func process<E: RawEvent>(incomingEvent: E) {
9697
guard enabled == true else { return }
9798
let event = incomingEvent.applyRawEventData(store: store)
98-
99+
99100
_ = timeline.process(incomingEvent: event)
100-
101+
101102
let flushPolicies = configuration.values.flushPolicies
102103
for policy in flushPolicies {
103104
policy.updateState(event: event)
104-
105+
105106
if (policy.shouldFlush() == true) {
106107
flush()
107108
policy.reset()
108109
}
109110
}
110111
}
111-
112+
112113
/// Process a raw event through the system. Useful when one needs to queue and replay events at a later time.
113114
/// - Parameters:
114115
/// - event: An event conforming to RawEvent that will be processed.
@@ -160,20 +161,20 @@ extension Analytics {
160161
}
161162
return ""
162163
}
163-
164+
164165
/// Returns the userId that was specified in the last identify call.
165166
public var userId: String? {
166167
if let userInfo: UserInfo = store.currentState() {
167168
return userInfo.userId
168169
}
169170
return nil
170171
}
171-
172+
172173
/// Returns the current operating mode this instance was given.
173174
public var operatingMode: OperatingMode {
174175
return configuration.values.operatingMode
175176
}
176-
177+
177178
/// Adjusts the flush interval post configuration.
178179
public var flushInterval: TimeInterval {
179180
get {
@@ -186,7 +187,7 @@ extension Analytics {
186187
}
187188
}
188189
}
189-
190+
190191
/// Adjusts the flush-at count post configuration.
191192
public var flushAt: Int {
192193
get {
@@ -199,30 +200,30 @@ extension Analytics {
199200
}
200201
}
201202
}
202-
203+
203204
/// Returns a list of currently active flush policies.
204205
public var flushPolicies: [FlushPolicy] {
205206
get {
206207
configuration.values.flushPolicies
207208
}
208209
}
209-
210+
210211
/// Returns the traits that were specified in the last identify call.
211212
public func traits<T: Codable>() -> T? {
212213
if let userInfo: UserInfo = store.currentState() {
213214
return userInfo.traits?.codableValue()
214215
}
215216
return nil
216217
}
217-
218+
218219
/// Returns the traits that were specified in the last identify call, as a dictionary.
219220
public func traits() -> [String: Any]? {
220221
if let userInfo: UserInfo = store.currentState() {
221222
return userInfo.traits?.dictionaryValue
222223
}
223224
return nil
224225
}
225-
226+
226227
/// Tells this instance of Analytics to flush any queued events up to Segment.com. This command will also
227228
/// be sent to each plugin present in the system. A completion handler can be optionally given and will be
228229
/// called when flush has completed.
@@ -247,7 +248,7 @@ extension Analytics {
247248
completion?()
248249
}
249250
}
250-
251+
251252
/// Resets this instance of Analytics to a clean slate. Traits, UserID's, anonymousId, etc are all cleared or reset. This
252253
/// command will also be sent to each plugin present in the system.
253254
public func reset() {
@@ -258,13 +259,13 @@ extension Analytics {
258259
}
259260
}
260261
}
261-
262+
262263
/// Retrieve the version of this library in use.
263264
/// - Returns: A string representing the version in "BREAKING.FEATURE.FIX" format.
264265
public func version() -> String {
265266
return Analytics.version()
266267
}
267-
268+
268269
/// Retrieve the version of this library in use.
269270
/// - Returns: A string representing the version in "BREAKING.FEATURE.FIX" format.
270271
public static func version() -> String {
@@ -282,7 +283,7 @@ extension Analytics {
282283
}
283284
return settings
284285
}
285-
286+
286287
/// Manually enable a destination plugin. This is useful when a given DestinationPlugin doesn't have any Segment tie-ins at all.
287288
/// This will allow the destination to be processed in the same way within this library.
288289
/// - Parameters:
@@ -306,25 +307,25 @@ extension Analytics {
306307

307308
return storage.dataStore.hasData
308309
}
309-
310+
310311
/// Provides a list of finished, but unsent events.
311312
public var pendingUploads: [URL]? {
312313
return storage.read(Storage.Constants.events)?.dataFiles
313314
}
314-
315+
315316
/// Purge all pending event upload files.
316317
public func purgeStorage() {
317318
storage.dataStore.reset()
318319
}
319-
320+
320321
/// Purge a single event upload file.
321322
public func purgeStorage(fileURL: URL) {
322323
guard let dataFiles = storage.read(Storage.Constants.events)?.dataFiles else { return }
323324
if dataFiles.contains(fileURL) {
324325
try? FileManager.default.removeItem(at: fileURL)
325326
}
326327
}
327-
328+
328329
/// Wait until the Analytics object has completed startup.
329330
/// This method is primarily useful for command line utilities where
330331
/// it's desirable to wait until the system is up and running
@@ -344,7 +345,7 @@ extension Analytics {
344345
Call openURL as needed or when instructed to by either UIApplicationDelegate or UISceneDelegate.
345346
This is necessary to track URL referrers across events. This method will also iterate
346347
any plugins that are watching for openURL events.
347-
348+
348349
Example:
349350
```
350351
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
@@ -359,12 +360,12 @@ extension Analytics {
359360
guard let dict = jsonProperties.dictionaryValue else { return }
360361
openURL(url, options: dict)
361362
}
362-
363+
363364
/**
364365
Call openURL as needed or when instructed to by either UIApplicationDelegate or UISceneDelegate.
365366
This is necessary to track URL referrers across events. This method will also iterate
366367
any plugins that are watching for openURL events.
367-
368+
368369
Example:
369370
```
370371
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
@@ -375,14 +376,14 @@ extension Analytics {
375376
*/
376377
public func openURL(_ url: URL, options: [String: Any] = [:]) {
377378
store.dispatch(action: UserInfo.SetReferrerAction(url: url))
378-
379+
379380
// let any conforming plugins know
380381
apply { plugin in
381382
if let p = plugin as? OpeningURLs {
382383
p.openURL(url, options: options)
383384
}
384385
}
385-
386+
386387
var jsonProperties: JSON? = nil
387388
if let json = try? JSON(options) {
388389
jsonProperties = json
@@ -411,7 +412,7 @@ extension Analytics {
411412
Self.firstInstance = self
412413
}
413414
}
414-
415+
415416
/// Determines if an instance is dead.
416417
internal var isDead: Bool {
417418
return configuration.values.writeKey == Self.deadInstance
@@ -455,4 +456,3 @@ extension OperatingMode {
455456
}
456457
}
457458
}
458-

0 commit comments

Comments
 (0)