Skip to content

Commit b0b067e

Browse files
committed
cleaned up.. virtually ready for submission
1 parent 4d1d01d commit b0b067e

File tree

6 files changed

+116
-105
lines changed

6 files changed

+116
-105
lines changed

DVTCompatibilitizer.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
@import Foundation;
3+
@import CoreServices;
34

45
@interface DVTCompatibilitizer : NSObject
56

@@ -11,3 +12,11 @@
1112
+ (void) watchAndFixPluginsAsNeeded;
1213

1314
@end
15+
16+
#define kCompatibilityUUIDKey @"DVTPlugInCompatibilityUUID"
17+
#define kCompatibilityUUIDsKey kCompatibilityUUIDKey @"s"
18+
#define kInfoPlistComponent @"Contents/Info.plist"
19+
#define FM NSFileManager.defaultManager
20+
21+
#define kPluginsDirectoryPath @"~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/"
22+
#define kXcodePluginSuffix @".xcplugin"

DVTCompatibilitizer.m

Lines changed: 78 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,67 @@
11

2-
@import CoreServices;
3-
42
#import "DVTCompatibilitizer.h"
53

6-
#define kCompatibilityUUIDKey @"DVTPlugInCompatibilityUUID"
7-
#define kCompatibilityUUIDsKey kCompatibilityUUIDKey @"s"
8-
#define kInfoPlistComponent @"Contents/Info.plist"
9-
#define FM NSFileManager.defaultManager
4+
@implementation DVTCompatibilitizer
105

11-
#define kPluginsDirectoryPath @"~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/"
12-
#define kXcodePluginSuffix @".xcplugin"
6+
+ (void) watchAndFixPluginsAsNeeded {
137

14-
//#define NSLog(...) (void)fprintf(stderr,"%s\n",[NSString stringWithFormat:__VA_ARGS__,nil].UTF8String)
8+
NSArray * pathsToWatch = [self.installedXcodes arrayByAddingObjectsFromArray:@[self.pluginsDirectoryPath]];
159

16-
@implementation DVTCompatibilitizer
10+
CFAbsoluteTime latency = 10.;
11+
FSEventStreamContext *callbackInfo = NULL;
12+
FSEventStreamRef stream = FSEventStreamCreate(NULL, &_mycallback, callbackInfo,
13+
(__bridge CFArrayRef)pathsToWatch,
14+
kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
15+
latency,
16+
kFSEventStreamCreateFlagNone); /* Flags explained in reference */
1717

18-
#pragma mark - Utility
18+
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
19+
FSEventStreamStart(stream);
20+
CFRunLoopRun();
21+
}
1922

20-
static NSArray * xcodes = nil,
21-
* uuids = nil,
22-
* plugs = nil;
23-
static NSString * plugPath = nil;
23+
+ (void) fixPlugins {
2424

25+
NSMutableArray *fixed = @[].mutableCopy;
2526

26-
+ (BOOL) _keysAreOK: (NSArray*) testing {
27+
for (id x in self.installedPlugins) {
2728

28-
return ![self.allCompatibilityUUIDs filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
29-
return ![testing containsObject:evaluatedObject];
30-
}]].count && [NSSet setWithArray:testing].allObjects.count == testing.count;
31-
}
29+
id plpath = [[self.pluginsDirectoryPath stringByAppendingPathComponent:x] stringByAppendingPathComponent:kInfoPlistComponent];
3230

33-
+ (NSString*) _cuuidsForXcode:(NSString*)path {
31+
if (![FM fileExistsAtPath:plpath]) {
3432

35-
NSString *info = [path stringByAppendingPathComponent:kInfoPlistComponent];
36-
return [NSDictionary dictionaryWithContentsOfFile:info][kCompatibilityUUIDKey];
33+
NSLog(@"WARNING: Skipped %@, as it was missing.", plpath);
34+
continue;
35+
}
36+
37+
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithContentsOfFile:plpath];
38+
39+
id a = d[kCompatibilityUUIDsKey];
40+
41+
if (a && [a count] && [self _keysAreOK:a]) {
42+
43+
NSLog(@"NOT fixing: %@... It's already ok!", x);
44+
continue;
45+
}
46+
47+
a = a ? [a mutableCopy] : @[].mutableCopy;
48+
49+
[a addObjectsFromArray:self.allCompatibilityUUIDs];
50+
51+
d[kCompatibilityUUIDsKey] = [NSSet setWithArray:a].allObjects;
52+
53+
BOOL ok = [d writeToFile:plpath atomically:YES];
54+
55+
ok ? [fixed addObject:[x stringByDeletingPathExtension]] : nil;
56+
57+
NSLog(@"%@: %@", ok ? @"FIXED" : @"FAILED TO FIX", x);
58+
}
59+
[self _notify: fixed.count ? [fixed componentsJoinedByString:@" "] : @"All Plugins OK"];
3760
}
3861

