Skip to content

Commit

Permalink
Merge pull request #5 from krafs/reference-replacement
Browse files Browse the repository at this point in the history
Replace ReferencePaths instead of changing ReferenceAssembly-attribute.
  • Loading branch information
krafs authored Sep 12, 2021
2 parents 40926e8 + 0016d7b commit c7f1642
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 91 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ dotnet_analyzer_diagnostic.severity = error
# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = none

# IDE0130: Namespace does not match containing folder.
dotnet_diagnostic.IDE0130.severity = none

# Organize usings
dotnet_separate_import_directive_groups = false
dotnet_sort_system_directives_first = true
Expand Down
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Publicizer is an MSBuild library for allowing direct access to non-public members in referenced assemblies.

## Installation
Use the Visual Studio package manager and reference [Krafs.Publicizer](https://www.nuget.org/packages/Krafs.Publicizer).
Use your IDE's package manager and reference [Krafs.Publicizer](https://www.nuget.org/packages/Krafs.Publicizer) from nuget.org.

Or add via the dotnet CLI:
```bash
Expand All @@ -11,15 +11,13 @@ dotnet add package Krafs.Publicizer
Or add directly to your project file:
```xml
<ItemGroup>
<PackageReference Include="Krafs.Publicizer" Version="1.0.0" />
<PackageReference Include="Krafs.Publicizer" Version="1.0.1" />
</ItemGroup>
```

## Usage
Define _Publicize_-items in your project file to instruct Publicizer what to make public.

Any assembly referenced by the project - through Reference, PackageReference, ProjectReference - can be publicized.

### Publicize an entire assembly:
```xml
<ItemGroup>
Expand All @@ -28,6 +26,8 @@ Any assembly referenced by the project - through Reference, PackageReference, Pr
```
Doing this will publicize all the assembly's containing members.

Make sure you type the assembly name without the file extension, i.e. **without** '.dll'.

### Publicize a specific member:
```xml
<ItemGroup>
Expand All @@ -53,6 +53,20 @@ As with most Items, you can include multiple patterns with semi-colons:
<Publicize Include="AssemblyOne;AssemblyTwo;AssemblyThree" />
</ItemGroup>
```
### Publicize assemblies from a PackageReference
PackageReferences, like other kinds of References, point towards one or more underlying assemblies. Publicizing these assemblies is just a matter of finding out what the underlying assemblies are called, and then specify them the same way as above.

Below is an example of publicizing two assemblies from the package [Krafs.Rimworld.Ref](https://www.nuget.org/packages/Krafs.Rimworld.Ref/):
```xml
<ItemGroup>
<PackageReference Include="Krafs.Publicizer" Version="1.0.1" />
<PackageReference Include="Krafs.Rimworld.Ref" Version="1.3.3117" />
</ItemGroup>

<ItemGroup>
<Publicize Include="Assembly-CSharp;UnityEngine.CoreModule" />
</ItemGroup>
```

### Publicize All
You can use this shorthand property to publicize all assemblies referenced by the project:
Expand All @@ -62,13 +76,16 @@ You can use this shorthand property to publicize all assemblies referenced by th
</PropertyGroup>
```

Save the project file and the changes should take effect shortly.
Save the project file and the changes should take effect shortly. If not, try performing a _Restore_.

## How Publicizer works
Publicizer works by copying the referenced assemblies into memory, rewriting the access modifiers to public, and feeding those assemblies to the compiler instead of the real ones.
Publicized assemblies are cached in _obj_ for future builds.

Additionally, the project's assembly is compiled as [unsafe](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code/). Among other things, this tells the runtime to not enforce access checks. Without this, accessing an unpermitted member at runtime throws a [MemberAccessException](https://docs.microsoft.com/en-us/dotnet/api/system.memberaccessexception/).

This means that you do **NOT** have to specify _AllowUnsafeBlocks=true_ in your project file. Publicizer does this for you under the hood.

By default, Publicizer additionally creates the new assemblies as [reference assemblies](https://docs.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies/).
This reduces build times and memory usage. However, if you use your IDE's decompilation feature to inspect code, you may want to turn that off, or you will just see empty methods.
Do that by specifying this property:
Expand All @@ -78,7 +95,7 @@ Do that by specifying this property:
</PropertyGroup>
```
## Acknowledgements
Project builds upon rwmt's [Publicise](https://github.com/rwmt/Publicise), simplyWiri's [TaskPubliciser](https://github.com/simplyWiri/TaskPubliciser), and [this gist](https://gist.github.com/Zetrith/d86b1d84e993c8117983c09f1a5dcdcd) by Zetrith
This project builds upon rwmt's [Publicise](https://github.com/rwmt/Publicise), simplyWiri's [TaskPubliciser](https://github.com/simplyWiri/TaskPubliciser), and [this gist](https://gist.github.com/Zetrith/d86b1d84e993c8117983c09f1a5dcdcd) by Zetrith.


## License
Expand Down
4 changes: 2 additions & 2 deletions src/Publicizer.Tests/Publicizer.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0" />
<PackageReference Include="MSBuild.ProjectCreation" Version="4.0.4" />
<PackageReference Include="MSBuild.ProjectCreation" Version="6.2.4" />
</ItemGroup>

<ItemGroup>
Expand Down
12 changes: 0 additions & 12 deletions src/Publicizer/ItemConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,11 @@ public static class ItemConstants
public static class DoNotPublicize
{
public const string ItemName = "DoNotPublicize";
public const string Pattern = "Pattern";
public const string Priority = "Priority";
public const string ParameterTypes = "ParameterTypes";
}

public static class Publicize
{
public const string ItemName = "Publicize";
public const string Pattern = "Pattern";
public const string Priority = "Priority";
public const string ParameterTypes = "ParameterTypes";
public const string Ignore = "Ignore";
}

public static class ReferencePath
{
public const string ReferenceAssembly = "ReferenceAssembly";
}
}
}
7 changes: 4 additions & 3 deletions src/Publicizer/Krafs.Publicizer.targets
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
DoNotPublicizes="@(DoNotPublicize)"
OutputDirectory="$(IntermediateOutputPath)PublicizedAssemblies\"
PublicizeAsReferenceAssemblies="$(PublicizeAsReferenceAssemblies)">
<Output TaskParameter="UpdatedReferencePaths" ItemName="_UpdatedReferencePaths" />
<Output TaskParameter="ReferencePathsToDelete" ItemName="_ReferencePathsToDelete" />
<Output TaskParameter="ReferencePathsToAdd" ItemName="_ReferencePathsToAdd" />
</PublicizeAssemblies>

<ItemGroup>
<ReferencePath Remove="@(_UpdatedReferencePaths)" />
<ReferencePath Include="@(_UpdatedReferencePaths)" />
<ReferencePath Remove="@(_ReferencePathsToDelete)" />
<ReferencePath Include="@(_ReferencePathsToAdd)" />
</ItemGroup>

<PropertyGroup>
Expand Down
22 changes: 15 additions & 7 deletions src/Publicizer/PublicizeAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ public class PublicizeAssemblies : Task
public string? PublicizeAsReferenceAssemblies { get; set; }

[Output]
public ITaskItem[]? UpdatedReferencePaths { get; set; }
public ITaskItem[]? ReferencePathsToDelete { get; set; }

[Output]
public ITaskItem[]? ReferencePathsToAdd { get; set; }

public override bool Execute()
{
Expand Down Expand Up @@ -101,7 +104,8 @@ public override bool Execute()
doNotPublicizes.Add(pattern);
}

List<ITaskItem> updatedReferencePaths = new List<ITaskItem>();
List<ITaskItem> referencePathsToDelete = new List<ITaskItem>();
List<ITaskItem> referencePathsToAdd = new List<ITaskItem>();

foreach (ITaskItem reference in ReferencePaths)
{
Expand Down Expand Up @@ -131,22 +135,26 @@ public override bool Execute()
module.Write(fileStream);
}

reference.SetReferenceAssemblyPath(outputAssemblyPath);
updatedReferencePaths.Add(reference);
referencePathsToDelete.Add(reference);
ITaskItem newReference = new TaskItem(outputAssemblyPath);
reference.CopyMetadataTo(newReference);
referencePathsToAdd.Add(newReference);
}

UpdatedReferencePaths = updatedReferencePaths.ToArray();
ReferencePathsToDelete = referencePathsToDelete.ToArray();
ReferencePathsToAdd = referencePathsToAdd.ToArray();

return true;
}

private static string ComputeHash(string assemblyPath, List<string> publicizes, List<string> assemblyDoNotPublicizes)
private static string ComputeHash(string assemblyPath, List<string> publicizes, List<string> doNotPublicizes)
{
StringBuilder sb = new StringBuilder();
foreach (string publicizePattern in publicizes)
{
sb.Append(publicizePattern);
}
foreach (string doNotPublicizePattern in assemblyDoNotPublicizes)
foreach (string doNotPublicizePattern in doNotPublicizes)
{
sb.Append(doNotPublicizePattern);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Publicizer/Publicizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
<RepositoryUrl>https://github.com/krafs/Publicizer.git</RepositoryUrl>
<Description>MSBuild library for allowing direct access to non-public members in .NET assemblies.</Description>
<PackageTags>msbuild accesschecks public publicizer</PackageTags>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="dnlib" Version="3.3.3" />
<PackageReference Include="ILRepack.Lib.MSBuild" Version="2.1.16.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.10.0" PrivateAssets="All" ExcludeAssets="runtime" />
<PackageReference Include="dnlib" Version="3.3.4" />
<PackageReference Include="ILRepack.Lib.MSBuild" Version="2.1.17.1" PrivateAssets="All" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.11.0" PrivateAssets="all" ExcludeAssets="runtime" />
</ItemGroup>

<ItemGroup>
Expand Down
58 changes: 1 addition & 57 deletions src/Publicizer/TaskItemExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,73 +1,17 @@
using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Framework;

namespace Publicizer
{
public static class TaskItemExtensions
{
public static string GetPattern(this ITaskItem item)
{
return item.GetMetadata(ItemConstants.Publicize.Pattern);
}

public static int GetPriority(this ITaskItem item)
{
if (!int.TryParse(item.GetMetadata(ItemConstants.Publicize.Priority), out int priority))
{
priority = 0;
}

return priority;
}

public static string GetFileName(this ITaskItem item)
{
return item.GetMetadata(ItemConstants.FileName);
}

public static string[] GetIgnorePatterns(this ITaskItem item)
{
string ignorePatternValue = item.GetMetadata("IgnorePatterns");
if (string.IsNullOrWhiteSpace(ignorePatternValue))
{
return Array.Empty<string>();
}

return ignorePatternValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
}

public static string GetFullPath(this ITaskItem item)
{
return item.GetMetadata(ItemConstants.FullPath);
}

public static bool GetIgnore(this ITaskItem item)
{
string ignore = item.GetMetadata(ItemConstants.Publicize.Ignore);
bool shouldIgnore = ignore?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false;

return shouldIgnore;
}

public static void SetReferenceAssemblyPath(this ITaskItem item, string path)
{
item.SetMetadata(ItemConstants.ReferencePath.ReferenceAssembly, path);
}

public static string GetRawParameterTypes(this ITaskItem item)
{
return item.GetMetadata(ItemConstants.Publicize.ParameterTypes);
}

public static string[] GetParameterTypes(this ITaskItem item)
{
string parameterTypesValue = item.GetRawParameterTypes();
if (string.IsNullOrWhiteSpace(parameterTypesValue))
{
return Array.Empty<string>();
}

return parameterTypesValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
}
}
}

0 comments on commit c7f1642

Please sign in to comment.