Skip to content

Commit

Permalink
Fix #531
Browse files Browse the repository at this point in the history
  • Loading branch information
bcssov committed Dec 23, 2024
1 parent 21d3784 commit db7c1ba
Show file tree
Hide file tree
Showing 7 changed files with 427 additions and 250 deletions.
96 changes: 61 additions & 35 deletions src/IronyModManager.IO/Mods/ModWriter.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@

// ***********************************************************************
// ***********************************************************************
// Assembly : IronyModManager.IO
// Author : Mario
// Created : 03-31-2020
//
// Last Modified By : Mario
// Last Modified On : 01-23-2024
// Last Modified On : 12-23-2024
// ***********************************************************************
// <copyright file="ModWriter.cs" company="Mario">
// Mario
Expand All @@ -31,7 +30,6 @@

namespace IronyModManager.IO.Mods
{

/// <summary>
/// Class ModWriter.
/// Implements the <see cref="IronyModManager.IO.Common.Mods.IModWriter" />
Expand Down Expand Up @@ -113,16 +111,17 @@ public async Task<bool> ApplyModsAsync(ModWriterParameters parameters)
{
throw new ArgumentException("Invalid descriptor type.");
}

Task<bool>[] tasks;

using (var mutex = await writeLock.LockAsync())
using (await writeLock.LockAsync())
{
tasks = new Task<bool>[]
{
Task.Run(async() => await sqliteExporter.ExportAsync(parameters)),
Task.Run(async() => await sqliteExporterBeta.ExportAsync(parameters)),
Task.Run(async() => await jsonExporter.ExportModsAsync(parameters))
};
tasks =
[
Task.Run(async () => await sqliteExporter.ExportAsync(parameters)),
Task.Run(async () => await sqliteExporterBeta.ExportAsync(parameters)),
Task.Run(async () => await jsonExporter.ExportModsAsync(parameters))
];
await Task.WhenAll(tasks);
}

Expand Down Expand Up @@ -158,6 +157,7 @@ public Task<bool> CanWriteToModDirectoryAsync(ModWriterParameters parameters)
// Real genious you picked C, D or whatever drive
return Task.FromResult(false);
}

var root = Path.Combine(el[0], el[1]);
if (!Directory.Exists(root) && !IsAdmin())
{
Expand All @@ -177,12 +177,15 @@ public Task<bool> CanWriteToModDirectoryAsync(ModWriterParameters parameters)
{
return Task.FromResult(false);
}

return Task.FromResult(true);
}
}
}

return Task.FromResult(true);
}

return Task.FromResult(false);
}

Expand All @@ -199,6 +202,7 @@ public Task<bool> CreateModDirectoryAsync(ModWriterParameters parameters)
Directory.CreateDirectory(fullPath);
return Task.FromResult(true);
}

return Task.FromResult(false);
}

Expand All @@ -217,8 +221,10 @@ Task<bool> delete()
DiskOperations.DeleteFile(fullPath);
return Task.FromResult(true);
}

return Task.FromResult(false);
}

var retry = new RetryStrategy();
return retry.RetryActionAsync(() => delete());
}
Expand All @@ -235,6 +241,7 @@ public Task<bool> DescriptorExistsAsync(ModWriterParameters parameters)
{
return Task.FromResult(true);
}

return Task.FromResult(false);
}

Expand All @@ -250,6 +257,7 @@ public string FormatPrefixModName(string prefix, string name)
{
return $"{prefix}{name}";
}

return name;
}

Expand All @@ -265,6 +273,7 @@ public virtual bool ModDirectoryExists(ModWriterParameters parameters)
{
return false;
}

return Directory.EnumerateFiles(fullPath, "*", SearchOption.AllDirectories).Any();
}

Expand Down Expand Up @@ -303,21 +312,25 @@ Task<bool> purge()
{
DiskOperations.DeleteDirectory(fullPath, true);
}

