Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dotnet-install.sh fails when using "Pair to Mac" in Visual Studio Enterprise 2022 #572

Open
Mr-Horse opened this issue Jan 31, 2025 · 13 comments
Assignees

Comments

@Mr-Horse
Copy link

Mr-Horse commented Jan 31, 2025

Describe the bug.

We're trying to connect to a mac to do development on our old "xamarin" project that is now .NET 8.0 iOS. We normally connect to the mac and build/run the app on the mac simulator or iOS device. We've tried a ton of stuff and nothing seems to work. Currently we're unable to develop on the repo because of this issue. We would appreciate any help, thank you.

Reproduction Steps

  • Open visual studio solution with iOS project
  • Click on the xamarin agent button in the toolbar
  • Click add mac button
  • Type in the IP address or mac name
  • Enter username and password
  • Image
  • Click sign in
  • Image
  • The window shows an error: The dotnet SDK installation '9.0.102-servicing.24611.3' failed. If trying again doesn't work, please refer to the public documentation for more information and troubleshooting: https://aka.ms/pairtomac/dotnet
  • Actual error from the script file:
    Xamarin.Messaging.Exceptions.MessagingRemoteException: An error occurred on client IDB17120153 while executing a reply for topic xvs/idb/initialize-dotnet-sdk ---> Xamarin.Messaging.IDB.Contracts.DotNetSdkInstallationException: Could not install dotnet SDK '9.0.102-servicing.24611.3'. Details: /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/scripts/dotnet-install.sh: line 1440: link_types[$link_index]: unbound variable

What we've tried

  • Visual studio and Visual studio code is installed on the PC and Mac(visual studio for mac was deprecated)
  • dotnet 8 and 9 Arm64 are installed on the mac from here and here
  • Added all required permissions and settings from here
  • We've run "dotnet workload restore" on the mac and PC
  • We've run "dotnet restore" and "dotnet build" on the Mac, and the solution does build
  • We're able to run the script file "./dotnet-install.sh" from the terminal but ONLY with sudo
  • cd /users/mrhorse/library/caches/xamarin/xma/sdks/dotnet/scripts
  • chmod +x dotnet-install.sh
  • sudo ./dotnet-install.sh --version 9.0.102-servicing.24611.3
  • dotnet-install: .NET Core SDK with version '9.0.102' is already installed.
  • We're able to ssh into the mac from the PC in powershell and run the script file "./dotnet-install.sh" but ONLY with sudo
  • We are an admin on the Mac and PC

Output from xamarin logs

Xamarin log output ``` Xamarin Information: 0 : Xamarin - 17.12.0.153-d17-12+1d0906d: 01/31/2025 14:28:00Z DateTime=2025-01-31T14:28:00.6908367Z: 01/31/2025 14:28:00Z Xamarin Information: 0 : DateTime=2025-01-31T14:28:00.6908367Z: 01/31/2025 14:28:00Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Starting Broker in-process...: 01/31/2025 14:28:00Z DateTime=2025-01-31T14:28:00.7113517Z: 01/31/2025 14:28:00Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:00.7113517Z: 01/31/2025 14:28:00Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Starting: Broker 17.12.0.153 ( PID = 23960 ): 01/31/2025 14:28:00Z DateTime=2025-01-31T14:28:00.7303517Z: 01/31/2025 14:28:00Z Xamarin.Messaging.Server.MessagingServer Information: 0 : Starting Messaging Server...: 01/31/2025 14:28:00Z DateTime=2025-01-31T14:28:00.7383547Z: 01/31/2025 14:28:00Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Connecting Agent to the Broker...: 01/31/2025 14:28:00Z DateTime=2025-01-31T14:28:00.7613542Z: 01/31/2025 14:28:00Z Xamarin.VisualStudio.TastyPackage Information: 0 : Hooked up SDB tracing adapter: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.4645860Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.TastyPackage Information: 0 : Initialization finished: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.4924587Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Initializing Agent context...: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.5744146Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering Agent message handlers...: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.5774146Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering message handler for message type: Xamarin.Messaging.GetAgentVersionMessage: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.5844142Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.TastyPackage Information: 0 : Hooked up SDB tracing adapter: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.6285597Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.TastyPackage Information: 0 : Initialization finished: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.6394378Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.XamarinIOSPackage Warning: 0 : Initializing Xamarin.VisualStudio.IOS.XamarinIOSPackage.: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.6394378Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering message handler for message type: Xamarin.Messaging.StopAgentMessage: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.6844384Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering message handler for message type: Xamarin.Messaging.RegisterAgentMessage: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7253871Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering message handler for message type: Xamarin.Messaging.GetActiveClientsMessage: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7423849Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Registering message handler for message type: Xamarin.Messaging.GetActiveAgentsMessage: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7493861Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Agent registered: Broker: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7593853Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Successfully started Broker in-process: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7633872Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:01.7633872Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Connecting to Local Broker...: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.7683853Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:01.7683853Z: 01/31/2025 14:28:01Z Xamarin.VisualStudio.IOS.AppleProjectCollector Information: 0 : Collecting new Apple project: Xamarin.Essentials.Release|AnyCPU|net8.0-ios.18.0: 01/31/2025 14:28:01Z DateTime=2025-01-31T14:28:01.8759090Z: 01/31/2025 14:28:01Z Xamarin.Messaging.Ssh.MessagingService Information: 0 : Agent Broker 17.12.0.153 is running: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.4620488Z: 01/31/2025 14:28:02Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Successfully connected to Local Broker: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.4660479Z: 01/31/2025 14:28:02Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:02.4660479Z: 01/31/2025 14:28:02Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Starting IDB Local Agent...: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.5026413Z: 01/31/2025 14:28:02Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:02.5026413Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Starting: IDB.Local 17.12.0.153 ( PID = 23960 ): 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.5041498Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Connecting Agent to the Broker...: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.5041498Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Initializing Agent context...: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.5051599Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering Agent message handlers...: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.6802565Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.GetAgentVersionMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.6802565Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.StopAgentMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.6812555Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : IDB Local Registering Handlers: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.6992670Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetMobileDeviceConfigurationMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7002665Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetDevicesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7087838Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.RefreshDevicesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7157798Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.DeployAppMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7277770Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.LaunchAppMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7357786Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.StopDebuggingAppMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7417781Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.AddDeveloperAccountMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7517793Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetDeveloperAccountsMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7587791Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetSigningIdentitiesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7647784Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetProvisioningProfilesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7707796Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.RemoveDeveloperAccountMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.7807797Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.SyncSigningIdentitiesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8272926Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.SyncProvisioningProfilesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8332901Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.DownloadProvisioningProfilesMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8442933Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.AutoProvisionMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8562922Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.CreateAppleCertificateMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8692927Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetProvisioningInformationMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8792929Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.CheckProvisioningStatusMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.8862928Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.ImportCertificateMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.9318145Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.GetSigningIdentityTypeMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.9408147Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.StartDeviceLogMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.9498940Z: 01/31/2025 14:28:02Z Xamarin.Messaging.IDB.Local.IDBLocalAgent Information: 0 : Registering message handler for message type: Xamarin.Messaging.IDB.Contracts.StopDeviceLogMessage: 01/31/2025 14:28:02Z DateTime=2025-01-31T14:28:02.9688934Z: 01/31/2025 14:28:02Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : Successfully started IDB Local Agent: 01/31/2025 14:28:03Z DateTime=2025-01-31T14:28:03.0475330Z: 01/31/2025 14:28:03Z Xamarin.VisualStudio.IOS.Messaging.LocalMessagingInitializer Information: 0 : DateTime=2025-01-31T14:28:03.0475330Z: 01/31/2025 14:28:03Z Xamarin.Messaging.Server.BrokerAgentInProcess Information: 0 : Agent registered: IDBLocal17120153: 01/31/2025 14:28:03Z DateTime=2025-01-31T14:28:03.0545330Z: 01/31/2025 14:28:03Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Checking xma 17.12.0.153 installation...: 01/31/2025 14:28:03Z DateTime=2025-01-31T14:28:03.0878763Z: 01/31/2025 14:28:03Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:03.0878763Z: 01/31/2025 14:28:03Z Xamarin.VisualStudio.IOS.AppleProjectCollector Information: 0 : Collecting new Apple project: dotStaff.iOS.Release|AnyCPU|net8.0-ios.18.0: 01/31/2025 14:28:05Z DateTime=2025-01-31T14:28:05.8916161Z: 01/31/2025 14:28:05Z Xamarin.VisualStudio.AssemblyRedirector Information: 0 : Redirecting assembly load of System.Reactive, Version=5.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263: 01/31/2025 14:28:12Z DateTime=2025-01-31T14:28:12.7275097Z: 01/31/2025 14:28:12Z Xamarin.VisualStudio.AssemblyRedirector Information: 0 : loaded by (unknown): 01/31/2025 14:28:12Z DateTime=2025-01-31T14:28:12.7275097Z: 01/31/2025 14:28:12Z Xamarin.VisualStudio.AssemblyRedirector Information: 0 : to version 6.0.0.0: 01/31/2025 14:28:12Z DateTime=2025-01-31T14:28:12.7275097Z: 01/31/2025 14:28:12Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from DisconnectedState to ConfiguringState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:16Z DateTime=2025-01-31T14:28:16.6774364Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking host configuration for connecting to 'inhqmb101155'...: 01/31/2025 14:28:16Z DateTime=2025-01-31T14:28:16.6974384Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:16.6974384Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking SSH configuration...: 01/31/2025 14:28:16Z DateTime=2025-01-31T14:28:16.7225350Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:16.7225350Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Ssh.SshInformationProvider Information: 0 : Current SSH Key File: C:\Users\mrhorse\AppData\Local\Xamarin\MonoTouch\id_xma.pub: 01/31/2025 14:28:16Z DateTime=2025-01-31T14:28:16.7265431Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Ssh.SshInformationProvider Information: 0 : DateTime=2025-01-31T14:28:16.7265431Z: 01/31/2025 14:28:16Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Initializing environment...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.2296070Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.2296070Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking available disk space...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.4108810Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.4108810Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Verifying dotnet runtime installation...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.4445531Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.4445531Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Ssh.SshCommands Information: 0 : dotnet runtimes for '/usr/local/share/dotnet/dotnet': Microsoft.AspNetCore.App 8.0.12 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 9.0.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 8.0.12 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 9.0.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.4852380Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking if Rosetta is installed...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.4932381Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.4932381Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking Mono installation...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.5745051Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.5745051Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Ssh.SshCommands Information: 0 : A valid Mono installation has been found at '/Library/Frameworks/Mono.framework/Versions/Current/bin/mono64': 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.8849347Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Checking host configuration for connecting to 'inhqmb101155'...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.9675145Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.9685127Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from ConfiguringState to ConfiguredState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.9705123Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Host 'inhqmb101155' is configured correctly: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.9780454Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.9780454Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from ConfiguredState to ConnectingState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.9790478Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Starting connection to 'inhqmb101155'...: 01/31/2025 14:28:17Z DateTime=2025-01-31T14:28:17.9830467Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:17.9830467Z: 01/31/2025 14:28:17Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Checking Broker 17.12.0.153 installation...: 01/31/2025 14:28:18Z DateTime=2025-01-31T14:28:18.1640296Z: 01/31/2025 14:28:18Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:18.1640296Z: 01/31/2025 14:28:18Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Starting Broker 17.12.0.153 in port 51976...: 01/31/2025 14:28:18Z DateTime=2025-01-31T14:28:18.9718900Z: 01/31/2025 14:28:18Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:18.9718900Z: 01/31/2025 14:28:18Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Broker 17.12.0.153 started successfully: 01/31/2025 14:28:19Z DateTime=2025-01-31T14:28:19.8808163Z: 01/31/2025 14:28:19Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:19.8808163Z: 01/31/2025 14:28:19Z Xamarin.Messaging.Ssh.MessagingService Information: 0 : Agent Broker 17.12.0.153 is running: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.0270315Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Starting connection to 'inhqmb101155'...: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.0722716Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:20.0722716Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from ConnectingState to SshConnectedState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.0732762Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : SSH connection to 'inhqmb101155' has been established...: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.0772752Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:20.0772752Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from SshConnectedState to AgentsStartingState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.0942776Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Starting registered Agents: IDB 17.12.0.153...: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.1022715Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:20.1022715Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Starting IDB 17.12.0.153...: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.1182797Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:20.1182797Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Checking IDB 17.12.0.153 installation...: 01/31/2025 14:28:20Z DateTime=2025-01-31T14:28:20.1192812Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:20.1192812Z: 01/31/2025 14:28:20Z Xamarin.Messaging.Ssh.MessagingService Information: 0 : Starting Agent IDB 17.12.0.153...: 01/31/2025 14:28:23Z DateTime=2025-01-31T14:28:23.7384941Z: 01/31/2025 14:28:23Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : Starting IDB 17.12.0.153 in port 51976...: 01/31/2025 14:28:23Z DateTime=2025-01-31T14:28:23.7384941Z: 01/31/2025 14:28:23Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:23.7384941Z: 01/31/2025 14:28:23Z Xamarin.Messaging.Client.MessageHandlerManager Error: 0 : An error occurred while handling a message of type Xamarin.Messaging.AgentStatusMessage System.ArgumentNullException: Value cannot be null. Parameter name: name at Xamarin.Messaging.AgentInfo..ctor(String name, String version, String instanceId) in D:\a\_work\1\s\src\Xamarin.Messaging.Common\AgentInfo.cs:line 24 at Xamarin.Messaging.Ssh.MessagingEvents.b__9_0(AgentStatusMessage message) in D:\a\_work\1\s\src\Xamarin.Messaging.Ssh\MessagingEvents.cs:line 26 at Xamarin.Messaging.Client.DefaultHandler`1.d__4.MoveNext() in D:\a\_work\1\s\src\Xamarin.Messaging.Client\Handlers\DefaultHandler.cs:line 24 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Xamarin.Messaging.Client.RequestHandler`1.d__5.MoveNext() in D:\a\_work\1\s\src\Xamarin.Messaging.Client\Handlers\RequestHandler.cs:line 34 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Xamarin.Messaging.Client.MessageHandlerManager.<>c__DisplayClass17_0`1.<b__0>d.MoveNext() in D:\a\_work\1\s\src\Xamarin.Messaging.Client\MessageHandlerManager.cs:line 148: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.4025463Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : IDB 17.12.0.153 started successfully: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8674103Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Ssh.MessagingCommands Information: 0 : DateTime=2025-01-31T14:28:24.8674103Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Ssh.MessagingService Information: 0 : Agent IDB 17.12.0.153 is running: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8674103Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : IDB 17.12.0.153 started: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8714122Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:24.8714122Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Starting registered Agents: ...: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8764110Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:24.8764110Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from AgentsStartingState to AgentsStartedState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8794116Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : The Agents have been started successfully: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8881158Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:24.8881158Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Server State transition from AgentsStartedState to ValidatingState on inhqmb101155 (10.40.20.30): 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8913706Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Performing server validations against 'inhqmb101155'...: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.8973746Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:24.8973746Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Setting up user remote session...: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.9053737Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:24.9053737Z: 01/31/2025 14:28:24Z Xamarin.VisualStudio.IOS.Messaging.DotNetSdkValidator Information: 0 : Selected project configuration for DotNet validation: C:\Repos\dotStaff_Mobile\CalendarExample\CalendarExample.csproj: CalendarExample.Debug|AnyCPU|net8.0-ios.18.0: 01/31/2025 14:28:24Z DateTime=2025-01-31T14:28:24.9275165Z: 01/31/2025 14:28:24Z Xamarin.VisualStudio.IOS.Messaging.DotNetSdkValidator Information: 0 : DateTime=2025-01-31T14:28:24.9275165Z: 01/31/2025 14:28:24Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Installing dotnet SDK '9.0.102-servicing.24611.3'...: 01/31/2025 14:28:25Z DateTime=2025-01-31T14:28:25.0487242Z: 01/31/2025 14:28:25Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:25.0487242Z: 01/31/2025 14:28:25Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Downloading dotnet-install script...: 01/31/2025 14:28:25Z DateTime=2025-01-31T14:28:25.0507237Z: 01/31/2025 14:28:25Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:25.0507237Z: 01/31/2025 14:28:25Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : --install-dir "/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet" --version 9.0.102-servicing.24611.3 --architecture Arm64 --no-path: 01/31/2025 14:28:38Z DateTime=2025-01-31T14:28:38.6209024Z: 01/31/2025 14:28:38Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:38.6209024Z: 01/31/2025 14:28:38Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Using dotnet install script '/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/scripts/dotnet-install.sh'...: 01/31/2025 14:28:38Z DateTime=2025-01-31T14:28:38.6391019Z: 01/31/2025 14:28:38Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:38.6391019Z: 01/31/2025 14:28:38Z Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : Could not install dotnet SDK '9.0.102-servicing.24611.3'. Details: /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/scripts/dotnet-install.sh: line 1440: link_types[$link_index]: unbound variable

