Skip to content

Commit 800fdc8

Browse files
Adds config new command to create new config file. Closes #975 (#996)
1 parent 025cd30 commit 800fdc8

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using DevProxy.Abstractions;
6+
using System.Text.Json;
7+
using System.Text.RegularExpressions;
8+
9+
namespace DevProxy.CommandHandlers;
10+
11+
public class VisualStudioCodeSnippet
12+
{
13+
public string? Prefix { get; set; }
14+
public string[]? Body { get; set; }
15+
public string? Description { get; set; }
16+
}
17+
18+
public static class ConfigNewCommandHandler
19+
{
20+
private static readonly string snippetsFileUrl = "https://aka.ms/devproxy/snippets";
21+
private static readonly string configFileSnippetName = "ConfigFile";
22+
23+
public static async Task CreateConfigFileAsync(string name, ILogger logger)
24+
{
25+
try
26+
{
27+
var snippets = await DownloadSnippetsAsync(logger);
28+
if (snippets is null)
29+
{
30+
return;
31+
}
32+
33+
if (!snippets.TryGetValue(configFileSnippetName, out var snippet))
34+
{
35+
logger.LogError("Snippet {snippetName} not found", configFileSnippetName);
36+
return;
37+
}
38+
39+
if (snippet.Body is null || snippet.Body.Length == 0)
40+
{
41+
logger.LogError("Snippet {snippetName} is empty", configFileSnippetName);
42+
return;
43+
}
44+
45+
var snippetBody = GetSnippetBody(snippet.Body);
46+
var targetFileName = GetTargetFileName(name, logger);
47+
File.WriteAllText(targetFileName, snippetBody);
48+
logger.LogInformation("Config file created at {targetFileName}", targetFileName);
49+
}
50+
catch (Exception ex)
51+
{
52+
logger.LogError(ex, "Error downloading config");
53+
}
54+
}
55+
56+
private static string? GetSnippetBody(string[] bodyLines)
57+
{
58+
var body = string.Join("\n", bodyLines);
59+
// unescape $
60+
body = body.Replace("\\$", "$");
61+
// remove snippet $n markers
62+
body = Regex.Replace(body, @"\$[0-9]+", "");
63+
return body;
64+
}
65+
66+
private static async Task<Dictionary<string, VisualStudioCodeSnippet>?> DownloadSnippetsAsync(ILogger logger)
67+
{
68+
logger.LogDebug("Downloading snippets from {snippetsFileUrl}...", snippetsFileUrl);
69+
using var client = new HttpClient();
70+
var response = await client.GetAsync(snippetsFileUrl);
71+
if (response.IsSuccessStatusCode)
72+
{
73+
var content = await response.Content.ReadAsStringAsync();
74+
return JsonSerializer.Deserialize<Dictionary<string, VisualStudioCodeSnippet>>(content, ProxyUtils.JsonSerializerOptions);
75+
}
76+
else
77+
{
78+
logger.LogError("Failed to download snippets. Status code: {statusCode}", response.StatusCode);
79+
return null;
80+
}
81+
}
82+
83+
private static string GetTargetFileName(string name, ILogger logger)
84+
{
85+
var originalNameWithoutExtension = Path.GetFileNameWithoutExtension(name);
86+
var originalExtension = Path.GetExtension(name);
87+
var counter = 1;
88+
89+
while (true)
90+
{
91+
if (!File.Exists(name))
92+
{
93+
return name;
94+
}
95+
96+
var newName = $"{originalNameWithoutExtension}-{++counter}{originalExtension}";
97+
logger.LogDebug("File {name} already exists. Trying {newName}...", name, newName);
98+
name = newName;
99+
}
100+
}
101+
}

dev-proxy/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
// we don't need to init plugins if the user is using a global option or
8181
// using a subcommand, so we can exit early
8282
await rootCommand.InvokeAsync(args);
83+
// required to output all messages before closing the program
84+
loggerFactory.Dispose();
8385
return;
8486
}
8587

dev-proxy/ProxyHost.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,16 @@ public RootCommand GetRootCommand(ILogger logger)
309309
configGetCommand.SetHandler(async configId => await ConfigGetCommandHandler.DownloadConfigAsync(configId, logger), configIdArgument);
310310
configCommand.Add(configGetCommand);
311311

312+
var configNewCommand = new Command("new", "Create new Dev Proxy configuration file");
313+
var nameArgument = new Argument<string>("name", "Name of the configuration file")
314+
{
315+
Arity = ArgumentArity.ZeroOrOne
316+
};
317+
nameArgument.SetDefaultValue("devproxyrc.json");
318+
configNewCommand.AddArgument(nameArgument);
319+
configNewCommand.SetHandler(async name => await ConfigNewCommandHandler.CreateConfigFileAsync(name, logger), nameArgument);
320+
configCommand.Add(configNewCommand);
321+
312322
var configOpenCommand = new Command("open", "Open devproxyrc.json");
313323
configOpenCommand.SetHandler(() =>
314324
{

0 commit comments

Comments
 (0)