return Task.FromResult(true);
}
else if (File.Exists(fullPath))
{
DiskOperations.DeleteFile(fullPath);
var directory = Path.GetDirectoryName(fullPath);
var files = Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories);
var files = Directory.EnumerateFiles(directory!, "*", SearchOption.AllDirectories);
if (!files.Any())
{
DiskOperations.DeleteDirectory(directory, true);
}

return Task.FromResult(true);
}

return Task.FromResult(false);
}

var retry = new RetryStrategy();
return retry.RetryActionAsync(() => purge());
}
Expand All @@ -333,12 +346,10 @@ public Task<bool> SetDescriptorLockAsync(ModWriterParameters parameters, bool is
var fullPath = Path.Combine(parameters.RootDirectory ?? string.Empty, parameters.Mod.DescriptorFile ?? string.Empty);
if (File.Exists(fullPath))
{
_ = new System.IO.FileInfo(fullPath)
{
IsReadOnly = isLocked
};
_ = new System.IO.FileInfo(fullPath) { IsReadOnly = isLocked };
return Task.FromResult(true);
}

return Task.FromResult(false);
}

Expand All @@ -356,6 +367,7 @@ public async Task<bool> WriteDescriptorAsync(ModWriterParameters parameters, boo
{
throw new ArgumentException("Invalid descriptor type.");
}

async Task<bool> writeDescriptors()
{
// If needed I've got a much more complex serializer, it is written for Kerbal Space Program but the structure seems to be the same though this is much more simpler
Expand All @@ -367,12 +379,10 @@ async Task<bool> writeDescriptors()
{
if (File.Exists(fullPath))
{
_ = new System.IO.FileInfo(fullPath)
{
IsReadOnly = true
};
_ = new System.IO.FileInfo(fullPath) { IsReadOnly = true };
}
}

if (writeDescriptorInModDirectory)
{
var modPath = Path.Combine(parameters.Mod.FileName ?? string.Empty, parameters.DescriptorType == DescriptorType.DescriptorMod ? Shared.Constants.DescriptorFile : Shared.Constants.DescriptorJsonMetadata);
Expand All @@ -381,13 +391,17 @@ async Task<bool> writeDescriptors()
var dir = Path.GetDirectoryName(modPath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
Directory.CreateDirectory(dir!);
}
}

await writeDescriptor(modPath, true);
}

return true;
}

// ReSharper disable once UnusedLocalFunctionReturnValue
async Task<bool> writeDescriptor(string fullPath, bool truncatePath)
{
bool? state = null;
Expand All @@ -397,15 +411,14 @@ async Task<bool> writeDescriptor(string fullPath, bool truncatePath)
state = fileInfo.IsReadOnly;
fileInfo.IsReadOnly = false;
}
using var fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.Read);

await using var fs = new FileStream(fullPath!, FileMode.Create, FileAccess.Write, FileShare.Read);
var result = await WriteDescriptorToStreamAsync(parameters, fs, truncatePath);
if (state.HasValue)
{
var fileInfo = new System.IO.FileInfo(fullPath)
{
IsReadOnly = state.GetValueOrDefault()
};
_ = new System.IO.FileInfo(fullPath) { IsReadOnly = state.GetValueOrDefault() };
}

return result;
}

Expand All @@ -428,6 +441,7 @@ public Task<bool> WriteDescriptorToStreamAsync(ModWriterParameters parameters, S
{
throw new ArgumentException("Invalid descriptor type.");
}

return WriteDescriptorToStreamInternalAsync(parameters.Mod, stream, parameters.DescriptorType, truncatePath);
}

Expand All @@ -452,7 +466,7 @@ static async Task serializeDescriptorMod(IMod content, StreamWriter sw)
{
if (col.Any())
{
if (attr.KeyedArray)
if (attr!.KeyedArray)
{
foreach (var item in col)
{
Expand All @@ -466,6 +480,7 @@ static async Task serializeDescriptorMod(IMod content, StreamWriter sw)
{
await sw.WriteLineAsync($"\t\"{item.Replace("\"", "\\\"")}\"");
}

await sw.WriteLineAsync("}");
}
}
Expand All @@ -474,36 +489,44 @@ static async Task serializeDescriptorMod(IMod content, StreamWriter sw)
{
if (!string.IsNullOrWhiteSpace(val != null ? val.ToString() : string.Empty))
{
if (attr.AlternateNameEndsWithCondition?.Count() > 0 && attr.AlternateNameEndsWithCondition.Any(p => val.ToString().EndsWith(p, StringComparison.OrdinalIgnoreCase)))
if (attr!.AlternateNameEndsWithCondition?.Count() > 0 && attr.AlternateNameEndsWithCondition.Any(p => val!.ToString()!.EndsWith(p, StringComparison.OrdinalIgnoreCase)))
{
await sw.WriteLineAsync($"{attr.AlternatePropertyName}=\"{val.ToString().Replace("\"", "\\\"")}\"");
await sw.WriteLineAsync($"{attr.AlternatePropertyName}=\"{val?.ToString()?.Replace("\"", "\\\"")}\"");
}
else
{
await sw.WriteLineAsync($"{attr.PropertyName}=\"{val.ToString().Replace("\"", "\\\"")}\"");
await sw.WriteLineAsync($"{attr.PropertyName}=\"{val?.ToString()?.Replace("\"", "\\\"")}\"");
}
}
}
}
}

static async Task serializeJsonDescriptorMod(IMod content, StreamWriter sw)
{
var customData = content.AdditionalData != null ? new Dictionary<string, object>(content.AdditionalData) : new Dictionary<string, object>();
if (content.ReplacePath != null && content.ReplacePath.Any())
{
customData[Shared.Constants.JsonMetadataReplacePaths] = content.ReplacePath;
}

if (content.UserDir != null && content.UserDir.Any())
{
customData[Shared.Constants.DescriptorUserDir] = content.UserDir;
}

var metaData = new JsonMetadata()
var relationshipData = new List<Dictionary<string, object>>();
if (content.RelationshipData != null)
{
relationshipData.AddRange(content.RelationshipData.Select(relData => new Dictionary<string, object>(relData)));
}

var metaData = new JsonMetadata
{
Id = content.RemoteId.HasValue ? content.RemoteId.ToString() : string.Empty,
Id = !string.IsNullOrWhiteSpace(content.JsonId) ? content.JsonId : content.RemoteId.HasValue ? content.RemoteId.ToString() : string.Empty,
Name = content.Name,
Path = content.FileName,
Relationships = content.Dependencies != null ? content.Dependencies.ToList() : new List<string>(),
Relationships = relationshipData,
SupportedGameVersion = content.Version,
Tags = content.Tags != null ? content.Tags.ToList() : new List<string>(),
ShortDescription = string.Empty,
Expand All @@ -519,7 +542,8 @@ static async Task serializeJsonDescriptorMod(IMod content, StreamWriter sw)
mod = mapper.Map<IMod>(mod);
mod.FileName = descriptorType == DescriptorType.JsonMetadata ? null : string.Empty;
}
using var sw = new StreamWriter(stream, leaveOpen: true);

await using var sw = new StreamWriter(stream, leaveOpen: true);
if (descriptorType == DescriptorType.DescriptorMod)
{
await serializeDescriptorMod(mod, sw);
Expand All @@ -528,6 +552,7 @@ static async Task serializeJsonDescriptorMod(IMod content, StreamWriter sw)
{
await serializeJsonDescriptorMod(mod, sw);
}

await sw.FlushAsync();
return true;
}
Expand All @@ -545,6 +570,7 @@ private bool IsAdmin()
using var identity = WindowsIdentity.GetCurrent();
return new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator);
}

return false;
}
catch
Expand Down Expand Up @@ -597,7 +623,7 @@ private class JsonMetadata
/// </summary>
/// <value>The relationships.</value>
[JsonProperty("relationships", NullValueHandling = NullValueHandling.Include)]
public List<string> Relationships { get; set; }
public List<Dictionary<string, object>> Relationships { get; set; }

/// <summary>
/// Gets or sets the short description.
Expand Down
Loading

0 comments on commit db7c1ba

Please sign in to comment.