Skip to content

Commit

Permalink
Update to produce correct output for platform based generation. (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
glennawatson authored Jun 11, 2019
1 parent 8a49eb7 commit 388e2c7
Show file tree
Hide file tree
Showing 23 changed files with 65,424 additions and 82 deletions.
2 changes: 1 addition & 1 deletion src/Pharmacist.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static async Task<int> Main(string[] args)
referenceAssembliesLocation = await ReferenceLocator.GetReferenceLocation().ConfigureAwait(false);
}

await ObservablesForEventGenerator.ExtractEventsFromPlatforms(options.OutputPath, options.OutputPrefix, referenceAssembliesLocation, options.Platforms).ConfigureAwait(false);
await ObservablesForEventGenerator.ExtractEventsFromPlatforms(options.OutputPath, options.OutputPrefix, ".cs", referenceAssembliesLocation, options.Platforms).ConfigureAwait(false);

return ExitCode.Success;
}
Expand Down
15 changes: 0 additions & 15 deletions src/Pharmacist.Core/AutoPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,11 @@ public enum AutoPlatform
/// </summary>
Mac,

/// <summary>
/// Tizen platform.
/// </summary>
Tizen4,

/// <summary>
/// WPF platform.
/// </summary>
WPF,

/// <summary>
/// Xamarin Forms platform.
/// </summary>
XamForms,

/// <summary>
/// UWP platform.
/// </summary>
Expand All @@ -56,10 +46,5 @@ public enum AutoPlatform
/// TV OS platform.
/// </summary>
TVOS,

/// <summary>
/// Xamarin Essentials platform.
/// </summary>
Essentials
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace Pharmacist.Core.Extractors.PlatformExtractors
/// </summary>
internal abstract class NetFrameworkBase : BasePlatform
{
private static readonly PackageIdentity ReferenceNuGet = new PackageIdentity("Microsoft.NETFramework.ReferenceAssemblies", new NuGetVersion("1.0.0-preview.2"));
private static readonly PackageIdentity ReferenceNuGet = new PackageIdentity("Microsoft.NETFramework.ReferenceAssemblies.net461", new NuGetVersion("1.0.0-preview.2"));

private static readonly NuGetFramework ReferenceFramework = FrameworkConstants.CommonFrameworks.Net461;

Expand Down
1 change: 1 addition & 0 deletions src/Pharmacist.Core/Extractors/PlatformExtractors/UWP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public override Task Extract(string referenceAssembliesLocation)
}

Assemblies = new[] { @"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd" };
SearchDirectories = new[] { @"C:\Windows\Microsoft.NET\Framework\v4.0.30319" };

return Task.CompletedTask;
}
Expand Down
42 changes: 28 additions & 14 deletions src/Pharmacist.Core/Generation/Generators/DelegateGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,42 @@ internal static class DelegateGenerator
/// </summary>
/// <param name="declarations">The declarations to add.</param>
/// <returns>An array of namespace declarations.</returns>
internal static IEnumerable<NamespaceDeclarationSyntax> Generate(IEnumerable<(ITypeDefinition typeDefinition, bool isAbstract, IEnumerable<IMethod> methods)> declarations) => declarations.GroupBy(x => x.typeDefinition.Namespace)
.Select(x => SyntaxFactory.NamespaceDeclaration(SyntaxFactory.IdentifierName(x.Key)).WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(GenerateClasses(x))));
internal static IEnumerable<NamespaceDeclarationSyntax> Generate(IEnumerable<(ITypeDefinition typeDefinition, bool isAbstract, IEnumerable<IMethod> methods)> declarations)
{
foreach (var groupedDeclarations in declarations.GroupBy(x => x.typeDefinition.Namespace))
{
var namespaceName = groupedDeclarations.Key;
var members = new List<ClassDeclarationSyntax>();

members.AddRange(groupedDeclarations.OrderBy(x => x.typeDefinition.Name).Select(x => GenerateClass(x.typeDefinition, x.isAbstract, x.methods)));

if (members.Count > 0)
{
yield return SyntaxFactory
.NamespaceDeclaration(SyntaxFactory.IdentifierName(namespaceName))
.WithMembers(SyntaxFactory.List<MemberDeclarationSyntax>(members));
}
}
}

/// <summary>
/// Generates our helper classes with the observables.
/// </summary>
/// <param name="declarations">Our class declarations along with the methods we want to generate the values for.</param>
/// <param name="typeDefinition">The type definition containing the information.</param>
/// <param name="isAbstract">If the delegates are abstract.</param>
/// <param name="methods">The methods to generate delegate overloads for.</param>
/// <returns>The generated class declarations.</returns>
private static IEnumerable<ClassDeclarationSyntax> GenerateClasses(IEnumerable<(ITypeDefinition typeDefinition, bool isAbstract, IEnumerable<IMethod> methods)> declarations)
private static ClassDeclarationSyntax GenerateClass(ITypeDefinition typeDefinition, bool isAbstract, IEnumerable<IMethod> methods)
{
foreach (var declaration in declarations)
{
var modifiers = declaration.typeDefinition.IsAbstract || declaration.isAbstract
var modifiers = typeDefinition.IsAbstract || isAbstract
? SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.AbstractKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword))
: SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword));
yield return SyntaxFactory.ClassDeclaration(declaration.typeDefinition.Name + "Rx")
return SyntaxFactory.ClassDeclaration(typeDefinition.Name + "Rx")
.WithModifiers(modifiers)
.WithMembers(SyntaxFactory.List(GenerateObservableMembers(declaration.methods)))
.WithBaseList(SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList<BaseTypeSyntax>(SyntaxFactory.SimpleBaseType(SyntaxFactory.IdentifierName(declaration.typeDefinition.GenerateFullGenericName())))))
.WithLeadingTrivia(XmlSyntaxFactory.GenerateSummarySeeAlsoComment("Wraps delegates events from {0} into Observables.", declaration.typeDefinition.GenerateFullGenericName()))
.WithObsoleteAttribute(declaration.typeDefinition);
}
.WithMembers(SyntaxFactory.List(GenerateObservableMembers(methods)))
.WithBaseList(SyntaxFactory.BaseList(SyntaxFactory.SingletonSeparatedList<BaseTypeSyntax>(SyntaxFactory.SimpleBaseType(SyntaxFactory.IdentifierName(typeDefinition.GenerateFullGenericName())))))
.WithLeadingTrivia(XmlSyntaxFactory.GenerateSummarySeeAlsoComment("Wraps delegates events from {0} into Observables.", typeDefinition.GenerateFullGenericName()))
.WithObsoleteAttribute(typeDefinition);
}

