-
Notifications
You must be signed in to change notification settings - Fork 464
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
Explore the use of fiddle to save ASCII plists using Xcode frameworks #199
Comments
🔥 |
👍 hell yeah it would definitely be Xmas if we could do this 🙏 |
@0xced Do you think this would be feasible without any objc method calling semantics? i.e. C function calling only? |
@alloy in theory that's always possible by using the C objc runtime functions! |
@segiddins Yeah definitely, but I guess I was wondering if it would be huge hassle, but I realise we could use the magic of Ruby to refactor some of that away. |
After 15 minutes writing a thorough explanation of why xcproj requires to be bound to the Xcode version that compiled it, I found a way to get xcproj to work with any version of Xcode. So thanks for filing this issue. 😆 The result is at 0xced/xcproj@4e26298. I’m still waiting for feedback in #196 to release a new version of xcproj by the way. Of course, this doesn’t solve the integrated behaviour inside Xcodeproj problem but it’s still nicer that the current situation. Now, to the actual issue of Xcode frameworks + fiddle to produce ASCII plist. Producing the ASCII plist from an NSDictionary is straightforward once you’ve loaded the Here is the bare minimum you’ll have to do: @interface NSDictionary (PBXPListASCIIDescription)
- (NSData *)plistDescriptionUTF8Data;
@end
void LoadDevToolsCore(NSBundle *xcodeBundle)
{
NSString *otherFrameworksPath = [[[xcodeBundle privateFrameworksPath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"OtherFrameworks"];
NSString *devToolsCorePath = [otherFrameworksPath stringByAppendingPathComponent:@"DevToolsCore.framework"];
NSBundle *devToolsCoreBundle = [NSBundle bundleWithPath:devToolsCorePath];
[devToolsCoreBundle loadAndReturnError:NULL];
}
int main(int argc, char *argv[])
{
@autoreleasepool
{
LoadDevToolsCore([NSBundle bundleWithPath:@"/Applications/Xcode.app"]);
NSDictionary *pbxprojPlist = …;
NSLog(@"%@", [[NSString alloc] initWithData:[pbxprojPlist plistDescriptionUTF8Data] encoding:NSUTF8StringEncoding]);
}
} Note that there is no error checking at all and the Xcode path is hardcoded. A production solution should be much more robust! See my solution in xcproj for loading the DevToolsCore framework. That’s just the Objectice-C starting point. Translating it to fiddle is going to be pretty ugly, something like this probably: objc_msgSend(pbxprojPlist, sel_registerName("plistDescriptionUTF8Data")) |
This should get its own
|
Loading Really, you just need to implement your own plist serialization routines. The OpenStep Plist format is pretty darn trivial to write out. The only complication is reproducing all the comments that Xcode puts in there. Which brings us to the next argument against loading the framework: It actually doesn't output what Xcode does. Take an Xcode project file and run it through the above code, and you get output that has some comments, but doesn't have all the comments it should. Notably, the above code only adds the It should certainly be possible to document all of the rules that Xcode is observed using and reproduce them. An alternative approach is instead to create a DOM model that represents the contents of a project file and maintains all existing comments, and all ordering of values in the dictionaries. If done write, this DOM can be re-serialized and produce a byte-for-byte identical output. You could then modify the nodes in the DOM as needed. The downside to this approach is any new nodes that CocoaPods adds won't have the appropriate comments or formatting, which means Xcode would presumably add in the comments/formatting the next time it saves the project file. However, any existing nodes would be preserved, and as long as Cocoapods isn't renaming the files or changing the groups they live in, the comments should not bit rot (besides Xcode, would rewrite any that do the next time it saves the project). This approach is obviously more work, but it allows Xcode to maintain control of the formatting of the project file, and is compatible with any future changes Xcode might want to make. The downside is that creating new nodes, and new project files (such as creating Pods.xcodeproj for the first time) will not be able to reproduce the correct formatting. The upside is that this approach should be less prone to creating conflicts; if all of Xcode's formatting is preserved as-is, then conflicts in that formatting cannot arise. Whereas if Cocoapods attempts to reproduce Xcode's formatting from scratch, the slightest deviation from Xcode's behavior can cause conflicts. All that said, I think something has to be done here. The other day I spent several hours manually resolving conflicts in an Xcode project file from a long-lived branch, where both the branch and mainline had modified the project file and run Also to note, I found a ton of UUIDs with values |
Please also provide actual arguments. Is this a principle issue? Is it a stability issue? (Because the idea is that code reverts back to using the public CFPropertyList API.)
You should assume that we are well aware of the costs and benefits analysis and that ‘the only complication’ is in fact the only reason why we’re “exploring” this approach, as the title states.
I don’t know which code exactly you are referring to, but the PR code doesn’t work like you state at all:
As you can see, git does not notice any changes in the project file. Opening with Xcode, making a change, and undo-ing shows the same result:
Here’s the actual fixture file so you can see for yourself that it does in fact contain all the comments.
Indeed, there are many possibilities. I’d love to see work being put into what you think is the best possible solution and being shared with us. We prefer to discuss actual implementations, however raw they might be.
I’m sorry to hear that you had to spent so much time on that. Clearly this is not as it should be. Please elaborate on your details if I got this wrong, but I read this as being an issue with your app Xcode project file being hard to merge? In that case, it might have something to do with 0.34.x introducing a regression that made it save the user's project on every To summarise, CocoaPods should never touch the user’s Xcode project, unless integration is necessary. i.e. when:
That does sounds really bad. Can you please open a new ticket that shows steps to reproduce this? I’m guessing it might be related to assigning new xcconfig files. (Although those shouldn’t be considered ‘resources’, but that might just be a red-herring.) |
@kballard Bump? |
@alloy Sorry for the delay.
If the behavior of the API changes, but the symbol still exists, then you won't know to revert to Apps on OS X have had a long history of (ab)using private frameworks. That's tolerable (though still a rather bad idea) when the private frameworks ship on the system, because system updates are infrequent and frameworks only change to fix bugs in between major releases. However, what's being proposed here is using a private framework that ships with Xcode, which means it isn't tied to the OS. It can change radically with every single Xcode update if it wants to. Which is to say, using a private Xcode framework is orders of magnitude worse than using private system frameworks.
I was referring to the sample code pasted in this comment. Glancing through the PR, it loads a handful of frameworks. I assume this is to get the objects that tell the plist formatter about the comments. This approach is not future-proof, because any objects that are added that exist in other frameworks will not be loaded. Furthermore, I'm not even convinced it works as-is today, because it's loading the
I'd love to give it a shot, but I don't have the free time to do something like that. I'm already juggling too many projects as it is.
Yes, CocoaPods rewrote that project file on every single
I have no idea how to reproduce this. I think every single project file rewrite was adding more |
As predicted, after installing Xcode 7, CocoaPods is now crashing when trying to call the private APIs in Xcode's private frameworks. See CocoaPods/CocoaPods#4151. |
We should be able to load
DVTFoundation.framework
dynamically using fiddle in Ruby which would allow us to save ASCII plists using the private API if available and Xcode is installed.This provides a couple of benefits:
Certainly not for the upcoming release. But I think in theory this could work and it would be great it we can get it to work.
/cc @alloy @0xced
The text was updated successfully, but these errors were encountered: