Ensure appsettings.json is created in a writable location.

This commit is contained in:
Michael Bucari-Tovo 2023-02-12 15:32:51 -07:00
parent 3bca495521
commit 6fdd6293ce
3 changed files with 77 additions and 80 deletions

View File

@ -11,7 +11,6 @@ using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using ApplicationServices; using ApplicationServices;
using Dinah.Core;
namespace LibationAvalonia namespace LibationAvalonia
{ {
@ -53,7 +52,7 @@ namespace LibationAvalonia
// check for existing settings in default location // check for existing settings in default location
var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json"); var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json");
if (Configuration.SettingsFileIsValid(defaultSettingsFile)) if (Configuration.SettingsFileIsValid(defaultSettingsFile))
config.SetLibationFiles(defaultLibationFilesDir); Configuration.SetLibationFiles(defaultLibationFilesDir);
if (config.LibationSettingsAreValid) if (config.LibationSettingsAreValid)
{ {
@ -86,7 +85,7 @@ namespace LibationAvalonia
// - error message, Exit() // - error message, Exit()
if (setupDialog.IsNewUser) if (setupDialog.IsNewUser)
{ {
setupDialog.Config.SetLibationFiles(Configuration.UserProfile); Configuration.SetLibationFiles(Configuration.UserProfile);
ShowSettingsWindow(desktop, setupDialog.Config, OnSettingsCompleted); ShowSettingsWindow(desktop, setupDialog.Config, OnSettingsCompleted);
} }
else if (setupDialog.IsReturningUser) else if (setupDialog.IsReturningUser)
@ -178,7 +177,7 @@ namespace LibationAvalonia
private async void OnLibationFilesCompleted(IClassicDesktopStyleApplicationLifetime desktop, LibationFilesDialog libationFilesDialog, Configuration config) private async void OnLibationFilesCompleted(IClassicDesktopStyleApplicationLifetime desktop, LibationFilesDialog libationFilesDialog, Configuration config)
{ {
config.SetLibationFiles(libationFilesDialog.SelectedDirectory); Configuration.SetLibationFiles(libationFilesDialog.SelectedDirectory);
if (config.LibationSettingsAreValid) if (config.LibationSettingsAreValid)
{ {
await RunMigrationsAsync(config); await RunMigrationsAsync(config);

View File

@ -10,39 +10,6 @@ namespace LibationFileManager
{ {
public partial class Configuration public partial class Configuration
{ {
private static string getAppsettingsFile()
{
const string appsettings_filename = "appsettings.json";
const string empty_json = "{ }";
System.Collections.Generic.Queue<string> searchDirs = new();
searchDirs.Enqueue(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
searchDirs.Enqueue(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation"));
searchDirs.Enqueue(UserProfile);
do
{
var appsettingsFile = Path.Combine(searchDirs.Dequeue(), appsettings_filename);
if (File.Exists(appsettingsFile))
return appsettingsFile;
try
{
File.WriteAllText(appsettingsFile, empty_json);
return appsettingsFile;
}
catch { }
}
while (searchDirs.Count > 0);
//We Could not find or create appsettings.json.
//As a Hail Mary, create it in temp files.
var tempAppsettings = Path.GetTempFileName();
File.WriteAllText(tempAppsettings, empty_json);
return tempAppsettings;
}
private static string APPSETTINGS_JSON { get; } = getAppsettingsFile(); private static string APPSETTINGS_JSON { get; } = getAppsettingsFile();
private const string LIBATION_FILES_KEY = "LibationFiles"; private const string LIBATION_FILES_KEY = "LibationFiles";
@ -78,31 +45,58 @@ namespace LibationFileManager
private static string libationFilesPathCache { get; set; } private static string libationFilesPathCache { get; set; }
private string getLibationFilesSettingFromJson() private static string getAppsettingsFile()
{
const string appsettings_filename = "appsettings.json";
//Possible appsettings.json locations, in order of preference.
string[] possibleAppsettingsFiles = new[]
{
Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), appsettings_filename),
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Libation", appsettings_filename),
Path.Combine(UserProfile, appsettings_filename),
Path.Combine(Path.GetTempPath(), "Libation", appsettings_filename)
};
//Try to find and validate appsettings.json in each folder
foreach (var appsettingsFile in possibleAppsettingsFiles)
{
if (File.Exists(appsettingsFile))
{ {
string startingContents = null;
try try
{ {
startingContents = File.ReadAllText(APPSETTINGS_JSON); var appSettings = JObject.Parse(File.ReadAllText(appsettingsFile));
var startingJObj = JObject.Parse(startingContents);
if (startingJObj.ContainsKey(LIBATION_FILES_KEY)) if (appSettings.ContainsKey(LIBATION_FILES_KEY)
{ && appSettings[LIBATION_FILES_KEY] is JValue jval
var startingValue = startingJObj[LIBATION_FILES_KEY].Value<string>(); && jval.Value is string settingsPath
if (!string.IsNullOrWhiteSpace(startingValue)) && !string.IsNullOrWhiteSpace(settingsPath))
return startingValue; return appsettingsFile;
}
} }
catch { } catch { }
}
// not found. write to file. read from file
var endingContents = new JObject { { LIBATION_FILES_KEY, UserProfile.ToString() } }.ToString(Formatting.Indented);
if (startingContents != endingContents)
{
File.WriteAllText(APPSETTINGS_JSON, endingContents);
System.Threading.Thread.Sleep(100);
} }
//Valid appsettings.json not found. Try to create it in each folder.
var endingContents = new JObject { { LIBATION_FILES_KEY, UserProfile } }.ToString(Formatting.Indented);
foreach (var appsettingsFile in possibleAppsettingsFiles)
{
try
{
File.WriteAllText(appsettingsFile, endingContents);
return appsettingsFile;
}
catch(Exception ex)
{
Log.Error(ex, $"Failed to create {appsettingsFile}");
}
}
throw new ApplicationException($"Could not locate or create {appsettings_filename}");
}
private static string getLibationFilesSettingFromJson()
{
// do not check whether directory exists. special/meta directory (eg: AppDir) is valid // do not check whether directory exists. special/meta directory (eg: AppDir) is valid
// verify from live file. no try/catch. want failures to be visible // verify from live file. no try/catch. want failures to be visible
var jObjFinal = JObject.Parse(File.ReadAllText(APPSETTINGS_JSON)); var jObjFinal = JObject.Parse(File.ReadAllText(APPSETTINGS_JSON));
@ -110,16 +104,8 @@ namespace LibationFileManager
return valueFinal; return valueFinal;
} }
public void SetLibationFiles(string directory) public static void SetLibationFiles(string directory)
{ {
// ensure exists
if (!File.Exists(APPSETTINGS_JSON))
{
// getter creates new file, loads PersistentDictionary
var _ = LibationFiles;
System.Threading.Thread.Sleep(100);
}
libationFilesPathCache = null; libationFilesPathCache = null;
var startingContents = File.ReadAllText(APPSETTINGS_JSON); var startingContents = File.ReadAllText(APPSETTINGS_JSON);
@ -131,14 +117,26 @@ namespace LibationFileManager
if (startingContents == endingContents) if (startingContents == endingContents)
return; return;
try
{
// now it's set in the file again but no settings have moved yet // now it's set in the file again but no settings have moved yet
File.WriteAllText(APPSETTINGS_JSON, endingContents); File.WriteAllText(APPSETTINGS_JSON, endingContents);
tryLog(() => Log.Logger.Information("Libation files changed {@DebugInfo}", new { APPSETTINGS_JSON, LIBATION_FILES_KEY, directory }));
}
catch (IOException ex)
{
tryLog(() => Log.Logger.Error(ex, "Failed to change Libation files location {@DebugInfo}", new { APPSETTINGS_JSON, LIBATION_FILES_KEY, directory }));
}
static void tryLog(Action logAction)
{
try try
{ {
Log.Logger.Information("Libation files changed {@DebugInfo}", new { APPSETTINGS_JSON, LIBATION_FILES_KEY, directory }); logAction();
} }
catch { } catch { }
} }
} }
}
} }

View File

@ -92,7 +92,7 @@ namespace LibationWinForms
// check for existing settings in default location // check for existing settings in default location
var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json"); var defaultSettingsFile = Path.Combine(defaultLibationFilesDir, "Settings.json");
if (Configuration.SettingsFileIsValid(defaultSettingsFile)) if (Configuration.SettingsFileIsValid(defaultSettingsFile))
config.SetLibationFiles(defaultLibationFilesDir); Configuration.SetLibationFiles(defaultLibationFilesDir);
if (config.LibationSettingsAreValid) if (config.LibationSettingsAreValid)
return; return;
@ -112,7 +112,7 @@ namespace LibationWinForms
} }
if (setupDialog.IsNewUser) if (setupDialog.IsNewUser)
config.SetLibationFiles(defaultLibationFilesDir); Configuration.SetLibationFiles(defaultLibationFilesDir);
else if (setupDialog.IsReturningUser) else if (setupDialog.IsReturningUser)
{ {
var libationFilesDialog = new LibationFilesDialog(); var libationFilesDialog = new LibationFilesDialog();
@ -123,7 +123,7 @@ namespace LibationWinForms
return; return;
} }
config.SetLibationFiles(libationFilesDialog.SelectedDirectory); Configuration.SetLibationFiles(libationFilesDialog.SelectedDirectory);
if (config.LibationSettingsAreValid) if (config.LibationSettingsAreValid)
return; return;