├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vsts-ci-steps.yml ├── .vsts-ci.yml ├── LICENSE ├── README.md ├── docfx ├── api │ ├── .gitignore │ └── index.md ├── articles │ ├── toc.yml │ └── traversal-projects-with-solutions.md ├── docfx.json ├── filterConfig.yml ├── index.md └── toc.yml ├── docs ├── api │ ├── Xamarin.BuildConsolidator.ILRepack.html │ ├── Xamarin.BuildConsolidator.PackageConsolidator.html │ ├── Xamarin.BuildConsolidator.html │ ├── Xamarin.Downloader.Download.html │ ├── Xamarin.Downloader.DownloadClient.DefaultOptions.html │ ├── Xamarin.Downloader.DownloadClient.html │ ├── Xamarin.Downloader.DownloadClientDelegate.html │ ├── Xamarin.Downloader.DownloadStatus.html │ ├── Xamarin.Downloader.html │ ├── Xamarin.FileHelpers.html │ ├── Xamarin.GuidHelpers.GuidNamespace.html │ ├── Xamarin.GuidHelpers.html │ ├── Xamarin.HashHelpers.html │ ├── Xamarin.Linq.LinqExtensions.html │ ├── Xamarin.Linq.html │ ├── Xamarin.MSBuild.Sdk.DependencyGraph.ProjectCollectionFactory.html │ ├── Xamarin.MSBuild.Sdk.DependencyGraph.html │ ├── Xamarin.MSBuild.Sdk.DependencyGraphVisualizationKind.html │ ├── Xamarin.MSBuild.Sdk.IDependencyNode.html │ ├── Xamarin.MSBuild.Sdk.MSBuildLocator.html │ ├── Xamarin.MSBuild.Sdk.ProjectDependencyNode.html │ ├── Xamarin.MSBuild.Sdk.Solution.ConfigurationPlatform.html │ ├── Xamarin.MSBuild.Sdk.Solution.SolutionBuilder.html │ ├── Xamarin.MSBuild.Sdk.Solution.SolutionConfigurationPlatformMap.html │ ├── Xamarin.MSBuild.Sdk.Solution.html │ ├── Xamarin.MSBuild.Sdk.Tasks.GenerateSolution.html │ ├── Xamarin.MSBuild.Sdk.Tasks.html │ ├── Xamarin.MSBuild.Sdk.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFArray.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFArrayBase.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFBoolean.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFMutableArray.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFNumber.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFNumberType.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFObject.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFRange.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFString.html │ ├── Xamarin.NativeHelpers.CoreFoundation.CFTypeID.html │ ├── Xamarin.NativeHelpers.CoreFoundation.html │ ├── Xamarin.NativeHelpers.Dlfcn.html │ ├── Xamarin.NativeHelpers.html │ ├── Xamarin.PathHelpers.Git.html │ ├── Xamarin.PathHelpers.Glob.html │ ├── Xamarin.PathHelpers.html │ ├── Xamarin.Preferences.MacUserDefaultsPreferenceStore.html │ ├── Xamarin.Preferences.MemoryOnlyPreferenceStore.html │ ├── Xamarin.Preferences.Preference-1.html │ ├── Xamarin.Preferences.PreferenceChangedEventArgs.html │ ├── Xamarin.Preferences.PreferenceStore.html │ ├── Xamarin.Preferences.PreferenceStoreConfiguration.html │ ├── Xamarin.Preferences.PreferenceTypeConverter-1.html │ ├── Xamarin.Preferences.RegistryPreferenceStore.html │ ├── Xamarin.Preferences.html │ ├── Xamarin.ProcessControl.ConsoleRedirection.FileDescriptor.html │ ├── Xamarin.ProcessControl.ConsoleRedirection.Segment.html │ ├── Xamarin.ProcessControl.ConsoleRedirection.SegmentCollection.html │ ├── Xamarin.ProcessControl.ConsoleRedirection.html │ ├── Xamarin.ProcessControl.Exec.ExitException.html │ ├── Xamarin.ProcessControl.Exec.ProcessRunnerHandler.html │ ├── Xamarin.ProcessControl.Exec.html │ ├── Xamarin.ProcessControl.ExecFlags.html │ ├── Xamarin.ProcessControl.ExecStatus.html │ ├── Xamarin.ProcessControl.ExecStatusEventArgs.html │ ├── Xamarin.ProcessControl.ProcessArguments.html │ ├── Xamarin.ProcessControl.html │ ├── Xamarin.Security.Keychain.html │ ├── Xamarin.Security.KeychainException.html │ ├── Xamarin.Security.KeychainItemAlreadyExistsException.html │ ├── Xamarin.Security.KeychainSecret.html │ ├── Xamarin.Security.KeychainSecretName.html │ ├── Xamarin.Security.Keychains.AppleKeychain.html │ ├── Xamarin.Security.Keychains.DPAPIKeychain.html │ ├── Xamarin.Security.Keychains.FileSystemKeychain.html │ ├── Xamarin.Security.Keychains.IKeychain.html │ ├── Xamarin.Security.Keychains.IKeychainExtensions.html │ ├── Xamarin.Security.Keychains.ManagedProtectionKeychain.html │ ├── Xamarin.Security.Keychains.OSKeychain.html │ ├── Xamarin.Security.Keychains.html │ ├── Xamarin.Security.html │ ├── Xamarin.html │ ├── Xunit.GB18030TestData.html │ ├── Xunit.GB18030TestDataWithNullAndEmpty.html │ ├── Xunit.LinuxFactAttribute.html │ ├── Xunit.LinuxTheoryAttribute.html │ ├── Xunit.MacFactAttribute.html │ ├── Xunit.MacTheoryAttribute.html │ ├── Xunit.OSFactAttribute.html │ ├── Xunit.OSTheoryAttribute.html │ ├── Xunit.UnixFactAttribute.html │ ├── Xunit.UnixTheoryAttribute.html │ ├── Xunit.WindowsFactAttribute.html │ ├── Xunit.WindowsMacFactAttribute.html │ ├── Xunit.WindowsMacTheoryAttribute.html │ ├── Xunit.WindowsTheoryAttribute.html │ ├── Xunit.html │ ├── index.html │ └── toc.html ├── articles │ ├── toc.html │ └── traversal-projects-with-solutions.html ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── index.html ├── logo.svg ├── manifest.json ├── search-stopwords.json ├── styles │ ├── docfx.css │ ├── docfx.js │ ├── docfx.vendor.css │ ├── docfx.vendor.js │ ├── lunr.js │ ├── lunr.min.js │ ├── main.css │ ├── main.js │ └── search-worker.js ├── toc.html └── xrefmap.yml ├── global.json ├── mirepoix.proj ├── mirepoix.sln ├── msbuild.rsp ├── src ├── CI.props ├── Directory.Build.props ├── Directory.Build.targets ├── Version.props ├── Version.targets ├── Xamarin.BuildConsolidator.Tests │ ├── FakeTest.cs │ └── Xamarin.BuildConsolidator.Tests.csproj ├── Xamarin.BuildConsolidator │ ├── FrameworkReferenceAssemblyComparer.cs │ ├── ILRepack.cs │ ├── ILRepackMSBuildLogger.cs │ ├── NuGetLocalRepoHelper.cs │ ├── PackageConsolidator.cs │ ├── PackageConsolidatorTask.cs │ ├── Xamarin.BuildConsolidator.csproj │ ├── Xamarin.BuildConsolidator.targets │ └── build │ │ ├── Xamarin.BuildConsolidator.props │ │ └── Xamarin.BuildConsolidator.targets ├── Xamarin.Cecil.Rocks.Tests │ ├── MetadataVisitorTests.cs │ └── Xamarin.Cecil.Rocks.Tests.csproj ├── Xamarin.Cecil.Rocks │ ├── AssemblyCollection.cs │ ├── MetadataVisitor.cs │ ├── MetadataVisitorAcceptors.cs │ └── Xamarin.Cecil.Rocks.csproj ├── Xamarin.Downloader.Tests │ ├── DownloadClientTests.cs │ └── Xamarin.Downloader.Tests.csproj ├── Xamarin.Downloader │ ├── Download.cs │ ├── DownloadClient.cs │ ├── DownloadClientDelegate.cs │ ├── DownloadStatus.cs │ └── Xamarin.Downloader.csproj ├── Xamarin.Helpers.Tests │ ├── FileHelperTests.cs │ ├── GuidHelperTests.cs │ ├── LinqExtensionsTests.cs │ └── Xamarin.Helpers.Tests.csproj ├── Xamarin.Helpers │ ├── FileHelpers.cs │ ├── GuidHelpers.cs │ ├── HashHelpers.cs │ ├── LinqExtensions.cs │ ├── PathHelpers.cs │ ├── PathHelpers_Glob.cs │ └── Xamarin.Helpers.csproj ├── Xamarin.MSBuild.Sdk.Tests │ ├── DependencyGraphTests.cs │ ├── MSBuildTestBase.cs │ ├── SolutionBuilderTests.cs │ ├── Solutions │ │ ├── .gitignore │ │ ├── DisabledProjectsInConfig.proj │ │ ├── DisabledProjectsInConfig.sln │ │ ├── FallbackToXmlForProjectGuid.proj │ │ ├── FallbackToXmlForProjectGuid.sln │ │ ├── Folders.proj │ │ ├── Folders.sln │ │ ├── NotReallyASharedProjectImportsProjitems.proj │ │ ├── NotReallyASharedProjectImportsProjitems.sln │ │ ├── OmitProjectFromSolution.proj │ │ ├── OmitProjectFromSolution.sln │ │ ├── Projects │ │ │ ├── A.csproj │ │ │ ├── B.csproj │ │ │ ├── C.csproj │ │ │ ├── FallbackToXmlForProjectGuid.csproj │ │ │ └── InvalidSdk.csproj │ │ ├── SharedProject │ │ │ ├── LibraryProject │ │ │ │ ├── LibraryProject.csproj │ │ │ │ └── LibraryProjectClass.cs │ │ │ ├── NotReallyASharedProjectImportsProjitems │ │ │ │ ├── NotASharedProject.csproj │ │ │ │ └── NotASharedProject.projitems │ │ │ └── SharedProject │ │ │ │ ├── SharedProject.projitems │ │ │ │ ├── SharedProject.shproj │ │ │ │ └── SharedProjectClass.cs │ │ ├── SharedProjectViaExplicitShprojReference.proj │ │ ├── SharedProjectViaExplicitShprojReference.sln │ │ ├── SharedProjectViaTransitiveProjitemsReference.proj │ │ ├── SharedProjectViaTransitiveProjitemsReference.sln │ │ ├── UnsupportedProjectDependency.proj │ │ └── UnsupportedProjectDependency.sln │ └── Xamarin.MSBuild.Sdk.Tests.csproj ├── Xamarin.MSBuild.Sdk │ ├── ConditionParser.cs │ ├── DependencyGraph.cs │ ├── DependencyGraphVisualizationKind.cs │ ├── IDependencyNode.cs │ ├── MSBuildLocator.cs │ ├── ProjectDependencyNode.cs │ ├── Resources │ │ └── VisJsTemplate.html │ ├── Sdk.props │ ├── Sdk.targets │ ├── Solution │ │ ├── ConfigurationPlatform.cs │ │ ├── SlnFile.cs │ │ ├── SolutionBuilder.cs │ │ ├── SolutionConfigurationPlatformMap.cs │ │ ├── SolutionNode.cs │ │ └── SolutionWriter.cs │ ├── Tasks │ │ ├── GenerateSolution.cs │ │ └── PrepareConsolidationProject.cs │ ├── VisJsGenerator.cs │ └── Xamarin.MSBuild.Sdk.csproj ├── Xamarin.Mac.Sdk │ ├── Sdk.props │ ├── Sdk.targets │ └── Xamarin.Mac.Sdk.csproj ├── Xamarin.NativeHelpers.Tests │ ├── CoreFoundationTests.cs │ └── Xamarin.NativeHelpers.Tests.csproj ├── Xamarin.NativeHelpers │ ├── CoreFoundation.cs │ ├── Dlfcn.cs │ └── Xamarin.NativeHelpers.csproj ├── Xamarin.Preferences.Tests │ ├── PreferenceTests.cs │ ├── Rect.cs │ └── Xamarin.Preferences.Tests.csproj ├── Xamarin.Preferences │ ├── AssemblyInfo.cs │ ├── Converters │ │ ├── PreferenceDateTimeConverter.cs │ │ └── PreferenceDateTimeOffsetConverter.cs │ ├── MacUserDefaultsPreferenceStore.cs │ ├── MemoryOnlyPreferenceStore.cs │ ├── Preference.cs │ ├── PreferenceChangedEventArgs.cs │ ├── PreferenceStore.cs │ ├── PreferenceStoreConfiguration.cs │ ├── PreferenceTypeConverter.cs │ ├── RegistryPreferenceStore.cs │ └── Xamarin.Preferences.csproj ├── Xamarin.ProcessControl.Tests │ ├── ExecTests.cs │ ├── ProcessArguments.cs │ └── Xamarin.ProcessControl.Tests.csproj ├── Xamarin.ProcessControl │ ├── ConsoleRedirection.cs │ ├── Exec.cs │ ├── ExecFlags.cs │ ├── ExecStatus.cs │ ├── ProcessArguments.cs │ └── Xamarin.ProcessControl.csproj ├── Xamarin.PropertyListDeserializer │ ├── PropertyListDeserializer.cs │ └── Xamarin.PropertyListDeserializer.csproj ├── Xamarin.Security.Keychain.Tests │ ├── KeychainSecretNameTests.cs │ ├── KeychainSecretTests.cs │ ├── KeychainTests.cs │ └── Xamarin.Security.Keychain.Tests.csproj ├── Xamarin.Security.Keychain │ ├── Assert.cs │ ├── Keychain.cs │ ├── KeychainExceptions.cs │ ├── KeychainSecret.cs │ ├── KeychainSecretName.cs │ ├── Keychains │ │ ├── AppleKeychain.cs │ │ ├── DPAPIKeychain.cs │ │ ├── FileSystemKeychain.cs │ │ ├── IKeychain.cs │ │ ├── ManagedProtectionKeychain.cs │ │ └── OSKeychain.cs │ ├── Mono.Security.Cryptography │ │ ├── Locale.cs │ │ └── ManagedProtection.cs │ └── Xamarin.Security.Keychain.csproj └── Xamarin.XunitHelpers │ ├── GB18030TestData.cs │ ├── OSFactAttribute.cs │ ├── OSTheoryAttribute.cs │ └── Xamarin.XunitHelpers.csproj └── tools └── ILRepackPatcher ├── ILRepackPatcher.cs └── ILRepackPatcher.csproj /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Don't use tabs for indentation. 7 | [*] 8 | indent_style = space 9 | end_of_line = lf 10 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 11 | 12 | # Code files 13 | [*.{cs,csx,vb,vbx}] 14 | indent_size = 4 15 | 16 | # Xml project files 17 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 18 | indent_size = 2 19 | 20 | # Xml config files 21 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 22 | indent_size = 2 23 | 24 | # Web files 25 | [*.{json,ts,js,html}] 26 | indent_size = 2 27 | 28 | # Dotnet code style settings: 29 | [*.{cs,vb}] 30 | # Sort using and Import directives with System.* appearing first 31 | dotnet_sort_system_directives_first = true 32 | # Avoid "this." and "Me." if not necessary 33 | dotnet_style_qualification_for_field = false:suggestion 34 | dotnet_style_qualification_for_property = false:suggestion 35 | dotnet_style_qualification_for_method = false:suggestion 36 | dotnet_style_qualification_for_event = false:suggestion 37 | 38 | # Use language keywords instead of framework type names for type references 39 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 40 | dotnet_style_predefined_type_for_member_access = true:suggestion 41 | 42 | # Suggest more modern language features when available 43 | dotnet_style_object_initializer = true:suggestion 44 | dotnet_style_collection_initializer = true:suggestion 45 | dotnet_style_coalesce_expression = true:suggestion 46 | dotnet_style_null_propagation = true:suggestion 47 | dotnet_style_explicit_tuple_names = false:suggestion 48 | 49 | # CSharp code style settings: 50 | [*.cs] 51 | # Prefer "var" everywhere 52 | csharp_style_var_for_built_in_types = true:suggestion 53 | csharp_style_var_when_type_is_apparent = true:suggestion 54 | csharp_style_var_elsewhere = true:suggestion 55 | 56 | # Prefer method-like constructs to have a block body 57 | csharp_style_expression_bodied_methods = true:none 58 | csharp_style_expression_bodied_constructors = false:none 59 | csharp_style_expression_bodied_operators = false:none 60 | 61 | # Prefer property-like constructs to have an expression-body 62 | csharp_style_expression_bodied_properties = true:none 63 | csharp_style_expression_bodied_indexers = true:none 64 | csharp_style_expression_bodied_accessors = true:none 65 | 66 | # Suggest more modern language features when available 67 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 68 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 69 | csharp_style_inlined_variable_declaration = true:suggestion 70 | csharp_style_throw_expression = true:suggestion 71 | csharp_style_conditional_delegate_call = true:suggestion 72 | 73 | # Newline settings 74 | csharp_new_line_before_open_brace = methods,types 75 | csharp_new_line_before_else = false 76 | csharp_new_line_before_catch = false 77 | csharp_new_line_before_finally = false 78 | csharp_new_line_before_members_in_object_initializers = true 79 | csharp_new_line_before_members_in_anonymous_types = true 80 | 81 | # Indentation preferences 82 | csharp_indent_block_contents = true 83 | csharp_indent_braces = false 84 | csharp_indent_case_contents = true 85 | csharp_indent_switch_labels = false 86 | csharp_indent_labels = flush_left 87 | 88 | # Space preferences 89 | csharp_space_after_cast = false 90 | csharp_space_after_colon_in_inheritance_clause = true 91 | csharp_space_after_comma = true 92 | csharp_space_after_dot = false 93 | csharp_space_after_keywords_in_control_flow_statements = true 94 | csharp_space_after_semicolon_in_for_statement = true 95 | csharp_space_around_binary_operators = before_and_after 96 | csharp_space_around_declaration_statements = do_not_ignore 97 | csharp_space_before_colon_in_inheritance_clause = true 98 | csharp_space_before_comma = false 99 | csharp_space_before_dot = false 100 | csharp_space_before_open_square_brackets = true 101 | csharp_space_before_semicolon_in_for_statement = false 102 | csharp_space_between_empty_square_brackets = false 103 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 104 | csharp_space_between_method_call_name_and_opening_parenthesis = true 105 | csharp_space_between_method_call_parameter_list_parentheses = false 106 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 107 | csharp_space_between_method_declaration_name_and_open_parenthesis = true 108 | csharp_space_between_method_declaration_parameter_list_parentheses = false 109 | csharp_space_between_square_brackets = false 110 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Setup .NET 20 | uses: actions/setup-dotnet@v1 21 | 22 | - name: Restore dependencies 23 | run: dotnet restore /v:n /bl:_artifacts/restore.binlog 24 | 25 | - name: Build 26 | run: dotnet build --no-restore /v:n /bl:_artifacts/build.binlog 27 | 28 | - name: Test 29 | run: for proj in `find . -name *.Tests.csproj`; do dotnet test $proj --no-restore --no-build; done 30 | 31 | - name: Pack 32 | run: dotnet pack --no-restore --no-build /v:n /bl:_artifacts/pack.binlog 33 | 34 | - uses: actions/upload-artifact@v2.2.4 35 | with: 36 | path: _artifacts/**/* 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | _artifacts/ 4 | 5 | /.vscode/launch.json 6 | /.vscode/tasks.json 7 | /.vs/ 8 | -------------------------------------------------------------------------------- /.vsts-ci-steps.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - task: DotNetCoreInstaller@0 3 | inputs: 4 | version: 2.1.500 5 | displayName: Install .NET Core 6 | 7 | # This script runs both via bash (macOS/Linux) and cmd (Windows). 8 | # Keep it both valid bash and batch or break it out conditionally. 9 | - script: | 10 | echo System Environment 11 | set 12 | echo .NET Core Info 13 | dotnet --info 14 | displayName: Dump Environment 15 | 16 | - script: | 17 | dotnet msbuild /noautoresponse /t:Restore /v:n /bl:_artifacts/restore.binlog mirepoix.proj 18 | displayName: Restore 19 | 20 | - script: | 21 | dotnet msbuild /noautoresponse /t:Build /v:n /bl:_artifacts/build.binlog mirepoix.proj 22 | displayName: Build 23 | 24 | - task: DotNetCoreCLI@2 25 | inputs: 26 | command: test 27 | projects: '**/*.Tests.csproj' 28 | arguments: '--no-restore --no-build' 29 | displayName: Run xUnit Tests 30 | continueOnError: true -------------------------------------------------------------------------------- /.vsts-ci.yml: -------------------------------------------------------------------------------- 1 | resources: 2 | repositories: 3 | - repository: mirepoix 4 | type: github 5 | name: xamarin/mirepoix 6 | ref: refs/heads/master 7 | endpoint: GitHub-XamarinInteractive 8 | 9 | trigger: 10 | - master 11 | 12 | pr: 13 | - master 14 | 15 | jobs: 16 | - job: macOS 17 | pool: 18 | vmImage: 'macOS-10.14' 19 | steps: 20 | - template: .vsts-ci-steps.yml 21 | 22 | - job: Linux 23 | pool: 24 | vmImage: 'ubuntu-16.04' 25 | steps: 26 | - template: .vsts-ci-steps.yml 27 | 28 | - job: Windows 29 | pool: 30 | vmImage: 'vs2017-win2016' 31 | steps: 32 | - template: .vsts-ci-steps.yml 33 | 34 | - script: | 35 | dotnet msbuild /noautoresponse /t:Pack /p:BuildProjectReferences=false /p:NoBuild=true /v:m /bl:_artifacts/pack.binlog mirepoix.proj 36 | displayName: Pack Libraries 37 | 38 | - task: PublishBuildArtifacts@1 39 | inputs: 40 | ArtifactName: Artifacts 41 | PathtoPublish: _artifacts 42 | displayName: Publish Artifacts 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mirepoix 2 | 3 | [![Build Status](https://devdiv.visualstudio.com/DevDiv/_apis/build/status/Xamarin/Mirepoix)](https://devdiv.visualstudio.com/DevDiv/_build/latest?definitionId=9683) 4 | 5 | > A mirepoix (/mɪərˈpwɑː/ meer-PWAH) is a flavor base made from diced 6 | vegetables that are cooked, usually with butter or oil or other fat, 7 | for a long time on a low heat without color or browning. 8 | 9 | This project contains a handful of useful utility libraries for constructing 10 | applications. All libraries target .NET Standard 2.0, but may have 11 | platform-specific components. 12 | 13 | Most of the functionality in this project has been derived from various 14 | utility APIs within other projects within Xamarin, particularly 15 | [Xamarin Workbooks](https://github.com/Microsoft/workbooks). 16 | 17 | Please [browse the full documentation][docs] for more information on 18 | consuming Mirepoix libraries. 19 | 20 | ## Use 21 | 22 | _Mirepoix is currently distributed on [MyGet][myget] while it is still 23 | establishing itself. It will move to nuget.org eventually._ 24 | 25 | Add the feed to your project's `NuGet.config` to reference packages. 26 | 27 | ### NuGet.config 28 | 29 | ```xml 30 | 31 | 32 | 35 | 36 | 37 | ``` 38 | 39 | ## Hack 40 | 41 | [.NET Core 2.1][dotnetcore] is used to build, test, and package Mirepoix. 42 | 43 | ### Build all Projects 44 | 45 | ``` 46 | dotnet build 47 | ``` 48 | 49 | ### Package all NuGets 50 | 51 | ``` 52 | dotnet pack 53 | ``` 54 | 55 | ### Write 56 | 57 | * Open the root of the repository as a workspace in VS Code (`code .`) and 58 | ensure OmniSharp is using `mirepoix.sln` 59 | 60 | * Or open `mirepoix.sln` in Visual Studio or Visual Studio for Mac. 61 | 62 | ### Test 63 | 64 | It's best to simply run `dotnet xunit` at the root of the `src/*.Tests/` 65 | directory to run scoped tests for the library of interest. 66 | 67 | Unfortunately running `dotnet test` at the root of the repository fails 68 | on both Windows and macOS locally, even though VSTS is happy to do it. 69 | 70 | ### CI 71 | 72 | VSTS is used to produce official builds. See `.vsts-ci.yml`. 73 | 74 | # Contributing 75 | 76 | This project welcomes contributions and suggestions. Most contributions 77 | require you to agree to a Contributor License Agreement (CLA) declaring that 78 | you have the right to, and actually do, grant us the rights to use your 79 | contribution. For details, visit https://cla.microsoft.com. 80 | 81 | When you submit a pull request, a CLA-bot will automatically determine 82 | whether you need to provide a CLA and decorate the PR appropriately (e.g., 83 | label, comment). Simply follow the instructions provided by the bot. You will 84 | only need to do this once across all repos using our CLA. 85 | 86 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 87 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 88 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any 89 | additional questions or comments. 90 | 91 | [docs]: https://xamarin.github.io/mirepoix 92 | [myget]: https://www.myget.org/feed/index/mirepoix 93 | [dotnetcore]: https://www.microsoft.com/net/download -------------------------------------------------------------------------------- /docfx/api/.gitignore: -------------------------------------------------------------------------------- 1 | ############### 2 | # temp file # 3 | ############### 4 | *.yml 5 | .manifest 6 | -------------------------------------------------------------------------------- /docfx/api/index.md: -------------------------------------------------------------------------------- 1 | # PLACEHOLDER 2 | TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! 3 | -------------------------------------------------------------------------------- /docfx/articles/toc.yml: -------------------------------------------------------------------------------- 1 | - name: MSBuild Traversal Projects with Solution Generation 2 | href: traversal-projects-with-solutions.md 3 | -------------------------------------------------------------------------------- /docfx/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../src", 7 | "files": [ 8 | "Xamarin.Preferences/Xamarin.Preferences.csproj", 9 | "Xamarin.ProcessControl/Xamarin.ProcessControl.csproj", 10 | "Xamarin.Helpers/Xamarin.Helpers.csproj", 11 | "Xamarin.NativeHelpers/Xamarin.NativeHelpers.csproj", 12 | "Xamarin.Downloader/Xamarin.Downloader.csproj", 13 | "Xamarin.MSBuild.Sdk/Xamarin.MSBuild.Sdk.csproj", 14 | "Xamarin.XunitHelpers/Xamarin.XunitHelpers.csproj", 15 | "Xamarin.Security.Keychain/Xamarin.Security.Keychain.csproj", 16 | "Xamarin.BuildConsolidator/Xamarin.BuildConsolidator.csproj" 17 | ], 18 | "exclude": [] 19 | } 20 | ], 21 | "dest": "api", 22 | "filter": "filterConfig.yml", 23 | "disableGitFeatures": false, 24 | "disableDefaultFilter": false 25 | } 26 | ], 27 | "build": { 28 | "content": [ 29 | { 30 | "files": [ 31 | "api/**.yml", 32 | "api/index.md" 33 | ] 34 | }, 35 | { 36 | "files": [ 37 | "articles/**.md", 38 | "articles/**/toc.yml", 39 | "toc.yml", 40 | "*.md" 41 | ] 42 | } 43 | ], 44 | "resource": [ 45 | { 46 | "files": [ 47 | "images/**" 48 | ] 49 | } 50 | ], 51 | "overwrite": [ 52 | { 53 | "files": [ 54 | "apidoc/**.md" 55 | ], 56 | "exclude": [ 57 | "obj/**" 58 | ] 59 | } 60 | ], 61 | "dest": "../docs", 62 | "globalMetadataFiles": [], 63 | "fileMetadataFiles": [], 64 | "template": [ 65 | "default" 66 | ], 67 | "postProcessors": [], 68 | "markdownEngineName": "markdig", 69 | "noLangKeyword": false, 70 | "keepFileLink": false, 71 | "cleanupCacheHistory": false, 72 | "disableGitFeatures": false 73 | } 74 | } -------------------------------------------------------------------------------- /docfx/filterConfig.yml: -------------------------------------------------------------------------------- 1 | apiRules: 2 | - exclude: 3 | uidRegex: ^System\.Object$ 4 | type: Type 5 | - exclude: 6 | uidRegex: ^.*\.Tests$ 7 | type: Namespace -------------------------------------------------------------------------------- /docfx/index.md: -------------------------------------------------------------------------------- 1 | # This is the **HOMEPAGE**. 2 | Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. 3 | ## Quick Start Notes: 4 | 1. Add images to the *images* folder if the file is referencing an image. 5 | -------------------------------------------------------------------------------- /docfx/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Articles 2 | href: articles/ 3 | - name: API Documentation 4 | href: api/ 5 | homepage: api/index.md 6 | -------------------------------------------------------------------------------- /docs/articles/toc.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |
12 | 13 |
    14 |
  • 15 | MSBuild Traversal Projects with Solution Generation 16 |
  • 17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/favicon.ico -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | This is the HOMEPAGE. 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 | 27 |
28 |
29 |
30 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | 45 |
46 |
47 |
48 |
49 |
50 | 51 |
52 |
53 |
    54 |
  • 55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |

This is the HOMEPAGE.

64 | 65 |

Refer to Markdown for how to write markdown files.

66 |

Quick Start Notes:

67 |
    68 |
  1. Add images to the images folder if the file is referencing an image.
  2. 69 |
70 |
71 |
72 | 73 |
74 |
75 |
76 |
    77 |
  • 78 | Improve this Doc 79 |
  • 80 |
81 |
82 |
83 | 84 |
85 |
86 |
87 |
88 |
89 | 90 |
91 |
92 |
93 |
94 | 95 | Back to top 96 | 97 | 98 | Generated by DocFX 99 |
100 |
101 |
102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by Docfx 9 | 10 | 12 | 15 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/search-stopwords.json: -------------------------------------------------------------------------------- 1 | [ 2 | "a", 3 | "able", 4 | "about", 5 | "across", 6 | "after", 7 | "all", 8 | "almost", 9 | "also", 10 | "am", 11 | "among", 12 | "an", 13 | "and", 14 | "any", 15 | "are", 16 | "as", 17 | "at", 18 | "be", 19 | "because", 20 | "been", 21 | "but", 22 | "by", 23 | "can", 24 | "cannot", 25 | "could", 26 | "dear", 27 | "did", 28 | "do", 29 | "does", 30 | "either", 31 | "else", 32 | "ever", 33 | "every", 34 | "for", 35 | "from", 36 | "get", 37 | "got", 38 | "had", 39 | "has", 40 | "have", 41 | "he", 42 | "her", 43 | "hers", 44 | "him", 45 | "his", 46 | "how", 47 | "however", 48 | "i", 49 | "if", 50 | "in", 51 | "into", 52 | "is", 53 | "it", 54 | "its", 55 | "just", 56 | "least", 57 | "let", 58 | "like", 59 | "likely", 60 | "may", 61 | "me", 62 | "might", 63 | "most", 64 | "must", 65 | "my", 66 | "neither", 67 | "no", 68 | "nor", 69 | "not", 70 | "of", 71 | "off", 72 | "often", 73 | "on", 74 | "only", 75 | "or", 76 | "other", 77 | "our", 78 | "own", 79 | "rather", 80 | "said", 81 | "say", 82 | "says", 83 | "she", 84 | "should", 85 | "since", 86 | "so", 87 | "some", 88 | "than", 89 | "that", 90 | "the", 91 | "their", 92 | "them", 93 | "then", 94 | "there", 95 | "these", 96 | "they", 97 | "this", 98 | "tis", 99 | "to", 100 | "too", 101 | "twas", 102 | "us", 103 | "wants", 104 | "was", 105 | "we", 106 | "were", 107 | "what", 108 | "when", 109 | "where", 110 | "which", 111 | "while", 112 | "who", 113 | "whom", 114 | "why", 115 | "will", 116 | "with", 117 | "would", 118 | "yet", 119 | "you", 120 | "your" 121 | ] 122 | -------------------------------------------------------------------------------- /docs/styles/main.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarin/mirepoix/265820cc5786c571bb47cf594c55ce1da31ddc71/docs/styles/main.css -------------------------------------------------------------------------------- /docs/styles/main.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information. 2 | -------------------------------------------------------------------------------- /docs/styles/search-worker.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | importScripts('lunr.min.js'); 3 | 4 | var lunrIndex; 5 | 6 | var stopWords = null; 7 | var searchData = {}; 8 | 9 | lunr.tokenizer.seperator = /[\s\-\.]+/; 10 | 11 | var stopWordsRequest = new XMLHttpRequest(); 12 | stopWordsRequest.open('GET', '../search-stopwords.json'); 13 | stopWordsRequest.onload = function () { 14 | if (this.status != 200) { 15 | return; 16 | } 17 | stopWords = JSON.parse(this.responseText); 18 | buildIndex(); 19 | } 20 | stopWordsRequest.send(); 21 | 22 | var searchDataRequest = new XMLHttpRequest(); 23 | 24 | searchDataRequest.open('GET', '../index.json'); 25 | searchDataRequest.onload = function () { 26 | if (this.status != 200) { 27 | return; 28 | } 29 | searchData = JSON.parse(this.responseText); 30 | 31 | buildIndex(); 32 | 33 | postMessage({ e: 'index-ready' }); 34 | } 35 | searchDataRequest.send(); 36 | 37 | onmessage = function (oEvent) { 38 | var q = oEvent.data.q; 39 | var hits = lunrIndex.search(q); 40 | var results = []; 41 | hits.forEach(function (hit) { 42 | var item = searchData[hit.ref]; 43 | results.push({ 'href': item.href, 'title': item.title, 'keywords': item.keywords }); 44 | }); 45 | postMessage({ e: 'query-ready', q: q, d: results }); 46 | } 47 | 48 | function buildIndex() { 49 | if (stopWords !== null && !isEmpty(searchData)) { 50 | lunrIndex = lunr(function () { 51 | this.pipeline.remove(lunr.stopWordFilter); 52 | this.ref('href'); 53 | this.field('title', { boost: 50 }); 54 | this.field('keywords', { boost: 20 }); 55 | 56 | for (var prop in searchData) { 57 | if (searchData.hasOwnProperty(prop)) { 58 | this.add(searchData[prop]); 59 | } 60 | } 61 | 62 | var docfxStopWordFilter = lunr.generateStopWordFilter(stopWords); 63 | lunr.Pipeline.registerFunction(docfxStopWordFilter, 'docfxStopWordFilter'); 64 | this.pipeline.add(docfxStopWordFilter); 65 | this.searchPipeline.add(docfxStopWordFilter); 66 | }); 67 | } 68 | } 69 | 70 | function isEmpty(obj) { 71 | if(!obj) return true; 72 | 73 | for (var prop in obj) { 74 | if (obj.hasOwnProperty(prop)) 75 | return false; 76 | } 77 | 78 | return true; 79 | } 80 | })(); 81 | -------------------------------------------------------------------------------- /docs/toc.html: -------------------------------------------------------------------------------- 1 |  2 |
3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |
12 | 13 |
    14 |
  • 15 | Articles 16 |
  • 17 |
  • 18 | API Documentation 19 |
  • 20 |
21 |
22 |
23 |
24 |
-------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.1.505" 4 | }, 5 | "msbuild-sdks": { 6 | "Microsoft.Build.Traversal": "1.0.45" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /mirepoix.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | $([MSBuild]::NormalizePath('docfx\docfx.json')) 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /msbuild.rsp: -------------------------------------------------------------------------------- 1 | mirepoix.proj /v:m 2 | -------------------------------------------------------------------------------- /src/CI.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | true 5 | 6 | false 7 | true 8 | 9 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | latest 7 | true 8 | true 9 | true 10 | 11 | 12 | 13 | Microsoft 14 | © Microsoft Corporation. All rights reserved. 15 | https://github.com/xamarin/mirepoix 16 | https://xamarin.github.io/mirepoix 17 | MIT 18 | https://www.xamarin.com/content/images/nuget/xamarin.png 19 | $([MSBuild]::NormalizePath($(MSBuildThisFileDirectory)..\_artifacts\)) 20 | true 21 | 22 | 23 | 24 | false 25 | true 26 | 27 | 28 | 29 | netcoreapp2.1 30 | false 31 | xUnit1026 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | all 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/Version.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | true 5 | high 6 | 7 | 8 | 9 | SetVersions;$(GenerateNuspecDependsOn) 10 | SetVersions;$(GetPackageVersionDependsOn) 11 | 12 | -------------------------------------------------------------------------------- /src/Version.targets: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | $(SYSTEM_PULLREQUEST_TARGETBRANCH) 10 | $(BUILD_SOURCEBRANCHNAME) 11 | $(APPVEYOR_REPO_BRANCH) 12 | 13 | 14 | 15 | 18 | 19 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | @(VersionMetadata -> '%(Identity)', '-') 32 | +$(VersionMetadataLabel) 33 | $(GitBaseVersionMajor).$(GitBaseVersionMinor).$(GitBaseVersionPatch)$(GitSemVerDashLabel) 34 | $(PackageVersion)$(VersionMetadataPlusLabel) 35 | 36 | 37 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator.Tests/FakeTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | public class FakeTest 4 | { 5 | [Fact] 6 | public void Nop () 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator.Tests/Xamarin.BuildConsolidator.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Xamarin.Mirepoix 4 | $(MSBuildThisFileDirectory)..\Xamarin.BuildConsolidator\ 5 | $(XamarinBuildConsolidatorProjectPath)\bin\Debug\netstandard2.0\Xamarin.BuildConsolidator.dll 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | A consolidated package containing @(PackageIdsToConsolidate -> '%(Identity)', ', ') in a single $(PackageId).dll assembly. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/FrameworkReferenceAssemblyComparer.cs: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Author: 4 | // Aaron Bockover 5 | // 6 | // Copyright (c) Microsoft Corporation. All rights reserved. 7 | // Licensed under the MIT License. 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | 13 | using NuGet.Packaging; 14 | 15 | namespace Xamarin.BuildConsolidator 16 | { 17 | sealed class FrameworkAssemblyReferenceComparer : IEqualityComparer 18 | { 19 | public bool Equals (FrameworkAssemblyReference x, FrameworkAssemblyReference y) 20 | { 21 | if (!string.Equals (x.AssemblyName, y.AssemblyName, StringComparison.OrdinalIgnoreCase)) 22 | return false; 23 | 24 | return x.SupportedFrameworks.SequenceEqual (y.SupportedFrameworks); 25 | } 26 | 27 | public int GetHashCode (FrameworkAssemblyReference obj) 28 | => 0; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/ILRepackMSBuildLogger.cs: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Author: 4 | // Aaron Bockover 5 | // 6 | // Copyright (c) Microsoft Corporation. All rights reserved. 7 | // Licensed under the MIT License. 8 | 9 | using System; 10 | 11 | using Microsoft.Build.Framework; 12 | using Microsoft.Build.Utilities; 13 | 14 | namespace Xamarin.BuildConsolidator 15 | { 16 | sealed class ILRepackMSBuildLogger : ILRepacking.ILogger 17 | { 18 | readonly TaskLoggingHelper log; 19 | 20 | public ILRepackMSBuildLogger (TaskLoggingHelper log) 21 | => this.log = log; 22 | 23 | bool ILRepacking.ILogger.ShouldLogVerbose { get; set; } 24 | 25 | void ILRepacking.ILogger.DuplicateIgnored (string ignoredType, object ignoredObject) 26 | => log.LogMessage ( 27 | MessageImportance.Low, 28 | "Ignoring duplicate {0} {1}", 29 | ignoredType, 30 | ignoredObject); 31 | 32 | void ILRepacking.ILogger.Log (object str) 33 | => log.LogMessage (MessageImportance.Normal, str.ToString ()); 34 | 35 | void ILRepacking.ILogger.Error (string msg) 36 | => log.LogError (msg); 37 | 38 | void ILRepacking.ILogger.Warn (string msg) 39 | { 40 | if (!msg.StartsWith ("Did not write source server data to output assembly.", StringComparison.OrdinalIgnoreCase)) 41 | log.LogWarning (msg); 42 | } 43 | 44 | void ILRepacking.ILogger.Info (string msg) 45 | => log.LogMessage (MessageImportance.Normal, msg); 46 | 47 | void ILRepacking.ILogger.Verbose (string msg) 48 | => log.LogMessage (MessageImportance.Low, msg); 49 | } 50 | } -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/NuGetLocalRepoHelper.cs: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Author: 4 | // Aaron Bockover 5 | // 6 | // Copyright (c) Microsoft Corporation. All rights reserved. 7 | // Licensed under the MIT License. 8 | 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IO; 12 | using System.Linq; 13 | 14 | using NuGet.Common; 15 | using NuGet.Frameworks; 16 | using NuGet.Repositories; 17 | using NuGet.Versioning; 18 | 19 | namespace Xamarin.BuildConsolidator 20 | { 21 | static class NuGetLocalRepoHelper 22 | { 23 | static readonly NuGetv3LocalRepository repo = new NuGetv3LocalRepository ( 24 | Path.Combine ( 25 | NuGetEnvironment.GetFolderPath (NuGetFolderPath.NuGetHome), 26 | "packages")); 27 | 28 | public static LocalPackageInfo GetPackage ( 29 | string id, 30 | VersionRange versionRange) 31 | { 32 | var packageCandidates = repo 33 | .FindPackagesById (id) 34 | .ToList (); 35 | 36 | if (packageCandidates.Count == 0) 37 | return null; 38 | 39 | var bestVersion = versionRange.FindBestMatch ( 40 | packageCandidates.Select (p => p.Version)); 41 | 42 | return packageCandidates.FirstOrDefault ( 43 | p => p.Version == bestVersion); 44 | } 45 | 46 | public static string GetPackageAssemblySearchPath ( 47 | string id, 48 | VersionRange versionRange, 49 | NuGetFramework framework) 50 | => GetPackageAssemblySearchPath ( 51 | GetPackage (id, versionRange), 52 | framework); 53 | 54 | public static string GetPackageAssemblySearchPath ( 55 | LocalPackageInfo packageInfo, 56 | NuGetFramework framework) 57 | { 58 | if (packageInfo == null) 59 | return null; 60 | 61 | if (framework == null) 62 | throw new ArgumentNullException (nameof (framework)); 63 | 64 | var possibleFrameworks = packageInfo.Files 65 | .Select (path => path.Split (new [] { '/', '\\' })) 66 | .Where (parts => string.Equals (parts [0], "lib", StringComparison.OrdinalIgnoreCase)) 67 | .Select (parts => NuGetFramework.ParseFolder (parts [1].ToLowerInvariant ())) 68 | .Distinct (); 69 | 70 | var bestFramework = new FrameworkReducer () 71 | .GetNearest (framework, possibleFrameworks); 72 | 73 | return Path.Combine ( 74 | packageInfo.ExpandedPath, 75 | "lib", 76 | bestFramework.GetShortFolderName ()); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/Xamarin.BuildConsolidator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Xamarin.BuildConsolidator.Unpacked 5 | Xamarin.BuildConsolidator 6 | false 7 | $(TargetsForTfmSpecificContentInPackage);GetPackageBuildFiles 8 | 9 | 10 | 11 | 12 | 13 | all 14 | 15 | 16 | 17 | all 18 | 19 | 20 | 21 | 22 | 23 | $(ILRepack) 24 | 25 | 26 | 27 | 28 | 29 | all 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/Xamarin.BuildConsolidator.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 26 | 27 | 33 | 34 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 50 | build 51 | 52 | 53 | build 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/build/Xamarin.BuildConsolidator.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | $(PackDependsOn);PackConsolidated 5 | $(GetPackageVersionDependsOn);GetPackagesToConsolidate 6 | 7 | -------------------------------------------------------------------------------- /src/Xamarin.BuildConsolidator/build/Xamarin.BuildConsolidator.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(MSBuildThisFileDirectory)Xamarin.BuildConsolidator.dll 4 | 5 | 6 | 9 | 10 | 13 | 14 | 17 | 37 | 38 | -------------------------------------------------------------------------------- /src/Xamarin.Cecil.Rocks.Tests/MetadataVisitorTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | using Xunit; 8 | 9 | using Mono.Cecil; 10 | 11 | namespace Xamarin.Cecil.Rocks 12 | { 13 | public class MetadataVisitorTests 14 | { 15 | static readonly AssemblyDefinition TestAssemblyDefinition = AssemblyDefinition.ReadAssembly ( 16 | typeof (MetadataVisitorTests).Assembly.Location); 17 | 18 | class TestVisitAssemblyDefinition : MetadataVisitor 19 | { 20 | int invocations; 21 | 22 | public override bool VisitAssemblyDefinition (AssemblyDefinition assemblyDefinition) 23 | { 24 | Assert.Equal (TestAssemblyDefinition, assemblyDefinition); 25 | Assert.Equal (1, ++invocations); 26 | return true; 27 | } 28 | } 29 | 30 | [Fact] 31 | public void VisitAssemblyDefinition () 32 | => TestAssemblyDefinition.AcceptVisitor (new TestVisitAssemblyDefinition ()); 33 | 34 | class TestVisitTypeDefinition : MetadataVisitor 35 | { 36 | class C { } 37 | class C { } 38 | class C { public class A { } } 39 | class C { public class A { } } 40 | enum E { } 41 | struct S { } 42 | 43 | public List ExpectedTypes { get; } = new List { 44 | typeof(ThisAssembly), 45 | typeof(ThisAssembly.Git), 46 | typeof(ThisAssembly.Git.BaseVersion), 47 | typeof(ThisAssembly.Git.SemVer), 48 | typeof(MetadataVisitorTests), 49 | typeof(TestVisitAssemblyDefinition), 50 | typeof(TestVisitTypeDefinition), 51 | typeof(C<>), 52 | typeof(C<,>), 53 | typeof(C<,,>), 54 | typeof(C<,,>.A), 55 | typeof(C<,,,>), 56 | typeof(C<,,,>.A<>), 57 | typeof(E), 58 | typeof(S) 59 | }; 60 | 61 | public override bool VisitTypeDefinition (TypeDefinition typeDefinition) 62 | { 63 | var fullName = typeDefinition.FullName.Replace ('/', '+'); 64 | switch (fullName) { 65 | case "": 66 | case "AutoGeneratedProgram": 67 | return true; 68 | } 69 | 70 | for (int i = ExpectedTypes.Count - 1; i >= 0; i--) { 71 | if (ExpectedTypes [i].FullName == fullName) { 72 | ExpectedTypes.RemoveAt (i); 73 | return true; 74 | } 75 | } 76 | 77 | throw new Exception ($"{typeDefinition} is unexpected"); 78 | } 79 | } 80 | 81 | [Fact] 82 | public void VisitTypeDefinition () 83 | { 84 | var visitor = new TestVisitTypeDefinition (); 85 | TestAssemblyDefinition.AcceptVisitor (visitor); 86 | Assert.Empty (visitor.ExpectedTypes); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/Xamarin.Cecil.Rocks.Tests/Xamarin.Cecil.Rocks.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.Cecil.Rocks/AssemblyCollection.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | 8 | using Mono.Cecil; 9 | 10 | namespace Xamarin.Cecil.Rocks 11 | { 12 | public class AssemblyCollection 13 | { 14 | readonly HashSet searchDirectories = new HashSet (); 15 | readonly List assemblyFileNames = new List (); 16 | 17 | public ReaderParameters ReaderParameters { get; } 18 | public BaseAssemblyResolver AssemblyResolver { get; } 19 | 20 | public AssemblyCollection (ReadingMode readingMode = ReadingMode.Immediate) : this ( 21 | new ReaderParameters (readingMode), 22 | new DefaultAssemblyResolver ()) 23 | { 24 | } 25 | 26 | public AssemblyCollection ( 27 | ReaderParameters readerParameters, 28 | BaseAssemblyResolver assemblyResolver) 29 | { 30 | ReaderParameters = readerParameters 31 | ?? throw new ArgumentNullException (nameof (readerParameters)); 32 | 33 | ReaderParameters.AssemblyResolver = assemblyResolver; 34 | ReaderParameters.MetadataResolver = new MetadataResolver (assemblyResolver); 35 | 36 | AssemblyResolver = assemblyResolver 37 | ?? throw new ArgumentNullException (nameof (assemblyResolver)); 38 | } 39 | 40 | public AssemblyCollection AddAssembly (string assemblyFileName) 41 | { 42 | assemblyFileName = Path.GetFullPath (assemblyFileName); 43 | 44 | var searchDirectory = Path.GetDirectoryName (assemblyFileName); 45 | if (searchDirectories.Add (searchDirectory)) 46 | AssemblyResolver.AddSearchDirectory (searchDirectory); 47 | 48 | if (!assemblyFileNames.Contains (assemblyFileName)) 49 | assemblyFileNames.Add (assemblyFileName); 50 | 51 | return this; 52 | } 53 | 54 | public AssemblyCollection AddAssemblies (IEnumerable assemblyFileNames) 55 | { 56 | foreach (var assemblyFileName in assemblyFileNames ?? Array.Empty ()) 57 | AddAssembly (assemblyFileName); 58 | 59 | return this; 60 | } 61 | 62 | public IEnumerable Load () 63 | { 64 | foreach (var assemblyFileName in assemblyFileNames) 65 | yield return AssemblyDefinition.ReadAssembly ( 66 | assemblyFileName, 67 | ReaderParameters); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/Xamarin.Cecil.Rocks/MetadataVisitor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Mono.Cecil; 5 | using Mono.Cecil.Cil; 6 | 7 | namespace Xamarin.Cecil.Rocks 8 | { 9 | public abstract class MetadataVisitor : MetadataVisitor 10 | { 11 | public override bool ShouldTraverseInto (bool visitResult) 12 | => visitResult; 13 | 14 | protected override bool VisitDefault (object any) 15 | => true; 16 | } 17 | 18 | public abstract class MetadataVisitor 19 | { 20 | public virtual bool ShouldTraverseInto (TResult visitResult) 21 | => true; 22 | 23 | protected virtual TResult VisitDefault (object any) 24 | => default; 25 | 26 | public virtual TResult VisitAssemblyDefinition ( 27 | AssemblyDefinition assemblyDefinition) 28 | => VisitDefault (assemblyDefinition); 29 | 30 | public virtual TResult VisitModuleReference ( 31 | ModuleReference moduleReference) 32 | => VisitDefault (moduleReference); 33 | 34 | public virtual TResult VisitModuleDefinition ( 35 | ModuleDefinition moduleDefinition) 36 | => VisitDefault (moduleDefinition); 37 | 38 | public virtual TResult VisitTypeReference ( 39 | TypeReference typeReference) 40 | => VisitDefault (typeReference); 41 | 42 | public virtual TResult VisitTypeDefinition ( 43 | TypeDefinition typeDefinition) 44 | => VisitDefault (typeDefinition); 45 | 46 | public virtual TResult VisitInterfaceImplementation ( 47 | InterfaceImplementation interfaceImplementation) 48 | => VisitDefault (interfaceImplementation); 49 | 50 | public virtual TResult VisitFieldReference ( 51 | FieldReference fieldReference) 52 | => VisitDefault (fieldReference); 53 | 54 | public virtual TResult VisitFieldDefinition ( 55 | FieldDefinition fieldDefinition) 56 | => VisitDefault (fieldDefinition); 57 | 58 | public virtual TResult VisitParameterDefinition ( 59 | ParameterDefinition parameterDefinition) 60 | => VisitDefault (parameterDefinition); 61 | 62 | public virtual TResult VisitMethodReference ( 63 | MethodReference methodReference) 64 | => VisitDefault (methodReference); 65 | 66 | public virtual TResult VisitMethodDefinition ( 67 | MethodDefinition methodDefinition) 68 | => VisitDefault (methodDefinition); 69 | 70 | public virtual TResult VisitMethodBody ( 71 | MethodBody methodBody) 72 | => VisitDefault (methodBody); 73 | 74 | public virtual TResult VisitInstruction ( 75 | Instruction instruction) 76 | => VisitDefault (instruction); 77 | 78 | public virtual TResult VisitPropertyReference ( 79 | PropertyReference propertyReference) 80 | => VisitDefault (propertyReference); 81 | 82 | public virtual TResult VisitPropertyDefinition ( 83 | PropertyDefinition propertyDefinition) 84 | => VisitDefault (propertyDefinition); 85 | 86 | public virtual TResult VisitEventReference ( 87 | EventReference eventReference) 88 | => VisitDefault (eventReference); 89 | 90 | public virtual TResult VisitEventDefinition ( 91 | EventDefinition eventDefinition) 92 | => VisitDefault (eventDefinition); 93 | 94 | public virtual TResult VisitGenericParameter ( 95 | GenericParameter genericParameter) 96 | => VisitDefault (genericParameter); 97 | 98 | public virtual TResult VisitCustomAttribute ( 99 | CustomAttribute customAttribute) 100 | => VisitDefault (customAttribute); 101 | 102 | public virtual TResult VisitCustomAttributeNamedArgument ( 103 | CustomAttributeNamedArgument customAttributeNamedArgument) 104 | => VisitDefault (customAttributeNamedArgument); 105 | 106 | public virtual TResult VisitCustomAttributeArgument ( 107 | CustomAttributeArgument customAttributeArgument) 108 | => VisitDefault (customAttributeArgument); 109 | } 110 | } -------------------------------------------------------------------------------- /src/Xamarin.Cecil.Rocks/Xamarin.Cecil.Rocks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Xamarin.Downloader.Tests/DownloadClientTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.IO; 10 | using System.Net; 11 | using System.Net.Http; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | 15 | using Xunit; 16 | 17 | using Xamarin.Downloader; 18 | 19 | namespace Xamarin.Downloader.Tests 20 | { 21 | public class DownloadClientTests 22 | { 23 | sealed class TestDownloadServer 24 | { 25 | readonly HttpListener httpListener; 26 | 27 | public string BaseUri { get; } = "http://localhost:8282/"; 28 | 29 | public TestDownloadServer () 30 | { 31 | var startWait = new ManualResetEvent (false); 32 | 33 | httpListener = new HttpListener (); 34 | httpListener.Prefixes.Add (BaseUri); 35 | httpListener.Start (); 36 | 37 | ThreadPool.QueueUserWorkItem (async o => { 38 | startWait.Set (); 39 | 40 | var buffer = new byte [512 * 1024 * 1024]; 41 | new Random ().NextBytes (buffer); 42 | 43 | try { 44 | while (true) { 45 | var context = await httpListener.GetContextAsync (); 46 | context.Response.StatusCode = 200; 47 | context.Response.ContentLength64 = buffer.Length; 48 | await context.Response.OutputStream.WriteAsync (buffer, 0, buffer.Length); 49 | await context.Response.OutputStream.FlushAsync (); 50 | context.Response.OutputStream.Close (); 51 | context.Response.Close (); 52 | } 53 | } catch { 54 | return; 55 | } 56 | }); 57 | 58 | startWait.WaitOne (); 59 | } 60 | } 61 | 62 | sealed class TestDownloadClientDelegate : DownloadClientDelegate 63 | { 64 | } 65 | 66 | readonly DownloadClient downloader = DownloadClient.Create ( 67 | outputDirectory: Path.Combine ( 68 | Path.GetTempPath (), 69 | "com.xamarin.mirepoix.tests", 70 | Guid.NewGuid ().ToString ())); 71 | 72 | [UnixFact (Skip = "HttpListener does not work reliably in test on Windows likely due to firewall")] 73 | public async Task DownloadBytesAsync () 74 | { 75 | var server = new TestDownloadServer (); 76 | await downloader.DownloadAsync (server.BaseUri); 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/Xamarin.Downloader.Tests/Xamarin.Downloader.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.Downloader/Download.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.IO; 11 | using System.Linq; 12 | 13 | namespace Xamarin.Downloader 14 | { 15 | public sealed class Download 16 | { 17 | public string RequestUri { get; } 18 | public IReadOnlyList<(string name, string value)> RequestHeaders { get; } 19 | public string OutputDirectory { get; } 20 | public string OutputFileName { get; } 21 | public string OutputFullPath { get; } 22 | internal string OutputIntermediateFullPath { get; } 23 | 24 | Download ( 25 | string requestUri, 26 | IReadOnlyList<(string name, string value)> requestHeaders, 27 | string outputDirectory, 28 | string outputFileName) 29 | { 30 | RequestUri = requestUri; 31 | RequestHeaders = requestHeaders; 32 | OutputDirectory = outputDirectory; 33 | OutputFileName = outputFileName; 34 | 35 | if (!string.IsNullOrEmpty (OutputDirectory) && 36 | !string.IsNullOrEmpty (OutputFileName)) { 37 | OutputFullPath = Path.Combine (OutputDirectory, OutputFileName); 38 | OutputIntermediateFullPath = OutputFullPath + ".downloading"; 39 | } 40 | } 41 | 42 | internal static Download Create ( 43 | string requestUri, 44 | IEnumerable<(string name, string value)> requestHeaders, 45 | string outputDirectory, 46 | string outputFileName) 47 | => new Download ( 48 | requestUri, 49 | requestHeaders?.ToArray () ?? Array.Empty<(string, string)> (), 50 | outputDirectory, 51 | outputFileName); 52 | 53 | internal Download WithRequestHeaders (IEnumerable<(string name, string value)> requestHeaders) 54 | => requestHeaders == RequestHeaders 55 | ? this 56 | : new Download ( 57 | RequestUri, 58 | requestHeaders?.ToArray () ?? Array.Empty<(string, string)> (), 59 | OutputDirectory, 60 | OutputFileName); 61 | 62 | internal Download WithOutputDirectory (string outputDirectory) 63 | => outputDirectory == OutputDirectory 64 | ? this 65 | : new Download ( 66 | RequestUri, 67 | RequestHeaders, 68 | outputDirectory, 69 | OutputFileName); 70 | 71 | internal Download WithOutputFileName (string outputFileName) 72 | => outputFileName == OutputFileName 73 | ? this 74 | : new Download ( 75 | RequestUri, 76 | RequestHeaders, 77 | OutputDirectory, 78 | outputFileName); 79 | } 80 | } -------------------------------------------------------------------------------- /src/Xamarin.Downloader/DownloadClientDelegate.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.IO; 10 | using System.Linq; 11 | using System.Net.Http; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | 15 | namespace Xamarin.Downloader 16 | { 17 | public class DownloadClientDelegate 18 | { 19 | internal static bool TryGetIntermediateFileSize (Download download, out long fileSize) 20 | { 21 | if (download.OutputIntermediateFullPath != null) { 22 | var downloadingFileInfo = new FileInfo (download.OutputIntermediateFullPath); 23 | if (downloadingFileInfo.Exists) { 24 | fileSize = downloadingFileInfo.Length; 25 | return true; 26 | } 27 | } 28 | 29 | fileSize = 0; 30 | return false; 31 | } 32 | 33 | internal protected virtual Download PrepareDownload ( 34 | DownloadClient downloadClient, 35 | Download download) 36 | { 37 | download = download.WithOutputDirectory ( 38 | download.OutputDirectory 39 | ?? downloadClient.OutputDirectory 40 | ?? Environment.CurrentDirectory); 41 | 42 | if (download.OutputFileName == null) { 43 | var fileName = Path.GetFileName (download.RequestUri); 44 | if (string.IsNullOrEmpty (fileName)) 45 | fileName = "UnknownDownload"; 46 | download = download.WithOutputFileName (fileName); 47 | } 48 | 49 | var rangeHeaders = Array.Empty<(string, string)> (); 50 | if (TryGetIntermediateFileSize (download, out var totalRead)) 51 | rangeHeaders = new [] { 52 | ("Range", $"bytes={totalRead}-"), 53 | ("x-ms-range", $"bytes={totalRead}-"), 54 | ("x-ms-version", "2011-08-18") 55 | }; 56 | 57 | download = download.WithRequestHeaders (downloadClient 58 | .RequestHeaders 59 | .Concat (download.RequestHeaders) 60 | .Concat (rangeHeaders)); 61 | 62 | return download; 63 | } 64 | 65 | internal protected virtual void NotifyDownloadAttemptFailed ( 66 | Download download, 67 | Exception exception, 68 | int attempt, 69 | int maxAttempts) 70 | { 71 | } 72 | 73 | internal protected virtual void NotifyDownloadStatus ( 74 | Download download, 75 | DownloadStatus status) 76 | { 77 | } 78 | 79 | internal protected virtual Task HandleHttpResponseMessageAsync ( 80 | Download download, 81 | HttpResponseMessage response, 82 | CancellationToken cancellationToken) 83 | => Task.CompletedTask; 84 | } 85 | } -------------------------------------------------------------------------------- /src/Xamarin.Downloader/DownloadStatus.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | namespace Xamarin.Downloader 11 | { 12 | /// 13 | /// Immutable record representing the status of a download at a point in time. 14 | /// 15 | public sealed class DownloadStatus 16 | { 17 | /// 18 | /// The total number of bytes expected to be downloaded. 19 | /// 20 | public long BytesExpected { get; } 21 | 22 | /// 23 | /// The total number of bytes already downloaded. 24 | /// 25 | public long BytesDownloaded { get; } 26 | 27 | /// 28 | /// The completion percentage of the download (0-1 inclusive). 29 | /// 30 | public float Progress { get; } 31 | 32 | /// 33 | /// The current rolling average speed of the download in bytes per second. 34 | /// 35 | public int BytesPerSecond { get; } 36 | 37 | /// 38 | /// The estimated time remaining to complete the download. 39 | /// 40 | public TimeSpan EstimatedTimeRemaining { get; } 41 | 42 | /// 43 | /// The amount of time taken to perform the download so far. If 44 | /// is 1 (completed), this value is the total amount of time the download took. 45 | /// 46 | public TimeSpan TimeElapsed { get; } 47 | 48 | /// 49 | /// When the download was started. 50 | /// 51 | public DateTimeOffset StartTime { get; } 52 | 53 | internal DownloadStatus ( 54 | long bytesExpected, 55 | long bytesDownloaded, 56 | float progress, 57 | int bytesPerSecond, 58 | TimeSpan estimatedTimeRemaining, 59 | DateTimeOffset startTime) 60 | { 61 | BytesExpected = bytesExpected; 62 | BytesDownloaded = bytesDownloaded; 63 | Progress = progress; 64 | BytesPerSecond = bytesPerSecond; 65 | EstimatedTimeRemaining = estimatedTimeRemaining; 66 | TimeElapsed = DateTimeOffset.UtcNow - startTime; 67 | StartTime = startTime; 68 | } 69 | 70 | internal DownloadStatus WithCompletion () 71 | => new DownloadStatus ( 72 | BytesExpected, 73 | BytesExpected, 74 | 1, 75 | 0, 76 | TimeSpan.Zero, 77 | StartTime); 78 | } 79 | } -------------------------------------------------------------------------------- /src/Xamarin.Downloader/Xamarin.Downloader.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Xamarin.Helpers.Tests/FileHelperTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | 8 | using Xunit; 9 | 10 | namespace Xamarin 11 | { 12 | public sealed class FileHelperTests 13 | { 14 | readonly Random random = new Random (); 15 | 16 | [Theory] 17 | [InlineData ("", null)] 18 | [InlineData ("Hello World", null)] 19 | [InlineData ("\n", "\n")] 20 | [InlineData ("\r", "\r")] 21 | [InlineData ("\r\n", "\r\n")] 22 | [InlineData ("\n\r", "\n")] 23 | [InlineData ("Hello\nWorld", "\n")] 24 | [InlineData ("Hello\rWorld", "\r")] 25 | [InlineData ("Hello\r\nWorld", "\r\n")] 26 | [InlineData ("Hello\n\rWorld", "\n")] 27 | public void DetectFileLineEnding (string fileContents, string expectedLineEnding) 28 | { 29 | var stream = new MemoryStream (); 30 | var writer = new StreamWriter (stream); 31 | writer.Write (fileContents); 32 | writer.Flush (); 33 | stream.Position = 0; 34 | var reader = new StreamReader (stream); 35 | Assert.Equal (expectedLineEnding, FileHelpers.DetectFileLineEnding (reader)); 36 | } 37 | 38 | public static IEnumerable GetStreamSizes () 39 | { 40 | IEnumerable GenerateSizes () 41 | { 42 | for (int i = 0; i <= 33; i++) 43 | yield return i; 44 | 45 | foreach (var p2 in new [] { 1024, 4096, 8192, 1048576 }) { 46 | for (int i = 0; i <= 9; i++) 47 | yield return p2 + i; 48 | } 49 | } 50 | 51 | foreach (var size in GenerateSizes ()) 52 | yield return new object [] { size }; 53 | } 54 | 55 | (byte [], byte []) RandomBufferWithCopy (int size) 56 | { 57 | var buffer1 = new byte [size]; 58 | random.NextBytes (buffer1); 59 | 60 | var buffer2 = new byte [buffer1.Length]; 61 | Array.Copy (buffer1, buffer2, buffer2.Length); 62 | 63 | return (buffer1, buffer2); 64 | } 65 | 66 | [Theory] 67 | [MemberData (nameof (GetStreamSizes))] 68 | public void StreamContentsAreEqual (int streamSize) 69 | { 70 | var (buffer1, buffer2) = RandomBufferWithCopy (streamSize); 71 | 72 | Assert.True (FileHelpers.StreamContentsAreEqual ( 73 | new MemoryStream (buffer1), 74 | new MemoryStream (buffer2))); 75 | 76 | if (buffer2.Length > 0) { 77 | buffer2 [random.Next (0, buffer2.Length)]++; 78 | 79 | Assert.False (FileHelpers.StreamContentsAreEqual ( 80 | new MemoryStream (buffer1), 81 | new MemoryStream (buffer2))); 82 | } 83 | } 84 | 85 | [Theory] 86 | [MemberData (nameof (GetStreamSizes))] 87 | public void FileContentsAreEqual (int streamSize) 88 | { 89 | var (buffer1, buffer2) = RandomBufferWithCopy (streamSize); 90 | 91 | var dir = Path.Combine ( 92 | Path.GetTempPath (), 93 | "com.xamarin.mirepoix.tests", 94 | nameof (FileContentsAreEqual)); 95 | 96 | Directory.CreateDirectory (dir); 97 | 98 | var path1 = Path.Combine (dir, Path.GetRandomFileName ()); 99 | var path2 = Path.Combine (dir, Path.GetRandomFileName ()); 100 | 101 | File.WriteAllBytes (path1, buffer1); 102 | File.WriteAllBytes (path2, buffer2); 103 | 104 | Assert.True (FileHelpers.FileContentsAreEqual (path1, path1)); 105 | Assert.True (FileHelpers.FileContentsAreEqual (path2, path2)); 106 | Assert.True (FileHelpers.FileContentsAreEqual (path1, path2)); 107 | 108 | if (buffer2.Length > 0) { 109 | using (var stream = new FileStream (path2, FileMode.Open, FileAccess.ReadWrite)) { 110 | stream.Seek (random.Next (0, (int)stream.Length), SeekOrigin.Begin); 111 | var b = (byte)(stream.ReadByte () + 1); 112 | stream.Seek (-1, SeekOrigin.Current); 113 | stream.WriteByte (b); 114 | stream.Flush (); 115 | } 116 | 117 | Assert.False (FileHelpers.FileContentsAreEqual (path1, path2)); 118 | } 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers.Tests/GuidHelperTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | using Xunit; 8 | 9 | using static Xamarin.GuidHelpers; 10 | 11 | namespace Xamarin 12 | { 13 | public class GuidHelperTests 14 | { 15 | [Fact] 16 | public void V3 () 17 | { 18 | Assert.Equal (new Guid ("ead916d5-7bbe-34b4-9946-f015e8b9371e"), GuidV3 (GuidNamespace.DNS, "catoverflow.com")); 19 | Assert.Equal (new Guid ("b8b17fb8-058d-355d-9a2b-d090ac5f7cb7"), GuidV3 (GuidNamespace.URL, "https://catoverflow.com/cqK1y73n")); 20 | } 21 | 22 | [Fact] 23 | public void V5 () 24 | { 25 | Assert.Equal (new Guid ("e8ef0d79-b41b-5d81-9ca6-2303e133a365"), GuidV5 (GuidNamespace.DNS, "catoverflow.com")); 26 | Assert.Equal (new Guid ("a63a9b6e-3429-5fc3-8f13-fefd7b356e94"), GuidV5 (GuidNamespace.URL, "https://catoverflow.com/cqK1y73n")); 27 | } 28 | 29 | static readonly string [] expectedGB18030TestDataHashes = { 30 | "4e5588fa-23b6-54ad-93fd-b60eadb0ad96", 31 | "63032cec-394f-566d-8256-10fad9a917fc", 32 | "741142e5-3b70-5bdd-93e7-4f92263870b5", 33 | "e83026e4-5606-5b81-8dd0-6331aeefbde5", 34 | "9ef2a5dd-16b3-5a41-90ec-7b68b2edcd7f", 35 | "8106e789-4558-5d9d-aecf-c5a02d5a8b1a", 36 | "98af12aa-1e51-5345-ba32-c0527c300d29", 37 | "88aa0f6f-546c-516b-9286-9757bd465fe6", 38 | "ce18fe1b-b2af-574d-af0c-a4a50b731d43", 39 | "99c39637-9252-59d8-b3ca-e362b832c3b1", 40 | "13c4c0f9-ccb9-5999-bb22-23720837c689" 41 | }; 42 | 43 | [Theory] 44 | [ClassData (typeof (GB18030TestData))] 45 | public void GB18030 (string stringDescription, string value) 46 | { 47 | var hashIndex = GB18030TestData.GetIndexOfStringDescription (stringDescription); 48 | Assert.True ( 49 | hashIndex >= 0 && hashIndex < expectedGB18030TestDataHashes.Length, 50 | $"{nameof (expectedGB18030TestDataHashes)} needs updating to reflect {nameof (GB18030TestData)}"); 51 | 52 | Assert.Equal ( 53 | new Guid (expectedGB18030TestDataHashes [hashIndex]), 54 | GuidV5 (new Guid ("0495e02e-a13d-44f7-b7d6-f3385434cde9"), value)); 55 | } 56 | 57 | [Fact] 58 | public void ThreadLocal () 59 | { 60 | var ns = Guid.NewGuid (); 61 | 62 | void CreateGuid (Guid expected, string name, Func func) 63 | { 64 | for (int i = 0; i < 100000; i++) 65 | Assert.Equal (expected, func (ns, name)); 66 | } 67 | 68 | var actions = new Action [64]; 69 | for (int i = 0; i < actions.Length; i++) { 70 | Func func; 71 | var name = $"thread{i}v"; 72 | 73 | if (i % 2 == 0) { 74 | func = GuidV3; 75 | name += "3"; 76 | } else { 77 | func = GuidV5; 78 | name += "5"; 79 | } 80 | 81 | actions [i] = () => CreateGuid (func (ns, name), name, func); 82 | } 83 | 84 | Parallel.Invoke (actions); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers.Tests/LinqExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | using Xunit; 8 | 9 | namespace Xamarin.Linq 10 | { 11 | public sealed class LinqExtensionsTests 12 | { 13 | static readonly Random random = new Random (); 14 | 15 | // NOTE: intentionally not using [MemberData]/[Theory] for these 16 | // tests since doing so reports thousands and thousands of discrete 17 | // tests which is misleading. 18 | static IEnumerable GetByteArrayData () 19 | { 20 | for (int length = 0; length <= 0x8000; length++) { 21 | var data = new byte [length]; 22 | random.NextBytes (data); 23 | yield return data; 24 | } 25 | } 26 | 27 | [Fact] 28 | public void SequenceEqual () 29 | { 30 | foreach (var data in GetByteArrayData ()) { 31 | var dataCopy = new byte [data.Length]; 32 | Array.Copy (data, dataCopy, data.Length); 33 | 34 | Assert.True (data.SequenceEqual (dataCopy, 0, data.Length)); 35 | } 36 | } 37 | 38 | [Fact] 39 | public void SequenceNotEqual () 40 | { 41 | foreach (var data in GetByteArrayData ()) { 42 | if (data.Length == 0) 43 | continue; 44 | 45 | var dataCopy = new byte [data.Length]; 46 | dataCopy [random.Next (0, dataCopy.Length)]++; 47 | 48 | Assert.False (data.SequenceEqual (dataCopy, 0, data.Length)); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers.Tests/Xamarin.Helpers.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.Helpers/FileHelpers.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.ComponentModel; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | using Xamarin.Linq; 11 | 12 | namespace Xamarin 13 | { 14 | public static class FileHelpers 15 | { 16 | /// 17 | /// Returns either "\r\n" (Windows CRLF ending), "\n" (Unix LF ending), 18 | /// "\r" (Legacy Mac CR ending), or null (no endings detected) based on the first 19 | /// occurrence of a valid line ending in the file. 20 | /// 21 | public static string DetectFileLineEnding (string fileName) 22 | { 23 | if (fileName == null) 24 | throw new ArgumentNullException (nameof (fileName)); 25 | 26 | using (var reader = new StreamReader (fileName)) 27 | return DetectFileLineEnding (reader); 28 | } 29 | 30 | [EditorBrowsable (EditorBrowsableState.Never)] 31 | public static string DetectFileLineEnding (StreamReader reader) 32 | { 33 | if (reader == null) 34 | throw new ArgumentNullException (nameof (reader)); 35 | 36 | string lineEnding = null; 37 | 38 | while (true) { 39 | var c = (char)reader.Read (); 40 | switch (c) { 41 | case '\r': 42 | lineEnding = "\r"; 43 | break; 44 | case '\n': 45 | return lineEnding + "\n"; 46 | case char.MaxValue: 47 | return lineEnding; 48 | default: 49 | if (lineEnding != null) 50 | return lineEnding; 51 | break; 52 | } 53 | } 54 | } 55 | 56 | /// 57 | /// Compare the contents of files on disk 58 | /// and for byte equality. 59 | /// 60 | /// Returns true if the files have the same byte content. 61 | public static bool FileContentsAreEqual (string file1, string file2) 62 | { 63 | if (file1 == null) 64 | throw new ArgumentNullException (nameof (file1)); 65 | 66 | if (file2 == null) 67 | throw new ArgumentNullException (nameof (file2)); 68 | 69 | var fullFilePath1 = PathHelpers.ResolveFullPath (file1); 70 | var fullFilePath2 = PathHelpers.ResolveFullPath (file2); 71 | 72 | // fast: same contents if the paths are identical 73 | if (fullFilePath1 == fullFilePath2) 74 | return true; 75 | 76 | // fast: not the same contents if lengths differ on disk 77 | if (new FileInfo (fullFilePath1).Length != new FileInfo (fullFilePath2).Length) 78 | return false; 79 | 80 | // slow: actually compare contents one stream read buffer at a time 81 | using (var stream1 = File.OpenRead (fullFilePath1)) 82 | using (var stream2 = File.OpenRead (fullFilePath2)) 83 | return StreamContentsAreEqual (stream1, stream2); 84 | } 85 | 86 | /// 87 | /// Compare the contents of streams 88 | /// and for byte equality. 89 | /// 90 | /// Returns true if the streams have the same byte content. 91 | public static bool StreamContentsAreEqual (Stream stream1, Stream stream2) 92 | { 93 | if (stream1 == null) 94 | throw new ArgumentNullException (nameof (stream1)); 95 | 96 | if (stream2 == null) 97 | throw new ArgumentNullException (nameof (stream2)); 98 | 99 | const int bufferSize = 4096; 100 | var buffer1 = new byte [bufferSize]; 101 | var buffer2 = new byte [bufferSize]; 102 | 103 | while (true) { 104 | var read1 = stream1.Read (buffer1, 0, buffer1.Length); 105 | var read2 = stream2.Read (buffer2, 0, buffer2.Length); 106 | if (read1 != read2) 107 | return false; 108 | 109 | if (read1 <= 0) 110 | return true; 111 | 112 | if (!buffer1.SequenceEqual (buffer2, 0, read1)) 113 | return false; 114 | } 115 | } 116 | } 117 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers/HashHelpers.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Xamarin 5 | { 6 | public static class HashHelpers 7 | { 8 | const int factor = unchecked ((int)0xa5555529); 9 | 10 | public static int Hash (int newKey, int currentKey) 11 | => unchecked ((currentKey * factor) + newKey); 12 | 13 | public static int Hash (bool newKeyPart, int currentKey) 14 | => Hash (currentKey, newKeyPart ? 1 : 0); 15 | 16 | /// 17 | /// Warning: this will box enum types. 18 | /// 19 | public static int Hash (T newKeyPart, int currentKey) where T : class 20 | { 21 | var hash = unchecked (currentKey * factor); 22 | return newKeyPart == null ? hash : unchecked (hash + newKeyPart.GetHashCode ()); 23 | } 24 | 25 | public static int Hash (params int [] values) 26 | { 27 | if (values?.Length == 0) 28 | return 0; 29 | 30 | var hash = 1; 31 | for (var i = 0; i < values.Length; i++) 32 | hash = unchecked (hash * factor + values [i]); 33 | return hash; 34 | } 35 | 36 | public static unsafe int Hash (params double [] values) 37 | { 38 | if (values?.Length == 0) 39 | return 0; 40 | 41 | var hash = 1; 42 | for (var i = 0; i < values.Length; i++) { 43 | var dv = values [i]; 44 | var lv = *((long*)&dv); 45 | var iv = (int)(lv & 0xffffffff) ^ (int)(lv >> 32); 46 | hash = unchecked (hash * factor + iv); 47 | } 48 | return hash; 49 | } 50 | 51 | /// 52 | /// Warning: this will box value/enum types! 53 | /// 54 | public static int Hash (params object [] values) 55 | { 56 | if (values?.Length == 0) 57 | return 0; 58 | 59 | var hash = 1; 60 | for (var i = 0; i < values.Length; i++) { 61 | if (values [i] != null) 62 | hash = unchecked (hash * factor + values [i].GetHashCode ()); 63 | } 64 | return hash; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers/LinqExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace Xamarin.Linq 8 | { 9 | public static class LinqExtensions 10 | { 11 | [DllImport ( 12 | "msvcrt.dll", 13 | EntryPoint = "memcmp", 14 | CallingConvention = CallingConvention.Cdecl)] 15 | static extern unsafe int windows_memcmp (byte *s1, byte *s2, IntPtr n); 16 | 17 | [DllImport ( 18 | "libc", 19 | EntryPoint = "memcmp", 20 | CallingConvention = CallingConvention.Cdecl)] 21 | static extern unsafe int posix_memcmp (byte *s1, byte *s2, IntPtr n); 22 | 23 | unsafe delegate int memcmp_handler (byte *s1, byte *s2, IntPtr n); 24 | 25 | static memcmp_handler memcmp; 26 | 27 | static unsafe LinqExtensions () 28 | { 29 | if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) 30 | memcmp = windows_memcmp; 31 | else 32 | memcmp = posix_memcmp; 33 | } 34 | 35 | /// 36 | /// Compares elements of two byte arrays starting 37 | /// at for sequence equality using memcmp. 38 | /// 39 | /// 40 | /// + must produce a legal 41 | /// index into both and to avoid 42 | /// an out of bounds read. 43 | /// 44 | /// Array to compare against 45 | /// Array to compare against 46 | /// Starting offset for comparison into the arrays 47 | /// Number of bytes to compare 48 | /// 49 | /// Returns true if the two byte arrays are equal with respect to 50 | /// and . 51 | /// 52 | public static unsafe bool SequenceEqual (this byte [] array1, byte [] array2, int offset, int length) 53 | { 54 | if (array1 == null) 55 | throw new ArgumentNullException (nameof (array1)); 56 | 57 | if (array2 == null) 58 | throw new ArgumentNullException (nameof (array1)); 59 | 60 | if (offset < 0) 61 | throw new ArgumentOutOfRangeException ( 62 | nameof (offset), 63 | "must be >= 0"); 64 | 65 | if (length < 0) 66 | throw new ArgumentOutOfRangeException ( 67 | nameof (length), 68 | "must be >= 0"); 69 | 70 | if (offset + length > array1.Length) 71 | throw new ArgumentOutOfRangeException ( 72 | nameof (array1), 73 | "offset + length produces an index larger than the size of the array"); 74 | 75 | if (offset + length > array2.Length) 76 | throw new ArgumentOutOfRangeException ( 77 | nameof (array2), 78 | "offset + length produces an index larger than the size of the array"); 79 | 80 | if (array1 == array2) 81 | return true; 82 | 83 | fixed (byte *array1Ptr = array1) 84 | fixed (byte *array2Ptr = array2) 85 | return memcmp ( 86 | array1Ptr + offset, 87 | array2Ptr + offset, 88 | (IntPtr)length) == 0; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/Xamarin.Helpers/Xamarin.Helpers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Very simple helper functions. 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/DependencyGraphTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | using Xunit; 10 | 11 | using static Xamarin.PathHelpers; 12 | 13 | namespace Xamarin.MSBuild.Sdk.Tests 14 | { 15 | public class DependencyGraphTests : MSBuildTestBase 16 | { 17 | [Fact] 18 | public async Task ProcessMirepoixSolution () 19 | { 20 | var solutionPath = Path.Combine ( 21 | Git.FindRepositoryRootPathFromAssembly (), 22 | "mirepoix.sln"); 23 | 24 | var dependencyGraph = await DependencyGraph 25 | .Create (solutionPath, ("Configuration", "Debug")) 26 | .LoadGraphAsync (); 27 | 28 | Assert.All (dependencyGraph.TopologicallySortedProjects, node => { 29 | if (node.LoadException != null) 30 | throw node.LoadException; 31 | }); 32 | 33 | Assert.Collection ( 34 | dependencyGraph 35 | .TopologicallySortedProjects 36 | .Select (p => Path.GetFileNameWithoutExtension (p.Project.FullPath)), 37 | p => Assert.Equal ("Xamarin.NativeHelpers", p), 38 | p => Assert.Equal ("Xamarin.Preferences", p), 39 | p => Assert.Equal ("Xamarin.Preferences.Tests", p), 40 | p => Assert.Equal ("Xamarin.Helpers", p), 41 | p => Assert.Equal ("Xamarin.ProcessControl", p), 42 | p => Assert.Equal ("Xamarin.XunitHelpers", p), 43 | p => Assert.Equal ("Xamarin.ProcessControl.Tests", p), 44 | p => Assert.Equal ("Xamarin.Downloader", p), 45 | p => Assert.Equal ("Xamarin.Downloader.Tests", p), 46 | p => Assert.Equal ("Xamarin.Security.Keychain", p), 47 | p => Assert.Equal ("Xamarin.Security.Keychain.Tests", p), 48 | p => Assert.Equal ("Xamarin.Helpers.Tests", p), 49 | p => Assert.Equal ("Xamarin.NativeHelpers.Tests", p), 50 | p => Assert.Equal ("Xamarin.MSBuild.Sdk", p), 51 | p => Assert.Equal ("Xamarin.MSBuild.Sdk.Tests", p), 52 | p => Assert.Equal ("Xamarin.Mac.Sdk", p), 53 | p => Assert.Equal ("ILRepackPatcher", p), 54 | p => Assert.Equal ("Xamarin.BuildConsolidator", p), 55 | p => Assert.Equal ("Xamarin.BuildConsolidator.Tests", p), 56 | p => Assert.Equal ("Xamarin.Cecil.Rocks", p), 57 | p => Assert.Equal ("Xamarin.Cecil.Rocks.Tests", p), 58 | p => Assert.Equal ("Xamarin.PropertyListDeserializer", p)); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/MSBuildTestBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Xamarin.MSBuild.Sdk.Tests 7 | { 8 | public abstract class MSBuildTestBase 9 | { 10 | static MSBuildTestBase () 11 | => MSBuildLocator.RegisterMSBuildPath (); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/SolutionBuilderTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | using Xunit; 10 | 11 | using static Xamarin.PathHelpers; 12 | 13 | using Xamarin.MSBuild.Sdk.Solution; 14 | 15 | namespace Xamarin.MSBuild.Sdk.Tests 16 | { 17 | public class SolutionBuilderTests : MSBuildTestBase 18 | { 19 | static readonly string solutionsDirectory = Path.Combine ( 20 | Git.FindRepositoryRootPathFromAssembly (), 21 | "src", 22 | "Xamarin.MSBuild.Sdk.Tests", 23 | "Solutions"); 24 | 25 | [Theory] 26 | [InlineData ("Folders.proj", true)] 27 | [InlineData ("Folders.proj", false)] 28 | [InlineData ("DisabledProjectsInConfig.proj", true)] 29 | [InlineData ("DisabledProjectsInConfig.proj", false)] 30 | [InlineData ("UnsupportedProjectDependency.proj", true)] 31 | [InlineData ("UnsupportedProjectDependency.proj", false)] 32 | [InlineData ("FallbackToXmlForProjectGuid.proj", true)] 33 | [InlineData ("FallbackToXmlForProjectGuid.proj", false)] 34 | [InlineData ("SharedProjectViaExplicitShprojReference.proj", true)] 35 | [InlineData ("SharedProjectViaExplicitShprojReference.proj", false)] 36 | [InlineData ("SharedProjectViaTransitiveProjitemsReference.proj", true)] 37 | [InlineData ("SharedProjectViaTransitiveProjitemsReference.proj", false)] 38 | [InlineData ("OmitProjectFromSolution.proj", true)] 39 | [InlineData ("OmitProjectFromSolution.proj", false)] 40 | [InlineData ("NotReallyASharedProjectImportsProjitems.proj", true)] 41 | [InlineData ("NotReallyASharedProjectImportsProjitems.proj", false)] 42 | public void GenerateSolution (string projectFile, bool updateExistingSolution) 43 | { 44 | var projectPath = Path.Combine (solutionsDirectory, projectFile); 45 | var referenceSolutionPath = Path.ChangeExtension (projectPath, ".sln"); 46 | var testSolutionPath = referenceSolutionPath + ".test"; 47 | 48 | File.Delete (testSolutionPath); 49 | 50 | if (updateExistingSolution) 51 | File.Copy (referenceSolutionPath, testSolutionPath, true); 52 | 53 | SolutionBuilder 54 | .FromTraversalProject (projectPath, testSolutionPath) 55 | .Write (); 56 | 57 | Assert.Equal ( 58 | File.ReadAllText (referenceSolutionPath), 59 | File.ReadAllText (testSolutionPath)); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/DisabledProjectsInConfig.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/DisabledProjectsInConfig.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "A", "Projects\A.csproj", "{A90BB646-CAD1-5645-AC96-516B561970C3}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "B", "Projects\B.csproj", "{017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C", "Projects\C.csproj", "{3EA39793-378F-50C5-BBF8-802DB4D353E6}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Release|Any CPU.ActiveCfg = Debug|Any CPU 24 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Release|Any CPU.Build.0 = Debug|Any CPU 25 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Release|Any CPU.ActiveCfg = Debug|Any CPU 28 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Release|Any CPU.Build.0 = Debug|Any CPU 29 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Release|Any CPU.ActiveCfg = Debug|Any CPU 32 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Release|Any CPU.Build.0 = Debug|Any CPU 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/FallbackToXmlForProjectGuid.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/FallbackToXmlForProjectGuid.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FallbackToXmlForProjectGuid", "Projects\FallbackToXmlForProjectGuid.csproj", "{0D0D0DEF-8D64-4D12-B37F-7651383AED3F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | EndGlobalSection 12 | GlobalSection(SolutionProperties) = preSolution 13 | HideSolutionNode = FALSE 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0D0D0DEF-8D64-4D12-B37F-7651383AED3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {0D0D0DEF-8D64-4D12-B37F-7651383AED3F}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Folders.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | One 8 | 9 | 10 | A\B\C\D\E 11 | 12 | 13 | A\B 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Folders.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "One", "One", "{4453B956-6158-5C64-A5B7-AAB6A5929CDE}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "A", "Projects\A.csproj", "{A90BB646-CAD1-5645-AC96-516B561970C3}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "A", "A", "{E8623AF7-1698-565E-A799-1119B07BC740}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "B", "B", "{0419C0CE-272A-5A6E-8B62-68706DDC25ED}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "C", "C", "{A5F09338-D59C-5D4B-96C8-4117BED6BB30}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "D", "D", "{39EC191D-8DAF-51CC-B16F-3F38CA495EE4}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "E", "E", "{F06C289A-F785-5A90-A23C-6FED153D807C}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "B", "Projects\B.csproj", "{017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "C", "Projects\C.csproj", "{3EA39793-378F-50C5-BBF8-802DB4D353E6}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {3EA39793-378F-50C5-BBF8-802DB4D353E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | EndGlobalSection 39 | GlobalSection(NestedProjects) = preSolution 40 | {A90BB646-CAD1-5645-AC96-516B561970C3} = {4453B956-6158-5C64-A5B7-AAB6A5929CDE} 41 | {0419C0CE-272A-5A6E-8B62-68706DDC25ED} = {E8623AF7-1698-565E-A799-1119B07BC740} 42 | {A5F09338-D59C-5D4B-96C8-4117BED6BB30} = {0419C0CE-272A-5A6E-8B62-68706DDC25ED} 43 | {39EC191D-8DAF-51CC-B16F-3F38CA495EE4} = {A5F09338-D59C-5D4B-96C8-4117BED6BB30} 44 | {F06C289A-F785-5A90-A23C-6FED153D807C} = {39EC191D-8DAF-51CC-B16F-3F38CA495EE4} 45 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE} = {F06C289A-F785-5A90-A23C-6FED153D807C} 46 | {3EA39793-378F-50C5-BBF8-802DB4D353E6} = {0419C0CE-272A-5A6E-8B62-68706DDC25ED} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/NotReallyASharedProjectImportsProjitems.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/NotReallyASharedProjectImportsProjitems.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedProject", "SharedProject\SharedProject\SharedProject.shproj", "{39A708D0-1A8A-4A42-8125-EF24601C2DA0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotASharedProject", "SharedProject\NotReallyASharedProjectImportsProjitems\NotASharedProject.csproj", "{0644BBB1-E9E4-545E-B6DD-2A737BF801B8}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | EndGlobalSection 14 | GlobalSection(SolutionProperties) = preSolution 15 | HideSolutionNode = FALSE 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {0644BBB1-E9E4-545E-B6DD-2A737BF801B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {0644BBB1-E9E4-545E-B6DD-2A737BF801B8}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/OmitProjectFromSolution.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | false 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/OmitProjectFromSolution.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "A", "Projects\A.csproj", "{A90BB646-CAD1-5645-AC96-516B561970C3}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | EndGlobalSection 12 | GlobalSection(SolutionProperties) = preSolution 13 | HideSolutionNode = FALSE 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Projects/A.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Projects/B.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Projects/C.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Projects/FallbackToXmlForProjectGuid.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | {0D0D0DEF-8D64-4D12-B37F-7651383AED3F} 7 | {94E463F9-07E0-4FBA-BFB2-6230F9CE5073};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | Exe 9 | v4.7.1 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/Projects/InvalidSdk.csproj: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/LibraryProject/LibraryProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/LibraryProject/LibraryProjectClass.cs: -------------------------------------------------------------------------------- 1 | class LibraryProjectClass 2 | { 3 | public LibraryProjectClass() => new SharedProjectClass(); 4 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/NotReallyASharedProjectImportsProjitems/NotASharedProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/NotReallyASharedProjectImportsProjitems/NotASharedProject.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {39A708D0-1A8A-4A42-8125-EF24601C2DA0} 7 | 8 | 9 | SharedProject 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/SharedProject/SharedProject.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {39A708D0-1A8A-4A42-8125-EF24601C2DA0} 7 | 8 | 9 | SharedProject 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/SharedProject/SharedProject.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {39A708D0-1A8A-4A42-8125-EF24601C2DA0} 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProject/SharedProject/SharedProjectClass.cs: -------------------------------------------------------------------------------- 1 | class SharedProjectClass 2 | { 3 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProjectViaExplicitShprojReference.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProjectViaExplicitShprojReference.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedProject", "SharedProject\SharedProject\SharedProject.shproj", "{39A708D0-1A8A-4A42-8125-EF24601C2DA0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryProject", "SharedProject\LibraryProject\LibraryProject.csproj", "{BBC4A766-C07B-5B3E-B5ED-21AA7460F368}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | EndGlobalSection 14 | GlobalSection(SolutionProperties) = preSolution 15 | HideSolutionNode = FALSE 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {BBC4A766-C07B-5B3E-B5ED-21AA7460F368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {BBC4A766-C07B-5B3E-B5ED-21AA7460F368}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProjectViaTransitiveProjitemsReference.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/SharedProjectViaTransitiveProjitemsReference.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedProject", "SharedProject\SharedProject\SharedProject.shproj", "{39A708D0-1A8A-4A42-8125-EF24601C2DA0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibraryProject", "SharedProject\LibraryProject\LibraryProject.csproj", "{BBC4A766-C07B-5B3E-B5ED-21AA7460F368}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | EndGlobalSection 14 | GlobalSection(SolutionProperties) = preSolution 15 | HideSolutionNode = FALSE 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {BBC4A766-C07B-5B3E-B5ED-21AA7460F368}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {BBC4A766-C07B-5B3E-B5ED-21AA7460F368}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | EndGlobalSection 21 | EndGlobal 22 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/UnsupportedProjectDependency.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | 6 | 7 | Debug 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Solutions/UnsupportedProjectDependency.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "A", "Projects\A.csproj", "{A90BB646-CAD1-5645-AC96-516B561970C3}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "B", "Projects\B.csproj", "{017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InvalidSdk", "Projects\InvalidSdk.csproj", "{6F212C51-FC68-5C0A-BD57-62F24A5724C0}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Mac|Any CPU = Mac|Any CPU 15 | Windows|Any CPU = Windows|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Mac|Any CPU.ActiveCfg = Debug|Any CPU 22 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Mac|Any CPU.Build.0 = Debug|Any CPU 23 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Windows|Any CPU.ActiveCfg = Debug|Any CPU 24 | {A90BB646-CAD1-5645-AC96-516B561970C3}.Windows|Any CPU.Build.0 = Debug|Any CPU 25 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Mac|Any CPU.ActiveCfg = Debug|Any CPU 26 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Mac|Any CPU.Build.0 = Debug|Any CPU 27 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Windows|Any CPU.ActiveCfg = Debug|Any CPU 28 | {017EF0F7-397E-50FB-AFAA-FD0EFB79AFCE}.Windows|Any CPU.Build.0 = Debug|Any CPU 29 | {6F212C51-FC68-5C0A-BD57-62F24A5724C0}.Windows|Any CPU.ActiveCfg = Debug|Any CPU 30 | {6F212C51-FC68-5C0A-BD57-62F24A5724C0}.Windows|Any CPU.Build.0 = Debug|Any CPU 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk.Tests/Xamarin.MSBuild.Sdk.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/ConditionParser.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Reflection; 6 | 7 | using Microsoft.Build.Construction; 8 | using Microsoft.Build.Evaluation; 9 | 10 | namespace Xamarin.MSBuild.Sdk 11 | { 12 | static class ConditionParser 13 | { 14 | static readonly Type parserType; 15 | static readonly Type parserOptionsType; 16 | static readonly MethodInfo parserParseMethod; 17 | 18 | static readonly Type equalExpressionNodeType; 19 | 20 | static readonly Type operatorExpressionNodeType; 21 | static readonly PropertyInfo operatorExpressionNodeLeftChildProperty; 22 | static readonly PropertyInfo operatorExpressionNodeRightChildProperty; 23 | 24 | static readonly Type stringExpressionNodeType; 25 | static readonly FieldInfo stringExpressionNodeValueField; 26 | 27 | static readonly BindingFlags bindingFlags = 28 | BindingFlags.Instance | 29 | BindingFlags.Public | 30 | BindingFlags.NonPublic; 31 | 32 | static ConditionParser () 33 | { 34 | var msbuildAssembly = typeof (Project).Assembly; 35 | 36 | parserType = msbuildAssembly.GetType ("Microsoft.Build.Evaluation.Parser"); 37 | parserOptionsType = msbuildAssembly.GetType ("Microsoft.Build.Evaluation.ParserOptions"); 38 | parserParseMethod = parserType.GetMethod ( 39 | "Parse", 40 | bindingFlags | BindingFlags.InvokeMethod, 41 | null, 42 | new [] { 43 | typeof (string), 44 | parserOptionsType, 45 | typeof (ElementLocation) 46 | }, 47 | null); 48 | 49 | equalExpressionNodeType = msbuildAssembly.GetType ("Microsoft.Build.Evaluation.EqualExpressionNode"); 50 | 51 | operatorExpressionNodeType = msbuildAssembly.GetType ("Microsoft.Build.Evaluation.OperatorExpressionNode"); 52 | 53 | operatorExpressionNodeLeftChildProperty = operatorExpressionNodeType.GetProperty ("LeftChild", bindingFlags); 54 | operatorExpressionNodeRightChildProperty = operatorExpressionNodeType.GetProperty ("RightChild", bindingFlags); 55 | 56 | stringExpressionNodeType = msbuildAssembly.GetType ("Microsoft.Build.Evaluation.StringExpressionNode"); 57 | stringExpressionNodeValueField = stringExpressionNodeType.GetField ("_value", bindingFlags); 58 | } 59 | 60 | static object Parse (string expression, ElementLocation elementLocation = null) 61 | { 62 | if (string.IsNullOrEmpty (expression)) 63 | return null; 64 | 65 | var parser = Activator.CreateInstance (parserType, nonPublic: true); 66 | 67 | return parserParseMethod.Invoke ( 68 | parser, 69 | new object [] { 70 | expression, 71 | 15, // ParserOptions.AllowAll 72 | elementLocation 73 | }); 74 | } 75 | 76 | public static bool TryGetStringEqualExpressionUnexpandedValues ( 77 | string condition, 78 | ElementLocation elementLocation, 79 | out (string Left, string Right) expression) 80 | { 81 | var expressionNode = Parse (condition, elementLocation); 82 | 83 | if (expressionNode != null && equalExpressionNodeType.IsAssignableFrom (expressionNode.GetType ())) { 84 | var leftChild = operatorExpressionNodeLeftChildProperty.GetValue (expressionNode); 85 | var rightChild = operatorExpressionNodeRightChildProperty.GetValue (expressionNode); 86 | 87 | if (leftChild?.GetType () == stringExpressionNodeType && 88 | rightChild?.GetType () == stringExpressionNodeType) { 89 | expression = ( 90 | (string)stringExpressionNodeValueField.GetValue (leftChild), 91 | (string)stringExpressionNodeValueField.GetValue (rightChild)); 92 | return true; 93 | } 94 | } 95 | 96 | expression = default; 97 | return false; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/DependencyGraphVisualizationKind.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Xamarin.MSBuild.Sdk 5 | { 6 | public enum DependencyGraphVisualizationKind 7 | { 8 | None, 9 | VisJsNetwork 10 | } 11 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/IDependencyNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Xamarin.MSBuild.Sdk 7 | { 8 | public interface IDependencyNode 9 | { 10 | string Id { get; } 11 | string Label { get; } 12 | Exception LoadException { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/ProjectDependencyNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | 8 | using Microsoft.Build.Evaluation; 9 | 10 | namespace Xamarin.MSBuild.Sdk 11 | { 12 | public sealed class ProjectDependencyNode : IDependencyNode 13 | { 14 | readonly List parents = new List (); 15 | public IReadOnlyList Parents => parents; 16 | 17 | readonly List projectReferenceItems = new List (); 18 | public IReadOnlyList ProjectReferenceItems => projectReferenceItems; 19 | 20 | public string ProjectPath { get; } 21 | public string Id { get; } 22 | public Project Project { get; } 23 | public string Label { get; } 24 | public Exception LoadException { get; } 25 | 26 | internal ProjectDependencyNode ( 27 | string projectPath, 28 | string id, 29 | Project project, 30 | Exception loadException) 31 | { 32 | ProjectPath = projectPath; 33 | Id = id; 34 | Project = project; 35 | Label = Path.GetFileNameWithoutExtension (projectPath); 36 | LoadException = loadException; 37 | } 38 | 39 | internal void AddParent (ProjectDependencyNode parent) 40 | { 41 | if (parent != null && !parents.Contains (parent)) 42 | parents.Add (parent); 43 | } 44 | 45 | internal void AddProjectReferenceItem (ProjectItem projectReferenceItem) 46 | { 47 | if (projectReferenceItem != null && !projectReferenceItems.Contains (projectReferenceItem)) 48 | projectReferenceItems.Add (projectReferenceItem); 49 | } 50 | 51 | public override string ToString () 52 | => $"{Id}:{Label}"; 53 | } 54 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Resources/VisJsTemplate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | MSBuild Dependency Graph 10 | 11 | 12 | 23 | 24 | 25 |
26 | 83 | 84 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Sdk.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(MSBuildThisFileDirectory)..\lib\netstandard2.0\Xamarin.MSBuild.Sdk.dll 4 | $(XamarinMSBuildSdkNuGetTaskAssembly) 5 | 6 | $(MSBuildThisFileDirectory)\bin\Debug\netstandard2.0\Xamarin.MSBuild.Sdk.dll 7 | $(XamarinMSBuildSdkLocalBuildTaskAssembly) 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Sdk.targets: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 11 | 12 | 13 | 18 | 19 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Solution/ConfigurationPlatform.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Xamarin.MSBuild.Sdk.Solution 8 | { 9 | public struct ConfigurationPlatform : IEquatable 10 | { 11 | public const string DefaultConfiguration = "Debug"; 12 | public const string DefaultPlatform = "AnyCPU"; 13 | 14 | public string Configuration { get; } 15 | public string Platform { get; } 16 | 17 | public ConfigurationPlatform ( 18 | string configuration = null, 19 | string platform = null) 20 | { 21 | configuration = configuration?.Trim (); 22 | Configuration = string.IsNullOrEmpty (configuration) 23 | ? DefaultConfiguration 24 | : configuration; 25 | 26 | platform = platform?.Trim (); 27 | Platform = string.IsNullOrEmpty (platform) || 28 | string.Equals (platform, "Any CPU", StringComparison.OrdinalIgnoreCase) 29 | ? DefaultPlatform 30 | : platform; 31 | } 32 | 33 | public static bool operator == (ConfigurationPlatform lhs, ConfigurationPlatform rhs) 34 | => lhs.Equals (rhs); 35 | 36 | public static bool operator != (ConfigurationPlatform lhs, ConfigurationPlatform rhs) 37 | => !lhs.Equals (rhs); 38 | 39 | public bool Equals (ConfigurationPlatform other) 40 | => string.Equals (Configuration, other.Configuration, StringComparison.OrdinalIgnoreCase) && 41 | string.Equals (Platform, other.Platform, StringComparison.OrdinalIgnoreCase); 42 | 43 | public override bool Equals (object obj) 44 | => obj is ConfigurationPlatform other && Equals (other); 45 | 46 | public override int GetHashCode () 47 | => HashHelpers.Hash (Configuration, Platform); 48 | 49 | public override string ToString () 50 | => $"{Configuration}|{Platform}"; 51 | 52 | public string ToSolutionString () 53 | { 54 | var platform = Platform; 55 | if (string.Equals (platform, DefaultPlatform, StringComparison.OrdinalIgnoreCase)) 56 | platform = "Any CPU"; 57 | return $"{Configuration}|{platform}"; 58 | } 59 | 60 | internal ConfigurationPlatform WithConfiguration (string configuration) 61 | { 62 | if (string.IsNullOrEmpty (configuration)) 63 | return this; 64 | 65 | return new ConfigurationPlatform (configuration, Platform); 66 | } 67 | 68 | internal ConfigurationPlatform WithPlatform (string platform) 69 | { 70 | if (string.IsNullOrEmpty (platform)) 71 | return this; 72 | 73 | return new ConfigurationPlatform (Configuration, platform); 74 | } 75 | 76 | public static ConfigurationPlatform Parse (string spec) 77 | { 78 | if (string.IsNullOrEmpty (spec)) 79 | return new ConfigurationPlatform (); 80 | 81 | var parts = spec.Trim ('\'').Split ('|'); 82 | 83 | return new ConfigurationPlatform ( 84 | parts.ElementAtOrDefault (0), 85 | parts.ElementAtOrDefault (1)); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Solution/SolutionConfigurationPlatformMap.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Xamarin.MSBuild.Sdk.Solution 7 | { 8 | public struct SolutionConfigurationPlatformMap : IEquatable 9 | { 10 | public ConfigurationPlatform Solution { get; } 11 | public ConfigurationPlatform Project { get; } 12 | 13 | public bool BuildEnabled { get; } 14 | 15 | public SolutionConfigurationPlatformMap ( 16 | ConfigurationPlatform solutionConfiguration, 17 | ConfigurationPlatform projectConfiguration, 18 | bool buildEnabled = true) 19 | { 20 | Solution = solutionConfiguration; 21 | Project = projectConfiguration; 22 | BuildEnabled = buildEnabled; 23 | } 24 | 25 | public static bool operator == (SolutionConfigurationPlatformMap lhs, SolutionConfigurationPlatformMap rhs) 26 | => lhs.Equals (rhs); 27 | 28 | public static bool operator != (SolutionConfigurationPlatformMap lhs, SolutionConfigurationPlatformMap rhs) 29 | => !lhs.Equals (rhs); 30 | 31 | public bool Equals (SolutionConfigurationPlatformMap other) 32 | => Solution == other.Solution && Project == other.Project; 33 | 34 | public override bool Equals (object obj) 35 | => obj is ConfigurationPlatform other && Equals (other); 36 | 37 | public override int GetHashCode () 38 | => HashHelpers.Hash ( 39 | Solution.GetHashCode (), 40 | Project.GetHashCode ()); 41 | 42 | public override string ToString () 43 | => $"{Solution} = {Project}"; 44 | } 45 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Tasks/GenerateSolution.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.Build.Framework; 5 | using Microsoft.Build.Utilities; 6 | 7 | using Xamarin.MSBuild.Sdk.Solution; 8 | 9 | namespace Xamarin.MSBuild.Sdk.Tasks 10 | { 11 | public sealed class GenerateSolution : Task 12 | { 13 | [Required] 14 | public string TraversalProjectFile { get; set; } 15 | 16 | public string SolutionFile { get; set; } 17 | 18 | public override bool Execute () 19 | { 20 | SolutionBuilder 21 | .FromTraversalProject ( 22 | TraversalProjectFile, 23 | SolutionFile, 24 | log: Log) 25 | .Write (); 26 | 27 | return true; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/VisJsGenerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | 8 | namespace Xamarin.MSBuild.Sdk 9 | { 10 | static class VisJsGenerator 11 | { 12 | static readonly string template; 13 | 14 | static VisJsGenerator () 15 | { 16 | using (var stream = typeof (VisJsGenerator) 17 | .Assembly 18 | .GetManifestResourceStream ("VisJsTemplate.html")) 19 | using (var reader = new StreamReader (stream)) 20 | template = reader.ReadToEnd (); 21 | } 22 | 23 | public static string Generate (DependencyGraph dependencyGraph) 24 | { 25 | var nodes = dependencyGraph 26 | .TopologicallySortedProjects 27 | .Select (node => $"{{ id: '{node.Id}', label: '{node.Label}'}}") 28 | .ToList (); 29 | 30 | var edges = dependencyGraph 31 | .Relationships 32 | .Select (rel => $"{{ from: '{rel.Dependency.Id}', to: '{rel.Dependent.Id}' }}"); 33 | 34 | return template 35 | .Replace ("// @NODES@", string.Join (",\n", nodes)) 36 | .Replace ("// @EDGES@", string.Join (",\n", edges)); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Xamarin.MSBuild.Sdk/Xamarin.MSBuild.Sdk.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | true 5 | Dependency;MSBuildSdk 6 | true 7 | false 8 | 9 | Provides support for generating solutions from MSBuild traversal projects, 10 | working with a project's dependency graph (including generating visualizations), 11 | and other various MSBuild utility APIs, targets, and tasks. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | all 26 | 27 | 28 | 29 | 30 | 31 | VisJsTemplate.html 32 | 33 | 34 | 35 | 36 | 37 | true 38 | Sdk 39 | 40 | 41 | 42 | 43 | $(TargetsForTfmSpecificContentInPackage);XamarinMirepoixDepsContent 44 | 45 | 46 | 47 | 48 | 49 | lib\$(TargetFramework) 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/Xamarin.Mac.Sdk/Sdk.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 12 | 13 | {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 35 | $([System.String]::Copy('%(Identity)').Substring( 36 | 0, 37 | $([System.String]::Copy('%(Identity)').LastIndexOf( 38 | '.designer.cs', 39 | System.StringComparison.OrdinalIgnoreCase)) 40 | )).cs 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/Xamarin.Mac.Sdk/Sdk.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Resources\%(RecursiveDir)%(Filename)%(Extension) 31 | 32 | 33 | 34 | 35 | $(MSBuildProjectDirectory)\Info.plist 36 | <_AppManifest>$(AppBundleManifest) 37 | false 38 | 39 | 40 | 44 | 45 | 48 | 49 | 50 | 54 | 58 | 59 | <_AppBundleOutputDir>$([System.IO.Path]::GetDirectoryName('$(AppBundleDir)'))\ 60 | <_AppBundleDirName>$([System.IO.Path]::GetFileName('$(AppBundleDir)')) 61 | <_AppBundleZipArchiveFileName>$([System.IO.Path]::ChangeExtension('$(_AppBundleDirName)', '.zip')) 62 | $(OutputPath)$(_AppBundleZipArchiveFileName) 63 | 64 | 65 | 68 | 69 | 70 | 75 | 76 | $(MSBuildProjectDirectory)\$(AppBundleDir)\Contents\MacOS\$([System.IO.Path]::GetFileNameWithoutExtension('$(AppBundleDir)')) 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/Xamarin.Mac.Sdk/Xamarin.Mac.Sdk.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | true 5 | MSBuildSdk 6 | true 7 | false 8 | Provides basic SDK-style project support for Xamarin.Mac. 9 | 10 | 11 | 12 | 13 | true 14 | Sdk 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Xamarin.NativeHelpers.Tests/Xamarin.NativeHelpers.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.NativeHelpers/Dlfcn.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Runtime.InteropServices; 10 | 11 | namespace Xamarin.NativeHelpers 12 | { 13 | public static class Dlfcn 14 | { 15 | [DllImport ("libc")] 16 | public static extern int dlclose (IntPtr handle); 17 | 18 | [DllImport ("libc")] 19 | public static extern IntPtr dlopen (string path, int mode); 20 | 21 | [DllImport ("libc")] 22 | public static extern IntPtr dlsym (IntPtr handle, string symbol); 23 | 24 | public static IntPtr ReadIntPtr (IntPtr handle, string symbol) 25 | => Marshal.ReadIntPtr (dlsym (handle, symbol)); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Xamarin.NativeHelpers/Xamarin.NativeHelpers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | Various low-level native interop helpers including some support 6 | for CoreFoundation on macOS. 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Xamarin.Preferences.Tests/Rect.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | 11 | namespace Xamarin.Preferences.Tests 12 | { 13 | sealed class RectTypeConverter : PreferenceTypeConverter 14 | { 15 | protected override string ConvertTo (Rect value) 16 | => value.ToString (); 17 | 18 | protected override object ConvertFrom (string value) 19 | { 20 | if (value == null) 21 | return null; 22 | 23 | return Rect.Parse (value); 24 | } 25 | } 26 | 27 | [TypeConverter (typeof (RectTypeConverter))] 28 | readonly struct Rect : IEquatable 29 | { 30 | public static readonly Rect MinValue = new Rect ( 31 | double.MinValue, 32 | double.MinValue, 33 | double.MinValue, 34 | double.MinValue); 35 | 36 | public static readonly Rect MaxValue = new Rect ( 37 | double.MaxValue, 38 | double.MaxValue, 39 | double.MaxValue, 40 | double.MaxValue); 41 | 42 | public readonly double X; 43 | public readonly double Y; 44 | public readonly double Width; 45 | public readonly double Height; 46 | 47 | public Rect ( 48 | double x, 49 | double y, 50 | double width, 51 | double height) 52 | { 53 | X = x; 54 | Y = y; 55 | Width = width; 56 | Height = height; 57 | } 58 | 59 | public override int GetHashCode () 60 | { 61 | var hash = 23; 62 | hash = hash * 31 + X.GetHashCode (); 63 | hash = hash * 31 + Y.GetHashCode (); 64 | hash = hash * 31 + Width.GetHashCode (); 65 | hash = hash * 31 + Height.GetHashCode (); 66 | return hash; 67 | } 68 | 69 | public override bool Equals (object obj) 70 | => obj is Rect rect && Equals (rect); 71 | 72 | public bool Equals (Rect other) 73 | => X == other.X && Y == other.Y && Width == other.Width && Height == other.Height; 74 | 75 | public override string ToString () 76 | => $"{X:R}, {Y:R}, {Width:R}, {Height:R}"; 77 | 78 | public static Rect Parse (string rect) 79 | { 80 | if (string.IsNullOrEmpty (rect)) 81 | return default; 82 | 83 | var parts = rect.Split (','); 84 | if (parts.Length != 4) 85 | throw new ArgumentException ( 86 | "must have four components separated by ','", 87 | nameof (rect)); 88 | 89 | return new Rect ( 90 | double.Parse (parts [0]), 91 | double.Parse (parts [1]), 92 | double.Parse (parts [2]), 93 | double.Parse (parts [3])); 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences.Tests/Xamarin.Preferences.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/Xamarin.Preferences/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System.Runtime.CompilerServices; 9 | 10 | [assembly: InternalsVisibleTo ("Xamarin.Preferences.Tests")] -------------------------------------------------------------------------------- /src/Xamarin.Preferences/Converters/PreferenceDateTimeConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Globalization; 11 | 12 | namespace Xamarin.Preferences.Converters 13 | { 14 | /// 15 | /// A better round-tripping converter for . The built-in 16 | /// converter does not accurately round-trip some values. 17 | /// 18 | /// 19 | /// With built-in we'd expect '9999-12-31T23:59:59.9999999+00:00' 20 | /// but get '9999-12-31T23:59:59.0000000+00:00' instead. 21 | /// 22 | sealed class PreferenceDateTimeConverter : PreferenceTypeConverter 23 | { 24 | protected override object ConvertFrom (string value) 25 | => DateTime.Parse ( 26 | value, 27 | CultureInfo.InvariantCulture, 28 | DateTimeStyles.RoundtripKind); 29 | 30 | protected override string ConvertTo (DateTime value) 31 | => value.ToString ("o"); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/Converters/PreferenceDateTimeOffsetConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Globalization; 11 | 12 | namespace Xamarin.Preferences.Converters 13 | { 14 | /// 15 | /// A better round-tripping converter for . The built-in 16 | /// converter does not accurately round-trip some values. 17 | /// 18 | /// 19 | /// With built-in we'd expect '9999-12-31T23:59:59.9999999+00:00' 20 | /// but get '9999-12-31T23:59:59.0000000+00:00' instead. 21 | /// 22 | sealed class PreferenceDateTimeOffsetConverter : PreferenceTypeConverter 23 | { 24 | protected override object ConvertFrom (string value) 25 | => DateTimeOffset.Parse ( 26 | value, 27 | CultureInfo.InvariantCulture, 28 | DateTimeStyles.RoundtripKind); 29 | 30 | protected override string ConvertTo (DateTimeOffset value) 31 | => value.ToString ("o"); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/MemoryOnlyPreferenceStore.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | namespace Xamarin.Preferences 12 | { 13 | public class MemoryOnlyPreferenceStore : PreferenceStore 14 | { 15 | readonly Dictionary storage = new Dictionary (); 16 | 17 | protected override IReadOnlyList GetKeys () 18 | { 19 | var keys = storage.Keys; 20 | var keysArray = new string [keys.Count]; 21 | keys.CopyTo (keysArray, 0); 22 | return keysArray; 23 | } 24 | 25 | protected override bool StorageSetValue (string key, object value) 26 | { 27 | if (value is string || value is IEnumerable) { 28 | storage [key] = value; 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | protected override bool StorageTryGetValue ( 36 | string key, 37 | Type valueType, 38 | TypeCode valueTypeCode, 39 | out object value) 40 | => storage.TryGetValue (key, out value); 41 | 42 | protected override bool StorageRemove (string key) 43 | => storage.Remove (key); 44 | } 45 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/Preference.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Globalization; 11 | 12 | using Xamarin.Preferences.Converters; 13 | 14 | namespace Xamarin.Preferences 15 | { 16 | public sealed class Preference 17 | { 18 | static Preference () 19 | { 20 | TypeDescriptor.AddAttributes ( 21 | typeof (DateTime), 22 | new TypeConverterAttribute (typeof (PreferenceDateTimeConverter))); 23 | 24 | TypeDescriptor.AddAttributes ( 25 | typeof (DateTimeOffset), 26 | new TypeConverterAttribute (typeof (PreferenceDateTimeOffsetConverter))); 27 | } 28 | 29 | readonly PreferenceStore preferenceStore; 30 | readonly Type type; 31 | readonly TypeCode typeCode; 32 | readonly TypeConverter converter; 33 | 34 | public string Key { get; } 35 | public T DefaultValue { get; } 36 | 37 | public Preference ( 38 | string key, 39 | T defaultValue = default, 40 | TypeConverter converter = null) 41 | : this ( 42 | null, 43 | key, 44 | defaultValue, 45 | converter) 46 | { 47 | } 48 | 49 | public Preference ( 50 | PreferenceStore preferenceStore, 51 | string key, 52 | T defaultValue = default, 53 | TypeConverter converter = null) 54 | { 55 | this.preferenceStore = preferenceStore; 56 | Key = key 57 | ?? throw new ArgumentNullException (nameof (key)); 58 | DefaultValue = defaultValue; 59 | type = typeof (T); 60 | typeCode = Type.GetTypeCode (type); 61 | this.converter = converter 62 | ?? TypeDescriptor.GetConverter (type); 63 | } 64 | 65 | PreferenceStore Store => preferenceStore 66 | ?? PreferenceStore.SharedInstance; 67 | 68 | public T GetValue () 69 | { 70 | if (!PreferenceStore.ReturnDefaultValueOnException) 71 | return GetValueUnchecked (); 72 | 73 | try { 74 | return GetValueUnchecked (); 75 | } catch { 76 | return DefaultValue; 77 | } 78 | } 79 | 80 | T GetValueUnchecked () 81 | { 82 | if (!Store.TryGetValue ( 83 | Key, 84 | type, 85 | typeCode, 86 | out var value) || value == null) 87 | return DefaultValue; 88 | 89 | var valueType = value.GetType (); 90 | 91 | if (type.IsAssignableFrom (valueType)) 92 | return (T)value; 93 | 94 | if (converter != null && converter.CanConvertFrom (valueType)) { 95 | return (T)converter.ConvertFrom ( 96 | null, 97 | CultureInfo.InvariantCulture, 98 | value); 99 | } 100 | 101 | return (T)Convert.ChangeType ( 102 | value, 103 | type, 104 | CultureInfo.InvariantCulture); 105 | } 106 | 107 | public void SetValue (T value) 108 | => Store.SetValue (Key, value, converter); 109 | 110 | public void Reset () 111 | => Store.Remove (Key); 112 | } 113 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/PreferenceChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | namespace Xamarin.Preferences 11 | { 12 | public sealed class PreferenceChangedEventArgs : EventArgs 13 | { 14 | public string Key { get; } 15 | 16 | internal PreferenceChangedEventArgs (string key) 17 | { 18 | if (key == null) 19 | throw new ArgumentNullException (nameof (key)); 20 | 21 | Key = key; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/PreferenceStoreConfiguration.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Runtime.InteropServices; 10 | 11 | using Microsoft.Win32; 12 | 13 | namespace Xamarin.Preferences 14 | { 15 | public sealed class PreferenceStoreConfiguration 16 | { 17 | readonly string macosAppDomain; 18 | 19 | readonly RegistryHive windowsRegistryHive; 20 | readonly RegistryView windowsRegistryView; 21 | readonly string windowsRegistrySubKey; 22 | 23 | readonly bool memoryStoreFallback; 24 | 25 | public PreferenceStoreConfiguration () 26 | { 27 | } 28 | 29 | PreferenceStoreConfiguration ( 30 | string macosAppDomain, 31 | RegistryHive windowsRegistryHive, 32 | RegistryView windowsRegistryView, 33 | string windowsRegistrySubKey, 34 | bool memoryStoreFallback) 35 | { 36 | this.macosAppDomain = macosAppDomain; 37 | 38 | this.windowsRegistryHive = windowsRegistryHive; 39 | this.windowsRegistryView = windowsRegistryView; 40 | this.windowsRegistrySubKey = windowsRegistrySubKey; 41 | 42 | this.memoryStoreFallback = memoryStoreFallback; 43 | } 44 | 45 | public PreferenceStoreConfiguration WithMac (string macosAppDomain) 46 | => new PreferenceStoreConfiguration ( 47 | macosAppDomain, 48 | this.windowsRegistryHive, 49 | this.windowsRegistryView, 50 | this.windowsRegistrySubKey, 51 | this.memoryStoreFallback); 52 | 53 | public PreferenceStoreConfiguration WithWindows ( 54 | string registrySubKey, 55 | RegistryHive registryHive = RegistryHive.CurrentUser, 56 | RegistryView registryView = RegistryView.Default) 57 | => new PreferenceStoreConfiguration ( 58 | this.macosAppDomain, 59 | registryHive, 60 | registryView, 61 | registrySubKey, 62 | this.memoryStoreFallback); 63 | 64 | public PreferenceStoreConfiguration WithMemoryFallback ( 65 | bool memoryFallback) 66 | => new PreferenceStoreConfiguration ( 67 | this.macosAppDomain, 68 | this.windowsRegistryHive, 69 | this.windowsRegistryView, 70 | this.windowsRegistrySubKey, 71 | memoryFallback); 72 | 73 | public PreferenceStore Create () 74 | { 75 | if (macosAppDomain != null && RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) 76 | return new MacUserDefaultsPreferenceStore (macosAppDomain); 77 | 78 | if (windowsRegistrySubKey != null && RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) 79 | return new RegistryPreferenceStore ( 80 | windowsRegistryHive, 81 | windowsRegistryView, 82 | windowsRegistrySubKey); 83 | 84 | if (memoryStoreFallback) 85 | return new MemoryOnlyPreferenceStore (); 86 | 87 | throw new PlatformNotSupportedException ( 88 | "Either the platform is not supported or the configuration has not been " + 89 | "specified appropriately for the current platform."); 90 | } 91 | 92 | public void CreateAndInitialize () 93 | => PreferenceStore.Initialize (Create ()); 94 | } 95 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/PreferenceTypeConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Globalization; 11 | 12 | namespace Xamarin.Preferences 13 | { 14 | public abstract class PreferenceTypeConverter : TypeConverter 15 | { 16 | protected abstract object ConvertFrom (string value); 17 | 18 | public sealed override bool CanConvertFrom ( 19 | ITypeDescriptorContext context, 20 | Type sourceType) 21 | => sourceType == typeof (string); 22 | 23 | public sealed override object ConvertFrom ( 24 | ITypeDescriptorContext context, 25 | CultureInfo culture, 26 | object value) 27 | => ConvertFrom ((string)value); 28 | 29 | protected abstract string ConvertTo (T value); 30 | 31 | public sealed override bool CanConvertTo ( 32 | ITypeDescriptorContext context, 33 | Type destinationType) 34 | => destinationType == typeof (T); 35 | 36 | public sealed override object ConvertTo ( 37 | ITypeDescriptorContext context, 38 | CultureInfo culture, 39 | object value, 40 | Type destinationType) 41 | => ConvertTo (value == null ? default (T) : (T)value); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Xamarin.Preferences/Xamarin.Preferences.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | An API for storing user preferences through a number of backends. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl.Tests/ExecTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq; 6 | 7 | using Xunit; 8 | 9 | using Xamarin.ProcessControl; 10 | 11 | namespace Xamarin.ProcessControl.Tests 12 | { 13 | public class ExecTests 14 | { 15 | [UnixFact] 16 | public void ImplicitlyExecAssemblyWithMonoOnUnix () 17 | { 18 | var exec = new Exec (ProcessArguments.Create ("test.exe", "a", "b")); 19 | Assert.False (exec.Elevated); 20 | Assert.Equal ( 21 | exec.Arguments, 22 | ProcessArguments.Create ("mono", "test.exe", "a", "b")); 23 | } 24 | 25 | [UnixFact] 26 | public void ElevateOnUnix () 27 | { 28 | var exec = new Exec ( 29 | ProcessArguments.Create ("installer"), 30 | ExecFlags.Elevate); 31 | Assert.True (exec.Elevated); 32 | Assert.Equal ( 33 | exec.Arguments, 34 | ProcessArguments.Create ("/usr/bin/sudo", "installer")); 35 | } 36 | 37 | #if false 38 | // As of 2018-12-04 the VSTS hosted pool vmImage 'ubuntu-16.04' 39 | // is [thankfully] no longer running as root (user is 'vsts'), so 40 | // this test is now disabled. The ElevateOnUnix test above was 41 | // previously a [MacFact] ElevateOnMac. 42 | [LinuxFact] 43 | public void IgnoreElevateOnUnix () 44 | { 45 | // On VSTS the hosted Linux pool runs as root (sigh, but we can take 46 | // advantage of that fact to test that we are _not_ wrapping with 47 | // sudo if we already are root). 48 | if (Environment.GetEnvironmentVariable ("TF_BUILD") == "True") { 49 | var exec = new Exec ( 50 | ProcessArguments.Create ("installer"), 51 | ExecFlags.Elevate); 52 | Assert.False (exec.Elevated); 53 | Assert.Equal ( 54 | exec.Arguments, 55 | ProcessArguments.Create ("installer")); 56 | } 57 | } 58 | #endif 59 | 60 | [MacFact] 61 | public void ElevateOnMacAndImplicitlyExecAssemblyWithMonoOnUnix () 62 | { 63 | var exec = new Exec ( 64 | ProcessArguments.Create ("test.exe", "a", "b"), 65 | ExecFlags.Elevate); 66 | Assert.True (exec.Elevated); 67 | Assert.Equal ( 68 | exec.Arguments, 69 | ProcessArguments.Create ("/usr/bin/sudo", "mono", "test.exe", "a", "b")); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl.Tests/ProcessArguments.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Linq; 5 | 6 | using Xunit; 7 | 8 | using Xamarin.ProcessControl; 9 | 10 | namespace Xamarin.ProcessControl.Tests 11 | { 12 | public class ProcessArgumentsTests 13 | { 14 | [Fact] 15 | public void Empty () 16 | { 17 | Assert.Same (ProcessArguments.Empty, ProcessArguments.Create ()); 18 | Assert.Same (ProcessArguments.Empty, ProcessArguments.Parse (string.Empty)); 19 | } 20 | 21 | [Theory] 22 | [InlineData] 23 | [InlineData ("one")] 24 | [InlineData ("one", "two")] 25 | [InlineData ("one", "two", "three")] 26 | [InlineData ("one", "two", "three", "four")] 27 | public void Create (params string [] args) 28 | => Assert.Equal (args, ProcessArguments.Create (args)); 29 | 30 | [Fact] 31 | public void Insert () 32 | => Assert.Equal ( 33 | new [] { "zero", "one", "two", "three", "four" }, 34 | ProcessArguments 35 | .Create ("one", "three") 36 | .Insert (1, "two") 37 | .Insert (3, "four") 38 | .Insert (0, "zero")); 39 | 40 | [Fact] 41 | public void InsertRange () 42 | => Assert.Equal ( 43 | new [] { "zero", "one", "two", "three", "four" }, 44 | ProcessArguments 45 | .Create ("four") 46 | .InsertRange (0, "zero", "one") 47 | .InsertRange (2, new [] { "two", "three" })); 48 | 49 | [Fact] 50 | public void Add () 51 | => Assert.Equal ( 52 | new [] { "one", "two", "three" }, 53 | ProcessArguments 54 | .Empty 55 | .Add ("one") 56 | .Add ("two") 57 | .Add ("three")); 58 | 59 | [Fact] 60 | public void AddRange () 61 | => Assert.Equal ( 62 | new [] { "zero", "one", "two", "three", "four" }, 63 | ProcessArguments 64 | .Empty 65 | .AddRange ("zero", "one", "two") 66 | .AddRange (new [] { "three", "four" })); 67 | 68 | [Theory] 69 | [InlineData ("hello", "hello")] 70 | [InlineData ("hello world", "\"hello world\"")] 71 | [InlineData ("\"", "\"\\\"\"")] 72 | [InlineData ("", "\"\"")] 73 | public void Quote (string unquoted, string quoted) 74 | => Assert.Equal (quoted, ProcessArguments.Quote (unquoted)); 75 | 76 | [Theory] 77 | [InlineData ("hello", "hello")] 78 | [InlineData ("hello world", "hello", "world")] 79 | [InlineData ("'hello world'", "hello world")] 80 | [InlineData ("\"hello world\"", "hello world")] 81 | [InlineData ("one 'two three' four", "one", "two three", "four")] 82 | public void ParseWithoutGlobs (string commandLine, params string [] expectedArguments) 83 | => Assert.Equal ( 84 | expectedArguments, 85 | ProcessArguments.Parse (commandLine)); 86 | 87 | [Theory] 88 | [InlineData ("hello", "hello")] 89 | [InlineData ("hello world", "hello world")] 90 | [InlineData ("'hello world'", "\"hello world\"")] 91 | [InlineData ("\"hello world\"", "\"hello world\"")] 92 | [InlineData ("one 'two three' four", "one \"two three\" four")] 93 | public void ParseAndToStringRoundTrip (string commandLine, string expectedToString) 94 | => Assert.Equal ( 95 | expectedToString, 96 | ProcessArguments.Parse (commandLine).ToString ()); 97 | } 98 | } -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl.Tests/Xamarin.ProcessControl.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl/ConsoleRedirection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections.ObjectModel; 10 | using System.Collections.Specialized; 11 | using System.IO; 12 | using System.Text; 13 | 14 | namespace Xamarin.ProcessControl 15 | { 16 | public sealed class ConsoleRedirection 17 | { 18 | public enum FileDescriptor 19 | { 20 | None, 21 | Output, 22 | Error 23 | } 24 | 25 | public sealed class SegmentCollection : INotifyCollectionChanged 26 | { 27 | readonly ObservableCollection segments = new ObservableCollection (); 28 | 29 | public event NotifyCollectionChangedEventHandler CollectionChanged { 30 | add => segments.CollectionChanged += value; 31 | remove => segments.CollectionChanged -= value; 32 | } 33 | 34 | public void Add (Segment segment) 35 | { 36 | lock (segments) 37 | segments.Add (segment); 38 | } 39 | 40 | public void Write (TextWriter writer, FileDescriptor fileDescriptor = FileDescriptor.None) 41 | { 42 | lock (segments) { 43 | foreach (var segment in segments) { 44 | if (fileDescriptor == FileDescriptor.None || 45 | segment.FileDescriptor == fileDescriptor) 46 | writer.Write (segment.Data); 47 | } 48 | } 49 | } 50 | 51 | public override string ToString () => ToString (FileDescriptor.None); 52 | 53 | public string ToString (FileDescriptor fileDescriptor) 54 | { 55 | using (var writer = new StringWriter ()) { 56 | Write (writer, fileDescriptor); 57 | return writer.ToString (); 58 | } 59 | } 60 | } 61 | 62 | [Serializable] 63 | public struct Segment 64 | { 65 | public FileDescriptor FileDescriptor { get; } 66 | public string Data { get; } 67 | 68 | internal Segment (FileDescriptor fileDescriptor, char [] buffer, int index, int count) 69 | { 70 | FileDescriptor = fileDescriptor; 71 | Data = new string (buffer, index, count); 72 | } 73 | 74 | internal Segment (FileDescriptor fileDescriptor, char singleChar) 75 | { 76 | FileDescriptor = fileDescriptor; 77 | Data = singleChar.ToString (); 78 | } 79 | 80 | public void Deconstruct (out FileDescriptor fd, out string data) 81 | { 82 | fd = FileDescriptor; 83 | data = Data; 84 | } 85 | } 86 | 87 | public Action WriteHandler { get; } 88 | public TextWriter StandardOutput { get; } 89 | public TextWriter StandardError { get; } 90 | 91 | public ConsoleRedirection (Action writeHandler) 92 | { 93 | WriteHandler = writeHandler ?? throw new ArgumentNullException (nameof (writeHandler)); 94 | 95 | StandardOutput = new Writer (FileDescriptor.Output, this); 96 | StandardError = new Writer (FileDescriptor.Error, this); 97 | } 98 | 99 | sealed class Writer : TextWriter 100 | { 101 | readonly FileDescriptor fileDescriptor; 102 | readonly ConsoleRedirection redirection; 103 | 104 | public override Encoding Encoding { get; } = new UTF8Encoding (false, false); 105 | 106 | public Writer (FileDescriptor fileDescriptor, ConsoleRedirection redirection) 107 | { 108 | this.fileDescriptor = fileDescriptor; 109 | this.redirection = redirection; 110 | } 111 | 112 | public override void Write (char value) 113 | => redirection?.WriteHandler ( 114 | new Segment (fileDescriptor, value)); 115 | 116 | public override void Write (char [] buffer, int index, int count) 117 | => redirection?.WriteHandler ( 118 | new Segment (fileDescriptor, buffer, index, count)); 119 | } 120 | } 121 | } -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl/ExecFlags.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | namespace Xamarin.ProcessControl 11 | { 12 | [Flags] 13 | public enum ExecFlags 14 | { 15 | None = 0 << 0, 16 | RedirectStdin = 1 << 0, 17 | RedirectStdout = 1 << 1, 18 | RedirectStderr = 1 << 2, 19 | Elevate = 1 << 3, 20 | OutputOnSynchronizationContext = 1 << 4, 21 | 22 | Default = OutputOnSynchronizationContext 23 | } 24 | } -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl/ExecStatus.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Xamarin.ProcessControl 7 | { 8 | public enum ExecStatus 9 | { 10 | None, 11 | ProcessStarted, 12 | ProcessEnded 13 | } 14 | 15 | public sealed class ExecStatusEventArgs : EventArgs 16 | { 17 | public Exec Exec { get; } 18 | public ExecStatus Status { get; } 19 | public int? ExitCode { get; } 20 | public DateTimeOffset EventTime { get; } 21 | public TimeSpan ExecDuration { get; } 22 | 23 | ExecStatusEventArgs ( 24 | Exec exec, 25 | ExecStatus status, 26 | int? exitCode, 27 | DateTimeOffset eventTime, 28 | TimeSpan execDuration) 29 | { 30 | Exec = exec; 31 | Status = status; 32 | ExitCode = exitCode; 33 | EventTime = eventTime; 34 | ExecDuration = execDuration; 35 | } 36 | 37 | internal ExecStatusEventArgs (Exec exec) 38 | : this ( 39 | exec, 40 | ExecStatus.ProcessStarted, 41 | null, 42 | DateTimeOffset.UtcNow, 43 | TimeSpan.Zero) 44 | { 45 | } 46 | 47 | internal ExecStatusEventArgs WithProcessEnded (int exitCode) 48 | { 49 | var now = DateTimeOffset.UtcNow; 50 | return new ExecStatusEventArgs ( 51 | Exec, 52 | ExecStatus.ProcessEnded, 53 | exitCode, 54 | now, 55 | now - EventTime); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Xamarin.ProcessControl/Xamarin.ProcessControl.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | A small collection of utility APIs including command line argument 6 | splitting and quoting, file system globbing, cross platform process 7 | execution, and console output redirection handling. 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Xamarin.PropertyListDeserializer/Xamarin.PropertyListDeserializer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Apple Property List (plist) deserializer supporting XML and Binary formats. 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain.Tests/KeychainSecretNameTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | using Xunit; 11 | 12 | namespace Xamarin.Security.Tests 13 | { 14 | public class KeychainSecretNameTests 15 | { 16 | [Fact] 17 | public void ServiceNullNotAllowed () 18 | { 19 | Assert.Throws ( 20 | () => new KeychainSecretName (null, "account")); 21 | Assert.Throws ( 22 | () => (KeychainSecretName)(null, "account")); 23 | } 24 | 25 | [Fact] 26 | public void ServiceEmptyNotAllowed () 27 | { 28 | Assert.Throws ( 29 | () => new KeychainSecretName (string.Empty, "account")); 30 | Assert.Throws ( 31 | () => (KeychainSecretName)(string.Empty, "account")); 32 | } 33 | 34 | [Fact] 35 | public void AccountNullNotAllowed () 36 | { 37 | Assert.Throws ( 38 | () => new KeychainSecretName ("service", null)); 39 | Assert.Throws ( 40 | () => (KeychainSecretName)(string.Empty, "account")); 41 | } 42 | 43 | [Fact] 44 | public void AccountEmptyNotAllowed () 45 | { 46 | Assert.Throws ( 47 | () => new KeychainSecretName ("service", string.Empty)); 48 | Assert.Throws ( 49 | () => (KeychainSecretName)(string.Empty, "account")); 50 | } 51 | 52 | [Fact] 53 | public void Equal () 54 | { 55 | Assert.Equal (new KeychainSecretName ("a", "b"), ("a", "b")); 56 | Assert.True (new KeychainSecretName ("a", "b") == ("a", "b")); 57 | Assert.False (new KeychainSecretName ("a", "b") != ("a", "b")); 58 | } 59 | 60 | [Fact] 61 | public void NotEqual () 62 | { 63 | Assert.NotEqual (new KeychainSecretName ("a", "b"), ("a", "c")); 64 | Assert.True (new KeychainSecretName ("a", "b") != ("a", "c")); 65 | Assert.False (new KeychainSecretName ("a", "b") == ("a", "c")); 66 | } 67 | 68 | [Fact] 69 | public void ToStringFormat () 70 | => Assert.Equal ("a/b", new KeychainSecretName ("a", "b").ToString ()); 71 | 72 | [Fact] 73 | public void Deconstruct () 74 | { 75 | var (service, account) = new KeychainSecretName ("a", "b"); 76 | Assert.Equal ("a", service); 77 | Assert.Equal ("b", account); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain.Tests/Xamarin.Security.Keychain.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Assert.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | namespace Xamarin.Security 11 | { 12 | static class ArgumentAssert 13 | { 14 | public static void IsNotNullOrEmpty (string argument, string parameterName) 15 | { 16 | if (argument == null) 17 | throw new ArgumentNullException (parameterName); 18 | 19 | if (argument == string.Empty) 20 | throw new ArgumentException ( 21 | "empty string is not allowed", 22 | parameterName); 23 | } 24 | 25 | public static void IsNotNullOrEmpty (byte [] argument, string parameterName) 26 | { 27 | if (argument == null) 28 | throw new ArgumentNullException (parameterName); 29 | 30 | if (argument.Length == 0) 31 | throw new ArgumentException ( 32 | "empty byte array is not allowed", 33 | parameterName); 34 | } 35 | 36 | public static void IsNotNull (T argument, string parameterName) 37 | where T : class 38 | { 39 | if (argument == null) 40 | throw new ArgumentNullException (parameterName); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System.Runtime.InteropServices; 9 | using System.Text; 10 | 11 | using Xamarin.Security.Keychains; 12 | 13 | namespace Xamarin.Security 14 | { 15 | public static class Keychain 16 | { 17 | internal static readonly Encoding Utf8 = new UTF8Encoding (false, false); 18 | 19 | static readonly IKeychain keychain = new OSKeychain (); 20 | 21 | static Keychain () 22 | { 23 | } 24 | 25 | public static bool TryGetSecret (KeychainSecretName name, out KeychainSecret secret) 26 | => keychain.TryGetSecret (name, out secret); 27 | 28 | public static bool TryGetSecret ( 29 | string serviceName, 30 | string accountName, 31 | out string secret) 32 | => keychain.TryGetSecret (serviceName, accountName, out secret); 33 | 34 | public static bool TryGetSecretBytes ( 35 | string serviceName, 36 | string accountName, 37 | out byte [] secret) 38 | => keychain.TryGetSecretBytes (serviceName, accountName, out secret); 39 | 40 | public static void StoreSecret (KeychainSecret secret, bool updateExisting = true) 41 | => keychain.StoreSecret (secret, updateExisting); 42 | 43 | public static void StoreSecret ( 44 | string serviceName, 45 | string accountName, 46 | string secret, 47 | bool updateExisting = true) 48 | => keychain.StoreSecret (serviceName, accountName, secret, updateExisting); 49 | 50 | public static void StoreSecret ( 51 | string serviceName, 52 | string accountName, 53 | byte [] secret, 54 | bool updateExisting = true) 55 | => keychain.StoreSecret (serviceName, accountName, secret, updateExisting); 56 | } 57 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/KeychainExceptions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | 10 | namespace Xamarin.Security 11 | { 12 | public abstract class KeychainException : Exception 13 | { 14 | internal KeychainException (string message, Exception innerException = null) 15 | : base (message, innerException) 16 | { 17 | } 18 | } 19 | 20 | public sealed class KeychainItemAlreadyExistsException : KeychainException 21 | { 22 | internal KeychainItemAlreadyExistsException (string message, Exception innerException = null) 23 | : base (message, innerException) 24 | { 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/KeychainSecret.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Text; 11 | 12 | namespace Xamarin.Security 13 | { 14 | public sealed class KeychainSecret 15 | { 16 | public KeychainSecretName Name { get; } 17 | 18 | readonly byte [] value; 19 | public IReadOnlyList Value => value; 20 | 21 | KeychainSecret ( 22 | KeychainSecretName name, 23 | byte [] value) 24 | { 25 | Name = name; 26 | this.value = value; 27 | } 28 | 29 | public string GetUtf8StringValue () 30 | => Keychain.Utf8.GetString (value); 31 | 32 | public static KeychainSecret Create ( 33 | KeychainSecretName name, 34 | byte [] value) 35 | { 36 | name.Assert (nameof (name)); 37 | ArgumentAssert.IsNotNull (value, nameof (value)); 38 | 39 | return new KeychainSecret ( 40 | name, 41 | value); 42 | } 43 | 44 | public static KeychainSecret Create ( 45 | KeychainSecretName name, 46 | string value) 47 | { 48 | name.Assert (nameof (name)); 49 | ArgumentAssert.IsNotNull (value, nameof (value)); 50 | 51 | return new KeychainSecret ( 52 | name, 53 | value == null ? null : Keychain.Utf8.GetBytes (value)); 54 | } 55 | 56 | public KeychainSecret WithName (KeychainSecretName name) 57 | { 58 | name.Assert (nameof (name)); 59 | 60 | return new KeychainSecret ( 61 | name, 62 | value); 63 | } 64 | 65 | public KeychainSecret WithValue (byte [] value) 66 | { 67 | ArgumentAssert.IsNotNull (value, nameof (value)); 68 | 69 | return new KeychainSecret ( 70 | Name, 71 | value); 72 | } 73 | 74 | public KeychainSecret WithValue (string value) 75 | { 76 | ArgumentAssert.IsNotNull (value, nameof (value)); 77 | 78 | return new KeychainSecret ( 79 | Name, 80 | Keychain.Utf8.GetBytes (value)); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/KeychainSecretName.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Text; 11 | 12 | namespace Xamarin.Security 13 | { 14 | public struct KeychainSecretName : IEquatable 15 | { 16 | public string Service { get; } 17 | public string Account { get; } 18 | 19 | public KeychainSecretName ( 20 | string service, 21 | string account) 22 | { 23 | ArgumentAssert.IsNotNullOrEmpty (service, nameof (service)); 24 | ArgumentAssert.IsNotNullOrEmpty (account, nameof (account)); 25 | 26 | Service = service; 27 | Account = account; 28 | } 29 | 30 | public bool Equals (KeychainSecretName other) 31 | => Service == other.Service && Account == other.Account; 32 | 33 | public override bool Equals (object obj) 34 | => obj is KeychainSecretName other && Equals (other); 35 | 36 | public override int GetHashCode () 37 | => Service.GetHashCode () * unchecked((int)0xa5555529) + Account.GetHashCode (); 38 | 39 | public override string ToString () 40 | => $"{Service}/{Account}"; 41 | 42 | public void Deconstruct (out string service, out string account) 43 | { 44 | service = Service; 45 | account = Account; 46 | } 47 | 48 | public static implicit operator KeychainSecretName ((string service, string account) name) 49 | => new KeychainSecretName (name.service, name.account); 50 | 51 | public static bool operator == (KeychainSecretName a, KeychainSecretName b) 52 | => a.Equals (b); 53 | 54 | public static bool operator != (KeychainSecretName a, KeychainSecretName b) 55 | => !a.Equals (b); 56 | 57 | internal void Assert (string parameterName) 58 | { 59 | if (this == default) 60 | throw new ArgumentException ("must not be an empty name", parameterName); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychains/DPAPIKeychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Security.Cryptography; 11 | 12 | namespace Xamarin.Security.Keychains 13 | { 14 | /// 15 | /// An implementation backed by the 16 | /// [Windows Data Protection](https://msdn.microsoft.com/en-us/library/ms995355.aspx) 17 | /// API for secure storage of secrets, scoped to the current user. 18 | /// 19 | [EditorBrowsable (EditorBrowsableState.Advanced)] 20 | public sealed class DPAPIKeychain : FileSystemKeychain 21 | { 22 | protected override byte [] Protect (byte [] data) 23 | => ProtectedData.Protect ( 24 | data, 25 | null, 26 | DataProtectionScope.CurrentUser); 27 | 28 | protected override byte [] Unprotect (byte [] data) 29 | => ProtectedData.Unprotect ( 30 | data, 31 | null, 32 | DataProtectionScope.CurrentUser); 33 | } 34 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychains/FileSystemKeychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.IO; 11 | 12 | namespace Xamarin.Security.Keychains 13 | { 14 | /// 15 | /// An abstract base class implementation for keychains 16 | /// that store items as files in a directory structure, like 17 | /// and . 18 | /// 19 | [EditorBrowsable (EditorBrowsableState.Advanced)] 20 | public abstract class FileSystemKeychain : IKeychain 21 | { 22 | static string GetSecretPath (KeychainSecretName secretName) 23 | => Path.Combine ( 24 | Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData), 25 | "DPAPIKeychain", 26 | secretName.Service, 27 | secretName.Account); 28 | 29 | public bool TryGetSecret (KeychainSecretName name, out KeychainSecret secret) 30 | { 31 | var secretPath = GetSecretPath (name); 32 | if (!File.Exists (secretPath)) { 33 | secret = null; 34 | return false; 35 | } 36 | 37 | secret = KeychainSecret.Create ( 38 | name, 39 | Unprotect (File.ReadAllBytes (secretPath))); 40 | 41 | return true; 42 | } 43 | 44 | public void StoreSecret (KeychainSecret secret, bool updateExisting = true) 45 | { 46 | var secretPath = GetSecretPath (secret.Name); 47 | if (!updateExisting && File.Exists (secretPath)) 48 | throw new KeychainItemAlreadyExistsException ( 49 | $"'{secret.Name}' already exists"); 50 | 51 | Directory.CreateDirectory (Path.GetDirectoryName (secretPath)); 52 | 53 | File.WriteAllBytes (secretPath, Protect ((byte [])secret.Value)); 54 | } 55 | 56 | protected abstract byte [] Protect (byte [] data); 57 | 58 | protected abstract byte [] Unprotect (byte [] data); 59 | } 60 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychains/IKeychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System.ComponentModel; 9 | 10 | namespace Xamarin.Security.Keychains 11 | { 12 | [EditorBrowsable (EditorBrowsableState.Advanced)] 13 | public interface IKeychain 14 | { 15 | bool TryGetSecret (KeychainSecretName name, out KeychainSecret secret); 16 | 17 | void StoreSecret (KeychainSecret secret, bool updateExisting = true); 18 | } 19 | 20 | [EditorBrowsable (EditorBrowsableState.Advanced)] 21 | public static class IKeychainExtensions 22 | { 23 | public static bool TryGetSecret ( 24 | this IKeychain keychain, 25 | string serviceName, 26 | string accountName, 27 | out string secret) 28 | { 29 | if (keychain.TryGetSecret (((serviceName, accountName)), out var fullSecret)) { 30 | secret = fullSecret.GetUtf8StringValue (); 31 | return true; 32 | } 33 | 34 | secret = null; 35 | return false; 36 | } 37 | 38 | public static bool TryGetSecretBytes ( 39 | this IKeychain keychain, 40 | string serviceName, 41 | string accountName, 42 | out byte [] secret) 43 | { 44 | if (keychain.TryGetSecret (((serviceName, accountName)), out var fullSecret)) { 45 | secret = (byte [])fullSecret.Value; 46 | return true; 47 | } 48 | 49 | secret = null; 50 | return false; 51 | } 52 | 53 | public static void StoreSecret ( 54 | this IKeychain keychain, 55 | string serviceName, 56 | string accountName, 57 | string secret, 58 | bool updateExisting = true) 59 | => keychain.StoreSecret ( 60 | KeychainSecret.Create ( 61 | (serviceName, accountName), 62 | secret), 63 | updateExisting); 64 | 65 | public static void StoreSecret ( 66 | this IKeychain keychain, 67 | string serviceName, 68 | string accountName, 69 | byte [] secret, 70 | bool updateExisting = true) 71 | => keychain.StoreSecret ( 72 | KeychainSecret.Create ( 73 | (serviceName, accountName), 74 | secret), 75 | updateExisting); 76 | } 77 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychains/ManagedProtectionKeychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Security.Cryptography; 11 | 12 | using Mono.Security.Cryptography; 13 | 14 | namespace Xamarin.Security.Keychains 15 | { 16 | /// 17 | /// An implementation backed by Mono's DPAPI-compatible 18 | /// [`Mono.Security.Cryptography.ManagedProtection`](https://github.com/mono/mono/blob/master/mcs/class/System.Security/Mono.Security.Cryptography/ManagedProtection.cs). 19 | /// 20 | [EditorBrowsable (EditorBrowsableState.Advanced)] 21 | public sealed class ManagedProtectionKeychain : FileSystemKeychain 22 | { 23 | protected override byte [] Protect (byte [] data) 24 | => ManagedProtection.Protect ( 25 | data, 26 | null, 27 | DataProtectionScope.CurrentUser); 28 | 29 | protected override byte [] Unprotect (byte [] data) 30 | => ManagedProtection.Unprotect ( 31 | data, 32 | null, 33 | DataProtectionScope.CurrentUser); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Keychains/OSKeychain.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.ComponentModel; 10 | using System.Runtime.InteropServices; 11 | 12 | namespace Xamarin.Security.Keychains 13 | { 14 | /// 15 | /// An implementation backed by on macOS, 16 | /// on Windows, and on 17 | /// other platforms. 18 | /// 19 | [EditorBrowsable (EditorBrowsableState.Advanced)] 20 | public sealed class OSKeychain : IKeychain 21 | { 22 | readonly IKeychain keychain; 23 | 24 | public OSKeychain () 25 | { 26 | if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) 27 | keychain = new AppleKeychain (); 28 | else if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) 29 | keychain = new DPAPIKeychain (); 30 | else 31 | keychain = new ManagedProtectionKeychain (); 32 | } 33 | 34 | public bool TryGetSecret (KeychainSecretName name, out KeychainSecret secret) 35 | => keychain.TryGetSecret (name, out secret); 36 | 37 | public void StoreSecret (KeychainSecret secret, bool updateExisting = true) 38 | => keychain.StoreSecret (secret, updateExisting); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Mono.Security.Cryptography/Locale.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Locale.cs 3 | // 4 | // Author: 5 | // Aaron Bockover 6 | // 7 | // Copyright 2017 Microsoft. All rights reserved. 8 | 9 | namespace Mono.Security.Cryptography 10 | { 11 | static class Locale 12 | { 13 | public static string GetText (string message, params object [] args) 14 | => string.Format (message, args); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Xamarin.Security.Keychain/Xamarin.Security.Keychain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | A simple API for storing simple key/value secrets securely on macOS using 6 | the login keychain or via DPAPI on Windows. 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Xamarin.XunitHelpers/GB18030TestData.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System; 9 | using System.Collections; 10 | using System.Collections.Generic; 11 | 12 | namespace Xunit 13 | { 14 | public class GB18030TestDataWithNullAndEmpty : IEnumerable 15 | { 16 | static readonly List testStrings = new List { 17 | new [] { "Null", null }, 18 | new [] { "Empty", string.Empty } 19 | }; 20 | 21 | static GB18030TestDataWithNullAndEmpty () 22 | => testStrings.AddRange (GB18030TestData.testStrings); 23 | 24 | public virtual IEnumerator GetEnumerator () 25 | => testStrings.GetEnumerator (); 26 | 27 | IEnumerator IEnumerable.GetEnumerator () 28 | => GetEnumerator (); 29 | } 30 | 31 | public class GB18030TestData : IEnumerable 32 | { 33 | // Test data adapted from Workbooks: 34 | // https://github.com/Microsoft/workbooks/blob/master/Tests/Workbooks/Regression/GB18030.workbook 35 | internal static readonly List testStrings = new List { 36 | new [] { "Single Byte", "!\"#)6=@Aa}~" }, 37 | new [] { "Double Byte", "啊齄丂狛狜隣郎隣兀﨩ˊ▇█〞〡¦TEL(株)‐ー*+@、〓ix1.€(一)(十)IXII!¯ぁんァヶΑ_АЯаяāɡㄅㄩ─╋(』【—__ixɑ ɡ〇〾⿻⺁ 䜣 €" }, 38 | new [] { "Four byte (Ext-A)", "㐀㒣㕴㕵㙉㙊䵯䵰䶴䶵" }, 39 | new [] { "Four byte (Ext-B, Optional, not supported on macOS out of the box)", "𪛖𪛕𪛔𪛓𪛒𪛑𠀃𠀂𠀁𠀀" }, 40 | new [] { "Four byte (Mongolian)", "᠀᠐᠙ᠠᡷᢀᡨᡩᡪᡫ" }, 41 | new [] { "Four byte (Tibetan)", "ༀཇཉཪཱྋ྾࿌࿏ྼྼ" }, 42 | new [] { "Four byte (Yi)", "ꀀ ꒌ ꂋ ꂌ ꂍ ꂎ ꂔ ꂕ ꒐ ꓆" }, 43 | new [] { "Four byte (Uighur)", "پپڭیئبلإلا،؟ئبتجدرشعە" }, 44 | new [] { "Four byte (Tai Le)", "ᥐᥥᥦᥧᥨᥭᥰᥱᥲᥴ" }, 45 | new [] { "Four byte (Hangul)", "ᄓᄕᇬᇌᇜᇱ기가힝" }, 46 | new [] { "Emoji", "🥑🌮🍔🐈" } 47 | }; 48 | 49 | public static int GetIndexOfStringDescription (string stringDescription) 50 | => testStrings.FindIndex (item => (string)item [0] == stringDescription); 51 | 52 | public IEnumerator GetEnumerator () 53 | => testStrings.GetEnumerator (); 54 | 55 | IEnumerator IEnumerable.GetEnumerator () 56 | => GetEnumerator (); 57 | } 58 | } -------------------------------------------------------------------------------- /src/Xamarin.XunitHelpers/OSFactAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System.Linq; 9 | using System.Runtime.InteropServices; 10 | 11 | namespace Xunit 12 | { 13 | public class WindowsFactAttribute : OSFactAttribute 14 | { 15 | public WindowsFactAttribute () : base (OSPlatform.Windows) 16 | { 17 | } 18 | } 19 | 20 | public class LinuxFactAttribute : OSFactAttribute 21 | { 22 | public LinuxFactAttribute () : base (OSPlatform.Linux) 23 | { 24 | } 25 | } 26 | 27 | public class MacFactAttribute : OSFactAttribute 28 | { 29 | public MacFactAttribute () : base (OSPlatform.OSX) 30 | { 31 | } 32 | } 33 | 34 | public class UnixFactAttribute : OSFactAttribute 35 | { 36 | public UnixFactAttribute () : base (OSPlatform.Linux, OSPlatform.OSX) 37 | { 38 | } 39 | } 40 | 41 | public class WindowsMacFactAttribute : OSFactAttribute 42 | { 43 | public WindowsMacFactAttribute () : base (OSPlatform.Windows, OSPlatform.OSX) 44 | { 45 | } 46 | } 47 | 48 | public class OSFactAttribute : FactAttribute 49 | { 50 | readonly string osSkipString; 51 | 52 | string skipReason; 53 | public override string Skip { 54 | get { 55 | if (osSkipString == null) 56 | return null; 57 | 58 | if (skipReason == null) 59 | return osSkipString; 60 | 61 | return $"{osSkipString}: {skipReason}"; 62 | } 63 | 64 | set => skipReason = value; 65 | } 66 | 67 | protected OSFactAttribute (params OSPlatform [] osPlatforms) 68 | : this (osPlatforms.Select (osPlatform => osPlatform.ToString ()).ToArray ()) 69 | { 70 | } 71 | 72 | public OSFactAttribute (params string [] osNames) 73 | { 74 | foreach (var osName in osNames) { 75 | if (RuntimeInformation.IsOSPlatform (OSPlatform.Create (osName.ToUpperInvariant ()))) 76 | return; 77 | } 78 | 79 | osSkipString = $"Only available on {string.Join (", ", osNames)}"; 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Xamarin.XunitHelpers/OSTheoryAttribute.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Author: 3 | // Aaron Bockover 4 | // 5 | // Copyright (c) Microsoft Corporation. All rights reserved. 6 | // Licensed under the MIT License. 7 | 8 | using System.Linq; 9 | using System.Runtime.InteropServices; 10 | 11 | namespace Xunit 12 | { 13 | public class WindowsTheoryAttribute : OSTheoryAttribute 14 | { 15 | public WindowsTheoryAttribute () : base (OSPlatform.Windows) 16 | { 17 | } 18 | } 19 | 20 | public class LinuxTheoryAttribute : OSTheoryAttribute 21 | { 22 | public LinuxTheoryAttribute () : base (OSPlatform.Linux) 23 | { 24 | } 25 | } 26 | 27 | public class MacTheoryAttribute : OSTheoryAttribute 28 | { 29 | public MacTheoryAttribute () : base (OSPlatform.OSX) 30 | { 31 | } 32 | } 33 | 34 | public class UnixTheoryAttribute : OSTheoryAttribute 35 | { 36 | public UnixTheoryAttribute () : base (OSPlatform.Linux, OSPlatform.OSX) 37 | { 38 | } 39 | } 40 | 41 | public class WindowsMacTheoryAttribute : OSTheoryAttribute 42 | { 43 | public WindowsMacTheoryAttribute () : base (OSPlatform.Windows, OSPlatform.OSX) 44 | { 45 | } 46 | } 47 | 48 | public class OSTheoryAttribute : TheoryAttribute 49 | { 50 | readonly string osSkipString; 51 | 52 | string skipReason; 53 | public override string Skip { 54 | get { 55 | if (osSkipString == null) 56 | return null; 57 | 58 | if (skipReason == null) 59 | return osSkipString; 60 | 61 | return $"{osSkipString}: {skipReason}"; 62 | } 63 | 64 | set => skipReason = value; 65 | } 66 | 67 | protected OSTheoryAttribute (params OSPlatform [] osPlatforms) 68 | : this (osPlatforms.Select (osPlatform => osPlatform.ToString ()).ToArray ()) 69 | { 70 | } 71 | 72 | public OSTheoryAttribute (params string [] osNames) 73 | { 74 | foreach (var osName in osNames) { 75 | if (RuntimeInformation.IsOSPlatform (OSPlatform.Create (osName.ToUpperInvariant ()))) 76 | return; 77 | } 78 | 79 | osSkipString = $"Only available on {string.Join (", ", osNames)}"; 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/Xamarin.XunitHelpers/Xamarin.XunitHelpers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | Small xUnit helper APIs like [MacFact], [WindowsFact], [LinuxFact], [UnixFact]. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tools/ILRepackPatcher/ILRepackPatcher.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------