From d4b4869501b075f9a061fe835ecba4f70273c569 Mon Sep 17 00:00:00 2001 From: JustMe Date: Sun, 4 Oct 2026 12:38:13 -0700 Subject: [PATCH] fix(ci): package cross-platform tarballs on Windows [CI SKIP] --- ci/Monitor.Tar/Monitor.Tar.csproj | 8 +++++++ ci/Monitor.Tar/Program.cs | 38 +++++++++++++++++++++++++++++++ ci/package-cross-platform.ps1 | 28 ++++++++--------------- 3 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 ci/Monitor.Tar/Monitor.Tar.csproj create mode 100644 ci/Monitor.Tar/Program.cs diff --git a/ci/Monitor.Tar/Monitor.Tar.csproj b/ci/Monitor.Tar/Monitor.Tar.csproj new file mode 100644 index 0000000..238f157 --- /dev/null +++ b/ci/Monitor.Tar/Monitor.Tar.csproj @@ -0,0 +1,8 @@ + + + Exe + net10.0 + enable + enable + + diff --git a/ci/Monitor.Tar/Program.cs b/ci/Monitor.Tar/Program.cs new file mode 100644 index 0000000..a66e340 --- /dev/null +++ b/ci/Monitor.Tar/Program.cs @@ -0,0 +1,38 @@ +using System.Formats.Tar; +using System.IO.Compression; + +if (args.Length < 3) +{ + Console.Error.WriteLine("usage: Monitor.Tar ..."); + return 2; +} + +string sourceDirectory = Path.GetFullPath(args[0]); +string archivePath = Path.GetFullPath(args[1]); +HashSet executables = args.Skip(2).Select(path => path.Replace('\\', '/')).ToHashSet(StringComparer.Ordinal); +UnixFileMode executableMode = UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute | + UnixFileMode.GroupRead | UnixFileMode.GroupExecute | + UnixFileMode.OtherRead | UnixFileMode.OtherExecute; +UnixFileMode regularMode = UnixFileMode.UserRead | UnixFileMode.UserWrite | + UnixFileMode.GroupRead | UnixFileMode.OtherRead; + +Directory.CreateDirectory(Path.GetDirectoryName(archivePath)!); +using FileStream fileStream = File.Create(archivePath); +using GZipStream gzipStream = new(fileStream, CompressionLevel.Optimal, leaveOpen: true); +using TarWriter writer = new(gzipStream, TarEntryFormat.Pax, leaveOpen: true); + +foreach (string filePath in Directory.EnumerateFiles(sourceDirectory, "*", SearchOption.AllDirectories)) +{ + string relativePath = Path.GetRelativePath(sourceDirectory, filePath).Replace('\\', '/'); + PaxTarEntry entry = new(TarEntryType.RegularFile, relativePath) + { + Mode = executables.Contains(relativePath) ? executableMode : regularMode, + DataStream = File.OpenRead(filePath) + }; + using (entry.DataStream) + { + writer.WriteEntry(entry); + } +} + +return 0; diff --git a/ci/package-cross-platform.ps1 b/ci/package-cross-platform.ps1 index dc45eea..ba44f20 100644 --- a/ci/package-cross-platform.ps1 +++ b/ci/package-cross-platform.ps1 @@ -15,31 +15,21 @@ if ($version -ne $projectVersion) { throw "Tag version $version does not match project version $projectVersion." } -Add-Type -AssemblyName System.Formats.Tar +$tarProject = Join-Path $PSScriptRoot 'Monitor.Tar\Monitor.Tar.csproj' +$tarTool = Join-Path $PSScriptRoot 'Monitor.Tar\bin\Release\net10.0\Monitor.Tar.dll' +& dotnet build $tarProject -c Release --nologo +if ($LASTEXITCODE -ne 0) { + throw 'Could not build the cross-platform tar helper.' +} $giteaBase = if ($env:GITEA_BASE) { $env:GITEA_BASE.TrimEnd('/') } else { 'http://localhost:3100' } $netrc = Join-Path $env:TEMP ("monitor-gitea-$([guid]::NewGuid().ToString('N')).netrc") $giteaHost = ([Uri]$giteaBase).Host Set-Content -LiteralPath $netrc -Value "machine $giteaHost login justme password $($env:GITEA_TOKEN)" -Encoding ascii -NoNewline function New-TarGzArchive([string]$SourceDirectory, [string]$ArchivePath, [string[]]$Executables) { - $tarFile = [IO.File]::Create($ArchivePath) - $gzip = [IO.Compression.GZipStream]::new($tarFile, [IO.Compression.CompressionLevel]::Optimal, $true) - $writer = [System.Formats.Tar.TarWriter]::new($gzip, [System.Formats.Tar.TarEntryFormat]::Pax, $true) - $executableMode = [System.IO.UnixFileMode]::UserRead -bor [System.IO.UnixFileMode]::UserWrite -bor [System.IO.UnixFileMode]::UserExecute -bor [System.IO.UnixFileMode]::GroupRead -bor [System.IO.UnixFileMode]::GroupExecute -bor [System.IO.UnixFileMode]::OtherRead -bor [System.IO.UnixFileMode]::OtherExecute - $regularMode = [System.IO.UnixFileMode]::UserRead -bor [System.IO.UnixFileMode]::UserWrite -bor [System.IO.UnixFileMode]::GroupRead -bor [System.IO.UnixFileMode]::OtherRead - try { - foreach ($file in Get-ChildItem -LiteralPath $SourceDirectory -File -Recurse) { - $relativePath = [IO.Path]::GetRelativePath($SourceDirectory, $file.FullName).Replace('\', '/') - $entry = [System.Formats.Tar.PaxTarEntry]::new([System.Formats.Tar.TarEntryType]::RegularFile, $relativePath) - $entry.Mode = if ($Executables -contains $relativePath) { $executableMode } else { $regularMode } - $entry.DataStream = [IO.File]::OpenRead($file.FullName) - try { $writer.WriteEntry($entry) } finally { $entry.DataStream.Dispose() } - } - } - finally { - $writer.Dispose() - $gzip.Dispose() - $tarFile.Dispose() + & dotnet $tarTool $SourceDirectory $ArchivePath @Executables + if ($LASTEXITCODE -ne 0) { + throw "Could not create tar archive $ArchivePath." } }