Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Sources/Segment/State.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ struct System: State {

func reduce(state: System) -> System {
var waitingPlugins = state.waitingPlugins
let countBefore = waitingPlugins.count
waitingPlugins.removeAll { p in
return plugin === p
}
Expand Down
44 changes: 36 additions & 8 deletions Sources/Segment/Utilities/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,45 @@ extension Optional: Flattenable {
}

internal func eventStorageDirectory(writeKey: String) -> URL {
#if (os(iOS) || os(watchOS)) && !targetEnvironment(macCatalyst)
let searchPathDirectory = FileManager.SearchPathDirectory.documentDirectory
#else
let searchPathDirectory = FileManager.SearchPathDirectory.cachesDirectory
#endif
let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let appSupportURL = urls[0]
let segmentURL = appSupportURL.appendingPathComponent("segment/\(writeKey)/")

// Handle one-time migration from old locations
migrateFromOldLocations(writeKey: writeKey, to: segmentURL)

let urls = FileManager.default.urls(for: searchPathDirectory, in: .userDomainMask)
let docURL = urls[0]
let segmentURL = docURL.appendingPathComponent("segment/\(writeKey)/")
// try to create it, will fail if already exists, nbd.
// tvOS, watchOS regularly clear out data.
try? FileManager.default.createDirectory(at: segmentURL, withIntermediateDirectories: true, attributes: nil)
return segmentURL
}

private func migrateFromOldLocations(writeKey: String, to newLocation: URL) {
let fm = FileManager.default

// Get the parent of where our new segment directory should live
let appSupportURL = fm.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let newSegmentDir = appSupportURL.appendingPathComponent("segment")

// If segment dir already exists in app support, we're done
guard !fm.fileExists(atPath: newSegmentDir.path) else { return }

// Only check the old location that was actually used on this platform
#if (os(iOS) || os(watchOS)) && !targetEnvironment(macCatalyst)
let oldSearchPath = FileManager.SearchPathDirectory.documentDirectory
#else
let oldSearchPath = FileManager.SearchPathDirectory.cachesDirectory
#endif

guard let oldBaseURL = fm.urls(for: oldSearchPath, in: .userDomainMask).first else { return }
let oldSegmentDir = oldBaseURL.appendingPathComponent("segment")

guard fm.fileExists(atPath: oldSegmentDir.path) else { return }

do {
try fm.moveItem(at: oldSegmentDir, to: newSegmentDir)
Analytics.segmentLog(message: "Migrated analytics data from \(oldSegmentDir.path)", kind: .debug)
} catch {
Analytics.segmentLog(message: "Failed to migrate from \(oldSegmentDir.path): \(error)", kind: .error)
}
}
46 changes: 45 additions & 1 deletion Tests/Segment-Tests/Storage_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ class StorageTests: XCTestCase {
}

func testFilePrepAndFinish() {
let analytics = Analytics(configuration: Configuration(writeKey: "test"))
let config = Configuration(writeKey: "test")
.storageMode(.diskAtURL(URL(fileURLWithPath: NSTemporaryDirectory())))
let analytics = Analytics(configuration: config)

analytics.storage.hardReset(doYouKnowHowToUseThis: true)

analytics.waitUntilStarted()
Expand Down Expand Up @@ -302,4 +305,45 @@ class StorageTests: XCTestCase {
let remaining = analytics.storage.read(.events)
XCTAssertNil(remaining)
}

func testMigrationFromOldLocation() {
let writeKey = "test-migration"
let fm = FileManager.default

// Clean slate
let appSupportURL = fm.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
let newSegmentDir = appSupportURL.appendingPathComponent("segment")
try? fm.removeItem(at: newSegmentDir)

// Create fake old data in the platform-specific old location
#if (os(iOS) || os(watchOS)) && !targetEnvironment(macCatalyst)
let oldSearchPath = FileManager.SearchPathDirectory.documentDirectory
#else
let oldSearchPath = FileManager.SearchPathDirectory.cachesDirectory
#endif

let oldBaseURL = fm.urls(for: oldSearchPath, in: .userDomainMask)[0]
let oldSegmentDir = oldBaseURL.appendingPathComponent("segment/\(writeKey)")
try! fm.createDirectory(at: oldSegmentDir, withIntermediateDirectories: true, attributes: nil)

// Write some fake event files
let testFile1 = oldSegmentDir.appendingPathComponent("0-segment-events.temp")
let testFile2 = oldSegmentDir.appendingPathComponent("1-segment-events.temp")
try! "fake event data 1".write(to: testFile1, atomically: true, encoding: .utf8)
try! "fake event data 2".write(to: testFile2, atomically: true, encoding: .utf8)

// Trigger migration
let resultURL = eventStorageDirectory(writeKey: writeKey)

// Verify migration worked
XCTAssertTrue(fm.fileExists(atPath: resultURL.path))
XCTAssertTrue(fm.fileExists(atPath: resultURL.appendingPathComponent("0-segment-events.temp").path))
XCTAssertTrue(fm.fileExists(atPath: resultURL.appendingPathComponent("1-segment-events.temp").path))

// Verify old directory is gone
XCTAssertFalse(fm.fileExists(atPath: oldSegmentDir.path))

// Clean up
try? fm.removeItem(at: newSegmentDir)
}
}