Skip to content

Commit

Permalink
[WIP] Transfer from laptop
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloambrosio committed Sep 30, 2024
1 parent 1f8c2c3 commit 17bac94
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/Core/IModInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace Core;

public interface IModInstaller
{
void Apply(IReadOnlyDictionary<string, InternalModInstallationState> currentState, IReadOnlyCollection<ModPackage> packages, string installDir, Action<IInstallation> afterInstall, ModInstaller.IEventHandler eventHandler, CancellationToken cancellationToken);
void Apply(IReadOnlyDictionary<string, ModInstallationState> currentState, IReadOnlyCollection<ModPackage> packages, string installDir, Action<IInstallation> afterInstall, ModInstaller.IEventHandler eventHandler, CancellationToken cancellationToken);
}
21 changes: 19 additions & 2 deletions src/Core/ModInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,36 @@ public ModInstaller(IInstallationFactory installationFactory, IBackupStrategy ba
}

public void Apply(
IReadOnlyDictionary<string, InternalModInstallationState> currentState,
IReadOnlyDictionary<string, ModInstallationState> currentState,
IReadOnlyCollection<ModPackage> toInstall,
string installDir,
Action<IInstallation> afterCallback,
IEventHandler eventHandler,
CancellationToken cancellationToken)
{
var updaters = FooUpdaters(currentState, toInstall);


UninstallPackages(currentState, installDir, afterCallback, eventHandler, cancellationToken);
InstallPackages(toInstall, installDir, afterCallback, eventHandler, cancellationToken);
}

private object FooUpdaters(

Check failure on line 78 in src/Core/ModInstaller.cs

View workflow job for this annotation

GitHub Actions / build (Release, x64)

'ModInstaller.FooUpdaters(IReadOnlyDictionary<string, ModInstallationState>, IReadOnlyCollection<ModPackage>)': not all code paths return a value

Check failure on line 78 in src/Core/ModInstaller.cs

View workflow job for this annotation

GitHub Actions / build (Release, x64)

'ModInstaller.FooUpdaters(IReadOnlyDictionary<string, ModInstallationState>, IReadOnlyCollection<ModPackage>)': not all code paths return a value
IReadOnlyDictionary<string, ModInstallationState> currentState,
IReadOnlyCollection<ModPackage> toInstall)
{
var left = new Dictionary<string, ModInstallationState>(currentState);
var updatersToInstall = toInstall.Select(_ => {
if (left.TryGetValue(_.PackageName, out var installState))
{
left.Remove(_.PackageName);
}
new ModUpdater(_, installState);

Check failure on line 88 in src/Core/ModInstaller.cs

View workflow job for this annotation

GitHub Actions / build (Release, x64)

Argument 1: cannot convert from 'Core.Mods.ModPackage' to 'Core.Mods.IInstaller?'

Check failure on line 88 in src/Core/ModInstaller.cs

View workflow job for this annotation

GitHub Actions / build (Release, x64)

Argument 1: cannot convert from 'Core.Mods.ModPackage' to 'Core.Mods.IInstaller?'
});
}

private void UninstallPackages(
IReadOnlyDictionary<string, InternalModInstallationState> currentState,
IReadOnlyDictionary<string, ModInstallationState> currentState,
string installDir,
Action<IInstallation> afterUninstall,
IEventHandler eventHandler,
Expand Down
16 changes: 7 additions & 9 deletions src/Core/ModManager.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System.Globalization;
using Core.Games;
using Core.IO;
using Core.Mods;
using Core.State;
using Core.Utils;
using Microsoft.VisualBasic;
using static Core.IModManager;

namespace Core;
Expand Down Expand Up @@ -53,7 +51,7 @@ public List<ModState> FetchState()
var availableModPackages = enabledModPackages.Merge(disabledModPackages);

var bootfilesFailed = installedMods.Where(kv => BootfilesManager.IsBootFiles(kv.Key) && (kv.Value?.Partial ?? false)).Any();
var isModInstalled = installedMods.SelectValues<string, InternalModInstallationState, bool?>(modInstallationState =>
var isModInstalled = installedMods.SelectValues<string, ModInstallationState, bool?>(modInstallationState =>
modInstallationState is null ? false : ((modInstallationState.Partial || bootfilesFailed) ? null : true)
);
var modsOutOfDate = installedMods.SelectValues((packageName, modInstallationState) =>
Expand Down Expand Up @@ -81,7 +79,7 @@ public List<ModState> FetchState()
}).ToList();
}

private static bool IsOutOfDate(ModPackage? modPackage, InternalModInstallationState? modInstallationState)
private static bool IsOutOfDate(ModPackage? modPackage, ModInstallationState? modInstallationState)
{
if (modPackage is null || modInstallationState is null)
{
Expand Down Expand Up @@ -140,14 +138,14 @@ public void InstallEnabledMods(IEventHandler eventHandler, CancellationToken can

// Clean what left by a previous failed installation
tempDir.Cleanup();
InstallMods(modRepository.ListEnabledMods(), eventHandler, cancellationToken);
UpdateMods(modRepository.ListEnabledMods(), eventHandler, cancellationToken);
tempDir.Cleanup();
}

public void UninstallAllMods(IEventHandler eventHandler, CancellationToken cancellationToken = default)
{
CheckGameNotRunning();
InstallMods(Array.Empty<ModPackage>(), eventHandler, cancellationToken);
UpdateMods(Array.Empty<ModPackage>(), eventHandler, cancellationToken);
}

private void CheckGameNotRunning()
Expand All @@ -158,10 +156,10 @@ private void CheckGameNotRunning()
}
}

private void InstallMods(IReadOnlyCollection<ModPackage> packages, IEventHandler eventHandler, CancellationToken cancellationToken)
private void UpdateMods(IReadOnlyCollection<ModPackage> packages, IEventHandler eventHandler, CancellationToken cancellationToken)
{
var previousState = statePersistence.ReadState().Install.Mods;
var currentState = new Dictionary<string, InternalModInstallationState>(previousState);
var currentState = new Dictionary<string, ModInstallationState>(previousState);
try
{
modInstaller.Apply(
Expand Down Expand Up @@ -198,7 +196,7 @@ private void InstallMods(IReadOnlyCollection<ModPackage> packages, IEventHandler
}
finally
{
statePersistence.WriteState(new InternalState(
statePersistence.WriteState(new SavedState(
Install: new(
Time: currentState.Values.Max(_ => _.Time),
Mods: currentState
Expand Down
34 changes: 34 additions & 0 deletions src/Core/Mods/ModUpdater.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Core.State;

namespace Core.Mods;

public class ModUpdater
{
private readonly IInstaller? installer;
public ModInstallationState State { get; private set; }

/// <summary>
///
/// </summary>
/// <param name="installer">Installer, or null for uninstall.</param>
/// <param name="state">Installation state, or null if not installed.</param>
public ModUpdater(IInstaller? installer, ModInstallationState? currentState)
{
this.installer = installer;
State = currentState ?? ModInstallationState.Empty;
}

public bool Installed => State.Files.Count > 0;

//// Do we just need accept callaback for whitelisting, etc.?
//// Add CancellationToken to stop
//public void Update()
//{
// // Could move the driveline config in the state
// // The other config should stay outside: even if we make it configurable per mod,
// // it will have an impact on what is installed rather than what is configured!
//}

public void Install() => throw new NotImplementedException();
public void Uninstall() => throw new NotImplementedException();
}
4 changes: 2 additions & 2 deletions src/Core/State/IStatePersistence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public interface IStatePersistence
{
public InternalState ReadState();
public void WriteState(InternalState state);
public SavedState ReadState();
public void WriteState(SavedState state);
}
12 changes: 6 additions & 6 deletions src/Core/State/JsonFileStatePersistence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ public JsonFileStatePersistence(string modsDir)
oldStateFile = Path.Combine(modsDir, OldStateFileName);
}

public InternalState ReadState()
public SavedState ReadState()
{
// Always favour new state if present
if (File.Exists(stateFile))
{
var contents = File.ReadAllText(stateFile);
var state = JsonConvert.DeserializeObject<InternalState>(contents);
var state = JsonConvert.DeserializeObject<SavedState>(contents);
// Fill mod install time if not present (for migration)
return state with
{
Expand All @@ -46,21 +46,21 @@ public InternalState ReadState()
var contents = File.ReadAllText(oldStateFile);
var oldState = JsonConvert.DeserializeObject<Dictionary<string, IReadOnlyCollection<string>>>(contents);
var installTime = File.GetLastWriteTimeUtc(oldStateFile);
return new InternalState(
return new SavedState(
Install: new(
Time: installTime,
Mods: oldState.AsEnumerable().ToDictionary(
kv => kv.Key,
kv => new InternalModInstallationState(Time: installTime, FsHash: null, Partial: false, Files: kv.Value)
kv => new ModInstallationState(Time: installTime, FsHash: null, Partial: false, Files: kv.Value)
)
)
);
}

return InternalState.Empty();
return SavedState.Empty();
}

public void WriteState(InternalState state)
public void WriteState(SavedState state)
{
// Remove old state if upgrading from a previous version
File.Delete(oldStateFile);
Expand Down
23 changes: 13 additions & 10 deletions src/Core/State/InternalState.cs → src/Core/State/SavedState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@

namespace Core.State;

public record InternalState(
InternalInstallationState Install
public record SavedState(
InstallationState Install
)
{
public static InternalState Empty() => new(
Install: InternalInstallationState.Empty()
public static SavedState Empty() => new(
Install: InstallationState.Empty()
);
};

public record InternalInstallationState(
public record InstallationState(
// TODO: needed for backward compatibility
DateTime? Time,
IReadOnlyDictionary<string, InternalModInstallationState> Mods
IReadOnlyDictionary<string, ModInstallationState> Mods
)
{
public static InternalInstallationState Empty() => new(
public static InstallationState Empty() => new(
Time: null,
Mods: ImmutableDictionary.Create<string, InternalModInstallationState>()
Mods: ImmutableDictionary.Create<string, ModInstallationState>()
);
};

public record InternalModInstallationState(
public record ModInstallationState(
// TODO: nullable for backward compatibility
DateTime? Time,
// Unknown when partially installed or upgrading from a previous version
Expand All @@ -32,4 +32,7 @@ public record InternalModInstallationState(
// infer from null hash after the first install
bool Partial,
IReadOnlyCollection<string> Files
);
)
{
public static ModInstallationState Empty => new(null, null, false, Array.Empty<string>());
}
12 changes: 6 additions & 6 deletions tests/Core.Tests/ModInstallerIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public ModInstallerIntegrationTest()
public void Apply_NoMods()
{
modInstaller.Apply(
new Dictionary<string, InternalModInstallationState>(),
new Dictionary<string, ModInstallationState>(),
[],
"",
RecordState,
Expand All @@ -69,7 +69,7 @@ public void Apply_UninstallsMods()
CreateTestFile("AF");

modInstaller.Apply(
new Dictionary<string, InternalModInstallationState>{
new Dictionary<string, ModInstallationState>{
["A"] = new(
Time: null,
FsHash: 42,
Expand Down Expand Up @@ -106,7 +106,7 @@ public void Apply_UninstallStopsIfBackupFails()
backupStrategyMock.Setup(_ => _.RestoreBackup(TestPath("Fail"))).Throws<TestException>();

modInstaller.Invoking(_ => _.Apply(
new Dictionary<string, InternalModInstallationState>
new Dictionary<string, ModInstallationState>
{
["A"] = new(
Time: null,
Expand All @@ -127,7 +127,7 @@ public void Apply_UninstallStopsIfBackupFails()
public void Apply_InstallsMods()
{
modInstaller.Apply(
new Dictionary<string, InternalModInstallationState>(),
new Dictionary<string, ModInstallationState>(),
[
PackageInstalling("A", 42, [
"AF"
Expand Down Expand Up @@ -161,7 +161,7 @@ public void Apply_InstallStopsIfBackupFails()
backupStrategyMock.Setup(_ => _.PerformBackup(TestPath("Fail"))).Throws<TestException>();

modInstaller.Invoking(_ => _.Apply(
new Dictionary<string, InternalModInstallationState>(),
new Dictionary<string, ModInstallationState>(),
[
PackageInstalling("A", 42, [
"AF1", "Fail", "AF2"
Expand All @@ -180,7 +180,7 @@ public void Apply_UpdatesMods()
{
var endState = new Dictionary<string, IInstallation>();
modInstaller.Apply(
new Dictionary<string, InternalModInstallationState>
new Dictionary<string, ModInstallationState>
{
["A"] = new(Time: null, FsHash: 1, Partial: false, Files: [
"AF",
Expand Down
Loading

0 comments on commit 17bac94

Please sign in to comment.