mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-11 07:43:28 +01:00
- [WIP]: migrations fix for coredata from v11(0.5.9) to v17_1(0.6.1) and v17(0.6.0 to v17_1(0.6.1)
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// SourceMigrationPolicy.swift
|
||||
// Source11To17MigrationPolicy.swift
|
||||
// AltStoreCore
|
||||
//
|
||||
// Created by Riley Testut on 10/19/23.
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// StoreAppMigration11To17Policy.swift
|
||||
// StoreApp11To17MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 25/02/25.
|
||||
@@ -108,7 +108,7 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
// Create a new ReleaseTrack entity
|
||||
let context = dInstance.managedObjectContext!
|
||||
let releaseTrack = NSEntityDescription.insertNewObject(forEntityName: ReleaseTrack.entity().name!, into: context)
|
||||
let releaseTrack = NSEntityDescription.insertNewObject(forEntityName: ReleaseTrack.entity().name! ?? ReleaseTrack.description(), into: context)
|
||||
releaseTrack.setValue(defaultChannel, forKey: #keyPath(ReleaseTrack._track))
|
||||
|
||||
// Connect the releaseTrack to the destination StoreApp
|
||||
@@ -116,7 +116,7 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
|
||||
// Find the mapping name for AppVersion (make sure this exactly matches your mapping model)
|
||||
let appVersionMappingName = findEntityMappingName(for: AppVersion.entity().name!, in: manager)
|
||||
let appVersionMappingName = findEntityMappingName(for: AppVersion.entity().name ?? AppVersion.description(), in: manager)
|
||||
|
||||
// Create a mutable ordered set for the destination AppVersion objects
|
||||
let destinationVersionsSet = NSMutableOrderedSet()
|
||||
@@ -145,5 +145,5 @@ class StoreApp11To17MigrationPolicy: NSEntityMigrationPolicy {
|
||||
// dInstance.setValue(NSOrderedSet(), forKey: #keyPath(StoreApp._versions))
|
||||
dInstance.setValue(nil, forKey: #keyPath(StoreApp._versions))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// AppPermission11To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(AppPermission11To17_1MigrationPolicy)
|
||||
class AppPermission11To17_1MigrationPolicy: AppPermission17To17_1MigrationPolicy
|
||||
{
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
}
|
||||
|
||||
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// ReleaseTrack11To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(ReleaseTrack11To17_1MigrationPolicy)
|
||||
class ReleaseTrack11To17_1MigrationPolicy: ReleaseTrack17To17_1MigrationPolicy
|
||||
{
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
}
|
||||
|
||||
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Source17To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(Source11To17_1MigrationPolicy)
|
||||
class Source11To17_1MigrationPolicy: Source17To17_1MigrationPolicy
|
||||
{
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
}
|
||||
|
||||
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// StoreApp11To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(StoreApp11To17_1MigrationPolicy)
|
||||
class StoreApp11To17_1MigrationPolicy: StoreApp11To17MigrationPolicy
|
||||
{
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
}
|
||||
|
||||
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// AppPermission17To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(AppPermission17To17_1MigrationPolicy)
|
||||
class AppPermission17To17_1MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
// Let the default implementation create the basic destination AppPermission
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
|
||||
// Get the destination AppPermission instance that was created
|
||||
guard let destinationPermission = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else {
|
||||
print("Failed to locate destination AppPermission instance")
|
||||
return
|
||||
}
|
||||
|
||||
// Extract the type value from source
|
||||
if let type = sInstance.value(forKey: #keyPath(AppPermission.type)) as? String {
|
||||
// In the new model, "permission" is the actual permission string, which needs to be derived from the old "type"
|
||||
let permission = self.derivePermissionFromType(type)
|
||||
destinationPermission.setValue(permission, forKey: #keyPath(AppPermission._permission))
|
||||
}
|
||||
|
||||
// set initial values copied from source as-is
|
||||
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
|
||||
if let storeApp = sInstance.value(forKey: #keyPath(AppPermission.app)) as? NSManagedObject{
|
||||
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
|
||||
destinationPermission.setValue(appBundle, forKey: #keyPath(AppPermission.appBundleID))
|
||||
}
|
||||
|
||||
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
|
||||
destinationPermission.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
override func createRelationships(
|
||||
forDestination dInstance: NSManagedObject,
|
||||
in mapping: NSEntityMapping,
|
||||
manager: NSMigrationManager
|
||||
) throws {
|
||||
// Retrieve the corresponding source instance for the destination StoreApp
|
||||
let sourceInstances = manager.sourceInstances(forEntityMappingName: mapping.name, destinationInstances: [dInstance])
|
||||
guard let sInstance = sourceInstances.first else {
|
||||
print("No source instance found for destination: \(dInstance)")
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve the source storeApp from the source appPermission
|
||||
guard let storeApp = sInstance.value(forKey: #keyPath(AppPermission.app)) as? NSManagedObject else {
|
||||
print("Source \(AppPermission.description()) has no storeApp")
|
||||
return
|
||||
}
|
||||
|
||||
// set initial values copied from source as-is to satisfy unique constraints
|
||||
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
|
||||
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
|
||||
dInstance.setValue(appBundle, forKey: #keyPath(AppPermission.appBundleID))
|
||||
}
|
||||
|
||||
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
|
||||
dInstance.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to derive permission string from type
|
||||
private func derivePermissionFromType(_ type: String) -> String {
|
||||
// Based on the code in the documents, we need to map the ALTAppPermissionType to permission strings
|
||||
switch type {
|
||||
case "photos": return "NSPhotosUsageDescription"
|
||||
case "camera": return "NSCameraUsageDescription"
|
||||
case "location": return "NSLocationUsageDescription"
|
||||
case "contacts": return "NSContactsUsageDescription"
|
||||
case "reminders": return "NSRemindersUsageDescription"
|
||||
case "music": return "NSAppleMusicUsageDescription"
|
||||
case "microphone": return "NSMicrophoneUsageDescription"
|
||||
case "speech-recognition": return "NSSpeechRecognitionUsageDescription"
|
||||
case "background-audio": return "NSBackgroundAudioUsageDescription"
|
||||
case "background-fetch": return "NSBackgroundFetchUsageDescription"
|
||||
case "bluetooth": return "NSBluetoothUsageDescription"
|
||||
case "network": return "NSNetworkUsageDescription"
|
||||
case "calendars": return "NSCalendarsUsageDescription"
|
||||
case "touchID": return "NSTouchIDUsageDescription"
|
||||
case "faceID": return "NSFaceIDUsageDescription"
|
||||
case "siri": return "NSSiriUsageDescription"
|
||||
case "motion": return "NSMotionUsageDescription"
|
||||
case "entitlement": return type // For entitlements, we might keep the raw value
|
||||
case "privacy": return type // For privacy permissions, we might keep the raw value
|
||||
default: return type // Default fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// ReleaseTrack17To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
@objc(ReleaseTrack17To17_1MigrationPolicy)
|
||||
class ReleaseTrack17To17_1MigrationPolicy: NSEntityMigrationPolicy {
|
||||
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
// Let the default implementation create the basic destination AppPermission
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
|
||||
// Get the destination AppPermission instance that was created
|
||||
guard let destinationPermission = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else {
|
||||
print("Failed to locate destination ReleaseTrack instance")
|
||||
return
|
||||
}
|
||||
|
||||
if let track = sInstance.value(forKey: #keyPath(ReleaseTrack._track)) as? String {
|
||||
destinationPermission.setValue(track, forKey: #keyPath(ReleaseTrack._track))
|
||||
}
|
||||
|
||||
// set initial values migrated from source as-is
|
||||
if let storeApp = sInstance.value(forKey: #keyPath(ReleaseTrack.storeApp)) as? NSManagedObject{
|
||||
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
|
||||
destinationPermission.setValue(appBundle, forKey: #keyPath(ReleaseTrack._appBundleID))
|
||||
}
|
||||
|
||||
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
|
||||
destinationPermission.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func createRelationships(
|
||||
forDestination dInstance: NSManagedObject,
|
||||
in mapping: NSEntityMapping,
|
||||
manager: NSMigrationManager
|
||||
) throws {
|
||||
// Retrieve the corresponding source instance for the destination StoreApp
|
||||
let sourceInstances = manager.sourceInstances(forEntityMappingName: mapping.name, destinationInstances: [dInstance])
|
||||
guard let sInstance = sourceInstances.first else {
|
||||
print("No source instance found for destination: \(dInstance)")
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve the source storeApp from the source ReleaseTrack
|
||||
guard let storeApp = sInstance.value(forKey: #keyPath(ReleaseTrack.storeApp)) as? NSManagedObject else {
|
||||
print("Source \(ReleaseTrack.description()) has no storeApp")
|
||||
return
|
||||
}
|
||||
|
||||
// set initial values copied from source as-is to satisfy unique constraints
|
||||
// (will be updated by StoreApp and Source migration policy in its createRelationship() method)
|
||||
if let appBundle = storeApp.value(forKey: #keyPath(StoreApp.bundleIdentifier)) as? String{
|
||||
dInstance.setValue(appBundle, forKey: #keyPath(ReleaseTrack._appBundleID))
|
||||
}
|
||||
|
||||
if let sourceID = storeApp.value(forKey: #keyPath(StoreApp.sourceIdentifier)) as? String {
|
||||
dInstance.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
//
|
||||
// Source17To17_1MigrationPolicy.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Magesh K on 15/03/25.
|
||||
// Copyright © 2025 SideStore. All rights reserved.
|
||||
//
|
||||
|
||||
import CoreData
|
||||
|
||||
fileprivate extension NSManagedObject
|
||||
{
|
||||
var sourceSourceURL: URL? {
|
||||
let sourceURL = self.value(forKey: #keyPath(Source.sourceURL)) as? URL
|
||||
return sourceURL
|
||||
}
|
||||
|
||||
var sourceSourceId: String? {
|
||||
let sourceId = self.value(forKey: #keyPath(Source.identifier)) as? String
|
||||
return sourceId
|
||||
}
|
||||
|
||||
var sourceApps: NSOrderedSet? {
|
||||
let apps = self.value(forKey: #keyPath(Source._apps)) as? NSOrderedSet
|
||||
return apps
|
||||
}
|
||||
|
||||
var sourceNewsItems: NSOrderedSet? {
|
||||
let newsItems = self.value(forKey: #keyPath(Source._newsItems)) as? NSOrderedSet
|
||||
return newsItems
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate extension NSManagedObject
|
||||
{
|
||||
func setSourceId(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(Source.identifier))
|
||||
}
|
||||
|
||||
func setGroupId(_ groupID: String)
|
||||
{
|
||||
self.setValue(groupID, forKey: #keyPath(Source.groupID))
|
||||
}
|
||||
|
||||
func setSourceSourceUrl(_ sourceURL: URL)
|
||||
{
|
||||
self.setValue(sourceURL, forKey: #keyPath(Source.sourceURL))
|
||||
}
|
||||
|
||||
func setSourceSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(Source.identifier))
|
||||
}
|
||||
|
||||
func setStoreAppSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(StoreApp.sourceIdentifier))
|
||||
}
|
||||
|
||||
func setNewsItemSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(NewsItem.sourceIdentifier))
|
||||
}
|
||||
|
||||
func setAppVersionSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(AppVersion.sourceID))
|
||||
}
|
||||
|
||||
func setAppPermissionSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(AppPermission.sourceID))
|
||||
}
|
||||
|
||||
func setAppScreenshotSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(AppScreenshot.sourceID))
|
||||
}
|
||||
|
||||
func setReleaseTracksSourceID(_ sourceID: String)
|
||||
{
|
||||
self.setValue(sourceID, forKey: #keyPath(ReleaseTrack._sourceID))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fileprivate extension NSManagedObject
|
||||
{
|
||||
var storeAppVersions: NSOrderedSet? {
|
||||
let versions = self.value(forKey: #keyPath(StoreApp._versions)) as? NSOrderedSet
|
||||
return versions
|
||||
}
|
||||
|
||||
var storeAppPermissions: NSSet? {
|
||||
let permissions = self.value(forKey: #keyPath(StoreApp._permissions)) as? NSSet
|
||||
return permissions
|
||||
}
|
||||
|
||||
var storeAppScreenshots: NSOrderedSet? {
|
||||
let screenshots = self.value(forKey: #keyPath(StoreApp._screenshots)) as? NSOrderedSet
|
||||
return screenshots
|
||||
}
|
||||
|
||||
var storeAppReleaseTracks: NSOrderedSet? {
|
||||
let tracks = self.value(forKey: #keyPath(StoreApp._releaseTracks)) as? NSOrderedSet
|
||||
return tracks
|
||||
}
|
||||
}
|
||||
|
||||
@objc(Source17To17_1MigrationPolicy)
|
||||
class Source17To17_1MigrationPolicy: NSEntityMigrationPolicy
|
||||
{
|
||||
override func createDestinationInstances(forSource sInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws {
|
||||
// Let the default implementation create the basic destination AppPermission
|
||||
try super.createDestinationInstances(forSource: sInstance, in: mapping, manager: manager)
|
||||
|
||||
// Get the destination Source instance that was created
|
||||
guard let dInstance = manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]).first else {
|
||||
print("Failed to locate destination Source instance")
|
||||
return
|
||||
}
|
||||
|
||||
// update new fields with initial values
|
||||
if let sourceID = sInstance.value(forKey: #keyPath(Source.identifier)) as? String {
|
||||
dInstance.setValue(sourceID, forKey: #keyPath(Source.groupID))
|
||||
}
|
||||
|
||||
guard var sourceURL = dInstance.sourceSourceURL else {
|
||||
return
|
||||
}
|
||||
|
||||
// sidestore official source has been moved to sidestore.io/apps-v2.json
|
||||
// if we don't switch, users will end up with 2 offical sources
|
||||
let normalizedSourceURL = try? sourceURL.normalized()
|
||||
if normalizedSourceURL == "apps.sidestore.io" // if using old source url (<0.5.9)
|
||||
{
|
||||
sourceURL = Source.altStoreSourceURL // switch to latest
|
||||
dInstance.setSourceSourceUrl(sourceURL) // and use it for current
|
||||
}
|
||||
|
||||
var sourceID = try Source.sourceID(from: sourceURL)
|
||||
dInstance.setSourceId(sourceID)
|
||||
|
||||
// for older versions migrating to current (their sourceID is their groupID)
|
||||
dInstance.setGroupId(sourceID)
|
||||
|
||||
if sourceID == "apps.sidestore.io" {
|
||||
sourceID = Source.altStoreIdentifier
|
||||
dInstance.setSourceId(sourceID)
|
||||
}
|
||||
}
|
||||
|
||||
override func createRelationships(forDestination dInstance: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws
|
||||
{
|
||||
try super.createRelationships(forDestination: dInstance, in: mapping, manager: manager)
|
||||
|
||||
guard let sourceID = dInstance.sourceSourceId else { return }
|
||||
|
||||
for case let app as NSManagedObject in dInstance.sourceApps ?? []
|
||||
{
|
||||
app.setStoreAppSourceID(sourceID)
|
||||
|
||||
for case let version as NSManagedObject in app.storeAppVersions ?? []
|
||||
{
|
||||
version.setAppVersionSourceID(sourceID)
|
||||
}
|
||||
|
||||
for case let permission as NSManagedObject in app.storeAppPermissions ?? []
|
||||
{
|
||||
permission.setAppPermissionSourceID(sourceID)
|
||||
}
|
||||
|
||||
for case let screenshot as NSManagedObject in app.storeAppScreenshots ?? []
|
||||
{
|
||||
screenshot.setAppScreenshotSourceID(sourceID)
|
||||
}
|
||||
|
||||
for case let tracks as NSManagedObject in app.storeAppReleaseTracks ?? []
|
||||
{
|
||||
tracks.setReleaseTracksSourceID(sourceID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user