private static IEnumerable<MemberDeclarationSyntax> GenerateObservableMembers(IEnumerable<IMethod> methods)
Expand All @@ -59,7 +73,7 @@ private static IEnumerable<MemberDeclarationSyntax> GenerateObservableMembers(IE
var fieldDeclarations = new List<FieldDeclarationSyntax>();
var propertyDeclarations = new List<PropertyDeclarationSyntax>();

foreach (var method in methods)
foreach (var method in methods.OrderBy(y => y.Name))
{
var observableName = "_" + char.ToLowerInvariant(method.Name[0]) + method.Name.Substring(1);
methodDeclarations.Add(GenerateMethodDeclaration(observableName, method));
Expand Down
20 changes: 14 additions & 6 deletions src/Pharmacist.Core/Generation/RoslynHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,22 @@ public static EventBuilderCompiler GetCompilation(IEnumerable<string> targetAsse
{
var modules = targetAssemblies.Select(x => new PEFile(x, PEStreamOptions.PrefetchMetadata));

var searchStack = new Stack<DirectoryInfo>(searchDirectories.Select(x => new DirectoryInfo(x)));
var foundDirectories = new HashSet<string>();
foreach (var searchDirectory in searchDirectories)

while (searchStack.Count != 0)
{
var directoryInfo = new DirectoryInfo(searchDirectory);
foundDirectories.UnionWith(
directoryInfo.EnumerateDirectories("*.*", SearchOption.AllDirectories)
.Where(x => x.EnumerateFiles().Any(file => file.FullName.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) || file.FullName.EndsWith(".winmd", StringComparison.InvariantCultureIgnoreCase)))
.Select(x => x.FullName));
var directoryInfo = searchStack.Pop();

if (directoryInfo.EnumerateFiles().Any(file => file.FullName.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase) || file.FullName.EndsWith(".winmd", StringComparison.InvariantCultureIgnoreCase)))
{
foundDirectories.Add(directoryInfo.FullName);
}

foreach (var directory in directoryInfo.EnumerateDirectories())
{
searchStack.Push(directory);
}
}

return new EventBuilderCompiler(modules, foundDirectories.ToList());
Expand Down
5 changes: 3 additions & 2 deletions src/Pharmacist.Core/ObservablesForEventGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,19 @@ public static class ObservablesForEventGenerator
/// </summary>
/// <param name="outputPath">The path where to output the files.</param>
/// <param name="prefix">The prefix to add to the start of the output file.</param>
/// <param name="suffix">The suffix to add to the end of output file names.</param>
/// <param name="defaultReferenceAssemblyLocation">A directory path to where reference assemblies can be located.</param>
/// <param name="platforms">The platforms to generate for.</param>
/// <returns>A task to monitor the progress.</returns>
public static async Task ExtractEventsFromPlatforms(string outputPath, string prefix, string defaultReferenceAssemblyLocation, IEnumerable<AutoPlatform> platforms)
public static async Task ExtractEventsFromPlatforms(string outputPath, string prefix, string suffix, string defaultReferenceAssemblyLocation, IEnumerable<AutoPlatform> platforms)
{
foreach (var platform in platforms)
{
LogHost.Default.Info(CultureInfo.InvariantCulture, "Processing platform {0}", platform);
var platformExtractor = _platformExtractors[platform];
await platformExtractor.Extract(defaultReferenceAssemblyLocation).ConfigureAwait(false);

using (var stream = new FileStream(Path.Combine(outputPath, prefix + ".cs"), FileMode.Create, FileAccess.Write))
using (var stream = new FileStream(Path.Combine(outputPath, $"{prefix}{platform}{suffix}"), FileMode.Create, FileAccess.Write))
{
await WriteHeader(stream).ConfigureAwait(false);
await ExtractEventsFromAssemblies(stream, platformExtractor.Assemblies, platformExtractor.SearchDirectories).ConfigureAwait(false);
Expand Down
69 changes: 69 additions & 0 deletions src/Pharmacist.Core/Utilities/StackExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) 2019 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Text;

namespace Pharmacist.Core.Utilities
{
/// <summary>
/// Extension methods for stack based operations.
/// </summary>
internal static class StackExtensions
{
public static void PushRange<T>(this Stack<T> stack, IEnumerable<T> items)
{
foreach (var item in items)
{
stack.Push(item);
}
}

public static int TryPopRange<T>(this Stack<T> stack, T[] items)
{
return TryPopRange(stack, items, 0, items.Length);
}

public static int TryPopRange<T>(this Stack<T> stack, T[] items, int startIndex, int count)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}

if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "The count must be greater than 0.");
}

int length = items.Length;
if (startIndex >= length || startIndex < 0)
{
throw new ArgumentOutOfRangeException(nameof(startIndex), "The start index is out of range. It must between 0 and less than the length of the array.");
}

if (length - count < startIndex)
{
// instead of (startIndex + count > items.Length) to prevent overflow
throw new ArgumentException("The start index is out of range. It must between 0 and less than the length of the array.");
}

if (count == 0)
{
return 0;
}

int nodesCount = stack.Count > count ? count : stack.Count;

for (int i = startIndex; i < startIndex + nodesCount; i++)
{
items[i] = stack.Pop();
}

return nodesCount;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@ namespace Pharmacist.Core
Android = 0,
iOS = 1,
Mac = 2,
Tizen4 = 3,
WPF = 4,
XamForms = 5,
UWP = 6,
Winforms = 7,
TVOS = 8,
Essentials = 9,
WPF = 3,
UWP = 4,
Winforms = 5,
TVOS = 6,
}
public class static ObservablesForEventGenerator
{
public static System.Threading.Tasks.Task ExtractEventsFromAssemblies(System.IO.Stream outputStream, System.Collections.Generic.IEnumerable<string> assemblyPaths, System.Collections.Generic.IEnumerable<string> searchDirectories) { }
public static System.Threading.Tasks.Task ExtractEventsFromNuGetPackages(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.Packaging.Core.PackageIdentity> packages, System.Collections.Generic.IReadOnlyCollection<NuGet.Frameworks.NuGetFramework> frameworks) { }
public static System.Threading.Tasks.Task ExtractEventsFromNuGetPackages(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.LibraryModel.LibraryRange> packages, System.Collections.Generic.IReadOnlyCollection<NuGet.Frameworks.NuGetFramework> frameworks) { }
public static System.Threading.Tasks.Task ExtractEventsFromPlatforms(string outputPath, string prefix, string defaultReferenceAssemblyLocation, System.Collections.Generic.IEnumerable<Pharmacist.Core.AutoPlatform> platforms) { }
public static System.Threading.Tasks.Task ExtractEventsFromPlatforms(string outputPath, string prefix, string suffix, string defaultReferenceAssemblyLocation, System.Collections.Generic.IEnumerable<Pharmacist.Core.AutoPlatform> platforms) { }
public static System.Threading.Tasks.Task WriteHeader(System.IO.Stream outputStream) { }
public static System.Threading.Tasks.Task WriteHeader(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.LibraryModel.LibraryRange> libraryRanges) { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@ namespace Pharmacist.Core
Android = 0,
iOS = 1,
Mac = 2,
Tizen4 = 3,
WPF = 4,
XamForms = 5,
UWP = 6,
Winforms = 7,
TVOS = 8,
Essentials = 9,
WPF = 3,
UWP = 4,
Winforms = 5,
TVOS = 6,
}
public class static ObservablesForEventGenerator
{
public static System.Threading.Tasks.Task ExtractEventsFromAssemblies(System.IO.Stream outputStream, System.Collections.Generic.IEnumerable<string> assemblyPaths, System.Collections.Generic.IEnumerable<string> searchDirectories) { }
public static System.Threading.Tasks.Task ExtractEventsFromNuGetPackages(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.Packaging.Core.PackageIdentity> packages, System.Collections.Generic.IReadOnlyCollection<NuGet.Frameworks.NuGetFramework> frameworks) { }
public static System.Threading.Tasks.Task ExtractEventsFromNuGetPackages(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.LibraryModel.LibraryRange> packages, System.Collections.Generic.IReadOnlyCollection<NuGet.Frameworks.NuGetFramework> frameworks) { }
public static System.Threading.Tasks.Task ExtractEventsFromPlatforms(string outputPath, string prefix, string defaultReferenceAssemblyLocation, System.Collections.Generic.IEnumerable<Pharmacist.Core.AutoPlatform> platforms) { }
public static System.Threading.Tasks.Task ExtractEventsFromPlatforms(string outputPath, string prefix, string suffix, string defaultReferenceAssemblyLocation, System.Collections.Generic.IEnumerable<Pharmacist.Core.AutoPlatform> platforms) { }
public static System.Threading.Tasks.Task WriteHeader(System.IO.Stream outputStream) { }
public static System.Threading.Tasks.Task WriteHeader(System.IO.Stream outputStream, System.Collections.Generic.IReadOnlyCollection<NuGet.LibraryModel.LibraryRange> libraryRanges) { }
}
Expand Down
Loading

0 comments on commit 388e2c7

Please sign in to comment.