Skip to content

Fix WordPressData runtime issues #24494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

kean
Copy link
Contributor

@kean kean commented Apr 23, 2025

No description provided.

@kean kean added the General label Apr 23, 2025
@kean kean added this to the 25.9 milestone Apr 23, 2025
@dangermattic
Copy link
Collaborator

1 Warning
⚠️ View files have been modified, but no screenshot or video is included in the pull request. Consider adding some for clarity.

Generated by 🚫 Danger

@@ -55,7 +55,7 @@
<fetchIndexElement property="blogs" type="Binary" order="ascending"/>
</fetchIndex>
</entity>
<entity name="AccountSettings" representedClassName="ManagedAccountSettings" syncable="YES">
<entity name="AccountSettings" representedClassName=".ManagedAccountSettings" syncable="YES">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swift-only types like ManagedAccountSettings are not present in the global namespace. You have to specify the module. . means "current module".

public class ManagedAccountSettings: NSManagedObject 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean the migration from version 154 (which has an incorrect module) to 155 is broken?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this change (adding .) to all modal files?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, my mistake was not making the leap in understanding that Objective-C types are handled differently from Swift ones.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that mean the migration from version 154 (which has an incorrect module) to 155 is broken?

Maybe a unit test could clear this up? #24496

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@crazytonyli you are onto it! ☝️

In version 154, we crash upon trying to init BlogAuthor with

Could not cast value of type 'NSManagedObject_BlogAuthor_' (0x6000012d5aa0) to 'WordPressData.BlogAuthor' (0x1616aea20).
image

The solution is to apply the same representedClassName change in 154:

diff --git a/Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress 154.xcdatamodel/contents b/Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress 154.xcdatamodel/contents
index 2267cb2313..292045b17d 100644
--- a/Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress 154.xcdatamodel/contents	
+++ b/Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress 154.xcdatamodel/contents	
@@ -204,7 +204,7 @@
         </fetchIndex>
         <userInfo/>
     </entity>
-    <entity name="BlogAuthor" representedClassName="WordPress.BlogAuthor" syncable="YES">
+    <entity name="BlogAuthor" representedClassName=".BlogAuthor" syncable="YES">
         <attribute name="avatarURL" optional="YES" attributeType="String" syncable="YES"/>
         <attribute name="deletedFromBlog" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
         <attribute name="displayName" optional="YES" attributeType="String" syncable="YES"/>
image

See also CI from #24496

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed 2a17e73 in my PR that updates all the models. I used two bash commands, so I might have messed up something. Still, the test above now passes. Progress.

Copy link
Contributor Author

@kean kean Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first thing the app does is migrate from the production model (154). It never loads the represented entities in memory. It uses NSManagedObject and KVC for migration. It's impossible to retroactively change the models and there is also no need to. The app has representedClassName values in the previous models with class name that no longer even exist in the codebase – it's what the migration is for.

@@ -8,7 +8,8 @@ import WordPressKit
/// Furthermore, sites eligible for unlimited sharing will still return a `PublicizeInfo` along with its sharing
/// limitations, but the numbers should be ignored (at least for now).
///
@objc public class PublicizeInfo: NSManagedObject {
@objc(PublicizeInfo)
public class PublicizeInfo: NSManagedObject {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following annotation implicitly adds a module name to the Objective-C class name.

@objc open class PublicizeInfo

(lldb) po NSStringFromClass(PublicizeInfo.self)
"WordPressData.PublicizeInfo"

This breaks most of our code that works with entities (it uses classNameWithoutNamespaces).

The fix is to manually set the global name:

@objc(PublicizeInfo)
open class PublicizeInfo

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL.

import Foundation

@objc(ReaderTeamTopic)
open class ReaderTeamTopic: ReaderAbstractTopic {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved from Keystone.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. I was sure to have moved all the types but clearly missed this. I think the fact that it does not inherit from NSManagedObject tricked me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I greped the model and checked every representedClassName – we should be good now.

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Apr 23, 2025

App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number27489
VersionPR #24494
Bundle IDorg.wordpress.alpha
Commit43032c5
Installation URL08arvsmm9pr90
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Apr 23, 2025

App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number27489
VersionPR #24494
Bundle IDcom.jetpack.alpha
Commit43032c5
Installation URL63nc4j8m52ps8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@kean kean requested a review from mokagio April 23, 2025 17:01
Copy link
Contributor

@mokagio mokagio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legend!

@@ -55,7 +55,7 @@
<fetchIndexElement property="blogs" type="Binary" order="ascending"/>
</fetchIndex>
</entity>
<entity name="AccountSettings" representedClassName="ManagedAccountSettings" syncable="YES">
<entity name="AccountSettings" representedClassName=".ManagedAccountSettings" syncable="YES">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, my mistake was not making the leap in understanding that Objective-C types are handled differently from Swift ones.

@@ -8,7 +8,8 @@ import WordPressKit
/// Furthermore, sites eligible for unlimited sharing will still return a `PublicizeInfo` along with its sharing
/// limitations, but the numbers should be ignored (at least for now).
///
@objc public class PublicizeInfo: NSManagedObject {
@objc(PublicizeInfo)
public class PublicizeInfo: NSManagedObject {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL.

import Foundation

@objc(ReaderTeamTopic)
open class ReaderTeamTopic: ReaderAbstractTopic {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. I was sure to have moved all the types but clearly missed this. I think the fact that it does not inherit from NSManagedObject tricked me.

mokagio added a commit that referenced this pull request Apr 24, 2025
First, convert all entities to "Global Namespace" with

```
sed -i '' -E 's/representedClassName="(WordPress)?(\.)?([^"]+)"/representedClassName="\3"/g' \
  Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress\ *.xcdatamodel/contents
```

Then, set the entities that need the "Current Product Module", using
#24494 as the
source for which to pick

```
sed -i '' -E 's/representedClassName="(ManagedAccountSettings|BlogAuthor|BloggingPrompt|BloggingPromptSettings|BloggingPromptSettingsReminderDays|BlogSettings|DiffAbstractValue|DiffContentValue|DiffTitleValue|ManagedDomain|ManagedPerson|Plan|PlanFeature|PlanGroup|PublicizeConnection|PublicizeService|ReaderCard|Revision|RevisionDiff|Role)"/representedClassName=".\1"/g' \
  Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress\ *.xcdatamodel/contents
```

Notice that
`Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress 155.xcdatamodel/contents`
did not change, which is a point in favor of showing this scripted
change being correct.
@kean kean merged commit 200048d into mokagio/wordpressdata-target-xcdatamodeld-workbench-2-move-files Apr 24, 2025
32 of 34 checks passed
@kean kean deleted the task/wpdata-fdsaf branch April 24, 2025 13:44
mokagio pushed a commit that referenced this pull request May 1, 2025
* Move remaining types to WordPressData

* Use Current Module for Swift-only types

* Fix ReaderTeamTopic compilation

* Add missing class names

* Remove unused SiteInfo

* Add Bundle.wordPressData and update DataMigratorTests

* Update CoreDataMigrationTests

* Fix unit tests (AppEnvironment required)
github-merge-queue bot pushed a commit that referenced this pull request May 1, 2025
* Configure `Package.swift` with WordPressData framework deps

* Add `WordPress-Swift.h` to WordPressData to work around build fail

* Add prefix header

* Add all required sources to WordPressData

* Add required imports to Swift layer

* Extract `defaultWordPressComAccountRestAPI` method to WordPressData

Only the method, not the rest of the extension to avoid dependencies
galore.

* Add `Blog+SelfHosted` to WordPressData, including dependencies

* Hack `ContextManager.swift` to compile

* Replicate Keystone preprocessor macro hack for WordPressData-Swift.h

* Add `Media+Blog.swift` to WordPressData to compile `PostHelper.m`

* Add `RemotePost+Metadata` source to WordPressData for `PostHelper.m`

* Add `PostServiceRemoteFactory` to WordPressData to fix `PostService.m`

* Add `PostHelper+JetpackSocial` to WordPressData to fix `PostHelper.m`

* Add `WordPressOrgRestApi+WordPress` to WordPressData

Made possible by
#24351

* Add `.m` file in WordPressData only to config CocoaLumberJack

* Add some `import CocoaLumberJackSwift` required by WordPressData

* Use `_private_wordPressComRestApi` in `Blog+WordPressComRestAPI.swift` to build WordPressData

* Add CocoaLumberjack as a dependency to the extensions to fix compilation

Otherwise, we'd get:

```
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_DDLog", referenced from:
       in AppExtensionsService.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

* Remove `WordPress-Swift.h` hack from WordPressData

* Add `Blog+Lookup` to WordPressData

* Add `WordPress.xcdatamodeld` to WordPressData

* Duplicate test infra in WordPressData in order to run `BlogTests`

* Remove unnecessary `CocoaLumberJackConfiguration.h` header

We don't need the header, the implementation file is enough for the
CocoaLumberJack shenanigans to take place.

* Remove WordPressData types from WordPress and Jetpack

Not Keystone yet because I don't know if that compiles okay to verify
the change.

* Update imports after removing WordPressData files from WP and Jetpack

* Disambiguate `Notification` usages — `/: Notification\)/`

* Disambiguate `Notification` usages — `/: Notification$/`

* Disambiguate `Notification` usages — `/, Notification(?!s)/`

* Disambiguate `Notification` usages — `/as\? Notification/`

* Disambiguate `Notification` usages — `/ Notification \{/`

* Disambiguate `Notification` usages — `/ Notification\?/`

* Disambiguate `Notification` usages — `/ Notification,$/`

* Disambiguate `Notification` usages — `/\[Notification\]/`

* Disambiguate `Notification` usages — `/ Notification\:/`

* Disambiguate `Notification` usages — `/: Notification,/`

* Disambiguate `Notification` usages — `/\(Notification\)/`

* Disambiguate `Notification` usages — `/Notification else/`

* Disambiguate `Notification` usages — `/Notification\!/`

* Disambiguate `Notification` usages — `/as\? Notification/`

* Add CocoaLumberjack to notification service extensions

* Update imports after `Notification` disambiguation

* Replace all `#import` of headers now in WordPressData with `@import WordPressData`

* Work around (temporarily?!) a build failure after the WordPressData move

* Remove unused `AccountService` import from `Blog.m`

It matters because once `Blog` is in WordPressData, `AccountService`
will no longer be available.

* Move some `MenuItem` imports from `.h` to `.m`

`MenuItem` was not used in the interface. Moving the import in the
implementation will make it cleaner to update once WordPressData is
integrated.

* Remove WordPressData types from `WordPress-Bridging-Header.h`

* Address module verifier warnings in WordPressData

* Extract Swift-dependant logic from `Theme`

* Make `Media` extension `public`

* Remove unused WordPressData import from NotificationServiceExtension

* Add CocoaLumberjack to extensions Jetpack uses to avoid compile failure

Undefined symbol: _OBJC_CLASS_$_DDLog

* Make WordPressData Swift API available to ObjC framework consumers

* Add `testable import WordPressData` to unit tests

* Update `WordPress.Notification` to `WordPressData.Notification` in tests

* Add more required `@testable import WordPressData`

Via

```
find WordPress/WordPressTest \
  -name "*.swift" \
  -type f \
  -exec perl -i -0pe 's/(@testable import WordPress\n)(\nclass (\w+): CoreDataTestCase \{)/\1\@testable import WordPressData\n\nclass \3: CoreDataTestCase {/g' \
  {} \;
```

and

```
find WordPress/WordPressTest \
  -name "*.swift" \
  -type f \
  -exec perl -i -0pe 's/(@testable import WordPress\n)(\nfinal class (\w+): CoreDataTestCase \{)/\1\@testable import WordPressData\n\nfinal class \3: CoreDataTestCase {/g' \
  {} \;
```

* Add WordPressData as a WordPressTests dependency

* Add missing dependencies to WordPressTesting post WordPressData addition

* Load model from the `ContextManager` bundle in the unit tests

* Replace `AppEnvironment` with `WordPressComRestApi.apiBaseURL` in RestAPI

Same rationale as 09990b8

* No longer access `_private_wordPressComRestApi` in `Blog`

* Fix WordPressData linkage in Keystone and move sources

* Update access of types required by Keystone for WordPressData link

* Explicitly add WebKit as a Keystone dependency

Triggered by a few errors like

```
In file included from /Users/gio/Developer/a8c/wpios/WordPress/Classes/ViewRelated/Suggestions/SuggestionsTableViewCell.m:3:
/Users/gio/Developer/a8c/wpios/DerivedData/WordPress/Build/Intermediates.noindex/WordPress.build/Debug-iphonesimulator/Keystone.build/DerivedSources/Keystone-Swift.h:295:9: fatal error: module 'WebKit' not found
  295 | @import WebKit;
      |  ~~~~~~~^~~~~~
```

which I got after linking WordPressData against Keystone and moving all
the sources there.

* Revert `CookieJar` `public` access level

Apparently unnecessary, see
#24420 (comment)

* REVERT ME - Only run WordPress tests

* Switch all models to use "Global Namespace"

Via

```
sed -i '' -E 's/representedClassName="(WordPress)?(\.)?([^"]+)"/representedClassName=".\3"/g' \
  Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress\ 155.xcdatamodel/contents
```

which switched to "Current Product Module" but resulted in unit tests
failure in WordPressData, followed by

```
➜ sed -i '' -E 's/representedClassName="\.([^"]+)"/representedClassName="\1"/g' \
  Sources/WordPressData/Resources/WordPress.xcdatamodeld/WordPress\ 155.xcdatamodel/contents
```

* Replace all string values passed to `forEntityName` with `entityName()`

Done via

```
find . \
  \( -path './DerivedData' -o -path './.git' -o -path './vendor' \) \
  -prune -o -type f -name "*.swift" \
  -exec sed -i '' -E 's/forEntityName: "([A-Za-z_][A-Za-z0-9_]*)"/forEntityName: \1.entityName()/g' {} +
```

* Replace all `NSStringFromClass` values passed to `forEntityName`

Done via

```
find . \
  \( -path './DerivedData' -o -path './.git' -o -path './vendor' \) \
  -prune -o -type f -name "*.swift" \
  -exec sed -i '' -E 's/forEntityName: NSStringFromClass\(([A-Za-z_][A-Za-z0-9_]*)\.self\)/forEntityName: \1.entityName()/g' {} +
```

The goal is to have a single way to get the entity name so we can adapt
it to the new WordPressData setup in one go.

* Replace all `Self.classNameWithoutNamespaces()` with `entityName()`

The goal is to have a single way to get the entity name so we can adapt
it to the new WordPressData setup in one go.

* Replace all `classNameWithoutNamespace()` calls with `entityName()`

Done via

```
find . \( -path './DerivedData' -o -path './.git' -o -path './vendor' \) \
  -prune -o -type f -name "*.swift" \
  -exec sed -i '' -E 's/forEntityName: ([A-Za-z_][A-Za-z0-9_]*)\.classNameWithoutNamespaces\(\)/forEntityName: \1.entityName()/g' {} +
```

The goal is to have a single way to get the entity name so we can adapt
it to the new WordPressData setup in one go.

* Fix WordPressData runtime issues (#24494)

* Move remaining types to WordPressData

* Use Current Module for Swift-only types

* Fix ReaderTeamTopic compilation

* Add missing class names

* Remove unused SiteInfo

* Add Bundle.wordPressData and update DataMigratorTests

* Update CoreDataMigrationTests

* Fix unit tests (AppEnvironment required)

* Add `BlobEntity` to WordPressData

* Address straightforward `FIXME` notes

---------

Co-authored-by: Alex Grebenyuk <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants