Skip to content

Commit

Permalink
Using package JTF + Install toolchain cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
unrenormalizable committed Aug 27, 2024
2 parents a225897 + a7a6619 commit 0b02882
Show file tree
Hide file tree
Showing 22 changed files with 3,861 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public async Task TestGetActiveToolChainAsync()
{
(await ToolChainServiceExtensions.GetDefaultToolchainAsync(TestHelpers.ThisTestRoot, default))
.Should()
.EndWith("-x86_64-pc-windows-msvc");
.EndWith($"-{ToolChainServiceExtensions.AlwaysAvailableTarget}");
}

[Fact]
Expand Down Expand Up @@ -48,4 +48,16 @@ public async Task TestGetInstalledToolchainsBasicAsync()
installToolchains.Select(x => x.Version).Should().Contain(x => !x.IsNullOrEmptyOrWhiteSpace());
installToolchains.Where(x => x.IsDefault).Should().HaveCount(1);
}

[Fact]
public async Task TestGetTargetsAsync()
{
var targets = await ToolChainServiceExtensions.GetTargets(default);

targets.Should().NotContain(ToolChainServiceExtensions.AlwaysAvailableTarget);
targets.Should().OnlyContain(t => !t.Contains(" ("));
targets.Take(ToolChainServiceExtensions.CommonTargets.Length)
.Should()
.ContainInOrder(ToolChainServiceExtensions.CommonTargets.OrderBy(x => x));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ public async Task RootPackageIsAddedAsync(string workspaceRelRoot)
wmd.Packages.Should().ContainSingle(p => p.Name == Workspace.Package.RootPackageName && !p.IsPackage);
}

// TODO: NEW: during build, fmt, clippy etc. save all open files.
[Theory]
[InlineData(@"hello_world", "dev")]
[InlineData(@"hello_library", "dev")]
Expand Down
129 changes: 47 additions & 82 deletions src/RustAnalyzer.TestAdapter/Cargo/ToolChainService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -274,7 +272,7 @@ private async Task<bool> ExecuteOperationAsync(string opName, PathEx filePath, s
ct: ct);
}

private static async Task<bool> RunAsync(PathEx cargoFullPath, string opName, string arguments, PathEx workingDir, ProcessOutputRedirector redirector, CancellationToken ct)
private static async Task<bool> RunAsync(PathEx exeFullPath, string opName, string arguments, PathEx workingDir, ProcessOutputRedirector redirector, CancellationToken ct)
{
EnsureArg.IsNotEmptyOrWhiteSpace(arguments, nameof(arguments));

Expand All @@ -285,98 +283,65 @@ private static async Task<bool> RunAsync(PathEx cargoFullPath, string opName, st
redirector?.WriteLineWithoutProcessing($"==== Build step: Started ====");
redirector?.WriteLineWithoutProcessing($" Using : {cargoVersion}");
redirector?.WriteLineWithoutProcessing($" Using : {toolVersion}");
redirector?.WriteLineWithoutProcessing($" Path : {cargoFullPath}");
redirector?.WriteLineWithoutProcessing($" Path : {exeFullPath}");
redirector?.WriteLineWithoutProcessing($" Arguments : {arguments}");
redirector?.WriteLineWithoutProcessing($" WorkingDir : {workingDir}");
redirector?.WriteLineWithoutProcessing($"");

using var process = ProcessRunner.Run(
cargoFullPath,
new[] { arguments },
return await exeFullPath.RunAsync(
arguments,
workingDir,
env: null,
visible: false,
redirector: redirector,
quoteArgs: false,
outputEncoding: Encoding.UTF8,
cancellationToken: ct);
var whnd = process.WaitHandle;
if (whnd == null)
{
// Process failed to start, and any exception message has
// already been sent through the redirector
redirector.WriteErrorLineWithoutProcessing(string.Format("Error - Failed to start '{0}'", cargoFullPath));
return false;
}
else
{
var finished = await Task.Run(() => whnd.WaitOne());
if (finished)
{
Debug.Assert(process.ExitCode.HasValue, "cargo.exe process has not really exited");

// there seems to be a case when we're signalled as completed, but the
// process hasn't actually exited
process.Wait();

redirector.WriteLineWithoutProcessing($"==== Build step: Finished ====\n");
redirector,
finishedMsg: "==== Build step: Finished ====\n",
cancelledMsg: "==== Build step canceled ====\n",
ct);
}
}

return process.ExitCode == 0;
}
else
{
process.Kill();
redirector.WriteErrorLineWithoutProcessing($"==== Build step canceled ====");
public sealed class BuildOutputRedirector : ProcessOutputRedirector
{
private readonly IBuildOutputSink _outputPane;
private readonly PathEx _rootPath;
private readonly Func<BuildMessage, Task> _buildMessageReporter;
private readonly Func<string, BuildMessage[]> _jsonProcessor;

return false;
}
}
public BuildOutputRedirector(IBuildOutputSink outputPane, PathEx rootPath, Func<BuildMessage, Task> buildMessageReporter, Func<string, BuildMessage[]> jsonProcessor)
{
_outputPane = outputPane;
_rootPath = rootPath;
_buildMessageReporter = buildMessageReporter;
_jsonProcessor = jsonProcessor;
}

private sealed class BuildOutputRedirector : ProcessOutputRedirector
public override void WriteErrorLine(string line)
{
private readonly IBuildOutputSink _outputPane;
private readonly PathEx _rootPath;
private readonly Func<BuildMessage, Task> _buildMessageReporter;
private readonly Func<string, BuildMessage[]> _jsonProcessor;

public BuildOutputRedirector(IBuildOutputSink outputPane, PathEx rootPath, Func<BuildMessage, Task> buildMessageReporter, Func<string, BuildMessage[]> jsonProcessor)
{
_outputPane = outputPane;
_rootPath = rootPath;
_buildMessageReporter = buildMessageReporter;
_jsonProcessor = jsonProcessor;
}

public override void WriteErrorLine(string line)
{
WriteErrorLineWithoutProcessing(line);
}
WriteErrorLineWithoutProcessing(line);
}

public override void WriteErrorLineWithoutProcessing(string line)
{
WriteLineCore(line, x => new[] { new StringBuildMessage { Message = x } });
}
public override void WriteErrorLineWithoutProcessing(string line)
{
WriteLineCore(line, x => new[] { new StringBuildMessage { Message = x } });
}

public override void WriteLine(string line)
{
WriteLineCore(line, _jsonProcessor);
}
public override void WriteLine(string line)
{
WriteLineCore(line, _jsonProcessor);
}

public override void WriteLineWithoutProcessing(string line)
{
WriteLineCore(line, x => new[] { new StringBuildMessage { Message = x } });
}
public override void WriteLineWithoutProcessing(string line)
{
WriteLineCore(line, x => new[] { new StringBuildMessage { Message = x } });
}

private void WriteLineCore(string jsonLine, Func<string, BuildMessage[]> jsonProcessor)
{
var lines = jsonProcessor(jsonLine);
Array.ForEach(
lines,
l =>
{
_outputPane.WriteLine(_rootPath, _buildMessageReporter, l);
});
}
private void WriteLineCore(string jsonLine, Func<string, BuildMessage[]> jsonProcessor)
{
var lines = jsonProcessor(jsonLine);
Array.ForEach(
lines,
l =>
{
_outputPane.WriteLine(_rootPath, _buildMessageReporter, l);
});
}
}

88 changes: 86 additions & 2 deletions src/RustAnalyzer.TestAdapter/Cargo/ToolChainServiceExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -20,7 +22,12 @@ namespace KS.RustAnalyzer.TestAdapter.Cargo;
/// </summary>
public static class ToolChainServiceExtensions
{
private const string DefaultTargetTriple = "x86_64-pc-windows-msvc";
public const string AlwaysAvailableTarget = "x86_64-pc-windows-msvc";

public static readonly string[] CommonTargets = new[]
{
"wasm32-unknown-unknown",
};

private static readonly Regex NameCracker =
new(@"^((?<name>.*)(?<default> \(default\))?)$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft);
Expand Down Expand Up @@ -51,7 +58,7 @@ public static PathEx GetRustupSettingsPath() =>
public static async Task<(PathEx Bin, PathEx Lib)> GetBinAndLibPathsAsync(PathEx workingDirectory, CancellationToken ct)
{
var root = GetRustupSettingsPath().GetDirectoryName() + @$"toolchains\{await GetDefaultToolchainAsync(workingDirectory, ct)}";
return (root + "bin", root + $@"lib\rustlib\{DefaultTargetTriple}\lib");
return (root + "bin", root + $@"lib\rustlib\{AlwaysAvailableTarget}\lib");
}

public static async Task<Toolchain[]> GetInstalledToolchainsAsync(PathEx workingDirectory, CancellationToken ct)
Expand Down Expand Up @@ -99,6 +106,20 @@ public static async Task<Toolchain[]> GetInstalledToolchainsAsync(PathEx working
return tcs;
}

public static async Task<string[]> GetTargets(CancellationToken ct)
{
var output = await GetCommandOutput("rustup", "target list", GetRustupPath().GetDirectoryName(), ct);
var targets = output
.Where(x => !x.IsNullOrEmptyOrWhiteSpace())
.Select(x => x.Replace(" (installed)", string.Empty))
.Where(x => x != AlwaysAvailableTarget)
.Where(x => !CommonTargets.Contains(x))
.Select(x => x.Trim())
.OrderBy(t => t);

return CommonTargets.OrderBy(x => x).Concat(targets).ToArray();
}

public static async Task<string> GetDefaultToolchainAsync(PathEx workingDirectory, CancellationToken ct)
{
return (await GetInstalledToolchainsAsync(workingDirectory, ct)).Where(x => x.IsDefault).First().Name;
Expand Down Expand Up @@ -141,6 +162,51 @@ public static void CleanTestContainers(this PathEx @this, IEnumerable<PathEx> ex
.ForEach(File.Delete);
}

public static async Task<bool> RunAsync(this PathEx exeFullPath, string args, PathEx workingDir, ProcessOutputRedirector redirector, string finishedMsg, string cancelledMsg, CancellationToken ct)
{
using var process = ProcessRunner.Run(
exeFullPath,
new[] { args },
workingDir,
env: null,
visible: false,
redirector: redirector,
quoteArgs: false,
outputEncoding: Encoding.UTF8,
cancellationToken: ct);
var whnd = process.WaitHandle;
if (whnd == null)
{
// Process failed to start, and any exception message has
// already been sent through the redirector
redirector.WriteErrorLineWithoutProcessing(string.Format("Error - Failed to start '{0}'", exeFullPath));
return false;
}
else
{
var finished = await Task.Run(() => whnd.WaitOne());
if (finished)
{
Debug.Assert(process.ExitCode.HasValue, "process has not really exited");

// there seems to be a case when we're signalled as completed, but the
// process hasn't actually exited
process.Wait();

redirector.WriteLineWithoutProcessing(finishedMsg);

return process.ExitCode == 0;
}
else
{
process.Kill();
redirector.WriteErrorLineWithoutProcessing(cancelledMsg);

return false;
}
}
}

public static async Task SetToolchainOverrideAsync(this PathEx workspaceRoot, string toolChain, ILogger l, CancellationToken ct)
{
var opName = "rustup";
Expand Down Expand Up @@ -174,6 +240,24 @@ public static async Task<string> GetCommandOutputSingleLine(string opName, strin

return string.Join(string.Empty, lines.Where(l => !l.IsNullOrEmptyOrWhiteSpace()));
}

public static Task<bool> InstallToolchain(string commandline, IBuildOutputSink bos, CancellationToken ct)
{
bos.Clear();

var rustupPath = GetRustupPath();
return rustupPath.RunAsync(
commandline,
rustupPath.GetPathRoot(),
new BuildOutputRedirector(
bos,
rustupPath.GetFileName(),
_ => Task.CompletedTask,
x => new[] { new StringBuildMessage { Message = x } }),
$"==== {rustupPath.GetFileName()} done. ====\n",
$"==== {rustupPath.GetFileName()} cancelled.====\n",
ct);
}
}

public struct Toolchain
Expand Down
2 changes: 2 additions & 0 deletions src/RustAnalyzer.TestAdapter/Common/PathExExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public static class PathExExtensions

public static PathEx GetDirectoryName(this PathEx @this) => (PathEx)Path.GetDirectoryName(@this);

public static PathEx GetPathRoot(this PathEx @this) => (PathEx)Path.GetPathRoot(@this);

public static PathEx GetFileNameWithoutExtension(this PathEx @this) => (PathEx)Path.GetFileNameWithoutExtension(@this);

public static PathEx GetTempFileName() => (PathEx)Path.GetTempFileName();
Expand Down
1 change: 0 additions & 1 deletion src/RustAnalyzer/Debugger/DebugLaunchTargetProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using KS.RustAnalyzer.Infrastructure;
using KS.RustAnalyzer.TestAdapter.Cargo;
using KS.RustAnalyzer.TestAdapter.Common;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Workspace;
Expand Down
4 changes: 2 additions & 2 deletions src/RustAnalyzer/Infrastructure/BuildOutputSink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void WriteLine(PathEx rootPath, Func<BuildMessage, Task> buildOutputTaskR
{
RustAnalyzerPackage.JTF.RunAsync(async () =>
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
await RustAnalyzerPackage.JTF.SwitchToMainThreadAsync();
Initialize();

if (message is StringBuildMessage sm)
Expand Down Expand Up @@ -68,7 +68,7 @@ public void Clear()
{
RustAnalyzerPackage.JTF.RunAsync(async () =>
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
await RustAnalyzerPackage.JTF.SwitchToMainThreadAsync();
Initialize();
_buildOutputPane.Clear();
}).FireAndForget();
Expand Down
4 changes: 2 additions & 2 deletions src/RustAnalyzer/Infrastructure/OutputWindowLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void WriteLine(string format, params object[] args)
{
RustAnalyzerPackage.JTF.RunAsync(async () =>
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
await RustAnalyzerPackage.JTF.SwitchToMainThreadAsync();
WriteCore(format, args);
}).FireAndForget();
}
Expand All @@ -42,7 +42,7 @@ public void WriteError(string format, params object[] args)
{
RustAnalyzerPackage.JTF.RunAsync(async () =>
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
await RustAnalyzerPackage.JTF.SwitchToMainThreadAsync();
WriteCore("[ERROR]: " + format, args);
}).FireAndForget();
}
Expand Down
Loading

0 comments on commit 0b02882

Please sign in to comment.