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

Build Debs using our own infra instead of debuild + custom scripting #15051

Merged
merged 5 commits into from
Sep 23, 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
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@
<UsingTask TaskName="GenerateJsonObjectString" AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)"/>
<UsingTask TaskName="GenerateMsiVersion" AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />
<UsingTask TaskName="StabilizeWixFileId" AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />
<UsingTask TaskName="CreateChangelogFile"
AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />
<UsingTask TaskName="CreateMD5SumsFile"
AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />
<UsingTask TaskName="CreateControlFile"
AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />
<UsingTask TaskName="CreateDebPackage"
AssemblyFile="$(MicrosoftDotNetBuildTasksInstallersTaskAssembly)" />

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
BuildInParallel="$(BuildInParallel)" />
</Target>

<Target Name="GenerateDeb" DependsOnTargets="FindDebuild;CreateDeb" />
<Target Name="GenerateDeb" DependsOnTargets="CreateDeb" />
<Target Name="GenerateRpm" DependsOnTargets="FindFPM;CreateRpm" />
<Target Name="GenerateMsi" DependsOnTargets="CreateWixInstaller" />
<Target Name="GenerateCrossArchMsi" DependsOnTargets="CreateCrossArchWixInstaller" />
Expand Down Expand Up @@ -169,29 +169,6 @@
<_InstallerFileCblMariner2>$(PackageOutputPath)$(_InstallerFileNameWithoutExtensionCblMariner2)$(InstallerExtension)</_InstallerFileCblMariner2>
</PropertyGroup>
</Target>

<!--
Check if the deb package build tool prereq is available.
-->
<Target Name="FindDebuild">
<!-- run Debuild -->
<Exec
Command="/usr/bin/env debuild -h > /dev/null 2>&amp;1"
ContinueOnError="true"
IgnoreExitCode="true"
IgnoreStandardErrorWarningFormat="true">
<Output TaskParameter="ExitCode" PropertyName="_DebuildSearchExitCode" />
</Exec>

<!-- Check if it successfully showed us a help message. -->
<PropertyGroup>
<_DebuildPresent>false</_DebuildPresent>
<_DebuildPresent Condition=" '$(_DebuildSearchExitCode)' == '0' ">true</_DebuildPresent>
</PropertyGroup>

<Error Condition=" '$(_DebuildPresent)' != 'true' "
Text="Debuild Not found, Debian packages will not be built." />
</Target>

<!--
Check if the RPM package build tool prereq is available.
Expand All @@ -215,62 +192,122 @@
<Error Condition=" '$(_FPMPresent)' != 'true' "
Text="FPM tool Not found, RPM packages will not be built." />
</Target>
<!--
Create Debian package.
-->

<!-- This target is kept for back-compat for targets that would hook it to add package info. -->
<Target Name="GetDebInstallerJsonProperties" />

<Target Name="CreateDeb"
DependsOnTargets="
_GetInstallerProperties;
_CreateInstallerLayout;
GetDebInstallerJsonProperties"
Condition="'$(_DebuildPresent)' == 'true'"
DependsOnTargets="_GetInstallerProperties;_GetCommonJsonProperties;GetDebInstallerJsonProperties"
Returns="$(_InstallerFile)">
<PropertyGroup>
<_ConfigJsonFile>$(_LayoutDirectory)debian_config.json</_ConfigJsonFile>
<_DebIntermediatesDir>$(IntermediateOutputPath)out-deb</_DebIntermediatesDir>

<_DebToolArgs>-i $(_LayoutDirectory)</_DebToolArgs>
<_DebToolArgs>$(_DebToolArgs) -o $(_DebIntermediatesDir)</_DebToolArgs>
<_DebToolArgs>$(_DebToolArgs) -n $(VersionedInstallerName)</_DebToolArgs>
<_DebToolArgs>$(_DebToolArgs) -v $(InstallerPackageVersion)</_DebToolArgs>
<_LayoutDirectory>$(IntermediateOutputPath)installer/debLayout/</_LayoutDirectory>
<_LayoutDataRoot>$(_LayoutDirectory)root/</_LayoutDataRoot>
<_LayoutPackageRoot>$(_LayoutDataRoot)$(LinuxInstallRoot)</_LayoutPackageRoot>
<_LayoutControlRoot>$(_LayoutDirectory)control/</_LayoutControlRoot>
<_LayoutDocs>$(_LayoutDataRoot)/usr/share/doc</_LayoutDocs>
</PropertyGroup>

