diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ee33035..652ee37 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -39,12 +39,21 @@ - + + all + runtime; build; native; contentfiles; analyzers + - - + + all + runtime; build; native; contentfiles; analyzers + + + all + runtime; build; native; contentfiles; analyzers + diff --git a/src/ReactiveMarbles.NuGet.Helpers/AssemblyHelpers.cs b/src/ReactiveMarbles.NuGet.Helpers/AssemblyHelpers.cs deleted file mode 100644 index 2533ce6..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/AssemblyHelpers.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Helps get details about assemblies. - /// - public static class AssemblyHelpers - { - private static readonly string[] AssemblyFileExtensions = - { - ".winmd", ".dll", ".exe" - }; - - /// - /// Gets the assembly file extensions set. - /// - public static ISet AssemblyFileExtensionsSet { get; } = new HashSet(AssemblyFileExtensions, StringComparer.InvariantCultureIgnoreCase); - - /// - /// Finds the union metadata file. - /// - /// The name. - /// The version. - /// The file if found. - public static string? FindUnionMetadataFile(string name, Version version) - { - var basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Kits", "10", "UnionMetadata"); - - if (!Directory.Exists(basePath)) - { - return null; - } - - basePath = Path.Combine(basePath, FindClosestVersionDirectory(basePath, version)); - - if (!Directory.Exists(basePath)) - { - return null; - } - - var file = Path.Combine(basePath, name + ".winmd"); - - return !File.Exists(file) ? null : file; - } - - /// - /// Finds the windows metadata file. - /// - /// The name. - /// The version. - /// The file if found. - public static string? FindWindowsMetadataFile(string name, Version? version) - { - // This is only supported on windows at the moment. - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return null; - } - - var basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Windows Kits", "10", "References"); - - if (!Directory.Exists(basePath)) - { - return FindWindowsMetadataInSystemDirectory(name); - } - - if (version is null) - { - return null; - } - - basePath = Path.Combine(basePath, FindClosestVersionDirectory(basePath, version)); - - if (!Directory.Exists(basePath)) - { - return FindWindowsMetadataInSystemDirectory(name); - } - - var file = Path.Combine(basePath, name + ".winmd"); - - return !File.Exists(file) ? FindWindowsMetadataInSystemDirectory(name) : file; - } - - private static string? FindWindowsMetadataInSystemDirectory(string name) - { - var file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd"); - return File.Exists(file) ? file : null; - } - - private static string? FindClosestVersionDirectory(string basePath, Version version) - { - string? path = null; - foreach (var folder in new DirectoryInfo(basePath) - .EnumerateDirectories() - .Select(d => ConvertToVersion(d.Name)) - .Where(v => v.Version != null) - .OrderByDescending(v => v.Version)) - { - if (path == null || folder.Version >= version) - { - path = folder.Name; - } - } - - return path ?? version.ToString(); - } - - [SuppressMessage("Design", "CA1031: Modify to catch a more specific exception type, or rethrow the exception.", Justification = "Deliberate usage.")] - private static (Version? Version, string? Name) ConvertToVersion(string name) - { - string RemoveTrailingVersionInfo() - { - var shortName = name; - var dashIndex = shortName.IndexOf('-'); - if (dashIndex > 0) - { - shortName = shortName.Remove(dashIndex); - } - - return shortName; - } - - try - { - return (new Version(RemoveTrailingVersionInfo()), name); - } - catch (Exception) - { - return (null, null); - } - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/ConsoleNuGetLoggerOutput.cs b/src/ReactiveMarbles.NuGet.Helpers/ConsoleNuGetLoggerOutput.cs deleted file mode 100644 index 4060366..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/ConsoleNuGetLoggerOutput.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Provides logging to the console. - /// - public class ConsoleNuGetLoggerOutput : INuGetLoggerOutput - { - /// - public void Debug(string data) - { - Console.WriteLine("[DEBUG]: " + data); - } - - /// - public void Error(string data) - { - Console.WriteLine("[ERROR]: " + data); - } - - /// - public void Info(string data) - { - Console.WriteLine("[INFO]: " + data); - } - - /// - public void Warn(string data) - { - Console.WriteLine("[WARN]: " + data); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/FileSystemHelpers.cs b/src/ReactiveMarbles.NuGet.Helpers/FileSystemHelpers.cs deleted file mode 100644 index 413a499..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/FileSystemHelpers.cs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.IO; -using System.Linq; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Helpers with the file system. - /// - public static class FileSystemHelpers - { - /// - /// Gets the subdirectories with match. - /// - /// The directories. - /// The extensions. - /// The subdirectories. - public static IEnumerable GetSubdirectoriesWithMatch(IEnumerable directories, ISet extensions) - { - var searchStack = new Stack(directories.Select(x => new DirectoryInfo(x))); - - while (searchStack.Count != 0) - { - var directoryInfo = searchStack.Pop(); - - if (directoryInfo.EnumerateFiles().Any(file => extensions.Contains(file.Extension))) - { - yield return directoryInfo.FullName; - } - - foreach (var directory in directoryInfo.EnumerateDirectories()) - { - searchStack.Push(directory); - } - } - } - - /// - /// Gets the files within subdirectories. - /// - /// The directories. - /// The files. - public static IEnumerable GetFilesWithinSubdirectories(IEnumerable directories) - { - return GetFilesWithinSubdirectories(directories, AssemblyHelpers.AssemblyFileExtensionsSet); - } - - /// - /// Gets the files within subdirectories. - /// - /// The directories. - /// The extensions. - /// The files. - public static IEnumerable GetFilesWithinSubdirectories(IEnumerable directories, ISet extensions) - { - if (extensions == null) - { - throw new ArgumentNullException(nameof(extensions)); - } - - var searchStack = new Stack(directories.Select(x => new DirectoryInfo(x))); - - while (searchStack.Count != 0) - { - var directoryInfo = searchStack.Pop(); - - foreach (var file in directoryInfo.EnumerateFiles().Where(file => extensions.Contains(file.Extension))) - { - yield return file.FullName; - } - - foreach (var directory in directoryInfo.EnumerateDirectories()) - { - searchStack.Push(directory); - } - } - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/FilesGroup.cs b/src/ReactiveMarbles.NuGet.Helpers/FilesGroup.cs deleted file mode 100644 index 22b4735..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/FilesGroup.cs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.IO; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Contains details about a folder within a NuGet package. - /// - public class FilesGroup - { - private readonly DirectoryNode _rootNode = new(string.Empty); - - /// - /// Gets for a file name, the nearest matching full name in the shallowest of the hierarchy. - /// - /// The file name to grab. - /// The full path if available, null otherwise. - public string? GetFullFilePath(string fileName) - { - var processing = new Queue(new[] { _rootNode }); - - while (processing.Count != 0) - { - var current = processing.Dequeue(); - - if (current.TryGetFile(fileName, out var fullPath)) - { - return fullPath; - } - - foreach (var child in current.ChildNodes) - { - processing.Enqueue(child); - } - } - - return null; - } - - /// - /// Gets all the files contained within the files group. - /// - /// The files. - public IEnumerable GetAllFileNames() - { - var processing = new Queue(new[] { _rootNode }); - - while (processing.Count != 0) - { - var current = processing.Dequeue(); - foreach (var file in current.Files) - { - yield return file.FullPath; - } - - foreach (var child in current.ChildNodes) - { - processing.Enqueue(child); - } - } - } - - /// - /// Adds files if they don't already exist to our collection. - /// - /// The files to add. - public void AddFiles(IEnumerable files) - { - if (files is null) - { - throw new ArgumentNullException(nameof(files)); - } - - foreach (var file in files) - { - var directoryPath = Path.GetDirectoryName(file); - - var splitDirectory = directoryPath?.Split(new[] { Path.PathSeparator, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty(); - - var directoryNode = _rootNode; - - foreach (var currentPath in splitDirectory) - { - directoryNode = directoryNode.AddChildNode(currentPath); - } - - directoryNode?.AddFile(file); - } - } - - private class DirectoryNode : IEqualityComparer, IComparable - { - private readonly Dictionary _childNodesDict = new(); - private readonly List _childNodes = new(); - private readonly List _files = new(); - private readonly Dictionary _filesDict = new(); - - public DirectoryNode(DirectoryNode? parent, string name) - { - Name = name; - Parent = parent; - } - - public DirectoryNode(string name) - : this(null, name) - { - } - - public string Name { get; } - - public string FullPath - { - get - { - return Parent == null || string.IsNullOrWhiteSpace(Parent.FullPath) ? Name : Parent.FullPath + Path.DirectorySeparatorChar + Name; - } - } - - public DirectoryNode? Parent { get; } - - public IEnumerable Files => _files; - - public IEnumerable ChildNodes => _childNodes; - - public bool TryGetChildNode(string path, out DirectoryNode? outValue) - { - return _childNodesDict.TryGetValue(path, out outValue); - } - - public bool TryGetFile(string name, out string? outValue) - { - if (_filesDict.TryGetValue(name, out var node)) - { - outValue = node.FullPath; - return true; - } - - outValue = null; - return false; - } - - public DirectoryNode AddChildNode(string name) - { - if (!_childNodesDict.TryGetValue(name, out var node)) - { - node = new DirectoryNode(this, name); - _childNodesDict.Add(name, node); - _childNodes.Add(node); - } - - return node; - } - - public FileNode AddFile(string fullPath) - { - var name = Path.GetFileName(fullPath); - - if (!_filesDict.TryGetValue(name, out var node)) - { - node = new FileNode(name, fullPath); - _filesDict.Add(name, node); - var index = _files.BinarySearch(node); - if (index < 0) - { - _files.Insert(~index, node); - } - } - - return node; - } - - /// - public bool Equals(DirectoryNode x, DirectoryNode y) - { - return StringComparer.InvariantCultureIgnoreCase.Equals(x?.Name, y?.Name); - } - - /// - public int GetHashCode(DirectoryNode obj) - { - return StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj.Name); - } - - /// - public int CompareTo(DirectoryNode other) - { - if (ReferenceEquals(this, other)) - { - return 0; - } - - return ReferenceEquals(null, other) ? 1 : StringComparer.InvariantCultureIgnoreCase.Compare(this, other); - } - } - - private class FileNode : IEqualityComparer, IComparable - { - public FileNode(string fileName, string fullPath) - { - FullPath = fullPath; - FileName = fileName; - } - - public string FullPath { get; } - - public string FileName { get; } - - /// - public bool Equals(FileNode x, FileNode y) - { - return StringComparer.InvariantCultureIgnoreCase.Equals(x?.FullPath, y?.FullPath); - } - - /// - public int GetHashCode(FileNode obj) - { - return StringComparer.InvariantCultureIgnoreCase.GetHashCode(obj.FullPath); - } - - /// - public int CompareTo(FileNode other) - { - return StringComparer.InvariantCultureIgnoreCase.Compare(FullPath, other?.FullPath); - } - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/INuGetLoggerOutput.cs b/src/ReactiveMarbles.NuGet.Helpers/INuGetLoggerOutput.cs deleted file mode 100644 index 420df26..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/INuGetLoggerOutput.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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 ReactiveMarbles.NuGet.Helpers -{ - /// - /// Provides logging to the NuGet helpers. - /// - public interface INuGetLoggerOutput - { - /// - /// Outputs a warning string. - /// - /// The logging data. - void Warn(string data); - - /// - /// Outputs a error string. - /// - /// The logging data. - void Error(string data); - - /// - /// Outputs a information string. - /// - /// The logging data. - void Info(string data); - - /// - /// Outputs a debug string. - /// - /// The logging data. - void Debug(string data); - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/InputAssembliesGroup.cs b/src/ReactiveMarbles.NuGet.Helpers/InputAssembliesGroup.cs deleted file mode 100644 index 26142cd..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/InputAssembliesGroup.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// A series of folders and files for processing. - /// - public class InputAssembliesGroup - { - /// - /// Gets a folder group which should contain the inclusions. - /// - public FilesGroup IncludeGroup { get; internal set; } = new FilesGroup(); - - /// - /// Gets a folder group with folders for including for support files only. - /// - public FilesGroup SupportGroup { get; internal set; } = new FilesGroup(); - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkFolderHelper.cs b/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkFolderHelper.cs deleted file mode 100644 index bbf411f..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkFolderHelper.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Diagnostics.CodeAnalysis; -using System.IO; -using System.Runtime.InteropServices; - -using NuGet.Frameworks; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// A folder helper to get nuget framework information. - /// - public static class NuGetFrameworkFolderHelper - { - /// - /// Handles getting additional reference libraries where none exists. - /// - /// The framework to analyze. - /// A list of additional paths. - public static IEnumerable GetNuGetFrameworkFolders(this NuGetFramework framework) - { - var folders = framework.Framework.ToLowerInvariant() switch - { - "monoandroid" => HandleAndroid(framework), - "xamarin.ios" => HandleiOS(), - "xamarin.tvos" => HandleTVOS(), - "xamarin.watchos" => HandleWatchOS(), - "xamarin.mac" => HandleMac(), - _ => Array.Empty(), - }; - - return FileSystemHelpers.GetSubdirectoriesWithMatch(folders, AssemblyHelpers.AssemblyFileExtensionsSet); - } - - private static IEnumerable HandleWatchOS() - { - var referenceAssembliesLocation = GetReferenceLocation("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/"); - - return new[] { Path.Combine(referenceAssembliesLocation, "Xamarin.WatchOS") }; - } - - private static IEnumerable HandleTVOS() - { - var referenceAssembliesLocation = GetReferenceLocation("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/"); - - return new[] { Path.Combine(referenceAssembliesLocation, "Xamarin.TVOS") }; - } - - private static IEnumerable HandleiOS() - { - var referenceAssembliesLocation = GetReferenceLocation("/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/lib/mono/"); - - return new[] { Path.Combine(referenceAssembliesLocation, "Xamarin.iOS") }; - } - - private static IEnumerable HandleMac() - { - var referenceAssembliesLocation = GetReferenceLocation("/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/lib/mono/"); - - return new[] { Path.Combine(referenceAssembliesLocation, "Xamarin.Mac") }; - } - - private static IEnumerable HandleAndroid(NuGetFramework nugetFramework) - { - var referenceAssembliesLocation = GetReferenceLocation("/Library/Frameworks/Xamarin.Android.framework/Versions/Current/lib/xamarin.android/xbuild-frameworks"); - - var versionText = $"v{nugetFramework.Version.Major}.{nugetFramework.Version.Minor}"; - - return new[] { Path.Combine(referenceAssembliesLocation, "MonoAndroid", versionText), Path.Combine(referenceAssembliesLocation, "MonoAndroid", "v1.0") }; - } - - private static string GetReferenceLocation(string macLocation) - { - string referenceAssembliesLocation; - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - referenceAssembliesLocation = macLocation; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - referenceAssembliesLocation = ReferenceLocator.GetReferenceLocation(); - } - else - { - throw new NotSupportedException("Cannot process on Linux"); - } - - return referenceAssembliesLocation; - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkHelper.cs b/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkHelper.cs deleted file mode 100644 index 73c142b..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkHelper.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Reflection; - -using NuGet.Frameworks; -using NuGet.Packaging.Core; -using NuGet.Versioning; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Helper class which will convert framework identifier strings to their nuget framework. - /// - public static class NuGetFrameworkHelper - { - private static readonly Dictionary> _nugetFrameworks; - - /// - /// Initializes static members of the class. - /// - static NuGetFrameworkHelper() - { - _nugetFrameworks = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); - foreach (var property in typeof(FrameworkConstants.CommonFrameworks).GetProperties(BindingFlags.NonPublic | BindingFlags.Static)) - { - _nugetFrameworks[property.Name] = new[] { (NuGetFramework)property.GetValue(null) }; - } - - // Some special cases for .net standard/.net app core since they require the '.' character in the numbers. - _nugetFrameworks["NetStandard1.0"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard10 }; - _nugetFrameworks["NetStandard1.1"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard11 }; - _nugetFrameworks["NetStandard1.2"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard12 }; - _nugetFrameworks["NetStandard1.3"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard13 }; - _nugetFrameworks["NetStandard1.4"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard14 }; - _nugetFrameworks["NetStandard1.5"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard15 }; - _nugetFrameworks["NetStandard1.6"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard16 }; - _nugetFrameworks["NetStandard1.7"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard17 }; - _nugetFrameworks["NetStandard2.0"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["NetStandard2.1"] = new[] { FrameworkConstants.CommonFrameworks.NetStandard21 }; - _nugetFrameworks["UAP"] = new[] { FrameworkConstants.CommonFrameworks.UAP10 }; - _nugetFrameworks["UAP10.0"] = new[] { FrameworkConstants.CommonFrameworks.UAP10 }; - _nugetFrameworks["NetCoreApp1.0"] = new[] { FrameworkConstants.CommonFrameworks.NetCoreApp10 }; - _nugetFrameworks["NetCoreApp1.1"] = new[] { FrameworkConstants.CommonFrameworks.NetCoreApp11 }; - _nugetFrameworks["NetCoreApp2.0"] = new[] { FrameworkConstants.CommonFrameworks.NetCoreApp20 }; - _nugetFrameworks["NetCoreApp2.1"] = new[] { FrameworkConstants.CommonFrameworks.NetCoreApp21 }; - _nugetFrameworks["NetCoreApp2.2"] = new[] { new NuGetFramework(".NETCoreApp", new Version(2, 1, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["NetCoreApp3.0"] = new[] { new NuGetFramework(".NETCoreApp", new Version(3, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["NetCoreApp3.1"] = new[] { new NuGetFramework(".NETCoreApp", new Version(3, 1, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid50"] = new[] { new NuGetFramework("MonoAndroid", new Version(5, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid51"] = new[] { new NuGetFramework("MonoAndroid", new Version(5, 1, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid60"] = new[] { new NuGetFramework("MonoAndroid", new Version(6, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid70"] = new[] { new NuGetFramework("MonoAndroid", new Version(7, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid71"] = new[] { new NuGetFramework("MonoAndroid", new Version(7, 1, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid80"] = new[] { new NuGetFramework("MonoAndroid", new Version(8, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid81"] = new[] { new NuGetFramework("MonoAndroid", new Version(8, 1, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid90"] = new[] { new NuGetFramework("MonoAndroid", new Version(9, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid10.0"] = new[] { new NuGetFramework("MonoAndroid", new Version(10, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoAndroid11.0"] = new[] { new NuGetFramework("MonoAndroid", new Version(11, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["MonoTouch10"] = new[] { new NuGetFramework("MonoAndroid", new Version(1, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["Xamarin.iOS10"] = new[] { new NuGetFramework("Xamarin.iOS", new Version(1, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["Xamarin.Mac20"] = new[] { new NuGetFramework("Xamarin.Mac", new Version(2, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["Xamarin.TVOS10"] = new[] { new NuGetFramework("Xamarin.TVOS", new Version(1, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["Xamarin.WATCHOS10"] = new[] { new NuGetFramework("Xamarin.WATCHOS", new Version(1, 0, 0, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["net11"] = new[] { FrameworkConstants.CommonFrameworks.Net11 }; - - _nugetFrameworks["net20"] = new[] { FrameworkConstants.CommonFrameworks.Net2 }; - _nugetFrameworks["net35"] = new[] { FrameworkConstants.CommonFrameworks.Net35 }; - _nugetFrameworks["net40"] = new[] { FrameworkConstants.CommonFrameworks.Net4 }; - _nugetFrameworks["net403"] = new[] { FrameworkConstants.CommonFrameworks.Net403 }; - _nugetFrameworks["net45"] = new[] { FrameworkConstants.CommonFrameworks.Net45 }; - _nugetFrameworks["net451"] = new[] { FrameworkConstants.CommonFrameworks.Net451 }; - _nugetFrameworks["net452"] = new[] { FrameworkConstants.CommonFrameworks.Net452 }; - _nugetFrameworks["net46"] = new[] { FrameworkConstants.CommonFrameworks.Net46 }; - _nugetFrameworks["net461"] = new[] { FrameworkConstants.CommonFrameworks.Net461 }; - _nugetFrameworks["net462"] = new[] { FrameworkConstants.CommonFrameworks.Net462 }; - _nugetFrameworks["net47"] = new[] { new NuGetFramework(".NETFramework", new Version(4, 7, 0, 0)) }; - _nugetFrameworks["net471"] = new[] { new NuGetFramework(".NETFramework", new Version(4, 7, 1, 0)) }; - _nugetFrameworks["net472"] = new[] { new NuGetFramework(".NETFramework", new Version(4, 7, 2, 0)) }; - _nugetFrameworks["net48"] = new[] { new NuGetFramework(".NETFramework", new Version(4, 8, 0, 0)) }; - _nugetFrameworks["net5.0"] = new[] { FrameworkConstants.CommonFrameworks.Net50 }; - - _nugetFrameworks["uap10.0"] = new[] { FrameworkConstants.CommonFrameworks.UAP10, FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap"] = new[] { FrameworkConstants.CommonFrameworks.UAP10, FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.18362"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 18362, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.17763"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 17763, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.17134"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 17134, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.16299"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 16299, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.15063"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 15063, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.14393"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 14393, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.10586"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 10586, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - _nugetFrameworks["uap10.0.10240"] = new[] { new NuGetFramework("UAP", new Version(10, 0, 10240, 0)), FrameworkConstants.CommonFrameworks.NetStandard20 }; - - _nugetFrameworks["Tizen40"] = new[] { FrameworkConstants.CommonFrameworks.Tizen4, FrameworkConstants.CommonFrameworks.NetStandard20 }; - } - - /// - /// Extension method for getting the framework from the framework name. - /// Ordered by the priority order. - /// - /// The name of the framework. - /// The framework. - public static IReadOnlyList ToFrameworks(this string frameworkName) - { - _nugetFrameworks.TryGetValue(frameworkName, out var framework); - - return framework; - } - - /// - /// Gets a package identity if the framework is package based. - /// - /// The framework to check. - /// The package details or null if none is available. - public static IEnumerable GetSupportLibraries(this NuGetFramework framework) - { - if (framework == null) - { - throw new ArgumentNullException(nameof(framework)); - } - - if (framework.Framework.StartsWith(".NETStandard", StringComparison.OrdinalIgnoreCase)) - { - return framework.Version >= new Version(2, 1, 0) - ? new[] { new PackageIdentity("NETStandard.Library.Ref", new NuGetVersion(framework.Version)) } - : new[] { new PackageIdentity("NETStandard.Library", new NuGetVersion(framework.Version)) }; - } - - if (framework.Framework.StartsWith(".NETCoreApp", StringComparison.OrdinalIgnoreCase)) - { - return framework.Version > new Version(2, 2, 8) ? - new[] { new PackageIdentity("Microsoft.NETCore.App.Ref", new NuGetVersion(framework.Version)) } : - new[] { new PackageIdentity("Microsoft.NETCore.App", new NuGetVersion(framework.Version)) }; - } - - if (framework.Framework.StartsWith("Tizen", StringComparison.OrdinalIgnoreCase) && framework.Version == new Version("4.0.0.0")) - { - return new[] - { - new PackageIdentity("Tizen.NET.API4", new NuGetVersion("4.0.1.14152")), - new PackageIdentity("NETStandard.Library", new NuGetVersion("2.0.0.0")) - }; - } - - if (framework.Framework.StartsWith(".NETFramework", StringComparison.OrdinalIgnoreCase)) - { - return new[] { new PackageIdentity("Microsoft.NETFramework.ReferenceAssemblies", new NuGetVersion("1.0.0-preview.2")) }; - } - - if (framework.Framework.StartsWith("Mono", StringComparison.OrdinalIgnoreCase)) - { - return new[] { new PackageIdentity("NETStandard.Library", new NuGetVersion("2.0.0.0")) }; - } - - return framework.Framework.StartsWith("Xamarin", StringComparison.OrdinalIgnoreCase) - ? new[] { new PackageIdentity("NETStandard.Library", new NuGetVersion("2.0.0.0")) } - : Array.Empty(); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkInRangeComparer.cs b/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkInRangeComparer.cs deleted file mode 100644 index be2fcdb..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/NuGetFrameworkInRangeComparer.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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 NuGet.Frameworks; - -namespace ReactiveMarbles.NuGet.Helpers -{ - internal class NuGetFrameworkInRangeComparer : IComparer, IEqualityComparer - { - public static NuGetFrameworkInRangeComparer Default { get; } = new NuGetFrameworkInRangeComparer(); - - /// - public bool Equals(NuGetFramework x, NuGetFramework y) - { - return !NuGetFramework.FrameworkNameComparer.Equals(x, y) ? false : x.Version >= y.Version; - } - - /// - public int GetHashCode(NuGetFramework obj) - { - return NuGetFramework.FrameworkNameComparer.GetHashCode(obj); - } - - /// - public int Compare(NuGetFramework x, NuGetFramework y) - { - var result = StringComparer.OrdinalIgnoreCase.Compare(x.Framework, y.Framework); - - return result != 0 ? result : x.Version.CompareTo(y.Version); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/NuGetLogger.cs b/src/ReactiveMarbles.NuGet.Helpers/NuGetLogger.cs deleted file mode 100644 index a720035..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/NuGetLogger.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated licenses this file to you under the MIT license. -// See the LICENSE file in the project root for full license information. - -using System.Threading.Tasks; - -using NuGet.Common; - -using LogLevel = NuGet.Common.LogLevel; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// A logger provider for the NuGet clients API. - /// - internal class NuGetLogger : ILogger - { - private INuGetLoggerOutput _logger; - - public NuGetLogger(INuGetLoggerOutput? logger = null) - { - _logger = logger ?? new ConsoleNuGetLoggerOutput(); - } - - /// - public void Log(LogLevel level, string data) - { - switch (level) - { - case LogLevel.Warning: - _logger.Warn(data); - break; - case LogLevel.Error: - _logger.Error(data); - break; - case LogLevel.Information: - _logger.Info(data); - break; - case LogLevel.Debug: - _logger.Debug(data); - break; - default: - _logger.Info(data); - break; - } - } - - /// - public void Log(ILogMessage message) - { - Log(message.Level, message.Message); - } - - /// - public Task LogAsync(LogLevel level, string data) - { - Log(level, data); - return Task.CompletedTask; - } - - /// - public Task LogAsync(ILogMessage message) - { - Log(message); - return Task.CompletedTask; - } - - /// - public void LogDebug(string data) - { - _logger.Debug(data); - } - - /// - public void LogError(string data) - { - _logger.Error(data); - } - - /// - public void LogInformation(string data) - { - _logger.Info(data); - } - - /// - public void LogInformationSummary(string data) - { - _logger.Info(data); - } - - /// - public void LogMinimal(string data) - { - _logger.Info(data); - } - - /// - public void LogVerbose(string data) - { - _logger.Info(data); - } - - /// - public void LogWarning(string data) - { - _logger.Warn(data); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/NuGetPackageHelper.cs b/src/ReactiveMarbles.NuGet.Helpers/NuGetPackageHelper.cs deleted file mode 100644 index 23c782a..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/NuGetPackageHelper.cs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using NuGet.Configuration; -using NuGet.Frameworks; -using NuGet.LibraryModel; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Protocol; -using NuGet.Protocol.Core.Types; -using NuGet.Versioning; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// A helper class for handling NuGet packages. - /// - public static class NuGetPackageHelper - { - /// - /// Gets the default nuget source. - /// - public const string DefaultNuGetSource = "https://api.nuget.org/v3/index.json"; - - private static readonly int ProcessingCount = Environment.ProcessorCount; - - private static readonly string[] DefaultFoldersToGrab = { PackagingConstants.Folders.Lib, PackagingConstants.Folders.Build, PackagingConstants.Folders.Ref }; - - // Bunch of NuGet based objects we can cache and only create once. - private static readonly string _globalPackagesPath; - private static readonly NuGetLogger _logger = new(); - private static readonly SourceCacheContext _sourceCacheContext = NullSourceCacheContext.Instance; - private static readonly PackageDownloadContext _downloadContext = new(_sourceCacheContext); - private static readonly IFrameworkNameProvider _frameworkNameProvider = DefaultFrameworkNameProvider.Instance; - - static NuGetPackageHelper() - { - Providers = new List>(); - Providers.AddRange(Repository.Provider.GetCoreV3()); - - _globalPackagesPath = SettingsUtility.GetGlobalPackagesFolder(new XPlatMachineWideSetting().Settings); - } - - /// - /// Gets the providers for the nuget resources. - /// - public static List> Providers { get; } - - /// - /// Downloads the specified packages and returns the files and directories where the package NuGet package lives. - /// - /// Library identity we want to match. - /// Optional framework parameter which will force NuGet to evaluate as the specified Framework. If null it will use .NET Standard 2.0. - /// Optional v3 nuget source. Will default to default nuget.org servers. - /// If we should get the dependencies. - /// Directories to package folders. Will be lib/build/ref if not defined. - /// A directory where to store the files, if null a random location will be used. - /// A cancellation token. - /// The directory where the NuGet packages are unzipped to. Also the files contained within the requested package only. - public static Task DownloadPackageFilesAndFolder( - LibraryRange library, - IReadOnlyCollection? frameworks = null, - PackageSource? nugetSource = null, - bool getDependencies = true, - IReadOnlyCollection? packageFolders = null, - string? packageOutputDirectory = null, - CancellationToken token = default) => - DownloadPackageFilesAndFolder(new LibraryRange[] { library }, frameworks, nugetSource, getDependencies, packageFolders, packageOutputDirectory, token); - - /// - /// Downloads the specified packages and returns the files and directories where the package NuGet package lives. - /// - /// Library identities we want to match. - /// Optional framework parameter which will force NuGet to evaluate as the specified Framework. If null it will use .NET Standard 2.0. - /// Optional v3 nuget source. Will default to default nuget.org servers. - /// If we should get the dependencies. - /// Directories to package folders. Will be lib/build/ref if not defined. - /// A directory where to store the files, if null a random location will be used. - /// A cancellation token. - /// The directory where the NuGet packages are unzipped to. Also the files contained within the requested package only. - public static async Task DownloadPackageFilesAndFolder( - IReadOnlyCollection libraryIdentities, - IReadOnlyCollection? frameworks = null, - PackageSource? nugetSource = null, - bool getDependencies = true, - IReadOnlyCollection? packageFolders = null, - string? packageOutputDirectory = null, - CancellationToken token = default) - { - // If the user hasn't selected a default framework to extract, select .NET Standard 2.0 - frameworks ??= new[] { FrameworkConstants.CommonFrameworks.NetStandard20 }; - - // Use the provided nuget package source, or use nuget.org - var sourceRepository = new SourceRepository(nugetSource ?? new PackageSource(DefaultNuGetSource), Providers); - - var downloadResource = await sourceRepository.GetResourceAsync(token).ConfigureAwait(false); - var findPackageResource = await sourceRepository.GetResourceAsync(token).ConfigureAwait(false); - - var packages = await Task.WhenAll(libraryIdentities.Select(x => GetBestMatch(x, findPackageResource, token))).ConfigureAwait(false); - - return await DownloadPackageFilesAndFolder(packages, frameworks, downloadResource, getDependencies, packageFolders, packageOutputDirectory, token).ConfigureAwait(false); - } - - /// - /// Downloads the specified packages and returns the files and directories where the package NuGet package lives. - /// - /// The identity of the packages to find. - /// Optional framework parameter which will force NuGet to evaluate as the specified Framework. If null it will use .NET Standard 2.0. - /// Optional v3 nuget source. Will default to default nuget.org servers. - /// If we should get the dependencies. - /// Directories to package folders. Will be lib/build/ref if not defined. - /// A directory where to store the files, if null a random location will be used. - /// A cancellation token. - /// The directory where the NuGet packages are unzipped to. Also the files contained within the requested package only. - public static async Task DownloadPackageFilesAndFolder( - IReadOnlyCollection packageIdentities, - IReadOnlyCollection? frameworks = null, - PackageSource? nugetSource = null, - bool getDependencies = true, - IReadOnlyCollection? packageFolders = null, - string? packageOutputDirectory = null, - CancellationToken token = default) - { - // If the user hasn't selected a default framework to extract, select .NET Standard 2.0 - frameworks ??= new[] { FrameworkConstants.CommonFrameworks.NetStandard20 }; - - // Use the provided nuget package source, or use nuget.org - var sourceRepository = new SourceRepository(nugetSource ?? new PackageSource(DefaultNuGetSource), Providers); - - var downloadResource = await sourceRepository.GetResourceAsync(token).ConfigureAwait(false); - - return downloadResource is null - ? throw new InvalidOperationException("Could not find a valid package to download.") - : await DownloadPackageFilesAndFolder(packageIdentities, frameworks, downloadResource, getDependencies, packageFolders, packageOutputDirectory, token).ConfigureAwait(false); - } - - /// - /// Gets the best matching PackageIdentity for the specified LibraryRange. - /// - /// The library range to find the best patch for. - /// Optional v3 nuget source. Will default to default nuget.org servers. - /// A optional cancellation token. - /// The best matching PackageIdentity to the specified version range. - public static async Task GetBestMatch(LibraryRange identity, PackageSource? nugetSource = null, CancellationToken token = default) - { - if (identity == null) - { - throw new ArgumentNullException(nameof(identity)); - } - - // Use the provided nuget package source, or use nuget.org - var sourceRepository = new SourceRepository(nugetSource ?? new PackageSource(DefaultNuGetSource), Providers); - - var findPackageResource = await sourceRepository.GetResourceAsync(token).ConfigureAwait(false); - - return await GetBestMatch(identity, findPackageResource, token).ConfigureAwait(false); - } - - /// - /// Gets the best matching PackageIdentity for the specified LibraryRange. - /// - /// The library range to find the best patch for. - /// The source repository where to match. - /// A optional cancellation token. - /// The best matching PackageIdentity to the specified version range. - public static async Task GetBestMatch(LibraryRange identity, FindPackageByIdResource findPackageResource, CancellationToken token) - { - if (identity == null) - { - throw new ArgumentNullException(nameof(identity)); - } - - if (findPackageResource == null) - { - throw new ArgumentNullException(nameof(findPackageResource)); - } - - var versions = await findPackageResource.GetAllVersionsAsync(identity.Name, _sourceCacheContext, _logger, token).ConfigureAwait(false); - - var bestPackageVersion = versions?.FindBestMatch(identity.VersionRange, version => version); - - return new PackageIdentity(identity.Name, bestPackageVersion); - } - - /// - /// Downloads the specified packages and returns the files and directories where the package NuGet package lives. - /// - /// The identity of the packages to find. - /// Framework parameter which will force NuGet to evaluate as the specified Framework. If null it will use .NET Standard 2.0. - /// The download resource. - /// If we should get the dependencies. - /// Directories to package folders. Will be lib/build/ref if not defined. - /// A directory where to store the files, if null a random location will be used. - /// A cancellation token. - /// The directory where the NuGet packages are unzipped to. Also the files contained within the requested package only. - private static async Task DownloadPackageFilesAndFolder( - IReadOnlyCollection packageIdentities, - IReadOnlyCollection frameworks, - DownloadResource downloadResource, - bool getDependencies = true, - IReadOnlyCollection? packageFolders = null, - string? packageOutputDirectory = null, - CancellationToken token = default) - { - var librariesToCopy = await GetPackagesToCopy(packageIdentities, downloadResource, frameworks, getDependencies, token).ConfigureAwait(false); - - packageOutputDirectory ??= GetRandomPackageDirectory(); - packageFolders ??= DefaultFoldersToGrab; - - return CopyPackageFiles(librariesToCopy, frameworks, packageFolders, packageOutputDirectory, token); - } - - private static async Task> GetPackagesToCopy( - IReadOnlyCollection startingPackages, - DownloadResource downloadResource, - IReadOnlyCollection frameworks, - bool getDependencies, - CancellationToken token) - { - if (downloadResource is null) - { - throw new ArgumentNullException(nameof(downloadResource)); - } - - var packagesToCopy = new Dictionary(PackageIdentityNameComparer.Default); - - var stack = new Stack<(PackageIdentity PackageIdentity, bool Include)>(startingPackages.Select(x => (x, true))); - - if (getDependencies) - { - var supportLibraries = frameworks.SelectMany(x => x.GetSupportLibraries()).ToArray(); - if (supportLibraries.Length > 0) - { - stack.PushRange(supportLibraries.Select(x => (x, false))); - } - } - - var processingItems = new (PackageIdentity PackageIdentity, bool IncludeFiles)[ProcessingCount]; - while (stack.Count != 0) - { - var count = stack.TryPopRange(processingItems); - - var currentItems = processingItems.Take(count).Where( - item => !packagesToCopy.TryGetValue(item.PackageIdentity, out var existingValue) || item.PackageIdentity.Version > existingValue.PackageIdentity.Version).ToList(); - - // Download the resource into the global packages path. We get a result which allows us to copy or do other operations based on the files. - var results = await Task.WhenAll( - currentItems.Select( - async item => - (DownloadResourceResult: await downloadResource.GetDownloadResourceResultAsync(item.PackageIdentity, _downloadContext, _globalPackagesPath, _logger, token).ConfigureAwait(false), PackageIdentity: item.PackageIdentity, IncludeFilesInOutput: item.IncludeFiles))).ConfigureAwait(false); - - foreach (var item in results.Where(x => x.DownloadResourceResult.Status == DownloadResourceResultStatus.Available || x.DownloadResourceResult.Status == DownloadResourceResultStatus.AvailableWithoutStream)) - { - packagesToCopy[item.PackageIdentity] = item; - var dependencyInfos = GetDependencyPackages(item.DownloadResourceResult, frameworks.First()); - - stack.PushRange(dependencyInfos.Select(x => (x, false))); - } - } - - return packagesToCopy.Values.ToList(); - } - - private static InputAssembliesGroup CopyPackageFiles( - IReadOnlyCollection<(DownloadResourceResult DownloadResourceResult, PackageIdentity PackageIdentity, bool IncludeFilesInOutput)> packagesToProcess, - IReadOnlyCollection frameworks, - IReadOnlyCollection packageFolders, - string packageDirectory, - CancellationToken token) - { - // Default back to a any framework. - if (!frameworks.Contains(NuGetFramework.AnyFramework)) - { - frameworks = frameworks.Concat(new[] { NuGetFramework.AnyFramework }).ToList(); - } - - var inputAssembliesGroup = new InputAssembliesGroup(); - - foreach (var packageToProcess in packagesToProcess) - { - var (downloadResourceResult, packageIdentity, includeFilesInOutput) = packageToProcess; - var directory = Path.Combine(packageDirectory, packageIdentity.Id, packageIdentity.Version.ToNormalizedString()); - - // Get all the folders in our lib and build directory of our nuget. These are the general contents we include in our projects. - var packageFolderGroup = downloadResourceResult.PackageReader.GetFileGroups(packageFolders, frameworks); - - EnsureDirectory(directory); - - var folders = packageFolderGroup.Select( - x => (x.Folder, files: downloadResourceResult.PackageReader.CopyFiles( - directory, - x.Files, - new PackageFileExtractor(x.Files, XmlDocFileSaveMode.Skip).ExtractPackageFile, - _logger, - token))); - - foreach (var folder in folders) - { - if (includeFilesInOutput) - { - inputAssembliesGroup.IncludeGroup.AddFiles(folder.files); - } - else - { - inputAssembliesGroup.SupportGroup.AddFiles(folder.files); - } - } - } - - return inputAssembliesGroup; - } - - private static string GetRandomPackageDirectory() => Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - - private static void EnsureDirectory(string packageUnzipPath) - { - if (!Directory.Exists(packageUnzipPath)) - { - Directory.CreateDirectory(packageUnzipPath); - } - } - - /// - /// Gets dependency packages that matches our framework (current version or below). - /// - /// The results where to get the dependencies from. - /// The framework to match dependencies for. - /// The dependencies, or an empty array if there are no dependencies. - private static IEnumerable GetDependencyPackages(DownloadResourceResult downloadResults, NuGetFramework framework) - { - // Grab the package dependency group that matches is closest to our framework. - var highestFramework = downloadResults.PackageReader.GetPackageDependencies() - .Where(dependency => NuGetFrameworkInRangeComparer.Default.Equals(framework, dependency.TargetFramework)) - .OrderByDescending(dependency => dependency.TargetFramework.Version) - .FirstOrDefault(); - - // If no packages match our framework just return an empty array. - return highestFramework == null - ? Array.Empty() - : highestFramework.Packages.Select(package => new PackageIdentity(package.Id, package.VersionRange.MinVersion)); - } - - private static IEnumerable<(string Folder, IEnumerable Files)> GetFileGroups(this PackageReaderBase reader, IReadOnlyCollection folders, IReadOnlyCollection frameworksToInclude) - { - var groups = new Dictionary>>(new NuGetFrameworkFullComparer()); - foreach (var folder in folders) - { - foreach (var file in reader.GetFiles(folder)) - { - var frameworkFromPath = reader.GetFrameworkFromPath(file, true); - - var framework = frameworksToInclude.FirstOrDefault(x => NuGetFrameworkInRangeComparer.Default.Equals(x, frameworkFromPath)); - - if (framework == null) - { - continue; - } - - if (!groups.TryGetValue(frameworkFromPath, out var folderDictionary)) - { - folderDictionary = new Dictionary>(); - groups.Add(frameworkFromPath, folderDictionary); - } - - if (!folderDictionary.TryGetValue(folder, out var stringList)) - { - stringList = new List(); - folderDictionary.Add(folder, stringList); - } - - stringList.Add(file); - } - } - - foreach (var targetFramework in frameworksToInclude) - { - var key = groups.Keys.Where(x => NuGetFrameworkInRangeComparer.Default.Equals(targetFramework, x)).OrderByDescending(x => x.Version).FirstOrDefault(); - - if (key == null) - { - continue; - } - - if (!groups.TryGetValue(key, out var foldersDictionary)) - { - continue; - } - - if (foldersDictionary.Count == 0) - { - continue; - } - - var filesFound = false; - foreach (var folder in folders) - { - if (!foldersDictionary.TryGetValue(folder, out var files)) - { - continue; - } - - if (files.Count > 0) - { - filesFound = true; - } - - yield return (folder, files); - } - - if (filesFound) - { - break; - } - } - } - - private static NuGetFramework GetFrameworkFromPath(this IPackageCoreReader reader, string path, bool allowSubFolders = false) - { - var nuGetFramework = NuGetFramework.AnyFramework; - var strArray = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - if ((strArray.Length == 3 || strArray.Length > 3) && allowSubFolders) - { - var folderName = strArray[1]; - NuGetFramework folder; - try - { - folder = NuGetFramework.ParseFolder(folderName, _frameworkNameProvider); - } - catch (ArgumentException ex) - { - throw new PackagingException(string.Format(CultureInfo.CurrentCulture, "There is a invalid project {0}, {1}", path, reader.GetIdentity()), ex); - } - - if (folder.IsSpecificFramework) - { - nuGetFramework = folder; - } - } - - return nuGetFramework; - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/PackageIdentityNameComparer.cs b/src/ReactiveMarbles.NuGet.Helpers/PackageIdentityNameComparer.cs deleted file mode 100644 index 0928622..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/PackageIdentityNameComparer.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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 NuGet.Packaging.Core; - -namespace ReactiveMarbles.NuGet.Helpers -{ - internal class PackageIdentityNameComparer : IEqualityComparer - { - public static PackageIdentityNameComparer Default { get; } = new PackageIdentityNameComparer(); - - /// - public bool Equals(PackageIdentity x, PackageIdentity y) - { - return x == y ? true : StringComparer.OrdinalIgnoreCase.Equals(x?.Id, y?.Id); - } - - /// - public int GetHashCode(PackageIdentity obj) - { - return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.Id); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/ReactiveMarbles.NuGet.Helpers.csproj b/src/ReactiveMarbles.NuGet.Helpers/ReactiveMarbles.NuGet.Helpers.csproj deleted file mode 100644 index e1eb090..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/ReactiveMarbles.NuGet.Helpers.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netstandard2.0 - latest - enable - false - - - - - - - - diff --git a/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocationNotFoundException.cs b/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocationNotFoundException.cs deleted file mode 100644 index 909757f..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocationNotFoundException.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Runtime.Serialization; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Exception that happens when a reference cannot be located. - /// - [Serializable] - public class ReferenceLocationNotFoundException : Exception - { - /// - /// Initializes a new instance of the class. - /// - /// The error message. - public ReferenceLocationNotFoundException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The error message. - /// A inner exception with more error details. - public ReferenceLocationNotFoundException(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Initializes a new instance of the class. - /// - public ReferenceLocationNotFoundException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The serialization information. - /// The serialization context. - protected ReferenceLocationNotFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocator.cs b/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocator.cs deleted file mode 100644 index d881eb0..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/ReferenceLocator.cs +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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.Concurrent; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -using NuGet.Frameworks; -using NuGet.Packaging; -using NuGet.Packaging.Core; -using NuGet.Versioning; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Implements the reference locations for windows builds. - /// - public static class ReferenceLocator - { - private static readonly PackageIdentity VSWherePackageIdentity = new("VSWhere", new NuGetVersion("2.6.7")); - - private static readonly ConcurrentDictionary _windowsInstallationDirectory = new(); - - /// - /// Gets the reference location. - /// - /// If we should include pre-release software. - /// The reference location. - public static string GetReferenceLocation(bool includePreRelease = true) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return "/Library/Frameworks"; - } - - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - throw new InvalidOperationException( - "Visual Studio reference location not supported on this platform: " - + RuntimeInformation.OSDescription); - } - - var visualStudioInstallation = GetWindowsInstallationDirectory(includePreRelease); - - return Path.Combine(visualStudioInstallation, "Common7", "IDE", "ReferenceAssemblies", "Microsoft", "Framework"); - } - - private static string GetWindowsInstallationDirectory(bool includePreRelease) - { - return _windowsInstallationDirectory.GetOrAdd( - includePreRelease, - incPreRelease => - { - return Task.Run( - async () => - { - var results = await NuGetPackageHelper.DownloadPackageFilesAndFolder( - new[] { VSWherePackageIdentity }, - new[] { new NuGetFramework("Any") }, - packageFolders: new[] { PackagingConstants.Folders.Tools }, - getDependencies: false).ConfigureAwait(false); - - var fileName = results.IncludeGroup.GetAllFileNames().FirstOrDefault(x => x.EndsWith("vswhere.exe", StringComparison.InvariantCultureIgnoreCase)); - - if (fileName == null) - { - throw new ReferenceLocationNotFoundException("Cannot find visual studio installation, due to vswhere not being installed correctly."); - } - - var parameters = new StringBuilder("-latest -nologo -property installationPath -format value"); - - if (incPreRelease) - { - parameters.Append(" -prerelease"); - } - - using var process = new Process - { - StartInfo = - { - FileName = fileName, - Arguments = parameters.ToString(), - UseShellExecute = false, - RedirectStandardOutput = true - } - }; - - process.Start(); - - // To avoid deadlocks, always read the output stream first and then wait. - var output = (await process.StandardOutput.ReadToEndAsync().ConfigureAwait(false)).Replace(Environment.NewLine, string.Empty); - process.WaitForExit(); - - return output; - }).ConfigureAwait(false).GetAwaiter().GetResult(); - }); - } - } -} diff --git a/src/ReactiveMarbles.NuGet.Helpers/StackExtensions.cs b/src/ReactiveMarbles.NuGet.Helpers/StackExtensions.cs deleted file mode 100644 index db34d61..0000000 --- a/src/ReactiveMarbles.NuGet.Helpers/StackExtensions.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved. -// ReactiveUI Association Incorporated 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; - -namespace ReactiveMarbles.NuGet.Helpers -{ - /// - /// Extension methods for stack based operations. - /// - internal static class StackExtensions - { - public static void PushRange(this Stack stack, IEnumerable items) - { - foreach (var item in items) - { - stack.Push(item); - } - } - - public static int TryPopRange(this Stack stack, T[] items) - { - return TryPopRange(stack, items, 0, items.Length); - } - - public static int TryPopRange(this Stack 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."); - } - - var 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; - } - - var nodesCount = stack.Count > count ? count : stack.Count; - - for (var i = startIndex; i < startIndex + nodesCount; i++) - { - items[i] = stack.Pop(); - } - - return nodesCount; - } - } -} diff --git a/src/ReactiveMarbles.ObservableEvents.Example/MyForm.cs b/src/ReactiveMarbles.ObservableEvents.Example/MyForm.cs index 9a0a365..cd9bb00 100644 --- a/src/ReactiveMarbles.ObservableEvents.Example/MyForm.cs +++ b/src/ReactiveMarbles.ObservableEvents.Example/MyForm.cs @@ -11,7 +11,7 @@ using Xamarin.Forms; -[assembly: GenerateStaticEventObservablesAttribute(typeof(StaticTest))] +[assembly: GenerateStaticEventObservables(typeof(StaticTest))] #pragma warning disable namespace ReactiveMarbles.ObservableEvents diff --git a/src/ReactiveMarbles.ObservableEvents.Example/ReactiveMarbles.ObservableEvents.Example.csproj b/src/ReactiveMarbles.ObservableEvents.Example/ReactiveMarbles.ObservableEvents.Example.csproj index 321459d..ed7a63d 100644 --- a/src/ReactiveMarbles.ObservableEvents.Example/ReactiveMarbles.ObservableEvents.Example.csproj +++ b/src/ReactiveMarbles.ObservableEvents.Example/ReactiveMarbles.ObservableEvents.Example.csproj @@ -13,10 +13,4 @@ - - - - - - diff --git a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/EventGenerator.cs b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/EventGenerator.cs index e8d3af9..7949491 100644 --- a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/EventGenerator.cs +++ b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/EventGenerator.cs @@ -138,7 +138,7 @@ out List<(Location Location, INamedTypeSymbol NamedType)> staticNamespaceList) instanceNamespaceList = new List<(Location Location, INamedTypeSymbol NamedType)>(); staticNamespaceList = new List<(Location Location, INamedTypeSymbol NamedType)>(); - foreach (var invocation in receiver.InstanceCandidates) + foreach (var invocation in receiver.Events) { var semanticModel = compilation.GetSemanticModel(invocation.SyntaxTree); diff --git a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/ReactiveMarbles.ObservableEvents.SourceGenerator.csproj b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/ReactiveMarbles.ObservableEvents.SourceGenerator.csproj index 142bc60..d6689b5 100644 --- a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/ReactiveMarbles.ObservableEvents.SourceGenerator.csproj +++ b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/ReactiveMarbles.ObservableEvents.SourceGenerator.csproj @@ -7,6 +7,7 @@ true false $(NoWarn);AD0001 + true diff --git a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/SyntaxReceiver.cs b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/SyntaxReceiver.cs index 4617cb8..b38d6cc 100644 --- a/src/ReactiveMarbles.ObservableEvents.SourceGenerator/SyntaxReceiver.cs +++ b/src/ReactiveMarbles.ObservableEvents.SourceGenerator/SyntaxReceiver.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Linq.Expressions; using System.Text; using Microsoft.CodeAnalysis; @@ -15,13 +16,33 @@ namespace ReactiveMarbles.ObservableEvents.SourceGenerator { internal class SyntaxReceiver : ISyntaxReceiver { - public List InstanceCandidates { get; } = new List(); + public List Events { get; } = new List(); public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - if (syntaxNode is InvocationExpressionSyntax invocation) + if (syntaxNode is not InvocationExpressionSyntax invocationExpression) { - InstanceCandidates.Add(invocation); + return; + } + + switch (invocationExpression.Expression) + { + case MemberAccessExpressionSyntax memberAccess: + HandleSimpleName(memberAccess.Name, invocationExpression); + break; + case MemberBindingExpressionSyntax bindingAccess: + HandleSimpleName(bindingAccess.Name, invocationExpression); + break; + } + } + + private void HandleSimpleName(SimpleNameSyntax simpleName, InvocationExpressionSyntax invocationExpression) + { + var methodName = simpleName.Identifier.Text; + + if (string.Equals(methodName, nameof(Events))) + { + Events.Add(invocationExpression); } } } diff --git a/src/ReactiveMarbles.ObservableEvents.Tests/ReactiveMarbles.ObservableEvents.Tests.csproj b/src/ReactiveMarbles.ObservableEvents.Tests/ReactiveMarbles.ObservableEvents.Tests.csproj index f1e85b9..95a13ad 100644 --- a/src/ReactiveMarbles.ObservableEvents.Tests/ReactiveMarbles.ObservableEvents.Tests.csproj +++ b/src/ReactiveMarbles.ObservableEvents.Tests/ReactiveMarbles.ObservableEvents.Tests.csproj @@ -22,10 +22,10 @@ + - diff --git a/src/ReactiveMarbles.ObservableEvents.sln b/src/ReactiveMarbles.ObservableEvents.sln index afd74f6..027459e 100644 --- a/src/ReactiveMarbles.ObservableEvents.sln +++ b/src/ReactiveMarbles.ObservableEvents.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30503.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31612.314 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveMarbles.ObservableEvents.Example", "ReactiveMarbles.ObservableEvents.Example\ReactiveMarbles.ObservableEvents.Example.csproj", "{2AF6CBC6-6EE4-4C99-B769-2A777DE6ADFC}" EndProject @@ -23,8 +23,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TesterConsoleApp", "TesterC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveMarbles.ObservableEvents.Tests", "ReactiveMarbles.ObservableEvents.Tests\ReactiveMarbles.ObservableEvents.Tests.csproj", "{F5EC30AD-DC77-4985-9649-E6C2FA97DD5A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveMarbles.NuGet.Helpers", "ReactiveMarbles.NuGet.Helpers\ReactiveMarbles.NuGet.Helpers.csproj", "{8898C386-7835-487A-BAF1-07FCAC27ADF5}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,10 +45,6 @@ Global {F5EC30AD-DC77-4985-9649-E6C2FA97DD5A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F5EC30AD-DC77-4985-9649-E6C2FA97DD5A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F5EC30AD-DC77-4985-9649-E6C2FA97DD5A}.Release|Any CPU.Build.0 = Release|Any CPU - {8898C386-7835-487A-BAF1-07FCAC27ADF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8898C386-7835-487A-BAF1-07FCAC27ADF5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8898C386-7835-487A-BAF1-07FCAC27ADF5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8898C386-7835-487A-BAF1-07FCAC27ADF5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE