Skip to content

Commit

Permalink
Merge pull request #23 from SuessLabs/feature/OutputWindow
Browse files Browse the repository at this point in the history
Output Window and Package cleanup
  • Loading branch information
DamianSuess authored May 2, 2022
2 parents cde5c98 + a429038 commit edf6a0b
Show file tree
Hide file tree
Showing 10 changed files with 246 additions and 153 deletions.
62 changes: 62 additions & 0 deletions docs/Snips.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Code Snips

## RemoteDebugger.cs

```cs
/*
* Borrowed from VSMonoDebugger
*
public async Task BuildStartupProjectAsync()
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
var failedBuilds = BuildStartupProject();
if (failedBuilds > 0)
{
Window window = _dte.Windows.Item("{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}");//EnvDTE.Constants.vsWindowKindOutput
OutputWindow outputWindow = (OutputWindow)window.Object;
outputWindow.ActivePane.Activate();
outputWindow.ActivePane.OutputString($"{failedBuilds} project(s) failed to build. See error and output window!");
//// _errorListProvider.Show();
throw new Exception($"{failedBuilds} project(s) failed to build. See error and output window!");
}
}
private int BuildStartupProject()
{
ThreadHelper.ThrowIfNotOnUIThread();
//// var dte = (DTE)Package.GetGlobalService(typeof(DTE));
var sb = (SolutionBuild2)_dte.Solution.SolutionBuild;
try
{
var startProject = GetStartupProject();
var activeConfiguration = _dte.Solution.SolutionBuild.ActiveConfiguration as SolutionConfiguration2;
var activeConfigurationName = activeConfiguration.Name;
var activeConfigurationPlatform = activeConfiguration.PlatformName;
var startProjectName = startProject.FullName;
sb.BuildProject($"{activeConfigurationName}|{activeConfigurationPlatform}", startProject.FullName, true);
}
catch (Exception ex)
{
// Build complete solution (fallback solution)
return BuildSolution();
}
return sb.LastBuildInfo;
}
private int BuildSolution()
{
ThreadHelper.ThrowIfNotOnUIThread();
var sb = (SolutionBuild2)_dte.Solution.SolutionBuild;
sb.Build(true);
return sb.LastBuildInfo;
}
*/
```
42 changes: 25 additions & 17 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,32 @@
# [VS .NET SSH Debugger](https://github.com/SuessLabs/RemoteDebug.git)
# [VS .NET Linux Debugger](https://github.com/SuessLabs/RemoteDebug.git)

<image align="right" width="200" height="200" src="https://github.com/SuessLabs/VsLinuxDebug/blob/master/docs/TuxDebug.png" />

Remotely deploy and debug your .NET C# apps via SSH to Linux using Visual Studio 2022.

Get it on the [VS MarketPlace](https://marketplace.visualstudio.com/items?itemName=SuessLabs.VSLinuxDebugger)!

> WARNING: This is a work in progress!
Visual Studio's "attach to process via SSH" is cute, but it lacks deployment and automatic attaching. This project aims to allow you to do just that when programming for your Linux VM or Raspberry Pi over the network.
Visual Studio's "attach to process via SSH" is cute, but it lacks deployment and automatic attaching. This project allows you to do just that on your Linux VM or Raspberry Pi over the network!

This project was inspired by [VS Mono Debugger](https://github.com/GordianDotNet/VSMonoDebugger) and their amazing efforts for cross-platform development.

## Overview

Now developers can build, deploy and debug projects on their remote Linux (Ubuntu, Raspberry PI, etc) devices! Customize your SSH connection to use either a _password_ or a _private key_.

### Work in Progress

This project is currently in the early alpha stages, so only Building and Deployment is available. This extension aims to allow you to automatically attach for debugging over the network. For now, that step is still manual. On the plus side, we just saved you 1.5 min of manual upload and `chown -R`.

### Usage

![VS Menu](docs/ScreenShot-MenuItems.png)

* Build and upload to remote devices (_yes, this is a real pain_)
* Remote debugging (_Work-in-Progress_)
* Remote debugging (_P-Link only_)
* VS Linux Debugger will automatically detect and install `vsdbg` for you!

### Customize your connections

![Tools Options](docs/ScreenShot-ToolsOptions.png)

### Generating Private Key (optional)
### Generating Private Key

The following steps are options if you wish to use an SSH Private Key. These steps were written for Windows 10, however, on Linux the steps are similar.

Expand All @@ -52,14 +47,27 @@ The following steps are options if you wish to use an SSH Private Key. These ste

## Action Items

In order to get this project moving, the following must be done.
### Work-in-Progress Items

Currently, debugging successfully works with **PLink.exe**. SSH debugging is still a work-in-progress.

### Manually Attaching (for GUI apps)

For GUI projects, you can use **Build and Deploy** and then manually attach to the process via SSH by using Visual Studio's built-in tool

1. Deploy to remote machine via
1. Extensions > Linux Debugger > **"Build and Deploy"**
2. Run GUI app on remote machine
1. `dotnet MyGuiApp.dll`
3. Debug > **"Attach to Process.."**
4. Connection Type: **SSH**
5. Connection Target: **(Remote machine's IP)**
6. (Select process)
7. Click, **Attach**
8. Check, **"Managed (.NET Core for Unix)"**
9. Click, **OK**

* [X] Create extension project for VS2022
* [X] SSH, SFTP, and SCP communication
* [X] Store settings (globally; per-project)
* [X] IP, User, Pass, default-folder `"~/VsLinuxDbg/(proj-name)"`
* [X] Perform upload to remote machine
* [ ] Attach to process - _in testing phase_
This will save you 1.5 minutes on every build of manual uploading and updating rights via `chown -R`.

## Developers Wanted

Expand Down
6 changes: 4 additions & 2 deletions sandbox/ConsoleNet5/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ public static void Main(string[] args)

Console.WriteLine("Apply breakpoint here!");

Console.WriteLine("Press any key to exit..");
var x = Console.ReadLine();
Console.WriteLine("All done.");

//// Console.WriteLine("Press any key to exit..");
//// var x = Console.ReadLine();
}
}
}
110 changes: 10 additions & 100 deletions src/VsLinuxDebugger/Core/RemoteDebugger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task<bool> BeginAsync(BuildOptions buildOptions)
// Work completed
if (!_buildSuccessful)
{
LogOutput("Build was not successful.");
Logger.Output("Build was not successful.");
return false;
}
}
Expand Down Expand Up @@ -92,7 +92,7 @@ public async Task<bool> BeginAsync(BuildOptions buildOptions)
}
catch (Exception ex)
{
LogOutput($"An error occurred during the build process. {ex.Message}");
Logger.Output($"An error occurred during the build process. {ex.Message}");
return false;
}

Expand All @@ -110,11 +110,6 @@ public bool IsProjectValid()
return sb.StartupProjects != null && ((Array)sb.StartupProjects).Cast<string>().Count() > 0;
}

private void AttachToProcess()
{
// TODO: Create Launch.JSON file.
}

private void BuildBegin()
{
// TODO: Disable the menu buttons.
Expand All @@ -127,7 +122,7 @@ private void BuildBegin()

BuildEvents.OnBuildProjConfigDone += (string project, string projectConfig, string platform, string solutionConfig, bool success) =>
{
LogOutput($"Project: {project} --- Success: {success}\n");
Logger.Output($"Project: {project} --- Success: {success}\n");

if (!success)
BuildCleanup();
Expand All @@ -142,7 +137,7 @@ private void BuildBegin()
_buildTask?.TrySetResult(true);

var not = !_buildSuccessful ? "not" : "";
LogOutput($"Build was {not}successful");
Logger.Output($"Build was {not}successful");
};

// For some reason, cleanup isn't actually always ran when there has been an error.
Expand Down Expand Up @@ -173,22 +168,22 @@ private void BuildDebugAttacher()
{
////_launchJsonPath = _launchBuilder.GenerateLaunchJson();

_launchJsonPath = _launchBuilder.GenerateLaunchJson(true);
_launchJsonPath = _launchBuilder.GenerateLaunchJson(vsdbgLogging: true);
if (string.IsNullOrEmpty(_launchJsonPath))
{
LogOutput("Could not generate 'launch.json'. Potential folder creation permissions in project's output directory.");
Logger.Output("Could not generate 'launch.json'. Potential folder creation permissions in project's output directory.");
}

LogOutput("Debugger launching...");
LogOutput($" - launch.json path: '{_launchJsonPath}'");
Logger.Output("Debugger launching...");
Logger.Output($"- launch.json path: '{_launchJsonPath}'");

DTE2 dte2 = (DTE2)Package.GetGlobalService(typeof(SDTE));
dte2.ExecuteCommand("DebugAdapterHost.Launch", $"/LaunchJson:\"{_launchJsonPath}\"");

// launchConfigName = "Debug on Linux";
// DebugAdapterHost.Launch /LaunchJson:LaunchTester\Properties\launch.json /ConfigurationName:"{launchConfigName}"

LogOutput("Debug session complete.");
Logger.Output("Debug session complete.");
}

private bool Initialize()
Expand All @@ -209,63 +204,6 @@ private bool Initialize()
return true;
}

