diff --git a/examples/ExampleApplication/Program.cs b/examples/ExampleApplication/Program.cs index 26b3a5c..344ba82 100644 --- a/examples/ExampleApplication/Program.cs +++ b/examples/ExampleApplication/Program.cs @@ -4,4 +4,9 @@ using TinyUpdate.Core; -Console.WriteLine("Hello, World! In Test Runner?: " + Testing.InTestRunner); \ No newline at end of file +var versionDetails = VersionHelper.GetVersionDetails(); + +Console.WriteLine("Hello, Updates!"); +Console.WriteLine("In Test Runner?: " + Testing.InTestRunner); +Console.WriteLine("Version: " + versionDetails.Version.ToString()); +Console.WriteLine("SourceRevisionId: " + versionDetails.SourceRevisionId.ToString()); \ No newline at end of file diff --git a/src/Appliers/TinyUpdate.Desktop/DesktopApplier.cs b/src/Appliers/TinyUpdate.Desktop/DesktopApplier.cs index a79d3a0..2036a6a 100644 --- a/src/Appliers/TinyUpdate.Desktop/DesktopApplier.cs +++ b/src/Appliers/TinyUpdate.Desktop/DesktopApplier.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System.Collections.Immutable; +using System.Diagnostics; using System.IO.Abstractions; using Microsoft.Extensions.Logging; using TinyUpdate.Core.Abstract.Delta; @@ -28,17 +29,24 @@ public DesktopApplier(ILogger logger, IHasher hasher, INative? n public async Task ApplyUpdates(ICollection updatePackages, string applicationLocation, IProgress? progress = null) { - var previousVersion = updatePackages.OrderBy(x => x.ReleaseEntry.PreviousVersion).First().ReleaseEntry.PreviousVersion; - var newVersion = updatePackages.OrderBy(x => x.ReleaseEntry.PreviousVersion).Last().ReleaseEntry.PreviousVersion; + if (updatePackages.Count == 0) + { + //TODO: Add logging + return false; + } + + var orderedUpdatePackages = updatePackages.OrderBy(x => x.ReleaseEntry.PreviousVersion).ToImmutableArray(); - var previousVersionLocation = Path.Combine(applicationLocation, previousVersion.ToString()); - var newVersionLocation = Path.Combine(applicationLocation, newVersion.ToString()); var multiProgress = progress != null ? new MultiProgress(progress, updatePackages.Count) : null; - foreach (var updatePackage in updatePackages) + foreach (var updatePackage in orderedUpdatePackages) { + var releaseEntry = updatePackage.ReleaseEntry; + var previousVersionLocation = Path.Combine(applicationLocation, releaseEntry.PreviousVersion.ToString()); + var newVersionLocation = Path.Combine(applicationLocation, releaseEntry.NewVersion.ToString()); + var successful = await ApplyUpdate(updatePackage, previousVersionLocation, newVersionLocation, multiProgress); if (!successful) diff --git a/src/Deltas/TinyUpdate.Delta.MSDelta/Struct/DeltaHash.cs b/src/Deltas/TinyUpdate.Delta.MSDelta/Struct/DeltaHash.cs index 2c2c24b..8571a33 100644 --- a/src/Deltas/TinyUpdate.Delta.MSDelta/Struct/DeltaHash.cs +++ b/src/Deltas/TinyUpdate.Delta.MSDelta/Struct/DeltaHash.cs @@ -1,5 +1,6 @@ using System.Runtime.InteropServices; using TinyUpdate.Core; +using TinyUpdate.Core.Services; namespace TinyUpdate.Delta.MSDelta.Struct; diff --git a/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs b/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs index 25d221a..445e408 100644 --- a/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs +++ b/src/TinyUpdate.Core/Abstract/ReleaseEntry.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using SemVersion; +using TinyUpdate.Core.Converters; namespace TinyUpdate.Core.Abstract; diff --git a/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackage.cs b/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackage.cs index d75c7c6..2036606 100644 --- a/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackage.cs +++ b/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackage.cs @@ -1,20 +1,7 @@ -using System.Diagnostics.CodeAnalysis; -using TinyUpdate.Core.Model; +using TinyUpdate.Core.Model; namespace TinyUpdate.Core.Abstract.UpdatePackage; -public record LoadResult -{ - public static LoadResult Failed(string message) => new() { Successful = false, Message = message }; - - public static readonly LoadResult Success = new() { Successful = true }; - - [MemberNotNullWhen(false, nameof(Message))] - public bool Successful { get; protected init; } - - public string? Message { get; protected init; } -} - /// /// Provides base functionality for handling update packages /// diff --git a/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackageFactory.cs b/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackageFactory.cs index 1db98f9..971e60c 100644 --- a/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackageFactory.cs +++ b/src/TinyUpdate.Core/Abstract/UpdatePackage/IUpdatePackageFactory.cs @@ -1,4 +1,6 @@ -namespace TinyUpdate.Core.Abstract.UpdatePackage; +using TinyUpdate.Core.Model; + +namespace TinyUpdate.Core.Abstract.UpdatePackage; public interface IUpdatePackageFactory { diff --git a/src/TinyUpdate.Core/SemanticVersionConverter.cs b/src/TinyUpdate.Core/Converters/SemanticVersionConverter.cs similarity index 93% rename from src/TinyUpdate.Core/SemanticVersionConverter.cs rename to src/TinyUpdate.Core/Converters/SemanticVersionConverter.cs index 8badacc..a6c4b71 100644 --- a/src/TinyUpdate.Core/SemanticVersionConverter.cs +++ b/src/TinyUpdate.Core/Converters/SemanticVersionConverter.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; using SemVersion; -namespace TinyUpdate.Core; +namespace TinyUpdate.Core.Converters; public class SemanticVersionConverter : JsonConverter { diff --git a/src/TinyUpdate.Core/Model/DeltaCreationResult.cs b/src/TinyUpdate.Core/Model/DeltaCreationResult.cs index 8429865..59919c9 100644 --- a/src/TinyUpdate.Core/Model/DeltaCreationResult.cs +++ b/src/TinyUpdate.Core/Model/DeltaCreationResult.cs @@ -6,7 +6,7 @@ namespace TinyUpdate.Core.Model; /// /// Details of creating a new delta update /// -public record DeltaCreationResult(IDeltaCreation? Creator, Stream? DeltaStream, bool Successful) +public class DeltaCreationResult(IDeltaCreation? creator, Stream? deltaStream, bool successful) { /// /// Failed to create a delta update @@ -16,16 +16,16 @@ public record DeltaCreationResult(IDeltaCreation? Creator, Stream? DeltaStream, /// /// The that created the update /// - public IDeltaCreation? Creator { get; } = Creator; + public IDeltaCreation? Creator { get; } = creator; /// /// The contents of the delta update /// - public Stream? DeltaStream { get; } = DeltaStream; + public Stream? DeltaStream { get; } = deltaStream; /// /// If we was successful in creating a delta update /// [MemberNotNullWhen(true, nameof(Creator), nameof(DeltaStream))] - public bool Successful { get; } = Successful; + public bool Successful { get; } = successful; } \ No newline at end of file diff --git a/src/TinyUpdate.Core/Model/LoadResult.cs b/src/TinyUpdate.Core/Model/LoadResult.cs new file mode 100644 index 0000000..78079f2 --- /dev/null +++ b/src/TinyUpdate.Core/Model/LoadResult.cs @@ -0,0 +1,15 @@ +using System.Diagnostics.CodeAnalysis; + +namespace TinyUpdate.Core.Abstract.UpdatePackage; + +public record LoadResult +{ + public static LoadResult Failed(string message) => new() { Successful = false, Message = message }; + + public static readonly LoadResult Success = new() { Successful = true }; + + [MemberNotNullWhen(false, nameof(Message))] + public bool Successful { get; protected init; } + + public string? Message { get; protected init; } +} \ No newline at end of file diff --git a/src/TinyUpdate.Core/Model/LoadUpdatePackageResult.cs b/src/TinyUpdate.Core/Model/LoadUpdatePackageResult.cs new file mode 100644 index 0000000..12182e7 --- /dev/null +++ b/src/TinyUpdate.Core/Model/LoadUpdatePackageResult.cs @@ -0,0 +1,26 @@ +using System.Diagnostics.CodeAnalysis; +using TinyUpdate.Core.Abstract.UpdatePackage; + +namespace TinyUpdate.Core.Model; + +public record LoadUpdatePackageResult +{ + public LoadUpdatePackageResult(bool successful, string? message, IUpdatePackage? updatePackage) + { + Successful = successful; + Message = message; + UpdatePackage = updatePackage; + } + + public static LoadUpdatePackageResult Failed(string message) => new(false, message, null); + + public static LoadUpdatePackageResult Success(IUpdatePackage updatePackage) => new(true, null, updatePackage); + + [MemberNotNullWhen(true, nameof(UpdatePackage))] + [MemberNotNullWhen(false, nameof(Message))] + public bool Successful { get; } + + public string? Message { get; } + + public IUpdatePackage? UpdatePackage { get; } +} \ No newline at end of file diff --git a/src/TinyUpdate.Core/Model/VersionDetails.cs b/src/TinyUpdate.Core/Model/VersionDetails.cs new file mode 100644 index 0000000..4580457 --- /dev/null +++ b/src/TinyUpdate.Core/Model/VersionDetails.cs @@ -0,0 +1,12 @@ +namespace TinyUpdate.Core.Model; + +public ref struct VersionDetails +{ + public VersionDetails(ReadOnlySpan version) + { + Version = version; + } + + public ReadOnlySpan Version { get; internal set; } = ReadOnlySpan.Empty; + public ReadOnlySpan SourceRevisionId { get; internal set; } = ReadOnlySpan.Empty; +} \ No newline at end of file diff --git a/src/TinyUpdate.Core/DeltaManager.cs b/src/TinyUpdate.Core/Services/DeltaManager.cs similarity index 99% rename from src/TinyUpdate.Core/DeltaManager.cs rename to src/TinyUpdate.Core/Services/DeltaManager.cs index fc8d09b..f566c37 100644 --- a/src/TinyUpdate.Core/DeltaManager.cs +++ b/src/TinyUpdate.Core/Services/DeltaManager.cs @@ -5,7 +5,7 @@ using TinyUpdate.Core.Abstract.Delta; using TinyUpdate.Core.Model; -namespace TinyUpdate.Core; +namespace TinyUpdate.Core.Services; /// /// Default implementation diff --git a/src/TinyUpdate.Core/SHA256.cs b/src/TinyUpdate.Core/Services/SHA256.cs similarity index 98% rename from src/TinyUpdate.Core/SHA256.cs rename to src/TinyUpdate.Core/Services/SHA256.cs index 9a781cc..896cd23 100644 --- a/src/TinyUpdate.Core/SHA256.cs +++ b/src/TinyUpdate.Core/Services/SHA256.cs @@ -2,7 +2,7 @@ using System.Text.RegularExpressions; using TinyUpdate.Core.Abstract; -namespace TinyUpdate.Core; +namespace TinyUpdate.Core.Services; /// /// Easy access to processing Streams into a SHA256 hash and comparing SHA256 hashes diff --git a/src/TinyUpdate.Core/UpdatePackageFactory.cs b/src/TinyUpdate.Core/Services/UpdatePackageFactory.cs similarity index 64% rename from src/TinyUpdate.Core/UpdatePackageFactory.cs rename to src/TinyUpdate.Core/Services/UpdatePackageFactory.cs index dd292db..b7207ee 100644 --- a/src/TinyUpdate.Core/UpdatePackageFactory.cs +++ b/src/TinyUpdate.Core/Services/UpdatePackageFactory.cs @@ -1,8 +1,8 @@ -using System.Diagnostics.CodeAnalysis; -using TinyUpdate.Core.Abstract; +using TinyUpdate.Core.Abstract; using TinyUpdate.Core.Abstract.UpdatePackage; +using TinyUpdate.Core.Model; -namespace TinyUpdate.Core; +namespace TinyUpdate.Core.Services; public class UpdatePackageFactory : IUpdatePackageFactory { @@ -39,26 +39,4 @@ public async Task CreateUpdatePackage(Stream? stream, s ? LoadUpdatePackageResult.Success(updatePackage) : LoadUpdatePackageResult.Failed(loadResult.Message); } -} - -public record LoadUpdatePackageResult -{ - public LoadUpdatePackageResult(bool successful, string? message, IUpdatePackage? updatePackage) - { - Successful = successful; - Message = message; - UpdatePackage = updatePackage; - } - - public static LoadUpdatePackageResult Failed(string message) => new(false, message, null); - - public static LoadUpdatePackageResult Success(IUpdatePackage updatePackage) => new(true, null, updatePackage); - - [MemberNotNullWhen(true, nameof(UpdatePackage))] - [MemberNotNullWhen(false, nameof(Message))] - public bool Successful { get; } - - public string? Message { get; } - - public IUpdatePackage? UpdatePackage { get; } } \ No newline at end of file diff --git a/src/TinyUpdate.Core/VersionHelper.cs b/src/TinyUpdate.Core/VersionHelper.cs new file mode 100644 index 0000000..b5767af --- /dev/null +++ b/src/TinyUpdate.Core/VersionHelper.cs @@ -0,0 +1,47 @@ +using System.Reflection; +using SemVersion; +using TinyUpdate.Core.Model; + +namespace TinyUpdate.Core; + +public static class VersionHelper +{ + public static SemanticVersion GetSemanticVersion(this ReadOnlySpan version) => SemanticVersion.Parse(GetVersionDetails(version).Version.ToString()); + public static ReadOnlySpan GetVersion(this ReadOnlySpan version) => GetVersionDetails(version).Version; + public static ReadOnlySpan GetSourceRevisionId(this ReadOnlySpan version) => GetVersionDetails(version).SourceRevisionId; + + public static VersionDetails GetVersionDetails() => GetVersionDetails(Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()); + public static VersionDetails GetVersionDetails(this Assembly assembly) + { + var versionAttribute = assembly.GetCustomAttribute(); + + var version = versionAttribute?.InformationalVersion; + return string.IsNullOrWhiteSpace(version) ? new VersionDetails() : GetVersionDetails(version); + } + + public static VersionDetails GetVersionDetails(this ReadOnlySpan version) + { + var versionDetails = new VersionDetails(version); + + var plusIndex = version.IndexOf('+'); + if (plusIndex != -1) + { + var tmpSpan = version[++plusIndex..]; + var dotIndex = tmpSpan.IndexOf('.'); + var hasDot = dotIndex != -1; + + if (hasDot) + { + versionDetails.SourceRevisionId = tmpSpan[(dotIndex + 1)..]; + versionDetails.Version = version[..^(versionDetails.SourceRevisionId.Length + 1)]; + } + else if (tmpSpan.Length == 40) + { + versionDetails.SourceRevisionId = tmpSpan; + versionDetails.Version = version[..^41]; + } + } + + return versionDetails; + } +} \ No newline at end of file diff --git a/tests/TinyUpdate.Appliers.Tests/DesktopTests.cs b/tests/TinyUpdate.Appliers.Tests/DesktopTests.cs index 1d476ad..03ebaed 100644 --- a/tests/TinyUpdate.Appliers.Tests/DesktopTests.cs +++ b/tests/TinyUpdate.Appliers.Tests/DesktopTests.cs @@ -7,6 +7,7 @@ using TinyUpdate.Core.Abstract.Delta; using TinyUpdate.Core.Abstract.UpdatePackage; using TinyUpdate.Core.Model; +using TinyUpdate.Core.Services; using TinyUpdate.Core.Tests; using TinyUpdate.Desktop; using TinyUpdate.Desktop.Abstract; @@ -31,6 +32,33 @@ public void Setup() _updateApplier = new DesktopApplier(NUnitLogger.Instance, _hasher, _mockNative, _deltaManager, _fileSystem); } + [Test] + public async Task CanApplyUpdates() { + var applicationPath = Path.Combine("Assets", nameof(DesktopApplier)); + var appV0Path = Path.Combine(applicationPath, "1.0.0"); + var appV1Path = Path.Combine(applicationPath, "1.0.1"); + var appV2Path = Path.Combine(applicationPath, "1.0.2"); + + var appV1 = new MockUpdatePackage(applicationPath, _fileSystem) + { + ReleaseEntry = new MockReleaseEntry("1.0.0", "1.0.1", true), + NewFiles = [DesktopApplierTestSource.MakeFileEntry("testing.exe", appV0Path)] + }; + var appV2 = new MockUpdatePackage(applicationPath, _fileSystem) + { + ReleaseEntry = new MockReleaseEntry("1.0.1", "1.0.2", true), + NewFiles = [DesktopApplierTestSource.MakeFileEntry(Path.Combine("testsub", "testApplication.exe"), appV1Path)] + }; + var appV3 = new MockUpdatePackage(applicationPath, _fileSystem) + { + ReleaseEntry = new MockReleaseEntry("1.0.2", "1.0.3", true), + NewFiles = [DesktopApplierTestSource.MakeFileEntry(Path.Combine("newsub", "testApplication.exe"), appV2Path)] + }; + + var result = await _updateApplier.ApplyUpdates([appV1, appV3, appV2], applicationPath); + Assert.That(result, Is.True); + } + [Test] [TestCaseSource(typeof(DesktopApplierTestSource), nameof(DesktopApplierTestSource.TestS))] public async Task CanApplyUpdate(ApplierTestData applierTestData) diff --git a/tests/TinyUpdate.Appliers.Tests/TestSources/DesktopApplierTestSource.cs b/tests/TinyUpdate.Appliers.Tests/TestSources/DesktopApplierTestSource.cs index 7ab9c2b..45fb57c 100644 --- a/tests/TinyUpdate.Appliers.Tests/TestSources/DesktopApplierTestSource.cs +++ b/tests/TinyUpdate.Appliers.Tests/TestSources/DesktopApplierTestSource.cs @@ -3,6 +3,7 @@ using TinyUpdate.Core; using TinyUpdate.Core.Abstract; using TinyUpdate.Core.Model; +using TinyUpdate.Core.Services; using TinyUpdate.Core.Tests; using TinyUpdate.Desktop; @@ -91,7 +92,7 @@ public static IEnumerable TestS() yield return new ApplierTestData("MovedFileSubDirToRoot", movedSubDirToRootUpdatePackage, applicationPath); } - private static FileEntry MakeFileEntry(string location, string sourceVersionPath, bool createInitialFile = true, bool unchanged = false, string? lastLocation = null) + internal static FileEntry MakeFileEntry(string location, string sourceVersionPath, bool createInitialFile = true, bool unchanged = false, string? lastLocation = null) { var dir = Path.GetDirectoryName(location) ?? ""; var targetFileStream = new MemoryStream(); diff --git a/tests/TinyUpdate.Core.Tests/DeltaMocker.cs b/tests/TinyUpdate.Core.Tests/DeltaMocker.cs index e7a2216..132554a 100644 --- a/tests/TinyUpdate.Core.Tests/DeltaMocker.cs +++ b/tests/TinyUpdate.Core.Tests/DeltaMocker.cs @@ -1,5 +1,6 @@ using Moq; using TinyUpdate.Core.Abstract.Delta; +using TinyUpdate.Core.Services; namespace TinyUpdate.Core.Tests; diff --git a/tests/TinyUpdate.Core.Tests/HasherTests.cs b/tests/TinyUpdate.Core.Tests/HasherTests.cs index 517275a..9f12c8f 100644 --- a/tests/TinyUpdate.Core.Tests/HasherTests.cs +++ b/tests/TinyUpdate.Core.Tests/HasherTests.cs @@ -1,4 +1,5 @@ -using TinyUpdate.Core.Tests.Abstract; +using TinyUpdate.Core.Services; +using TinyUpdate.Core.Tests.Abstract; using TinyUpdate.Core.Tests.Attributes; using TinyUpdate.Core.Tests.TestSources; diff --git a/tests/TinyUpdate.Delta.Tests/Abstract/DeltaCan.cs b/tests/TinyUpdate.Delta.Tests/Abstract/DeltaCan.cs index 72d97fc..ffdca79 100644 --- a/tests/TinyUpdate.Delta.Tests/Abstract/DeltaCan.cs +++ b/tests/TinyUpdate.Delta.Tests/Abstract/DeltaCan.cs @@ -5,6 +5,7 @@ using TinyUpdate.Core; using TinyUpdate.Core.Abstract; using TinyUpdate.Core.Abstract.Delta; +using TinyUpdate.Core.Services; using TinyUpdate.Core.Tests; using TinyUpdate.Core.Tests.Attributes; diff --git a/tests/TinyUpdate.Delta.Tests/DeltaManagerTests.cs b/tests/TinyUpdate.Delta.Tests/DeltaManagerTests.cs index e250afc..9499c4e 100644 --- a/tests/TinyUpdate.Delta.Tests/DeltaManagerTests.cs +++ b/tests/TinyUpdate.Delta.Tests/DeltaManagerTests.cs @@ -1,5 +1,6 @@ using TinyUpdate.Core; using TinyUpdate.Core.Abstract.Delta; +using TinyUpdate.Core.Services; using TinyUpdate.Core.Tests; using TinyUpdate.Delta.Tests.Abstract; diff --git a/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs b/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs index 8d13051..28a0285 100644 --- a/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs +++ b/tests/TinyUpdate.Packages.Tests/UpdatePackageTests.cs @@ -1,5 +1,6 @@ using System.IO.Compression; using TinyUpdate.Core; +using TinyUpdate.Core.Services; using TinyUpdate.Core.Tests; using TinyUpdate.Core.Tests.Attributes; using TinyUpdate.Packages.Tests.Abstract;