Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Zafiro.DivineBytes;

namespace DotnetPackaging.Exe.Installer.Core;

internal static class BrandingLogoFactory
{
public static IBitmap? FromBytes(IByteSource? bytes)
public static IImage? FromBytes(IByteSource? bytes)
{
if (bytes is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CSharpFunctionalExtensions;
using Zafiro.DivineBytes;
using Zafiro.ProgressReporting;
using Path = System.IO.Path;

namespace DotnetPackaging.Exe.Installer.Core;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Reactive;
using Avalonia.Media.Imaging;
using Avalonia.Media;
using CSharpFunctionalExtensions;
using DotnetPackaging.Exe.Installer.Core;
using Reactive.Bindings;
Expand All @@ -11,7 +11,7 @@ namespace DotnetPackaging.Exe.Installer.Installation.Wizard.Welcome;
public interface IWelcomeViewModel
{
Reactive.Bindings.ReactiveProperty<InstallerMetadata?> Metadata { get; }
ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }
ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }
ReadOnlyReactivePropertySlim<IBitmap?> Logo { get; }
ReactiveUI.ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }
ReactiveUI.ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }
ReadOnlyReactivePropertySlim<IImage?> Logo { get; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using CSharpFunctionalExtensions;
using DotnetPackaging.Exe.Installer.Core;
Expand All @@ -21,25 +22,25 @@ public sealed class WelcomeViewModel : ReactiveValidationObject, IWelcomeViewMod
public WelcomeViewModel(IInstallerPayload payload)
{
this.payload = payload;
LoadMetadata = ReactiveCommand.CreateFromTask(() => this.payload.GetMetadata());
Metadata = new ReactiveProperty<InstallerMetadata?>(LoadMetadata.Successes());
LoadMetadata = ReactiveUI.ReactiveCommand.CreateFromTask(() => this.payload.GetMetadata());
Metadata = new Reactive.Bindings.ReactiveProperty<InstallerMetadata?>(LoadMetadata.Successes());
this.ValidationRule(model => model.Metadata.Value, m => m is not null, "Metadata is required");

LoadLogo = ReactiveCommand.CreateFromTask(() => payload.GetLogo());
LoadLogo = ReactiveUI.ReactiveCommand.CreateFromTask(() => payload.GetLogo());

Logo = LoadLogo
.Successes()
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IBitmap?)null))
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IImage?)null))
.ToReadOnlyReactivePropertySlim();
}

public ReactiveProperty<InstallerMetadata?> Metadata { get; }
public Reactive.Bindings.ReactiveProperty<InstallerMetadata?> Metadata { get; }

public ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }
public ReactiveUI.ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }

public ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }
public ReactiveUI.ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }

public ReadOnlyReactivePropertySlim<IBitmap?> Logo { get; }
public ReadOnlyReactivePropertySlim<IImage?> Logo { get; }

public IObservable<bool> IsValid => this.IsValid();
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using CSharpFunctionalExtensions;
using DotnetPackaging.Exe.Installer.Core;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using ReactiveUI;
using Zafiro.CSharpFunctionalExtensions;
using Zafiro.DivineBytes;

namespace DotnetPackaging.Exe.Installer.Installation.Wizard.Welcome;
Expand All @@ -16,33 +19,33 @@ public class WelcomeViewModelMock : IWelcomeViewModel

public WelcomeViewModelMock()
{
Metadata = new ReactiveProperty<InstallerMetadata>(new InstallerMetadata(
Metadata = new Reactive.Bindings.ReactiveProperty<InstallerMetadata?>(new InstallerMetadata(
"com.example.app",
"Example App",
"1.0.0",
"Example, Inc.",
Description: "This is an example app. It does nothing. It's just a demo.",
HasLogo: true));

LoadLogo = ReactiveCommand.Create(() => Result.Success(Maybe<IByteSource>.From(ByteSource.FromBytes(SampleLogo))));
LoadLogo = ReactiveUI.ReactiveCommand.Create(() => Result.Success(Maybe<IByteSource>.From(ByteSource.FromBytes(SampleLogo))));

Logo = LoadLogo
.Successes()
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IBitmap?)null))
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IImage?)null))
.ToReadOnlyReactivePropertySlim();
}

public ReactiveProperty<InstallerMetadata?> Metadata { get; }
public Reactive.Bindings.ReactiveProperty<InstallerMetadata?> Metadata { get; }

public ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; } = ReactiveCommand.Create(() => Result.Success(new InstallerMetadata(
public ReactiveUI.ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; } = ReactiveUI.ReactiveCommand.Create(() => Result.Success(new InstallerMetadata(
"com.example.app",
"Example App",
"1.0.0",
"Example, Inc.",
Description: "This is an example app. It does nothing. It's just a demo.",
HasLogo: true)));

public ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }
public ReactiveUI.ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }

public ReadOnlyReactivePropertySlim<IBitmap?> Logo { get; }
public ReadOnlyReactivePropertySlim<IImage?> Logo { get; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Reactive;
using System.Reactive.Linq;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using CSharpFunctionalExtensions;
using DotnetPackaging.Exe.Installer.Core;
Expand All @@ -21,25 +22,25 @@ public sealed class UninstallWelcomeViewModel : ReactiveValidationObject, IValid
public UninstallWelcomeViewModel(IInstallerPayload payload)
{
this.payload = payload;
LoadMetadata = ReactiveCommand.CreateFromTask(() => this.payload.GetMetadata());
Metadata = new ReactiveProperty<InstallerMetadata?>(LoadMetadata.Successes());
LoadMetadata = ReactiveUI.ReactiveCommand.CreateFromTask(() => this.payload.GetMetadata());
Metadata = new Reactive.Bindings.ReactiveProperty<InstallerMetadata?>(LoadMetadata.Successes());
this.ValidationRule(model => model.Metadata.Value, m => m is not null, "Metadata is required");

LoadLogo = ReactiveCommand.CreateFromTask(() => payload.GetLogo());
LoadLogo = ReactiveUI.ReactiveCommand.CreateFromTask(() => payload.GetLogo());

Logo = LoadLogo
.Successes()
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IBitmap?)null))
.Select(logoBytes => logoBytes.Match(BrandingLogoFactory.FromBytes, () => (IImage?)null))
.ToReadOnlyReactivePropertySlim();
}

public ReactiveProperty<InstallerMetadata?> Metadata { get; }
public Reactive.Bindings.ReactiveProperty<InstallerMetadata?> Metadata { get; }

public ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }
public ReactiveUI.ReactiveCommand<Unit, Result<InstallerMetadata>> LoadMetadata { get; }

public ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }
public ReactiveUI.ReactiveCommand<Unit, Result<Maybe<IByteSource>>> LoadLogo { get; }

public ReadOnlyReactivePropertySlim<IBitmap?> Logo { get; }
public ReadOnlyReactivePropertySlim<IImage?> Logo { get; }

public IObservable<bool> IsValid => this.IsValid();
}
14 changes: 8 additions & 6 deletions src/DotnetPackaging.Exe/ExePackagingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -579,12 +579,14 @@ private static async Task<Result<string>> CreateInstallerPayloadZip(string publi
await src.CopyToAsync(dst);
}

foreach (var bytes in logoBytes)
{
var logoEntry = zip.CreateEntry(BrandingLogoEntry, CompressionLevel.NoCompression);
await using var logoStream = logoEntry.Open();
await logoStream.WriteAsync(bytes, 0, bytes.Length);
}
await logoBytes.Match(
async bytes =>
{
var logoEntry = zip.CreateEntry(BrandingLogoEntry, CompressionLevel.NoCompression);
await using var logoStream = logoEntry.Open();
await logoStream.WriteAsync(bytes, 0, bytes.Length);
},
() => Task.CompletedTask);

return Result.Success(zipPath);
}
Expand Down
14 changes: 8 additions & 6 deletions src/DotnetPackaging.Exe/SimpleExePacker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,13 @@ private static async Task CreatePayloadZip(string zipPath, string publishDir, In
await src.CopyToAsync(dst);
}

foreach (var bytes in logoBytes)
{
var logoEntry = zip.CreateEntry(BrandingLogoEntry, CompressionLevel.NoCompression);
await using var stream = logoEntry.Open();
await stream.WriteAsync(bytes, 0, bytes.Length);
}
await logoBytes.Match(
async bytes =>
{
var logoEntry = zip.CreateEntry(BrandingLogoEntry, CompressionLevel.NoCompression);
await using var stream = logoEntry.Open();
await stream.WriteAsync(bytes, 0, bytes.Length);
},
() => Task.CompletedTask);
}
}
2 changes: 1 addition & 1 deletion test/DotnetPackaging.Exe.Tests/ExeSfxEndToEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task From_project_builds_setup_with_expected_metadata_when_external

// Act: build the SFX installer from the project
var service = new ExePackagingService();
var result = await service.BuildFromProject(new FileInfo(projectPath), "win-x64", true, "Release", true, false, new FileInfo(outputExe), new Options(), vendor: null, stubFile: null);
var result = await service.BuildFromProject(new FileInfo(projectPath), "win-x64", true, "Release", true, false, new FileInfo(outputExe), new Options(), vendor: null, stubFile: null, setupLogo: null);
result.IsSuccess.Should().BeTrue(result.IsFailure ? result.Error : string.Empty);

// Run the produced installer with the env hook to dump metadata and exit
Expand Down