: 01/31/2025 14:28:39Z
DateTime=2025-01-31T14:28:39.3335494Z: 01/31/2025 14:28:39Z
Xamarin.Messaging.Integration.State.ServerStateContext Information: 0 : DateTime=2025-01-31T14:28:39.3335494Z: 01/31/2025 14:28:39Z
Xamarin.Messaging.Client.MessagingClient Error: 0 : An error occurred on the receiver while executing a post for topic xvs/idb/initialize-dotnet-sdk and client vs23960rober
Xamarin.Messaging.Exceptions.MessagingRemoteException: An error occurred on client IDB17120153 while executing a reply for topic xvs/idb/initialize-dotnet-sdk ---> Xamarin.Messaging.IDB.Contracts.DotNetSdkInstallationException: Could not install dotnet SDK '9.0.102-servicing.24611.3'. Details: /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/scripts/dotnet-install.sh: line 1440: link_types[$link_index]: unbound variable

at Xamarin.Messaging.IDB.DotNetSdk.DotNetSdkManager.InstallSdkAsync(String, String , String , String )
at Xamarin.Messaging.IDB.InitializeDotNetSdkMessageHandler.ExecuteAsync(InitializeDotNetSdkMessage)
at Xamarin.Messaging.Client.RequestHandler2.HandleAsync(TMessage) at Xamarin.Messaging.Client.MessageHandlerManager.<>c__DisplayClass16_12.<b__2>d.MoveNext()
--- End of stack trace from previous location ---
at Xamarin.Messaging.Client.MessagingClient.ReplyAsync[TRequest,TResponse](IRequest1, MessagePriority, Func1)
--- End of inner exception stack trace ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Xamarin.Messaging.Client.ApplicationMessageExtensions.<>c__DisplayClass10_01.<OfResponse>b__1(MqttApplicationMessage m) in D:\a\_work\1\s\src\Xamarin.Messaging.Client\Extensions\ApplicationMessageExtensions.cs:line 194 at System.Reactive.Linq.ObservableImpl.Select2.Selector._.OnNext(TSource value)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Xamarin.Messaging.Client.MessagingClient.d__21`2.MoveNext() in D:\a_work\1\s\src\Xamarin.Messaging.Client\MessagingClient.cs:line 190: 01/31/2025 14:28:39Z
DateTime=2025-01-31T14:28:39.3647170Z: 01/31/2025 14:28:39Z

</details>
@baronfel
Copy link
Member

Can you attach the content of the dotnet-install scripts packaged by those tools? I suspect that they are using the out-of date versions of those scripts, and you might be impacted by the changes we've been forced to make by dotnet/core#9671.

@Mr-Horse
Copy link
Author

Mr-Horse commented Jan 31, 2025

Can you attach the content of the dotnet-install scripts packaged by those tools? I suspect that they are using the out-of date versions of those scripts, and you might be impacted by the changes we've been forced to make by dotnet/core#9671.

Here is the content, it won't allow me to add the file, even as a zip:

dotnet-install.sh ``` #!/usr/bin/env bash # Copyright (c) .NET Foundation and contributors. All rights reserved. # Licensed under the MIT license. See LICENSE file in the project root for full license information. #

Stop script on NZEC

set -e

Stop script if unbound variable found (use ${var:-} if intentional)

set -u

By default cmd1 | cmd2 returns exit code of cmd2 regardless of cmd1 success

This is causing it to fail

set -o pipefail

Use in the the functions: eval $invocation

invocation='say_verbose "Calling: ${yellow:-}${FUNCNAME[0]} ${green:-}$*${normal:-}"'

standard output may be used as a return value in the functions

we need a way to write text on the screen in the functions so that

it won't interfere with the return value.

Exposing stream 3 as a pipe to standard output of the script itself

exec 3>&1

Setup some colors to use. These need to work in fairly limited shells, like the Ubuntu Docker container where there are only 8 colors.

See if stdout is a terminal

if [ -t 1 ] && command -v tput > /dev/null; then
# see if it supports colors
ncolors=$(tput colors || echo 0)
if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
bold="$(tput bold || echo)"
normal="$(tput sgr0 || echo)"
black="$(tput setaf 0 || echo)"
red="$(tput setaf 1 || echo)"
green="$(tput setaf 2 || echo)"
yellow="$(tput setaf 3 || echo)"
blue="$(tput setaf 4 || echo)"
magenta="$(tput setaf 5 || echo)"
cyan="$(tput setaf 6 || echo)"
white="$(tput setaf 7 || echo)"
fi
fi

say_warning() {
printf "%b\n" "${yellow:-}dotnet_install: Warning: $1${normal:-}" >&3
}

say_err() {
printf "%b\n" "${red:-}dotnet_install: Error: $1${normal:-}" >&2
}

say() {
# using stream 3 (defined in the beginning) to not interfere with stdout of functions
# which may be used as return value
printf "%b\n" "${cyan:-}dotnet-install:${normal:-} $1" >&3
}

say_verbose() {
if [ "$verbose" = true ]; then
say "$1"
fi
}

This platform list is finite - if the SDK/Runtime has supported Linux distribution-specific assets,

then and only then should the Linux distribution appear in this list.

Adding a Linux distribution to this list does not imply distribution-specific support.

