diff --git a/DevProxy.Abstractions/Utils/ProxyUtils.cs b/DevProxy.Abstractions/Utils/ProxyUtils.cs
index d07367e7..b5799481 100644
--- a/DevProxy.Abstractions/Utils/ProxyUtils.cs
+++ b/DevProxy.Abstractions/Utils/ProxyUtils.cs
@@ -10,6 +10,7 @@
using System.Collections.ObjectModel;
using System.Reflection;
using System.Text.Encodings.Web;
+using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
@@ -42,6 +43,23 @@ public static class ProxyUtils
// doesn't end with a path separator
public static string? AppFolder => Path.GetDirectoryName(AppContext.BaseDirectory);
+
+ ///
+ /// Gets the path to the user data folder for Dev Proxy.
+ /// On macOS: ~/Library/Application Support/dev-proxy/
+ /// On Linux: ~/.config/dev-proxy/ (or $XDG_CONFIG_HOME/dev-proxy/)
+ /// On Windows: %LocalAppData%\dev-proxy\
+ ///
+ public static string DataFolder
+ {
+ get
+ {
+ var basePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
+ ? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)
+ : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+ return Path.Combine(basePath, "dev-proxy");
+ }
+ }
public static JsonSerializerOptions JsonSerializerOptions { get; } = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
@@ -175,6 +193,7 @@ public static string ReplacePathTokens(string? path)
return path ?? string.Empty;
}
+ path = path.Replace("~dataFolder", DataFolder, StringComparison.OrdinalIgnoreCase);
return path.Replace("~appFolder", AppFolder, StringComparison.OrdinalIgnoreCase);
}
diff --git a/DevProxy/Commands/ConfigCommand.cs b/DevProxy/Commands/ConfigCommand.cs
index c502bc8f..5ead2b1e 100644
--- a/DevProxy/Commands/ConfigCommand.cs
+++ b/DevProxy/Commands/ConfigCommand.cs
@@ -106,7 +106,7 @@ internal static async Task RunValidateStandaloneAsync(string[] args)
using var loggerFactory = LoggerFactory.Create(builder =>
{
- builder
+ _ = builder
.SetMinimumLevel(LogLevel.Information)
.AddConsole(consoleOptions =>
{
@@ -215,17 +215,9 @@ private async Task DownloadConfigAsync(string configId, OutputFormat outputForma
{
try
{
- var appFolder = ProxyUtils.AppFolder;
- if (string.IsNullOrEmpty(appFolder) || !Directory.Exists(appFolder))
- {
- if (outputFormat == OutputFormat.Text)
- {
- _logger.LogError("App folder {AppFolder} not found", appFolder);
- }
- return;
- }
+ var dataFolder = ProxyUtils.DataFolder;
- var configFolderPath = Path.Combine(appFolder, "config");
+ var configFolderPath = Path.Combine(dataFolder, "configs");
_logger.LogDebug("Checking if config folder {ConfigFolderPath} exists...", configFolderPath);
if (!Directory.Exists(configFolderPath))
{
@@ -235,7 +227,7 @@ private async Task DownloadConfigAsync(string configId, OutputFormat outputForma
}
_logger.LogDebug("Getting target folder path for config {ConfigId}...", configId);
- var targetFolderPath = GetTargetFolderPath(appFolder, configId);
+ var targetFolderPath = GetTargetFolderPath(dataFolder, configId);
_logger.LogDebug("Creating target folder {TargetFolderPath}...", targetFolderPath);
_ = Directory.CreateDirectory(targetFolderPath);
@@ -287,7 +279,7 @@ private async Task DownloadConfigAsync(string configId, OutputFormat outputForma
{
if (_logger.IsEnabled(LogLevel.Information))
{
- _logger.LogInformation(" devproxy --config-file \"{ConfigFile}\"", configFile.Replace(appFolder, "~appFolder", StringComparison.OrdinalIgnoreCase));
+ _logger.LogInformation(" devproxy --config-file \"{ConfigFile}\"", configFile.Replace(dataFolder, "~dataFolder", StringComparison.OrdinalIgnoreCase));
}
}
}
@@ -298,7 +290,7 @@ private async Task DownloadConfigAsync(string configId, OutputFormat outputForma
{
if (_logger.IsEnabled(LogLevel.Information))
{
- _logger.LogInformation(" devproxy --mock-file \"{MockFile}\"", mockFile.Replace(appFolder, "~appFolder", StringComparison.OrdinalIgnoreCase));
+ _logger.LogInformation(" devproxy --mock-file \"{MockFile}\"", mockFile.Replace(dataFolder, "~dataFolder", StringComparison.OrdinalIgnoreCase));
}
}
}
@@ -332,13 +324,13 @@ private ProxyConfigInfo GetConfigInfo(string configFolder)
var configInfo = new ProxyConfigInfo();
_logger.LogDebug("Getting list of config files in {ConfigFolder}...", configFolder);
-
+
// Get both JSON and YAML files
var jsonFiles = Directory.GetFiles(configFolder, "*.json");
var yamlFiles = Directory.GetFiles(configFolder, "*.yaml");
var ymlFiles = Directory.GetFiles(configFolder, "*.yml");
var allConfigFiles = jsonFiles.Concat(yamlFiles).Concat(ymlFiles).ToArray();
-
+
if (allConfigFiles.Length == 0)
{
_logger.LogDebug("No config files found");
@@ -350,7 +342,7 @@ private ProxyConfigInfo GetConfigInfo(string configFolder)
_logger.LogDebug("Reading file {ConfigFile}...", configFile);
var fileContents = File.ReadAllText(configFile);
-
+
// Check for plugins marker (case-insensitive)
// For JSON: "plugins":
// For YAML: plugins:
@@ -561,9 +553,9 @@ private string GetTargetFileName(string name)
}
}
- private static string GetTargetFolderPath(string appFolder, string configId)
+ private static string GetTargetFolderPath(string dataFolder, string configId)
{
- var baseFolder = Path.Combine(appFolder, "config", configId);
+ var baseFolder = Path.Combine(dataFolder, "configs", configId);
var newFolder = baseFolder;
var i = 1;
while (Directory.Exists(newFolder))
@@ -701,7 +693,7 @@ private static async Task ValidateConfigCoreAsync(
if (configDoc.RootElement.TryGetProperty("plugins", out var pluginsElement) &&
pluginsElement.ValueKind == JsonValueKind.Array)
{
- ValidatePlugins(pluginsElement, configFileDirectory, errors, warnings, pluginNames);
+ ValidatePlugins(pluginsElement, configFileDirectory, errors, pluginNames);
}
else
{
@@ -737,7 +729,6 @@ private static void ValidatePlugins(
JsonElement pluginsElement,
string configFileDirectory,
List errors,
- List warnings,
List pluginNames)
{
var hasEnabledPlugins = false;
diff --git a/DevProxy/Commands/DevProxyCommand.cs b/DevProxy/Commands/DevProxyCommand.cs
index ce52e6b6..2ff5502b 100644
--- a/DevProxy/Commands/DevProxyCommand.cs
+++ b/DevProxy/Commands/DevProxyCommand.cs
@@ -33,7 +33,7 @@ sealed class DevProxyCommand : RootCommand
internal static readonly Option ConfigFileOption = new(ConfigFileOptionName, "-c")
{
HelpName = "config-file",
- Description = "Path to config file. If not specified, Dev Proxy searches for devproxyrc.jsonc or devproxyrc.json in the current directory, then in a .devproxy/ directory, then under the ~appFolder location. Supports ~appFolder token."
+ Description = "Path to config file. If not specified, Dev Proxy searches for devproxyrc.jsonc or devproxyrc.json in the current directory, then in a .devproxy/ directory, then under the ~appFolder location. Supports ~appFolder and ~dataFolder tokens."
};
internal const string NoFirstRunOptionName = "--no-first-run";
internal const string NoWatchOptionName = "--no-watch";