parent
f79ae77a3a
commit
878d1561aa
@ -1,28 +0,0 @@
|
|||||||
Code reused from duplicati, licensed under LGPL 2.1
|
|
||||||
Modified for Sonarr by Taloth Saldono
|
|
||||||
|
|
||||||
see here for the original source: https://github.com/duplicati/duplicati/tree/679981d29f8a6e445d3c1e6d41e72a673ffaa653/Installer/OSX
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
|
|
||||||
Sonarr as a whole is licensed under GPL 3.0 as specified in the git repository root.
|
|
||||||
|
|
||||||
But to preserve the original intent of the duplicati project, the modified versions of the sources in this folder are dual licensed under LGPL 2.1 and GPL 3.0.
|
|
||||||
Note: This exception can be freely removed in any copy of Sonarr sources as per LGPL/GPL licensing terms.
|
|
||||||
|
|
||||||
A copy of the LGPL 2.1 license is included in the LICENSE.LGPL.md file.
|
|
||||||
|
|
||||||
Purpose
|
|
||||||
-------
|
|
||||||
|
|
||||||
The Launcher is a bootstrap/shim application that checks if the appropriate version of mono is installed and subsequently use it to execute Sonarr.
|
|
||||||
By using a separate application, instead of a shell script, this allows the user to assign certain operating system permissions to Sonarr specifically.
|
|
||||||
|
|
||||||
Compiling the Launcher
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
You need an OSX installation with xcode
|
|
||||||
Then run compile.sh in a terminal
|
|
||||||
|
|
||||||
The generated dist/Launcher can be renamed to Sonarr and Sonarr.Update to serve as shims to run Sonarr.exe and Sonarr.Update.exe respectively.
|
|
Binary file not shown.
@ -1,32 +0,0 @@
|
|||||||
#import "run-with-mono.h"
|
|
||||||
#import "PFMoveApplication.h"
|
|
||||||
|
|
||||||
int const MONO_VERSION_MAJOR = 5;
|
|
||||||
int const MONO_VERSION_MINOR = 20;
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
@autoreleasepool {
|
|
||||||
// Use our own executable name so the same compiled binary to be used for forks
|
|
||||||
NSString * const FileName = NSProcessInfo.processInfo.arguments[0].lastPathComponent;
|
|
||||||
|
|
||||||
// Sonarr.Update.exe
|
|
||||||
NSString * const ASSEMBLY = [NSString stringWithFormat:@"%@.exe", FileName];
|
|
||||||
|
|
||||||
// Sonarr Update
|
|
||||||
NSString * const APP_NAME = [FileName stringByReplacingOccurrencesOfString:@"." withString:@" "];
|
|
||||||
|
|
||||||
// -sonarrupdate
|
|
||||||
NSString * const PROCESS_NAME = [NSString stringWithFormat:@"-%@", [FileName stringByReplacingOccurrencesOfString:@"." withString:@""].lowercaseString];
|
|
||||||
|
|
||||||
@try
|
|
||||||
{
|
|
||||||
PFMoveToApplicationsFolderIfNecessary();
|
|
||||||
}
|
|
||||||
@catch (NSException * ex)
|
|
||||||
{
|
|
||||||
NSLog(@"Translocation/Quarantine check failed, starting normally. Reason: %@", ex.reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [RunWithMono runAssemblyWithMono:APP_NAME procnamesuffix:PROCESS_NAME assembly:ASSEMBLY major:MONO_VERSION_MAJOR minor:MONO_VERSION_MINOR];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
//
|
|
||||||
// PFMoveApplication.h, version 1.24
|
|
||||||
// LetsMove
|
|
||||||
//
|
|
||||||
// Created by Andy Kim at Potion Factory LLC on 9/17/09
|
|
||||||
//
|
|
||||||
// The contents of this file are dedicated to the public domain.
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
Moves the running application to ~/Applications or /Applications if the former does not exist.
|
|
||||||
After the move, it relaunches app from the new location.
|
|
||||||
DOES NOT work for sandboxed applications.
|
|
||||||
|
|
||||||
Call from \c NSApplication's delegate method \c -applicationWillFinishLaunching: method. */
|
|
||||||
void PFMoveToApplicationsFolderIfNecessary(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check whether an app move is currently in progress.
|
|
||||||
Returns YES if LetsMove is currently in-progress trying to move the app to the Applications folder, or NO otherwise.
|
|
||||||
This can be used to work around a crash with apps that terminate after last window is closed.
|
|
||||||
See https://github.com/potionfactory/LetsMove/issues/64 for details. */
|
|
||||||
BOOL PFMoveIsInProgress(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -1,565 +0,0 @@
|
|||||||
//
|
|
||||||
// PFMoveApplication.m, version 1.24
|
|
||||||
// LetsMove
|
|
||||||
//
|
|
||||||
// Created by Andy Kim at Potion Factory LLC on 9/17/09
|
|
||||||
//
|
|
||||||
// The contents of this file are dedicated to the public domain.
|
|
||||||
|
|
||||||
#import "PFMoveApplication.h"
|
|
||||||
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
#import <Security/Security.h>
|
|
||||||
#import <dlfcn.h>
|
|
||||||
#import <sys/mount.h>
|
|
||||||
|
|
||||||
@interface LetsMove : NSObject
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation LetsMove
|
|
||||||
+ (NSBundle *)bundle {
|
|
||||||
return [NSBundle bundleForClass:self];
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
// Strings
|
|
||||||
// These are macros to be able to use custom i18n tools
|
|
||||||
#define _I10NS(nsstr) NSLocalizedStringFromTableInBundle(nsstr, @"MoveApplication", [LetsMove bundle], nil)
|
|
||||||
#define kStrMoveApplicationCouldNotMove _I10NS(@"Could not move to Applications folder")
|
|
||||||
#define kStrMoveApplicationQuestionTitle _I10NS(@"Move to Applications folder?")
|
|
||||||
#define kStrMoveApplicationQuestionTitleHome _I10NS(@"Move to Applications folder in your Home folder?")
|
|
||||||
#define kStrMoveApplicationQuestionMessage _I10NS(@"I can move myself to the Applications folder if you'd like.")
|
|
||||||
#define kStrMoveApplicationButtonMove _I10NS(@"Move to Applications Folder")
|
|
||||||
#define kStrMoveApplicationButtonDoNotMove _I10NS(@"Do Not Move")
|
|
||||||
#define kStrMoveApplicationQuestionInfoWillRequirePasswd _I10NS(@"Note that this will require an administrator password.")
|
|
||||||
#define kStrMoveApplicationQuestionInfoInDownloadsFolder _I10NS(@"This will keep your Downloads folder uncluttered.")
|
|
||||||
|
|
||||||
// Needs to be defined for compiling under 10.5 SDK
|
|
||||||
#ifndef NSAppKitVersionNumber10_5
|
|
||||||
#define NSAppKitVersionNumber10_5 949
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// By default, we use a small control/font for the suppression button.
|
|
||||||
// If you prefer to use the system default (to match your other alerts),
|
|
||||||
// set this to 0.
|
|
||||||
#define PFUseSmallAlertSuppressCheckbox 1
|
|
||||||
|
|
||||||
|
|
||||||
static NSString *AlertSuppressKey = @"moveToApplicationsFolderAlertSuppress";
|
|
||||||
static BOOL MoveInProgress = NO;
|
|
||||||
|
|
||||||
// Helper functions
|
|
||||||
static NSString *PreferredInstallLocation(BOOL *isUserDirectory);
|
|
||||||
static BOOL IsInApplicationsFolder(NSString *path);
|
|
||||||
static BOOL IsInDownloadsFolder(NSString *path);
|
|
||||||
static BOOL IsApplicationAtPathRunning(NSString *path);
|
|
||||||
static BOOL IsApplicationAtPathNested(NSString *path);
|
|
||||||
static NSString *ContainingDiskImageDevice(NSString *path);
|
|
||||||
static BOOL Trash(NSString *path);
|
|
||||||
static BOOL DeleteOrTrash(NSString *path);
|
|
||||||
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled);
|
|
||||||
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath);
|
|
||||||
static NSString *ShellQuotedString(NSString *string);
|
|
||||||
static void Relaunch(NSString *destinationPath);
|
|
||||||
|
|
||||||
// Main worker function
|
|
||||||
void PFMoveToApplicationsFolderIfNecessary(void) {
|
|
||||||
|
|
||||||
// Make sure to do our work on the main thread.
|
|
||||||
// Apparently Electron apps need this for things to work properly.
|
|
||||||
if (![NSThread isMainThread]) {
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
|
||||||
PFMoveToApplicationsFolderIfNecessary();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if user suppressed the alert before
|
|
||||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return;
|
|
||||||
|
|
||||||
// Path of the bundle
|
|
||||||
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
|
|
||||||
|
|
||||||
// Check if the bundle is embedded in another application
|
|
||||||
BOOL isNestedApplication = IsApplicationAtPathNested(bundlePath);
|
|
||||||
|
|
||||||
// Skip if the application is already in some Applications folder,
|
|
||||||
// unless it's inside another app's bundle.
|
|
||||||
if (IsInApplicationsFolder(bundlePath) && !isNestedApplication) return;
|
|
||||||
|
|
||||||
// OK, looks like we'll need to do a move - set the status variable appropriately
|
|
||||||
MoveInProgress = YES;
|
|
||||||
|
|
||||||
// File Manager
|
|
||||||
NSFileManager *fm = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
// Are we on a disk image?
|
|
||||||
NSString *diskImageDevice = ContainingDiskImageDevice(bundlePath);
|
|
||||||
|
|
||||||
// Since we are good to go, get the preferred installation directory.
|
|
||||||
BOOL installToUserApplications = NO;
|
|
||||||
NSString *applicationsDirectory = PreferredInstallLocation(&installToUserApplications);
|
|
||||||
NSString *bundleName = [bundlePath lastPathComponent];
|
|
||||||
NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName];
|
|
||||||
|
|
||||||
// Check if we need admin password to write to the Applications directory
|
|
||||||
BOOL needAuthorization = ([fm isWritableFileAtPath:applicationsDirectory] == NO);
|
|
||||||
|
|
||||||
// Check if the destination bundle is already there but not writable
|
|
||||||
needAuthorization |= ([fm fileExistsAtPath:destinationPath] && ![fm isWritableFileAtPath:destinationPath]);
|
|
||||||
|
|
||||||
// Setup the alert
|
|
||||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
|
||||||
{
|
|
||||||
NSString *informativeText = nil;
|
|
||||||
|
|
||||||
[alert setMessageText:(installToUserApplications ? kStrMoveApplicationQuestionTitleHome : kStrMoveApplicationQuestionTitle)];
|
|
||||||
|
|
||||||
informativeText = kStrMoveApplicationQuestionMessage;
|
|
||||||
|
|
||||||
if (needAuthorization) {
|
|
||||||
informativeText = [informativeText stringByAppendingString:@" "];
|
|
||||||
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoWillRequirePasswd];
|
|
||||||
}
|
|
||||||
else if (IsInDownloadsFolder(bundlePath)) {
|
|
||||||
// Don't mention this stuff if we need authentication. The informative text is long enough as it is in that case.
|
|
||||||
informativeText = [informativeText stringByAppendingString:@" "];
|
|
||||||
informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoInDownloadsFolder];
|
|
||||||
}
|
|
||||||
|
|
||||||
[alert setInformativeText:informativeText];
|
|
||||||
|
|
||||||
// Add accept button
|
|
||||||
[alert addButtonWithTitle:kStrMoveApplicationButtonMove];
|
|
||||||
|
|
||||||
// Add deny button
|
|
||||||
NSButton *cancelButton = [alert addButtonWithTitle:kStrMoveApplicationButtonDoNotMove];
|
|
||||||
[cancelButton setKeyEquivalent:[NSString stringWithFormat:@"%C", 0x1b]]; // Escape key
|
|
||||||
|
|
||||||
// Setup suppression button
|
|
||||||
[alert setShowsSuppressionButton:YES];
|
|
||||||
|
|
||||||
if (PFUseSmallAlertSuppressCheckbox) {
|
|
||||||
NSCell *cell = [[alert suppressionButton] cell];
|
|
||||||
[cell setControlSize:NSSmallControlSize];
|
|
||||||
[cell setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activate app -- work-around for focus issues related to "scary file from internet" OS dialog.
|
|
||||||
if (![NSApp isActive]) {
|
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
|
||||||
NSLog(@"INFO -- Moving myself to the Applications folder");
|
|
||||||
|
|
||||||
// Move
|
|
||||||
if (needAuthorization) {
|
|
||||||
BOOL authorizationCanceled;
|
|
||||||
|
|
||||||
if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) {
|
|
||||||
if (authorizationCanceled) {
|
|
||||||
NSLog(@"INFO -- Not moving because user canceled authorization");
|
|
||||||
MoveInProgress = NO;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSLog(@"ERROR -- Could not copy myself to /Applications with authorization");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// If a copy already exists in the Applications folder, put it in the Trash
|
|
||||||
if ([fm fileExistsAtPath:destinationPath]) {
|
|
||||||
// But first, make sure that it's not running
|
|
||||||
if (IsApplicationAtPathRunning(destinationPath)) {
|
|
||||||
// Give the running app focus and terminate myself
|
|
||||||
NSLog(@"INFO -- Switching to an already running version");
|
|
||||||
[[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit];
|
|
||||||
MoveInProgress = NO;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName]))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CopyBundle(bundlePath, destinationPath)) {
|
|
||||||
NSLog(@"ERROR -- Could not copy myself to %@", destinationPath);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trash the original app. It's okay if this fails.
|
|
||||||
// NOTE: This final delete does not work if the source bundle is in a network mounted volume.
|
|
||||||
// Calling rm or file manager's delete method doesn't work either. It's unlikely to happen
|
|
||||||
// but it'd be great if someone could fix this.
|
|
||||||
if (!isNestedApplication && diskImageDevice == nil && !DeleteOrTrash(bundlePath)) {
|
|
||||||
NSLog(@"WARNING -- Could not delete application after moving it to Applications folder");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relaunch.
|
|
||||||
Relaunch(destinationPath);
|
|
||||||
|
|
||||||
// Launched from within a disk image? -- unmount (if no files are open after 5 seconds,
|
|
||||||
// otherwise leave it mounted).
|
|
||||||
if (diskImageDevice && !isNestedApplication) {
|
|
||||||
NSString *script = [NSString stringWithFormat:@"(/bin/sleep 5 && /usr/bin/hdiutil detach %@) &", ShellQuotedString(diskImageDevice)];
|
|
||||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveInProgress = NO;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
// Save the alert suppress preference if checked
|
|
||||||
else if ([[alert suppressionButton] state] == NSOnState) {
|
|
||||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveInProgress = NO;
|
|
||||||
return;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
{
|
|
||||||
// Show failure message
|
|
||||||
alert = [[[NSAlert alloc] init] autorelease];
|
|
||||||
[alert setMessageText:kStrMoveApplicationCouldNotMove];
|
|
||||||
[alert runModal];
|
|
||||||
MoveInProgress = NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL PFMoveIsInProgress() {
|
|
||||||
return MoveInProgress;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark -
|
|
||||||
#pragma mark Helper Functions
|
|
||||||
|
|
||||||
static NSString *PreferredInstallLocation(BOOL *isUserDirectory) {
|
|
||||||
// Return the preferred install location.
|
|
||||||
// Assume that if the user has a ~/Applications folder, they'd prefer their
|
|
||||||
// applications to go there.
|
|
||||||
|
|
||||||
NSFileManager *fm = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
/*
|
|
||||||
NSArray *userApplicationsDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
|
|
||||||
|
|
||||||
if ([userApplicationsDirs count] > 0) {
|
|
||||||
NSString *userApplicationsDir = [userApplicationsDirs objectAtIndex:0];
|
|
||||||
BOOL isDirectory;
|
|
||||||
|
|
||||||
if ([fm fileExistsAtPath:userApplicationsDir isDirectory:&isDirectory] && isDirectory) {
|
|
||||||
// User Applications directory exists. Get the directory contents.
|
|
||||||
NSArray *contents = [fm contentsOfDirectoryAtPath:userApplicationsDir error:NULL];
|
|
||||||
|
|
||||||
// Check if there is at least one ".app" inside the directory.
|
|
||||||
for (NSString *contentsPath in contents) {
|
|
||||||
if ([[contentsPath pathExtension] isEqualToString:@"app"]) {
|
|
||||||
if (isUserDirectory) *isUserDirectory = YES;
|
|
||||||
return [userApplicationsDir stringByResolvingSymlinksInPath];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// No user Applications directory in use. Return the machine local Applications directory
|
|
||||||
if (isUserDirectory) *isUserDirectory = NO;
|
|
||||||
|
|
||||||
return [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByResolvingSymlinksInPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL IsInApplicationsFolder(NSString *path) {
|
|
||||||
// Check all the normal Application directories
|
|
||||||
NSArray *applicationDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES);
|
|
||||||
for (NSString *appDir in applicationDirs) {
|
|
||||||
if ([path hasPrefix:appDir]) return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also, handle the case that the user has some other Application directory (perhaps on a separate data partition).
|
|
||||||
if ([[path pathComponents] containsObject:@"Applications"]) return YES;
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL IsInDownloadsFolder(NSString *path) {
|
|
||||||
NSArray *downloadDirs = NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSAllDomainsMask, YES);
|
|
||||||
for (NSString *downloadsDirPath in downloadDirs) {
|
|
||||||
if ([path hasPrefix:downloadsDirPath]) return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL IsApplicationAtPathRunning(NSString *bundlePath) {
|
|
||||||
bundlePath = [bundlePath stringByStandardizingPath];
|
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
|
|
||||||
// Use the new API on 10.6 or higher to determine if the app is already running
|
|
||||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
|
|
||||||
for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
|
||||||
NSString *runningAppBundlePath = [[[runningApplication bundleURL] path] stringByStandardizingPath];
|
|
||||||
if ([runningAppBundlePath isEqualToString:bundlePath]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// Use the shell to determine if the app is already running on systems 10.5 or lower
|
|
||||||
NSString *script = [NSString stringWithFormat:@"/bin/ps ax -o comm | /usr/bin/grep %@/ | /usr/bin/grep -v grep >/dev/null", ShellQuotedString(bundlePath)];
|
|
||||||
NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
|
||||||
[task waitUntilExit];
|
|
||||||
|
|
||||||
// If the task terminated with status 0, it means that the final grep produced 1 or more lines of output.
|
|
||||||
// Which means that the app is already running
|
|
||||||
return [task terminationStatus] == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL IsApplicationAtPathNested(NSString *path) {
|
|
||||||
NSString *containingPath = [path stringByDeletingLastPathComponent];
|
|
||||||
|
|
||||||
NSArray *components = [containingPath pathComponents];
|
|
||||||
for (NSString *component in components) {
|
|
||||||
if ([[component pathExtension] isEqualToString:@"app"]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static NSString *ContainingDiskImageDevice(NSString *path) {
|
|
||||||
NSString *containingPath = [path stringByDeletingLastPathComponent];
|
|
||||||
|
|
||||||
struct statfs fs;
|
|
||||||
if (statfs([containingPath fileSystemRepresentation], &fs) || (fs.f_flags & MNT_ROOTFS))
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
NSString *device = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:fs.f_mntfromname length:strlen(fs.f_mntfromname)];
|
|
||||||
|
|
||||||
NSTask *hdiutil = [[[NSTask alloc] init] autorelease];
|
|
||||||
[hdiutil setLaunchPath:@"/usr/bin/hdiutil"];
|
|
||||||
[hdiutil setArguments:[NSArray arrayWithObjects:@"info", @"-plist", nil]];
|
|
||||||
[hdiutil setStandardOutput:[NSPipe pipe]];
|
|
||||||
[hdiutil launch];
|
|
||||||
[hdiutil waitUntilExit];
|
|
||||||
|
|
||||||
NSData *data = [[[hdiutil standardOutput] fileHandleForReading] readDataToEndOfFile];
|
|
||||||
NSDictionary *info = nil;
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
|
|
||||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
|
|
||||||
info = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:NULL];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
#endif
|
|
||||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
|
|
||||||
info = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:NULL errorDescription:NULL];
|
|
||||||
#endif
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (![info isKindOfClass:[NSDictionary class]]) return nil;
|
|
||||||
|
|
||||||
NSArray *images = (NSArray *)[info objectForKey:@"images"];
|
|
||||||
if (![images isKindOfClass:[NSArray class]]) return nil;
|
|
||||||
|
|
||||||
for (NSDictionary *image in images) {
|
|
||||||
if (![image isKindOfClass:[NSDictionary class]]) return nil;
|
|
||||||
|
|
||||||
id systemEntities = [image objectForKey:@"system-entities"];
|
|
||||||
if (![systemEntities isKindOfClass:[NSArray class]]) return nil;
|
|
||||||
|
|
||||||
for (NSDictionary *systemEntity in systemEntities) {
|
|
||||||
if (![systemEntity isKindOfClass:[NSDictionary class]]) return nil;
|
|
||||||
|
|
||||||
NSString *devEntry = [systemEntity objectForKey:@"dev-entry"];
|
|
||||||
if (![devEntry isKindOfClass:[NSString class]]) return nil;
|
|
||||||
|
|
||||||
if ([devEntry isEqualToString:device])
|
|
||||||
return device;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL Trash(NSString *path) {
|
|
||||||
BOOL result = NO;
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
|
|
||||||
if (floor(NSAppKitVersionNumber) >= NSAppKitVersionNumber10_8) {
|
|
||||||
result = [[NSFileManager defaultManager] trashItemAtURL:[NSURL fileURLWithPath:path] resultingItemURL:NULL error:NULL];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
|
|
||||||
if (!result) {
|
|
||||||
result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
|
||||||
source:[path stringByDeletingLastPathComponent]
|
|
||||||
destination:@""
|
|
||||||
files:[NSArray arrayWithObject:[path lastPathComponent]]
|
|
||||||
tag:NULL];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// As a last resort try trashing with AppleScript.
|
|
||||||
// This allows us to trash the app in macOS Sierra even when the app is running inside
|
|
||||||
// an app translocation image.
|
|
||||||
if (!result) {
|
|
||||||
NSAppleScript *appleScript = [[[NSAppleScript alloc] initWithSource:
|
|
||||||
[NSString stringWithFormat:@"\
|
|
||||||
set theFile to POSIX file \"%@\" \n\
|
|
||||||
tell application \"Finder\" \n\
|
|
||||||
move theFile to trash \n\
|
|
||||||
end tell", path]] autorelease];
|
|
||||||
NSDictionary *errorDict = nil;
|
|
||||||
NSAppleEventDescriptor *scriptResult = [appleScript executeAndReturnError:&errorDict];
|
|
||||||
if (scriptResult == nil) {
|
|
||||||
NSLog(@"Trash AppleScript error: %@", errorDict);
|
|
||||||
}
|
|
||||||
result = (scriptResult != nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
NSLog(@"ERROR -- Could not trash '%@'", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL DeleteOrTrash(NSString *path) {
|
|
||||||
NSError *error;
|
|
||||||
|
|
||||||
if ([[NSFileManager defaultManager] removeItemAtPath:path error:&error]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Don't log warning if on Sierra and running inside App Translocation path
|
|
||||||
if ([path rangeOfString:@"/AppTranslocation/"].location == NSNotFound)
|
|
||||||
NSLog(@"WARNING -- Could not delete '%@': %@", path, [error localizedDescription]);
|
|
||||||
|
|
||||||
return Trash(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled) {
|
|
||||||
if (canceled) *canceled = NO;
|
|
||||||
|
|
||||||
// Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf'
|
|
||||||
// so we really don't want to fuck this up.
|
|
||||||
if (![[dstPath pathExtension] isEqualToString:@"app"]) return NO;
|
|
||||||
|
|
||||||
// Do some more checks
|
|
||||||
if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
|
|
||||||
if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
|
|
||||||
|
|
||||||
int pid, status;
|
|
||||||
AuthorizationRef myAuthorizationRef;
|
|
||||||
|
|
||||||
// Get the authorization
|
|
||||||
OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef);
|
|
||||||
if (err != errAuthorizationSuccess) return NO;
|
|
||||||
|
|
||||||
AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
|
|
||||||
AuthorizationRights myRights = {1, &myItems};
|
|
||||||
AuthorizationFlags myFlags = (AuthorizationFlags)(kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize);
|
|
||||||
|
|
||||||
err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL);
|
|
||||||
if (err != errAuthorizationSuccess) {
|
|
||||||
if (err == errAuthorizationCanceled && canceled)
|
|
||||||
*canceled = YES;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool,
|
|
||||||
AuthorizationFlags options, char * const *arguments,
|
|
||||||
FILE **communicationsPipe) = NULL;
|
|
||||||
if (!security_AuthorizationExecuteWithPrivileges) {
|
|
||||||
// On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no
|
|
||||||
// good alternative (without requiring code signing). We'll look up the function through dyld and fail
|
|
||||||
// if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If
|
|
||||||
// they keep the function and throw some sort of exception, this won't fail gracefully, but that's a
|
|
||||||
// risk we'll have to take for now.
|
|
||||||
security_AuthorizationExecuteWithPrivileges = (OSStatus (*)(AuthorizationRef, const char*,
|
|
||||||
AuthorizationFlags, char* const*,
|
|
||||||
FILE **)) dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
|
|
||||||
}
|
|
||||||
if (!security_AuthorizationExecuteWithPrivileges) goto fail;
|
|
||||||
|
|
||||||
// Delete the destination
|
|
||||||
{
|
|
||||||
char *args[] = {"-rf", (char *)[dstPath fileSystemRepresentation], NULL};
|
|
||||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
|
|
||||||
if (err != errAuthorizationSuccess) goto fail;
|
|
||||||
|
|
||||||
// Wait until it's done
|
|
||||||
pid = wait(&status);
|
|
||||||
if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy
|
|
||||||
{
|
|
||||||
char *args[] = {"-pR", (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL};
|
|
||||||
err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
|
|
||||||
if (err != errAuthorizationSuccess) goto fail;
|
|
||||||
|
|
||||||
// Wait until it's done
|
|
||||||
pid = wait(&status);
|
|
||||||
if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
|
||||||
return YES;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL CopyBundle(NSString *srcPath, NSString *dstPath) {
|
|
||||||
NSFileManager *fm = [NSFileManager defaultManager];
|
|
||||||
NSError *error = nil;
|
|
||||||
|
|
||||||
if ([fm copyItemAtPath:srcPath toPath:dstPath error:&error]) {
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSLog(@"ERROR -- Could not copy '%@' to '%@' (%@)", srcPath, dstPath, error);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static NSString *ShellQuotedString(NSString *string) {
|
|
||||||
return [NSString stringWithFormat:@"'%@'", [string stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"]];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Relaunch(NSString *destinationPath) {
|
|
||||||
// The shell script waits until the original app process terminates.
|
|
||||||
// This is done so that the relaunched app opens as the front-most app.
|
|
||||||
int pid = [[NSProcessInfo processInfo] processIdentifier];
|
|
||||||
|
|
||||||
// Command run just before running open /final/path
|
|
||||||
NSString *preOpenCmd = @"";
|
|
||||||
|
|
||||||
NSString *quotedDestinationPath = ShellQuotedString(destinationPath);
|
|
||||||
|
|
||||||
// OS X >=10.5:
|
|
||||||
// Before we launch the new app, clear xattr:com.apple.quarantine to avoid
|
|
||||||
// duplicate "scary file from the internet" dialog.
|
|
||||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
|
|
||||||
// Add the -r flag on 10.6
|
|
||||||
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine %@", quotedDestinationPath];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine %@", quotedDestinationPath];
|
|
||||||
}
|
|
||||||
|
|
||||||
NSString *script = [NSString stringWithFormat:@"(while /bin/kill -0 %d >&/dev/null; do /bin/sleep 0.1; done; %@; /usr/bin/open %@) &", pid, preOpenCmd, quotedDestinationPath];
|
|
||||||
|
|
||||||
[NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# -fobjc-arc: enables ARC
|
|
||||||
# -fmodules: enables modules so you can import with `@import AppKit;`
|
|
||||||
# -mmacosx-version-min=10.6: support older OS X versions, this might increase the binary size
|
|
||||||
|
|
||||||
if [ ! -d "../dist" ]; then mkdir ../dist; fi
|
|
||||||
|
|
||||||
clang PFMoveApplication.m -fno-objc-arc -fmodules -mmacosx-version-min=10.6 -c -o PFMoveApplication.o
|
|
||||||
clang run-with-mono.m Launcher.m PFMoveApplication.o -fobjc-arc -fmodules -mmacosx-version-min=10.6 -o ../dist/Launcher
|
|
||||||
rm PFMoveApplication.o
|
|
||||||
|
|
||||||
if [ "$1" == "install" ] && [ "$2" != "" ]; then
|
|
||||||
echo "Installing to $2"
|
|
||||||
cp ../dist/Launcher $2
|
|
||||||
chmod +x $2
|
|
||||||
fi
|
|
@ -1,11 +0,0 @@
|
|||||||
@import Foundation;
|
|
||||||
@import AppKit;
|
|
||||||
|
|
||||||
@interface RunWithMono : NSObject {
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) openDownloadLink:(NSButton*)button;
|
|
||||||
+ (bool) showDownloadMonoDialog:(NSString *)appName major:(int)major minor:(int)minor;
|
|
||||||
+ (int) runAssemblyWithMono:(NSString *)appName procnamesuffix:(NSString *)procnamesuffix assembly:(NSString *)assembly major:(int) major minor:(int) minor;
|
|
||||||
|
|
||||||
@end
|
|
@ -1,258 +0,0 @@
|
|||||||
#import "run-with-mono.h"
|
|
||||||
|
|
||||||
@import Foundation;
|
|
||||||
@import AppKit;
|
|
||||||
|
|
||||||
NSString * const VERSION_TITLE = @"Cannot launch %@";
|
|
||||||
NSString * const VERSION_MSG = @"%@ requires the Mono Framework version %d.%d or later.";
|
|
||||||
NSString * const DOWNLOAD_URL = @"http://www.mono-project.com/download/stable/#download-mac";
|
|
||||||
|
|
||||||
// Helper method to see if the user has requested debug output
|
|
||||||
bool D() {
|
|
||||||
NSString* v = [[[NSProcessInfo processInfo]environment]objectForKey:@"DEBUG"];
|
|
||||||
if (v == nil || v.length == 0 || [v isEqual:@"0"] || [v isEqual:@"false"] || [v isEqual:@"f"])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrapper method to invoke commandline operations and return the string output
|
|
||||||
NSString *runCommand(NSString *program, NSArray<NSString *> *arguments) {
|
|
||||||
NSPipe *pipe = [NSPipe pipe];
|
|
||||||
NSFileHandle *file = pipe.fileHandleForReading;
|
|
||||||
|
|
||||||
NSTask *task = [[NSTask alloc] init];
|
|
||||||
task.launchPath = program;
|
|
||||||
task.arguments = arguments;
|
|
||||||
task.standardOutput = pipe;
|
|
||||||
|
|
||||||
[task launch];
|
|
||||||
|
|
||||||
NSData *data = [file readDataToEndOfFile];
|
|
||||||
[file closeFile];
|
|
||||||
[task waitUntilExit];
|
|
||||||
|
|
||||||
NSString *cmdOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
|
|
||||||
if (cmdOutput == nil || cmdOutput.length == 0)
|
|
||||||
return nil;
|
|
||||||
|
|
||||||
return [cmdOutput stringByTrimmingCharactersInSet:
|
|
||||||
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if the Mono version is greater than or equal to the desired version
|
|
||||||
bool isValidMono(NSString *mono, int major, int minor) {
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
if (mono == nil)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (![fileManager fileExistsAtPath:mono] || ![fileManager isExecutableFileAtPath:mono])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
NSString *versionInfo = runCommand(mono, @[@"--version"]);
|
|
||||||
|
|
||||||
NSRange rg = [versionInfo rangeOfString:@"Mono JIT compiler version \\d+\\.\\d+" options:NSRegularExpressionSearch];
|
|
||||||
if (rg.location != NSNotFound) {
|
|
||||||
versionInfo = [versionInfo substringWithRange:rg];
|
|
||||||
if (D()) NSLog(@"Matched version: %@", versionInfo);
|
|
||||||
rg = [versionInfo rangeOfString:@"\\d+\\.\\d+" options:NSRegularExpressionSearch];
|
|
||||||
if (rg.location != NSNotFound) {
|
|
||||||
versionInfo = [versionInfo substringWithRange:rg];
|
|
||||||
if (D()) NSLog(@"Matched version: %@", versionInfo);
|
|
||||||
|
|
||||||
NSArray<NSString *> *versionComponents = [versionInfo componentsSeparatedByString:@"."];
|
|
||||||
if ([versionComponents[0] intValue] < major)
|
|
||||||
return false;
|
|
||||||
if ([versionComponents[0] intValue] == major && [versionComponents[1] intValue] < minor)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempts to locate a mono with a valid version
|
|
||||||
NSString *findMono(int major, int minor) {
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
NSString *currentMono = runCommand(@"/usr/bin/which", @[@"mono"]);
|
|
||||||
if (D()) NSLog(@"which mono: %@", currentMono);
|
|
||||||
|
|
||||||
if (isValidMono(currentMono, major, minor)) {
|
|
||||||
if (D()) NSLog(@"Found mono with: %@", currentMono);
|
|
||||||
return currentMono;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSArray *probepaths = @[@"/usr/local/bin/mono", @"/Library/Frameworks/Mono.framework/Versions/Current/bin/mono", @"/opt/local/bin/mono"];
|
|
||||||
for(NSString* probepath in probepaths) {
|
|
||||||
if (D()) NSLog(@"Trying mono with: %@", probepath);
|
|
||||||
if (isValidMono(probepath, major, minor)) {
|
|
||||||
if (D()) NSLog(@"Found mono with: %@", probepath);
|
|
||||||
return probepath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (D()) NSLog(@"Failed to find Mono, returning: %@", nil);
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Bundle for quarantine
|
|
||||||
void checkBundle() {
|
|
||||||
|
|
||||||
NSString * const bundlePath = [[NSBundle mainBundle] bundlePath];
|
|
||||||
NSString * const attributes = runCommand(@"/usr/bin/xattr", @[@"-l", bundlePath]);
|
|
||||||
if (D()) NSLog(@"Attributes: %@", attributes);
|
|
||||||
if ([attributes containsString:@"com.apple.quarantine:"]) {
|
|
||||||
runCommand(@"/usr/bin/xattr", @[@"-dr", @"com.apple.quarantine", bundlePath]);
|
|
||||||
NSLog(@"Removed quarantine attribute from bundle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@implementation RunWithMono
|
|
||||||
|
|
||||||
+ (void) openDownloadLink:(NSButton*)button {
|
|
||||||
if (D()) NSLog(@"Clicked Download");
|
|
||||||
runCommand(@"/usr/bin/open", @[DOWNLOAD_URL]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shows the download dialog, prompting to download Mono
|
|
||||||
+ (bool) showDownloadMonoDialog:(NSString *)appName major:(int)major minor:(int)minor {
|
|
||||||
NSAlert *alert = [[NSAlert alloc] init];
|
|
||||||
|
|
||||||
[alert setInformativeText:[NSString stringWithFormat:VERSION_MSG, appName, major, minor]];
|
|
||||||
[alert setMessageText:[NSString stringWithFormat:VERSION_TITLE, appName]];
|
|
||||||
[alert addButtonWithTitle:@"Cancel"];
|
|
||||||
[alert addButtonWithTitle:@"Retry"];
|
|
||||||
[alert addButtonWithTitle:@"Download"];
|
|
||||||
|
|
||||||
NSButton *downloadButton = [[alert buttons] objectAtIndex:2];
|
|
||||||
|
|
||||||
[downloadButton setTarget:self];
|
|
||||||
[downloadButton setAction:@selector(openDownloadLink:)];
|
|
||||||
|
|
||||||
NSModalResponse btn = [alert runModal];
|
|
||||||
if (btn == NSAlertFirstButtonReturn) {
|
|
||||||
if (D()) NSLog(@"Clicked Cancel");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (btn == NSAlertSecondButtonReturn) {
|
|
||||||
if (D()) NSLog(@"Clicked Retry");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-level method, finds Mono with an appropriate version and launches the assembly
|
|
||||||
+ (int) runAssemblyWithMono: (NSString *)appName procnamesuffix:(NSString *)procnamesuffix assembly:(NSString *)assembly major:(int) major minor:(int) minor {
|
|
||||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
||||||
|
|
||||||
NSString *assemblyPath;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
NSString *localPath = NSProcessInfo.processInfo.arguments[0].stringByDeletingLastPathComponent;
|
|
||||||
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
|
|
||||||
NSArray *paths = @[
|
|
||||||
localPath,
|
|
||||||
[NSString pathWithComponents:@[localPath, @"bin"]],
|
|
||||||
resourcePath,
|
|
||||||
[NSString pathWithComponents:@[resourcePath, @"bin"]]
|
|
||||||
];
|
|
||||||
for (NSString* entryFolder in paths) {
|
|
||||||
if (D()) NSLog(@"Checking folder: %@", entryFolder);
|
|
||||||
|
|
||||||
assemblyPath = [NSString pathWithComponents:@[entryFolder, assembly]];
|
|
||||||
|
|
||||||
if ([fileManager fileExistsAtPath:assemblyPath]) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
NSLog(@"Assembly file not found");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (D()) NSLog(@"assemblyPath: %@", assemblyPath);
|
|
||||||
|
|
||||||
checkBundle();
|
|
||||||
|
|
||||||
NSString *currentMono = findMono(major, minor);
|
|
||||||
|
|
||||||
while (currentMono == nil) {
|
|
||||||
NSLog(@"No valid mono found!");
|
|
||||||
bool close = [self showDownloadMonoDialog:appName major:major minor:minor];
|
|
||||||
if (close)
|
|
||||||
return 1;
|
|
||||||
currentMono = findMono(major, minor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup dylib fallback loading
|
|
||||||
NSMutableArray * dylibPath = [NSMutableArray arrayWithObject:assemblyPath.stringByDeletingLastPathComponent];
|
|
||||||
|
|
||||||
// Update the PATH to use the specified mono version
|
|
||||||
if ([currentMono hasPrefix:@"/"])
|
|
||||||
{
|
|
||||||
NSString * curMonoBinDir = currentMono.stringByDeletingLastPathComponent;
|
|
||||||
NSString * curMonoDir = curMonoBinDir.stringByDeletingLastPathComponent;
|
|
||||||
NSString * curMonoLibDir = [NSString pathWithComponents:@[curMonoDir, @"lib"]];
|
|
||||||
|
|
||||||
NSString * curEnvPath = [NSString stringWithUTF8String:getenv("PATH")];
|
|
||||||
NSString * newEnvPath = [NSString stringWithFormat:@"%@:%@", curMonoBinDir, curEnvPath];
|
|
||||||
setenv("PATH", newEnvPath.UTF8String, 1);
|
|
||||||
|
|
||||||
[dylibPath addObject:curMonoLibDir];
|
|
||||||
|
|
||||||
NSLog(@"Added %@ to PATH", curMonoBinDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup libsqlite?
|
|
||||||
/* if [[ -f '/opt/local/lib/libsqlite3.0.dylib' ]]; then
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="/opt/local/lib:$DYLD_FALLBACK_LIBRARY_PATH"
|
|
||||||
fi
|
|
||||||
*/
|
|
||||||
|
|
||||||
[dylibPath addObjectsFromArray:@[@"$HOME/lib", @"/usr/local/lib", @"/lib", @"/usr/lib"]];
|
|
||||||
|
|
||||||
setenv("DYLD_FALLBACK_LIBRARY_PATH", [dylibPath componentsJoinedByString:@":"].UTF8String, 1);
|
|
||||||
|
|
||||||
if (D()) NSLog(@"Running %@ --debug %@", currentMono, assemblyPath);
|
|
||||||
|
|
||||||
// Copy commandline arguments
|
|
||||||
NSMutableArray* arguments = [[NSMutableArray alloc] init];
|
|
||||||
// Disabled suffix for now coz it's confusing and not preserved on in-app restart
|
|
||||||
[arguments addObject:currentMono];
|
|
||||||
//[arguments addObject:[currentMono stringByAppendingString:procnamesuffix]];
|
|
||||||
[arguments addObject:@"--debug"];
|
|
||||||
[arguments addObjectsFromArray:[[NSProcessInfo processInfo] arguments]];
|
|
||||||
|
|
||||||
// replace the executable-path with the assembly path
|
|
||||||
[arguments replaceObjectAtIndex:2 withObject:assemblyPath];
|
|
||||||
|
|
||||||
// Try switch to mono using execv
|
|
||||||
char * cPath = strdup([currentMono UTF8String]);
|
|
||||||
char ** cArgs;
|
|
||||||
char ** pArgNext = cArgs = malloc(sizeof(*cArgs) * ([arguments count] + 1));
|
|
||||||
for (NSString *s in arguments) {
|
|
||||||
*pArgNext++ = strdup([s UTF8String]);
|
|
||||||
}
|
|
||||||
*pArgNext = NULL;
|
|
||||||
int ret = execv(cPath, cArgs);
|
|
||||||
if (ret != 0)
|
|
||||||
NSLog(@"Failed execv with errno @d", errno);
|
|
||||||
// execv failed, cleanup
|
|
||||||
pArgNext = cArgs;
|
|
||||||
for (NSString *s in arguments) {
|
|
||||||
free(*pArgNext++);
|
|
||||||
}
|
|
||||||
free(cArgs);
|
|
||||||
free(cPath);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1,62 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#get the bundle's MacOS directory full path
|
|
||||||
DIR=$(cd "$(dirname "$0")"; pwd)
|
|
||||||
|
|
||||||
#change these values to match your app
|
|
||||||
EXE_PATH="$DIR/Sonarr.exe"
|
|
||||||
APPNAME="Sonarr"
|
|
||||||
|
|
||||||
#set up environment
|
|
||||||
if [[ -x '/opt/local/bin/mono' ]]; then
|
|
||||||
# Macports and mono-supplied installer path
|
|
||||||
export PATH="/opt/local/bin:$PATH"
|
|
||||||
elif [[ -x '/usr/local/bin/mono' ]]; then
|
|
||||||
# Homebrew-supplied path to mono
|
|
||||||
export PATH="/usr/local/bin:$PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$DIR"
|
|
||||||
|
|
||||||
if [ -e /Library/Frameworks/Mono.framework ]; then
|
|
||||||
MONO_FRAMEWORK_PATH=/Library/Frameworks/Mono.framework/Versions/Current
|
|
||||||
export PATH="$MONO_FRAMEWORK_PATH/bin:$PATH"
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$MONO_FRAMEWORK_PATH/lib"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f '/opt/local/lib/libsqlite3.0.dylib' ]]; then
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="/opt/local/lib:$DYLD_FALLBACK_LIBRARY_PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$DYLD_FALLBACK_LIBRARY_PATH:$HOME/lib:/usr/local/lib:/lib:/usr/lib"
|
|
||||||
|
|
||||||
#mono version check
|
|
||||||
REQUIRED_MAJOR=4
|
|
||||||
REQUIRED_MINOR=6
|
|
||||||
|
|
||||||
VERSION_TITLE="Cannot launch $APPNAME"
|
|
||||||
VERSION_MSG="$APPNAME requires Mono Runtime Environment(MRE) $REQUIRED_MAJOR.$REQUIRED_MINOR or later."
|
|
||||||
DOWNLOAD_URL="http://www.mono-project.com/download/#download-mac"
|
|
||||||
|
|
||||||
MONO_VERSION="$(mono --version | grep 'Mono JIT compiler version ' | cut -f5 -d\ )"
|
|
||||||
# if [[ -o DEBUG ]]; then osascript -e "display dialog \"MONO_VERSION: $MONO_VERSION\""; fi
|
|
||||||
|
|
||||||
|
|
||||||
MONO_VERSION_MAJOR="$(echo $MONO_VERSION | cut -f1 -d.)"
|
|
||||||
MONO_VERSION_MINOR="$(echo $MONO_VERSION | cut -f2 -d.)"
|
|
||||||
if [ -z "$MONO_VERSION" ] \
|
|
||||||
|| [ $MONO_VERSION_MAJOR -lt $REQUIRED_MAJOR ] \
|
|
||||||
|| [ $MONO_VERSION_MAJOR -eq $REQUIRED_MAJOR -a $MONO_VERSION_MINOR -lt $REQUIRED_MINOR ]
|
|
||||||
then
|
|
||||||
osascript \
|
|
||||||
-e "set question to display dialog \"$VERSION_MSG\" with title \"$VERSION_TITLE\" buttons {\"Cancel\", \"Download...\"} default button 2" \
|
|
||||||
-e "if button returned of question is equal to \"Download...\" then open location \"$DOWNLOAD_URL\""
|
|
||||||
echo "$VERSION_TITLE"
|
|
||||||
echo "$VERSION_MSG"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
MONO_EXEC="exec mono --debug"
|
|
||||||
|
|
||||||
#run app using mono
|
|
||||||
$MONO_EXEC "$EXE_PATH"
|
|
@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<Dictionary>
|
|
||||||
<Words>
|
|
||||||
<Recognized>
|
|
||||||
<Word>Ack</Word>
|
|
||||||
<Word>Minifier</Word>
|
|
||||||
<Word>Jsonp</Word>
|
|
||||||
<Word>Linktionary</Word>
|
|
||||||
<Word>Scaleout</Word>
|
|
||||||
<Word>Redis</Word>
|
|
||||||
<Word>Owin</Word>
|
|
||||||
<Word>Stringify</Word>
|
|
||||||
<Word>Unminify</Word>
|
|
||||||
<Word>Unminified</Word>
|
|
||||||
<Word>Stateful</Word>
|
|
||||||
<Word>SignalR</Word>
|
|
||||||
<Word>Hubservable</Word>
|
|
||||||
<Word>Sse</Word>
|
|
||||||
<Word>GitHub</Word>
|
|
||||||
</Recognized>
|
|
||||||
</Words>
|
|
||||||
</Dictionary>
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
|
|
||||||
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
[assembly: AssemblyVersion("10.0.0.*")]
|
|
@ -1,227 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="11.0">
|
|
||||||
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
|
|
||||||
<Rule Id="CA1000" Action="Error" />
|
|
||||||
<Rule Id="CA1001" Action="Error" />
|
|
||||||
<Rule Id="CA1002" Action="Error" />
|
|
||||||
<Rule Id="CA1003" Action="Error" />
|
|
||||||
<Rule Id="CA1004" Action="Error" />
|
|
||||||
<Rule Id="CA1005" Action="Error" />
|
|
||||||
<Rule Id="CA1007" Action="Error" />
|
|
||||||
<Rule Id="CA1008" Action="Error" />
|
|
||||||
<Rule Id="CA1010" Action="Error" />
|
|
||||||
<Rule Id="CA1011" Action="Error" />
|
|
||||||
<Rule Id="CA1012" Action="Error" />
|
|
||||||
<Rule Id="CA1013" Action="Error" />
|
|
||||||
<Rule Id="CA1014" Action="Error" />
|
|
||||||
<Rule Id="CA1016" Action="Error" />
|
|
||||||
<Rule Id="CA1017" Action="Error" />
|
|
||||||
<Rule Id="CA1018" Action="Error" />
|
|
||||||
<Rule Id="CA1019" Action="Error" />
|
|
||||||
<Rule Id="CA1021" Action="Error" />
|
|
||||||
<Rule Id="CA1023" Action="Error" />
|
|
||||||
<Rule Id="CA1024" Action="Error" />
|
|
||||||
<Rule Id="CA1025" Action="Error" />
|
|
||||||
<Rule Id="CA1026" Action="Error" />
|
|
||||||
<Rule Id="CA1027" Action="Error" />
|
|
||||||
<Rule Id="CA1028" Action="Error" />
|
|
||||||
<Rule Id="CA1030" Action="Error" />
|
|
||||||
<Rule Id="CA1031" Action="Error" />
|
|
||||||
<Rule Id="CA1032" Action="Error" />
|
|
||||||
<Rule Id="CA1034" Action="Error" />
|
|
||||||
<Rule Id="CA1035" Action="Error" />
|
|
||||||
<Rule Id="CA1036" Action="Error" />
|
|
||||||
<Rule Id="CA1038" Action="Error" />
|
|
||||||
<Rule Id="CA1039" Action="Error" />
|
|
||||||
<Rule Id="CA1040" Action="Error" />
|
|
||||||
<Rule Id="CA1041" Action="Error" />
|
|
||||||
<Rule Id="CA1043" Action="Error" />
|
|
||||||
<Rule Id="CA1044" Action="Error" />
|
|
||||||
<Rule Id="CA1045" Action="Error" />
|
|
||||||
<Rule Id="CA1046" Action="Error" />
|
|
||||||
<Rule Id="CA1047" Action="Error" />
|
|
||||||
<Rule Id="CA1048" Action="Error" />
|
|
||||||
<Rule Id="CA1049" Action="Error" />
|
|
||||||
<Rule Id="CA1050" Action="Error" />
|
|
||||||
<Rule Id="CA1051" Action="Error" />
|
|
||||||
<Rule Id="CA1052" Action="Error" />
|
|
||||||
<Rule Id="CA1053" Action="Error" />
|
|
||||||
<Rule Id="CA1057" Action="Error" />
|
|
||||||
<Rule Id="CA1058" Action="Error" />
|
|
||||||
<Rule Id="CA1059" Action="Error" />
|
|
||||||
<Rule Id="CA1060" Action="Error" />
|
|
||||||
<Rule Id="CA1061" Action="Error" />
|
|
||||||
<Rule Id="CA1062" Action="Error" />
|
|
||||||
<Rule Id="CA1063" Action="Error" />
|
|
||||||
<Rule Id="CA1064" Action="Error" />
|
|
||||||
<Rule Id="CA1065" Action="Error" />
|
|
||||||
<Rule Id="CA1300" Action="Error" />
|
|
||||||
<Rule Id="CA1301" Action="Error" />
|
|
||||||
<Rule Id="CA1302" Action="Error" />
|
|
||||||
<Rule Id="CA1303" Action="Error" />
|
|
||||||
<Rule Id="CA1304" Action="Error" />
|
|
||||||
<Rule Id="CA1305" Action="Error" />
|
|
||||||
<Rule Id="CA1306" Action="Error" />
|
|
||||||
<Rule Id="CA1307" Action="Error" />
|
|
||||||
<Rule Id="CA1308" Action="Error" />
|
|
||||||
<Rule Id="CA1309" Action="Error" />
|
|
||||||
<Rule Id="CA1400" Action="Error" />
|
|
||||||
<Rule Id="CA1401" Action="Error" />
|
|
||||||
<Rule Id="CA1402" Action="Error" />
|
|
||||||
<Rule Id="CA1403" Action="Error" />
|
|
||||||
<Rule Id="CA1404" Action="Error" />
|
|
||||||
<Rule Id="CA1405" Action="Error" />
|
|
||||||
<Rule Id="CA1406" Action="Error" />
|
|
||||||
<Rule Id="CA1407" Action="Error" />
|
|
||||||
<Rule Id="CA1408" Action="Error" />
|
|
||||||
<Rule Id="CA1409" Action="Error" />
|
|
||||||
<Rule Id="CA1410" Action="Error" />
|
|
||||||
<Rule Id="CA1411" Action="Error" />
|
|
||||||
<Rule Id="CA1412" Action="Error" />
|
|
||||||
<Rule Id="CA1413" Action="Error" />
|
|
||||||
<Rule Id="CA1414" Action="Error" />
|
|
||||||
<Rule Id="CA1415" Action="Error" />
|
|
||||||
<Rule Id="CA1500" Action="Error" />
|
|
||||||
<Rule Id="CA1501" Action="Error" />
|
|
||||||
<Rule Id="CA1502" Action="Error" />
|
|
||||||
<Rule Id="CA1504" Action="Error" />
|
|
||||||
<Rule Id="CA1505" Action="Error" />
|
|
||||||
<Rule Id="CA1506" Action="Error" />
|
|
||||||
<Rule Id="CA1600" Action="Error" />
|
|
||||||
<Rule Id="CA1601" Action="Error" />
|
|
||||||
<Rule Id="CA1700" Action="Error" />
|
|
||||||
<Rule Id="CA1701" Action="Error" />
|
|
||||||
<Rule Id="CA1702" Action="Error" />
|
|
||||||
<Rule Id="CA1703" Action="Error" />
|
|
||||||
<Rule Id="CA1704" Action="Error" />
|
|
||||||
<Rule Id="CA1707" Action="Error" />
|
|
||||||
<Rule Id="CA1708" Action="Error" />
|
|
||||||
<Rule Id="CA1709" Action="Error" />
|
|
||||||
<Rule Id="CA1712" Action="Error" />
|
|
||||||
<Rule Id="CA1713" Action="Error" />
|
|
||||||
<Rule Id="CA1714" Action="Error" />
|
|
||||||
<Rule Id="CA1715" Action="Error" />
|
|
||||||
<Rule Id="CA1716" Action="Error" />
|
|
||||||
<Rule Id="CA1717" Action="Error" />
|
|
||||||
<Rule Id="CA1719" Action="Error" />
|
|
||||||
<Rule Id="CA1720" Action="Error" />
|
|
||||||
<Rule Id="CA1721" Action="Error" />
|
|
||||||
<Rule Id="CA1722" Action="Error" />
|
|
||||||
<Rule Id="CA1724" Action="Error" />
|
|
||||||
<Rule Id="CA1725" Action="Error" />
|
|
||||||
<Rule Id="CA1726" Action="Error" />
|
|
||||||
<Rule Id="CA1800" Action="Error" />
|
|
||||||
<Rule Id="CA1801" Action="Error" />
|
|
||||||
<Rule Id="CA1802" Action="Error" />
|
|
||||||
<Rule Id="CA1804" Action="Error" />
|
|
||||||
<Rule Id="CA1806" Action="Error" />
|
|
||||||
<Rule Id="CA1809" Action="Error" />
|
|
||||||
<Rule Id="CA1810" Action="Error" />
|
|
||||||
<Rule Id="CA1811" Action="Error" />
|
|
||||||
<Rule Id="CA1812" Action="Error" />
|
|
||||||
<Rule Id="CA1813" Action="Error" />
|
|
||||||
<Rule Id="CA1814" Action="Error" />
|
|
||||||
<Rule Id="CA1815" Action="Error" />
|
|
||||||
<Rule Id="CA1819" Action="Error" />
|
|
||||||
<Rule Id="CA1820" Action="Error" />
|
|
||||||
<Rule Id="CA1821" Action="Error" />
|
|
||||||
<Rule Id="CA1822" Action="Error" />
|
|
||||||
<Rule Id="CA1823" Action="Error" />
|
|
||||||
<Rule Id="CA1824" Action="Error" />
|
|
||||||
<Rule Id="CA1900" Action="Error" />
|
|
||||||
<Rule Id="CA1901" Action="Error" />
|
|
||||||
<Rule Id="CA1903" Action="Error" />
|
|
||||||
<Rule Id="CA2000" Action="Error" />
|
|
||||||
<Rule Id="CA2001" Action="Error" />
|
|
||||||
<Rule Id="CA2002" Action="Error" />
|
|
||||||
<Rule Id="CA2003" Action="Error" />
|
|
||||||
<Rule Id="CA2004" Action="Error" />
|
|
||||||
<Rule Id="CA2006" Action="Error" />
|
|
||||||
<Rule Id="CA2100" Action="Error" />
|
|
||||||
<Rule Id="CA2101" Action="Error" />
|
|
||||||
<Rule Id="CA2102" Action="Error" />
|
|
||||||
<Rule Id="CA2103" Action="Error" />
|
|
||||||
<Rule Id="CA2104" Action="Error" />
|
|
||||||
<Rule Id="CA2105" Action="Error" />
|
|
||||||
<Rule Id="CA2106" Action="Error" />
|
|
||||||
<Rule Id="CA2107" Action="Error" />
|
|
||||||
<Rule Id="CA2108" Action="Error" />
|
|
||||||
<Rule Id="CA2109" Action="Error" />
|
|
||||||
<Rule Id="CA2111" Action="Error" />
|
|
||||||
<Rule Id="CA2112" Action="Error" />
|
|
||||||
<Rule Id="CA2114" Action="Error" />
|
|
||||||
<Rule Id="CA2115" Action="Error" />
|
|
||||||
<Rule Id="CA2116" Action="Error" />
|
|
||||||
<Rule Id="CA2117" Action="Error" />
|
|
||||||
<Rule Id="CA2118" Action="Error" />
|
|
||||||
<Rule Id="CA2119" Action="Error" />
|
|
||||||
<Rule Id="CA2120" Action="Error" />
|
|
||||||
<Rule Id="CA2121" Action="Error" />
|
|
||||||
<Rule Id="CA2122" Action="Error" />
|
|
||||||
<Rule Id="CA2123" Action="Error" />
|
|
||||||
<Rule Id="CA2124" Action="Error" />
|
|
||||||
<Rule Id="CA2126" Action="Error" />
|
|
||||||
<Rule Id="CA2130" Action="Error" />
|
|
||||||
<Rule Id="CA2131" Action="Error" />
|
|
||||||
<Rule Id="CA2132" Action="Error" />
|
|
||||||
<Rule Id="CA2133" Action="Error" />
|
|
||||||
<Rule Id="CA2134" Action="Error" />
|
|
||||||
<Rule Id="CA2135" Action="Error" />
|
|
||||||
<Rule Id="CA2136" Action="Error" />
|
|
||||||
<Rule Id="CA2137" Action="Error" />
|
|
||||||
<Rule Id="CA2138" Action="Error" />
|
|
||||||
<Rule Id="CA2139" Action="Error" />
|
|
||||||
<Rule Id="CA2140" Action="Error" />
|
|
||||||
<Rule Id="CA2141" Action="Error" />
|
|
||||||
<Rule Id="CA2142" Action="Error" />
|
|
||||||
<Rule Id="CA2143" Action="Error" />
|
|
||||||
<Rule Id="CA2144" Action="Error" />
|
|
||||||
<Rule Id="CA2145" Action="Error" />
|
|
||||||
<Rule Id="CA2146" Action="Error" />
|
|
||||||
<Rule Id="CA2147" Action="Error" />
|
|
||||||
<Rule Id="CA2149" Action="Error" />
|
|
||||||
<Rule Id="CA2151" Action="Error" />
|
|
||||||
<Rule Id="CA2200" Action="Error" />
|
|
||||||
<Rule Id="CA2201" Action="Error" />
|
|
||||||
<Rule Id="CA2202" Action="Error" />
|
|
||||||
<Rule Id="CA2204" Action="Error" />
|
|
||||||
<Rule Id="CA2205" Action="Error" />
|
|
||||||
<Rule Id="CA2207" Action="Error" />
|
|
||||||
<Rule Id="CA2208" Action="Error" />
|
|
||||||
<Rule Id="CA2210" Action="Error" />
|
|
||||||
<Rule Id="CA2211" Action="Error" />
|
|
||||||
<Rule Id="CA2212" Action="Error" />
|
|
||||||
<Rule Id="CA2213" Action="Error" />
|
|
||||||
<Rule Id="CA2214" Action="Error" />
|
|
||||||
<Rule Id="CA2215" Action="Error" />
|
|
||||||
<Rule Id="CA2216" Action="Error" />
|
|
||||||
<Rule Id="CA2217" Action="Error" />
|
|
||||||
<Rule Id="CA2218" Action="Error" />
|
|
||||||
<Rule Id="CA2219" Action="Error" />
|
|
||||||
<Rule Id="CA2220" Action="Error" />
|
|
||||||
<Rule Id="CA2221" Action="Error" />
|
|
||||||
<Rule Id="CA2222" Action="Error" />
|
|
||||||
<Rule Id="CA2223" Action="Error" />
|
|
||||||
<Rule Id="CA2224" Action="Error" />
|
|
||||||
<Rule Id="CA2225" Action="Error" />
|
|
||||||
<Rule Id="CA2226" Action="Error" />
|
|
||||||
<Rule Id="CA2227" Action="Error" />
|
|
||||||
<Rule Id="CA2228" Action="Error" />
|
|
||||||
<Rule Id="CA2229" Action="Error" />
|
|
||||||
<Rule Id="CA2230" Action="Error" />
|
|
||||||
<Rule Id="CA2231" Action="Error" />
|
|
||||||
<Rule Id="CA2232" Action="Error" />
|
|
||||||
<Rule Id="CA2233" Action="Error" />
|
|
||||||
<Rule Id="CA2234" Action="Error" />
|
|
||||||
<Rule Id="CA2235" Action="Error" />
|
|
||||||
<Rule Id="CA2236" Action="Error" />
|
|
||||||
<Rule Id="CA2237" Action="Error" />
|
|
||||||
<Rule Id="CA2238" Action="Error" />
|
|
||||||
<Rule Id="CA2239" Action="Error" />
|
|
||||||
<Rule Id="CA2240" Action="Error" />
|
|
||||||
<Rule Id="CA2241" Action="Error" />
|
|
||||||
<Rule Id="CA2242" Action="Error" />
|
|
||||||
<Rule Id="CA2243" Action="Error" />
|
|
||||||
<Rule Id="CA5122" Action="Error" />
|
|
||||||
</Rules>
|
|
||||||
</RuleSet>
|
|
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup Condition="'$(ArtifactsDir)' != ''">
|
|
||||||
<OutputPath Condition="$(UseBinPath) == ''">$(ArtifactsDir)\$(MSBuildProjectName)</OutputPath>
|
|
||||||
<OutputPath Condition="$(UseBinPath) == 'true'">$(ArtifactsDir)\$(MSBuildProjectName)\bin</OutputPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Microsoft.AspNet.SignalR.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<RunCodeAnalysis Condition="'$(RunCodeAnalysis)' == ''">false</RunCodeAnalysis>
|
|
||||||
<NoWarn>1591</NoWarn>
|
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(RunCodeAnalysis)' == 'true'">
|
|
||||||
<DefineConstants>$(DefineConstants);CODE_ANALYSIS</DefineConstants>
|
|
||||||
<VisualStudioVersion>11.0</VisualStudioVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
|
|
||||||
<DefineConstants>$(DefineConstants);MONO</DefineConstants>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(KeyFile)' != '' And '$(DisableSigning)' != 'true'">
|
|
||||||
<DefineConstants>$(DefineConstants);SIGNED</DefineConstants>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<DelaySign>true</DelaySign>
|
|
||||||
<AssemblyOriginatorKeyFile>$(KeyFile)</AssemblyOriginatorKeyFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="Exists('$(MSBuildThisFileDirectory)GlobalSuppressions.cs')">
|
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)GlobalSuppressions.cs">
|
|
||||||
<Link>GlobalSuppressions.cs</Link>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<CodeAnalysisDictionary Include="$(MSBuildThisFileDirectory)CodeAnalysisDictionary.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||||||
|
<Project>
|
||||||
|
<Import Project="Targets/PublishAllRids.targets" />
|
||||||
|
<Import Project="Targets/CopyRuntimes.targets" />
|
||||||
|
</Project>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
Copied from mono/4.5/Facades of the mono 5.4 release.
|
|
||||||
These are the mono version of the dotnet Core TypeForwardedTo assemblies.
|
|
||||||
Using these assemblies is no longer necessary once we reach mono 5.18 as minimum version
|
|
@ -1,69 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
using NzbDrone.Core.HealthCheck.Checks;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class DotnetVersionCheckFixture : CoreTest<DotnetVersionCheck>
|
|
||||||
{
|
|
||||||
private void GivenOutput(string version)
|
|
||||||
{
|
|
||||||
WindowsOnly();
|
|
||||||
|
|
||||||
Mocker.GetMock<IPlatformInfo>()
|
|
||||||
.SetupGet(s => s.Version)
|
|
||||||
.Returns(new Version(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("4.7.2")]
|
|
||||||
[TestCase("4.8")]
|
|
||||||
public void should_return_ok(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void should_return_notice(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeNotice();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void should_return_warning(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeWarning();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("4.5")]
|
|
||||||
[TestCase("4.5.2")]
|
|
||||||
[TestCase("4.6.1")]
|
|
||||||
[TestCase("4.6.2")]
|
|
||||||
[TestCase("4.7")]
|
|
||||||
[TestCase("4.7.1")]
|
|
||||||
public void should_return_error(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeError();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_return_nok_for_net462_on_Win1511()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IOsInfo>()
|
|
||||||
.SetupGet(v => v.Version)
|
|
||||||
.Returns("10.0.14392");
|
|
||||||
|
|
||||||
GivenOutput("4.6.2");
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
using NzbDrone.Core.HealthCheck.Checks;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class MonoVersionCheckFixture : CoreTest<MonoVersionCheck>
|
|
||||||
{
|
|
||||||
private void GivenOutput(string version)
|
|
||||||
{
|
|
||||||
MonoOnly();
|
|
||||||
|
|
||||||
Mocker.GetMock<IPlatformInfo>()
|
|
||||||
.SetupGet(s => s.Version)
|
|
||||||
.Returns(new Version(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("5.18")]
|
|
||||||
[TestCase("5.20")]
|
|
||||||
[TestCase("6.4")]
|
|
||||||
public void should_return_ok(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void should_return_notice(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeNotice();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void should_return_warning(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeWarning();
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCase("2.10.2")]
|
|
||||||
[TestCase("2.10.8.1")]
|
|
||||||
[TestCase("3.0.0.1")]
|
|
||||||
[TestCase("3.2.0.1")]
|
|
||||||
[TestCase("3.2.1")]
|
|
||||||
[TestCase("3.2.7")]
|
|
||||||
[TestCase("3.6.1")]
|
|
||||||
[TestCase("3.8")]
|
|
||||||
[TestCase("3.10")]
|
|
||||||
[TestCase("4.0.0.0")]
|
|
||||||
[TestCase("4.2")]
|
|
||||||
[TestCase("4.4.0")]
|
|
||||||
[TestCase("4.4.1")]
|
|
||||||
[TestCase("5.4")]
|
|
||||||
[TestCase("5.8")]
|
|
||||||
[TestCase("5.10")]
|
|
||||||
[TestCase("5.12")]
|
|
||||||
[TestCase("5.14")]
|
|
||||||
[TestCase("5.16")]
|
|
||||||
public void should_return_error(string version)
|
|
||||||
{
|
|
||||||
GivenOutput(version);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
public class DotnetVersionCheck : HealthCheckBase
|
|
||||||
{
|
|
||||||
private readonly IPlatformInfo _platformInfo;
|
|
||||||
private readonly IOsInfo _osInfo;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public DotnetVersionCheck(IPlatformInfo platformInfo, IOsInfo osInfo, Logger logger)
|
|
||||||
{
|
|
||||||
_platformInfo = platformInfo;
|
|
||||||
_osInfo = osInfo;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override HealthCheck Check()
|
|
||||||
{
|
|
||||||
if (!PlatformInfo.IsDotNet)
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
var dotnetVersion = _platformInfo.Version;
|
|
||||||
|
|
||||||
// Target .Net version, which would allow us to increase our target framework
|
|
||||||
var targetVersion = new Version("4.7.2");
|
|
||||||
if (dotnetVersion >= targetVersion)
|
|
||||||
{
|
|
||||||
_logger.Debug("Dotnet version is {0} or better: {1}", targetVersion, dotnetVersion);
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supported .net version but below our desired target
|
|
||||||
var stableVersion = new Version("4.7.2");
|
|
||||||
if (dotnetVersion >= stableVersion)
|
|
||||||
{
|
|
||||||
_logger.Debug("Dotnet version is {0} or better: {1}", stableVersion, dotnetVersion);
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Notice,
|
|
||||||
$"Currently installed .Net Framework {dotnetVersion} is supported but we recommend upgrading to at least {targetVersion}.",
|
|
||||||
"#currently-installed-net-framework-is-supported-but-upgrading-is-recommended");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Version.TryParse(_osInfo.Version, out var osVersion) && osVersion < new Version("10.0.14393"))
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed .Net Framework {dotnetVersion} is no longer supported. However your Operating System cannot be upgraded to {targetVersion}.",
|
|
||||||
"#currently-installed-net-framework-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldVersion = new Version("4.6.2");
|
|
||||||
if (dotnetVersion >= oldVersion)
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed .Net Framework {dotnetVersion} is no longer supported. Please upgrade the .Net Framework to at least {targetVersion}.",
|
|
||||||
"#currently-installed-net-framework-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed .Net Framework {dotnetVersion} is old and unsupported. Please upgrade the .Net Framework to at least {targetVersion}.",
|
|
||||||
"#currently-installed-net-framework-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CheckOnSchedule => false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.HealthCheck.Checks
|
|
||||||
{
|
|
||||||
public class MonoVersionCheck : HealthCheckBase
|
|
||||||
{
|
|
||||||
private readonly IPlatformInfo _platformInfo;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public MonoVersionCheck(IPlatformInfo platformInfo, Logger logger)
|
|
||||||
{
|
|
||||||
_platformInfo = platformInfo;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override HealthCheck Check()
|
|
||||||
{
|
|
||||||
if (!PlatformInfo.IsMono)
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
var monoVersion = _platformInfo.Version;
|
|
||||||
|
|
||||||
// Known buggy Mono versions
|
|
||||||
if (monoVersion == new Version("4.4.0") || monoVersion == new Version("4.4.1"))
|
|
||||||
{
|
|
||||||
_logger.Debug("Mono version {0}", monoVersion);
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed Mono version {monoVersion} has a bug that causes issues connecting to indexers/download clients. You should upgrade to a higher version",
|
|
||||||
"#currently-installed-mono-version-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently best stable Mono version (5.18 gets us .net 4.7.2 support)
|
|
||||||
var bestVersion = new Version("5.20");
|
|
||||||
var targetVersion = new Version("5.18");
|
|
||||||
if (monoVersion >= targetVersion)
|
|
||||||
{
|
|
||||||
_logger.Debug("Mono version is {0} or better: {1}", targetVersion, monoVersion);
|
|
||||||
return new HealthCheck(GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stable Mono versions
|
|
||||||
var stableVersion = new Version("5.18");
|
|
||||||
if (monoVersion >= stableVersion)
|
|
||||||
{
|
|
||||||
_logger.Debug("Mono version is {0} or better: {1}", stableVersion, monoVersion);
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Notice,
|
|
||||||
$"Currently installed Mono version {monoVersion} is supported but upgrading to {bestVersion} is recommended.",
|
|
||||||
"#currently-installed-mono-version-is-supported-but-upgrading-is-recommended");
|
|
||||||
}
|
|
||||||
|
|
||||||
var oldVersion = new Version("5.4");
|
|
||||||
if (monoVersion >= oldVersion)
|
|
||||||
{
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed Mono version {monoVersion} is no longer supported. Please upgrade Mono to version {bestVersion}.",
|
|
||||||
"#currently-installed-mono-version-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error,
|
|
||||||
$"Currently installed Mono version {monoVersion} is old and unsupported. Please upgrade Mono to version {bestVersion}.",
|
|
||||||
"#currently-installed-mono-version-is-old-and-unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CheckOnSchedule => false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<dllmap os="osx" dll="MediaInfo.dll" target="libmediainfo.0.dylib"/>
|
|
||||||
<dllmap os="linux" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
|
||||||
<dllmap os="freebsd" dll="MediaInfo.dll" target="libmediainfo.so.0" />
|
|
||||||
<dllmap os="solaris" dll="MediaInfo.dll" target="libmediainfo.so.0.0.0" />
|
|
||||||
</configuration>
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue