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
135 changes: 135 additions & 0 deletions src/EventBuilder/Cecil/StaticEventTemplateInformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using EventBuilder.Entities;
using Mono.Cecil;
using System.Collections.Generic;
using System.Linq;

namespace EventBuilder.Cecil
{
public static class StaticEventTemplateInformation
{
private static string GetEventArgsTypeForEvent(EventDefinition ei)
{
// Find the EventArgs type parameter of the event via digging around via reflection
var type = ei.EventType.Resolve();
var invoke = type.Methods.First(x => x.Name == "Invoke");
if (invoke.Parameters.Count < 1) return null;

var param = invoke.Parameters.Count == 1 ? invoke.Parameters[0] : invoke.Parameters[1];
var ret = param.ParameterType.FullName;

var generic = ei.EventType as GenericInstanceType;
if (generic != null)
{
foreach (
var kvp in
type.GenericParameters.Zip(generic.GenericArguments, (name, actual) => new {name, actual}))
{
var realType = GetRealTypeName(kvp.actual);

ret = ret.Replace(kvp.name.FullName, realType);
}
}

// NB: Inner types in Mono.Cecil get reported as 'Foo/Bar'
return ret.Replace('/', '.');
}

private static string GetRealTypeName(TypeDefinition t)
{
if (t.GenericParameters.Count == 0) return t.FullName;

var ret = string.Format("{0}<{1}>",
t.Namespace + "." + t.Name,
string.Join(",", t.GenericParameters.Select(x => GetRealTypeName(x.Resolve()))));

// NB: Inner types in Mono.Cecil get reported as 'Foo/Bar'
return ret.Replace('/', '.');
}

private static string GetRealTypeName(TypeReference t)
{
var generic = t as GenericInstanceType;
if (generic == null) return t.FullName;

var ret = string.Format("{0}<{1}>",
generic.Namespace + "." + generic.Name,
string.Join(",", generic.GenericArguments.Select(x => GetRealTypeName(x))));

// NB: Inner types in Mono.Cecil get reported as 'Foo/Bar'
return ret.Replace('/', '.');
}

private static EventDefinition[] GetPublicEvents(TypeDefinition t)
{
return
t.Events

.Where(x =>
{
return x.AddMethod.IsPublic && GetEventArgsTypeForEvent(x) != null;
})
.ToArray();
}

public static NamespaceInfo[] Create(AssemblyDefinition[] targetAssemblies)
{
var publicTypesWithEvents = targetAssemblies
.SelectMany(x => SafeTypes.GetSafeTypes(x))
.Where(x => x.IsPublic && !x.HasGenericParameters)
.Select(x => new {Type = x, Events = GetPublicEvents(x)})
.Where(x => x.Events.Length > 0)
.ToArray();

var garbageNamespaceList = new[]
{
"ReactiveUI.Events"
};

var namespaceData = publicTypesWithEvents
.GroupBy(x => x.Type.Namespace)
.Where(x => !garbageNamespaceList.Contains(x.Key))
.Select(x => new NamespaceInfo
{
Name = x.Key,
Types = x.Select(y => new PublicTypeInfo
{
Name = y.Type.Name,
Type = y.Type,
Events = y.Events.Select(z => new PublicEventInfo
{
Name = z.Name,
EventHandlerType = GetRealTypeName(z.EventType),
EventArgsType = GetEventArgsTypeForEvent(z)
}).ToArray()
}).ToArray()
}).ToArray();

foreach (var type in namespaceData.SelectMany(x => x.Types))
{
var parentWithEvents = GetParents(type.Type).FirstOrDefault(x => GetPublicEvents(x).Any());
if (parentWithEvents == null)
continue;

type.Parent = new ParentInfo {Name = parentWithEvents.FullName};
}

return namespaceData;
}

private static IEnumerable<TypeDefinition> GetParents(TypeDefinition type)
{
var current = type.BaseType != null && type.BaseType.ToString() != "System.Object"
? type.BaseType.Resolve()
: null;

while (current != null)
{
yield return current.Resolve();

current = current.BaseType != null
? current.BaseType.Resolve()
: null;
}
}
}
}
3 changes: 2 additions & 1 deletion src/EventBuilder/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public enum AutoPlatform
WPF,
XamForms,
UWP,
Winforms
Winforms,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be fun doing TVOS who wins first :)

Essentials
}

public class CommandLineOptions
Expand Down
38 changes: 20 additions & 18 deletions src/EventBuilder/EventBuilder.csproj
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
<Project Sdk="MSBuild.Sdk.Extras">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>net461</TargetFrameworks>
<AssemblyName>EventBuilder</AssemblyName>
<RootNamespace>EventBuilder</RootNamespace>
</PropertyGroup>


<ItemGroup>
<Content Include="DefaultTemplate.mustache">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework>
<AssemblyName>EventBuilder</AssemblyName>
<RootNamespace>EventBuilder</RootNamespace>
</PropertyGroup>


