nuke icon indicating copy to clipboard operation
nuke copied to clipboard

Allow overridable component settings via ApplyX

Open matkoch opened this issue 2 years ago • 1 comments

Description

  • Adapt GetTarget to support InvocationExpression
    (((configurator.Body as InvocationExpression).Expression as MemberExpression).Expression as ConstantExpression).Value
    
  • Introduce new ApplyX method with Expression<Configure<T>> (no overload, since ambiguous)
  • Add assertion in existing Apply method and check if configurator.Target/Method is declared by interface
  • Use GetAllMembers to get quasi-override for original member similar as in ValueInjectionAttributeBase.GetMemberValue<T>
  • Maybe base calls via .Apply<T>(...)
JetBrains Rider-nuke-common – SettingsEntity Apply cs-2022-06-25-Y7ugiORf@2x JetBrains Rider-nuke-common – SettingsEntity Apply cs-2022-06-25-FJP1g6oM@2x

Usage Example

interface ICompile : INukeBuild
{
    Target Compile => _ => _
        .Executes(() =>
        {
            var settings = new DotNetBuildSettings()
                .ApplyX(x => x.CompileSettings);
        });

    Configure<DotNetBuildSettings> CompileSettings => _ => _;
}

interface ICompileWithSomething : INukeBuild
{
    Configure<DotNetBuildSettings> ICompile.CompileSettings => _ => _
        .SetProperty("foo", "bar");
}

class Build : ICompileWithSomething
{
}

matkoch avatar Jun 24 '22 22:06 matkoch

With the help of @matkoch I managed to get this method working:

public static TSettings Apply<TComponent, TSettings>(this TSettings settings, Expression<Func<TComponent, Configure<TSettings>>> configurator)
{
     var target = configurator.GetTarget();
     var memberInfo = configurator.GetMemberInfo();
     var config = memberInfo.GetValue<Configure<TSettings>>(target);
     return config.Invoke(settings);
}

Which would have been called like this:

DotNetBuild(_ => _
    .Apply(CompileSettingsBase)
    .Apply((ICompileEx x) => CompileSettings));

Where ICompileX looked like this:

public interface ICompileEx : ICompile
{
     Configure<DotNetBuildSettings> ICompile.CompileSettings => _ =>
            _.SetProperty("TestPropertyFromICompileEx.Key", "TestPropertyFromICompileEx.Value");
}

And Build had this:

Configure<DotNetBuildSettings> ICompile.CompileSettings => _ => _.SetProperty("TestPropertyFromBuild.Key", "TestPropertyFromBuild.Value");

The end result was that only TestPropertyFromBuild was present in the final settings and the ICompileX "layer" was ignored (not called). This is probably because they layers are not virtual.

Using GetValueNonVirtual instead of GetValue in the new Apply method resulted in no layers being called at all.

bitbonk avatar Jul 02 '22 23:07 bitbonk