Skip to content

Commit

Permalink
Merge dev to main
Browse files Browse the repository at this point in the history
  • Loading branch information
mthalman authored Dec 18, 2023
2 parents 144074b + 2043229 commit 3b9e407
Show file tree
Hide file tree
Showing 17 changed files with 245 additions and 123 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "7.0.x"
dotnet-version: "8.0.x"
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}

Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ jobs:
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "7.0.x"
dotnet-version: "8.0.x"

- name: Install dependencies
working-directory: src/Valleysoft.Dredge
run: dotnet restore --runtime ${{ matrix.rid }} /p:PublishReadyToRun=true
run: dotnet restore --runtime ${{ matrix.rid }}

- name: Publish
working-directory: src/Valleysoft.Dredge
run: dotnet publish -f net7.0 -c Release --no-restore -o ${{ github.workspace }}/publish --runtime ${{ matrix.rid }} --self-contained /p:PublishTrimmed=true /p:PublishReadyToRun=true /p:PublishSingleFile=true /p:TrimMode=partial
run: dotnet publish -f net8.0 -c Release --no-restore -o ${{ github.workspace }}/publish --runtime ${{ matrix.rid }}

- name: Rename output
run: |
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "7.0.x"
dotnet-version: "8.0.x"

- name: Install dependencies
run: dotnet restore
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
- name: Build and push
uses: docker/build-push-action@v3
with:
context: ./src/Valleysoft.Dredge
context: ./src
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event.inputs.packageVersion }},${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
Expand Down
File renamed without changes.
20 changes: 20 additions & 0 deletions src/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build

ARG TARGETARCH
ARG PACKAGE_VERSION

WORKDIR /source

COPY Valleysoft.Dredge/*.csproj Valleysoft.Dredge/
COPY Valleysoft.Dredge.Analyzers/*.csproj Valleysoft.Dredge.Analyzers/
RUN dotnet restore -a $TARGETARCH Valleysoft.Dredge/*.csproj

COPY Valleysoft.Dredge/ Valleysoft.Dredge/
COPY Valleysoft.Dredge.Analyzers/ Valleysoft.Dredge.Analyzers/
RUN dotnet publish Valleysoft.Dredge/*.csproj -f net8.0 -o /app -a $TARGETARCH --self-contained /p:Version=$PACKAGE_VERSION --no-restore


FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy-chiseled
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["./dredge"]
141 changes: 141 additions & 0 deletions src/Valleysoft.Dredge.Analyzers/SettingsPropertyGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Text;

namespace Valleysoft.Dredge.Analyzers;

[Generator]
public class SettingsSourceGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
}

public void Execute(GeneratorExecutionContext context)
{
// Iterate over all the syntax trees in the compilation
foreach (SyntaxTree tree in context.Compilation.SyntaxTrees)
{
// Retrieve the semantic model for the syntax tree
SemanticModel semanticModel = context.Compilation.GetSemanticModel(tree);

// Find all class declarations whose name ends with "Settings"
IEnumerable<ClassDeclarationSyntax> classes = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Where(c => c.Identifier.Text.EndsWith("Settings"));

foreach (ClassDeclarationSyntax classDecl in classes)
{
// Retrieve the symbol for the class
INamedTypeSymbol classSymbol = semanticModel.GetDeclaredSymbol(classDecl)!;

// Start building the source code
StringBuilder sourceBuilder = new();

// Add the necessary using directives
sourceBuilder.AppendLine("#nullable enable");
sourceBuilder.AppendLine("using System;");
sourceBuilder.AppendLine("using System.Collections.Generic;");
sourceBuilder.AppendLine("using Newtonsoft.Json;");

// Start the namespace declaration
sourceBuilder.AppendLine($"namespace {classSymbol.ContainingNamespace}");
sourceBuilder.AppendLine("{");

// Start the class declaration
sourceBuilder.AppendLine($" internal partial class {classSymbol.Name}");
sourceBuilder.AppendLine(" {");

sourceBuilder.AppendLine(GetMethod(semanticModel, classDecl,
"public void SetProperty(Queue<string> propertyPath, string value)",
propertyName => $"{propertyName}.SetProperty(propertyPath, value);",
propertyName => $"{propertyName} = value;",
includeBreak: true));

sourceBuilder.AppendLine(GetMethod(semanticModel, classDecl,
"public object? GetProperty(Queue<string> propertyPath)",
propertyName => $"return {propertyName}.GetProperty(propertyPath);",
propertyName => $"return {propertyName};",
includeBreak: false));

sourceBuilder.AppendLine(" }"); // end class

sourceBuilder.AppendLine(" }"); // end namespace
sourceBuilder.AppendLine("#nullable disable");


// Add the new syntax tree to the compilation
context.AddSource($"{classDecl.Identifier.Text}.Generated.cs", sourceBuilder.ToString());
}
}
}

private static string GetMethod(
SemanticModel semanticModel, ClassDeclarationSyntax classDecl, string methodSignature,
Func<string, string> settingsPropertyAction, Func<string, string> propertyAction, bool includeBreak)
{
StringBuilder sourceBuilder = new();

sourceBuilder.AppendLine($@"
{methodSignature}
{{
if (propertyPath.Count == 0)
{{
throw new ArgumentException(""Property path cannot be empty"", nameof(propertyPath));
}}
var currentProperty = propertyPath.Dequeue();
switch (currentProperty)
{{");

// Generate a case for each property in the class
foreach (PropertyDeclarationSyntax property in classDecl.DescendantNodes().OfType<PropertyDeclarationSyntax>())
{
// Get the JsonPropertyAttribute for the property, if it exists
AttributeSyntax jsonPropertyAttribute = property.AttributeLists
.SelectMany(a => a.Attributes)
.FirstOrDefault(a => a.Name.ToString() == "JsonProperty");

if (jsonPropertyAttribute != null)
{
// Get the name argument of the JsonPropertyAttribute
AttributeArgumentSyntax attribArg = jsonPropertyAttribute.ArgumentList?.Arguments[0]!;
string jsonPropertyName = semanticModel.GetConstantValue(attribArg.Expression).Value?.ToString().Trim('"')!;

if (property.Type.ToString().EndsWith("Settings"))
{
sourceBuilder.AppendLine($@"
case ""{jsonPropertyName}"":
if (propertyPath.Count > 0)
{{
{settingsPropertyAction(property.Identifier.Text)}
}}
else
{{
throw new ArgumentException(""Property path must point to a valid property"", nameof(propertyPath));
}}
{(includeBreak ? "break;" : string.Empty)}");
}
else
{
sourceBuilder.AppendLine($@"
case ""{jsonPropertyName}"":
if (propertyPath.Count > 0)
{{
throw new ArgumentException(""Property path must point to a valid property"", nameof(propertyPath));
}}
{propertyAction(property.Identifier.Text)}
{(includeBreak ? "break;" : string.Empty)}");
}
}
}

sourceBuilder.AppendLine($@"
default:
throw new ArgumentException($""Unknown property: {{currentProperty}}"", nameof(propertyPath));
}}
}}");

return sourceBuilder.ToString();
}
}
15 changes: 15 additions & 0 deletions src/Valleysoft.Dredge.Analyzers/Valleysoft.Dredge.Analyzers.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<LangVersion>11.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/Valleysoft.Dredge.Tests/Valleysoft.Dredge.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

Expand Down
8 changes: 7 additions & 1 deletion src/Valleysoft.Dredge.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ VisualStudioVersion = 17.5.33109.374
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Valleysoft.Dredge", "Valleysoft.Dredge\Valleysoft.Dredge.csproj", "{781B651C-A6F3-445B-AD9D-ABB5E5632445}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Valleysoft.Dredge.Tests", "Valleysoft.Dredge.Tests\Valleysoft.Dredge.Tests.csproj", "{39FD6D54-14E0-4894-95AC-951E3209A59F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Valleysoft.Dredge.Tests", "Valleysoft.Dredge.Tests\Valleysoft.Dredge.Tests.csproj", "{39FD6D54-14E0-4894-95AC-951E3209A59F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Valleysoft.Dredge.Analyzers", "Valleysoft.Dredge.Analyzers\Valleysoft.Dredge.Analyzers.csproj", "{23CD573A-1001-4856-A9E5-188043E314CE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -21,6 +23,10 @@ Global
{39FD6D54-14E0-4894-95AC-951E3209A59F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39FD6D54-14E0-4894-95AC-951E3209A59F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39FD6D54-14E0-4894-95AC-951E3209A59F}.Release|Any CPU.Build.0 = Release|Any CPU
{23CD573A-1001-4856-A9E5-188043E314CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23CD573A-1001-4856-A9E5-188043E314CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23CD573A-1001-4856-A9E5-188043E314CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23CD573A-1001-4856-A9E5-188043E314CE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
8 changes: 4 additions & 4 deletions src/Valleysoft.Dredge/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Valleysoft.Dredge;

internal class AppSettings
internal partial class AppSettings
{
public static readonly string SettingsPath =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Valleysoft.Dredge", "settings.json");
Expand Down Expand Up @@ -36,7 +36,7 @@ public static AppSettings Load()
else
{
string settings = File.ReadAllText(SettingsPath);
return JsonConvert.DeserializeObject<AppSettings>(settings);
return JsonConvert.DeserializeObject<AppSettings>(settings)!;
}
}

Expand All @@ -47,7 +47,7 @@ public void Save()
}
}

internal class FileCompareToolSettings
internal partial class FileCompareToolSettings
{
[JsonProperty("exePath")]
public string ExePath { get; set; } = string.Empty;
Expand All @@ -56,7 +56,7 @@ internal class FileCompareToolSettings
public string Args { get; set; } = string.Empty;
}

internal class PlatformSettings
internal partial class PlatformSettings
{
[JsonProperty("os")]
public string Os { get; set; } = string.Empty;
Expand Down
8 changes: 4 additions & 4 deletions src/Valleysoft.Dredge/Commands/Image/CompareFilesOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ public class CompareFilesOptions : CompareOptionsBase
{
public const string LayerIndexSuffix = "-layer-index";

private readonly Option<int> baseLayerIndex;
private readonly Option<int> targetLayerIndex;
private readonly Option<int?> baseLayerIndex;
private readonly Option<int?> targetLayerIndex;
private readonly Option<CompareFilesOutput> outputOption;

public int? BaseLayerIndex { get; set; }
Expand All @@ -16,8 +16,8 @@ public class CompareFilesOptions : CompareOptionsBase

public CompareFilesOptions()
{
baseLayerIndex = Add(new Option<int>($"--{BaseArg}{LayerIndexSuffix}", "Non-empty layer index of the base container image to compare with"));
targetLayerIndex = Add(new Option<int>($"--{TargetArg}{LayerIndexSuffix}", "Non-empty layer index of the target container image to compare against"));
baseLayerIndex = Add(new Option<int?>($"--{BaseArg}{LayerIndexSuffix}", "Non-empty layer index of the base container image to compare with"));
targetLayerIndex = Add(new Option<int?>($"--{TargetArg}{LayerIndexSuffix}", "Non-empty layer index of the target container image to compare against"));
outputOption = Add(new Option<CompareFilesOutput>("--output", () => CompareFilesOutput.ExternalTool, "Output type"));
}

Expand Down
9 changes: 3 additions & 6 deletions src/Valleysoft.Dredge/Commands/Image/InspectCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ protected override Task ExecuteAsync()
{
using IDockerRegistryClient client = await DockerRegistryClientFactory.GetClientAsync(imageName.Registry);
DockerManifestV2 manifest = (await ManifestHelper.GetResolvedManifestAsync(client, imageName, Options)).Manifest;
string? digest = manifest.Config?.Digest;
if (digest is null)
{
string? digest = (manifest.Config?.Digest) ??
throw new NotSupportedException($"Could not resolve the image config digest of '{Options.Image}'.");
}

Stream blob = await client.Blobs.GetAsync(imageName.Repo, digest);
using StreamReader reader = new(blob);
string content = await reader.ReadToEndAsync();
object json = JsonConvert.DeserializeObject(content);
object? json = JsonConvert.DeserializeObject(content) ??
throw new Exception($"Unable to deserialize content into JSON:\n{content}");
string output = JsonConvert.SerializeObject(json, Formatting.Indented);
Console.Out.WriteLine(output);
});
Expand Down
34 changes: 1 addition & 33 deletions src/Valleysoft.Dredge/Commands/Settings/GetCommand.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Newtonsoft.Json;
using System.Reflection;

namespace Valleysoft.Dredge.Commands.Settings;

Expand All @@ -16,7 +15,7 @@ protected override Task ExecuteAsync()

Queue<string> names = new(Options.Name.Split('.'));

object? value = GetSettingProperty(settings, names);
object? value = settings.GetProperty(names);

if (value is not null)
{
Expand All @@ -32,35 +31,4 @@ protected override Task ExecuteAsync()

return Task.CompletedTask;
}

private object? GetSettingProperty(object obj, Queue<string> names)
{
string propertyName = names.Dequeue();
PropertyInfo? property = obj.GetType().GetProperties()
.FirstOrDefault(prop => prop.GetCustomAttribute<JsonPropertyAttribute>()?.PropertyName == propertyName);
if (property is null)
{
throw new Exception($"Could not find property '{propertyName}' in object of type '{obj.GetType()}'");
}

if (names.Any())
{
object? propertyValue = property.GetValue(obj);
if (propertyValue is null)
{
propertyValue = Activator.CreateInstance(property.PropertyType);
if (propertyValue is null)
{
throw new Exception($"Unable to create instance of '{property.PropertyType}'.");
}
}
property.SetValue(obj, propertyValue);

return GetSettingProperty(propertyValue, names);
}
else
{
return property.GetValue(obj);
}
}
}
Loading

0 comments on commit 3b9e407

Please sign in to comment.