39-
#pragma mark - public
62+
#pragma mark - Static Info Fetchers
4063

41-
+ (NSArray*) installedPlugins {
64+
+ (NSArray*) installedPlugins { static NSArray * plugs;
4265

4366
return plugs = plugs ?: ({
4467
NSError* error = nil;
@@ -50,7 +73,7 @@ + (NSArray*) installedPlugins {
5073
});
5174
}
5275

53-
+ (NSArray*) allCompatibilityUUIDs {
76+
+ (NSArray*) allCompatibilityUUIDs { static NSArray * uuids;
5477

5578
return uuids = uuids ?: ({
5679
NSMutableArray *pot = @[].mutableCopy;
@@ -62,56 +85,52 @@ + (NSArray*) allCompatibilityUUIDs {
6285
});
6386
}
6487

65-
+ (NSArray *) installedXcodes {
88+
+ (NSArray*) installedXcodes { static NSArray * xcodes;
6689

6790
return xcodes = xcodes ?: ({
6891
CFArrayRef result = LSCopyApplicationURLsForBundleIdentifier(CFSTR("com.apple.dt.Xcode"), nil);
6992
!result ? nil : [(__bridge NSArray*) result valueForKeyPath:@"path"];
7093
});
7194
}
7295

73-
+ (void) fixPlugins {
96+
+ (NSString*) pluginsDirectoryPath { static NSString * plugPath;
7497

75-
NSMutableArray *fixed = @[].mutableCopy;
98+
return plugPath = plugPath ?: [NSURL fileURLWithPath:kPluginsDirectoryPath.stringByStandardizingPath.stringByResolvingSymlinksInPath.stringByExpandingTildeInPath isDirectory:YES].path;
99+
}
76100

77-
for (id x in self.installedPlugins) {
101+
#pragma mark - Utility
78102

79-
id plpath = [[self.pluginsDirectoryPath stringByAppendingPathComponent:x] stringByAppendingPathComponent:kInfoPlistComponent];
80-
if (![FM fileExistsAtPath:plpath]) {
81-
NSLog(@"WARNING: Skipped %@, as it was missing.", plpath);
82-
continue;
83-
}
103+
+ (void) _notify:(NSString*) reason { // Posts notifications on our behalf!
84104

85-
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithContentsOfFile:plpath];
86-
id a = d[kCompatibilityUUIDsKey];
105+
id notifier = [[[NSBundle bundleForClass:self]
106+
pathForAuxiliaryExecutable:@"DVTCompatibilitizer.notfier.app"]
107+
stringByAppendingPathComponent:@"Contents/MacOS/applet"];
87108

88-
if (a && [a count] && [self _keysAreOK:a]) {
89-
NSLog(@"NOT fixing: %@... It's already ok!", x);
90-
continue;
91-
}
92-
a = a ? [a mutableCopy] : @[].mutableCopy;
93-
[a addObjectsFromArray:self.allCompatibilityUUIDs];
94-
d[kCompatibilityUUIDsKey] = [NSSet setWithArray:a].allObjects;
95-
BOOL ok = [d writeToFile:plpath atomically:YES];
96-
ok ? [fixed addObject:[x stringByDeletingPathExtension]] : nil;
97-
NSLog(@"%@: %@", ok ? @"FIXED" : @"FAILED TO FIX", x);
98-
}
99-
[self _notify: fixed.count ? [fixed componentsJoinedByString:@" "] : @"All Plugins OK"];
109+
system([[NSString stringWithFormat:@"title=\"%@\" message=\"%@\" \"%@\"", NSStringFromClass(self),
110+
reason ?: @"DVTCompatibilitized!",
111+
notifier] UTF8String]);
100112
}
101113

102-
+ (NSString*) pluginsDirectoryPath
103-
{
104-
return plugPath = plugPath ?: [NSURL fileURLWithPath:kPluginsDirectoryPath.stringByStandardizingPath.stringByResolvingSymlinksInPath.stringByExpandingTildeInPath isDirectory:YES].path;
114+
+ (BOOL) _keysAreOK: (NSArray*) testing {
115+
116+
return ![self.allCompatibilityUUIDs filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
117+
return ![testing containsObject:evaluatedObject];
118+
}]].count && [NSSet setWithArray:testing].allObjects.count == testing.count;
119+
}
120+
121+
+ (NSString*) _cuuidsForXcode:(NSString*)path {
122+
123+
NSString *info = [path stringByAppendingPathComponent:kInfoPlistComponent];
124+
return [NSDictionary dictionaryWithContentsOfFile:info][kCompatibilityUUIDKey];
105125
}
106126

107-
void mycallback(
108-
ConstFSEventStreamRef streamRef,
109-
void *clientCallBackInfo,
110-
size_t numEvents,
111-
void *eventPaths,
127+
void _mycallback(
128+
ConstFSEventStreamRef streamRef,
129+
void * clientCallBackInfo,
130+
size_t numEvents,
131+
void * eventPaths,
112132
const FSEventStreamEventFlags eventFlags[],
113-
const FSEventStreamEventId eventIds[])
114-
{
133+
const FSEventStreamEventId eventIds[]) {
115134

116135
NSLog(@"Fixing plugins due to some change!\n");
117136
BOOL needsFix = YES;
@@ -125,41 +144,4 @@ void mycallback(
125144
needsFix ? [DVTCompatibilitizer fixPlugins] : nil;
126145
}
127146

128-
+ (void) _notify:(NSString*) reason {
129-
130-
131-
132-
id notifier = [[[NSBundle bundleForClass:self] pathForAuxiliaryExecutable:@"DVTCompatibilitizer.notfier.app"] stringByAppendingPathComponent:@"Contents/MacOS/applet"];
133-
id title = NSStringFromClass(self);
134-
id r = reason ?: @"DVTCompatibilitized!";
135-
id cmd = [NSString stringWithFormat:@"title=\"%@\" message=\"%@\" \"%@\"", title, r, notifier];
136-
NSLog(@"running: %@", cmd);
137-
system([cmd UTF8String]);
138-
// NSUserNotification *notification = NSUserNotification.new;
139-
// notification.title = NSStringFromClass(self);
140-
// notification.informativeText = r;
141-
// notification.soundName = @"Sosumi";
142-
// [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification];
143-
}
144-
145-
+ (void) watchAndFixPluginsAsNeeded {
146-
147-
NSArray *paths = [self.installedXcodes arrayByAddingObjectsFromArray:@[self.pluginsDirectoryPath]];
148-
149-
// CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&mypath, 1, NULL);
150-
FSEventStreamContext *callbackInfo = NULL;
151-
152-
CFAbsoluteTime latency = 10.;
153-
FSEventStreamRef stream = FSEventStreamCreate(NULL, &mycallback, callbackInfo,
154-
(__bridge CFArrayRef)paths,
155-
kFSEventStreamEventIdSinceNow, /* Or a previous event ID */
156-
latency,
157-
kFSEventStreamCreateFlagNone); /* Flags explained in reference */
158-
159-
FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
160-
FSEventStreamStart(stream);
161-
CFRunLoopRun();
162-
}
163-
164147
@end
165-

DVTPlugInCompatibilityUUIDifier.xcodeproj/project.pbxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
7B6A680F1BE046D80023C7D8 /* NSFileManger+Privileged.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSFileManger+Privileged.m"; sourceTree = "<group>"; };
6868
7B6A68101BE046D80023C7D8 /* NSString+ah_versionCompare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+ah_versionCompare.h"; sourceTree = "<group>"; };
6969
7B6A68111BE046D80023C7D8 /* NSString+ah_versionCompare.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+ah_versionCompare.m"; sourceTree = "<group>"; };
70+
7B89A34A1C1F1AB0000ADD8D /* scratch */ = {isa = PBXFileReference; lastKnownFileType = text; path = scratch; sourceTree = "<group>"; };
7071
7B91FE901BE023E200F3BF55 /* DVTCompatibilitizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DVTCompatibilitizer.h; sourceTree = "<group>"; };
7172
7B91FE911BE023E200F3BF55 /* DVTCompatibilitizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DVTCompatibilitizer.m; sourceTree = "<group>"; };
7273
7B953EEE1BE00F0500EB7F15 /* DVTPlugInCompatibilityUUIDifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DVTPlugInCompatibilityUUIDifier.m; sourceTree = "<group>"; };
@@ -80,6 +81,7 @@
8081
children = (
8182
7B91FE901BE023E200F3BF55 /* DVTCompatibilitizer.h */,
8283
7B91FE911BE023E200F3BF55 /* DVTCompatibilitizer.m */,
84+
7B89A34A1C1F1AB0000ADD8D /* scratch */,
8385
7B953EEE1BE00F0500EB7F15 /* DVTPlugInCompatibilityUUIDifier.m */,
8486
7B6A67C41BE02C980023C7D8 /* DVTPlugInCompatibilityWatchdog.m */,
8587
7B2153381BE0BE2B00BDE9AE /* Support */,

DVTPlugInCompatibilityUUIDifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33

44
![Sreneity Now](https://github.com/mralexgray/DVTPlugInCompatibilityUUIDifier/raw/master/Screenshots/alcatraz.art.png)
55

6-
## _Permanent, automatic, and hassle-free_ Xcode upgrades.
6+
## _Permanent, automatic, and hassle-free_ `Xcode`/`Alcatraz` "compatibility" upgrades.
77

8-
- [x] Are you *sick and tired* of thinking about / dealing with Alcatraz / all your Xcode plugins breaking with each Xcode release?
8+
- [x] Are you *sick and tired* of thinking about / dealing with `Alcatraz` / all your `Xcode` plugins breaking with each `Xcode` release?
99

10-
- [x] Have you tried those other hacks, and still you can't keep up with all the compatibility UUID's?
10+
- [x] Have you tried those other hacks, and still you can't keep up with all the compatibility UUID's, aka `DVTPlugInCompatibilityUUIDs`?
1111

12-
- [x] Does the fact that Alcatraz doesn't do this automcatically make you want to jump off a cliff?
12+
- [x] Does the fact that `Alcatraz` doesn't do this automcatically make you want to _jump off a cliff_?
1313

1414
### Stop the insanity!!
1515

16-
Through the magic of science, the ever-incompatible [`Alcatraz`](http://alcatraz.io) (and all it's little friends) will now "magically" BE compatible. Wow. Imagine. If something doesn't work, don't cry! *Just delete the offending plugin-in* from ``~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/` and move on! You can always just install it later (now that you can depend on ALcatraz being around!)
16+
Through the _magic of science_, the _ever-incompatible_ [`Alcatraz`](http://alcatraz.io) (and all it's little friends) will now "magically" BE compatible. Wow. Imagine. If something doesn't work, don't cry! *Just delete the offending plugin-in* from
17+
18+
~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/
19+
20+
and move on! You can _always just install it later_ (now that you CAN depend on ALcatraz being available, via this plugin!)
1721

1822
### Mo' Xcode's.. Mo' Problems..
1923

@@ -29,7 +33,6 @@ Through the magic of science, the ever-incompatible [`Alcatraz`](http://alcatraz
2933

3034
**Behold**
3135

32-
3336
![Screenshot](https://github.com/mralexgray/DVTPlugInCompatibilityUUIDifier/raw/master/Screenshots/notification.png "Notifications!")
3437

3538
## Installation
@@ -38,11 +41,26 @@ Simply build this Xcode project once and restart Xcode. You can delete the proje
3841

3942
If you get a "Permission Denied" error while building, please see [this issue](https://github.com/omz/ColorSense-for-Xcode/issues/1) of the great [ColorSense plugin](https://github.com/omz/ColorSense-for-Xcode/).
4043

44+
The plugin automatically registers a LaunchAgent with `launchd`, which keeps
45+
46+
~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/DVTPlugInCompatibilityUUIDifier.xcplugin/Contents/MacOS/DVTPlugInCompatibilityWatchdog
47+
48+
running for you, unassisted! `DVTPlugInCompatibilityWatchdog` is the little macgic helper that makes sure you can ALWAYS be up and running with ALL your plugins/Alcatraz, no matter what!
49+
50+
![Screenshot](https://github.com/mralexgray/DVTPlugInCompatibilityUUIDifier/raw/master/Screenshots/xcode.hates.you.png "WAAAA. No cooties!")
51+
52+
**Make sure to always <kbd>Load Bundles</kbd> when prompted by _prissy/cooties-averse/xenophobic_ `Xcode`.**
4153

4254
## Uninstall
4355

44-
In Xcode, go to *Plugins > JDPluginManager > Uninstall* and restart Xcode afterwards.
56+
Either manually delete
57+
58+
~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/DVTPlugInCompatibilityUUIDifier.xcplugin
59+
60+
or use the great [JDPluginManager](https://github.com/jaydee3/JDPluginManager), and within `Xcode`, just go to <kbd>Plugins</kbd> `>` <kbd>DVTPlugInCompatibilityUUIDifier</kbd> `>` <kbd>Uninstall</kbd>
61+
62+
and restart `Xcode`.
4563

4664
## Twitter
4765

48-
I'm [@jaydee3](http://twitter.com/jaydee3) on Twitter. Please [tweet](https://twitter.com/intent/tweet?button_hashtag=JDPluginManager&text=This%20plugin%20manages%20Xcode%20plugins!%20Easy%20installing%20and%20uninstalling%20for%20plugins!%20https%3A%2F%2Fgithub.com%2Fjaydee3%2FJDPluginManager&via=jaydee3) about the plugin.
66+
I'm [@mralexgray](http://twitter.com/mralexgray) on Twitter. Please [tweet](https://twitter.com/intent/tweet?button_hashtag=DVTPlugInCompatibilityUUIDifier&text=Permanent%2C+automatic%2C+and+hassle-free+Xcode%2FAlcatraz+upgrades.%20http%3A%2F%2Flinks.mrgray.com%2FMoPluginsMoProblems&via=mralexgray) about the plugin.

Screenshots/xcode.hates.you.png

35.4 KB
Loading

0 commit comments

Comments
 (0)