Skip to content

Commit

Permalink
Upload files async #2. Enhanced Output #7 and removal of `launch.json…
Browse files Browse the repository at this point in the history
…` if it previously existed #14
  • Loading branch information
DamianSuess committed May 2, 2022
1 parent edf6a0b commit 134d9e6
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/VsLinuxDebugger/Core/LaunchBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public LaunchBuilder(DTE2 dte, Project dteProject, UserOptions o)
public string ProjectName { get; set; }

/// <summary>Full path to the remote assembly. (i.e. `/home/USER/VLSDbg/Proj/ConsoleApp1.dll`)</summary>
public string RemoteDeployAppPath => LinuxPath.Combine(RemoteDeployFolder, $"{AssemblyName}.dll");
public string RemoteDeployAssemblyFilePath => LinuxPath.Combine(RemoteDeployFolder, $"{AssemblyName}.dll");

/// <summary>Folder of our remote assembly. (i.e. `/home/USER/VLSDbg/Proj`)</summary>
public string RemoteDeployFolder =>
Expand Down
133 changes: 77 additions & 56 deletions src/VsLinuxDebugger/Core/SshTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Renci.SshNet;
using SharpCompress.Common;
using SharpCompress.Writers;
Expand Down Expand Up @@ -53,14 +51,23 @@ public string Bash(string command)

/// <summary>Cleans the contents of the deployment path.</summary>
/// <param name="fullScrub">Clear entire base deployment folder (TRUE) or just our project.</param>
public void CleanDeploymentFolder(bool fullScrub = false)
public void CleanDeploymentFolder(bool fullScrub = true)
{
//// Bash($"sudo rm -rf {_opts.RemoteDeployBasePath}/*");

if (fullScrub)
Bash($"rm -rf {_opts.RemoteDeployBasePath}/*");
{
// Whole deployment folder and hidden files
// rm -rf xxx/* == Contents of the folder but not the folder itself
// rm -rf xxx/{*,.*} == All hidden files and folders
var filesAndFolders = "{*,.*}";
Bash($"rm -rf \"{_opts.RemoteDeployBasePath}/{filesAndFolders}\"");
}
else
Bash($"rm -rf \"{_launch.RemoteDeployAppPath}/*\"");
{
// Full path to the file we'll execute (i.e. "/home/USER/VsLinuxDbg/PROJECT/AppName.dll").
Bash($"rm -rf \"{_launch.RemoteDeployAssemblyFilePath}\"");
}
}

public bool Connect()
Expand All @@ -76,7 +83,6 @@ public bool Connect()
else
keyFile = new PrivateKeyFile(_opts.UserPrivateKeyPath, _opts.UserPrivateKeyPassword);
}

}
catch (Exception ex)
{
Expand Down Expand Up @@ -177,7 +183,8 @@ public async Task<string> UploadFilesAsync()
{
try
{
Bash($@"mkdir -p {_launch.RemoteDeployFolder}");
// Clean output folder just incase
//// Bash($@"rm -rf {_launch.RemoteDeployFolder}");

// TODO: Rev1 - Iterate through each file and upload it via SCP client or SFTP.
// TODO: Rev2 - Compress _localHost.OutputDirFullName, upload ZIP, and unzip it.
Expand All @@ -191,16 +198,13 @@ public async Task<string> UploadFilesAsync()
throw new DirectoryNotFoundException($"Directory '{_launch.OutputDirFullPath}' not found!");

// Compress files to upload as single `tar.gz`.
// TODO: Use base folder path: var pathTarGz = $"{_opts.RemoteDeployBasePath}/{_tarGzFileName}";

//// var destTarGz = $"{RemoteDeployPath}/{_tarGzFileName}";
var destTarGz = LinuxPath.Combine(_launch.RemoteDeployFolder, _tarGzFileName);
Logger.Output($"Destination Tar.GZ: '{destTarGz}'");

var success = PayloadCompressAndUpload(_sftp, srcDirInfo, destTarGz);
var success = await PayloadCompressAndUploadAsync(_sftp, srcDirInfo, destTarGz);

// Decompress file
PayloadDecompress(destTarGz, false);
await PayloadDecompressAsync(destTarGz, false);

return string.Empty;
}
Expand Down Expand Up @@ -306,75 +310,86 @@ private void LogOutput(string message)
/// <param name="srcDirInfo">Build (source) contents directory info.</param>
/// <param name="pathBuildTarGz">Upload path and filename of build's tar.gz file.</param>
/// <returns></returns>
private bool PayloadCompressAndUpload(SftpClient sftp, DirectoryInfo srcDirInfo, string pathBuildTarGz)
private async Task<bool> PayloadCompressAndUploadAsync(SftpClient sftp, DirectoryInfo srcDirInfo, string pathBuildTarGz)
{
var success = false;
var localFiles = GetLocalFiles(srcDirInfo);

// TODO: Delta remote files against local files for changes.
using (Stream tarGzStream = new MemoryStream())
{
try
var outputMsg = string.Empty;

await Task.Run(() =>
{
using (var tarGzWriter = WriterFactory.Open(tarGzStream, ArchiveType.Tar, CompressionType.GZip))
try
{
using (MemoryStream fileStream = new MemoryStream())
using (var tarGzWriter = WriterFactory.Open(tarGzStream, ArchiveType.Tar, CompressionType.GZip))
{
using (BinaryWriter fileWriter = new BinaryWriter(fileStream))
using (MemoryStream fileStream = new MemoryStream())
{
fileWriter.Write(localFiles.Count);

var updateFileCount = 0;
long updateFileSize = 0;
var allFileCount = 0;
long allFileSize = 0;

foreach (var file in localFiles)
using (BinaryWriter fileWriter = new BinaryWriter(fileStream))
{
allFileCount++;
allFileSize += file.Value.Length;
fileWriter.Write(localFiles.Count);

// TODO: Add new cache file entry
//// UpdateCacheEntry.WriteToStream(newCacheFileWriter, file.Key, file.Value);
var updateFileCount = 0;
long updateFileSize = 0;
var allFileCount = 0;
long allFileSize = 0;

updateFileCount++;
updateFileSize += file.Value.Length;

try
{
tarGzWriter.Write(file.Key, file.Value);
}
catch (IOException ioEx)
{
LogOutput($"Exception: {ioEx.Message}");
}
catch (Exception ex)
foreach (var file in localFiles)
{
LogOutput($"Exception: {ex.Message}\n{ex.StackTrace}");
allFileCount++;
allFileSize += file.Value.Length;

// TODO: Add new cache file entry
//// UpdateCacheEntry.WriteToStream(newCacheFileWriter, file.Key, file.Value);

updateFileCount++;
updateFileSize += file.Value.Length;

try
{
tarGzWriter.Write(file.Key, file.Value);
}
catch (IOException ioEx)
{
outputMsg += $"Exception: {ioEx.Message}{Environment.NewLine}";
}
catch (Exception ex)
{
outputMsg += $"Exception: {ex.Message}{Environment.NewLine}{ex.StackTrace}{Environment.NewLine}";
}
}
}

LogOutput($"{updateFileCount,7:n0} [{updateFileSize,13:n0} bytes] of {allFileCount,7:n0} [{allFileSize,13:n0} bytes] files need to be updated");
outputMsg += $"Update file count: {updateFileCount}; File Size: [{updateFileSize} bytes] of Total Files: {allFileCount} [{allFileSize} bytes] need to be updated";
}
}
}

success = true;
}
catch (Exception ex)
{
outputMsg += $"Error while compressing file contents. {ex.Message}\n{ex.StackTrace}";
}
});

success = true;
}
catch (Exception ex)
{
LogOutput($"Error while compressing file contents. {ex.Message}\n{ex.StackTrace}");
}
Logger.Output(outputMsg);

// Upload the file
if (success)
{
try
{
var tarGzSize = tarGzStream.Length;
tarGzStream.Seek(0, SeekOrigin.Begin);

sftp.UploadFile(tarGzStream, pathBuildTarGz);
await Task.Run(() =>
{
tarGzStream.Seek(0, SeekOrigin.Begin);

sftp.UploadFile(tarGzStream, pathBuildTarGz);
});

LogOutput($"Uploaded '{_tarGzFileName}' [{tarGzSize,13:n0} bytes].");
success = true;
Expand All @@ -394,10 +409,12 @@ private bool PayloadCompressAndUpload(SftpClient sftp, DirectoryInfo srcDirInfo,
/// <param name="pathBuildTarGz">Path to upload to.</param>
/// <param name="removeTarGz">Remove our build's tar.gz file. Set to FALSE for debugging. (default=true)</param>
/// <returns>Returns true on success.</returns>
private bool PayloadDecompress(string pathBuildTarGz, bool removeTarGz = true)
private async Task<bool> PayloadDecompressAsync(string pathBuildTarGz, bool removeTarGz = true)
{
try
{
var decompressOutput = string.Empty;

var cmd = "set -e";
cmd += $";cd \"{_launch.RemoteDeployFolder}\"";
cmd += $";tar -zxf \"{_tarGzFileName}\"";
Expand All @@ -406,8 +423,12 @@ private bool PayloadDecompress(string pathBuildTarGz, bool removeTarGz = true)
if (removeTarGz)
cmd += $";rm \"{pathBuildTarGz}\"";

var output = Bash(cmd);
LogOutput(output);
await Task.Run(() =>
{
decompressOutput = Bash(cmd);
});

Logger.Output($"Payload Decompress results: '{decompressOutput}' (blank=OK)");

return true;
}
Expand Down
7 changes: 5 additions & 2 deletions src/VsLinuxDebugger/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,21 @@ public static void Init(IServiceProvider provider, OutputWindowType outputType =

public static void Output(string message)
{
var msg = $"{FormattedTime}: {message}{Environment.NewLine}";

try
{
ThreadHelper.ThrowIfNotOnUIThread();

if (HasOutputWindow())
{
_outputPane.OutputStringThreadSafe($"{FormattedTime}: {message}{Environment.NewLine}");
_outputPane.Activate(); // Brings this pane into view
_outputPane.OutputStringThreadSafe(msg);
_outputPane.Activate(); // Brings pane into view
}
}
catch (Exception)
{
Console.Write($"Failed to Output: '{msg}'");
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/VsLinuxDebugger/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.8.0.0")]
[assembly: AssemblyFileVersion("1.8.0.0")]
[assembly: AssemblyVersion("1.8.1.0")]
[assembly: AssemblyFileVersion("1.8.1.0")]
2 changes: 1 addition & 1 deletion src/VsLinuxDebugger/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Id="VsLinuxDebugger.4d7bf4de-5015-4e24-92c0-7f9f3397b2da" Version="1.8.0" Language="en-US" Publisher="Suess Labs" />
<Identity Id="VsLinuxDebugger.4d7bf4de-5015-4e24-92c0-7f9f3397b2da" Version="1.8.1" Language="en-US" Publisher="Suess Labs" />
<DisplayName>VS Linux Debugger</DisplayName>
<Description xml:space="preserve">Remotely deploy and debug your .NET apps visa SSH on your Linux device using Visual Studio 2022. Works with popular Linux distrobutions such as Ubuntu, Raspberry Pi, and more!</Description>
<MoreInfo>https://github.com/SuessLabs/VsLinuxDebug</MoreInfo>
Expand Down

0 comments on commit 134d9e6

Please sign in to comment.