Exemplo n.º 1
0
        /// <summary>
        /// Determines whether the current project is Raspberry compatible, has Raspberry project
        /// settings and is enabled for debugging and returns the name of the target connection when
        /// these conditions are met.
        /// </summary>
        /// <returns>
        /// <c>null</c> if the project does not have Raspberry settings or is not an eligible
        /// .NET Core project, <see cref="ProjectSettings.DefaultConnectionName"/> when the project
        /// targets the default Raspberry connection, otherwise the name of the specific target
        /// connection will be returned.
        /// </returns>
        private string GetConnectionName()
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            if (dte.Solution == null)
            {
                return(null);
            }

            var project = PackageHelper.GetStartupProject(dte.Solution);

            if (project == null)
            {
                return(null);
            }

            var projectProperties = ProjectProperties.CopyFrom(dte.Solution, project);

            if (!projectProperties.IsRaspberryCompatible)
            {
                return(null);
            }

            var projectSettings = PackageHelper.GetProjectSettings(dte.Solution, project);

            if (projectSettings == null || !projectSettings.EnableRemoteDebugging)
            {
                return(null);
            }

            return(projectSettings.RemoteDebugTarget ?? ProjectSettings.DefaultConnectionName);
        }
        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
#pragma warning disable VSTHRD100
        private async void Execute(object sender, EventArgs e)
#pragma warning restore VSTHRD100
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

            if (!await DebugHelper.EnsureOpenSshAsync())
            {
                return;
            }

            var project = DebugHelper.GetTargetProject(dte);

            if (project == null)
            {
                return;
            }

            var projectProperties = ProjectProperties.CopyFrom(dte.Solution, project);

            if (!await DebugHelper.PublishProjectWithUIAsync(dte, dte.Solution, project, projectProperties))
            {
                return;
            }

            var connectionInfo = DebugHelper.GetDebugConnectionInfo(projectProperties);

            if (connectionInfo == null)
            {
                return;
            }

            // Identify the most recent SDK installed on the workstation that has the same
            // major and minor version numbers as the project.  We'll ensure that the same
            // SDK is installed on the Raspberry (further below).

            var targetSdk = DebugHelper.GetTargetSdk(projectProperties);

            if (targetSdk == null)
            {
                return;
            }

            // Establish a Raspberry connection to handle some things before we start the debugger.

            var connection = await DebugHelper.InitializeConnectionAsync(connectionInfo, targetSdk, projectProperties, PackageHelper.GetProjectSettings(dte.Solution, project));

            if (connection == null)
            {
                return;
            }

            using (connection)
            {
                // Generate a temporary [launch.json] file and launch the debugger.

                using (var tempFile = await CreateLaunchSettingsAsync(connectionInfo, projectProperties))
                {
                    dte.ExecuteCommand("DebugAdapterHost.Launch", $"/LaunchJson:\"{tempFile.Path}\"");
                }

                // Launch the browser for ASPNET apps if requested.  Note that we're going to do this
                // on a background task to poll the Raspberry, waiting for the app to create the create
                // the LISTENING socket.

                if (projectProperties.IsAspNet && projectProperties.AspLaunchBrowser)
                {
                    var baseUri     = $"http://{connectionInfo.Host}:{projectProperties.AspPort}";
                    var launchReady = false;

                    await NeonHelper.WaitForAsync(
                        async() =>
                    {
                        if (dte.Mode != vsIDEMode.vsIDEModeDebug)
                        {
                            // The developer must have stopped debugging before the ASPNET
                            // application was able to begin servicing requests.

                            return(true);
                        }

                        try
                        {
                            var appListeningScript =
                                $@"
if lsof -i -P -n | grep --quiet 'TCP \*:{projectProperties.AspPort} (LISTEN)' ; then
    exit 0
else
    exit 1
fi
";
                            var response = connection.SudoCommand(CommandBundle.FromScript(appListeningScript));

                            if (response.ExitCode != 0)
                            {
                                return(false);
                            }

                            // Wait just a bit longer to give the application a chance to
                            // perform any additional initialization.

                            await Task.Delay(TimeSpan.FromSeconds(1));

                            launchReady = true;
                            return(true);
                        }
                        catch
                        {
                            return(false);
                        }
                    },
                        timeout : TimeSpan.FromSeconds(30),
                        pollInterval : TimeSpan.FromSeconds(0.5));

                    if (launchReady)
                    {
                        NeonHelper.OpenBrowser($"{baseUri}{projectProperties.AspRelativeBrowserUri}");
                    }
                }
            }
        }