mirror of
https://github.com/XcodesOrg/XcodesApp.git
synced 2026-03-25 08:55:46 +00:00
Adds option to create symbolic link at Path Xcode.app
This commit is contained in:
parent
e628d04beb
commit
4cee0f2f15
6 changed files with 75 additions and 5 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// swift-tools-version:5.3
|
||||
// swift-tools-version:5.4
|
||||
|
||||
import PackageDescription
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ extension AppState {
|
|||
private func getXcodeArchive(_ installationType: InstallationType, downloader: Downloader) -> AnyPublisher<(AvailableXcode, URL), Error> {
|
||||
switch installationType {
|
||||
case .version(let availableXcode):
|
||||
if let installedXcode = Current.files.installedXcodes(Path.root/"Applications").first(where: { $0.version.isEquivalent(to: availableXcode.version) }) {
|
||||
if let installedXcode = Current.files.installedXcodes(Path.installDirectory).first(where: { $0.version.isEquivalent(to: availableXcode.version) }) {
|
||||
return Fail(error: InstallationError.versionAlreadyInstalled(installedXcode))
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ extension AppState {
|
|||
|
||||
public func installArchivedXcode(_ availableXcode: AvailableXcode, at archiveURL: URL) -> AnyPublisher<InstalledXcode, Error> {
|
||||
do {
|
||||
let destinationURL = Path.root.join("Applications").join("Xcode-\(availableXcode.version.descriptionWithoutBuildMetadata).app").url
|
||||
let destinationURL = Path.installDirectory.join("Xcode-\(availableXcode.version.descriptionWithoutBuildMetadata).app").url
|
||||
switch archiveURL.pathExtension {
|
||||
case "xip":
|
||||
return unarchiveAndMoveXIP(availableXcode: availableXcode, at: archiveURL, to: destinationURL)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class AppState: ObservableObject {
|
|||
}
|
||||
updateAllXcodes(
|
||||
availableXcodes: newValue,
|
||||
installedXcodes: Current.files.installedXcodes(Path.root/"Applications"),
|
||||
installedXcodes: Current.files.installedXcodes(Path.installDirectory),
|
||||
selectedXcodePath: selectedXcodePath
|
||||
)
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class AppState: ObservableObject {
|
|||
willSet {
|
||||
updateAllXcodes(
|
||||
availableXcodes: availableXcodes,
|
||||
installedXcodes: Current.files.installedXcodes(Path.root/"Applications"),
|
||||
installedXcodes: Current.files.installedXcodes(Path.installDirectory),
|
||||
selectedXcodePath: newValue
|
||||
)
|
||||
}
|
||||
|
|
@ -495,6 +495,41 @@ class AppState: ObservableObject {
|
|||
NSPasteboard.general.writeObjects([installedXcodePath.url as NSURL])
|
||||
NSPasteboard.general.setString(installedXcodePath.string, forType: .string)
|
||||
}
|
||||
|
||||
func createSymbolicLink(xcode: Xcode) {
|
||||
guard let installedXcodePath = xcode.installedPath else { return }
|
||||
|
||||
let destinationPath: Path = Path.installDirectory/"Xcode.app"
|
||||
|
||||
// does an Xcode.app file exist?
|
||||
if FileManager.default.fileExists(atPath: destinationPath.string) {
|
||||
do {
|
||||
// if it's not a symlink, error because we don't want to delete an actual xcode.app file
|
||||
let attributes: [FileAttributeKey : Any]? = try? FileManager.default.attributesOfItem(atPath: destinationPath.string)
|
||||
|
||||
if attributes?[.type] as? FileAttributeType == FileAttributeType.typeSymbolicLink {
|
||||
try FileManager.default.removeItem(atPath: destinationPath.string)
|
||||
Logger.appState.info("Successfully deleted old symlink")
|
||||
} else {
|
||||
let message = "Xcode.app exists and is not a symbolic link"
|
||||
self.presentedAlert = .generic(title: "Unable to create symbolic Link", message: message)
|
||||
return
|
||||
}
|
||||
} catch {
|
||||
self.presentedAlert = .generic(title: "Unable to create symbolic Link", message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
try FileManager.default.createSymbolicLink(atPath: destinationPath.string, withDestinationPath: installedXcodePath.string)
|
||||
Logger.appState.info("Successfully created symbolic link with Xcode.app")
|
||||
} catch {
|
||||
Logger.appState.error("Unable to create symbolic Link")
|
||||
self.error = error
|
||||
self.presentedAlert = .generic(title: "Unable to create symbolic Link", message: error.legibleLocalizedDescription)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func updateAllXcodes(availableXcodes: [AvailableXcode], installedXcodes: [InstalledXcode], selectedXcodePath: String?) {
|
||||
var adjustedAvailableXcodes = availableXcodes
|
||||
|
|
|
|||
|
|
@ -16,4 +16,8 @@ extension Path {
|
|||
static var cacheFile: Path {
|
||||
return xcodesApplicationSupport/"available-xcodes.json"
|
||||
}
|
||||
|
||||
static var installDirectory: Path {
|
||||
return Path.root/"Applications"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ struct XcodeCommands: Commands {
|
|||
OpenCommand()
|
||||
RevealCommand()
|
||||
CopyPathCommand()
|
||||
CreateSymbolicLinkCommand()
|
||||
|
||||
Divider()
|
||||
|
||||
|
|
@ -153,6 +154,23 @@ struct CopyPathButton: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct CreateSymbolicLinkButton: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
let xcode: Xcode?
|
||||
|
||||
var body: some View {
|
||||
Button(action: createSymbolicLink) {
|
||||
Text("Create SymLink as Xcode.app")
|
||||
}
|
||||
.help("Create SymLink as Xcode.app")
|
||||
}
|
||||
|
||||
private func createSymbolicLink() {
|
||||
guard let xcode = xcode else { return }
|
||||
appState.createSymbolicLink(xcode: xcode)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Commands
|
||||
|
||||
struct InstallCommand: View {
|
||||
|
|
@ -225,3 +243,15 @@ struct UninstallCommand: View {
|
|||
.disabled(selectedXcode.unwrapped?.installState.installed != true)
|
||||
}
|
||||
}
|
||||
|
||||
struct CreateSymbolicLinkCommand: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@FocusedValue(\.selectedXcode) private var selectedXcode: SelectedXcode?
|
||||
|
||||
var body: some View {
|
||||
CreateSymbolicLinkButton(xcode: selectedXcode.unwrapped)
|
||||
.keyboardShortcut("s", modifiers: [.command, .option])
|
||||
.disabled(selectedXcode.unwrapped?.installState.installed != true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ struct XcodeListViewRow: View {
|
|||
OpenButton(xcode: xcode)
|
||||
RevealButton(xcode: xcode)
|
||||
CopyPathButton(xcode: xcode)
|
||||
CreateSymbolicLinkButton(xcode: xcode)
|
||||
Divider()
|
||||
UninstallButton(xcode: xcode)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue