Skip to content

Instantly share code, notes, and snippets.

@danielcrenna
Forked from attilah/X.Y.Z.Sources.csproj
Last active November 21, 2019 17:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielcrenna/f87dd455e31e90ee9c402c0ca06982f2 to your computer and use it in GitHub Desktop.
Save danielcrenna/f87dd455e31e90ee9c402c0ca06982f2 to your computer and use it in GitHub Desktop.
X.Y.Z.Sources nuget package (with pre-processor transformations support)
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
</Project>
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
namespace PackagePrep
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0 || args.Length > 3 ||
args[0].Equals("tokenize", StringComparison.OrdinalIgnoreCase) && args.Length != 3 ||
args[0].Equals("nuspec", StringComparison.OrdinalIgnoreCase) && args.Length != 2)
{
Console.WriteLine("PackagePrep [tokenize|nuspec] [project-directory] (rootNamespace)");
return;
}
Console.WriteLine($"PackagePrep {string.Join(' ', args)}");
Console.WriteLine();
void ReplaceFileInArchive(ZipArchiveEntry entry, string content)
{
using (var stream = entry.Open())
{
stream.SetLength(content.Length);
using (var sw = new StreamWriter(stream))
sw.Write(content);
}
}
string ReadFileInArchive(ZipArchiveEntry entry)
{
using (var sr = new StreamReader(entry.Open()))
{
return sr.ReadToEnd();
}
}
var command = args[0];
if (command.Equals("tokenize", StringComparison.OrdinalIgnoreCase))
{
var path = args[1];
var rootNamespace = args[2];
Console.WriteLine("Tokenizing sources...");
Console.WriteLine("Path: " + path);
foreach (var file in Directory.GetFiles(path, "*.pp", SearchOption.AllDirectories))
File.Delete(file);
foreach (var file in Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories))
{
var text = File.ReadAllText(file, Encoding.UTF8);
text = text.Replace($"{rootNamespace}.", "$RootNamespace$.");
var sb = new StringBuilder();
sb.AppendLine(text);
var code = sb.ToString();
File.WriteAllText(file + ".pp", code, Encoding.UTF8);
}
}
if (command.Equals("nuspec"))
{
var path = args[1];
Console.WriteLine("Correcting nuspecs...");
Console.WriteLine("Path: " + path);
foreach (var package in Directory.GetFiles(path, "*.nupkg", SearchOption.AllDirectories))
{
Console.WriteLine("Found package: " + package);
using (var archive = ZipFile.Open(package, ZipArchiveMode.Update))
{
for (int i = archive.Entries.Count - 1; i >= 0; i--)
{
var entry = archive.Entries[i];
var file = new FileInfo(entry.FullName);
if (file.Extension == ".nuspec")
{
var before = ReadFileInArchive(entry);
Console.Write("Found .nuspec: " + file.Name + "...");
var updated = before
.Replace("exclude=\"Build,Analyzers\"", string.Empty) // fix PackageReferences
.Replace("buildAction=\"Content\"", string.Empty); // fix file tags
if (before == updated)
{
Console.WriteLine(" not modified.");
}
else
{
Console.WriteLine();
Console.WriteLine(updated);
}
ReplaceFileInArchive(entry, updated);
var after = ReadFileInArchive(entry);
if (after != updated)
{
throw new IOException("The update process did not change the .nuspec.");
}
}
}
}
}
}
}
}
}
<Project>
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='PackageSources'">
<IsPackable>true</IsPackable>
<IncludeBuildOutput>false</IncludeBuildOutput>
<ContentTargetFolders>contentFiles</ContentTargetFolders>
<DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
<NoWarn>CS8021</NoWarn>
<NoBuild>true</NoBuild>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'!='PackageSources'">
<None Remove="**\*.pp" /><!-- Don't show generated files during regular development -->
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='PackageSources'">
<None Include="**\*.pp" Exclude="obj\**" />
<Compile Remove="**\*.cs" /><!-- Don't show source files during package deployment -->
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='PackageSources'">
<Content Include="**\*.pp" Exclude="obj\**">
<Pack>true</Pack>
<PackagePath>$(ContentTargetFolders)\cs\netstandard2.0\$(ProjectName)\%(RecursiveDir)%(Filename)%(Extension)</PackagePath>
</Content>
<EmbeddedResource Update="@(EmbeddedResource)">
<Pack>true</Pack>
<PackagePath>$(ContentTargetFolders)\any\any\$(ProjectName)\%(RecursiveDir)%(Filename)%(Extension)</PackagePath>
</EmbeddedResource>
<PackageReference Remove="@(PackageReference)" />
</ItemGroup>
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
<Target Name="Compile" Condition="'$(Configuration)'=='PackageSources'" />
<Target Name="CopyFilesToOutputDirectory" Condition="'$(Configuration)'=='PackageSources'" />
<!-- Unfortunately the .nuspec file is not valid for .pp files due to the attributes added by None/Content/Compile -->
<Target Name="PostPack" AfterTargets="Pack" Condition="'$(Configuration)'=='PackageSources'">
<Exec Command="dotnet run --project &quot;.\PackagePrep\PackagePrep.csproj&quot; -- nuspec $(ProjectDir)bin\$(Configuration)" />
</Target>
<!-- Transform all .cs files into .cs.pp files with $RootNamespace$ -->
<PropertyGroup>
<PreBuildEvent>
dotnet run --project &quot.\PackagePrep\PackagePrep.csproj&quot; -- tokenize $(RootNamespace) $(MSBuildProjectDirectory)
</PreBuildEvent>
</PropertyGroup>
</Project>
@mmoreira2000
Copy link

Thanks for sharing, just what I was looking for!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment