Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
43 changes: 35 additions & 8 deletions Sources/Segment/Utilities/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,44 @@ 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 }

// Look for old segment directories to move
let oldLocations = [
fm.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("segment"),
fm.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("segment")
].compactMap { $0 }

for oldSegmentDir in oldLocations {
guard fm.fileExists(atPath: oldSegmentDir.path) else { continue }

do {
try fm.moveItem(at: oldSegmentDir, to: newSegmentDir)
Analytics.segmentLog(message: "Migrated analytics data from \(oldSegmentDir.path)", kind: .debug)
return // Success!
} 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)
}
}