get_legacy_os_name_from_platform() {
eval $invocation

platform="$1"
case "$platform" in
    "centos.7")
        echo "centos"
        return 0
        ;;
    "debian.8")
        echo "debian"
        return 0
        ;;
    "debian.9")
        echo "debian.9"
        return 0
        ;;
    "fedora.23")
        echo "fedora.23"
        return 0
        ;;
    "fedora.24")
        echo "fedora.24"
        return 0
        ;;
    "fedora.27")
        echo "fedora.27"
        return 0
        ;;
    "fedora.28")
        echo "fedora.28"
        return 0
        ;;
    "opensuse.13.2")
        echo "opensuse.13.2"
        return 0
        ;;
    "opensuse.42.1")
        echo "opensuse.42.1"
        return 0
        ;;
    "opensuse.42.3")
        echo "opensuse.42.3"
        return 0
        ;;
    "rhel.7"*)
        echo "rhel"
        return 0
        ;;
    "ubuntu.14.04")
        echo "ubuntu"
        return 0
        ;;
    "ubuntu.16.04")
        echo "ubuntu.16.04"
        return 0
        ;;
    "ubuntu.16.10")
        echo "ubuntu.16.10"
        return 0
        ;;
    "ubuntu.18.04")
        echo "ubuntu.18.04"
        return 0
        ;;
    "alpine.3.4.3")
        echo "alpine"
        return 0
        ;;
esac
return 1

}

get_legacy_os_name() {
eval $invocation

local uname=$(uname)
if [ "$uname" = "Darwin" ]; then
    echo "osx"
    return 0
elif [ -n "$runtime_id" ]; then
    echo $(get_legacy_os_name_from_platform "${runtime_id%-*}" || echo "${runtime_id%-*}")
    return 0
else
    if [ -e /etc/os-release ]; then
        . /etc/os-release
        os=$(get_legacy_os_name_from_platform "$ID${VERSION_ID:+.${VERSION_ID}}" || echo "")
        if [ -n "$os" ]; then
            echo "$os"
            return 0
        fi
    fi
fi

say_verbose "Distribution specific OS name and version could not be detected: UName = $uname"
return 1

}

get_linux_platform_name() {
eval $invocation

if [ -n "$runtime_id" ]; then
    echo "${runtime_id%-*}"
    return 0
else
    if [ -e /etc/os-release ]; then
        . /etc/os-release
        echo "$ID${VERSION_ID:+.${VERSION_ID}}"
        return 0
    elif [ -e /etc/redhat-release ]; then
        local redhatRelease=$(</etc/redhat-release)
        if [[ $redhatRelease == "CentOS release 6."* || $redhatRelease == "Red Hat Enterprise Linux "*" release 6."* ]]; then
            echo "rhel.6"
            return 0
        fi
    fi
fi

say_verbose "Linux specific platform name and version could not be detected: UName = $uname"
return 1

}

is_musl_based_distro() {
(ldd --version 2>&1 || true) | grep -q musl
}

get_current_os_name() {
eval $invocation

local uname=$(uname)
if [ "$uname" = "Darwin" ]; then
    echo "osx"
    return 0
elif [ "$uname" = "FreeBSD" ]; then
    echo "freebsd"
    return 0
elif [ "$uname" = "Linux" ]; then
    local linux_platform_name=""
    linux_platform_name="$(get_linux_platform_name)" || true

    if [ "$linux_platform_name" = "rhel.6" ]; then
        echo $linux_platform_name
        return 0
    elif is_musl_based_distro; then
        echo "linux-musl"
        return 0
    elif [ "$linux_platform_name" = "linux-musl" ]; then
        echo "linux-musl"
        return 0
    else
        echo "linux"
        return 0
    fi
fi

say_err "OS name could not be detected: UName = $uname"
return 1

}

machine_has() {
eval $invocation

command -v "$1" > /dev/null 2>&1
return $?

}

check_min_reqs() {
local hasMinimum=false
if machine_has "curl"; then
hasMinimum=true
elif machine_has "wget"; then
hasMinimum=true
fi

if [ "$hasMinimum" = "false" ]; then
    say_err "curl (recommended) or wget are required to download dotnet. Install missing prerequisite to proceed."
    return 1
fi
return 0

}

args:

input - $1

to_lowercase() {
#eval $invocation

echo "$1" | tr '[:upper:]' '[:lower:]'
return 0

}

args:

input - $1

remove_trailing_slash() {
#eval $invocation

local input="${1:-}"
echo "${input%/}"
return 0

}

args:

input - $1

remove_beginning_slash() {
#eval $invocation

local input="${1:-}"
echo "${input#/}"
return 0

}

args:

root_path - $1

child_path - $2 - this parameter can be empty

combine_paths() {
eval $invocation

# TODO: Consider making it work with any number of paths. For now:
if [ ! -z "${3:-}" ]; then
    say_err "combine_paths: Function takes two parameters."
    return 1
fi

local root_path="$(remove_trailing_slash "$1")"
local child_path="$(remove_beginning_slash "${2:-}")"
say_verbose "combine_paths: root_path=$root_path"
say_verbose "combine_paths: child_path=$child_path"
echo "$root_path/$child_path"
return 0

}

get_machine_architecture() {
eval $invocation

if command -v uname > /dev/null; then
    CPUName=$(uname -m)
    case $CPUName in
    armv1*|armv2*|armv3*|armv4*|armv5*|armv6*)
        echo "armv6-or-below"
        return 0
        ;;
    armv*l)
        echo "arm"
        return 0
        ;;
    aarch64|arm64)
        if [ "$(getconf LONG_BIT)" -lt 64 ]; then
            # This is 32-bit OS running on 64-bit CPU (for example Raspberry Pi OS)
            echo "arm"
            return 0
        fi
        echo "arm64"
        return 0
        ;;
    s390x)
        echo "s390x"
        return 0
        ;;
    ppc64le)
        echo "ppc64le"
        return 0
        ;;
    loongarch64)
        echo "loongarch64"
        return 0
        ;;
    riscv64)
        echo "riscv64"
        return 0
        ;;
    powerpc|ppc)
        echo "ppc"
        return 0
        ;;
    esac
fi

# Always default to 'x64'
echo "x64"
return 0

}

args:

architecture - $1

get_normalized_architecture_from_architecture() {
eval $invocation

local architecture="$(to_lowercase "$1")"

if [[ $architecture == \<auto\> ]]; then
    machine_architecture="$(get_machine_architecture)"
    if [[ "$machine_architecture" == "armv6-or-below" ]]; then
        say_err "Architecture \`$machine_architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
        return 1
    fi

    echo $machine_architecture
    return 0
fi

case "$architecture" in
    amd64|x64)
        echo "x64"
        return 0
        ;;
    arm)
        echo "arm"
        return 0
        ;;
    arm64)
        echo "arm64"
        return 0
        ;;
    s390x)
        echo "s390x"
        return 0
        ;;
    ppc64le)
        echo "ppc64le"
        return 0
        ;;
    loongarch64)
        echo "loongarch64"
        return 0
        ;;
esac

say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
return 1

}

args:

version - $1

channel - $2

architecture - $3

get_normalized_architecture_for_specific_sdk_version() {
eval $invocation

local is_version_support_arm64="$(is_arm64_supported "$1")"
local is_channel_support_arm64="$(is_arm64_supported "$2")"
local architecture="$3";
local osname="$(get_current_os_name)"

if [ "$osname" == "osx" ] && [ "$architecture" == "arm64" ] && { [ "$is_version_support_arm64" = false ] || [ "$is_channel_support_arm64" = false ]; }; then
    #check if rosetta is installed
    if [ "$(/usr/bin/pgrep oahd >/dev/null 2>&1;echo $?)" -eq 0 ]; then 
        say_verbose "Changing user architecture from '$architecture' to 'x64' because .NET SDKs prior to version 6.0 do not support arm64." 
        echo "x64"
        return 0;
    else
        say_err "Architecture \`$architecture\` is not supported for .NET SDK version \`$version\`. Please install Rosetta to allow emulation of the \`$architecture\` .NET SDK on this platform"
        return 1
    fi
fi

echo "$architecture"
return 0

}

args:

version or channel - $1

is_arm64_supported() {
# Extract the major version by splitting on the dot
major_version="${1%%.*}"

# Check if the major version is a valid number and less than 6
case "$major_version" in
    [0-9]*)  
        if [ "$major_version" -lt 6 ]; then
            echo false
            return 0
        fi
        ;;
esac

echo true
return 0

}

args:

user_defined_os - $1

get_normalized_os() {
eval $invocation

local osname="$(to_lowercase "$1")"
if [ ! -z "$osname" ]; then
    case "$osname" in
        osx | freebsd | rhel.6 | linux-musl | linux)
            echo "$osname"
            return 0
            ;;
        macOS)
            osname='osx'
            echo "$osname"
            return 0
            ;;
        *)
            say_err "'$user_defined_os' is not a supported value for --os option, supported values are: osx, macos, linux, linux-musl, freebsd, rhel.6. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
            return 1
            ;;
    esac
else
    osname="$(get_current_os_name)" || return 1
fi
echo "$osname"
return 0

}

args:

quality - $1

get_normalized_quality() {
eval $invocation

local quality="$(to_lowercase "$1")"
if [ ! -z "$quality" ]; then
    case "$quality" in
        daily | signed | validated | preview)
            echo "$quality"
            return 0
            ;;
        ga)
            #ga quality is available without specifying quality, so normalizing it to empty
            return 0
            ;;
        *)
            say_err "'$quality' is not a supported value for --quality option. Supported values are: daily, signed, validated, preview, ga. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues."
            return 1
            ;;
    esac
fi
return 0

}

args:

channel - $1