/*
* Borrowed from VSMonoDebugger
*
public async Task BuildStartupProjectAsync()
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
var failedBuilds = BuildStartupProject();
if (failedBuilds > 0)
{
Window window = _dte.Windows.Item("{34E76E81-EE4A-11D0-AE2E-00A0C90FFFC3}");//EnvDTE.Constants.vsWindowKindOutput
OutputWindow outputWindow = (OutputWindow)window.Object;
outputWindow.ActivePane.Activate();
outputWindow.ActivePane.OutputString($"{failedBuilds} project(s) failed to build. See error and output window!");
//// _errorListProvider.Show();
throw new Exception($"{failedBuilds} project(s) failed to build. See error and output window!");
}
}
private int BuildStartupProject()
{
ThreadHelper.ThrowIfNotOnUIThread();
//// var dte = (DTE)Package.GetGlobalService(typeof(DTE));
var sb = (SolutionBuild2)_dte.Solution.SolutionBuild;
try
{
var startProject = GetStartupProject();
var activeConfiguration = _dte.Solution.SolutionBuild.ActiveConfiguration as SolutionConfiguration2;
var activeConfigurationName = activeConfiguration.Name;
var activeConfigurationPlatform = activeConfiguration.PlatformName;
var startProjectName = startProject.FullName;
sb.BuildProject($"{activeConfigurationName}|{activeConfigurationPlatform}", startProject.FullName, true);
}
catch (Exception ex)
{
// Build complete solution (fallback solution)
return BuildSolution();
}
return sb.LastBuildInfo;
}
private int BuildSolution()
{
ThreadHelper.ThrowIfNotOnUIThread();
var sb = (SolutionBuild2)_dte.Solution.SolutionBuild;
sb.Build(true);
return sb.LastBuildInfo;
}
*/

private bool IsCSharpProject(Project vsProject)
{
ThreadHelper.ThrowIfNotOnUIThread();
Expand All @@ -276,37 +214,9 @@ private bool IsCSharpProject(Project vsProject)
}
catch (Exception ex)
{
LogOutput($"Project doesn't support property vsProject.CodeModel.Language! No CSharp project. {ex.Message}");
Logger.Output($"Only C# projects are supported at this time. {ex.Message}");
return false;
}
}

private void LogOutput(string message)
{
// Reference:
// - https://stackoverflow.com/a/1852535/249492
// - https://docs.microsoft.com/en-us/visualstudio/extensibility/extending-the-output-window?view=vs-2022
// - https://github.com/microsoft/VSSDK-Extensibility-Samples/blob/master/Reference_Services/C%23/Reference.Services/HelperFunctions.cs
//
Console.WriteLine($">> {message}");

// TODO: ERROR, 'generalPane' is NULL!
// 1) Consider passing in IServiceProvider from Commands class
// 2) Use the MS GitHub example
//
////// TODO: Use main thread
////////await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
////ThreadHelper.ThrowIfNotOnUIThread();
////
////IVsOutputWindow output = Package.GetGlobalService(typeof(SVsOutputWindow)) as IVsOutputWindow;
////
////// Guid debugPaneGuid = VSConstants.GUID_OutWindowDebugPane;
////Guid generalPaneGuid = VSConstants.GUID_OutWindowGeneralPane;
////IVsOutputWindowPane generalPane;
////output.GetPane(ref generalPaneGuid, out generalPane);
////
////generalPane.OutputStringThreadSafe(message);
////generalPane.Activate(); // Brings this pane into view
}
}
}
Loading

0 comments on commit edf6a0b

Please sign in to comment.