├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── ---support-request.md │ ├── --bug.md │ ├── --feature-request.md │ └── --thank-you.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml ├── lock.yml ├── stale.yml ├── support.yml └── workflows │ ├── build-and-test.yml │ └── dependabot-auto-merge.yml ├── .gitignore ├── GitReleaseManager.yaml ├── GitVersion.yml ├── LICENSE ├── build.cake ├── build.ps1 ├── cake.config ├── deployment └── cake │ ├── apps-uwp-tasks.cake │ ├── apps-uwp-variables.cake │ ├── apps-wpf-tasks.cake │ ├── apps-wpf-variables.cake │ ├── buildserver-continuaci.cake │ ├── buildserver.cake │ ├── codesigning-tasks.cake │ ├── codesigning-variables.cake │ ├── components-tasks.cake │ ├── components-variables.cake │ ├── dependencies-tasks.cake │ ├── dependencies-variables.cake │ ├── docker-tasks.cake │ ├── docker-variables.cake │ ├── generic-tasks.cake │ ├── generic-variables.cake │ ├── github-pages-tasks.cake │ ├── github-pages-variables.cake │ ├── installers-innosetup.cake │ ├── installers-msix.cake │ ├── installers-squirrel.cake │ ├── installers-velopack.cake │ ├── installers.cake │ ├── issuetrackers-github.cake │ ├── issuetrackers-jira.cake │ ├── issuetrackers.cake │ ├── lib-generic.cake │ ├── lib-logging.cake │ ├── lib-msbuild.cake │ ├── lib-nuget.cake │ ├── lib-signing.cake │ ├── lib-sourcelink.cake │ ├── notifications-msteams.cake │ ├── notifications.cake │ ├── sourcecontrol-github.cake │ ├── sourcecontrol.cake │ ├── tasks.cake │ ├── templates-tasks.cake │ ├── templates-variables.cake │ ├── tests-nunit.cake │ ├── tests-variables.cake │ ├── tests.cake │ ├── tools-tasks.cake │ ├── tools-variables.cake │ ├── vsextensions-tasks.cake │ └── vsextensions-variables.cake ├── design ├── logo │ └── package_icon.png └── package │ └── icon.png ├── readme.md ├── src ├── .vsconfig ├── AssemblyToProcess │ ├── AssemblyToProcess.csproj │ └── ClassToTest.cs ├── AssemblyToReference │ ├── AssemblyToReference.csproj │ ├── ClassToReference.cs │ ├── strings.Designer.cs │ ├── strings.de.resx │ ├── strings.fr.resx │ ├── strings.resx │ ├── strings.zh-CN.resx │ └── strings.zh-Hans.resx ├── AssemblyToReferenceMixed │ ├── AssemblyToReferenceMixed.vcxproj │ ├── AssemblyToReferenceMixed.vcxproj.filters │ ├── ClassToReferenceMixed.cpp │ └── Native.cpp ├── AssemblyToReferenceNative │ ├── AssemblyToReferenceNative.vcxproj │ ├── AssemblyToReferenceNative.vcxproj.filters │ └── Native.cpp ├── AssemblyToReferencePreEmbedded │ ├── AssemblyToReferencePreEmbedded.csproj │ └── ClassToReferencePreEmbedded.cs ├── AssemblyToReferenceWithRuntimeReferences │ ├── AssemblyToReferenceWithRuntimeReferences.csproj │ └── RuntimeReferences.cs ├── AssemblyWithoutInitialize │ ├── AssemblyWithoutInitialize.csproj │ └── ClassToTest.cs ├── Costura.Fody.IntegrationTests │ ├── Costura.Fody.IntegrationTests.csproj │ ├── FodyWeavers.xml │ └── Integration.cs ├── Costura.Fody.Tests │ ├── AssemblyExtensions.cs │ ├── BaseCosturaTest.cs │ ├── BasicTests.cs │ ├── ConfigReaderTests.cs │ ├── Costura.Fody.Tests.csproj │ ├── CultureResourceTests.cs │ ├── Helpers │ │ ├── AssemblyDirectoryHelper.cs │ │ ├── AssemblyHelper.cs │ │ ├── CultureResourceTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── CultureResourceTests.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── CultureResourceTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── CultureResourceTests.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── InMemoryTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── InMemoryTests.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── InMemoryTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── InMemoryTests.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── InitializeCallTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── InitializeCallTests.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── InitializeCallTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── InitializeCallTests.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── InitializeCallWithoutModuleInitTest.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── InitializeCallWithoutModuleInitTest.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── InitializeCallWithoutModuleInitTest.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── InitializeCallWithoutModuleInitTest.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── MixedAndNativeTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── MixedAndNativeTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── NoEventSubscriptionTest.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── NoEventSubscriptionTest.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── NoEventSubscriptionTest.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── NoEventSubscriptionTest.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── ReferenceCasingTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── ReferenceCasingTests.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── ReferenceCasingTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── ReferenceCasingTests.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── RunHelper.cs │ │ ├── TempFileTests.TemplateHasCorrectSymbols.DotNet8_0.Debug.verified.txt │ │ ├── TempFileTests.TemplateHasCorrectSymbols.DotNet8_0.Release.verified.txt │ │ ├── TempFileTests.TemplateHasCorrectSymbols.Net4_7.Debug.verified.txt │ │ ├── TempFileTests.TemplateHasCorrectSymbols.Net4_7.Release.verified.txt │ │ ├── VerifyHelper.cs │ │ └── WeavingHelper.cs │ ├── Ildasm.cs │ ├── InMemoryTests.cs │ ├── InitializeCallTests.cs │ ├── InitializeCallWithoutModuleInitTest.cs │ ├── MixedAndNativeTests.cs │ ├── MixedAndNativeTestsWithEmbeddedMixed.cs │ ├── MultipleNativeTests.cs │ ├── MultipleNativeTestsWithPreloadOrder.cs │ ├── NativeTests.cs │ ├── NoEventSubscriptionTest.cs │ ├── NoInitializeTest.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ReferenceCasingTests.cs │ ├── ReferenceMissingTests.cs │ ├── ReferenceTests.cs │ ├── ResourceEmbedderTests.cs │ ├── RuntimeReferencesTests.cs │ ├── TempFileTests.cs │ └── WildcardTest.cs ├── Costura.Fody.sln ├── Costura.Fody.sln.DotSettings ├── Costura.Fody │ ├── AssemblyLoaderImporter.cs │ ├── CallAttach.cs │ ├── Checksums.cs │ ├── Configuration.cs │ ├── Costura.Fody.csproj │ ├── Costura.Fody.props │ ├── Costura.Fody.targets │ ├── Costura.Fody.xcf │ ├── EmbeddedReferenceInfo.cs │ ├── Extensions │ │ ├── AssemblyExtensions.cs │ │ ├── CecilExtensions.assembly.cs │ │ └── Extensions.cs │ ├── HashCalculator.cs │ ├── ModuleWeaver.cs │ ├── MsCoreReferenceFinder.cs │ ├── NativeResources.cs │ ├── NetStandardAssemblyResolver.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Reference.cs │ ├── ResourceCaseFixer.cs │ ├── ResourceEmbedder.cs │ └── ResourceNameFinder.cs ├── Costura.Template │ ├── Common.cs │ ├── Costura.Template.csproj │ ├── ILTemplate.cs │ ├── ILTemplateWithTempAssembly.cs │ ├── ILTemplateWithUnmanagedHandler.cs │ └── Properties │ │ └── AssemblyInfo.cs ├── Costura │ ├── Costura.csproj │ ├── CosturaUtility.cs │ └── Properties │ │ └── AssemblyInfo.cs ├── Directory.Build.analyzers.props ├── Directory.Build.implicitusings.props ├── Directory.Build.nullable.props ├── Directory.Build.project.props ├── Directory.Build.props ├── Directory.Build.shared.explicit.props ├── Directory.Build.shared.implicit.props ├── Directory.Build.shared.mat.props ├── Directory.Build.shared.tests.props ├── Directory.Build.shared.tools.props ├── Directory.Build.shared.xamltools.props ├── Directory.Build.targets ├── ExeToProcess │ ├── ClassToTest.cs │ ├── ExeToProcess.csproj │ └── Program.cs ├── ExeToProcessWithMultipleNative │ ├── ExeToProcessWithMultipleNative.csproj │ ├── Program.cs │ └── QueueHelper.cs ├── ExeToProcessWithNative │ ├── ClassToTest.cs │ └── ExeToProcessWithNative.csproj ├── ExeToProcessWithNativeAndEmbeddedMixed │ ├── ClassToTest.cs │ └── ExeToProcessWithNativeAndEmbeddedMixed.csproj ├── ExeToReference │ ├── ExeToReference.csproj │ └── Program.cs ├── MethodTimeLogger.cs ├── Settings.StyleCop ├── SolutionAssemblyInfo.cs ├── global.json ├── key.snk └── nuget.config └── tools └── nuget.exe /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "cake.tool": { 6 | "version": "5.0.0", 7 | "commands": [ 8 | "dotnet-cake" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | .editorconfig -text 6 | *.sln.DotSettings -text 7 | 8 | ############################################################################### 9 | # Set default behavior for command prompt diff. 10 | # 11 | # This is need for earlier builds of msysgit that does not have it on by 12 | # default for csharp files. 13 | # Note: This is only used by command line 14 | ############################################################################### 15 | #*.cs diff=csharp 16 | 17 | ############################################################################### 18 | # Set the merge driver for project and solution files 19 | # 20 | # Merging from the command prompt will add diff markers to the files if there 21 | # are conflicts (Merging from VS is not affected by the settings below, in VS 22 | # the diff markers are never inserted). Diff markers may cause the following 23 | # file extensions to fail to load in VS. An alternative would be to treat 24 | # these files as binary and thus will always conflict and require user 25 | # intervention with every merge. To do so, just uncomment the entries below 26 | ############################################################################### 27 | #*.sln merge=binary 28 | #*.csproj merge=binary 29 | #*.vbproj merge=binary 30 | #*.vcxproj merge=binary 31 | #*.vcproj merge=binary 32 | #*.dbproj merge=binary 33 | #*.fsproj merge=binary 34 | #*.lsproj merge=binary 35 | #*.wixproj merge=binary 36 | #*.modelproj merge=binary 37 | #*.sqlproj merge=binary 38 | #*.wwaproj merge=binary 39 | 40 | ############################################################################### 41 | # behavior for image files 42 | # 43 | # image files are treated as binary by default. 44 | ############################################################################### 45 | #*.jpg binary 46 | #*.png binary 47 | #*.gif binary 48 | 49 | ############################################################################### 50 | # diff behavior for common document formats 51 | # 52 | # Convert binary document formats to text before diffing them. This feature 53 | # is only available from the command line. Turn it on by uncommenting the 54 | # entries below. 55 | ############################################################################### 56 | #*.doc diff=astextplain 57 | #*.DOC diff=astextplain 58 | #*.docx diff=astextplain 59 | #*.DOCX diff=astextplain 60 | #*.dot diff=astextplain 61 | #*.DOT diff=astextplain 62 | #*.pdf diff=astextplain 63 | #*.PDF diff=astextplain 64 | #*.rtf diff=astextplain 65 | #*.RTF diff=astextplain 66 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thanks you for your interest in contributing - Please see our our [Code of Conduct](CODE_OF_CONDUCT.md). 4 | 5 | 6 | ### Bug Fixes 7 | 8 | If you're looking for something to fix, please browse the open issues. 9 | 10 | Follow the style used by the [.NET Foundation](https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md), with a few exceptions: 11 | 12 | - Apply readonly on class level private variables that are assigned in the constructor 13 | - 4 SPACES - tabs do not exist :) 14 | 15 | Read and follow our [Pull Request template](PULL_REQUEST_TEMPLATE.md) if you are submitting fixes. 16 | 17 | ### Feature Requests 18 | 19 | To propose a change or new feature, please make use the feature request area in issues. 20 | 21 | #### Non-Starter Topics 22 | The following topics should generally not be proposed for discussion as they are non-starters: 23 | 24 | * Large renames of APIs 25 | * Large non-backward-compatible breaking changes 26 | * Avoid clutter posts like "+1" which do not serve to further the conversation 27 | 28 | #### Proposal States 29 | ##### Open 30 | Open proposals are still under discussion. Please leave your concrete, constructive feedback on this proposal. +1s and other clutter posts which do not add to the discussion will be removed. 31 | 32 | ##### Accepted 33 | Accepted proposals are proposals that both the community and core team agree should be a part of projects. These proposals are ready for implementation. These proposals are available for anyone to work on unless it is already assigned to someone. 34 | 35 | If you wish to start working on an accepted proposal, please reply to the thread so we can mark you as the implementor and change the title to In Progress. This helps to avoid multiple people working on the same thing. If you decide to work on this proposal publicly, feel free to post a link to the branch as well for folks to follow along. 36 | 37 | ###### What "Accepted" does mean 38 | * Any community member is welcome to work on the idea. 39 | * The maintainers _may_ consider working on this idea on their own, but has not done so until it is marked "In Progress" with a team member assigned as the implementor. 40 | * Any pull request implementing the proposal will be welcomed with an API and code review. 41 | 42 | ###### What "Accepted" does not mean 43 | * The proposal will ever be implemented, either by a community member or maintainers. 44 | * The maintainers are committing to implementing a proposal, even if nobody else does. 45 | 46 | ##### In Progress 47 | Once a developer has begun work on a proposal, either from the team or a community member, the proposal is marked as in progress with the implementors name and (possibly) a link to a development branch to follow along with progress. 48 | 49 | #### Rejected 50 | Rejected proposals will not be implemented or merged into the code base. Once a proposal is rejected, the thread will be closed and the conversation is considered completed, pending considerable new information or changes.. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/---support-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F62C Support Request" 3 | about: Having Trouble - ONLY contributors to other OSS projects OR people who are 4 | funding this project can submit these! If you aren't one of these, expect the ban 5 | hammer to fall 6 | title: '' 7 | labels: '' 8 | assignees: '' 9 | 10 | --- 11 | 12 | ONLY active OSS contributors OR people who buy us a coffee can ask questions here. If you don't do either of these things - DO NOT FILE HERE :) 13 | 14 | Give as much details as humanly possible if you want any sort of answer! 15 | 16 | Enter Question Below (don't delete this line) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F99FBug" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: "s/unverified, t/bug \U0001F47E" 6 | assignees: '' 7 | 8 | --- 9 | 10 | # IF YOU DON'T ANSWER THIS TEMPLATE - THE BOT WILL AUTOMATICALLY CLOSE YOUR ISSUE! 11 | 12 | ## Please check all of the platforms you are having the issue on (if platform is not listed, it is not supported) 13 | 14 | - [ ] WPF 15 | - [ ] Blazor WASM 16 | - [ ] .NET Core 17 | 18 | ## Component 19 | 20 | What component is this issue occurring in? 21 | 22 | ## Version of Library 23 | 24 | 25 | ## Version of OS(s) listed above with issue 26 | 27 | 28 | ## Steps to Reproduce 29 | 1. 30 | 2. 31 | 3. 32 | 33 | ## Expected Behavior 34 | 35 | 36 | ## Actual Behavior -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F354Feature Request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: "s/unverified, t/enhancement \U0001F423" 6 | assignees: '' 7 | 8 | --- 9 | 10 | # IF YOU DON'T ANSWER THIS TEMPLATE - THE BOT WILL AUTOMATICALLY CLOSE YOUR ISSUE! 11 | 12 | ## Summary 13 | Please provide a brief summary of your proposal. Two to three sentences is best here. 14 | 15 | ## API Changes 16 | Include a list of all API changes, additions, subtractions as would be required by your proposal. These APIs should be considered placeholders, so the naming is not as important as getting the concepts correct. If possible you should include some "example" code of usage of your new API. 17 | 18 | ## Intended Use Case 19 | Provide a detailed example of where your proposal would be used and for what purpose. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/--thank-you.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "❤️Thank You" 3 | about: Just want to say thank you, this is the one to do it in 4 | title: Thank You 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Leave Your Message Below (don't delete this line though) -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description of Change ### 2 | 3 | 4 | 5 | ### Issues Resolved ### 6 | 7 | 8 | 9 | - fixes # 10 | 11 | ### API Changes ### 12 | 13 | 14 | 15 | None 16 | 17 | ### Behavioral Changes ### 18 | 19 | 20 | 21 | None 22 | 23 | ### Testing Procedure ### 24 | 25 | 26 | 27 | ### PR Checklist ### 28 | 29 | - [ ] I have included examples or tests 30 | - [ ] I have updated the change log or created a GitHub ticket with the change 31 | - [ ] I am listed in the CONTRIBUTORS file (if it exists) 32 | - [ ] Changes adhere to coding standard 33 | - [ ] I checked the licenses of Third Party software and discussed new dependencies with at least 1 other team member -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | registries: 3 | nuget-feed-default: 4 | type: nuget-feed 5 | url: https://api.nuget.org/v3/index.json 6 | 7 | updates: 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | 13 | - package-ecosystem: nuget 14 | directories: 15 | - "/src" 16 | schedule: 17 | interval: daily 18 | open-pull-requests-limit: 10 19 | ignore: 20 | - dependency-name: "*Analyzers" 21 | versions: 22 | - ">= 0" 23 | registries: 24 | - nuget-feed-default -------------------------------------------------------------------------------- /.github/lock.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Lock Threads - https://github.com/dessant/lock-threads 2 | 3 | # Number of days of inactivity before a closed issue or pull request is locked 4 | daysUntilLock: 4 5 | 6 | # Skip issues and pull requests created before a given timestamp. Timestamp must 7 | # follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable 8 | skipCreatedBefore: false 9 | 10 | # Issues and pull requests with these labels will be ignored. Set to `[]` to disable 11 | exemptLabels: ["pinned", "planned"] 12 | 13 | # Label to add before locking, such as `outdated`. Set to `false` to disable 14 | lockLabel: false 15 | 16 | # Comment to post before locking. Set to `false` to disable 17 | lockComment: > 18 | This thread has been automatically locked since there has not been 19 | any recent activity after it was closed. Please open a new issue for 20 | related bugs. 21 | 22 | # Assign `resolved` as the reason for locking. Set to `false` to disable 23 | setLockReason: true 24 | 25 | # Limit to only `issues` or `pulls` 26 | # only: issues 27 | 28 | # Optionally, specify configuration settings just for `issues` or `pulls` 29 | # issues: 30 | # exemptLabels: 31 | # - help-wanted 32 | # lockLabel: outdated 33 | 34 | # pulls: 35 | # daysUntilLock: 30 36 | 37 | # Repository to extend settings from 38 | # _extends: repo -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - planned 10 | - nostale 11 | # Label to use when marking an issue as stale 12 | staleLabel: wontfix 13 | # Comment to post when marking an issue as stale. Set to `false` to disable 14 | markComment: > 15 | This issue has been automatically marked as stale because it has not had 16 | recent activity. It will be closed if no further activity occurs. Thank you 17 | for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false -------------------------------------------------------------------------------- /.github/support.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Support Requests - https://github.com/dessant/support-requests 2 | 3 | # Label used to mark issues as support requests 4 | supportLabel: support 5 | 6 | # Comment to post on issues marked as support requests, `{issue-author}` is an 7 | # optional placeholder. Set to `false` to disable 8 | supportComment: > 9 | :wave: @{issue-author}, we use the issue tracker exclusively for bug reports 10 | and feature requests. However, this issue appears to be a support request. 11 | Please use our support channels to get help with the project. 12 | 13 | # Close issues marked as support requests 14 | close: true 15 | 16 | # Lock issues marked as support requests 17 | lock: false 18 | 19 | # Assign `off-topic` as the reason for locking. Set to `false` to disable 20 | setLockReason: true 21 | 22 | # Repository to extend settings from 23 | # _extends: repo -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: 4 | push: 5 | branches: 6 | - develop 7 | - master 8 | pull_request: 9 | 10 | #permissions: 11 | #pull-requests: write 12 | #contents: write 13 | 14 | jobs: 15 | build-and-test: 16 | runs-on: windows-latest # Required for some (WPF) projects 17 | 18 | steps: 19 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 20 | id: checkout 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Setup .NET Core 25 | id: setup-dotnet 26 | uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4.3.1 27 | with: 28 | dotnet-version: '9.0.x' 29 | 30 | - name: Cake Action 31 | id: cake-action 32 | uses: cake-build/cake-action@5167c3f6a9e15c76f009de2acdfb9488552bc0b9 #v3.0.0 33 | with: 34 | target: BuildAndTest 35 | arguments: | 36 | IsCiBuild: true -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request_target 3 | permissions: 4 | pull-requests: write 5 | contents: write 6 | jobs: 7 | dependabot: 8 | runs-on: ubuntu-latest 9 | # Checking the actor will prevent your Action run failing on non-Dependabot PRs 10 | if: ${{ github.actor == 'dependabot[bot]' }} 11 | steps: 12 | - name: Dependabot metadata 13 | id: dependabot-metadata 14 | uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b #2.4.0 15 | with: 16 | github-token: "${{ secrets.GITHUB_TOKEN }}" 17 | - name: Approve Dependabot PR 18 | run: gh pr review --approve "$PR_URL" 19 | env: 20 | PR_URL: ${{github.event.pull_request.html_url}} 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 22 | - name: Enable auto-merge for Dependabot PRs 23 | if: | 24 | (startsWith(steps.dependabot-metadata.outputs.dependency-names, 'catel.') || 25 | startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orc.') || 26 | startsWith(steps.dependabot-metadata.outputs.dependency-names, 'orchestra.')) && 27 | (steps.dependabot-metadata.outputs.update-type == 'version-update:semver-minor' || 28 | steps.dependabot-metadata.outputs.update-type == 'version-update:semver-patch') 29 | run: gh pr merge --auto --merge "$PR_URL" 30 | env: 31 | PR_URL: ${{github.event.pull_request.html_url}} 32 | PR_NUMBER: ${{github.event.pull_request.number}} 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | .nuget/ 10 | tools/FAKE/ 11 | build-log.xml 12 | Nuget.key 13 | TestResult.xml 14 | 15 | # Build results 16 | [Bb]in/ 17 | [Cc]lientbin/ 18 | [Dd]ebug/ 19 | [Rr]elease/ 20 | [Oo]utput*/ 21 | [Pp]ackages*/ 22 | [Tt]emp/ 23 | bin 24 | obj 25 | [Ll]ib/* 26 | ![Ll]ib/repositories.config 27 | *.ide/ 28 | *_i.c 29 | *_p.c 30 | *.ilk 31 | *.meta 32 | *.obj 33 | *.orig 34 | *.pch 35 | *.pdb 36 | *.pgc 37 | *.pgd 38 | *.rsp 39 | *.sbr 40 | *.tlb 41 | *.tli 42 | *.tlh 43 | *.tmp 44 | *.vspscc 45 | *.xap 46 | .builds 47 | *.log 48 | 49 | # Visual C++ cache files 50 | ipch/ 51 | *.aps 52 | *.ncb 53 | *.opensdf 54 | *.sdf 55 | 56 | # Visual Studio profiler 57 | *.psess 58 | *.vsp 59 | 60 | # ReSharper is a .NET coding add-in 61 | _ReSharper* 62 | *.resharper.user 63 | 64 | # Catel 65 | CatelLogging.txt 66 | 67 | # Dotcover 68 | *.dotCover 69 | *.dotsettings.user 70 | 71 | # Finalbuilder 72 | *.fbl7 73 | *.fb7lck 74 | *.fbpInf 75 | 76 | # Ghostdoc 77 | *.GhostDoc.xml 78 | 79 | # Deployments 80 | deployment/FinalBuilder/backup 81 | deployment/InnoSetup/template/templates 82 | deployment/InnoSetup/template/snippets 83 | deployment/InnoSetup/template/libraries 84 | deployment/InnoSetup/template/doc 85 | 86 | # Installshield output folder 87 | [Ee]xpress 88 | 89 | # DocProject is a documentation generator add-in 90 | DocProject/buildhelp/ 91 | DocProject/Help/*.HxT 92 | DocProject/Help/*.HxC 93 | DocProject/Help/*.hhc 94 | DocProject/Help/*.hhk 95 | DocProject/Help/*.hhp 96 | DocProject/Help/Html2 97 | DocProject/Help/html 98 | 99 | # Click-Once directory 100 | publish 101 | 102 | # Others 103 | [Bb]in 104 | [Oo]bj 105 | sql 106 | TestResults 107 | *.Cache 108 | ClientBin 109 | stylecop.* 110 | ~$* 111 | *.dbmdl 112 | Generated_Code #added for RIA/Silverlight projects 113 | 114 | # Backup & report files from converting an old project file to a newer 115 | # Visual Studio version. Backup files are not needed, because we have git ;-) 116 | _UpgradeReport_Files/ 117 | Backup*/ 118 | UpgradeLog*.XML 119 | 120 | # Windows image file caches 121 | Thumbs.db 122 | 123 | # Folder config file 124 | Desktop.ini 125 | 126 | # Cake - Uncomment if you are using it 127 | tools/** 128 | !tools/packages.config 129 | build.cakeoverrides 130 | 131 | # mstest test results 132 | TestResults 133 | .vs/ 134 | .sonarqube/ 135 | BundleArtifacts/ 136 | 137 | # docker / tye 138 | .tye 139 | 140 | # editors 141 | .idea 142 | .vscode 143 | 144 | # Binaries 145 | *.dll 146 | *.exe 147 | 148 | # fody 149 | FodyWeavers.xsd 150 | 151 | # Approval tests 152 | *.received.* 153 | 154 | # ANTLR 155 | data/dsl/*.class 156 | data/dsl/*.java 157 | 158 | # Nodejs / NPM 159 | node_modules 160 | package-lock.json 161 | -------------------------------------------------------------------------------- /GitReleaseManager.yaml: -------------------------------------------------------------------------------- 1 | issue-labels-include: 2 | - Breaking change 3 | - Feature 4 | - Bug 5 | - Improvement 6 | - Documentation 7 | - Dependencies 8 | issue-labels-exclude: 9 | - Build 10 | - Won't fix 11 | issue-labels-alias: 12 | - name: Documentation 13 | header: Documentation 14 | plural: Documentation -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: ContinuousDeployment 2 | assembly-versioning-scheme: MajorMinorPatch 3 | next-version: 6.0.0 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2012 Simon Cropp and contributors 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /build.cake: -------------------------------------------------------------------------------- 1 | //======================================================= 2 | // DEFINE PARAMETERS 3 | //======================================================= 4 | 5 | // Define the required parameters 6 | var Parameters = new Dictionary(); 7 | Parameters["SolutionName"] = "Costura.Fody"; 8 | Parameters["Company"] = "Fody"; 9 | Parameters["RepositoryUrl"] = string.Format("https://github.com/{0}/{1}", GetBuildServerVariable("SolutionName"), GetBuildServerVariable("SolutionName")); 10 | Parameters["StartYear"] = "2015"; 11 | Parameters["UseVisualStudioPrerelease"] = "true"; 12 | Parameters["SkipComponentsThatAreNotDeployable"] = "false"; 13 | Parameters["BuildCostura"] = "true"; 14 | Parameters["DeployCostura"] = "false"; 15 | Parameters["NuGet_NoDependencies"] = "false"; 16 | Parameters["TestProcessBit"] = "X86"; 17 | 18 | // Note: the rest of the variables should be coming from the build server, 19 | // see `/deployment/cake/*-variables.cake` for customization options 20 | // 21 | // If required, more variables can be overridden by specifying them via the 22 | // Parameters dictionary, but the build server variables will always override 23 | // them if defined by the build server. For example, to override the code 24 | // sign wild card, add this to build.cake 25 | // 26 | // Parameters["CodeSignWildcard"] = "Orc.EntityFramework"; 27 | 28 | //======================================================= 29 | // DEFINE COMPONENTS TO BUILD / PACKAGE 30 | //======================================================= 31 | 32 | Dependencies.Add("Costura"); 33 | Dependencies.Add("Costura.Template"); 34 | Dependencies.Add("ExeToReference"); 35 | Dependencies.Add("AssemblyToReference"); 36 | Dependencies.Add("AssemblyToReferenceNative"); 37 | Dependencies.Add("AssemblyToReferenceMixed"); 38 | Dependencies.Add("AssemblyToReferencePreEmbedded"); 39 | Dependencies.Add("AssemblyToReferenceWithRuntimeReferences"); 40 | Dependencies.Add("AssemblyWithoutInitialize"); 41 | Dependencies.Add("AssemblyToProcess"); 42 | Dependencies.Add("ExeToProcess"); 43 | Dependencies.Add("ExeToProcessWithNative"); 44 | Dependencies.Add("ExeToProcessWithNativeAndEmbeddedMixed"); 45 | Dependencies.Add("ExeToProcessWithMultipleNative"); 46 | 47 | Components.Add("Costura.Fody"); 48 | Components.Add("Costura"); 49 | 50 | TestProjects.Add("Costura.Fody.Tests"); 51 | 52 | //======================================================= 53 | // REQUIRED INITIALIZATION, DO NOT CHANGE 54 | //======================================================= 55 | 56 | // Now all variables are defined, include the tasks, that 57 | // script will take care of the rest of the magic 58 | 59 | #l "./deployment/cake/tasks.cake" -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = 'Stop' 2 | 3 | Set-Location -LiteralPath $PSScriptRoot 4 | 5 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1' 6 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = '1' 7 | $env:DOTNET_NOLOGO = '1' 8 | 9 | dotnet tool restore 10 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 11 | 12 | dotnet cake @args 13 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } 14 | -------------------------------------------------------------------------------- /cake.config: -------------------------------------------------------------------------------- 1 | ; The configuration file for Cake. 2 | 3 | [Settings] 4 | SkipVerification=true 5 | 6 | [Settings] 7 | EnableScriptCache=true 8 | 9 | [Paths] 10 | ; Cache=%temp%/cake-build/cache/ 11 | ; Note: cache-path is set via environment variables -------------------------------------------------------------------------------- /deployment/cake/apps-uwp-variables.cake: -------------------------------------------------------------------------------- 1 | #l "./buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class UwpContext : BuildContextWithItemsBase 6 | { 7 | public UwpContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string WindowsStoreAppId { get; set; } 13 | public string WindowsStoreClientId { get; set; } 14 | public string WindowsStoreClientSecret { get; set; } 15 | public string WindowsStoreTenantId { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | } 20 | 21 | protected override void LogStateInfoForContext() 22 | { 23 | CakeContext.Information($"Found '{Items.Count}' uwp projects"); 24 | } 25 | } 26 | 27 | //------------------------------------------------------------- 28 | 29 | private UwpContext InitializeUwpContext(BuildContext buildContext, IBuildContext parentBuildContext) 30 | { 31 | var data = new UwpContext(parentBuildContext) 32 | { 33 | Items = UwpApps ?? new List(), 34 | WindowsStoreAppId = buildContext.BuildServer.GetVariable("WindowsStoreAppId", showValue: true), 35 | WindowsStoreClientId = buildContext.BuildServer.GetVariable("WindowsStoreClientId", showValue: false), 36 | WindowsStoreClientSecret = buildContext.BuildServer.GetVariable("WindowsStoreClientSecret", showValue: false), 37 | WindowsStoreTenantId = buildContext.BuildServer.GetVariable("WindowsStoreTenantId", showValue: false) 38 | }; 39 | 40 | return data; 41 | } 42 | 43 | //------------------------------------------------------------- 44 | 45 | List _uwpApps; 46 | 47 | public List UwpApps 48 | { 49 | get 50 | { 51 | if (_uwpApps is null) 52 | { 53 | _uwpApps = new List(); 54 | } 55 | 56 | return _uwpApps; 57 | } 58 | } -------------------------------------------------------------------------------- /deployment/cake/apps-wpf-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class WpfContext : BuildContextWithItemsBase 6 | { 7 | public WpfContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | 13 | public string DeploymentsShare { get; set; } 14 | public string Channel { get; set; } 15 | public bool AppendDeploymentChannelSuffix { get; set; } 16 | public bool UpdateDeploymentsShare { get; set; } 17 | public string AzureDeploymentsStorageConnectionString { get; set; } 18 | 19 | public bool GenerateDeploymentCatalog { get; set; } 20 | public bool GroupUpdatesByMajorVersion { get; set; } 21 | public bool DeployUpdatesToAlphaChannel { get; set; } 22 | public bool DeployUpdatesToBetaChannel { get; set; } 23 | public bool DeployUpdatesToStableChannel { get; set; } 24 | public bool DeployInstallers { get; set; } 25 | 26 | protected override void ValidateContext() 27 | { 28 | 29 | } 30 | 31 | protected override void LogStateInfoForContext() 32 | { 33 | CakeContext.Information($"Found '{Items.Count}' wpf projects"); 34 | 35 | CakeContext.Information($"Generate Deployment Catalog: '{GenerateDeploymentCatalog}'"); 36 | CakeContext.Information($"Group updates by major version: '{GroupUpdatesByMajorVersion}'"); 37 | CakeContext.Information($"Deploy updates to alpha channel: '{DeployUpdatesToAlphaChannel}'"); 38 | CakeContext.Information($"Deploy updates to beta channel: '{DeployUpdatesToBetaChannel}'"); 39 | CakeContext.Information($"Deploy updates to stable channel: '{DeployUpdatesToStableChannel}'"); 40 | CakeContext.Information($"Deploy installers: '{DeployInstallers}'"); 41 | } 42 | 43 | public string GetDeploymentShareForProject(string projectName) 44 | { 45 | var projectSlug = GetProjectSlug(projectName, "-"); 46 | var deploymentShare = System.IO.Path.Combine(DeploymentsShare, projectSlug); 47 | 48 | return deploymentShare; 49 | } 50 | } 51 | 52 | //------------------------------------------------------------- 53 | 54 | private WpfContext InitializeWpfContext(BuildContext buildContext, IBuildContext parentBuildContext) 55 | { 56 | var data = new WpfContext(parentBuildContext) 57 | { 58 | Items = WpfApps ?? new List(), 59 | DeploymentsShare = buildContext.BuildServer.GetVariable("DeploymentsShare", showValue: true), 60 | Channel = buildContext.BuildServer.GetVariable("Channel", showValue: true), 61 | AppendDeploymentChannelSuffix = buildContext.BuildServer.GetVariableAsBool("AppendDeploymentChannelSuffix", false, showValue: true), 62 | UpdateDeploymentsShare = buildContext.BuildServer.GetVariableAsBool("UpdateDeploymentsShare", true, showValue: true), 63 | AzureDeploymentsStorageConnectionString = buildContext.BuildServer.GetVariable("AzureDeploymentsStorageConnectionString"), 64 | GenerateDeploymentCatalog = buildContext.BuildServer.GetVariableAsBool("WpfGenerateDeploymentCatalog", true, showValue: true), 65 | GroupUpdatesByMajorVersion = buildContext.BuildServer.GetVariableAsBool("WpfGroupUpdatesByMajorVersion", false, showValue: true), 66 | DeployUpdatesToAlphaChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToAlphaChannel", true, showValue: true), 67 | DeployUpdatesToBetaChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToBetaChannel", true, showValue: true), 68 | DeployUpdatesToStableChannel = buildContext.BuildServer.GetVariableAsBool("WpfDeployUpdatesToStableChannel", true, showValue: true), 69 | DeployInstallers = buildContext.BuildServer.GetVariableAsBool("WpfDeployInstallers", true, showValue: true), 70 | }; 71 | 72 | if (string.IsNullOrWhiteSpace(data.Channel)) 73 | { 74 | data.Channel = DetermineChannel(buildContext.General); 75 | 76 | data.CakeContext.Information($"Determined channel '{data.Channel}' for wpf projects"); 77 | } 78 | 79 | return data; 80 | } 81 | 82 | //------------------------------------------------------------- 83 | 84 | List _wpfApps; 85 | 86 | public List WpfApps 87 | { 88 | get 89 | { 90 | if (_wpfApps is null) 91 | { 92 | _wpfApps = new List(); 93 | } 94 | 95 | return _wpfApps; 96 | } 97 | } -------------------------------------------------------------------------------- /deployment/cake/codesigning-tasks.cake: -------------------------------------------------------------------------------- 1 | #l "codesigning-variables.cake" 2 | 3 | using System.Xml.Linq; 4 | 5 | //------------------------------------------------------------- 6 | 7 | // Empty by design for now 8 | -------------------------------------------------------------------------------- /deployment/cake/codesigning-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class CodeSigningContext : BuildContextBase 6 | { 7 | public CodeSigningContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public List ProjectsToSignImmediately { get; set; } 13 | 14 | protected override void ValidateContext() 15 | { 16 | 17 | } 18 | 19 | protected override void LogStateInfoForContext() 20 | { 21 | //CakeContext.Information($"Found '{Items.Count}' component projects"); 22 | } 23 | } 24 | 25 | //------------------------------------------------------------- 26 | 27 | private CodeSigningContext InitializeCodeSigningContext(BuildContext buildContext, IBuildContext parentBuildContext) 28 | { 29 | var data = new CodeSigningContext(parentBuildContext) 30 | { 31 | ProjectsToSignImmediately = CodeSignImmediately, 32 | }; 33 | 34 | return data; 35 | } 36 | 37 | //------------------------------------------------------------- 38 | 39 | List _codeSignImmediately; 40 | 41 | public List CodeSignImmediately 42 | { 43 | get 44 | { 45 | if (_codeSignImmediately is null) 46 | { 47 | _codeSignImmediately = new List(); 48 | } 49 | 50 | return _codeSignImmediately; 51 | } 52 | } -------------------------------------------------------------------------------- /deployment/cake/components-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class ComponentsContext : BuildContextWithItemsBase 6 | { 7 | public ComponentsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string NuGetRepositoryUrl { get; set; } 13 | public string NuGetRepositoryApiKey { get; set; } 14 | 15 | protected override void ValidateContext() 16 | { 17 | 18 | } 19 | 20 | protected override void LogStateInfoForContext() 21 | { 22 | CakeContext.Information($"Found '{Items.Count}' component projects"); 23 | } 24 | } 25 | 26 | //------------------------------------------------------------- 27 | 28 | private ComponentsContext InitializeComponentsContext(BuildContext buildContext, IBuildContext parentBuildContext) 29 | { 30 | var data = new ComponentsContext(parentBuildContext) 31 | { 32 | Items = Components ?? new List(), 33 | NuGetRepositoryUrl = buildContext.BuildServer.GetVariable("NuGetRepositoryUrl", showValue: true), 34 | NuGetRepositoryApiKey = buildContext.BuildServer.GetVariable("NuGetRepositoryApiKey", showValue: false) 35 | }; 36 | 37 | return data; 38 | } 39 | 40 | //------------------------------------------------------------- 41 | 42 | List _components; 43 | 44 | public List Components 45 | { 46 | get 47 | { 48 | if (_components is null) 49 | { 50 | _components = new List(); 51 | } 52 | 53 | return _components; 54 | } 55 | } -------------------------------------------------------------------------------- /deployment/cake/dependencies-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class DependenciesContext : BuildContextWithItemsBase 6 | { 7 | public DependenciesContext(IBuildContext parentBuildContext, Dictionary> dependencies) 8 | : base(parentBuildContext) 9 | { 10 | Dependencies = dependencies ?? new Dictionary>(); 11 | Items = Dependencies.Keys.ToList(); 12 | } 13 | 14 | public Dictionary> Dependencies { get; private set; } 15 | 16 | protected override void ValidateContext() 17 | { 18 | 19 | } 20 | 21 | protected override void LogStateInfoForContext() 22 | { 23 | CakeContext.Information($"Found '{Items.Count}' dependency projects"); 24 | } 25 | 26 | public bool ShouldBuildDependency(string dependencyProject) 27 | { 28 | return ShouldBuildDependency(dependencyProject, Array.Empty()); 29 | } 30 | 31 | public bool ShouldBuildDependency(string dependencyProject, IEnumerable knownDependenciesToBeBuilt) 32 | { 33 | if (!Dependencies.TryGetValue(dependencyProject, out var dependencyInfo)) 34 | { 35 | return false; 36 | } 37 | 38 | if (dependencyInfo.Count == 0) 39 | { 40 | // No explicit projects defined, always build dependency 41 | return true; 42 | } 43 | 44 | foreach (var projectRequiringDependency in dependencyInfo) 45 | { 46 | CakeContext.Information($"Checking whether '{projectRequiringDependency}' is in the list to be processed"); 47 | 48 | // Check dependencies of dependencies 49 | if (knownDependenciesToBeBuilt.Any(x => string.Equals(x, projectRequiringDependency, StringComparison.OrdinalIgnoreCase))) 50 | { 51 | CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of dependency project '{projectRequiringDependency}', including this in the build"); 52 | return true; 53 | } 54 | 55 | // Special case: *if* this is the 2nd round we check, and the project requiring this dependency is a test project, 56 | // we should check whether the test project is not already excluded. If so, the Deploy[SomeProject]Tests will return true 57 | // and this logic will still include it, so we need to exclude it explicitly 58 | if (IsTestProject((BuildContext)ParentContext, projectRequiringDependency) && 59 | !knownDependenciesToBeBuilt.Contains(projectRequiringDependency)) 60 | { 61 | CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of '{projectRequiringDependency}', but that is an already excluded test project, not yet including in the build"); 62 | 63 | // Important: don't return, there might be other projects 64 | continue; 65 | } 66 | 67 | // Check if we should build this project 68 | if (ShouldProcessProject((BuildContext)ParentContext, projectRequiringDependency)) 69 | { 70 | CakeContext.Information($"Dependency '{dependencyProject}' is a dependency of '{projectRequiringDependency}', including this in the build"); 71 | return true; 72 | } 73 | } 74 | 75 | return false; 76 | } 77 | } 78 | 79 | //------------------------------------------------------------- 80 | 81 | private DependenciesContext InitializeDependenciesContext(BuildContext buildContext, IBuildContext parentBuildContext) 82 | { 83 | var data = new DependenciesContext(parentBuildContext, Dependencies); 84 | 85 | return data; 86 | } 87 | 88 | //------------------------------------------------------------- 89 | 90 | Dictionary> _dependencies; 91 | 92 | public Dictionary> Dependencies 93 | { 94 | get 95 | { 96 | if (_dependencies is null) 97 | { 98 | _dependencies = new Dictionary>(); 99 | } 100 | 101 | return _dependencies; 102 | } 103 | } -------------------------------------------------------------------------------- /deployment/cake/docker-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class DockerImagesContext : BuildContextWithItemsBase 6 | { 7 | public DockerImagesContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string DockerEngineUrl { get; set; } 13 | public string DockerRegistryUrl { get; set; } 14 | public string DockerRegistryUserName { get; set; } 15 | public string DockerRegistryPassword { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | } 20 | 21 | protected override void LogStateInfoForContext() 22 | { 23 | CakeContext.Information($"Found '{Items.Count}' docker image projects"); 24 | } 25 | } 26 | 27 | //------------------------------------------------------------- 28 | 29 | private DockerImagesContext InitializeDockerImagesContext(BuildContext buildContext, IBuildContext parentBuildContext) 30 | { 31 | var data = new DockerImagesContext(parentBuildContext) 32 | { 33 | Items = DockerImages ?? new List(), 34 | DockerEngineUrl = buildContext.BuildServer.GetVariable("DockerEngineUrl", showValue: true), 35 | DockerRegistryUrl = buildContext.BuildServer.GetVariable("DockerRegistryUrl", showValue: true), 36 | DockerRegistryUserName = buildContext.BuildServer.GetVariable("DockerRegistryUserName", showValue: false), 37 | DockerRegistryPassword = buildContext.BuildServer.GetVariable("DockerRegistryPassword", showValue: false) 38 | }; 39 | 40 | return data; 41 | } 42 | 43 | //------------------------------------------------------------- 44 | 45 | List _dockerImages; 46 | 47 | public List DockerImages 48 | { 49 | get 50 | { 51 | if (_dockerImages is null) 52 | { 53 | _dockerImages = new List(); 54 | } 55 | 56 | return _dockerImages; 57 | } 58 | } -------------------------------------------------------------------------------- /deployment/cake/github-pages-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class GitHubPagesContext : BuildContextWithItemsBase 6 | { 7 | public GitHubPagesContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string RepositoryUrl { get; set; } 13 | public string BranchName { get; set; } 14 | public string Email { get; set; } 15 | public string UserName { get; set; } 16 | public string ApiToken { get; set; } 17 | 18 | protected override void ValidateContext() 19 | { 20 | if (Items.Count == 0) 21 | { 22 | return; 23 | } 24 | 25 | if (string.IsNullOrWhiteSpace(RepositoryUrl)) 26 | { 27 | throw new Exception("GitHubPagesRepositoryUrl must be defined"); 28 | } 29 | 30 | if (string.IsNullOrWhiteSpace(BranchName)) 31 | { 32 | throw new Exception("GitHubPagesBranchName must be defined"); 33 | } 34 | 35 | if (string.IsNullOrWhiteSpace(Email)) 36 | { 37 | throw new Exception("GitHubPagesEmail must be defined"); 38 | } 39 | 40 | if (string.IsNullOrWhiteSpace(UserName)) 41 | { 42 | throw new Exception("GitHubPagesUserName must be defined"); 43 | } 44 | 45 | if (string.IsNullOrWhiteSpace(ApiToken)) 46 | { 47 | throw new Exception("GitHubPagesApiToken must be defined"); 48 | } 49 | } 50 | 51 | protected override void LogStateInfoForContext() 52 | { 53 | CakeContext.Information($"Found '{Items.Count}' GitHub pages projects"); 54 | } 55 | } 56 | 57 | //------------------------------------------------------------- 58 | 59 | private GitHubPagesContext InitializeGitHubPagesContext(BuildContext buildContext, IBuildContext parentBuildContext) 60 | { 61 | var data = new GitHubPagesContext(parentBuildContext) 62 | { 63 | Items = GitHubPages ?? new List(), 64 | RepositoryUrl = buildContext.BuildServer.GetVariable("GitHubPagesRepositoryUrl", ((BuildContext)parentBuildContext).General.Repository.Url, showValue: true), 65 | BranchName = buildContext.BuildServer.GetVariable("GitHubPagesRepositoryUrl", "gh-pages", showValue: true), 66 | Email = buildContext.BuildServer.GetVariable("GitHubPagesEmail", showValue: true), 67 | UserName = buildContext.BuildServer.GetVariable("GitHubPagesUserName", showValue: true), 68 | ApiToken = buildContext.BuildServer.GetVariable("GitHubPagesApiToken", showValue: false), 69 | }; 70 | 71 | return data; 72 | } 73 | 74 | //------------------------------------------------------------- 75 | 76 | List _gitHubPages; 77 | 78 | public List GitHubPages 79 | { 80 | get 81 | { 82 | if (_gitHubPages is null) 83 | { 84 | _gitHubPages = new List(); 85 | } 86 | 87 | return _gitHubPages; 88 | } 89 | } -------------------------------------------------------------------------------- /deployment/cake/issuetrackers-github.cake: -------------------------------------------------------------------------------- 1 | #tool "nuget:?package=gitreleasemanager&version=0.20.0" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class GitHubIssueTracker : IIssueTracker 6 | { 7 | public GitHubIssueTracker(BuildContext buildContext) 8 | { 9 | BuildContext = buildContext; 10 | 11 | ApiKey = buildContext.BuildServer.GetVariable("GitHubApiKey", showValue: false); 12 | OwnerName = buildContext.BuildServer.GetVariable("GitHubOwnerName", buildContext.General.Copyright.Company, showValue: true); 13 | ProjectName = buildContext.BuildServer.GetVariable("GitHubProjectName", buildContext.General.Solution.Name, showValue: true); 14 | 15 | if (!string.IsNullOrWhiteSpace(ApiKey) && 16 | !string.IsNullOrWhiteSpace(OwnerName) && 17 | !string.IsNullOrWhiteSpace(ProjectName)) 18 | { 19 | IsAvailable = true; 20 | } 21 | } 22 | 23 | public BuildContext BuildContext { get; private set; } 24 | 25 | public string ApiKey { get; set; } 26 | public string OwnerName { get; set; } 27 | public string ProjectName { get; set; } 28 | 29 | public string OwnerAndProjectName 30 | { 31 | get { return $"{OwnerName}/{ProjectName}"; } 32 | } 33 | 34 | public bool IsAvailable { get; private set; } 35 | 36 | public async Task CreateAndReleaseVersionAsync() 37 | { 38 | if (!IsAvailable) 39 | { 40 | BuildContext.CakeContext.Information("GitHub is not available, skipping GitHub integration"); 41 | return; 42 | } 43 | 44 | var version = BuildContext.General.Version.FullSemVer; 45 | 46 | BuildContext.CakeContext.Information("Releasing version '{0}' in GitHub", version); 47 | 48 | // For docs, see https://cakebuild.net/dsl/gitreleasemanager/ 49 | 50 | BuildContext.CakeContext.Information("Step 1 / 4: Creating release"); 51 | 52 | BuildContext.CakeContext.GitReleaseManagerCreate(ApiKey, OwnerName, ProjectName, new GitReleaseManagerCreateSettings 53 | { 54 | TargetDirectory = BuildContext.General.RootDirectory, 55 | Milestone = BuildContext.General.Version.MajorMinorPatch, 56 | Name = version, 57 | Prerelease = !BuildContext.General.IsOfficialBuild, 58 | TargetCommitish = BuildContext.General.Repository.CommitId 59 | }); 60 | 61 | BuildContext.CakeContext.Information("Step 2 / 4: Adding assets to the release (not supported yet)"); 62 | 63 | // Not yet supported 64 | 65 | if (!BuildContext.General.IsOfficialBuild) 66 | { 67 | BuildContext.CakeContext.Information("GitHub release publishing only runs against non-prerelease builds"); 68 | } 69 | else 70 | { 71 | BuildContext.CakeContext.Information("Step 3 / 4: Publishing release"); 72 | 73 | BuildContext.CakeContext.GitReleaseManagerPublish(ApiKey, OwnerName, ProjectName, BuildContext.General.Version.MajorMinorPatch, new GitReleaseManagerPublishSettings 74 | { 75 | TargetDirectory = BuildContext.General.RootDirectory 76 | }); 77 | 78 | BuildContext.CakeContext.Information("Step 4 / 4: Closing the milestone"); 79 | 80 | BuildContext.CakeContext.GitReleaseManagerClose(ApiKey, OwnerName, ProjectName, BuildContext.General.Version.MajorMinorPatch, new GitReleaseManagerCloseMilestoneSettings 81 | { 82 | TargetDirectory = BuildContext.General.RootDirectory 83 | }); 84 | } 85 | 86 | BuildContext.CakeContext.Information("Released version in GitHub"); 87 | } 88 | } -------------------------------------------------------------------------------- /deployment/cake/issuetrackers-jira.cake: -------------------------------------------------------------------------------- 1 | #tool "nuget:?package=JiraCli&version=1.3.0-alpha0338&prerelease" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class JiraIssueTracker : IIssueTracker 6 | { 7 | public JiraIssueTracker(BuildContext buildContext) 8 | { 9 | BuildContext = buildContext; 10 | 11 | Url = buildContext.BuildServer.GetVariable("JiraUrl", showValue: true); 12 | Username = buildContext.BuildServer.GetVariable("JiraUsername", showValue: true); 13 | Password = buildContext.BuildServer.GetVariable("JiraPassword", showValue: false); 14 | ProjectName = buildContext.BuildServer.GetVariable("JiraProjectName", showValue: true); 15 | 16 | if (!string.IsNullOrWhiteSpace(Url) && 17 | !string.IsNullOrWhiteSpace(ProjectName)) 18 | { 19 | IsAvailable = true; 20 | } 21 | } 22 | 23 | public BuildContext BuildContext { get; private set; } 24 | 25 | public string Url { get; set; } 26 | public string Username { get; set; } 27 | public string Password { get; set; } 28 | public string ProjectName { get; set; } 29 | public bool IsAvailable { get; private set; } 30 | 31 | public async Task CreateAndReleaseVersionAsync() 32 | { 33 | if (!IsAvailable) 34 | { 35 | BuildContext.CakeContext.Information("JIRA is not available, skipping JIRA integration"); 36 | return; 37 | } 38 | 39 | var version = BuildContext.General.Version.FullSemVer; 40 | 41 | BuildContext.CakeContext.Information("Releasing version '{0}' in JIRA", version); 42 | 43 | // Example call: 44 | // JiraCli.exe -url %JiraUrl% -user %JiraUsername% -pw %JiraPassword% -action createandreleaseversion 45 | // -project %JiraProjectName% -version %GitVersion_FullSemVer% -merge %IsOfficialBuild% 46 | 47 | var nugetPath = BuildContext.CakeContext.Tools.Resolve("JiraCli.exe"); 48 | BuildContext.CakeContext.StartProcess(nugetPath, new ProcessSettings 49 | { 50 | Arguments = new ProcessArgumentBuilder() 51 | .AppendSwitch("-url", Url) 52 | .AppendSwitch("-user", Username) 53 | .AppendSwitchSecret("-pw", Password) 54 | .AppendSwitch("-action", "createandreleaseversion") 55 | .AppendSwitch("-project", ProjectName) 56 | .AppendSwitch("-version", version) 57 | .AppendSwitch("-merge", BuildContext.General.IsOfficialBuild.ToString()) 58 | }); 59 | 60 | BuildContext.CakeContext.Information("Released version in JIRA"); 61 | } 62 | } -------------------------------------------------------------------------------- /deployment/cake/issuetrackers.cake: -------------------------------------------------------------------------------- 1 | // Customize this file when using a different issue tracker 2 | #l "issuetrackers-github.cake" 3 | #l "issuetrackers-jira.cake" 4 | 5 | //------------------------------------------------------------- 6 | 7 | public interface IIssueTracker 8 | { 9 | Task CreateAndReleaseVersionAsync(); 10 | } 11 | 12 | //------------------------------------------------------------- 13 | 14 | public class IssueTrackerIntegration : IntegrationBase 15 | { 16 | private readonly List _issueTrackers = new List(); 17 | 18 | public IssueTrackerIntegration(BuildContext buildContext) 19 | : base(buildContext) 20 | { 21 | _issueTrackers.Add(new GitHubIssueTracker(buildContext)); 22 | _issueTrackers.Add(new JiraIssueTracker(buildContext)); 23 | } 24 | 25 | public async Task CreateAndReleaseVersionAsync() 26 | { 27 | BuildContext.CakeContext.LogSeparator("Creating and releasing version"); 28 | 29 | foreach (var issueTracker in _issueTrackers) 30 | { 31 | try 32 | { 33 | await issueTracker.CreateAndReleaseVersionAsync(); 34 | } 35 | catch (Exception ex) 36 | { 37 | BuildContext.CakeContext.Error(ex.Message); 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /deployment/cake/lib-logging.cake: -------------------------------------------------------------------------------- 1 | // Note: code originally comes from https://stackoverflow.com/questions/50826394/how-to-print-tool-command-line-in-cake 2 | 3 | /// 4 | /// Temporary sets logging verbosity. 5 | /// 6 | /// 7 | /// 8 | /// // Temporary sets logging verbosity to Diagnostic. 9 | /// using(context.UseVerbosity(Verbosity.Diagnostic)) 10 | /// { 11 | /// context.DotNetBuild(project, settings); 12 | /// } 13 | /// 14 | /// 15 | public static VerbosityChanger UseVerbosity(this ICakeContext context, Verbosity newVerbosity) => 16 | new VerbosityChanger(context.Log, newVerbosity); 17 | 18 | 19 | /// 20 | /// Temporary sets logging verbosity to Diagnostic. 21 | /// 22 | /// 23 | /// 24 | /// // Temporary sets logging verbosity to Diagnostic. 25 | /// using(context.UseDiagnosticVerbosity()) 26 | /// { 27 | /// context.DotNetBuild(project, settings); 28 | /// } 29 | /// 30 | /// 31 | public static VerbosityChanger UseDiagnosticVerbosity(this ICakeContext context) => 32 | context.UseVerbosity(Verbosity.Diagnostic); 33 | 34 | /// 35 | /// Cake log verbosity changer. 36 | /// Restores old verbosity on Dispose. 37 | /// 38 | public class VerbosityChanger : IDisposable 39 | { 40 | ICakeLog _log; 41 | Verbosity _oldVerbosity; 42 | 43 | public VerbosityChanger(ICakeLog log, Verbosity newVerbosity) 44 | { 45 | _log = log; 46 | _oldVerbosity = log.Verbosity; 47 | _log.Verbosity = newVerbosity; 48 | } 49 | 50 | public void Dispose() => _log.Verbosity = _oldVerbosity; 51 | } -------------------------------------------------------------------------------- /deployment/cake/lib-sourcelink.cake: -------------------------------------------------------------------------------- 1 | public static bool IsSourceLinkSupported(BuildContext buildContext, string projectName, string projectFileName) 2 | { 3 | if (buildContext.General.SourceLink.IsDisabled) 4 | { 5 | return false; 6 | } 7 | 8 | if (buildContext.General.IsLocalBuild) 9 | { 10 | return false; 11 | } 12 | 13 | if (string.IsNullOrWhiteSpace(buildContext.General.Repository.Url)) 14 | { 15 | return false; 16 | } 17 | 18 | // Only support C# projects 19 | if (!projectFileName.EndsWith(".csproj")) 20 | { 21 | return false; 22 | } 23 | 24 | // Is this a test project? 25 | if (buildContext.Tests.Items.Contains(projectName)) 26 | { 27 | return false; 28 | } 29 | 30 | // Only support when running a real build, e.g. ot for 'Package' only 31 | if (!buildContext.General.Target.ToLower().Contains("build")) 32 | { 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | 39 | //------------------------------------------------------------- 40 | 41 | public static void InjectSourceLinkInProjectFile(BuildContext buildContext, string projectName, string projectFileName) 42 | { 43 | try 44 | { 45 | // Only support C# projects 46 | if (!IsSourceLinkSupported(buildContext, projectName, projectFileName)) 47 | { 48 | return; 49 | } 50 | 51 | // For SourceLink to work, the .csproj should contain something like this: 52 | // 53 | var projectFileContents = System.IO.File.ReadAllText(projectFileName); 54 | if (projectFileContents.Contains("Microsoft.SourceLink.GitHub")) 55 | { 56 | return; 57 | } 58 | 59 | buildContext.CakeContext.Warning("No SourceLink reference found, automatically injecting SourceLink package reference now"); 60 | 61 | //const string MSBuildNS = (XNamespace) "http://schemas.microsoft.com/developer/msbuild/2003"; 62 | 63 | var xmlDocument = XDocument.Parse(projectFileContents); 64 | var projectElement = xmlDocument.Root; 65 | 66 | // Item group with package reference 67 | var referencesItemGroup = new XElement("ItemGroup"); 68 | var sourceLinkPackageReference = new XElement("PackageReference"); 69 | sourceLinkPackageReference.Add(new XAttribute("Include", "Microsoft.SourceLink.GitHub")); 70 | sourceLinkPackageReference.Add(new XAttribute("Version", "1.1.1")); 71 | sourceLinkPackageReference.Add(new XAttribute("PrivateAssets", "all")); 72 | 73 | referencesItemGroup.Add(sourceLinkPackageReference); 74 | projectElement.Add(referencesItemGroup); 75 | 76 | // Item group with source root 77 | // 78 | var sourceRootItemGroup = new XElement("ItemGroup"); 79 | var sourceRoot = new XElement("SourceRoot"); 80 | 81 | // Required to end with a \ 82 | var sourceRootValue = buildContext.General.RootDirectory; 83 | var directorySeparator = System.IO.Path.DirectorySeparatorChar.ToString(); 84 | if (!sourceRootValue.EndsWith(directorySeparator)) 85 | { 86 | sourceRootValue += directorySeparator; 87 | }; 88 | 89 | sourceRoot.Add(new XAttribute("Include", sourceRootValue)); 90 | sourceRoot.Add(new XAttribute("RepositoryUrl", buildContext.General.Repository.Url)); 91 | 92 | // Note: since we are not allowing source control manager queries (we don't want to require a .git directory), 93 | // we must specify the additional information below 94 | sourceRoot.Add(new XAttribute("SourceControl", "git")); 95 | sourceRoot.Add(new XAttribute("RevisionId", buildContext.General.Repository.CommitId)); 96 | 97 | sourceRootItemGroup.Add(sourceRoot); 98 | projectElement.Add(sourceRootItemGroup); 99 | 100 | xmlDocument.Save(projectFileName); 101 | } 102 | catch (Exception ex) 103 | { 104 | buildContext.CakeContext.Error($"Failed to process source link for project '{projectFileName}': {ex.Message}"); 105 | } 106 | } -------------------------------------------------------------------------------- /deployment/cake/notifications-msteams.cake: -------------------------------------------------------------------------------- 1 | #addin "nuget:?package=Cake.MicrosoftTeams&version=2.0.0" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class MsTeamsNotifier : INotifier 6 | { 7 | public MsTeamsNotifier(BuildContext buildContext) 8 | { 9 | BuildContext = buildContext; 10 | 11 | WebhookUrl = buildContext.BuildServer.GetVariable("MsTeamsWebhookUrl", showValue: false); 12 | WebhookUrlForErrors = buildContext.BuildServer.GetVariable("MsTeamsWebhookUrlForErrors", WebhookUrl, showValue: false); 13 | } 14 | 15 | public BuildContext BuildContext { get; private set; } 16 | 17 | public string WebhookUrl { get; private set; } 18 | public string WebhookUrlForErrors { get; private set; } 19 | 20 | public string GetMsTeamsWebhookUrl(string project, TargetType targetType) 21 | { 22 | // Allow per target overrides via "MsTeamsWebhookUrlFor[TargetType]" 23 | var targetTypeUrl = GetTargetSpecificConfigurationValue(BuildContext, targetType, "MsTeamsWebhookUrlFor", string.Empty); 24 | if (!string.IsNullOrEmpty(targetTypeUrl)) 25 | { 26 | return targetTypeUrl; 27 | } 28 | 29 | // Allow per project overrides via "MsTeamsWebhookUrlFor[ProjectName]" 30 | var projectTypeUrl = GetProjectSpecificConfigurationValue(BuildContext, project, "MsTeamsWebhookUrlFor", string.Empty); 31 | if (!string.IsNullOrEmpty(projectTypeUrl)) 32 | { 33 | return projectTypeUrl; 34 | } 35 | 36 | // Return default fallback 37 | return WebhookUrl; 38 | } 39 | 40 | //------------------------------------------------------------- 41 | 42 | private string GetMsTeamsTarget(string project, TargetType targetType, NotificationType notificationType) 43 | { 44 | if (notificationType == NotificationType.Error) 45 | { 46 | return WebhookUrlForErrors; 47 | } 48 | 49 | return GetMsTeamsWebhookUrl(project, targetType); 50 | } 51 | 52 | //------------------------------------------------------------- 53 | 54 | public async Task NotifyAsync(string project, string message, TargetType targetType, NotificationType notificationType) 55 | { 56 | var targetWebhookUrl = GetMsTeamsTarget(project, targetType, notificationType); 57 | if (string.IsNullOrWhiteSpace(targetWebhookUrl)) 58 | { 59 | return; 60 | } 61 | 62 | var messageCard = new MicrosoftTeamsMessageCard 63 | { 64 | title = project, 65 | summary = notificationType.ToString(), 66 | sections = new [] 67 | { 68 | new MicrosoftTeamsMessageSection 69 | { 70 | activityTitle = notificationType.ToString(), 71 | activitySubtitle = message, 72 | activityText = " ", 73 | activityImage = "https://raw.githubusercontent.com/cake-build/graphics/master/png/cake-small.png", 74 | facts = new [] 75 | { 76 | new MicrosoftTeamsMessageFacts { name ="Project", value = project }, 77 | new MicrosoftTeamsMessageFacts { name ="Version", value = BuildContext.General.Version.FullSemVer }, 78 | new MicrosoftTeamsMessageFacts { name ="CakeVersion", value = BuildContext.CakeContext.Environment.Runtime.CakeVersion.ToString() }, 79 | //new MicrosoftTeamsMessageFacts { name ="TargetFramework", value = Context.Environment.Runtime .TargetFramework.ToString() }, 80 | }, 81 | } 82 | } 83 | }; 84 | 85 | var result = BuildContext.CakeContext.MicrosoftTeamsPostMessage(messageCard, new MicrosoftTeamsSettings 86 | { 87 | IncomingWebhookUrl = targetWebhookUrl 88 | }); 89 | 90 | if (result != System.Net.HttpStatusCode.OK) 91 | { 92 | BuildContext.CakeContext.Warning(string.Format("MsTeams result: {0}", result)); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /deployment/cake/notifications.cake: -------------------------------------------------------------------------------- 1 | #l "notifications-msteams.cake" 2 | //#l "notifications-slack.cake" 3 | 4 | //------------------------------------------------------------- 5 | 6 | public enum NotificationType 7 | { 8 | Info, 9 | 10 | Error 11 | } 12 | 13 | //------------------------------------------------------------- 14 | 15 | public interface INotifier 16 | { 17 | Task NotifyAsync(string project, string message, TargetType targetType = TargetType.Unknown, NotificationType notificationType = NotificationType.Info); 18 | } 19 | 20 | //------------------------------------------------------------- 21 | 22 | public class NotificationsIntegration : IntegrationBase 23 | { 24 | private readonly List _notifiers = new List(); 25 | 26 | public NotificationsIntegration(BuildContext buildContext) 27 | : base(buildContext) 28 | { 29 | _notifiers.Add(new MsTeamsNotifier(buildContext)); 30 | } 31 | 32 | public async Task NotifyDefaultAsync(string project, string message, TargetType targetType = TargetType.Unknown) 33 | { 34 | await NotifyAsync(project, message, targetType, NotificationType.Info); 35 | } 36 | 37 | //------------------------------------------------------------- 38 | 39 | public async Task NotifyErrorAsync(string project, string message, TargetType targetType = TargetType.Unknown) 40 | { 41 | await NotifyAsync(project, string.Format("ERROR: {0}", message), targetType, NotificationType.Error); 42 | } 43 | 44 | //------------------------------------------------------------- 45 | 46 | public async Task NotifyAsync(string project, string message, TargetType targetType = TargetType.Unknown, NotificationType notificationType = NotificationType.Info) 47 | { 48 | foreach (var notifier in _notifiers) 49 | { 50 | await notifier.NotifyAsync(project, message, targetType, notificationType); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /deployment/cake/sourcecontrol-github.cake: -------------------------------------------------------------------------------- 1 | #addin "nuget:?package=Cake.GitHub&version=1.0.0" 2 | #addin "nuget:?package=Octokit&version=14.0.0" 3 | 4 | //------------------------------------------------------------- 5 | 6 | public class GitHubSourceControl : ISourceControl 7 | { 8 | public GitHubSourceControl(BuildContext buildContext) 9 | { 10 | BuildContext = buildContext; 11 | 12 | ApiKey = buildContext.BuildServer.GetVariable("GitHubApiKey", buildContext.General.Repository.Password, showValue: false); 13 | OwnerName = buildContext.BuildServer.GetVariable("GitHubOwnerName", buildContext.General.Copyright.Company, showValue: true); 14 | ProjectName = buildContext.BuildServer.GetVariable("GitHubProjectName", buildContext.General.Solution.Name, showValue: true); 15 | 16 | if (!string.IsNullOrWhiteSpace(ApiKey) && 17 | !string.IsNullOrWhiteSpace(OwnerName) && 18 | !string.IsNullOrWhiteSpace(ProjectName)) 19 | { 20 | IsAvailable = true; 21 | } 22 | } 23 | 24 | public BuildContext BuildContext { get; private set; } 25 | 26 | public string ApiKey { get; set; } 27 | public string OwnerName { get; set; } 28 | public string ProjectName { get; set; } 29 | 30 | public string OwnerAndProjectName 31 | { 32 | get { return $"{OwnerName}/{ProjectName}"; } 33 | } 34 | 35 | public bool IsAvailable { get; private set; } 36 | 37 | public async Task MarkBuildAsPendingAsync(string context, string description) 38 | { 39 | UpdateStatus(GitHubStatusState.Pending, context, description); 40 | } 41 | 42 | public async Task MarkBuildAsFailedAsync(string context, string description) 43 | { 44 | UpdateStatus(GitHubStatusState.Failure, context, description); 45 | } 46 | 47 | public async Task MarkBuildAsSucceededAsync(string context, string description) 48 | { 49 | UpdateStatus(GitHubStatusState.Success, context, description); 50 | } 51 | 52 | private void UpdateStatus(GitHubStatusState state, string context, string description) 53 | { 54 | // Disabled for now 55 | return; 56 | 57 | if (!IsAvailable) 58 | { 59 | return; 60 | } 61 | 62 | BuildContext.CakeContext.Information("Updating GitHub status to '{0}' | '{1}'", state, description); 63 | 64 | var commitSha = BuildContext.General.Repository.CommitId; 65 | 66 | // Note: UserName is not really required, use string.Empty, then only api key is needed 67 | BuildContext.CakeContext.GitHubStatus(string.Empty, ApiKey, OwnerName, ProjectName, commitSha, new GitHubStatusSettings 68 | { 69 | State = state, 70 | TargetUrl = null,// "url-to-build-server", 71 | Description = description, 72 | Context = $"Cake - {context}" 73 | }); 74 | } 75 | } -------------------------------------------------------------------------------- /deployment/cake/sourcecontrol.cake: -------------------------------------------------------------------------------- 1 | // Customize this file when using a different source controls 2 | #l "sourcecontrol-github.cake" 3 | 4 | //------------------------------------------------------------- 5 | 6 | public interface ISourceControl 7 | { 8 | Task MarkBuildAsPendingAsync(string context, string description); 9 | Task MarkBuildAsFailedAsync(string context, string description); 10 | Task MarkBuildAsSucceededAsync(string context, string description); 11 | } 12 | 13 | //------------------------------------------------------------- 14 | 15 | public class SourceControlIntegration : IntegrationBase 16 | { 17 | private readonly List _sourceControls = new List(); 18 | 19 | public SourceControlIntegration(BuildContext buildContext) 20 | : base(buildContext) 21 | { 22 | _sourceControls.Add(new GitHubSourceControl(buildContext)); 23 | } 24 | 25 | public async Task MarkBuildAsPendingAsync(string context, string description = null) 26 | { 27 | BuildContext.CakeContext.LogSeparator($"Marking build as pending: '{description ?? string.Empty}'"); 28 | 29 | context = context ?? "default"; 30 | description = description ?? "Build pending"; 31 | 32 | foreach (var sourceControl in _sourceControls) 33 | { 34 | try 35 | { 36 | await sourceControl.MarkBuildAsPendingAsync(context, description); 37 | } 38 | catch (Exception ex) 39 | { 40 | BuildContext.CakeContext.Warning($"Failed to update status: {ex.Message}"); 41 | } 42 | } 43 | } 44 | 45 | public async Task MarkBuildAsFailedAsync(string context, string description = null) 46 | { 47 | BuildContext.CakeContext.LogSeparator($"Marking build as failed: '{description ?? string.Empty}'"); 48 | 49 | context = context ?? "default"; 50 | description = description ?? "Build failed"; 51 | 52 | foreach (var sourceControl in _sourceControls) 53 | { 54 | try 55 | { 56 | await sourceControl.MarkBuildAsFailedAsync(context, description); 57 | } 58 | catch (Exception ex) 59 | { 60 | BuildContext.CakeContext.Warning($"Failed to update status: {ex.Message}"); 61 | } 62 | } 63 | } 64 | 65 | public async Task MarkBuildAsSucceededAsync(string context, string description = null) 66 | { 67 | BuildContext.CakeContext.LogSeparator($"Marking build as succeeded: '{description ?? string.Empty}'"); 68 | 69 | context = context ?? "default"; 70 | description = description ?? "Build succeeded"; 71 | 72 | foreach (var sourceControl in _sourceControls) 73 | { 74 | try 75 | { 76 | await sourceControl.MarkBuildAsSucceededAsync(context, description); 77 | } 78 | catch (Exception ex) 79 | { 80 | BuildContext.CakeContext.Warning($"Failed to update status: {ex.Message}"); 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /deployment/cake/templates-tasks.cake: -------------------------------------------------------------------------------- 1 | #l "templates-variables.cake" 2 | 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using System.Xml.Linq; 6 | using System.IO; 7 | 8 | //------------------------------------------------------------- 9 | 10 | public class TemplatesProcessor : ProcessorBase 11 | { 12 | public TemplatesProcessor(BuildContext buildContext) 13 | : base(buildContext) 14 | { 15 | var templatesRelativePath = "./deployment/templates"; 16 | 17 | if (CakeContext.DirectoryExists(templatesRelativePath)) 18 | { 19 | var currentDirectoryPath = System.IO.Directory.GetCurrentDirectory(); 20 | var templateAbsolutePath = System.IO.Path.Combine(currentDirectoryPath, templatesRelativePath); 21 | var files = System.IO.Directory.GetFiles(templateAbsolutePath, "*.*", System.IO.SearchOption.AllDirectories); 22 | 23 | CakeContext.Information($"Found '{files.Count()}' template files"); 24 | 25 | foreach (var file in files) 26 | { 27 | BuildContext.Templates.Items.Add(file.Substring(templateAbsolutePath.Length + 1)); 28 | } 29 | } 30 | } 31 | 32 | public override bool HasItems() 33 | { 34 | return BuildContext.Templates.Items.Count > 0; 35 | } 36 | 37 | public override async Task PrepareAsync() 38 | { 39 | 40 | } 41 | 42 | public override async Task UpdateInfoAsync() 43 | { 44 | if (!HasItems()) 45 | { 46 | return; 47 | } 48 | 49 | var variableRegex = new Regex(@"\$\{([^}]+)\}", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); 50 | 51 | foreach (var template in BuildContext.Templates.Items) 52 | { 53 | CakeContext.Information($"Updating template file '{template}'"); 54 | 55 | var templateSourceFile = $"./deployment/templates/{template}"; 56 | var content = CakeContext.FileReadText(templateSourceFile); 57 | 58 | var matches = variableRegex.Matches(content); 59 | 60 | foreach (var match in matches.Cast()) 61 | { 62 | var variableName = match.Groups[1].Value; 63 | 64 | CakeContext.Information($"Found usage of variable '{variableName}'"); 65 | 66 | if (!BuildContext.Variables.TryGetValue(variableName, out var replacement)) 67 | { 68 | CakeContext.Error($"Could not find value for variable '{variableName}'"); 69 | continue; 70 | } 71 | 72 | content = content.Replace($"${{{variableName}}}", replacement); 73 | } 74 | 75 | CakeContext.FileWriteText($"{template}", content); 76 | } 77 | } 78 | 79 | public override async Task BuildAsync() 80 | { 81 | // Run templates every time 82 | await UpdateInfoAsync(); 83 | } 84 | 85 | public override async Task PackageAsync() 86 | { 87 | // Run templates every time 88 | await UpdateInfoAsync(); 89 | } 90 | 91 | public override async Task DeployAsync() 92 | { 93 | if (!HasItems()) 94 | { 95 | return; 96 | } 97 | } 98 | 99 | public override async Task FinalizeAsync() 100 | { 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /deployment/cake/templates-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class TemplatesContext : BuildContextWithItemsBase 6 | { 7 | public TemplatesContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | protected override void ValidateContext() 13 | { 14 | 15 | } 16 | 17 | protected override void LogStateInfoForContext() 18 | { 19 | CakeContext.Information($"Found '{Items.Count}' template items"); 20 | } 21 | } 22 | 23 | //------------------------------------------------------------- 24 | 25 | private TemplatesContext InitializeTemplatesContext(BuildContext buildContext, IBuildContext parentBuildContext) 26 | { 27 | var data = new TemplatesContext(parentBuildContext) 28 | { 29 | Items = Templates ?? new List(), 30 | }; 31 | 32 | return data; 33 | } 34 | 35 | //------------------------------------------------------------- 36 | 37 | List _templates; 38 | 39 | public List Templates 40 | { 41 | get 42 | { 43 | if (_templates is null) 44 | { 45 | _templates = new List(); 46 | } 47 | 48 | return _templates; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /deployment/cake/tests-nunit.cake: -------------------------------------------------------------------------------- 1 | #tool "nuget:?package=NUnit.ConsoleRunner&version=3.20.1" 2 | 3 | //------------------------------------------------------------- 4 | 5 | private static void RunTestsUsingNUnit(BuildContext buildContext, string projectName, string testTargetFramework, string testResultsDirectory) 6 | { 7 | var testFile = System.IO.Path.Combine(GetProjectOutputDirectory(buildContext, projectName), 8 | testTargetFramework, $"{projectName}.dll"); 9 | var resultsFile = System.IO.Path.Combine(testResultsDirectory, "testresults.xml"); 10 | 11 | var nunitSettings = new NUnit3Settings 12 | { 13 | Results = new NUnit3Result[] 14 | { 15 | new NUnit3Result 16 | { 17 | FileName = resultsFile, 18 | Format = "nunit3" 19 | } 20 | }, 21 | NoHeader = true, 22 | NoColor = true, 23 | NoResults = false, 24 | X86 = string.Equals(buildContext.Tests.ProcessBit, "X86", StringComparison.OrdinalIgnoreCase), 25 | Timeout = 60 * 1000, // 60 seconds 26 | Workers = 1 27 | //Work = testResultsDirectory 28 | }; 29 | 30 | // Note: although the docs say you can use without array initialization, you can't 31 | buildContext.CakeContext.NUnit3(new string[] { testFile }, nunitSettings); 32 | 33 | buildContext.CakeContext.Information("Verifying whether results file '{0}' exists", resultsFile); 34 | 35 | if (!buildContext.CakeContext.FileExists(resultsFile)) 36 | { 37 | throw new Exception(string.Format("Expected results file '{0}' does not exist", resultsFile)); 38 | } 39 | } -------------------------------------------------------------------------------- /deployment/cake/tests-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class TestsContext : BuildContextWithItemsBase 6 | { 7 | public TestsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string Framework { get; set; } 13 | public string TargetFramework { get; set; } 14 | public string OperatingSystem { get; set; } 15 | public string ProcessBit { get; set; } 16 | 17 | protected override void ValidateContext() 18 | { 19 | if (Items.Count == 0) 20 | { 21 | return; 22 | } 23 | 24 | if (string.IsNullOrWhiteSpace(Framework)) 25 | { 26 | throw new Exception("Framework is required, specify via 'TestFramework'"); 27 | } 28 | 29 | if (string.IsNullOrWhiteSpace(ProcessBit)) 30 | { 31 | throw new Exception("ProcessBit is required, specify via 'TestProcessBit'"); 32 | } 33 | } 34 | 35 | protected override void LogStateInfoForContext() 36 | { 37 | CakeContext.Information($"Found '{Items.Count}' test projects"); 38 | } 39 | } 40 | 41 | //------------------------------------------------------------- 42 | 43 | private TestsContext InitializeTestsContext(BuildContext buildContext, IBuildContext parentBuildContext) 44 | { 45 | var data = new TestsContext(parentBuildContext) 46 | { 47 | Items = TestProjects, 48 | 49 | Framework = buildContext.BuildServer.GetVariable("TestFramework", "nunit", showValue: true), 50 | TargetFramework = buildContext.BuildServer.GetVariable("TestTargetFramework", "", showValue: true), 51 | OperatingSystem = buildContext.BuildServer.GetVariable("TestOperatingSystem", "win", showValue: true), 52 | ProcessBit = buildContext.BuildServer.GetVariable("TestProcessBit", "X64", showValue: true) 53 | }; 54 | 55 | return data; 56 | } 57 | 58 | //------------------------------------------------------------- 59 | 60 | List _testProjects; 61 | 62 | public List TestProjects 63 | { 64 | get 65 | { 66 | if (_testProjects is null) 67 | { 68 | _testProjects = new List(); 69 | } 70 | 71 | return _testProjects; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /deployment/cake/tools-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | //------------------------------------------------------------- 4 | 5 | public class ToolsContext : BuildContextWithItemsBase 6 | { 7 | public ToolsContext(IBuildContext parentBuildContext) 8 | : base(parentBuildContext) 9 | { 10 | } 11 | 12 | public string NuGetRepositoryUrls { get; set; } 13 | public string NuGetRepositoryApiKeys { get; set; } 14 | 15 | protected override void ValidateContext() 16 | { 17 | 18 | } 19 | 20 | protected override void LogStateInfoForContext() 21 | { 22 | CakeContext.Information($"Found '{Items.Count}' tool projects"); 23 | } 24 | } 25 | 26 | //------------------------------------------------------------- 27 | 28 | private ToolsContext InitializeToolsContext(BuildContext buildContext, IBuildContext parentBuildContext) 29 | { 30 | var data = new ToolsContext(parentBuildContext) 31 | { 32 | Items = Tools ?? new List(), 33 | NuGetRepositoryUrls = buildContext.BuildServer.GetVariable("ToolsNuGetRepositoryUrls", showValue: true), 34 | NuGetRepositoryApiKeys = buildContext.BuildServer.GetVariable("ToolsNuGetRepositoryApiKeys", showValue: false) 35 | }; 36 | 37 | return data; 38 | } 39 | 40 | //------------------------------------------------------------- 41 | 42 | List _tools; 43 | 44 | public List Tools 45 | { 46 | get 47 | { 48 | if (_tools is null) 49 | { 50 | _tools = new List(); 51 | } 52 | 53 | return _tools; 54 | } 55 | } -------------------------------------------------------------------------------- /deployment/cake/vsextensions-variables.cake: -------------------------------------------------------------------------------- 1 | #l "buildserver.cake" 2 | 3 | public class VsExtensionsContext : BuildContextWithItemsBase 4 | { 5 | public VsExtensionsContext(IBuildContext parentBuildContext) 6 | : base(parentBuildContext) 7 | { 8 | } 9 | 10 | public string PublisherName { get; set; } 11 | public string PersonalAccessToken { get; set; } 12 | 13 | protected override void ValidateContext() 14 | { 15 | 16 | } 17 | 18 | protected override void LogStateInfoForContext() 19 | { 20 | CakeContext.Information($"Found '{Items.Count}' vs extension projects"); 21 | } 22 | } 23 | 24 | //------------------------------------------------------------- 25 | 26 | private VsExtensionsContext InitializeVsExtensionsContext(BuildContext buildContext, IBuildContext parentBuildContext) 27 | { 28 | var data = new VsExtensionsContext(parentBuildContext) 29 | { 30 | Items = VsExtensions ?? new List(), 31 | PublisherName = buildContext.BuildServer.GetVariable("VsExtensionsPublisherName", showValue: true), 32 | PersonalAccessToken = buildContext.BuildServer.GetVariable("VsExtensionsPersonalAccessToken", showValue: false), 33 | }; 34 | 35 | return data; 36 | } 37 | 38 | //------------------------------------------------------------- 39 | 40 | List _vsExtensions; 41 | 42 | public List VsExtensions 43 | { 44 | get 45 | { 46 | if (_vsExtensions is null) 47 | { 48 | _vsExtensions = new List(); 49 | } 50 | 51 | return _vsExtensions; 52 | } 53 | } -------------------------------------------------------------------------------- /design/logo/package_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fody/Costura/0f474a604cbc8260539b09e55ef64bcfb953cbb3/design/logo/package_icon.png -------------------------------------------------------------------------------- /design/package/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fody/Costura/0f474a604cbc8260539b09e55ef64bcfb953cbb3/design/package/icon.png -------------------------------------------------------------------------------- /src/.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.VisualStudio.Component.CoreEditor", 5 | "Microsoft.VisualStudio.Workload.CoreEditor", 6 | "Microsoft.Net.Component.4.8.SDK", 7 | "Microsoft.Net.Component.4.7.2.TargetingPack", 8 | "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites", 9 | "Microsoft.VisualStudio.Component.TypeScript.TSServer", 10 | "Microsoft.VisualStudio.ComponentGroup.WebToolsExtensions", 11 | "Microsoft.VisualStudio.Component.JavaScript.TypeScript", 12 | "Microsoft.VisualStudio.Component.JavaScript.Diagnostics", 13 | "Microsoft.VisualStudio.Component.Roslyn.Compiler", 14 | "Microsoft.Component.MSBuild", 15 | "Microsoft.VisualStudio.Component.Roslyn.LanguageServices", 16 | "Microsoft.VisualStudio.Component.TextTemplating", 17 | "Component.Microsoft.VisualStudio.RazorExtension", 18 | "Microsoft.VisualStudio.Component.IISExpress", 19 | "Microsoft.VisualStudio.Component.NuGet", 20 | "Microsoft.VisualStudio.Component.MSODBC.SQL", 21 | "Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime", 22 | "Microsoft.VisualStudio.Component.Common.Azure.Tools", 23 | "Microsoft.VisualStudio.Component.SQL.CLR", 24 | "Microsoft.VisualStudio.Component.MSSQL.CMDLnUtils", 25 | "Microsoft.VisualStudio.Component.ManagedDesktop.Core", 26 | "Microsoft.VisualStudio.Component.SQL.SSDT", 27 | "Microsoft.VisualStudio.Component.SQL.DataSources", 28 | "Component.Microsoft.Web.LibraryManager", 29 | "Component.Microsoft.WebTools.BrowserLink.WebLivePreview", 30 | "Microsoft.VisualStudio.ComponentGroup.Web", 31 | "Microsoft.NetCore.Component.Runtime.8.0", 32 | "Microsoft.NetCore.Component.SDK", 33 | "Microsoft.VisualStudio.Component.FSharp", 34 | "Microsoft.NetCore.Component.DevelopmentTools", 35 | "Microsoft.VisualStudio.Component.FSharp.WebTemplates", 36 | "Microsoft.VisualStudio.Component.DockerTools", 37 | "Microsoft.NetCore.Component.Web", 38 | "Microsoft.VisualStudio.Component.WebDeploy", 39 | "Microsoft.VisualStudio.Component.AppInsights.Tools", 40 | "Microsoft.VisualStudio.Component.Web", 41 | "Microsoft.VisualStudio.Component.AspNet45", 42 | "Microsoft.VisualStudio.Component.AspNet", 43 | "Component.Microsoft.VisualStudio.Web.AzureFunctions", 44 | "Microsoft.VisualStudio.ComponentGroup.AzureFunctions", 45 | "Microsoft.VisualStudio.ComponentGroup.Web.CloudTools", 46 | "Microsoft.VisualStudio.Component.DiagnosticTools", 47 | "Microsoft.VisualStudio.Component.Debugger.JustInTime", 48 | "Microsoft.VisualStudio.Component.WslDebugging", 49 | "Microsoft.VisualStudio.Workload.NetWeb", 50 | "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", 51 | "Microsoft.VisualStudio.Workload.ManagedDesktop" 52 | ], 53 | "extensions": [] 54 | } -------------------------------------------------------------------------------- /src/AssemblyToProcess/AssemblyToProcess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/AssemblyToProcess/ClassToTest.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | public class ClassToTest 4 | { 5 | static ClassToTest() 6 | { 7 | CosturaUtility.Initialize(); 8 | } 9 | 10 | public string Simple() => ClassToReference.Simple(); 11 | 12 | public string InternationalFoo() => ClassToReference.InternationalFoo(); 13 | 14 | public string SimplePreEmbed() => ClassToReferencePreEmbedded.SimplePreEmbed(); 15 | 16 | public string Exe() => ExeClassToReference.Exe(); 17 | 18 | public string RuntimeReferences() => global::RuntimeReferences.UseAssemblyWithRuntimeAssemblies(); 19 | 20 | 21 | public void ThrowException() 22 | { 23 | ClassToReference.ThrowException(); 24 | } 25 | 26 | public Assembly GetReferencedAssembly() => typeof(ClassToReference).Assembly; 27 | } 28 | -------------------------------------------------------------------------------- /src/AssemblyToReference/AssemblyToReference.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | full 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/AssemblyToReference/ClassToReference.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AssemblyToReference; 3 | 4 | public static class ClassToReference 5 | { 6 | public static string Simple() => "Hello"; 7 | 8 | public static void ThrowException() 9 | { 10 | throw new Exception("Hello"); 11 | } 12 | 13 | public static string InternationalFoo() => Strings.Hello; 14 | } 15 | -------------------------------------------------------------------------------- /src/AssemblyToReference/strings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace AssemblyToReference { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Strings { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Strings() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AssemblyToReference.Strings", typeof(Strings).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to Hello. 65 | /// 66 | internal static string Hello { 67 | get { 68 | return ResourceManager.GetString("Hello", resourceCulture); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/AssemblyToReference/strings.de.resx: -------------------------------------------------------------------------------- 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 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | Hallo 63 | 64 | -------------------------------------------------------------------------------- /src/AssemblyToReference/strings.fr.resx: -------------------------------------------------------------------------------- 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 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | Salut 63 | 64 | -------------------------------------------------------------------------------- /src/AssemblyToReference/strings.resx: -------------------------------------------------------------------------------- 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 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | Hello 63 | 64 | -------------------------------------------------------------------------------- /src/AssemblyToReferenceMixed/AssemblyToReferenceMixed.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/AssemblyToReferenceMixed/ClassToReferenceMixed.cpp: -------------------------------------------------------------------------------- 1 | using namespace System; 2 | 3 | public ref class ClassToReferenceMixed 4 | { 5 | public: 6 | static String^ Foo(); 7 | }; 8 | 9 | String^ ClassToReferenceMixed::Foo() { 10 | return "Hello"; 11 | }; -------------------------------------------------------------------------------- /src/AssemblyToReferenceMixed/Native.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | C# PInvoke Code 4 | 5 | [DllImport("AssemblyToReferenceMixed.dll", CallingConvention = CallingConvention.Cdecl)] 6 | [return: MarshalAs(UnmanagedType.BStr)] 7 | private static extern string SayHelloFromMixed(); 8 | 9 | */ 10 | 11 | #include 12 | 13 | extern "C" __declspec(dllexport) BSTR SayHelloFromMixed(); 14 | 15 | BSTR SayHelloFromMixed() 16 | { 17 | return ::SysAllocString(L"Hello"); 18 | } -------------------------------------------------------------------------------- /src/AssemblyToReferenceNative/AssemblyToReferenceNative.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/AssemblyToReferenceNative/Native.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | C# PInvoke Code 4 | 5 | [DllImport("AssemblyToReferenceNative.dll", CallingConvention = CallingConvention.Cdecl)] 6 | [return: MarshalAs(UnmanagedType.BStr)] 7 | private static extern string SayHelloFromNative(); 8 | 9 | */ 10 | 11 | #include 12 | 13 | extern "C" __declspec(dllexport) BSTR SayHelloFromNative(); 14 | 15 | BSTR SayHelloFromNative() 16 | { 17 | return ::SysAllocString(L"Hello"); 18 | } -------------------------------------------------------------------------------- /src/AssemblyToReferencePreEmbedded/AssemblyToReferencePreEmbedded.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/AssemblyToReferencePreEmbedded/ClassToReferencePreEmbedded.cs: -------------------------------------------------------------------------------- 1 | public static class ClassToReferencePreEmbedded 2 | { 3 | public static string SimplePreEmbed() => "Hello"; 4 | } -------------------------------------------------------------------------------- /src/AssemblyToReferenceWithRuntimeReferences/AssemblyToReferenceWithRuntimeReferences.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | full 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/AssemblyToReferenceWithRuntimeReferences/RuntimeReferences.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Data.SqlClient; 3 | 4 | public static class RuntimeReferences 5 | { 6 | public static string UseAssemblyWithRuntimeAssemblies() 7 | { 8 | using (var connection = new SqlConnection("Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;")) 9 | { 10 | try 11 | { 12 | connection.Open(); 13 | } 14 | catch (Exception) 15 | { 16 | // ignore 17 | } 18 | 19 | return "Hello"; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/AssemblyWithoutInitialize/AssemblyWithoutInitialize.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/AssemblyWithoutInitialize/ClassToTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | // ReSharper disable UnusedVariable 4 | 5 | public class ClassToTest 6 | { 7 | static ClassToTest() 8 | { 9 | // Produces an instruction with the method as an operand. 10 | // ldftn System.Void CosturaUtility::Initialize() 11 | var initialize = CosturaUtility.Initialize; 12 | } 13 | 14 | public string Simple() => ClassToReference.Simple(); 15 | 16 | public string InternationalFoo() => ClassToReference.InternationalFoo(); 17 | 18 | public string SimplePreEmbed() => ClassToReferencePreEmbedded.SimplePreEmbed(); 19 | 20 | public string Exe() => ExeClassToReference.Exe(); 21 | 22 | public void ThrowException() 23 | { 24 | ClassToReference.ThrowException(); 25 | } 26 | 27 | public Assembly GetReferencedAssembly() => typeof(ClassToReference).Assembly; 28 | } 29 | -------------------------------------------------------------------------------- /src/Costura.Fody.IntegrationTests/Costura.Fody.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net472;net8.0 4 | Costura.Fody.Tests 5 | Costura.Fody.Tests 6 | en-US 7 | Costura.Fody.Tests 8 | 1.0.0-alpha0001 9 | 10 | 11 | true 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 | -------------------------------------------------------------------------------- /src/Costura.Fody.IntegrationTests/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /src/Costura.Fody.IntegrationTests/Integration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using NUnit.Framework; 5 | 6 | [TestFixture] 7 | public class Integration 8 | { 9 | static Integration() 10 | { 11 | CosturaUtility.Initialize(); 12 | } 13 | 14 | [Test, Explicit] 15 | public void Test() 16 | { 17 | // just use some code from Newtonsoft.Json to ensure it's referenced. 18 | var json = Newtonsoft.Json.JsonConvert.SerializeObject(this); 19 | Assert.That(json, Is.EqualTo("{\"SomeProperty\":\"Test\"}")); 20 | 21 | // just use some code to ensure assemblies are properly embedded. 22 | var now = Catel.FastDateTime.Now; 23 | 24 | Console.WriteLine(now); 25 | 26 | var embeddedAssembly = typeof(Catel.FastDateTime).Assembly; 27 | var thisAssembly = GetType().Assembly; 28 | 29 | Assert.That(embeddedAssembly.Location,Is.Empty); 30 | // does not work on build server: Assert.Equal(embeddedAssembly.CodeBase, thisAssembly.CodeBase, StringComparer.OrdinalIgnoreCase); 31 | 32 | var targetDir = Path.GetDirectoryName(new Uri(thisAssembly.Location).LocalPath); 33 | 34 | var localCopyFiles = Directory.EnumerateFiles(targetDir) 35 | .Select(Path.GetFileName) 36 | .ToArray(); 37 | 38 | Assert.That(localCopyFiles.Any(file => file.StartsWith("Newtonsoft", StringComparison.OrdinalIgnoreCase)), Is.True); 39 | Assert.That(localCopyFiles.Any(file => file.StartsWith("Catel.Core", StringComparison.OrdinalIgnoreCase)), Is.False); 40 | } 41 | 42 | public string SomeProperty { get; set; } = "Test"; 43 | } 44 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/AssemblyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | public static class AssemblyExtensions 5 | { 6 | public static dynamic GetInstance(this Assembly assembly, string className) 7 | { 8 | var type = assembly.GetType(className, true); 9 | return Activator.CreateInstance(type); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/BaseCosturaTest.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | [TestFixture] 5 | public abstract class BaseCosturaTest 6 | { 7 | public abstract TestResult TestResult { get; } 8 | } 9 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/BasicTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Threading.Tasks; 4 | using NUnit.Framework; 5 | 6 | public abstract class BasicTests : BaseCosturaTest 7 | { 8 | [Test] 9 | public void Simple() 10 | { 11 | var instance = TestResult.GetInstance("ClassToTest"); 12 | Assert.That("Hello", Is.EqualTo(instance.Simple())); 13 | } 14 | 15 | [Test] 16 | public void SimplePreEmbed() 17 | { 18 | var instance2 = TestResult.GetInstance("ClassToTest"); 19 | Assert.That("Hello", Is.EqualTo(instance2.SimplePreEmbed())); 20 | } 21 | 22 | [Test] 23 | public void Exe() 24 | { 25 | var instance2 = TestResult.GetInstance("ClassToTest"); 26 | Assert.That("Hello", Is.EqualTo(instance2.Exe())); 27 | } 28 | 29 | [Test] 30 | public void ThrowException() 31 | { 32 | try 33 | { 34 | var instance = TestResult.GetInstance("ClassToTest"); 35 | instance.ThrowException(); 36 | } 37 | catch (Exception exception) 38 | { 39 | Debug.WriteLine(exception.StackTrace); 40 | Assert.That(exception.StackTrace.Contains("ClassToReference.cs:line"), Is.True); 41 | } 42 | } 43 | 44 | [Test] 45 | public void TypeReferencedWithPartialAssemblyNameIsLoadedFromExistingAssemblyInstance() 46 | { 47 | var instance = TestResult.GetInstance("ClassToTest"); 48 | var assemblyLoadedByCompileTimeReference = instance.GetReferencedAssembly(); 49 | var typeName = "ClassToReference, AssemblyToReference"; 50 | if (TestResult.Assembly.GetName().Name.EndsWith("35")) 51 | { 52 | typeName = typeName + "35"; 53 | } 54 | var typeLoadedWithPartialAssemblyName = Type.GetType(typeName); 55 | Assert.That(typeLoadedWithPartialAssemblyName, Is.Not.Null); 56 | 57 | Assert.That(assemblyLoadedByCompileTimeReference, Is.EqualTo(typeLoadedWithPartialAssemblyName.Assembly)); 58 | } 59 | 60 | [Test] 61 | public async Task TemplateHasCorrectSymbols() 62 | { 63 | await VerifyHelper.AssertIlCodeAsync(TestResult.AssemblyPath); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Costura.Fody.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | Costura.Fody.Tests 5 | Costura.Fody.Tests 6 | en-US 7 | Costura.Fody.Tests 8 | 1.0.0-alpha0001 9 | 10 | 11 | true 12 | true 13 | $(NoWarn);NU1201;CL0002 14 | $(NoError);NU1201 15 | 11.0 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 | 47 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/CultureResourceTests.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Fody; 5 | using NUnit.Framework; 6 | 7 | public class CultureResourceTests : BaseCosturaTest 8 | { 9 | private static readonly TestResult testResult; 10 | 11 | static CultureResourceTests() 12 | { 13 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcess.exe", 14 | "", 15 | new[] 16 | { 17 | "AssemblyToReference.dll", 18 | "de\\AssemblyToReference.resources.dll", 19 | "fr\\AssemblyToReference.resources.dll", 20 | "zh-CN\\AssemblyToReference.resources.dll", 21 | "zh-Hans\\AssemblyToReference.resources.dll", 22 | "AssemblyToReferencePreEmbedded.dll", 23 | "ExeToReference.exe" 24 | }, "Culture"); 25 | } 26 | 27 | [Test] 28 | public void Using_Resource_French() 29 | { 30 | var culture = Thread.CurrentThread.CurrentUICulture; 31 | try 32 | { 33 | Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("fr-FR"); 34 | var instance1 = testResult.GetInstance("ClassToTest"); 35 | Assert.That(instance1.InternationalFoo(), Is.EqualTo("Salut")); 36 | } 37 | finally 38 | { 39 | Thread.CurrentThread.CurrentUICulture = culture; 40 | } 41 | } 42 | 43 | [Test] 44 | public void Using_Resource_Chinese() 45 | { 46 | var culture = Thread.CurrentThread.CurrentUICulture; 47 | try 48 | { 49 | // Yes, this seems correct, when creating the zh-Hans culture, it uses zh-CN 50 | Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("zh-Hans"); 51 | var instance1 = testResult.GetInstance("ClassToTest"); 52 | Assert.That(instance1.InternationalFoo(), Is.EqualTo("zh-CN")); 53 | } 54 | finally 55 | { 56 | Thread.CurrentThread.CurrentUICulture = culture; 57 | } 58 | } 59 | 60 | [Test] 61 | public async Task TemplateHasCorrectSymbols() 62 | { 63 | await VerifyHelper.AssertIlCodeAsync(TestResult.AssemblyPath); 64 | } 65 | 66 | public override TestResult TestResult => testResult; 67 | } 68 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Helpers/AssemblyDirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | namespace Costura.Fody.Tests 2 | { 3 | using System; 4 | 5 | internal static class AssemblyDirectoryHelper 6 | { 7 | public static string GetCurrentDirectory() 8 | { 9 | var directory = AppDomain.CurrentDomain.BaseDirectory; 10 | return directory; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Helpers/AssemblyHelper.cs: -------------------------------------------------------------------------------- 1 | #if NETCORE 2 | 3 | using System; 4 | using System.IO; 5 | using System.Reflection.PortableExecutable; 6 | 7 | internal static class AssemblyHelper 8 | { 9 | public static bool IsManagedAssembly(string assemblyPath) 10 | { 11 | try 12 | { 13 | using var fileStream = File.OpenRead(assemblyPath); 14 | using var peReader = new PEReader(fileStream); 15 | 16 | if (!peReader.HasMetadata) 17 | { 18 | return false; 19 | } 20 | } 21 | catch (Exception) 22 | { 23 | return false; 24 | } 25 | 26 | // Assume true 27 | return true; 28 | } 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Helpers/RunHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | 4 | internal static class RunHelper 5 | { 6 | public static string RunExecutable(string executablePath) 7 | { 8 | if (executablePath.EndsWith(".dll")) 9 | { 10 | executablePath = Path.ChangeExtension(executablePath, ".exe"); 11 | } 12 | 13 | var startInfo = new ProcessStartInfo(executablePath) 14 | { 15 | CreateNoWindow = true, 16 | RedirectStandardOutput = true, 17 | UseShellExecute = false, 18 | }; 19 | 20 | using var process = new Process 21 | { 22 | StartInfo = startInfo 23 | }; 24 | process.Start(); 25 | process.WaitForExit(); 26 | return process.StandardOutput.ReadToEnd(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Helpers/VerifyHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Threading.Tasks; 4 | using Microsoft.Win32.SafeHandles; 5 | using VerifyNUnit; 6 | using VerifyTests; 7 | 8 | public static class VerifyHelper 9 | { 10 | static VerifyHelper() 11 | { 12 | } 13 | 14 | [MethodImpl(MethodImplOptions.NoInlining)] 15 | public static async Task AssertIlCodeAsync(string assemblyFileName, [CallerMemberName] string callerMemberName = "") 16 | { 17 | var actualIl = Ildasm.Decompile(assemblyFileName, "Costura.AssemblyLoader"); 18 | 19 | var settings = new VerifySettings 20 | { 21 | 22 | }; 23 | 24 | settings.UniqueForAssemblyConfiguration(); 25 | settings.UniqueForTargetFrameworkAndVersion(); 26 | 27 | // Replace versions so it never breaks on updates 28 | foreach (var assembly in new[] 29 | { 30 | typeof(VerifyHelper).Assembly, // test assembly version 31 | typeof(CriticalHandleMinusOneIsInvalid).Assembly, // System.Private.CoreLib 32 | }) 33 | { 34 | var search = $"Version={assembly.GetCustomAttribute().Version}"; 35 | 36 | settings.ScrubLinesWithReplace(replaceLine: _ => 37 | { 38 | return _.Replace(search, "Version=Version"); 39 | }); 40 | } 41 | 42 | await Verifier.Verify(actualIl, settings); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Helpers/WeavingHelper.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | using System.Xml.Linq; 4 | using Costura.Fody.Tests; 5 | using Fody; 6 | 7 | public static class WeavingHelper 8 | { 9 | public static TestResult CreateIsolatedAssemblyCopy(string assemblyPath, string config, string[] references, string assemblyName) 10 | { 11 | var currentDirectory = AssemblyDirectoryHelper.GetCurrentDirectory(); 12 | 13 | using (var weaver = new ModuleWeaver 14 | { 15 | Config = XElement.Parse(config), 16 | References = string.Join(";", references.Select(r => Path.Combine(currentDirectory, r))), 17 | ReferenceCopyLocalPaths = references.Select(r => Path.Combine(currentDirectory, r)).ToList(), 18 | }) 19 | { 20 | if (!Path.IsPathRooted(assemblyPath)) 21 | { 22 | assemblyPath = Path.Combine(currentDirectory, assemblyPath); 23 | } 24 | 25 | #if NETCORE 26 | var shouldCopyExe = false; 27 | var originalExe = string.Empty; 28 | 29 | // Exe are now native, use .dll instead, but copy the exe 30 | if (assemblyPath.EndsWith(".exe", System.StringComparison.OrdinalIgnoreCase)) 31 | { 32 | if (!AssemblyHelper.IsManagedAssembly(assemblyPath)) 33 | { 34 | shouldCopyExe = true; 35 | originalExe = assemblyPath; 36 | 37 | assemblyPath = Path.ChangeExtension(assemblyPath, ".dll"); 38 | } 39 | } 40 | #endif 41 | 42 | var assembly = weaver.ExecuteTestRun( 43 | assemblyPath, 44 | folderName: assemblyName, 45 | ignoreCodes: new[] { "0x80131869" }, 46 | runPeVerify: false); 47 | 48 | #if NETCORE 49 | if (shouldCopyExe && !string.IsNullOrWhiteSpace(originalExe)) 50 | { 51 | var destinationExe = Path.ChangeExtension(assembly.AssemblyPath, ".exe"); 52 | 53 | File.Copy(originalExe, destinationExe, true); 54 | } 55 | 56 | var extensionsToCopy = new[] 57 | { 58 | ".runtimeconfig.json", 59 | ".pdb" 60 | }; 61 | 62 | foreach (var extensionToCopy in extensionsToCopy) 63 | { 64 | var targetFile = Path.ChangeExtension(assembly.AssemblyPath, extensionToCopy); 65 | var sourceFile = Path.Combine(currentDirectory, Path.GetFileName(targetFile)); 66 | 67 | if (File.Exists(sourceFile)) 68 | { 69 | File.Copy(sourceFile, targetFile, true); 70 | } 71 | } 72 | #endif 73 | 74 | return assembly; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Ildasm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text.RegularExpressions; 4 | 5 | public class Ildasm 6 | { 7 | public static string Decompile(string afterAssemblyPath, string costuraAssemblyLoader) 8 | { 9 | #pragma warning disable CS0618 // Type or member is obsolete 10 | var decompile = Fody.Ildasm.Decompile(afterAssemblyPath, costuraAssemblyLoader); 11 | #pragma warning restore CS0618 // Type or member is obsolete 12 | var checksumPattern = new Regex(@"^(\s*IL_[0123456789abcdef]{4}: ldstr\s*"")[0123456789ABCDEF]{32,40}""", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 13 | return string.Join(Environment.NewLine, decompile.Split(new[]{ Environment.NewLine }, StringSplitOptions.None) 14 | .Where(l => !l.StartsWith("// ", StringComparison.CurrentCulture) && !string.IsNullOrEmpty(l)) 15 | .Select(l => checksumPattern.Replace(l, _ => _.Groups[1].Value + "[CHECKSUM]\"")) 16 | .ToList()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/InMemoryTests.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | public class InMemoryTests : BasicTests 5 | { 6 | private static readonly TestResult testResult; 7 | 8 | static InMemoryTests() 9 | { 10 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcess.exe", 11 | "", 12 | new[] {"AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe"}, "InMemory"); 13 | } 14 | 15 | [Test] 16 | public void ExecutableRunsSuccessfully() 17 | { 18 | var output = RunHelper.RunExecutable(TestResult.AssemblyPath); 19 | Assert.That(output, Is.EqualTo("Run-OK")); 20 | } 21 | 22 | public override TestResult TestResult => testResult; 23 | } 24 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/InitializeCallTests.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | 3 | public class InitializeCallTests : BasicTests 4 | { 5 | private static readonly TestResult testResult; 6 | 7 | static InitializeCallTests() 8 | { 9 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 10 | "", 11 | new[] { "AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe" }, 12 | "InitializeCall"); 13 | } 14 | 15 | public override TestResult TestResult => testResult; 16 | } 17 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/InitializeCallWithoutModuleInitTest.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | 3 | public class InitializeCallWithoutModuleInitTest : BasicTests 4 | { 5 | private static readonly TestResult testResult; 6 | 7 | static InitializeCallWithoutModuleInitTest() 8 | { 9 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 10 | "", 11 | new[] {"AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe"}, 12 | "InitializeCallWithoutModuleInit"); 13 | } 14 | 15 | public override TestResult TestResult => testResult; 16 | } 17 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/MixedAndNativeTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Fody; 3 | using NUnit.Framework; 4 | 5 | public class MixedAndNativeTests : BaseCosturaTest 6 | { 7 | public override TestResult TestResult => testResult; 8 | 9 | private static readonly TestResult testResult = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcessWithNative.exe", 10 | "", 11 | new[] { "AssemblyToReferenceMixed.dll" }, "MixedAndNative"); 12 | 13 | [Test] 14 | public void Native() 15 | { 16 | var instance1 = TestResult.GetInstance("ClassToTest"); 17 | Assert.That("Hello", Is.EqualTo(instance1.NativeFoo())); 18 | } 19 | 20 | [Test] 21 | public void Mixed() 22 | { 23 | var instance1 = TestResult.GetInstance("ClassToTest"); 24 | Assert.That("Hello", Is.EqualTo(instance1.MixedFoo())); 25 | } 26 | 27 | [Test] 28 | public void MixedPInvoke() 29 | { 30 | var instance1 = TestResult.GetInstance("ClassToTest"); 31 | Assert.That("Hello", Is.EqualTo(instance1.MixedFooPInvoke())); 32 | } 33 | 34 | [Test] 35 | public async Task TemplateHasCorrectSymbols() 36 | { 37 | await VerifyHelper.AssertIlCodeAsync(TestResult.AssemblyPath); 38 | } 39 | 40 | [Test] 41 | public void ExecutableRunsSuccessfully() 42 | { 43 | var output = RunHelper.RunExecutable(TestResult.AssemblyPath); 44 | Assert.That(output, Is.EqualTo("Run-OK")); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/MixedAndNativeTestsWithEmbeddedMixed.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | public class MixedAndNativeTestsWithEmbeddedMixed : BaseCosturaTest 5 | { 6 | public override TestResult TestResult => testResult; 7 | 8 | #pragma warning disable IDE1006 // Naming Styles 9 | private static readonly TestResult testResult = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcessWithNativeAndEmbeddedMixed.exe", 10 | #pragma warning restore IDE1006 // Naming Styles 11 | "", 12 | new[] {"AssemblyToReferenceMixed.dll"}, "MixedAndNative"); 13 | 14 | [Test] 15 | public void Native() 16 | { 17 | var instance1 = TestResult.GetInstance("ClassToTest"); 18 | Assert.That("Hello", Is.EqualTo(instance1.NativeFoo())); 19 | } 20 | 21 | [Test] 22 | public void Mixed() 23 | { 24 | var instance1 = TestResult.GetInstance("ClassToTest"); 25 | Assert.That("Hello", Is.EqualTo(instance1.MixedFoo())); 26 | } 27 | 28 | [Test] 29 | public void MixedPInvoke() 30 | { 31 | var instance1 = TestResult.GetInstance("ClassToTest"); 32 | Assert.That("Hello", Is.EqualTo(instance1.MixedFooPInvoke())); 33 | } 34 | 35 | [Test] 36 | public void ExecutableRunsSuccessfully() 37 | { 38 | var output = RunHelper.RunExecutable(TestResult.AssemblyPath); 39 | Assert.That(output, Is.EqualTo("Run-OK")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/MultipleNativeTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Fody; 3 | using NUnit.Framework; 4 | 5 | public class MultipleNativeTests : BaseCosturaTest 6 | { 7 | #pragma warning disable IDE1006 // Naming Styles 8 | private static readonly TestResult testResult = WeavingHelper.CreateIsolatedAssemblyCopy( 9 | #pragma warning restore IDE1006 // Naming Styles 10 | "ExeToProcessWithMultipleNative.exe", 11 | "", 12 | Array.Empty(), 13 | "MultipleNative"); 14 | 15 | public override TestResult TestResult => testResult; 16 | 17 | [Test] 18 | public void Native() 19 | { 20 | var instance1 = TestResult.GetInstance("ExeToProcessWithMultipleNative.Program"); 21 | Assert.That(42, Is.EqualTo(instance1.Test())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/MultipleNativeTestsWithPreloadOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Fody; 3 | using NUnit.Framework; 4 | 5 | public class MultipleNativeTestsWithPreloadOrder : BaseCosturaTest 6 | { 7 | #pragma warning disable IDE1006 // Naming Styles 8 | private static readonly TestResult testResult = WeavingHelper.CreateIsolatedAssemblyCopy( 9 | #pragma warning restore IDE1006 // Naming Styles 10 | "ExeToProcessWithMultipleNative.exe", 11 | "", 12 | Array.Empty(), 13 | "MultipleNativeWithPreloadOrder"); 14 | 15 | public override TestResult TestResult => testResult; 16 | 17 | [Test] 18 | public void Native() 19 | { 20 | var instance1 = TestResult.GetInstance("ExeToProcessWithMultipleNative.Program"); 21 | Assert.That(42, Is.EqualTo(instance1.Test())); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/NativeTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Costura.Fody.Tests; 3 | using NUnit.Framework; 4 | 5 | public abstract class NativeTests : BaseCosturaTest 6 | { 7 | [Test] 8 | public void Native() 9 | { 10 | var instance1 = TestResult.GetInstance("ClassToTest"); 11 | Assert.That("Hello", Is.EqualTo(instance1.NativeFoo())); 12 | } 13 | 14 | [Test] 15 | public void Mixed() 16 | { 17 | var instance1 = TestResult.GetInstance("ClassToTest"); 18 | Assert.That("Hello", Is.EqualTo(instance1.MixedFoo())); 19 | } 20 | 21 | [Test] 22 | public void MixedPInvoke() 23 | { 24 | var instance1 = TestResult.GetInstance("ClassToTest"); 25 | Assert.That("Hello", Is.EqualTo(instance1.MixedFooPInvoke())); 26 | } 27 | 28 | [Test] 29 | public async Task TemplateHasCorrectSymbols() 30 | { 31 | await VerifyHelper.AssertIlCodeAsync(TestResult.AssemblyPath); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/NoEventSubscriptionTest.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | using System; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | 7 | #if NETCORE 8 | using System.Runtime.Loader; 9 | #else 10 | 11 | #endif 12 | 13 | [TestFixture] 14 | public class NoEventSubscriptionTest : BaseCosturaTest 15 | { 16 | private static readonly TestResult testResult; 17 | 18 | static NoEventSubscriptionTest() 19 | { 20 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 21 | "", 22 | new[] { "AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe" }, 23 | "DisableEventSubscription"); 24 | } 25 | 26 | public override TestResult TestResult => testResult; 27 | 28 | 29 | 30 | [Test, Explicit("Consider finalizing this test")] 31 | public void Does_Not_Subscribe_To_Events() 32 | { 33 | var instance2 = TestResult.GetInstance("ClassToTest"); 34 | 35 | EventInfo eventInfo = null; 36 | object instance = null; 37 | 38 | #if NETCORE 39 | instance = AssemblyLoadContext.Default; 40 | eventInfo = typeof(AssemblyLoadContext).GetEvent("Resolving"); 41 | #else 42 | instance = AppDomain.CurrentDomain; 43 | eventInfo = typeof(AppDomain).GetEvent("AssemblyResolve"); 44 | #endif 45 | 46 | //var eventField = instance.GetType().GetRuntimeFields().Single(x => x.Name == $"_{eventInfo.Name}"); 47 | 48 | //var eventInstance = (EventHandler)eventField.GetValue(instance); 49 | 50 | //var invocationList = eventInstance.GetInvocationList(); 51 | 52 | //Assert.That(invocationList.Count, Is.EqualTo(0)); 53 | 54 | //Assert.That("Hello", Is.EqualTo(instance2.SimplePreEmbed())); 55 | } 56 | 57 | [Test] 58 | public async Task TemplateHasCorrectSymbols() 59 | { 60 | await VerifyHelper.AssertIlCodeAsync(TestResult.AssemblyPath); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/NoInitializeTest.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | [TestFixture] 5 | public class NoInitializeTest 6 | { 7 | [Test] 8 | public void FailsToWeave() 9 | { 10 | Assert.Throws(() => 11 | WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyWithoutInitialize.dll", 12 | "", 13 | new[] { "AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe" }, 14 | "NoInitialize")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | #if DEBUG 4 | [assembly: AssemblyConfiguration("Debug")] 5 | #else 6 | [assembly: AssemblyConfiguration("Release")] 7 | #endif 8 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/ReferenceCasingTests.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | 3 | public class ReferenceCasingTests : BasicTests 4 | { 5 | private static readonly TestResult testResult; 6 | 7 | static ReferenceCasingTests() 8 | { 9 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 10 | "", 11 | new[] { "AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe" }, 12 | "ReferenceCasing"); 13 | } 14 | 15 | public override TestResult TestResult => testResult; 16 | } 17 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/ReferenceMissingTests.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | [TestFixture] 5 | public class ReferenceMissingTests 6 | { 7 | [Test] 8 | public void ThrowsForMissingReference() 9 | { 10 | // Note: this will throw WeavingException because References is null, but should actually 11 | // log an error about the missing assembly 12 | Assert.Throws(() => 13 | { 14 | WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 15 | "", 16 | new[] { "AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe" }, 17 | "InitializeCall"); 18 | }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/ReferenceTests.cs: -------------------------------------------------------------------------------- 1 | namespace Costura.Fody.Tests 2 | { 3 | using NUnit.Framework; 4 | 5 | [TestFixture] 6 | public class ReferenceTests 7 | { 8 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", "Catel.Core.dll")] 9 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", "nl/Catel.Core.resources.dll")] 10 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", "runtimes/win-x64/Catel.Core.dll")] 11 | public void RelativePath(string input, string expectedOutput) 12 | { 13 | var reference = new Reference(input, useRuntimeReferencePaths: true); 14 | 15 | Assert.That(reference.RelativeFileName, Is.EqualTo(expectedOutput)); 16 | } 17 | 18 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", "Catel.Core.dll")] 19 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", "nl/Catel.Core.resources.dll")] 20 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", "Catel.Core.dll")] 21 | public void RelativePath_UseNonRuntimeReferencePath(string input, string expectedOutput) 22 | { 23 | var reference = new Reference(input, useRuntimeReferencePaths: false); 24 | 25 | Assert.That(reference.RelativeFileName, Is.EqualTo(expectedOutput)); 26 | } 27 | 28 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", "")] 29 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", "")] 30 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", "runtimes.win-x64")] 31 | public void RelativePrefix(string input, string expectedOutput) 32 | { 33 | var reference = new Reference(input, useRuntimeReferencePaths: true); 34 | 35 | Assert.That(reference.RelativePrefix, Is.EqualTo(expectedOutput)); 36 | } 37 | 38 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", "")] 39 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", "")] 40 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", "")] 41 | public void RelativePrefix_UseNonRuntimeReferencePath(string input, string expectedOutput) 42 | { 43 | var reference = new Reference(input, useRuntimeReferencePaths: false); 44 | 45 | Assert.That(reference.RelativePrefix, Is.EqualTo(expectedOutput)); 46 | } 47 | 48 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", false)] 49 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", false)] 50 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", true)] 51 | public void IsRuntimeReference(string input, bool expectedOutput) 52 | { 53 | var reference = new Reference(input, useRuntimeReferencePaths: true); 54 | 55 | Assert.That(reference.IsRuntimeReference, Is.EqualTo(expectedOutput)); 56 | } 57 | 58 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", false)] 59 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", false)] 60 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", false)] 61 | public void IsRuntimeReference_UseNonRuntimeReferencePath(string input, bool expectedOutput) 62 | { 63 | var reference = new Reference(input, useRuntimeReferencePaths: false); 64 | 65 | Assert.That(reference.IsRuntimeReference, Is.EqualTo(expectedOutput)); 66 | } 67 | 68 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", false)] 69 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", true)] 70 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", false)] 71 | public void IsResourcesAssembly(string input, bool expectedOutput) 72 | { 73 | var reference = new Reference(input, useRuntimeReferencePaths: true); 74 | 75 | Assert.That(reference.IsResourcesAssembly, Is.EqualTo(expectedOutput)); 76 | } 77 | 78 | [TestCase(@"C:\Source\Catel.Core\output\Catel.Core.dll", false)] 79 | [TestCase(@"C:\Source\Catel.Core\output\nl\Catel.Core.resources.dll", true)] 80 | [TestCase(@"C:\Source\Catel.Core\output\runtimes\win-x64\Catel.Core.dll", false)] 81 | public void IsResourcesAssembly_UseNonRuntimeReferencePath(string input, bool expectedOutput) 82 | { 83 | var reference = new Reference(input, useRuntimeReferencePaths: false); 84 | 85 | Assert.That(reference.IsResourcesAssembly, Is.EqualTo(expectedOutput)); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/ResourceEmbedderTests.cs: -------------------------------------------------------------------------------- 1 | namespace Costura.Fody.Tests 2 | { 3 | using NUnit.Framework; 4 | 5 | [TestFixture] 6 | public class ResourceEmbedderTests 7 | { 8 | private const string CacheRoot = "C:\\CI_WS\\Ws\\195338\\Source\\My_SuperLarge_ProjectName_WithTooLongPaths\\src\\My_SuperLarge_ProjectName_With_Additional_SuperPaths\\obj\\Release\\net5.0-windows\\Costura"; 9 | private const string DummyShaChecksum = "123456789123456789123456789"; 10 | 11 | [TestCase("shortpath.dll", $"{CacheRoot}\\{DummyShaChecksum}.shortpath.dll.compressed")] 12 | [TestCase("runtimes.unix.lib.netcoreapp2.1.microsoft.data.sqlclient.dll", $"{CacheRoot}\\{DummyShaChecksum}.1.compressed")] 13 | public void TheGetCacheFileMethod(string resourceName, string expectedOutput) 14 | { 15 | // Just dummy values 16 | using (var moduleWeaver = new ModuleWeaver()) 17 | { 18 | var actualOutput = moduleWeaver.GetCacheFile(CacheRoot, resourceName, true, DummyShaChecksum); 19 | 20 | Assert.That(actualOutput, Is.EqualTo(expectedOutput)); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/RuntimeReferencesTests.cs: -------------------------------------------------------------------------------- 1 | namespace Costura.Fody.Tests 2 | { 3 | using System; 4 | using System.IO; 5 | using global::Fody; 6 | using NUnit.Framework; 7 | 8 | public class RuntimeReferencesTests : BaseCosturaTest 9 | { 10 | private static readonly TestResult testResult; 11 | 12 | static RuntimeReferencesTests() 13 | { 14 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("AssemblyToProcess.dll", 15 | "", 16 | new[] { "AssemblyToReferenceWithRuntimeReferences.dll" }, 17 | "RuntimeReferences"); 18 | } 19 | 20 | public override TestResult TestResult => testResult; 21 | 22 | [Explicit, Test] 23 | public void UseRuntimeReferences() 24 | { 25 | DeleteRuntimeReferencesFolder(); 26 | 27 | var instance = TestResult.GetInstance("ClassToTest"); 28 | Assert.That("Hello", Is.EqualTo(instance.RuntimeReferences())); 29 | } 30 | 31 | private void DeleteRuntimeReferencesFolder() 32 | { 33 | // Because we can't use private assets for project references, we have to delete the runtimes folder manually 34 | 35 | var location = Path.GetDirectoryName(GetType().Assembly.Location); 36 | var runtimesFolder = Path.Combine(location, "runtimes"); 37 | 38 | try 39 | { 40 | Directory.Delete(runtimesFolder, true); 41 | } 42 | catch (Exception) 43 | { 44 | // Some libs might not be deleted, but the runtime references have been deleted 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/TempFileTests.cs: -------------------------------------------------------------------------------- 1 | using Fody; 2 | using NUnit.Framework; 3 | 4 | public class TempFileTests : BasicTests 5 | { 6 | private static readonly TestResult testResult; 7 | public override TestResult TestResult => testResult; 8 | 9 | static TempFileTests() 10 | { 11 | testResult = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcess.exe", 12 | "", 13 | new[] {"AssemblyToReference.dll", "AssemblyToReferencePreEmbedded.dll", "ExeToReference.exe"}, "TempFile"); 14 | } 15 | 16 | [Test] 17 | #if NETCORE 18 | [Explicit("Somehow this only succeeds when ran manually for .NET Core")] 19 | #endif 20 | public void ExecutableRunsSuccessfully() 21 | { 22 | var output = RunHelper.RunExecutable(TestResult.AssemblyPath); 23 | Assert.That(output, Is.EqualTo("Run-OK")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Costura.Fody.Tests/WildcardTest.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | 4 | public class WildcardTest 5 | { 6 | [Test] 7 | public void WeavesWildcards() 8 | { 9 | var wildcardWeave = WeavingHelper.CreateIsolatedAssemblyCopy("ExeToProcess.exe", 10 | "", 11 | new[] { "AssemblyToReference.dll", "AssemblyToReferenceMixed.dll"}, "WildcardWeave"); 12 | 13 | var referencedAssemblies = wildcardWeave.Assembly.GetReferencedAssemblies().Select(_ => _.Name).ToList(); 14 | Assert.That(referencedAssemblies, Does.Contain("AssemblyToReference")); 15 | Assert.That(referencedAssemblies, Does.Contain("AssemblyToReferencePreEmbedded")); 16 | 17 | var instance = wildcardWeave.GetInstance("ClassToTest"); 18 | Assert.That("Hello", Is.EqualTo(instance.Simple())); 19 | Assert.That("Hello", Is.EqualTo(instance.SimplePreEmbed())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Costura.Fody/CallAttach.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Fody; 3 | using Mono.Cecil; 4 | using Mono.Cecil.Cil; 5 | 6 | public partial class ModuleWeaver 7 | { 8 | private void CallAttach(Configuration config) 9 | { 10 | var initialized = FindInitializeCalls(config); 11 | 12 | if (config.LoadAtModuleInit) 13 | { 14 | AddModuleInitializerCall(config); 15 | } 16 | else if (!initialized) 17 | { 18 | throw new WeavingException("Costura was not initialized. Make sure LoadAtModuleInit=true or call CosturaUtility.Initialize()."); 19 | } 20 | } 21 | 22 | private bool FindInitializeCalls(Configuration config) 23 | { 24 | var found = false; 25 | 26 | foreach (var type in ModuleDefinition.Types) 27 | { 28 | if (!type.HasMethods) 29 | { 30 | continue; 31 | } 32 | 33 | foreach (var method in type.Methods) 34 | { 35 | if (!method.HasBody) 36 | { 37 | continue; 38 | } 39 | 40 | var instructions = method.Body.Instructions; 41 | for (var i = 0; i < instructions.Count; i++) 42 | { 43 | var instruction = instructions[i]; 44 | if (instruction.OpCode != OpCodes.Call) 45 | { 46 | continue; 47 | } 48 | 49 | if (instruction.Operand is not MethodReference callMethod) 50 | { 51 | continue; 52 | } 53 | 54 | if (callMethod.FullName == "System.Void CosturaUtility::Initialize()") 55 | { 56 | found = true; 57 | 58 | instructions[i] = Instruction.Create(OpCodes.Call, _attachMethod); 59 | instructions.Insert(i--, Instruction.Create(config.DisableEventSubscription ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1)); 60 | } 61 | } 62 | } 63 | } 64 | 65 | return found; 66 | } 67 | 68 | private void AddModuleInitializerCall(Configuration config) 69 | { 70 | const MethodAttributes attributes = MethodAttributes.Private 71 | | MethodAttributes.HideBySig 72 | | MethodAttributes.Static 73 | | MethodAttributes.SpecialName 74 | | MethodAttributes.RTSpecialName; 75 | 76 | var moduleClass = ModuleDefinition.Types.FirstOrDefault(_ => _.Name == ""); 77 | if (moduleClass is null) 78 | { 79 | throw new WeavingException("Found no module class!"); 80 | } 81 | 82 | var cctor = moduleClass.Methods.FirstOrDefault(_ => _.Name == ".cctor"); 83 | if (cctor is null) 84 | { 85 | cctor = new MethodDefinition(".cctor", attributes, TypeSystem.VoidReference); 86 | cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); 87 | moduleClass.Methods.Add(cctor); 88 | } 89 | 90 | cctor.Body.Instructions.Insert(0, Instruction.Create(config.DisableEventSubscription ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1)); 91 | cctor.Body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, _attachMethod)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Costura.Fody/Checksums.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Security.Cryptography; 4 | using System.Text; 5 | 6 | public partial class ModuleWeaver 7 | { 8 | private readonly Dictionary _checksums = new Dictionary(); 9 | 10 | private static string CalculateSha1Checksum(string filename) 11 | { 12 | using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 13 | { 14 | return CalculateSha1Checksum(fs); 15 | } 16 | } 17 | 18 | private static string CalculateSha1Checksum(Stream stream) 19 | { 20 | using (var bs = new BufferedStream(stream)) 21 | { 22 | using (var sha1 = new SHA1CryptoServiceProvider()) 23 | { 24 | var hash = sha1.ComputeHash(bs); 25 | var formatted = new StringBuilder(2 * hash.Length); 26 | 27 | foreach (var b in hash) 28 | { 29 | formatted.AppendFormat("{0:X2}", b); 30 | } 31 | 32 | return formatted.ToString(); 33 | } 34 | } 35 | } 36 | 37 | private void AddChecksumsToTemplate() 38 | { 39 | if (_checksumsField is null) 40 | { 41 | return; 42 | } 43 | 44 | foreach (var checksum in _checksums) 45 | { 46 | AddToDictionary(_checksumsField, checksum.Key, checksum.Value); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Costura.Fody/Costura.Fody.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net472;netstandard2.0 4 | Costura.Fody 5 | Costura.Fody 6 | en-US 7 | true 8 | Debug;Release;Test 9 | 10 | 11 | 12 | 13 | E5622B74-B6C6-46A5-9207-0872533E6C2F 14 | 15 | 16 | 17 | false 18 | 19 | 20 | 21 | 22 | bin\Template.dll 23 | false 24 | Costura.Template.netstandard2.0.dll 25 | 26 | 27 | bin\Template.dll 28 | false 29 | Costura.Template.net6.0.dll 30 | 31 | 32 | bin\Template.dll 33 | false 34 | Costura.Template.net8.0.dll 35 | 36 | 37 | 38 | bin\netstandard.dll 39 | false 40 | Costura.NETFramework.netstandard.dll 41 | 42 | 43 | 44 | src\Common.cs 45 | false 46 | 47 | 48 | 49 | src\ILTemplate.cs 50 | false 51 | 52 | 53 | 54 | src\ILTemplateWithTempAssembly.cs 55 | false 56 | 57 | 58 | 59 | src\ILTemplateWithUnmanagedHandler.cs 60 | false 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | PreserveNewest 71 | 72 | 73 | PreserveNewest 74 | 75 | 76 | PreserveNewest 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | false 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/Costura.Fody/Costura.Fody.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netclassicweaver 6 | netstandardweaver 8 | 9 | 10 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Costura.Fody/Costura.Fody.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Costura.Fody/EmbeddedReferenceInfo.cs: -------------------------------------------------------------------------------- 1 | public class EmbeddedReferenceInfo 2 | { 3 | public string ResourceName { get; set; } 4 | 5 | public string Version { get; set; } 6 | 7 | public string AssemblyName { get; set; } 8 | 9 | public string RelativeFileName { get; set; } 10 | 11 | public string Sha1Checksum { get; set; } 12 | 13 | public long Size { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return $"{ResourceName}|{Version}|{AssemblyName}|{RelativeFileName}|{Sha1Checksum}|{Size}"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Costura.Fody/Extensions/AssemblyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | 5 | internal static class AssemblyExtensions 6 | { 7 | public static string GetVersion(this Assembly assembly) 8 | { 9 | var version = GetAssemblyAttribute(assembly); 10 | return version is null ? null : version.InformationalVersion; 11 | } 12 | 13 | private static TAttibute GetAssemblyAttribute(Assembly assembly) 14 | where TAttibute : Attribute 15 | { 16 | var attibutes = assembly.GetCustomAttributes(typeof(TAttibute))?.ToArray() ?? Array.Empty(); 17 | return attibutes.Length > 0 ? attibutes[0] as TAttibute : null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Costura.Fody/Extensions/CecilExtensions.assembly.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mono.Cecil; 3 | 4 | public static partial class CecilExtensions 5 | { 6 | public static Version GetVersion(this AssemblyDefinition assemblyDefinition) 7 | { 8 | return assemblyDefinition.Name.Version; 9 | 10 | //var stringVersion = "0.0.0.0"; 11 | 12 | //var assemblyVersionAttributeName = typeof(AssemblyVersionAttribute).FullName; 13 | //var assemblyFileVersionAttributeName = typeof(AssemblyFileVersionAttribute).FullName; 14 | 15 | //var attribute = assemblyDefinition.CustomAttributes.FirstOrDefault(_ => _.AttributeType.FullName == assemblyVersionAttributeName); 16 | //if (attribute is null) 17 | //{ 18 | // attribute = assemblyDefinition.CustomAttributes.FirstOrDefault(_ => _.AttributeType.FullName == assemblyFileVersionAttributeName); 19 | //} 20 | 21 | //if (attribute is not null) 22 | //{ 23 | // stringVersion = (string)attribute.ConstructorArguments.First().Value; 24 | //} 25 | 26 | //var version = new Version(stringVersion); 27 | //return version; 28 | } 29 | 30 | public static bool IsNetStandardLibrary(this AssemblyDefinition assemblyDefinition) 31 | { 32 | return assemblyDefinition.MainModule.FileName.IndexOf("netstandard", 0, StringComparison.OrdinalIgnoreCase) >= 0; 33 | } 34 | 35 | public static bool IsUsingDotNetCore(this AssemblyDefinition assemblyDefinition) 36 | { 37 | return assemblyDefinition.MainModule.IsUsingDotNetCore(); 38 | } 39 | 40 | public static bool IsUsingDotNetCore(this ModuleDefinition moduleDefinition) 41 | { 42 | using (var resolvedAssembly = moduleDefinition.AssemblyResolver.Resolve("System.Runtime.Loader")) 43 | { 44 | return resolvedAssembly is not null; 45 | } 46 | } 47 | 48 | public static AssemblyDefinition Resolve(this IAssemblyResolver assemblyResolver, string name) 49 | { 50 | return assemblyResolver.Resolve(new AssemblyNameReference(name, null)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Costura.Fody/Extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | using Mono.Cecil; 2 | using Mono.Cecil.Cil; 3 | using Mono.Cecil.Rocks; 4 | using Mono.Collections.Generic; 5 | 6 | internal static class Extensions 7 | { 8 | public static Collection GetGenericInstanceArguments(this TypeReference type) => ((GenericInstanceType)type).GenericArguments; 9 | 10 | public static MethodReference MakeHostInstanceGeneric(this MethodReference self, params TypeReference[] args) 11 | { 12 | var reference = new MethodReference( 13 | self.Name, 14 | self.ReturnType, 15 | self.DeclaringType.MakeGenericInstanceType(args)) 16 | { 17 | HasThis = self.HasThis, 18 | ExplicitThis = self.ExplicitThis, 19 | CallingConvention = self.CallingConvention 20 | }; 21 | 22 | foreach (var parameter in self.Parameters) 23 | { 24 | reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType)); 25 | } 26 | 27 | foreach (var genericParam in self.GenericParameters) 28 | { 29 | reference.GenericParameters.Add(new GenericParameter(genericParam.Name, reference)); 30 | } 31 | 32 | return reference; 33 | } 34 | 35 | public static void InsertBefore(this Collection instructions, int index, params Instruction[] newInstructions) 36 | { 37 | foreach (var item in newInstructions) 38 | { 39 | instructions.Insert(index, item); 40 | index++; 41 | } 42 | } 43 | 44 | public static byte[] FixedGetResourceData(this EmbeddedResource resource) 45 | { 46 | // There's a bug in Mono.Cecil so when you access a resources data 47 | // the stream is not reset after use. 48 | var data = resource.GetResourceData(); 49 | #pragma warning disable IDISP004 // Don't ignore created IDisposable 50 | resource.GetResourceStream().Position = 0; 51 | #pragma warning restore IDISP004 // Don't ignore created IDisposable 52 | return data; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Costura.Fody/HashCalculator.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Security.Cryptography; 3 | using System.Text; 4 | using Mono.Cecil; 5 | 6 | public partial class ModuleWeaver 7 | { 8 | private string _resourcesHash; 9 | 10 | private void CalculateHash() 11 | { 12 | var data = ModuleDefinition.Resources.OfType() 13 | .OrderBy(r => r.Name) 14 | .Where(r => r.Name.StartsWith("costura")) 15 | .SelectMany(r => r.FixedGetResourceData()) 16 | .ToArray(); 17 | 18 | using (var md5 = MD5.Create()) 19 | { 20 | var hashBytes = md5.ComputeHash(data); 21 | 22 | var sb = new StringBuilder(); 23 | for (var i = 0; i < hashBytes.Length; i++) 24 | { 25 | sb.Append(hashBytes[i].ToString("X2")); 26 | } 27 | 28 | _resourcesHash = sb.ToString(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Costura.Fody/ModuleWeaver.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using Fody; 4 | 5 | public sealed partial class ModuleWeaver : BaseModuleWeaver 6 | { 7 | public override void Execute() 8 | { 9 | //#if DEBUG 10 | // if (!Debugger.IsAttached) 11 | // { 12 | // Debugger.Launch(); 13 | // } 14 | //#endif 15 | 16 | var config = new Configuration(Config); 17 | 18 | WriteInfo($"Costura.Fody v{GetType().Assembly.GetVersion()}"); 19 | 20 | FindMsCoreReferences(); 21 | 22 | FixResourceCase(); 23 | ProcessNativeResources(!config.DisableCompression); 24 | EmbedResources(config); 25 | 26 | CalculateHash(); 27 | ImportAssemblyLoader(config.CreateTemporaryAssemblies); 28 | CallAttach(config); 29 | 30 | AddChecksumsToTemplate(); 31 | BuildUpNameDictionary(config.CreateTemporaryAssemblies, config.PreloadOrder); 32 | } 33 | 34 | public override IEnumerable GetAssembliesForScanning() 35 | { 36 | yield return "mscorlib"; 37 | yield return "System"; 38 | } 39 | 40 | public override bool ShouldCleanReference => true; 41 | } 42 | -------------------------------------------------------------------------------- /src/Costura.Fody/MsCoreReferenceFinder.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Mono.Cecil; 3 | 4 | public partial class ModuleWeaver 5 | { 6 | private MethodReference _compilerGeneratedAttributeCtor; 7 | private MethodReference _dictionaryOfStringOfStringAdd; 8 | private MethodReference _listOfStringAdd; 9 | 10 | private void FindMsCoreReferences() 11 | { 12 | var dictionary = FindTypeDefinition("System.Collections.Generic.Dictionary`2"); 13 | var dictionaryOfStringOfString = ModuleDefinition.ImportReference(dictionary); 14 | _dictionaryOfStringOfStringAdd = ModuleDefinition.ImportReference(dictionaryOfStringOfString.Resolve().Methods.First(_ => _.Name == "Add")) 15 | .MakeHostInstanceGeneric(TypeSystem.StringReference, TypeSystem.StringReference); 16 | 17 | var list = FindTypeDefinition("System.Collections.Generic.List`1"); 18 | var listOfString = ModuleDefinition.ImportReference(list); 19 | _listOfStringAdd = ModuleDefinition.ImportReference(listOfString.Resolve().Methods.First(_ => _.Name == "Add")) 20 | .MakeHostInstanceGeneric(TypeSystem.StringReference); 21 | 22 | var compilerGeneratedAttribute = FindTypeDefinition("System.Runtime.CompilerServices.CompilerGeneratedAttribute"); 23 | _compilerGeneratedAttributeCtor = ModuleDefinition.ImportReference(compilerGeneratedAttribute.Methods.First(_ => _.IsConstructor)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Costura.Fody/NativeResources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO.Compression; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using Mono.Cecil; 6 | 7 | public partial class ModuleWeaver 8 | { 9 | private void ProcessNativeResources(bool compress) 10 | { 11 | var unprocessedNameMatchBackwardsCompatibility = new Regex(@"^(.*\.)?costura(32|64)\.", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 12 | var unprocessedNameMatch = new Regex(@"^(.*\.)?costura_(win|linux|osx)_(x86|x64|Arm64)\.", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 13 | 14 | var processedNameMatchBackwardsCompatibility = new Regex(@"^costura(32|64)\.", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 15 | var processedNameMatch = new Regex(@"^costura_(win|linux|osx)_(x86|x64|arm64)\.", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); 16 | 17 | foreach (var resource in ModuleDefinition.Resources.OfType()) 18 | { 19 | if (unprocessedNameMatchBackwardsCompatibility.IsMatch(resource.Name)) 20 | { 21 | WriteError($"Please use the new folder structure (e.g. 'costura-win-x86')"); 22 | continue; 23 | } 24 | 25 | var match = unprocessedNameMatch.Match(resource.Name); 26 | if (match.Success) 27 | { 28 | resource.Name = resource.Name.Substring(match.Groups[1].Length).ToLowerInvariant(); 29 | _hasUnmanaged = true; 30 | } 31 | 32 | if (processedNameMatchBackwardsCompatibility.IsMatch(resource.Name)) 33 | { 34 | WriteError($"Please use the new folder structure (e.g. 'costura-win-x86')"); 35 | continue; 36 | } 37 | 38 | if (processedNameMatch.IsMatch(resource.Name)) 39 | { 40 | using (var stream = resource.GetResourceStream()) 41 | { 42 | if (compress && resource.Name.EndsWith(".compressed",StringComparison.OrdinalIgnoreCase)) 43 | { 44 | using (var compressStream = new DeflateStream(stream, CompressionMode.Decompress)) 45 | { 46 | _checksums.Add(resource.Name, CalculateSha1Checksum(compressStream)); 47 | } 48 | } 49 | else 50 | { 51 | _checksums.Add(resource.Name, CalculateSha1Checksum(stream)); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Costura.Fody/NetStandardAssemblyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Mono.Cecil; 4 | 5 | /// 6 | /// An assembly resolver that resolves with the of the 7 | /// of the given with special handling for the netstandard assembly reference to 8 | /// support .NET Framework 4.7 and lower. 9 | /// 10 | public sealed class NetStandardAssemblyResolver : IAssemblyResolver 11 | { 12 | private readonly ModuleWeaver _weaver; 13 | private readonly HashSet _resolvedReferences; 14 | private readonly Lazy _netStandardAssemblyDefinition; 15 | 16 | public NetStandardAssemblyResolver(ModuleWeaver weaver) 17 | { 18 | _weaver = weaver ?? throw new ArgumentNullException(nameof(weaver)); 19 | _weaver.WriteDebug("\tResolving assembly references"); 20 | _resolvedReferences = new HashSet(); 21 | _netStandardAssemblyDefinition = new Lazy(() => 22 | { 23 | const string dllName = "Costura.NETFramework.netstandard.dll"; 24 | var assembly = GetType().Assembly; 25 | using (var stream = assembly.GetManifestResourceStream(dllName)) 26 | { 27 | if (stream is null) 28 | { 29 | throw new InvalidOperationException($"Failed to get the manifest resource stream named '{dllName}' on {assembly}"); 30 | } 31 | 32 | return AssemblyDefinition.ReadAssembly(stream, new ReaderParameters { AssemblyResolver = this }); 33 | } 34 | }); 35 | } 36 | 37 | public void Dispose() 38 | { 39 | } 40 | 41 | public AssemblyDefinition Resolve(AssemblyNameReference name) 42 | { 43 | var assemblyDefinition = _weaver.ModuleDefinition.AssemblyResolver.Resolve(name); 44 | return Resolve(name, assemblyDefinition); 45 | } 46 | 47 | public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) 48 | { 49 | var assemblyDefinition = _weaver.ModuleDefinition.AssemblyResolver.Resolve(name, parameters); 50 | return Resolve(name, assemblyDefinition); 51 | } 52 | 53 | private AssemblyDefinition Resolve(AssemblyNameReference name, AssemblyDefinition assemblyDefinition) 54 | { 55 | if (assemblyDefinition is not null) 56 | { 57 | return ResolvedReference(name, assemblyDefinition); 58 | } 59 | 60 | if (name.Name == "netstandard" && !_weaver.ModuleDefinition.IsUsingDotNetCore()) 61 | { 62 | var netStandardAssemblyDefinition = _netStandardAssemblyDefinition.Value; 63 | return ResolvedReference(name, netStandardAssemblyDefinition); 64 | } 65 | 66 | throw new AssemblyResolutionException(name); 67 | } 68 | 69 | private AssemblyDefinition ResolvedReference(AssemblyNameReference name, AssemblyDefinition assemblyDefinition) 70 | { 71 | var added = _resolvedReferences.Add(name); 72 | if (added) 73 | { 74 | var toFileName = string.IsNullOrEmpty(assemblyDefinition.MainModule.FileName) ? string.Empty : $" to {assemblyDefinition.MainModule.FileName}"; 75 | _weaver.WriteDebug($"\t\tResolved {name}{toFileName}"); 76 | } 77 | 78 | return assemblyDefinition ?? throw new AssemblyResolutionException(name); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Costura.Fody/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Costura.Fody")] 4 | [assembly: AssemblyProduct("Costura.Fody")] 5 | [assembly: AssemblyDescription("Costura plugin for Fody")] -------------------------------------------------------------------------------- /src/Costura.Fody/ResourceCaseFixer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | public partial class ModuleWeaver 4 | { 5 | private void FixResourceCase() 6 | { 7 | foreach (var resource in ModuleDefinition.Resources) 8 | { 9 | if (resource.Name.StartsWith("costura.",StringComparison.OrdinalIgnoreCase)) 10 | { 11 | resource.Name = resource.Name.ToLowerInvariant(); 12 | } 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Costura.Template/Costura.Template.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0;net6.0;net8.0 4 | Costura.Template 5 | Costura.Template 6 | en-US 7 | 3.0.0-alpha0001 8 | 9 | 10 | true 11 | embedded 12 | true 13 | 14 | 15 | 16 | 17 | CD9AEBAA-78F4-4A78-BF06-0CB7D84D83E8 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Costura.Template/ILTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using System.Threading; 5 | 6 | #if NETCORE 7 | using System.Runtime.Loader; 8 | #endif 9 | 10 | internal static class ILTemplate 11 | { 12 | private static object nullCacheLock = new object(); 13 | private static Dictionary nullCache = new Dictionary(); 14 | 15 | private static Dictionary assemblyNames = new Dictionary(); 16 | private static Dictionary symbolNames = new Dictionary(); 17 | 18 | private static int isAttached; 19 | 20 | public static void Attach(bool subscribe) 21 | { 22 | if (Interlocked.Exchange(ref isAttached, 1) == 1) 23 | { 24 | return; 25 | } 26 | 27 | if (subscribe) 28 | { 29 | #if NETCORE 30 | AssemblyLoadContext.Default.Resolving += ResolveAssembly; 31 | #else 32 | var currentDomain = AppDomain.CurrentDomain; 33 | currentDomain.AssemblyResolve += ResolveAssembly; 34 | #endif 35 | } 36 | } 37 | 38 | #if NETCORE 39 | public static Assembly ResolveAssembly(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) 40 | #else 41 | public static Assembly ResolveAssembly(object sender, ResolveEventArgs e) 42 | #endif 43 | { 44 | #if NETCORE 45 | var assemblyNameAsString = assemblyName.Name; 46 | #else 47 | var assemblyNameAsString = e.Name; 48 | var assemblyName = new AssemblyName(assemblyNameAsString); 49 | #endif 50 | 51 | lock (nullCacheLock) 52 | { 53 | if (nullCache.ContainsKey(assemblyNameAsString)) 54 | { 55 | return null; 56 | } 57 | } 58 | 59 | var assembly = Common.ReadExistingAssembly(assemblyName); 60 | if (assembly is not null) 61 | { 62 | return assembly; 63 | } 64 | 65 | Common.Log("Loading assembly '{0}' into the current context", assemblyName); 66 | 67 | assembly = Common.ReadFromEmbeddedResources(assemblyNames, symbolNames, assemblyName); 68 | if (assembly is null) 69 | { 70 | lock (nullCacheLock) 71 | { 72 | nullCache[assemblyNameAsString] = true; 73 | } 74 | 75 | // Handles re-targeted assemblies like PCL 76 | if ((assemblyName.Flags & AssemblyNameFlags.Retargetable) != 0) 77 | { 78 | assembly = Assembly.Load(assemblyName); 79 | } 80 | } 81 | 82 | return assembly; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Costura.Template/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Costura.Template")] 4 | [assembly: AssemblyProduct("Costura.Template")] 5 | [assembly: AssemblyDescription("Costura template")] -------------------------------------------------------------------------------- /src/Costura/Costura.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | Costura 5 | Costura 6 | en-US 7 | 3.0.0-alpha0001 8 | Fody add-in for embedding references as resources. 9 | true 10 | Costura.Fody 11 | ILMerge, ILWeaving, Embed, Resource, Fody, Cecil 12 | true 13 | True 14 | ..\key.snk 15 | $(NoWarn);NU5100 16 | $(NoError);NU5100 17 | 18 | 19 | 20 | 21 | 2B508691-68E6-4AE6-8F8D-1B78F7E65F80 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | $(TargetsForTfmSpecificContentInPackage);IncludeFodyFiles 44 | true 45 | $(OverridableOutputPath)\..\$(PackageId) 46 | Debug;Release;Test 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/Costura/CosturaUtility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | /// 4 | /// Contains methods for interacting with the Costura system. 5 | /// 6 | public static class CosturaUtility 7 | { 8 | /// 9 | /// Call this to Initialize the Costura system. 10 | /// 11 | public static void Initialize() 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Costura/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyTitle("Costura")] 4 | [assembly: AssemblyProduct("Costura")] 5 | [assembly: AssemblyDescription("Costura library")] -------------------------------------------------------------------------------- /src/Directory.Build.analyzers.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | all 9 | runtime; build; native; contentfiles; analyzers; buildtransitive 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | all 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | 23 | 24 | all 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | 27 | 28 | 29 | 30 | 32 | latest 33 | 34 | 35 | 46 | 47 | $(NoWarn);CA1030;CA1031;CA1054;CA1062;CA1724;CA1810;CA2007;CA2237 48 | $(NoError);CA1030;CA1031;CA1054;CA1062;CA1724;CA810;CA2007;CA2237 49 | 50 | -------------------------------------------------------------------------------- /src/Directory.Build.implicitusings.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 5 | -------------------------------------------------------------------------------- /src/Directory.Build.nullable.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | enable 4 | 5 | -------------------------------------------------------------------------------- /src/Directory.Build.project.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | geertvanhorrik,simoncropp 8 | https://github.com/Fody/Costura 9 | MIT 10 | https://github.com/Fody/Costura 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 9 | 11 | 13 | 14 | 15 | 16 | 18 | 20 | 22 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.implicit.props: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | $(NoWarn);CA1416;CS1591;CS1998;NU1603;NU1605;NU1608;NU1701;AD0001;HAA0301;HAA0302;HAA0303;HAA0401;HAA0603 8 | $(NoError);CS1591;CS1998;NU1603;NU1605;NU1608;NU1701;AD0001;HAA0301;HAA0302;HAA0303;HAA0401;HAA0603 9 | true 10 | false 11 | true 12 | false 13 | false 14 | Release 15 | $(ProjectDir)..\..\output\$(Configuration)\ 16 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb;.xml 17 | False 18 | true 19 | 20 | 21 | 22 | 26 | 27 | 28 | true 29 | 30 | 31 | 32 | 33 | 34 | latest 35 | 36 | 37 | 38 | 40 | portable 41 | 42 | true 43 | 44 | 45 | 46 | 48 | portable 49 | true 50 | 51 | 52 | 53 | 55 | portable 56 | true 57 | 58 | 59 | 60 | 61 | 62 | direct 63 | 64 | low 65 | 66 | 67 | 68 | 69 | true 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.mat.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 4.0 10 | en-US 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | <_ResxFiles Remove="Properties\*.resx" /> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.tests.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | false 10 | true 11 | true 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.tools.props: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | $(Description) 10 | $(PackageProjectUrl) 11 | IncludeDefaultProjectBuildOutputInPack 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolDllFiles.FullPath))) 31 | tools 32 | 33 | 34 | 35 | $([MSBuild]::MakeRelative('$(OutputPath)\$(TargetFrameworks)\', %(ToolExeFiles.FullPath))) 36 | tools 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/Directory.Build.shared.xamltools.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | false 35 | 36 | 37 | 38 | true 39 | 40 | 41 | 42 | 43 | False 44 | False 45 | False 46 | 47 | 48 | 49 | 50 | True 51 | 52 | 53 | 54 | 55 | False 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/ExeToProcess/ClassToTest.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | public class ClassToTest 4 | { 5 | public string Simple() => ClassToReference.Simple(); 6 | 7 | public string InternationalFoo() => ClassToReference.InternationalFoo(); 8 | 9 | public string SimplePreEmbed() => ClassToReferencePreEmbedded.SimplePreEmbed(); 10 | 11 | public string Exe() => ExeClassToReference.Exe(); 12 | 13 | public void ThrowException() 14 | { 15 | ClassToReference.ThrowException(); 16 | } 17 | 18 | public Assembly GetReferencedAssembly() => typeof(ClassToReference).Assembly; 19 | } -------------------------------------------------------------------------------- /src/ExeToProcess/ExeToProcess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | Exe 6 | 7 | 8 | 9 | win7-x86 10 | 11 | 12 | 13 | 14 | false 15 | Costura.AssemblyToReferencePreEmbedded.dll 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/ExeToProcess/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | internal class Program 4 | { 5 | private static void Main() 6 | { 7 | // When the AppContext switches are properly initialized with the executable targeting ".NETFramework,Version=v4.7.2", 8 | // the "Switch.System.Diagnostics.IgnorePortablePDBsInStackTraces" is _not_ set at all. 9 | // "Switch.System.Diagnostics.IgnorePortablePDBsInStackTraces" is set to true if the AppContext switches are initialized with a wrong target framework name 10 | // See https://github.com/Fody/Costura/issues/633 for more information 11 | var appContextDefaultSwitchIsCorrect = AppContext.TryGetSwitch("Switch.System.Diagnostics.IgnorePortablePDBsInStackTraces", out _) == false; 12 | const string errorMessage = "Switch.System.Diagnostics.IgnorePortablePDBsInStackTraces should not be set for an executable targeting .NET Framework 4.7.2"; 13 | Console.Out.Write(appContextDefaultSwitchIsCorrect ? "Run-OK" : errorMessage); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ExeToProcessWithMultipleNative/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ExeToProcessWithMultipleNative 2 | { 3 | using System; 4 | 5 | public class Program 6 | { 7 | public static int Main() 8 | { 9 | // you can pass ANY valid library here, it's only important that kafka runs it's internal setup :-) 10 | Confluent.Kafka.Library.Load("librdkafka.dll"); 11 | 12 | QueueHelper.SendMessage("test", "message1"); 13 | 14 | Console.WriteLine(Guid.NewGuid().ToString()); 15 | QueueHelper.SendMessage("test", "message2"); 16 | 17 | return 42; 18 | } 19 | 20 | public int Test() 21 | { 22 | return Main(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ExeToProcessWithMultipleNative/QueueHelper.cs: -------------------------------------------------------------------------------- 1 | namespace ExeToProcessWithMultipleNative 2 | { 3 | using System.Net; 4 | 5 | using Confluent.Kafka; 6 | 7 | public static class QueueHelper 8 | { 9 | private const string QueueAddressesList = "kafka:9200"; 10 | 11 | public static void SendMessage(string topic, string message) 12 | { 13 | using (var producer = new ProducerBuilder(new ProducerConfig 14 | { 15 | ClientId = Dns.GetHostName(), 16 | BootstrapServers = QueueAddressesList 17 | }).Build()) 18 | { 19 | producer.Produce(topic, new Message { Value = message }); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ExeToProcessWithNative/ClassToTest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | public class ClassToTest 4 | { 5 | [DllImport("AssemblyToReferenceNative.dll", CallingConvention = CallingConvention.Cdecl)] 6 | [return: MarshalAs(UnmanagedType.BStr)] 7 | private static extern string SayHelloFromNative(); 8 | 9 | public string NativeFoo() => SayHelloFromNative(); 10 | 11 | [DllImport("AssemblyToReferenceMixed.dll", CallingConvention = CallingConvention.Cdecl)] 12 | [return: MarshalAs(UnmanagedType.BStr)] 13 | private static extern string SayHelloFromMixed(); 14 | 15 | public string MixedFooPInvoke() => SayHelloFromMixed(); 16 | 17 | public string MixedFoo() => ClassToReferenceMixed.Foo(); 18 | } -------------------------------------------------------------------------------- /src/ExeToProcessWithNative/ExeToProcessWithNative.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | Exe 6 | x86 7 | $(NoWarn);NU1201 8 | $(NoError);NU1201 9 | 10 | 11 | 12 | win7-x86 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | costura-win-x86\AssemblyToReferenceNative.dll 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/ExeToProcessWithNativeAndEmbeddedMixed/ClassToTest.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | public class ClassToTest 4 | { 5 | [DllImport("AssemblyToReferenceNative.dll", CallingConvention = CallingConvention.Cdecl)] 6 | [return: MarshalAs(UnmanagedType.BStr)] 7 | private static extern string SayHelloFromNative(); 8 | 9 | public string NativeFoo() => SayHelloFromNative(); 10 | 11 | [DllImport("AssemblyToReferenceMixed.dll", CallingConvention = CallingConvention.Cdecl)] 12 | [return: MarshalAs(UnmanagedType.BStr)] 13 | private static extern string SayHelloFromMixed(); 14 | 15 | public string MixedFooPInvoke() => SayHelloFromMixed(); 16 | 17 | public string MixedFoo() => ClassToReferenceMixed.Foo(); 18 | } -------------------------------------------------------------------------------- /src/ExeToProcessWithNativeAndEmbeddedMixed/ExeToProcessWithNativeAndEmbeddedMixed.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | Exe 6 | x86 7 | $(NoWarn);NU1201 8 | $(NoError);NU1201 9 | 10 | 11 | 12 | win7-x86 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | costura-win-x86\AssemblyToReferenceNative.dll 26 | 27 | 28 | costura-win-x86\AssemblyToReferenceMixed.dll 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/ExeToReference/ExeToReference.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net472;net8.0 4 | true 5 | Exe 6 | 7 | 8 | 9 | win7-x86 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/ExeToReference/Program.cs: -------------------------------------------------------------------------------- 1 | public class ExeClassToReference 2 | { 3 | public static void Main() 4 | { 5 | } 6 | 7 | public static string Exe() => "Hello"; 8 | } -------------------------------------------------------------------------------- /src/MethodTimeLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | //using Catel.Logging; 3 | using System; 4 | using System.Globalization; 5 | 6 | /// 7 | /// Note: do not rename this class or put it inside a namespace. 8 | /// 9 | internal static class MethodTimeLogger 10 | { 11 | public static void Log(MethodBase methodBase, long milliseconds, string message) 12 | { 13 | Log(methodBase.DeclaringType ?? typeof(object), methodBase.Name, milliseconds, message); 14 | } 15 | 16 | public static void Log(Type type, string methodName, long milliseconds, string message) 17 | { 18 | // if (type is null) 19 | // { 20 | // return; 21 | // } 22 | 23 | // if (milliseconds == 0) 24 | // { 25 | // // Don't log superfast methods 26 | // return; 27 | // } 28 | 29 | // var finalMessage = $"[METHODTIMER] {type.Name}.{methodName} took '{milliseconds.ToString(CultureInfo.InvariantCulture)}' ms"; 30 | 31 | // if (!string.IsNullOrWhiteSpace(message)) 32 | // { 33 | // finalMessage += $" | {message}"; 34 | // } 35 | 36 | // var logger = LogManager.GetLogger(type); 37 | // logger.Debug(finalMessage); 38 | } 39 | } -------------------------------------------------------------------------------- /src/SolutionAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by Cake. 4 | // 5 | //------------------------------------------------------------------------------ 6 | using System.Reflection; 7 | 8 | [assembly: AssemblyCompany("Fody")] 9 | [assembly: AssemblyVersion("6.0.0")] 10 | [assembly: AssemblyFileVersion("6.0.0")] 11 | [assembly: AssemblyInformationalVersion("6.0.0-alpha.368")] 12 | [assembly: AssemblyCopyright("Copyright © Fody 2015 - 2024")] 13 | 14 | -------------------------------------------------------------------------------- /src/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "msbuild-sdks": { 3 | "MSBuild.Sdk.Extras": "3.0.44" 4 | }, 5 | "sdk": { 6 | "version": "9.0.0", 7 | "rollForward": "latestMinor", 8 | "allowPrerelease": false 9 | } 10 | } -------------------------------------------------------------------------------- /src/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fody/Costura/0f474a604cbc8260539b09e55ef64bcfb953cbb3/src/key.snk -------------------------------------------------------------------------------- /src/nuget.config: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /tools/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fody/Costura/0f474a604cbc8260539b09e55ef64bcfb953cbb3/tools/nuget.exe --------------------------------------------------------------------------------