Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use .NET built-in Tar and Zip handling #67

Merged
merged 2 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/DotNetReleaser.Tests/BasicTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Formats.Tar;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
Expand Down Expand Up @@ -110,6 +112,97 @@ public async Task TestBuild()
File.Delete(_configurationFile);
}

[Test]
public async Task TestMacOSTarZipAreExecutable()
{
EnsureTestsFolder();

File.Delete(_configurationFile);

await CreateConfiguration();

var config = await File.ReadAllTextAsync(_configurationFile);

if (Directory.Exists(_artifactsFolder))
{
Directory.Delete(_artifactsFolder, true);
}

config = "profile = \"custom\"" + Environment.NewLine + config;
config += @"
[msbuild.properties]
SelfContained = false
PublishSingleFile = false
PublishTrimmed = false
[[pack]]
rid = ""osx-x64""
kinds = [""tar"", ""zip""]
[nuget]
publish = false
";
config = config.Replace("\r\n", "\n").Replace("\n", Environment.NewLine);
await File.WriteAllTextAsync(_configurationFile, config);

var resultBuild = await CliWrap.Cli.Wrap(_releaserExe)
.WithArguments("build --force dotnet-releaser.toml")
.WithStandardOutputPipe(PipeTarget.ToDelegate(x => Console.Out.WriteLine(x)))
.WithStandardErrorPipe(PipeTarget.ToDelegate(x => Console.Error.WriteLine(x)))
.WithWorkingDirectory(_helloWorldFolder).ExecuteAsync();

Assert.True(Directory.Exists(_artifactsFolder));

var files = Directory.GetFiles(_artifactsFolder).Select(Path.GetFileName).OrderBy(x => x).ToList();

var expectedFiles = new List<string>()
{
"HelloWorld.0.1.0.osx-x64.tar.gz",
"HelloWorld.0.1.0.osx-x64.zip",
}.OrderBy(x => x).ToList();

foreach (var file in files)
{
Console.WriteLine($"-> {file}");
}

Assert.AreEqual(expectedFiles, files);

if (!OperatingSystem.IsWindows())
{
// ensure files are executable
var tar = Path.Combine(_artifactsFolder, "HelloWorld.0.1.0.osx-x64.tar.gz");
using FileStream fs = new(tar, FileMode.Open, FileAccess.Read);
using var gzip = new GZipStream(fs, CompressionMode.Decompress);
using var unzippedStream = new MemoryStream();
{
await gzip.CopyToAsync(unzippedStream);
unzippedStream.Seek(0, SeekOrigin.Begin);

using var reader = new TarReader(unzippedStream);

while (reader.GetNextEntry() is TarEntry entry)
{
if (entry.Name == "./HelloWorld")
{
Assert.IsTrue(entry.Mode.HasFlag(UnixFileMode.GroupExecute));
Assert.IsTrue(entry.Mode.HasFlag(UnixFileMode.OtherExecute));
Assert.IsTrue(entry.Mode.HasFlag(UnixFileMode.UserExecute));
break;
}
}
}
// extract zip files and check executable
var zippath = Path.Combine(_artifactsFolder, "HelloWorld.0.1.0.osx-x64.zip");
ZipFile.ExtractToDirectory(zippath, _artifactsFolder);
var fileMode = File.GetUnixFileMode(Path.Combine(_artifactsFolder, "HelloWorld"));
Assert.IsTrue(fileMode.HasFlag(UnixFileMode.GroupExecute));
Assert.IsTrue(fileMode.HasFlag(UnixFileMode.OtherExecute));
Assert.IsTrue(fileMode.HasFlag(UnixFileMode.UserExecute));
}

Directory.Delete(_artifactsFolder, true);
File.Delete(_configurationFile);
}

[Test]
public async Task TestBuildService()
{
Expand Down
51 changes: 51 additions & 0 deletions src/dotnet-releaser/Helpers/CompressionHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Formats.Tar;
using System.IO;
using System.IO.Compression;

namespace DotNetReleaser.Helpers;

internal static class CompressionHelper
{
public static string? MakeTarGz(ProjectPackageInfo projectPackageInfo, string publishDir, string artifactsFolder, string rid)
{
string? outputPath = null;
var publishPath = Path.Combine(Path.GetDirectoryName(projectPackageInfo.ProjectFullPath) ?? "", publishDir);
if (Directory.Exists(publishPath))
{
var gzipPath = Path.GetFullPath(Path.Combine(artifactsFolder,
projectPackageInfo.Name + "." + projectPackageInfo.Version + "." + rid + ".tar.gz"));
if (File.Exists(gzipPath))
{
return null; // file already exists
}
using FileStream fs = new(gzipPath, FileMode.CreateNew, FileAccess.Write);
using GZipStream gz = new(fs, CompressionMode.Compress, leaveOpen: true);
{
TarFile.CreateFromDirectory(publishPath, gz, includeBaseDirectory: false);
}
outputPath = gzipPath;
}
return outputPath;
}

public static string? MakeZip(ProjectPackageInfo projectPackageInfo, string publishDir, string artifactsFolder, string rid)
{
string? outputPath = null;
var publishPath = Path.Combine(Path.GetDirectoryName(projectPackageInfo.ProjectFullPath) ?? "", publishDir);
if (Directory.Exists(publishPath))
{
var zipPath = Path.GetFullPath(Path.Combine(artifactsFolder,
projectPackageInfo.Name + "." + projectPackageInfo.Version + "." + rid + ".zip"));
if (File.Exists(zipPath))
{
return null; // file already exists
}
using FileStream fs = new(zipPath, FileMode.CreateNew, FileAccess.Write);
{
ZipFile.CreateFromDirectory(publishPath, fs, compressionLevel: CompressionLevel.Optimal, includeBaseDirectory: false);
}
outputPath = zipPath;
}
return outputPath;
}
}
24 changes: 23 additions & 1 deletion src/dotnet-releaser/ReleaserApp.AppPackaging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Security.Cryptography;
using System.Threading.Tasks;
using DotNetReleaser.Configuration;
using DotNetReleaser.Helpers;
using DotNetReleaser.Logging;
using Spectre.Console;

Expand Down Expand Up @@ -225,7 +226,28 @@ private async Task<List<AppPackageInfo>> BuildAppPackages(BuildInformation build

// Copy the file to the output
var path = result[0].ItemSpec;
path = CopyToArtifacts(path);
if (target == ReleaserConstants.DotNetReleaserPublishAndCreateTar)
{
path = CompressionHelper.MakeTarGz(projectPackageInfo, path, _config.ArtifactsFolder, rid);
if (path is null)
{
Error("Unable to make tar file with publish directory " + path + "; does the file already exist?");
break;
}
}
else if (target == ReleaserConstants.DotNetReleaserPublishAndCreateZip)
{
path = CompressionHelper.MakeZip(projectPackageInfo, path, _config.ArtifactsFolder, rid);
if (path is null)
{
Error("Unable to make zip file with publish directory " + path + "; does the file already exist?");
break;
}
}
else
{
path = CopyToArtifacts(path);
}

var sha256 = string.Join("", SHA256.HashData(await File.ReadAllBytesAsync(path)).Select(x => x.ToString("x2")));

Expand Down
9 changes: 5 additions & 4 deletions src/dotnet-releaser/dotnet-releaser.targets
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<_DotNetReleaserGetPackageInfo Include="$(IsPackable)" Kind="IsNuGetPackable"/>
<_DotNetReleaserGetPackageInfo Include="$(IsTestProject)" Kind="IsTestProject"/>
<_DotNetReleaserGetPackageInfo Include="@(ProjectReference)" Kind="ProjectReference"/>
<_DotNetReleaserGetPackageInfo Include="$([System.IO.Path]::GetFullPath('$(PublishDir)'))" Kind="PublishDir"/>
</ItemGroup>
</Target>

Expand All @@ -116,14 +117,14 @@
<_DotNetReleaserPublishAndCreateRpm Include="$(RpmPath)" Kind="RpmPath"/>
</ItemGroup>
</Target>
<Target Name="DotNetReleaserPublishAndCreateZip" Outputs="@(_DotNetReleaserPublishAndCreateZip)" DependsOnTargets="CreateZip">
<Target Name="DotNetReleaserPublishAndCreateZip" Outputs="@(_DotNetReleaserPublishAndCreateZip)" DependsOnTargets="Publish">
<ItemGroup>
<_DotNetReleaserPublishAndCreateZip Include="$(ZipPath)" Kind="ZipPath"/>
<_DotNetReleaserPublishAndCreateZip Include="$(PublishDir)" Kind="PublishDir"/>
</ItemGroup>
</Target>
<Target Name="DotNetReleaserPublishAndCreateTar" Outputs="@(_DotNetReleaserPublishAndCreateTar)" DependsOnTargets="CreateTarball">
<Target Name="DotNetReleaserPublishAndCreateTar" Outputs="@(_DotNetReleaserPublishAndCreateTar)" DependsOnTargets="Publish">
<ItemGroup>
<_DotNetReleaserPublishAndCreateTar Include="$(TarballPath)" Kind="TarballPath"/>
<_DotNetReleaserPublishAndCreateTar Include="$(PublishDir)" Kind="PublishDir"/>
</ItemGroup>
</Target>
</Project>
Loading