<!-- Write the configuration JSON. -->
<GenerateJsonObjectString
Properties="@(_CommonLinuxPackageProperty);@(_DebJsonProperty)"
TargetFile="$(_ConfigJsonFile)" />
<RemoveDir Condition="Exists('$(_InstallerIntermediatesDir)')" Directories="$(_InstallerIntermediatesDir)" />
<MakeDir Directories="$(_InstallerIntermediatesDir)" />

<!-- Run deb tool in the directory of the consumer project. -->
<Exec
Command="/usr/bin/env bash $(MSBuildThisFileDirectory)deb-package-tool/package_tool.sh $(_DebToolArgs)"
IgnoreStandardErrorWarningFormat="true" />
<!-- Create empty layout. -->
<RemoveDir Condition="Exists('$(_LayoutDirectory)')" Directories="$(_LayoutDirectory)" />
<MakeDir Directories="$(_LayoutDirectory)" />
<MakeDir Directories="$(_LayoutPackageRoot)" />
<MakeDir Directories="$(_LayoutControlRoot)" />
<MakeDir Directories="$(_LayoutDocs)" />

<!-- Copy package to output. -->
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="PublishToDisk"
Properties="OutputPath=$([MSBuild]::EnsureTrailingSlash('$(_LayoutPackageRoot)'))"
RemoveProperties="@(_GlobalPropertiesToRemoveForPublish)" />

<Copy
SourceFiles="@(Manpage)"
DestinationFiles="@(Manpage->'$(_LayoutDocs)/%(RecursiveDir)%(Filename)%(Extension)')" />

<!-- Write copyright file in the debian format. -->
<ItemGroup>
<_GeneratedDebFiles Include="$(_DebIntermediatesDir)/*.deb" />
<_CopyrightLine Include="Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" />
<_CopyrightLine Include="%0AFiles: *" />
<_CopyrightLine Include="Copyright: $(_PackageCopyright)" />
<_CopyrightLine Include="Comment: Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license." />
<_CopyrightLine Include="License: MIT and ASL 2.0 and BSD" />
<_CopyrightLine Include="%0ALicense: $([System.IO.File]::ReadAllText('$(LicenseFile)'))" />
</ItemGroup>

<Error Text="@(_GeneratedDebFiles->Count()) .deb files generated." Condition="'@(_GeneratedDebFiles->Count())' != 1" />
<WriteLinesToFile File="$(_LayoutDocs)/$(VersionedInstallerName)/copyright" Lines="@(_CopyrightLine)" />

<Copy SourceFiles="@(_GeneratedDebFiles)"
DestinationFiles="$(_InstallerFile)"
OverwriteReadOnlyFiles="True"
SkipUnchangedFiles="False"
UseHardlinksIfPossible="False" />
<ItemGroup>
<_ChangelogFile Include="$(_LayoutDocs)/$(VersionedInstallerName)/changelog.Debian.gz" />
</ItemGroup>

<CreateChangelogFile
ChangelogOutputPath="@(_ChangelogFile)"
MaintainerEmail="[email protected]"
MaintainerName=".NET Team"
PackageName="$(VersionedInstallerName)"
PackageVersion="$(InstallerPackageVersion)_$(InstallerPackageRelease)"
ReleaseNotes="https://github.com/dotnet/core/tree/master/release-notes" />

<ItemGroup>
<FileWrites Include="$(_ChangelogFile)" />
</ItemGroup>

<Message Text="$(MSBuildProjectName) -> $(_InstallerFile)" Importance="high" />
</Target>
<ItemGroup>
<_MD5SumsFile Include="$(_LayoutControlRoot)/md5sums" />
<_MD5SourceFiles Include="$(_LayoutDataRoot)/**/*" />
</ItemGroup>

<CreateMD5SumsFile
OutputFile="@(_MD5SumsFile)"
RootDirectory="$(_LayoutDataRoot)"
Files="@(_MD5SourceFiles)">
<Output TaskParameter="InstalledSize" PropertyName="_InstalledSize" />
</CreateMD5SumsFile>

<Target Name="GetDebInstallerJsonProperties"
DependsOnTargets="_GetCommonJsonProperties">
<ItemGroup>
<_DebDependenciesJsonEntry Include="@(LinuxPackageDependency->'&quot;%(Identity)&quot; : { &quot;package_version&quot; : &quot;%(Version)&quot;}')" />
<FileWrites Include="@(_MD5SumsFile)" />
</ItemGroup>

<ItemGroup>
<_DebJsonProperty Include="debian_dependencies" Object="{@(_DebDependenciesJsonEntry, ', ')}" />
<_DebJsonProperty Include="@(DebJsonProperty)" />
NikolaMilosavljevic marked this conversation as resolved.
Show resolved Hide resolved
<_ControlFile Include="$(_LayoutControlRoot)/control" />
</ItemGroup>

<CreateControlFile
ControlFileOutputPath="@(_ControlFile)"
PackageName="$(VersionedInstallerName)"
PackageVersion="$(InstallerPackageVersion)"
PackageArchitecture="$(LinuxPackageArchitecture)"
Maintainer=".NET Team &lt;[email protected]&gt;"
Description="$(_ShortDescription)%0A $(_PackageLongDescription)"
InstalledSize="$(_InstalledSize)"
Depends="@(LinuxPackageDependency)"
Section="libs"
AdditionalProperties="@(DebControlProperty)" />

<ItemGroup>
<FileWrites Include="@(_ControlFile)" />
</ItemGroup>

<!-- Create any symlinks -->
<MakeDir Directories="$(_LayoutDataRoot)%(DebSymlink.RelativeDir)" Condition="'%(DebSymlink.Identity)' != ''" />
<Exec Command="ln -s %(DebSymlink.LinkTarget) %(DebSymlink.FileName)%(DebSymlink.Extension)" WorkingDirectory="$(_LayoutDataRoot)%(DebSymlink.RelativeDir)" Condition="'%(DebSymlink.Identity)' != ''" />

<Exec Command="tar -C '$(_LayoutControlRoot)' -czf '$(_LayoutDirectory)/control.tar.gz' ."
IgnoreExitCode="true"
IgnoreStandardErrorWarningFormat="true" />

<Exec Command="tar -C '$(_LayoutDataRoot)' -czf '$(_LayoutDirectory)/data.tar.gz' ."
IgnoreExitCode="true"
IgnoreStandardErrorWarningFormat="true" />

<CreateDebPackage
OutputDebPackagePath="$(_InstallerFile)"
ControlFile="$(_LayoutDirectory)/control.tar.gz"
DataFile="$(_LayoutDirectory)/data.tar.gz" />

<Message Text="$(MSBuildProjectName) -> $(_InstallerFile)" Importance="high" />
</Target>

<!--
Expand Down Expand Up @@ -485,6 +522,8 @@
<LinuxPackageArchitecture>$(InstallerTargetArchitecture)</LinuxPackageArchitecture>
<!-- Linux packaging requires 'amd64' for x64 packages -->
<LinuxPackageArchitecture Condition="'$(LinuxPackageArchitecture)' == 'x64'">amd64</LinuxPackageArchitecture>
<_PackageCopyright>2017 Microsoft</_PackageCopyright>
<_PackageLongDescription>.NET is a development platform that you can use to build command-line applications, microservices and modern websites. It is open source, cross-platform and is supported by Microsoft. We hope you enjoy using it! If you do, please consider joining the active community of developers that are contributing to the project on GitHub (https://github.com/dotnet/core). We happily accept issues and PRs.</_PackageLongDescription>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -522,9 +561,9 @@
<_CommonLinuxPackageProperty Include="maintainer_name" String=".NET Team" />
<_CommonLinuxPackageProperty Include="maintainer_email" String="[email protected]" />
<_CommonLinuxPackageProperty Include="install_root" String="$(LinuxInstallRoot)" />
<_CommonLinuxPackageProperty Include="long_description" String=".NET is a development platform that you can use to build command-line applications, microservices and modern websites. It is open source, cross-platform and is supported by Microsoft. We hope you enjoy using it! If you do, please consider joining the active community of developers that are contributing to the project on GitHub (https://github.com/dotnet/core). We happily accept issues and PRs." />
<_CommonLinuxPackageProperty Include="long_description" String="$(_PackageLongDescription)" />
<_CommonLinuxPackageProperty Include="homepage" String="https://github.com/dotnet/core" />
<_CommonLinuxPackageProperty Include="copyright" String="2017 Microsoft" />
<_CommonLinuxPackageProperty Include="copyright" String="$(_PackageCopyright)" />
<_CommonLinuxPackageProperty Include="release" Object="$(_JsonReleaseObject)" />
<_CommonLinuxPackageProperty Include="control" Object="$(_JsonControlObject)" />
<_CommonLinuxPackageProperty Include="license" Object="$(_JsonLicenseObject)" />
Expand Down
27 changes: 27 additions & 0 deletions src/Microsoft.DotNet.Build.Tasks.Installers/src/ArEntry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;

namespace Microsoft.DotNet.Build.Tasks.Installers
{
internal sealed class ArEntry
{
public ArEntry(string name, ulong timestamp, ulong ownerID, ulong groupID, uint mode, Stream dataStream)
{
Name = name;
Timestamp = timestamp;
OwnerID = ownerID;
GroupID = groupID;
Mode = mode;
DataStream = dataStream;
}

public string Name { get; }
public ulong Timestamp { get; }
public ulong OwnerID { get; }
public ulong GroupID { get; }
public uint Mode { get; }
public Stream DataStream { get; }
}
}
123 changes: 123 additions & 0 deletions src/Microsoft.DotNet.Build.Tasks.Installers/src/ArReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

#nullable enable

namespace Microsoft.DotNet.Build.Tasks.Installers
{
internal sealed class ArReader(Stream stream, bool leaveOpen) : IDisposable
{
private bool readMagic;
public ArEntry? GetNextEntry()
{
if (!readMagic)
{
byte[] magic = new byte[8];
jkoritzinsky marked this conversation as resolved.
Show resolved Hide resolved
ReadExactly(magic, 0, 8);
readMagic = true;
if (!magic.AsSpan().SequenceEqual("!<arch>\n"u8))
{
throw new InvalidDataException("Invalid archive magic");
}
}

if (stream.Position == stream.Length)
{
return null;
}

byte[] fileName = new byte[16];
ReadExactly(fileName, 0, 16);
string name = Encoding.ASCII.GetString(fileName).TrimEnd(' ');
byte[] timestampBytes = new byte[12];
ReadExactly(timestampBytes, 0, 12);

ulong timestamp = ulong.Parse(Encoding.ASCII.GetString(timestampBytes).TrimEnd(' '));

byte[] ownerIDBytes = new byte[6];
ReadExactly(ownerIDBytes, 0, 6);

ulong ownerID = ulong.Parse(Encoding.ASCII.GetString(ownerIDBytes).TrimEnd(' '));

byte[] groupIDBytes = new byte[6];
ReadExactly(groupIDBytes, 0, 6);

ulong groupID = ulong.Parse(Encoding.ASCII.GetString(groupIDBytes).TrimEnd(' '));

byte[] modeBytes = new byte[8];
ReadExactly(modeBytes, 0, 8);

uint mode = Convert.ToUInt32(Encoding.ASCII.GetString(modeBytes).TrimEnd(' '), 8);

byte[] sizeBytes = new byte[10];
ReadExactly(sizeBytes, 0, 10);

ulong size = ulong.Parse(Encoding.ASCII.GetString(sizeBytes).TrimEnd(' '));

byte[] footer = new byte[2];
ReadExactly(footer, 0, 2);
if (!footer.AsSpan().SequenceEqual("`\n"u8))
{
throw new InvalidDataException("Invalid archive magic");
}

MemoryStream dataStream = new MemoryStream();
for (ulong remaining = size; remaining > 0; remaining -= int.MaxValue)
{
stream.CopyTo(dataStream, (int)Math.Min(remaining, int.MaxValue));
}

if (size % 2 == 1)
{
// Skip the padding newline
// for an odd-length entry
_ = stream.ReadByte();
}

return new ArEntry(
name,
timestamp,
ownerID,
groupID,
mode,
dataStream);
}

public void Dispose()
{
if (!leaveOpen)
{
stream.Dispose();
}
}

#if !NET
private void ReadExactly(byte[] buffer, int offset, int count)
{
while (count > 0)
{
int read = stream.Read(buffer, offset, count);
if (read == 0)
{
throw new InvalidOperationException("Unexpected end of stream");
}
offset += read;
count -= read;
}
}
#else
private void ReadExactly(byte[] buffer, int offset, int count)
{
stream.ReadExactly(buffer.AsSpan(offset, count));
}
#endif
}
}
Loading
Loading