Merge pull request #333 from RobotsAndPencils/matt/OpenInRosetta

Adds open in Rosetta option for Apple Silicon machines
This commit is contained in:
Matt Kiazyk 2022-12-06 18:42:57 -06:00 committed by GitHub
commit 0b6ae5d7ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 85 additions and 11 deletions

View file

@ -104,6 +104,7 @@
CAFFFED8259CDA5000903F81 /* XcodeListViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAFFFED7259CDA5000903F81 /* XcodeListViewRow.swift */; };
E81D7EA02805250100A205FC /* Collection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81D7E9F2805250100A205FC /* Collection+.swift */; };
E872EE4E2808D4F100D3DD8B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E872EE502808D4F100D3DD8B /* Localizable.strings */; };
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87AB3C42939B65E00D72F43 /* Hardware.swift */; };
E87DD6EB25D053FA00D86808 /* Progress+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E87DD6EA25D053FA00D86808 /* Progress+.swift */; };
E89342FA25EDCC17007CF557 /* NotificationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E89342F925EDCC17007CF557 /* NotificationManager.swift */; };
E8977EA325C11E1500835F80 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8977EA225C11E1500835F80 /* PreferencesView.swift */; };
@ -297,6 +298,7 @@
E2AFDCCA28F024D000864ADD /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
E81D7E9F2805250100A205FC /* Collection+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+.swift"; sourceTree = "<group>"; };
E872EE4F2808D4F100D3DD8B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
E87AB3C42939B65E00D72F43 /* Hardware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hardware.swift; sourceTree = "<group>"; };
E87DD6EA25D053FA00D86808 /* Progress+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+.swift"; sourceTree = "<group>"; };
E89342F925EDCC17007CF557 /* NotificationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationManager.swift; sourceTree = "<group>"; };
E8977EA225C11E1500835F80 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
@ -489,6 +491,7 @@
E87DD6EA25D053FA00D86808 /* Progress+.swift */,
E81D7E9F2805250100A205FC /* Collection+.swift */,
E8D655BF288DD04700A139C2 /* SelectedActionType.swift */,
E87AB3C42939B65E00D72F43 /* Hardware.swift */,
);
path = Backend;
sourceTree = "<group>";
@ -877,6 +880,7 @@
CAC281CD259F97FA00B8AB0B /* ObservingProgressIndicator.swift in Sources */,
CABFA9C22592EEEA00380FEE /* Publisher+Resumable.swift in Sources */,
CAFBDC68259A308B003DCC5A /* InfoPane.swift in Sources */,
E87AB3C52939B65E00D72F43 /* Hardware.swift in Sources */,
CAA1CB4D255A5CFD003FD669 /* SignInPhoneListView.swift in Sources */,
CAFBDC6C259A3098003DCC5A /* View+Conditional.swift in Sources */,
CABFA9CF2592EEEA00380FEE /* Process.swift in Sources */,

View file

@ -93,7 +93,12 @@ class AppState: ObservableObject {
}
}
}
@Published var showOpenInRosettaOption = false {
didSet {
Current.defaults.set(showOpenInRosettaOption, forKey: "showOpenInRosettaOption")
}
}
// MARK: - Publisher Cancellables
var cancellables = Set<AnyCancellable>()
@ -142,6 +147,7 @@ class AppState: ObservableObject {
createSymLinkOnSelect = Current.defaults.bool(forKey: "createSymLinkOnSelect") ?? false
onSelectActionType = SelectedActionType(rawValue: Current.defaults.string(forKey: "onSelectActionType") ?? "none") ?? .none
installPath = Current.defaults.string(forKey: "installPath") ?? Path.defaultInstallDirectory.string
showOpenInRosettaOption = Current.defaults.bool(forKey: "showOpenInRosettaOption") ?? false
}
// MARK: Timer
@ -585,13 +591,18 @@ class AppState: ObservableObject {
)
}
func open(xcode: Xcode) {
func open(xcode: Xcode, openInRosetta: Bool? = false) {
switch xcode.installState {
case let .installed(path):
NSWorkspace.shared.openApplication(at: path.url, configuration: .init())
default:
Logger.appState.error("\(xcode.id) is not installed")
return
case let .installed(path):
let config = NSWorkspace.OpenConfiguration.init()
if (openInRosetta ?? false) {
config.architecture = CPU_TYPE_X86_64
}
config.allowsRunningApplicationSubstitution = false
NSWorkspace.shared.openApplication(at: path.url, configuration: config)
default:
Logger.appState.error("\(xcode.id) is not installed")
return
}
}

View file

@ -0,0 +1,28 @@
import Foundation
struct Hardware {
///
/// Determines the architecture of the Mac on which we're running. Returns `arm64` for Apple Silicon
/// and `x86_64` for Intel-based Macs or `nil` if the system call fails.
static func getMachineHardwareName() -> String?
{
var sysInfo = utsname()
let retVal = uname(&sysInfo)
var finalString: String? = nil
if retVal == EXIT_SUCCESS
{
let bytes = Data(bytes: &sysInfo.machine, count: Int(_SYS_NAMELEN))
finalString = String(data: bytes, encoding: .utf8)
}
// _SYS_NAMELEN will include a billion null-terminators. Clear those out so string comparisons work as you expect.
return finalString?.trimmingCharacters(in: CharacterSet(charactersIn: "\0"))
}
static func isAppleSilicon() -> Bool {
return Hardware.getMachineHardwareName() == "arm64"
}
}

View file

@ -92,16 +92,34 @@ struct OpenButton: View {
@EnvironmentObject var appState: AppState
let xcode: Xcode?
var openInRosetta: Bool {
appState.showOpenInRosettaOption && Hardware.isAppleSilicon()
}
var body: some View {
Button(action: open) {
Text("Open")
if openInRosetta {
Menu("Open") {
Button(action: open) {
Text("Open")
}
.help("Open")
Button(action: open) {
Text("Open In Rosetta")
}
.help("Open In Rosetta")
}
} else {
Button(action: open) {
Text("Open")
}
.help("Open")
}
.help("Open")
}
private func open() {
guard let xcode = xcode else { return }
appState.open(xcode: xcode)
appState.open(xcode: xcode, openInRosetta: openInRosetta)
}
}

View file

@ -106,6 +106,16 @@ struct AdvancedPreferencePane: View {
}
.groupBoxStyle(PreferencesGroupBoxStyle())
if Hardware.isAppleSilicon() {
GroupBox(label: Text("Apple Silicon")) {
Toggle("ShowOpenInRosetta", isOn: $appState.showOpenInRosettaOption)
.disabled(appState.createSymLinkOnSelectDisabled)
Text("ShowOpenInRosettaDescription")
.font(.footnote)
.fixedSize(horizontal: false, vertical: true)
}
.groupBoxStyle(PreferencesGroupBoxStyle())
}
GroupBox(label: Text("PrivilegedHelper")) {
VStack(alignment: .leading, spacing: 8) {

View file

@ -102,6 +102,9 @@
"HelperNotInstalled" = "Helper is not installed";
"InstallHelper" = "Install helper";
"ShowOpenInRosetta" = "Show Open In Rosetta option";
"ShowOpenInRosettaDescription" = "Open in Rosetta option will show where other \"Open\" functions are available. Note: This will only show for Apple Silicon machines.";
// Experiment Preference Pane
"Experiments" = "Experiments";
"FasterUnxip" = "Faster Unxip";