<ItemGroup>
<Content Include="DefaultTemplate.mustache">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="XamarinEssentialsTemplate.mustache">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="1.9.71" />
<PackageReference Include="Microsoft.Web.Xdt" Version="2.1.1" />
<PackageReference Include="Mono.Cecil" Version="0.9.6.1" />
<PackageReference Include="NuGet.Core" Version="2.10.1" />
<PackageReference Include="Nustache" Version="1.15.3.7" />
<PackageReference Include="Polly" Version="3.0.0" />
<PackageReference Include="Serilog" Version="1.5.14" />
<PackageReference Include="NuGet.Core" Version="2.14.0" />
</ItemGroup>
</Project>
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace EventBuilder.Platforms
{
public class Android : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.Android;

public Android(string referenceAssembliesLocation)
{
if (PlatformHelper.IsRunningOnMono()) {
Expand Down
4 changes: 3 additions & 1 deletion src/EventBuilder/Platforms/BasePlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@

namespace EventBuilder.Platforms
{
public class BasePlatform : IPlatform
public abstract class BasePlatform : IPlatform
{
public BasePlatform()
{
Assemblies = new List<string>();
CecilSearchDirectories = new List<string>();
}

public abstract AutoPlatform Platform { get; }

public List<string> Assemblies { get; set; }
public List<string> CecilSearchDirectories { get; set; }
}
Expand Down
1 change: 1 addition & 0 deletions src/EventBuilder/Platforms/Bespoke.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ namespace EventBuilder.Platforms
{
public class Bespoke : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.None;
}
}
63 changes: 63 additions & 0 deletions src/EventBuilder/Platforms/Essentials.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using NuGet;
using Polly;
using Serilog;
using System;
using System.IO;
using System.Linq;

namespace EventBuilder.Platforms
{
public class Essentials : BasePlatform
{
private const string _packageName = "Xamarin.Essentials";

public override AutoPlatform Platform => AutoPlatform.Essentials;

public Essentials()
{
var packageUnzipPath = Environment.CurrentDirectory;

var retryPolicy = Policy
.Handle<Exception>()
.WaitAndRetry(
5,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
(exception, timeSpan, context) =>
{
Log.Warning(
"An exception was thrown whilst retrieving or installing {packageName}: {exception}",
_packageName, exception);
});

retryPolicy.Execute(() =>
{
var repo = PackageRepositoryFactory.Default.CreateRepository("https://packages.nuget.org/api/v2");
var packageManager = new PackageManager(repo, packageUnzipPath);
var fpid = packageManager.SourceRepository.FindPackagesById(_packageName);
var package = fpid.Single(x => x.Version.ToString() == "0.9.1-preview");

packageManager.InstallPackage(package, true, true);

Log.Debug("Using Xamarin Essentials {Version} released on {Published}", package.Version, package.Published);
Log.Debug("{ReleaseNotes}", package.ReleaseNotes);
});

var xamarinForms =
Directory.GetFiles(packageUnzipPath,
"Xamarin.Essentials.dll", SearchOption.AllDirectories);

var latestVersion = xamarinForms.First(x => x.Contains("netstandard1.0"));
Assemblies.Add(latestVersion);

if (PlatformHelper.IsRunningOnMono())
{
CecilSearchDirectories.Add(
@"/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/xbuild-frameworks/.NETPortable/v4.5/Profile/Profile111");
}
else
{
CecilSearchDirectories.Add(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile111");
}
}
}
}
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/IPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace EventBuilder.Platforms
{
public interface IPlatform
{
AutoPlatform Platform { get; }

List<string> Assemblies { get; set; }

// Cecil when run on Mono needs some direction as to the location of the platform specific MSCORLIB.
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/Mac.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace EventBuilder.Platforms
// ReSharper disable once InconsistentNaming
public class Mac : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.Mac;

public Mac(string referenceAssembliesLocation)
{
if (PlatformHelper.IsRunningOnMono()) {
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/Tizen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class Tizen : BasePlatform
{
private const string _packageName = "Tizen.NET";

public override AutoPlatform Platform => AutoPlatform.Tizen;

public Tizen()
{
var packageUnzipPath = Environment.CurrentDirectory;
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/UWP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace EventBuilder.Platforms
{
public class UWP : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.UWP;

public UWP()
{
if (PlatformHelper.IsRunningOnMono())
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/WPF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace EventBuilder.Platforms
{
public class WPF : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.WPF;

public WPF()
{
if (PlatformHelper.IsRunningOnMono()) {
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/Winforms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace EventBuilder.Platforms
{
public class Winforms : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.Winforms;

public Winforms()
{
if (PlatformHelper.IsRunningOnMono()) {
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/XamForms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class XamForms : BasePlatform
{
private const string _packageName = "Xamarin.Forms";

public override AutoPlatform Platform => AutoPlatform.XamForms;

public XamForms()
{
var packageUnzipPath = Environment.CurrentDirectory;
Expand Down
2 changes: 2 additions & 0 deletions src/EventBuilder/Platforms/iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace EventBuilder.Platforms
// ReSharper disable once InconsistentNaming
public class iOS : BasePlatform
{
public override AutoPlatform Platform => AutoPlatform.iOS;

public iOS(string referenceAssembliesLocation)
{
if (PlatformHelper.IsRunningOnMono()) {
Expand Down
Loading