get_normalized_channel() {
eval $invocation

local channel="$(to_lowercase "$1")"

if [[ $channel == current ]]; then
    say_warning 'Value "Current" is deprecated for -Channel option. Use "STS" instead.'
fi

if [[ $channel == release/* ]]; then
    say_warning 'Using branch name with -Channel option is no longer supported with newer releases. Use -Quality option with a channel in X.Y format instead.';
fi

if [ ! -z "$channel" ]; then
    case "$channel" in
        lts)
            echo "LTS"
            return 0
            ;;
        sts)
            echo "STS"
            return 0
            ;;
        current)
            echo "STS"
            return 0
            ;;
        *)
            echo "$channel"
            return 0
            ;;
    esac
fi

return 0

}

args:

runtime - $1

get_normalized_product() {
eval $invocation

local product=""
local runtime="$(to_lowercase "$1")"
if [[ "$runtime" == "dotnet" ]]; then
    product="dotnet-runtime"
elif [[ "$runtime" == "aspnetcore" ]]; then
    product="aspnetcore-runtime"
elif [ -z "$runtime" ]; then
    product="dotnet-sdk"
fi
echo "$product"
return 0

}

The version text returned from the feeds is a 1-line or 2-line string:

For the SDK and the dotnet runtime (2 lines):

Line 1: # commit_hash

Line 2: # 4-part version

For the aspnetcore runtime (1 line):

Line 1: # 4-part version

args:

version_text - stdin

get_version_from_latestversion_file_content() {
eval $invocation

cat | tail -n 1 | sed 's/\r$//'
return 0

}

args:

install_root - $1

relative_path_to_package - $2

specific_version - $3

is_dotnet_package_installed() {
eval $invocation

local install_root="$1"
local relative_path_to_package="$2"
local specific_version="${3//[$'\t\r\n']}"

local dotnet_package_path="$(combine_paths "$(combine_paths "$install_root" "$relative_path_to_package")" "$specific_version")"
say_verbose "is_dotnet_package_installed: dotnet_package_path=$dotnet_package_path"

if [ -d "$dotnet_package_path" ]; then
    return 0
else
    return 1
fi

}

args:

downloaded file - $1

remote_file_size - $2

validate_remote_local_file_sizes()
{
eval $invocation

local downloaded_file="$1"
local remote_file_size="$2"
local file_size=''

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
    file_size="$(stat -c '%s' "$downloaded_file")"
elif [[ "$OSTYPE" == "darwin"* ]]; then
    # hardcode in order to avoid conflicts with GNU stat
    file_size="$(/usr/bin/stat -f '%z' "$downloaded_file")"
fi  

if [ -n "$file_size" ]; then
    say "Downloaded file size is $file_size bytes."

    if [ -n "$remote_file_size" ] && [ -n "$file_size" ]; then
        if [ "$remote_file_size" -ne "$file_size" ]; then
            say "The remote and local file sizes are not equal. The remote file size is $remote_file_size bytes and the local size is $file_size bytes. The local package may be corrupted."
        else
            say "The remote and local file sizes are equal."
        fi
    fi
    
else
    say "Either downloaded or local package size can not be measured. One of them may be corrupted."      
fi 

}

args:

azure_feed - $1

channel - $2

normalized_architecture - $3

get_version_from_latestversion_file() {
eval $invocation

local azure_feed="$1"
local channel="$2"
local normalized_architecture="$3"

local version_file_url=null
if [[ "$runtime" == "dotnet" ]]; then
    version_file_url="$azure_feed/Runtime/$channel/latest.version"
elif [[ "$runtime" == "aspnetcore" ]]; then
    version_file_url="$azure_feed/aspnetcore/Runtime/$channel/latest.version"
elif [ -z "$runtime" ]; then
     version_file_url="$azure_feed/Sdk/$channel/latest.version"
else
    say_err "Invalid value for \$runtime"
    return 1
fi
say_verbose "get_version_from_latestversion_file: latest url: $version_file_url"

download "$version_file_url" || return $?
return 0

}

args:

json_file - $1

parse_globaljson_file_for_version() {
eval $invocation

local json_file="$1"
if [ ! -f "$json_file" ]; then
    say_err "Unable to find \`$json_file\`"
    return 1
fi

sdk_section=$(cat $json_file | tr -d "\r" | awk '/"sdk"/,/}/')
if [ -z "$sdk_section" ]; then
    say_err "Unable to parse the SDK node in \`$json_file\`"
    return 1
fi

sdk_list=$(echo $sdk_section | awk -F"[{}]" '{print $2}')
sdk_list=${sdk_list//[\" ]/}
sdk_list=${sdk_list//,/$'\n'}

local version_info=""
while read -r line; do
  IFS=:
  while read -r key value; do
    if [[ "$key" == "version" ]]; then
      version_info=$value
    fi
  done <<< "$line"
done <<< "$sdk_list"
if [ -z "$version_info" ]; then
    say_err "Unable to find the SDK:version node in \`$json_file\`"
    return 1
fi

unset IFS;
echo "$version_info"
return 0

}

args:

azure_feed - $1

channel - $2

normalized_architecture - $3

version - $4

json_file - $5

get_specific_version_from_version() {
eval $invocation

local azure_feed="$1"
local channel="$2"
local normalized_architecture="$3"
local version="$(to_lowercase "$4")"
local json_file="$5"

if [ -z "$json_file" ]; then
    if [[ "$version" == "latest" ]]; then
        local version_info
        version_info="$(get_version_from_latestversion_file "$azure_feed" "$channel" "$normalized_architecture" false)" || return 1
        say_verbose "get_specific_version_from_version: version_info=$version_info"
        echo "$version_info" | get_version_from_latestversion_file_content
        return 0
    else
        echo "$version"
        return 0
    fi
else
    local version_info
    version_info="$(parse_globaljson_file_for_version "$json_file")" || return 1
    echo "$version_info"
    return 0
fi

}

args:

azure_feed - $1

channel - $2

normalized_architecture - $3

specific_version - $4

normalized_os - $5

construct_download_link() {
eval $invocation

local azure_feed="$1"
local channel="$2"
local normalized_architecture="$3"
local specific_version="${4//[$'\t\r\n']}"
local specific_product_version="$(get_specific_product_version "$1" "$4")"
local osname="$5"

local download_link=null
if [[ "$runtime" == "dotnet" ]]; then
    download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
elif [[ "$runtime" == "aspnetcore" ]]; then
    download_link="$azure_feed/aspnetcore/Runtime/$specific_version/aspnetcore-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
elif [ -z "$runtime" ]; then
    download_link="$azure_feed/Sdk/$specific_version/dotnet-sdk-$specific_product_version-$osname-$normalized_architecture.tar.gz"
else
    return 1
fi

echo "$download_link"
return 0

}

args:

azure_feed - $1

specific_version - $2

download link - $3 (optional)

get_specific_product_version() {
# If we find a 'productVersion.txt' at the root of any folder, we'll use its contents
# to resolve the version of what's in the folder, superseding the specified version.
# if 'productVersion.txt' is missing but download link is already available, product version will be taken from download link
eval $invocation

local azure_feed="$1"
local specific_version="${2//[$'\t\r\n']}"
local package_download_link=""
if [ $# -gt 2  ]; then
    local package_download_link="$3"
fi
local specific_product_version=null

# Try to get the version number, using the productVersion.txt file located next to the installer file.
local download_links=($(get_specific_product_version_url "$azure_feed" "$specific_version" true "$package_download_link")
    $(get_specific_product_version_url "$azure_feed" "$specific_version" false "$package_download_link"))

for download_link in "${download_links[@]}"
do
    say_verbose "Checking for the existence of $download_link"

    if machine_has "curl"
    then
        if ! specific_product_version=$(curl -s --fail "${download_link}${feed_credential}" 2>&1); then
            continue
        else
            echo "${specific_product_version//[$'\t\r\n']}"
            return 0
        fi

    elif machine_has "wget"
    then
        specific_product_version=$(wget -qO- "${download_link}${feed_credential}" 2>&1)
        if [ $? = 0 ]; then
            echo "${specific_product_version//[$'\t\r\n']}"
            return 0
        fi
    fi
done

# Getting the version number with productVersion.txt has failed. Try parsing the download link for a version number.
say_verbose "Failed to get the version using productVersion.txt file. Download link will be parsed instead."
specific_product_version="$(get_product_specific_version_from_download_link "$package_download_link" "$specific_version")"
echo "${specific_product_version//[$'\t\r\n']}"
return 0

}

args:

azure_feed - $1

specific_version - $2

is_flattened - $3

download link - $4 (optional)

get_specific_product_version_url() {
eval $invocation

local azure_feed="$1"
local specific_version="$2"
local is_flattened="$3"
local package_download_link=""
if [ $# -gt 3  ]; then
    local package_download_link="$4"
fi

local pvFileName="productVersion.txt"
if [ "$is_flattened" = true ]; then
    if [ -z "$runtime" ]; then
        pvFileName="sdk-productVersion.txt"
    elif [[ "$runtime" == "dotnet" ]]; then
        pvFileName="runtime-productVersion.txt"
    else
        pvFileName="$runtime-productVersion.txt"
    fi
fi

local download_link=null

if [ -z "$package_download_link" ]; then
    if [[ "$runtime" == "dotnet" ]]; then
        download_link="$azure_feed/Runtime/$specific_version/${pvFileName}"
    elif [[ "$runtime" == "aspnetcore" ]]; then
        download_link="$azure_feed/aspnetcore/Runtime/$specific_version/${pvFileName}"
    elif [ -z "$runtime" ]; then
        download_link="$azure_feed/Sdk/$specific_version/${pvFileName}"
    else
        return 1
    fi
else
    download_link="${package_download_link%/*}/${pvFileName}"
fi

say_verbose "Constructed productVersion link: $download_link"
echo "$download_link"
return 0

}

args:

download link - $1

specific version - $2

get_product_specific_version_from_download_link()
{
eval $invocation

local download_link="$1"
local specific_version="$2"
local specific_product_version="" 

if [ -z "$download_link" ]; then
    echo "$specific_version"
    return 0
fi

#get filename
filename="${download_link##*/}"

#product specific version follows the product name
#for filename 'dotnet-sdk-3.1.404-linux-x64.tar.gz': the product version is 3.1.404
IFS='-'
read -ra filename_elems <<< "$filename"
count=${#filename_elems[@]}
if [[ "$count" -gt 2 ]]; then
    specific_product_version="${filename_elems[2]}"
else
    specific_product_version=$specific_version
fi
unset IFS;
echo "$specific_product_version"
return 0

}

args:

azure_feed - $1

channel - $2

normalized_architecture - $3

specific_version - $4

construct_legacy_download_link() {
eval $invocation

local azure_feed="$1"
local channel="$2"
local normalized_architecture="$3"
local specific_version="${4//[$'\t\r\n']}"

local distro_specific_osname
distro_specific_osname="$(get_legacy_os_name)" || return 1

local legacy_download_link=null
if [[ "$runtime" == "dotnet" ]]; then
    legacy_download_link="$azure_feed/Runtime/$specific_version/dotnet-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz"
elif [ -z "$runtime" ]; then
    legacy_download_link="$azure_feed/Sdk/$specific_version/dotnet-dev-$distro_specific_osname-$normalized_architecture.$specific_version.tar.gz"
else
    return 1
fi

echo "$legacy_download_link"
return 0

}

get_user_install_path() {
eval $invocation

if [ ! -z "${DOTNET_INSTALL_DIR:-}" ]; then
    echo "$DOTNET_INSTALL_DIR"
else
    echo "$HOME/.dotnet"
fi
return 0

}

args:

install_dir - $1

resolve_installation_path() {
eval $invocation

local install_dir=$1
if [ "$install_dir" = "<auto>" ]; then
    local user_install_path="$(get_user_install_path)"
    say_verbose "resolve_installation_path: user_install_path=$user_install_path"
    echo "$user_install_path"
    return 0
fi

echo "$install_dir"
return 0

}

args:

relative_or_absolute_path - $1

get_absolute_path() {
eval $invocation

local relative_or_absolute_path=$1
echo "$(cd "$(dirname "$1")" && pwd -P)/$(basename "$1")"
return 0

}

args:

override - $1 (boolean, true or false)

get_cp_options() {
eval $invocation

local override="$1"
local override_switch=""

if [ "$override" = false ]; then
    override_switch="-n"

    # create temporary files to check if 'cp -u' is supported
    tmp_dir="$(mktemp -d)"
    tmp_file="$tmp_dir/testfile"
    tmp_file2="$tmp_dir/testfile2"

    touch "$tmp_file"

    # use -u instead of -n if it's available
    if cp -u "$tmp_file" "$tmp_file2" 2>/dev/null; then
        override_switch="-u"
    fi

    # clean up
    rm -f "$tmp_file" "$tmp_file2"
    rm -rf "$tmp_dir"
fi

echo "$override_switch"

}

args:

input_files - stdin

root_path - $1

out_path - $2

override - $3

copy_files_or_dirs_from_list() {
eval $invocation

local root_path="$(remove_trailing_slash "$1")"
local out_path="$(remove_trailing_slash "$2")"
local override="$3"
local override_switch="$(get_cp_options "$override")"

cat | uniq | while read -r file_path; do
    local path="$(remove_beginning_slash "${file_path#$root_path}")"
    local target="$out_path/$path"
    if [ "$override" = true ] || (! ([ -d "$target" ] || [ -e "$target" ])); then
        mkdir -p "$out_path/$(dirname "$path")"
        if [ -d "$target" ]; then
            rm -rf "$target"
        fi
        cp -R $override_switch "$root_path/$path" "$target"
    fi
done

}

args:

zip_uri - $1

get_remote_file_size() {
local zip_uri="$1"

if machine_has "curl"; then
    file_size=$(curl -sI  "$zip_uri" | grep -i content-length | awk '{ num = $2 + 0; print num }')
elif machine_has "wget"; then
    file_size=$(wget --spider --server-response -O /dev/null "$zip_uri" 2>&1 | grep -i 'Content-Length:' | awk '{ num = $2 + 0; print num }')
else
    say "Neither curl nor wget is available on this system."
    return
fi

if [ -n "$file_size" ]; then
    say "Remote file $zip_uri size is $file_size bytes."
    echo "$file_size"
else
    say_verbose "Content-Length header was not extracted for $zip_uri."
    echo ""
fi

}

args:

zip_path - $1

out_path - $2

remote_file_size - $3

extract_dotnet_package() {
eval $invocation

local zip_path="$1"
local out_path="$2"
local remote_file_size="$3"

local temp_out_path="$(mktemp -d "$temporary_file_template")"

local failed=false
tar -xzf "$zip_path" -C "$temp_out_path" > /dev/null || failed=true

local folders_with_version_regex='^.*/[0-9]+\.[0-9]+[^/]+/'
find "$temp_out_path" -type f | grep -Eo "$folders_with_version_regex" | sort | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" false
find "$temp_out_path" -type f | grep -Ev "$folders_with_version_regex" | copy_files_or_dirs_from_list "$temp_out_path" "$out_path" "$override_non_versioned_files"

validate_remote_local_file_sizes "$zip_path" "$remote_file_size"

rm -rf "$temp_out_path"
if [ -z ${keep_zip+x} ]; then
    rm -f "$zip_path" && say_verbose "Temporary archive file $zip_path was removed"
fi

if [ "$failed" = true ]; then
    say_err "Extraction failed"
    return 1
fi
return 0

}

args:

remote_path - $1

disable_feed_credential - $2

get_http_header()
{
eval $invocation
local remote_path="$1"
local disable_feed_credential="$2"

local failed=false
local response
if machine_has "curl"; then
    get_http_header_curl $remote_path $disable_feed_credential || failed=true
elif machine_has "wget"; then
    get_http_header_wget $remote_path $disable_feed_credential || failed=true
else
    failed=true
fi
if [ "$failed" = true ]; then
    say_verbose "Failed to get HTTP header: '$remote_path'."
    return 1
fi
return 0

}

args:

remote_path - $1

disable_feed_credential - $2

get_http_header_curl() {
eval $invocation
local remote_path="$1"
local disable_feed_credential="$2"

remote_path_with_credential="$remote_path"
if [ "$disable_feed_credential" = false ]; then
    remote_path_with_credential+="$feed_credential"
fi

curl_options="-I -sSL --retry 5 --retry-delay 2 --connect-timeout 15 "
curl $curl_options "$remote_path_with_credential" 2>&1 || return 1
return 0

}

args:

remote_path - $1

disable_feed_credential - $2

get_http_header_wget() {
eval $invocation
local remote_path="$1"
local disable_feed_credential="$2"
local wget_options="-q -S --spider --tries 5 "

local wget_options_extra=''

# Test for options that aren't supported on all wget implementations.
if [[ $(wget -h 2>&1 | grep -E 'waitretry|connect-timeout') ]]; then
    wget_options_extra="--waitretry 2 --connect-timeout 15 "
else
    say "wget extra options are unavailable for this environment"
fi

remote_path_with_credential="$remote_path"
if [ "$disable_feed_credential" = false ]; then
    remote_path_with_credential+="$feed_credential"
fi

wget $wget_options $wget_options_extra "$remote_path_with_credential" 2>&1

return $?

}

args:

remote_path - $1

[out_path] - $2 - stdout if not provided

download() {
eval $invocation

local remote_path="$1"
local out_path="${2:-}"

if [[ "$remote_path" != "http"* ]]; then
    cp "$remote_path" "$out_path"
    return $?
fi

local failed=false
local attempts=0
while [ $attempts -lt 3 ]; do
    attempts=$((attempts+1))
    failed=false
    if machine_has "curl"; then
        downloadcurl "$remote_path" "$out_path" || failed=true
    elif machine_has "wget"; then
        downloadwget "$remote_path" "$out_path" || failed=true
    else
        say_err "Missing dependency: neither curl nor wget was found."
        exit 1
    fi

    if [ "$failed" = false ] || [ $attempts -ge 3 ] || { [ ! -z $http_code ] && [ $http_code = "404" ]; }; then
        break
    fi

    say "Download attempt #$attempts has failed: $http_code $download_error_msg"
    say "Attempt #$((attempts+1)) will start in $((attempts*10)) seconds."
    sleep $((attempts*10))
done

if [ "$failed" = true ]; then
    say_verbose "Download failed: $remote_path"
    return 1
fi
return 0

}

Updates global variables $http_code and $download_error_msg

downloadcurl() {
eval $invocation
unset http_code
unset download_error_msg
local remote_path="$1"
local out_path="${2:-}"
# Append feed_credential as late as possible before calling curl to avoid logging feed_credential
# Avoid passing URI with credentials to functions: note, most of them echoing parameters of invocation in verbose output.
local remote_path_with_credential="${remote_path}${feed_credential}"
local curl_options="--retry 20 --retry-delay 2 --connect-timeout 15 -sSL -f --create-dirs "
local curl_exit_code=0;
if [ -z "$out_path" ]; then
curl $curl_options "$remote_path_with_credential" 2>&1
curl_exit_code=$?
else
curl $curl_options -o "$out_path" "$remote_path_with_credential" 2>&1
curl_exit_code=$?
fi

if [ $curl_exit_code -gt 0 ]; then
    download_error_msg="Unable to download $remote_path."
    # Check for curl timeout codes
    if [[ $curl_exit_code == 7 || $curl_exit_code == 28 ]]; then
        download_error_msg+=" Failed to reach the server: connection timeout."
    else
        local disable_feed_credential=false
        local response=$(get_http_header_curl $remote_path $disable_feed_credential)
        http_code=$( echo "$response" | awk '/^HTTP/{print $2}' | tail -1 )
        if  [[ ! -z $http_code && $http_code != 2* ]]; then
            download_error_msg+=" Returned HTTP status code: $http_code."
        fi
    fi
    say_verbose "$download_error_msg"
    return 1
fi
return 0

}

Updates global variables $http_code and $download_error_msg

downloadwget() {
eval $invocation
unset http_code
unset download_error_msg
local remote_path="$1"
local out_path="${2:-}"
# Append feed_credential as late as possible before calling wget to avoid logging feed_credential
local remote_path_with_credential="${remote_path}${feed_credential}"
local wget_options="--tries 20 "

local wget_options_extra=''
local wget_result=''

# Test for options that aren't supported on all wget implementations.
if [[ $(wget -h 2>&1 | grep -E 'waitretry|connect-timeout') ]]; then
    wget_options_extra="--waitretry 2 --connect-timeout 15 "
else
    say "wget extra options are unavailable for this environment"
fi

if [ -z "$out_path" ]; then
    wget -q $wget_options $wget_options_extra -O - "$remote_path_with_credential" 2>&1
    wget_result=$?
else
    wget $wget_options $wget_options_extra -O "$out_path" "$remote_path_with_credential" 2>&1
    wget_result=$?
fi

if [[ $wget_result != 0 ]]; then
    local disable_feed_credential=false
    local response=$(get_http_header_wget $remote_path $disable_feed_credential)
    http_code=$( echo "$response" | awk '/^  HTTP/{print $2}' | tail -1 )
    download_error_msg="Unable to download $remote_path."
    if  [[ ! -z $http_code && $http_code != 2* ]]; then
        download_error_msg+=" Returned HTTP status code: $http_code."
    # wget exit code 4 stands for network-issue
    elif [[ $wget_result == 4 ]]; then
        download_error_msg+=" Failed to reach the server: connection timeout."
    fi
    say_verbose "$download_error_msg"
    return 1
fi

return 0

}

extract_stem() {
local url="$1"
# extract the protocol
proto="$(echo $1 | grep :// | sed -e's,^(.://).,\1,g')"
# remove the protocol
url="${1/$proto/}"
# extract the path (if any) - since we know all of our feeds have a first path segment, we can skip the first one. otherwise we'd use -f2- to get the full path
full_path="$(echo $url | grep / | cut -d/ -f2-)"
path="$(echo $full_path | cut -d/ -f2-)"
echo $path
}

check_url_exists() {
eval $invocation
local url="$1"

local code=""
if machine_has "curl"
then
    code=$(curl --head -o /dev/null -w "%{http_code}" -s --fail "$url");
elif machine_has "wget"
then
    # get the http response, grab the status code
    server_response=$(wget -qO- --method=HEAD --server-response "$url" 2>&1)
    code=$(echo "$server_response" | grep "HTTP/" | awk '{print $2}')
fi
if [ $code = "200" ]; then
    return 0
else
    return 1
fi

}

sanitize_redirect_url() {
eval $invocation

local url_stem
url_stem=$(extract_stem "$1")
say_verbose "Checking configured feeds for the asset at ${yellow:-}$url_stem${normal:-}"

for feed in "${feeds[@]}"
do
    local trial_url="$feed/$url_stem"
    say_verbose "Checking ${yellow:-}$trial_url${normal:-}"
    if check_url_exists "$trial_url"; then
        say_verbose "Found a match at ${yellow:-}$trial_url${normal:-}"
        echo "$trial_url"
        return 0
    else
        say_verbose "No match at ${yellow:-}$trial_url${normal:-}"
    fi
done
return 1

}

get_download_link_from_aka_ms() {
eval $invocation

#quality is not supported for LTS or STS channel
#STS maps to current
if [[ ! -z "$normalized_quality"  && ("$normalized_channel" == "LTS" || "$normalized_channel" == "STS") ]]; then
    normalized_quality=""
    say_warning "Specifying quality for STS or LTS channel is not supported, the quality will be ignored."
fi

say_verbose "Retrieving primary payload URL from aka.ms for channel: '$normalized_channel', quality: '$normalized_quality', product: '$normalized_product', os: '$normalized_os', architecture: '$normalized_architecture'." 

#construct aka.ms link
aka_ms_link="https://aka.ms/dotnet"
if  [ "$internal" = true ]; then
    aka_ms_link="$aka_ms_link/internal"
fi
aka_ms_link="$aka_ms_link/$normalized_channel"
if [[ ! -z "$normalized_quality" ]]; then
    aka_ms_link="$aka_ms_link/$normalized_quality"
fi
aka_ms_link="$aka_ms_link/$normalized_product-$normalized_os-$normalized_architecture.tar.gz"
say_verbose "Constructed aka.ms link: '$aka_ms_link'."

#get HTTP response
#do not pass credentials as a part of the $aka_ms_link and do not apply credentials in the get_http_header function
#otherwise the redirect link would have credentials as well
#it would result in applying credentials twice to the resulting link and thus breaking it, and in echoing credentials to the output as a part of redirect link
disable_feed_credential=true
response="$(get_http_header $aka_ms_link $disable_feed_credential)"

say_verbose "Received response: $response"
# Get results of all the redirects.
http_codes=$( echo "$response" | awk '$1 ~ /^HTTP/ {print $2}' )
# They all need to be 301, otherwise some links are broken (except for the last, which is not a redirect but 200 or 404).
broken_redirects=$( echo "$http_codes" | sed '$d' | grep -v '301' )
# The response may end without final code 2xx/4xx/5xx somehow, e.g. network restrictions on www.bing.com causes redirecting to bing.com fails with connection refused.
# In this case it should not exclude the last.
last_http_code=$(  echo "$http_codes" | tail -n 1 )
if ! [[ $last_http_code =~ ^(2|4|5)[0-9][0-9]$ ]]; then
    broken_redirects=$( echo "$http_codes" | grep -v '301' )
fi

# All HTTP codes are 301 (Moved Permanently), the redirect link exists.
if [[ -z "$broken_redirects" ]]; then
    aka_ms_download_link=$( echo "$response" | awk '$1 ~ /^Location/{print $2}' | tail -1 | tr -d '\r')

    if [[ -z "$aka_ms_download_link" ]]; then
        say_verbose "The aka.ms link '$aka_ms_link' is not valid: failed to get redirect location."
        return 1
    fi

    sanitized_redirect_url=$(sanitize_redirect_url "$aka_ms_download_link")
    if [[ -n "$sanitized_redirect_url" ]]; then
        aka_ms_download_link="$sanitized_redirect_url"
    fi

    say_verbose "The redirect location retrieved: '$aka_ms_download_link'."
    return 0
else
    say_verbose "The aka.ms link '$aka_ms_link' is not valid: received HTTP code: $(echo "$broken_redirects" | paste -sd "," -)."
    return 1
fi

}

get_feeds_to_use()
{
feeds=(
"https://builds.dotnet.microsoft.com/dotnet"
"https://ci.dot.net/public"
)

if [[ -n "$azure_feed" ]]; then
    feeds=("$azure_feed")
fi

if [[ -n "$uncached_feed" ]]; then
    feeds=("$uncached_feed")
fi

}

THIS FUNCTION MAY EXIT (if the determined version is already installed).

generate_download_links() {

download_links=()
specific_versions=()
effective_versions=()
link_types=()

# If generate_akams_links returns false, no fallback to old links. Just terminate.
# This function may also 'exit' (if the determined version is already installed).
generate_akams_links || return

# Check other feeds only if we haven't been able to find an aka.ms link.
if [[ "${#download_links[@]}" -lt 1 ]]; then
    for feed in ${feeds[@]}
    do
        # generate_regular_links may also 'exit' (if the determined version is already installed).
        generate_regular_links $feed || return
    done
fi

if [[ "${#download_links[@]}" -eq 0 ]]; then
    say_err "Failed to resolve the exact version number."
    return 1
fi

say_verbose "Generated ${#download_links[@]} links."
for link_index in ${!download_links[@]}
do
    say_verbose "Link $link_index: ${link_types[$link_index]}, ${effective_versions[$link_index]}, ${download_links[$link_index]}"
done

}

THIS FUNCTION MAY EXIT (if the determined version is already installed).

generate_akams_links() {
local valid_aka_ms_link=true;

normalized_version="$(to_lowercase "$version")"
if [[ "$normalized_version" != "latest" ]] && [ -n "$normalized_quality" ]; then
    say_err "Quality and Version options are not allowed to be specified simultaneously. See https://learn.microsoft.com/dotnet/core/tools/dotnet-install-script#options for details."
    return 1
fi

if [[ -n "$json_file" || "$normalized_version" != "latest" ]]; then
    # aka.ms links are not needed when exact version is specified via command or json file
    return
fi

get_download_link_from_aka_ms || valid_aka_ms_link=false

if [[ "$valid_aka_ms_link" == true ]]; then
    say_verbose "Retrieved primary payload URL from aka.ms link: '$aka_ms_download_link'."
    say_verbose "Downloading using legacy url will not be attempted."

    download_link=$aka_ms_download_link

    #get version from the path
    IFS='/'
    read -ra pathElems <<< "$download_link"
    count=${#pathElems[@]}
    specific_version="${pathElems[count-2]}"
    unset IFS;
    say_verbose "Version: '$specific_version'."

    #Retrieve effective version
    effective_version="$(get_specific_product_version "$azure_feed" "$specific_version" "$download_link")"

    # Add link info to arrays
    download_links+=($download_link)
    specific_versions+=($specific_version)
    effective_versions+=($effective_version)
    link_types+=("aka.ms")

    #  Check if the SDK version is already installed.
    if [[ "$dry_run" != true ]] && is_dotnet_package_installed "$install_root" "$asset_relative_path" "$effective_version"; then
        say "$asset_name with version '$effective_version' is already installed."
        exit 0
    fi

    return 0
fi

# if quality is specified - exit with error - there is no fallback approach
if [ ! -z "$normalized_quality" ]; then
    say_err "Failed to locate the latest version in the channel '$normalized_channel' with '$normalized_quality' quality for '$normalized_product', os: '$normalized_os', architecture: '$normalized_architecture'."
    say_err "Refer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support."
    return 1
fi
say_verbose "Falling back to latest.version file approach."

}

THIS FUNCTION MAY EXIT (if the determined version is already installed)

args:

feed - $1

generate_regular_links() {
local feed="$1"
local valid_legacy_download_link=true

specific_version=$(get_specific_version_from_version "$feed" "$channel" "$normalized_architecture" "$version" "$json_file") || specific_version='0'

if [[ "$specific_version" == '0' ]]; then
    say_verbose "Failed to resolve the specific version number using feed '$feed'"
    return
fi

effective_version="$(get_specific_product_version "$feed" "$specific_version")"
say_verbose "specific_version=$specific_version"

download_link="$(construct_download_link "$feed" "$channel" "$normalized_architecture" "$specific_version" "$normalized_os")"
say_verbose "Constructed primary named payload URL: $download_link"

# Add link info to arrays
download_links+=($download_link)
specific_versions+=($specific_version)
effective_versions+=($effective_version)
link_types+=("primary")

legacy_download_link="$(construct_legacy_download_link "$feed" "$channel" "$normalized_architecture" "$specific_version")" || valid_legacy_download_link=false

if [ "$valid_legacy_download_link" = true ]; then
    say_verbose "Constructed legacy named payload URL: $legacy_download_link"

    download_links+=($legacy_download_link)
    specific_versions+=($specific_version)
    effective_versions+=($effective_version)
    link_types+=("legacy")
else
    legacy_download_link=""
    say_verbose "Could not construct a legacy_download_link; omitting..."
fi

#  Check if the SDK version is already installed.
if [[ "$dry_run" != true ]] && is_dotnet_package_installed "$install_root" "$asset_relative_path" "$effective_version"; then
    say "$asset_name with version '$effective_version' is already installed."
    exit 0
fi

}

print_dry_run() {

say "Payload URLs:"

for link_index in "${!download_links[@]}"
    do
        say "URL #$link_index - ${link_types[$link_index]}: ${download_links[$link_index]}"
done

resolved_version=${specific_versions[0]}
repeatable_command="./$script_name --version "\""$resolved_version"\"" --install-dir "\""$install_root"\"" --architecture "\""$normalized_architecture"\"" --os "\""$normalized_os"\"""

if [ ! -z "$normalized_quality" ]; then
    repeatable_command+=" --quality "\""$normalized_quality"\"""
fi

if [[ "$runtime" == "dotnet" ]]; then
    repeatable_command+=" --runtime "\""dotnet"\"""
elif [[ "$runtime" == "aspnetcore" ]]; then
    repeatable_command+=" --runtime "\""aspnetcore"\"""
fi

repeatable_command+="$non_dynamic_parameters"

if [ -n "$feed_credential" ]; then
    repeatable_command+=" --feed-credential "\""<feed_credential>"\"""
fi

say "Repeatable invocation: $repeatable_command"

}

calculate_vars() {
eval $invocation

script_name=$(basename "$0")
normalized_architecture="$(get_normalized_architecture_from_architecture "$architecture")"
say_verbose "Normalized architecture: '$normalized_architecture'."
normalized_os="$(get_normalized_os "$user_defined_os")"
say_verbose "Normalized OS: '$normalized_os'."
normalized_quality="$(get_normalized_quality "$quality")"
say_verbose "Normalized quality: '$normalized_quality'."
normalized_channel="$(get_normalized_channel "$channel")"
say_verbose "Normalized channel: '$normalized_channel'."
normalized_product="$(get_normalized_product "$runtime")"
say_verbose "Normalized product: '$normalized_product'."
install_root="$(resolve_installation_path "$install_dir")"
say_verbose "InstallRoot: '$install_root'."

normalized_architecture="$(get_normalized_architecture_for_specific_sdk_version "$version" "$normalized_channel" "$normalized_architecture")"

if [[ "$runtime" == "dotnet" ]]; then
    asset_relative_path="shared/Microsoft.NETCore.App"
    asset_name=".NET Core Runtime"
elif [[ "$runtime" == "aspnetcore" ]]; then
    asset_relative_path="shared/Microsoft.AspNetCore.App"
    asset_name="ASP.NET Core Runtime"
elif [ -z "$runtime" ]; then
    asset_relative_path="sdk"
    asset_name=".NET Core SDK"
fi

get_feeds_to_use

}

install_dotnet() {
eval $invocation
local download_failed=false
local download_completed=false
local remote_file_size=0

mkdir -p "$install_root"
zip_path="${zip_path:-$(mktemp "$temporary_file_template")}"
say_verbose "Archive path: $zip_path"

for link_index in "${!download_links[@]}"
do
    download_link="${download_links[$link_index]}"
    specific_version="${specific_versions[$link_index]}"
    effective_version="${effective_versions[$link_index]}"
    link_type="${link_types[$link_index]}"

    say "Attempting to download using $link_type link $download_link"

    # The download function will set variables $http_code and $download_error_msg in case of failure.
    download_failed=false
    download "$download_link" "$zip_path" 2>&1 || download_failed=true

    if [ "$download_failed" = true ]; then
        case $http_code in
        404)
            say "The resource at $link_type link '$download_link' is not available."
            ;;
        *)
            say "Failed to download $link_type link '$download_link': $http_code $download_error_msg"
            ;;
        esac
        rm -f "$zip_path" 2>&1 && say_verbose "Temporary archive file $zip_path was removed"
    else
        download_completed=true
        break
    fi
done

if [[ "$download_completed" == false ]]; then
    say_err "Could not find \`$asset_name\` with version = $specific_version"
    say_err "Refer to: https://aka.ms/dotnet-os-lifecycle for information on .NET Core support"
    return 1
fi

remote_file_size="$(get_remote_file_size "$download_link")"

say "Extracting archive from $download_link"
extract_dotnet_package "$zip_path" "$install_root" "$remote_file_size" || return 1

#  Check if the SDK version is installed; if not, fail the installation.
# if the version contains "RTM" or "servicing"; check if a 'release-type' SDK version is installed.
if [[ $specific_version == *"rtm"* || $specific_version == *"servicing"* ]]; then
    IFS='-'
    read -ra verArr <<< "$specific_version"
    release_version="${verArr[0]}"
    unset IFS;
    say_verbose "Checking installation: version = $release_version"
    if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$release_version"; then
        say "Installed version is $effective_version"
        return 0
    fi
fi

#  Check if the standard SDK version is installed.
say_verbose "Checking installation: version = $effective_version"
if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$effective_version"; then
    say "Installed version is $effective_version"
    return 0
fi

# Version verification failed. More likely something is wrong either with the downloaded content or with the verification algorithm.
say_err "Failed to verify the version of installed \`$asset_name\`.\nInstallation source: $download_link.\nInstallation location: $install_root.\nReport the bug at https://github.com/dotnet/install-scripts/issues."
say_err "\`$asset_name\` with version = $effective_version failed to install with an error."
return 1

}

args=("$@")

local_version_file_relative_path="/.version"
bin_folder_relative_path=""
temporary_file_template="${TMPDIR:-/tmp}/dotnet.XXXXXXXXX"

channel="LTS"
version="Latest"
json_file=""
install_dir=""
architecture=""
dry_run=false
no_path=false
azure_feed=""
uncached_feed=""
feed_credential=""
verbose=false
runtime=""
runtime_id=""
quality=""
internal=false
override_non_versioned_files=true
non_dynamic_parameters=""
user_defined_os=""

while [ $# -ne 0 ]
do
name="$1"
case "$name" in
-c|--channel|-[Cc]hannel)
shift
channel="$1"
;;
-v|--version|-[Vv]ersion)
shift
version="$1"
;;
-q|--quality|-[Qq]uality)
shift
quality="$1"
;;
--internal|-[Ii]nternal)
internal=true
non_dynamic_parameters+=" $name"
;;
-i|--install-dir|-[Ii]nstall[Dd]ir)
shift
install_dir="$1"
;;
--arch|--architecture|-[Aa]rch|-[Aa]rchitecture)
shift
architecture="$1"
;;
--os|-[Oo][SS])
shift
user_defined_os="$1"
;;
--shared-runtime|-[Ss]hared[Rr]untime)
say_warning "The --shared-runtime flag is obsolete and may be removed in a future version of this script. The recommended usage is to specify '--runtime dotnet'."
if [ -z "$runtime" ]; then
runtime="dotnet"
fi
;;
--runtime|-[Rr]untime)
shift
runtime="$1"
if [[ "$runtime" != "dotnet" ]] && [[ "$runtime" != "aspnetcore" ]]; then
say_err "Unsupported value for --runtime: '$1'. Valid values are 'dotnet' and 'aspnetcore'."
if [[ "$runtime" == "windowsdesktop" ]]; then
say_err "WindowsDesktop archives are manufactured for Windows platforms only."
fi
exit 1
fi
;;
--dry-run|-[Dd]ry[Rr]un)
dry_run=true
;;
--no-path|-[Nn]o[Pp]ath)
no_path=true
non_dynamic_parameters+=" $name"
;;
--verbose|-[Vv]erbose)
verbose=true
non_dynamic_parameters+=" $name"
;;
--azure-feed|-[Aa]zure[Ff]eed)
shift
azure_feed="$1"
non_dynamic_parameters+=" $name """$1""""
;;
--uncached-feed|-[Uu]ncached[Ff]eed)
shift
uncached_feed="$1"
non_dynamic_parameters+=" $name """$1""""
;;
--feed-credential|-[Ff]eed[Cc]redential)
shift
feed_credential="$1"
#feed_credential should start with "?", for it to be added to the end of the link.
#adding "?" at the beginning of the feed_credential if needed.
[[ -z "$(echo $feed_credential)" ]] || [[ $feed_credential == ?* ]] || feed_credential="?$feed_credential"
;;
--runtime-id|-[Rr]untime[Ii]d)
shift
runtime_id="$1"
non_dynamic_parameters+=" $name """$1""""
say_warning "Use of --runtime-id is obsolete and should be limited to the versions below 2.1. To override architecture, use --architecture option instead. To override OS, use --os option instead."
;;
--jsonfile|-[Jj][Ss]on[Ff]ile)
shift
json_file="$1"
;;
--skip-non-versioned-files|-[Ss]kip[Nn]on[Vv]ersioned[Ff]iles)
override_non_versioned_files=false
non_dynamic_parameters+=" $name"
;;
--keep-zip|-[Kk]eep[Zz]ip)
keep_zip=true
non_dynamic_parameters+=" $name"
;;
--zip-path|-[Zz]ip[Pp]ath)
shift
zip_path="$1"
;;
-?|--?|-h|--help|-[Hh]elp)
script_name="dotnet-install.sh"
echo ".NET Tools Installer"
echo "Usage:"
echo " # Install a .NET SDK of a given Quality from a given Channel"
echo " $script_name [-c|--channel ] [-q|--quality ]"
echo " # Install a .NET SDK of a specific public version"
echo " $script_name [-v|--version ]"
echo " $script_name -h|-?|--help"
echo ""
echo "$script_name is a simple command line interface for obtaining dotnet cli."
echo " Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
echo " - The SDK needs to be installed without user interaction and without admin rights."
echo " - The SDK installation doesn't need to persist across multiple CI runs."
echo " To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer."
echo ""
echo "Options:"
echo " -c,--channel Download from the channel specified, Defaults to `$channel`."
echo " -Channel"
echo " Possible values:"
echo " - STS - the most recent Standard Term Support release"
echo " - LTS - the most recent Long Term Support release"
echo " - 2-part version in a format A.B - represents a specific release"
echo " examples: 2.0; 1.0"
echo " - 3-part version in a format A.B.Cxx - represents a specific SDK release"
echo " examples: 5.0.1xx, 5.0.2xx."
echo " Supported since 5.0 release"
echo " Warning: Value 'Current' is deprecated for the Channel parameter. Use 'STS' instead."
echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used."
echo " -v,--version Use specific VERSION, Defaults to `$version`."
echo " -Version"
echo " Possible values:"
echo " - latest - the latest build on specific channel"
echo " - 3-part version in a format A.B.C - represents specific version of build"
echo " examples: 2.0.0-preview2-006120; 1.1.0"
echo " -q,--quality Download the latest build of specified quality in the channel."
echo " -Quality"
echo " The possible values are: daily, signed, validated, preview, GA."
echo " Works only in combination with channel. Not applicable for STS and LTS channels and will be ignored if those channels are used."
echo " For SDK use channel in A.B.Cxx format. Using quality for SDK together with channel in A.B format is not supported."
echo " Supported since 5.0 release."
echo " Note: The version parameter overrides the channel parameter when any version other than 'latest' is used, and therefore overrides the quality."
echo " --internal,-Internal Download internal builds. Requires providing credentials via --feed-credential parameter."
echo " --feed-credential Token to access Azure feed. Used as a query string to append to the Azure feed."
echo " -FeedCredential This parameter typically is not specified."
echo " -i,--install-dir

Install under specified location (see Install Location below)"
echo " -InstallDir"
echo " --architecture Architecture of dotnet binaries to be installed, Defaults to `$architecture`."
echo " --arch,-Architecture,-Arch"
echo " Possible values: x64, arm, arm64, s390x, ppc64le and loongarch64"
echo " --os Specifies operating system to be used when selecting the installer."
echo " Overrides the OS determination approach used by the script. Supported values: osx, linux, linux-musl, freebsd, rhel.6."
echo " In case any other value is provided, the platform will be determined by the script based on machine configuration."
echo " Not supported for legacy links. Use --runtime-id to specify platform for legacy links."
echo " Refer to: https://aka.ms/dotnet-os-lifecycle for more information."
echo " --runtime Installs a shared runtime only, without the SDK."
echo " -Runtime"
echo " Possible values:"
echo " - dotnet - the Microsoft.NETCore.App shared runtime"
echo " - aspnetcore - the Microsoft.AspNetCore.App shared runtime"
echo " --dry-run,-DryRun Do not perform installation. Display download link."
echo " --no-path, -NoPath Do not set PATH for the current process."
echo " --verbose,-Verbose Display diagnostics information."
echo " --azure-feed,-AzureFeed For internal use only."
echo " Allows using a different storage to download SDK archives from."
echo " --uncached-feed,-UncachedFeed For internal use only."
echo " Allows using a different storage to download SDK archives from."
echo " --skip-non-versioned-files Skips non-versioned files if they already exist, such as the dotnet executable."
echo " -SkipNonVersionedFiles"
echo " --jsonfile Determines the SDK version from a user specified global.json file."
echo " Note: global.json must have a value for 'SDK:Version'"
echo " --keep-zip,-KeepZip If set, downloaded file is kept."
echo " --zip-path, -ZipPath If set, downloaded file is stored at the specified path."
echo " -?,--?,-h,--help,-Help Shows this help message"
echo ""
echo "Install Location:"
echo " Location is chosen in following order:"
echo " - --install-dir option"
echo " - Environmental variable DOTNET_INSTALL_DIR"
echo " - $HOME/.dotnet"
exit 0
;;
*)
say_err "Unknown argument `$name`"
exit 1
;;
esac

shift

done

say_verbose "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
say_verbose "- The SDK needs to be installed without user interaction and without admin rights."
say_verbose "- The SDK installation doesn't need to persist across multiple CI runs."
say_verbose "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"

if [ "$internal" = true ] && [ -z "$(echo $feed_credential)" ]; then
message="Provide credentials via --feed-credential parameter."
if [ "$dry_run" = true ]; then
say_warning "$message"
else
say_err "$message"
exit 1
fi
fi

check_min_reqs
calculate_vars

generate_regular_links call below will 'exit' if the determined version is already installed.

generate_download_links

if [[ "$dry_run" = true ]]; then
print_dry_run
exit 0
fi

install_dotnet

bin_path="$(get_absolute_path "$(combine_paths "$install_root" "$bin_folder_relative_path")")"
if [ "$no_path" = false ]; then
say "Adding to current process PATH: `$bin_path`. Note: This change will be visible only when sourcing script."
export PATH="$bin_path":"$PATH"
else
say "Binaries of dotnet can be found in $bin_path"
fi

say "Note that the script does not resolve dependencies during installation."
say "To check the list of dependencies, go to https://learn.microsoft.com/dotnet/core/install, select your operating system and check the "Dependencies" section."
say "Installation finished successfully."

</details>

@JanProvaznik
Copy link
Member

JanProvaznik commented Jan 31, 2025

Here is the content, it won't allow me to add the file, even as a zip:

Thanks, that is the correct script which is puzzling.

Could you try if this fixes your issue?
sudo ./dotnet-install.sh --install-dir /Users/USER/Library/Caches/Xamarin/XMA/SDKs/dotnet --version 9.0.102-servicing.24611.3 --architecture Arm64 --no-path --verbose

The "Pair to Mac" seems to expect the binaries in that directory (based on analogous case here: #407 )

@Mr-Horse
Copy link
Author

Mr-Horse commented Jan 31, 2025

@JanProvaznik here is the output from that:

inhqmb101155:scripts mrhorse$ sudo ./dotnet-install.sh --install-dir /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet --version 9.0.102-servicing.24611.3 --architecture Arm64 --no-path --verbose
Password:
sudo: ./dotnet-install.sh: command not found
inhqmb101155:scripts mrhorse$ chmod +x dotnet-install.sh
inhqmb101155:scripts mrhorse$ sudo ./dotnet-install.sh --install-dir /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet --version 9.0.102-servicing.24611.3 --architecture Arm64 --no-path --verbose
dotnet-install: Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:
dotnet-install: - The SDK needs to be installed without user interaction and without admin rights.
dotnet-install: - The SDK installation doesn't need to persist across multiple CI runs.
dotnet-install: To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.

dotnet-install: Calling: machine_has curl
dotnet-install: Calling: calculate_vars 
dotnet-install: Calling: get_normalized_architecture_from_architecture Arm64
dotnet-install: Normalized architecture: 'arm64'.
dotnet-install: Calling: get_normalized_os 
dotnet-install: Calling: get_current_os_name 
dotnet-install: Normalized OS: 'osx'.
dotnet-install: Calling: get_normalized_quality 
dotnet-install: Normalized quality: ''.
dotnet-install: Calling: get_normalized_channel LTS
dotnet-install: Normalized channel: 'LTS'.
dotnet-install: Calling: get_normalized_product 
dotnet-install: Normalized product: 'dotnet-sdk'.
dotnet-install: Calling: resolve_installation_path /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet
dotnet-install: InstallRoot: '/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet'.
dotnet-install: Calling: get_normalized_architecture_for_specific_sdk_version 9.0.102-servicing.24611.3 LTS arm64
dotnet-install: Calling: get_current_os_name 
dotnet-install: Calling: get_specific_version_from_version https://builds.dotnet.microsoft.com/dotnet LTS arm64 9.0.102-servicing.24611.3 
dotnet-install: Calling: get_specific_product_version https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3
dotnet-install: Calling: get_specific_product_version_url https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3 true 
dotnet-install: Constructed productVersion link: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: get_specific_product_version_url https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3 false 
dotnet-install: Constructed productVersion link: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/productVersion.txt
dotnet-install: Checking for the existence of https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: machine_has curl
dotnet-install: specific_version=9.0.102-servicing.24611.3
dotnet-install: Calling: construct_download_link https://builds.dotnet.microsoft.com/dotnet LTS arm64 9.0.102-servicing.24611.3 osx
dotnet-install: Calling: get_specific_product_version https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3
dotnet-install: Calling: get_specific_product_version_url https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3 true 
dotnet-install: Constructed productVersion link: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: get_specific_product_version_url https://builds.dotnet.microsoft.com/dotnet 9.0.102-servicing.24611.3 false 
dotnet-install: Constructed productVersion link: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/productVersion.txt
dotnet-install: Checking for the existence of https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: machine_has curl
dotnet-install: Constructed primary named payload URL: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/dotnet-sdk-9.0.102-osx-arm64.tar.gz
dotnet-install: Calling: construct_legacy_download_link https://builds.dotnet.microsoft.com/dotnet LTS arm64 9.0.102-servicing.24611.3
dotnet-install: Calling: get_legacy_os_name 
dotnet-install: Constructed legacy named payload URL: https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/dotnet-dev-osx-arm64.9.0.102-servicing.24611.3.tar.gz
dotnet-install: Calling: is_dotnet_package_installed /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet sdk 9.0.102
dotnet-install: Calling: combine_paths /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet sdk
dotnet-install: combine_paths: root_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet
dotnet-install: combine_paths: child_path=sdk
dotnet-install: Calling: combine_paths /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk 9.0.102
dotnet-install: combine_paths: root_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk
dotnet-install: combine_paths: child_path=9.0.102
dotnet-install: is_dotnet_package_installed: dotnet_package_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk/9.0.102
dotnet-install: Calling: get_specific_version_from_version https://ci.dot.net/public LTS arm64 9.0.102-servicing.24611.3 
dotnet-install: Calling: get_specific_product_version https://ci.dot.net/public 9.0.102-servicing.24611.3
dotnet-install: Calling: get_specific_product_version_url https://ci.dot.net/public 9.0.102-servicing.24611.3 true 
dotnet-install: Constructed productVersion link: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: get_specific_product_version_url https://ci.dot.net/public 9.0.102-servicing.24611.3 false 
dotnet-install: Constructed productVersion link: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/productVersion.txt
dotnet-install: Checking for the existence of https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: machine_has curl
dotnet-install: specific_version=9.0.102-servicing.24611.3
dotnet-install: Calling: construct_download_link https://ci.dot.net/public LTS arm64 9.0.102-servicing.24611.3 osx
dotnet-install: Calling: get_specific_product_version https://ci.dot.net/public 9.0.102-servicing.24611.3
dotnet-install: Calling: get_specific_product_version_url https://ci.dot.net/public 9.0.102-servicing.24611.3 true 
dotnet-install: Constructed productVersion link: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: get_specific_product_version_url https://ci.dot.net/public 9.0.102-servicing.24611.3 false 
dotnet-install: Constructed productVersion link: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/productVersion.txt
dotnet-install: Checking for the existence of https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/sdk-productVersion.txt
dotnet-install: Calling: machine_has curl
dotnet-install: Constructed primary named payload URL: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/dotnet-sdk-<html><head><title>302 Moved Temporarily</title></head><body><center><h1>302 Moved Temporarily</h1></center><hr><center>Umbrella Cloud Security Gateway</center></body></html>-osx-arm64.tar.gz
dotnet-install: Calling: construct_legacy_download_link https://ci.dot.net/public LTS arm64 9.0.102-servicing.24611.3
dotnet-install: Calling: get_legacy_os_name 
dotnet-install: Constructed legacy named payload URL: https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/dotnet-dev-osx-arm64.9.0.102-servicing.24611.3.tar.gz
dotnet-install: Calling: is_dotnet_package_installed /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet sdk <html><head><title>302 Moved Temporarily</title></head><body><center><h1>302 Moved Temporarily</h1></center><hr><center>Umbrella Cloud Security Gateway</center></body></html>
dotnet-install: Calling: combine_paths /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet sdk
dotnet-install: combine_paths: root_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet
dotnet-install: combine_paths: child_path=sdk
dotnet-install: Calling: combine_paths /Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk <html><head><title>302 Moved Temporarily</title></head><body><center><h1>302 Moved Temporarily</h1></center><hr><center>Umbrella Cloud Security Gateway</center></body></html>
dotnet-install: combine_paths: root_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk
dotnet-install: combine_paths: child_path=<html><head><title>302 Moved Temporarily</title></head><body><center><h1>302 Moved Temporarily</h1></center><hr><center>Umbrella Cloud Security Gateway</center></body></html>
dotnet-install: is_dotnet_package_installed: dotnet_package_path=/Users/mrhorse/Library/Caches/Xamarin/XMA/SDKs/dotnet/sdk/<html><head><title>302 Moved Temporarily</title></head><body><center><h1>302 Moved Temporarily</h1></center><hr><center>Umbrella Cloud Security Gateway</center></body></html>
dotnet-install: Generated 11 links.
dotnet-install: Link 0: primary, 9.0.102, https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/dotnet-sdk-9.0.102-osx-arm64.tar.gz
dotnet-install: Link 1: legacy, 9.0.102, https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/dotnet-dev-osx-arm64.9.0.102-servicing.24611.3.tar.gz
dotnet-install: Link 2: primary, <html><head><title>302, https://ci.dot.net/public/Sdk/9.0.102-servicing.24611.3/dotnet-sdk-<html><head><title>302
dotnet-install: Link 3: legacy, Moved, Moved
./dotnet-install.sh: line 1440: link_types[$link_index]: unbound variable

@baronfel
Copy link
Member

Our script tries to follow 3xx redirects, but it looks like that's failing for your case, and I agree that it looks like your network security is interfering here.

@JanProvaznik
Copy link
Member

as a short term fix I would try downloading from https://builds.dotnet.microsoft.com/dotnet/Sdk/9.0.102-servicing.24611.3/dotnet-sdk-9.0.102-osx-arm64.tar.gz and unzipping that to the install-dir manually

preferably convince your network security to not break the link

@baronfel
Copy link
Member

@JanProvaznik I think there's a potential bit of hardening we should do on the productversion.txt calls as well - it seems that we're not checking for a real success here (3xx responses don't count as 'failures') and we probably should be. A minimum bar would be failing, but we should probably attempt to follow any redirects to get the final content.

@JanProvaznik
Copy link
Member

Also I notice that these don't exist. Shouldn't they @rbhanda ?

<Error>
<Code>BlobNotFound</Code>
<Message>The specified blob does not exist. RequestId:61e3d936-201e-002a-7a01-74562e000000 Time:2025-01-31T17:00:30.4233264Z</Message>
</Error>

only these exist:

@Mr-Horse
Copy link
Author

We put in a request to get the domain https://ci.dot.net unblocked. That fixed it. Thanks @baronfel and @JanProvaznik for the help and for being so responsive!

@baronfel
Copy link
Member

@Mr-Horse is the builds.dotnet.microsoft.com domain also unblocked? That is the primary domain for stable releases (like the one you're trying to download in your example), and I'd expect it to be preferred over ci.dot.net.

@Mr-Horse
Copy link
Author

@Mr-Horse is the builds.dotnet.microsoft.com domain also unblocked? That is the primary domain for stable releases (like the one you're trying to download in your example), and I'd expect it to be preferred over ci.dot.net.

That's probably also blocked. I'll have them add that one as well, thanks!

@rbhanda
Copy link

rbhanda commented Jan 31, 2025

Also I notice that these don't exist. Shouldn't they @rbhanda ?

<Error>
<Code>BlobNotFound</Code>
<Message>The specified blob does not exist. RequestId:61e3d936-201e-002a-7a01-74562e000000 Time:2025-01-31T17:00:30.4233264Z</Message>
</Error>

only these exist:

@mmitche should these exist in ci.dot.net?

@mmitche
Copy link
Member

mmitche commented Jan 31, 2025

No, since this was an internal build. They would exist in internal containers, but not public ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants