-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRemoteRunner.cs
More file actions
132 lines (110 loc) · 4.85 KB
/
RemoteRunner.cs
File metadata and controls
132 lines (110 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System.Diagnostics;
using System.Net;
using DotNetConfig;
using Spectre.Console;
namespace Devlooped;
public class RemoteRunner(RemoteRef location, string toolName, Config? config = null)
{
Config config = config ?? Config.Build(Config.GlobalLocation);
public async Task<int> RunAsync(string[] args, bool aot, bool force = false)
{
// Only use cached ETag if not forcing a fresh download
if (!force)
{
var etag = config.GetString(toolName, location.ToString(), "etag");
if (etag != null && Directory.Exists(location.TempPath))
{
if (etag.StartsWith("W/\"", StringComparison.OrdinalIgnoreCase) && !etag.EndsWith('"'))
etag += '"';
location = location with { ETag = etag };
}
if (config.TryGetString(toolName, location.ToString(), "uri", out var url) &&
Uri.TryCreate(url, UriKind.Absolute, out var uri))
location = location with { ResolvedUri = uri };
}
if (DotnetMuxer.Path is null)
{
AnsiConsole.MarkupLine($":cross_mark: Unable to locate the .NET SDK.");
return 1;
}
var provider = DownloadProvider.Create(location);
var contents = await provider.GetAsync(location);
var updated = false;
// We consider a not modified as successful too
var success = contents.IsSuccessStatusCode || contents.StatusCode == HttpStatusCode.NotModified;
if (!success)
{
AnsiConsole.MarkupLine($":cross_mark: Reference [yellow]{location}[/] not found.");
return 1;
}
var program = Path.Combine(location.TempPath, location.Path ?? "program.cs");
if (contents.StatusCode != HttpStatusCode.NotModified)
{
#if DEBUG
await AnsiConsole.Status().StartAsync($":open_file_folder: {location} :backhand_index_pointing_right: {location.TempPath}", async ctx =>
{
await contents.ExtractToAsync(location);
});
#else
await contents.ExtractToAsync(location);
#endif
if (contents.Headers.ETag?.ToString() is { } newEtag)
config = config.SetString(toolName, location.ToString(), "etag", newEtag);
if (contents.Headers.TryGetValues("X-Original-URI", out var urls) && urls.Any())
config = config.SetString(toolName, location.ToString(), "uri", urls.First());
else
config = config.SetString(toolName, location.ToString(), "uri", contents.RequestMessage!.RequestUri!.AbsoluteUri);
updated = true;
}
else if (!File.Exists(program))
{
// Redownload if etag matches but file was cleared from local cache somehow
contents = await provider.GetAsync(location with { ETag = null });
if (!contents.IsSuccessStatusCode)
{
AnsiConsole.MarkupLine($":cross_mark: Reference [yellow]{location}[/] not found.");
return 1;
}
await contents.ExtractToAsync(location);
if (contents.Headers.ETag?.ToString() is { } newEtag &&
newEtag != config.GetString(toolName, location.ToString(), "etag"))
{
config = config.SetString(toolName, location.ToString(), "etag", newEtag);
updated = true;
}
}
if (!File.Exists(program))
{
if (location.Path is not null)
{
AnsiConsole.MarkupLine($":cross_mark: File reference not found in {location}.");
return 1;
}
var first = Directory.EnumerateFiles(location.TempPath, "*.cs", SearchOption.TopDirectoryOnly).FirstOrDefault();
if (first is null)
{
AnsiConsole.MarkupLine($":cross_mark: No .cs files found in {location}.");
return 1;
}
program = first;
}
if (updated)
{
var objDir = Path.Combine(location.TempPath, "obj");
// Only clean when there are existing build artifacts; skip on freshly extracted
// directories (no obj/) since dotnet clean on a new dir can corrupt the lock file.
if (Directory.Exists(objDir))
Process.Start(DotnetMuxer.Path.FullName, ["clean", "-v:q", program]).WaitForExit();
}
string[] runargs = aot
? [program, "-v:q", .. args]
: [program, "-v:q", "-p:PublishAot=false", .. args];
#if DEBUG
AnsiConsole.MarkupLine($":rocket: {DotnetMuxer.Path.FullName} {string.Join(' ', runargs)}");
#endif
var start = new ProcessStartInfo(DotnetMuxer.Path.FullName, runargs);
var process = Process.Start(start);
process?.WaitForExit();
return process?.ExitCode ?? 1;
}
}