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

Add arm64 support to .NET snap #17

Merged
merged 3 commits into from
Oct 15, 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
55 changes: 39 additions & 16 deletions .github/workflows/build-on-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,23 @@ permissions:

jobs:
unit-test:
runs-on: ubuntu-latest

strategy:
matrix:
os:
- [self-hosted, large, jammy, X64]
- [self-hosted, large, jammy, ARM64]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
id: checkout

- name: Install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
id: install-dotnet
run: |
sudo apt-get update
sudo apt-get upgrade --yes
sudo apt-get install --yes dotnet-sdk-8.0
echo "DPKG_ARCH=$(dpkg --print-architecture)" >> "$GITHUB_OUTPUT"

- name: Run Tests
run: dotnet test --verbosity normal --logger trx --results-directory TestResults
Expand All @@ -31,16 +39,25 @@ jobs:
if: always()
with:
check_name: test-results
comment_title: Test Results
comment_title: Test Results (${{ steps.install-dotnet.outputs.DPKG_ARCH }})
files: |
TestResults/*.trx

snapcraft-build:
runs-on: ubuntu-latest
strategy:
matrix:
os:
- [self-hosted, large, jammy, X64]
- [self-hosted, large, jammy, ARM64]
mateusrodrigues marked this conversation as resolved.
Show resolved Hide resolved
runs-on: ${{ matrix.os }}
needs: unit-test

steps:
- uses: actions/checkout@v4
id: checkout

- name: Retrieve Architecture
id: get-arch
run: echo "DPKG_ARCH=$(dpkg --print-architecture)" >> "$GITHUB_OUTPUT"

- name: Run Snapcraft
id: snapcraft
Expand All @@ -50,27 +67,31 @@ jobs:
id: upload-artifact
uses: actions/upload-artifact@v4
with:
name: snap
name: dotnet-${{ steps.get-arch.outputs.DPKG_ARCH }}
path: ${{ steps.snapcraft.outputs.snap }}

snapcraft-publish:
runs-on: ubuntu-latest
if: ${{ contains(fromJSON('["push", "workflow_dispatch"]'), github.event_name) && github.ref_name == 'main' }}
needs: snapcraft-build

strategy:
matrix:
artifact-name:
- dotnet-amd64
- dotnet-arm64
steps:
- uses: actions/download-artifact@v4
id: download-artifact
with:
name: snap
name: ${{ matrix.artifact-name }}

- name: Gather filename
id: gather-filename
env:
ARTIFACT_PATH: ${{ steps.download-artifact.outputs.download-path }}
run: |
ls -la $ARTIFACT_PATH
SNAP_FILE_NAME=$(ls ${ARTIFACT_PATH}/${SNAP_NAME}*.snap)
SNAP_FILE_NAME=$(ls ${ARTIFACT_PATH}/dotnet*.snap)
echo "SNAP_PATH=${SNAP_FILE_NAME}" >> "$GITHUB_OUTPUT"

- uses: snapcore/action-publish@v1
Expand All @@ -85,14 +106,16 @@ jobs:
if: ${{ github.event_name == 'push' }}
permissions:
contents: write

steps:
- uses: actions/checkout@v4
id: checkout

- name: Install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
id: install-dotnet
run: |
sudo apt-get update
sudo apt-get upgrade --yes
sudo apt-get install --yes dotnet-sdk-8.0
mateusrodrigues marked this conversation as resolved.
Show resolved Hide resolved

- name: Install reportgenerator tool
run: |
Expand Down
72 changes: 50 additions & 22 deletions snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ grade: devel # must be 'stable' to release into candidate/stable channels
confinement: classic

package-repositories:
- type: apt
ppa: dotnet/snaps
priority: always
- type: apt
ppa: dotnet/snaps
priority: always

architectures:
- build-on: [amd64]
build-for: [amd64]
- build-on: [arm64]
build-for: [arm64]

parts:
pre-reqs:
Expand All @@ -39,6 +45,7 @@ parts:
dotnet-installer:
plugin: dump
source: .
after: [ pre-reqs ]
build-packages:
- dotnet-sdk-8.0
stage-packages:
Expand All @@ -53,30 +60,39 @@ parts:
elif [ "${CRAFT_ARCH_BUILD_FOR}" = "arm64" ]; then
RUNTIME_RID="linux-arm64"
else
echo "Unknown architecture (${CRAFT_ARCH_BUILD_FOR})"
echo "Unsupported architecture (${CRAFT_ARCH_BUILD_FOR})"
exit 1
fi

/usr/bin/dotnet publish src/Dotnet.Installer.Console --output "${SNAPCRAFT_PART_INSTALL}" \
--configuration Release -r "${RUNTIME_RID}" -p:DebugSymbols=false -p:DebugType=none
chmod 555 "${SNAPCRAFT_PART_INSTALL}/Dotnet.Installer.Console"

craftctl default
override-stage: |
craftctl default
# jq files
patchelf --set-interpreter /snap/dotnet/current/lib64/ld-linux-x86-64.so.2 usr/bin/jq
patchelf --force-rpath --set-rpath /snap/dotnet/current/usr/lib/x86_64-linux-gnu usr/bin/jq
# .NET Installer files
patchelf --set-interpreter /snap/dotnet/current/lib64/ld-linux-x86-64.so.2 Dotnet.Installer.Console
patchelf --force-rpath --set-rpath \$ORIGIN/netcoredeps:/snap/dotnet/current/usr/lib/x86_64-linux-gnu Dotnet.Installer.Console
prime:
- usr/bin/jq
- usr/lib/*/libjq.so*
- usr/lib/*/libonig.so*
- Dotnet.Installer.Console
- Configuration/*
- Scripts/*
mateusrodrigues marked this conversation as resolved.
Show resolved Hide resolved

if [ "${CRAFT_ARCH_BUILD_FOR}" = "amd64" ]; then
LIB_PATH=lib/x86_64-linux-gnu
INTERPRETER="/snap/dotnet/current/lib64/ld-linux-x86-64.so.2"

patchelf --force-rpath --set-rpath \$ORIGIN/../${LIB_PATH} \
${CRAFT_STAGE}/usr/bin/jq
patchelf --force-rpath --set-rpath \$ORIGIN/usr/${LIB_PATH} \
${CRAFT_STAGE}/Dotnet.Installer.Console
elif [ "${CRAFT_ARCH_BUILD_FOR}" = "arm64" ]; then
LIB_PATH=lib/aarch64-linux-gnu
INTERPRETER="/snap/dotnet/current/lib/ld-linux-aarch64.so.1"

patchelf --force-rpath --set-rpath \$ORIGIN/../${LIB_PATH}:\$ORIGIN/../../${LIB_PATH} \
${CRAFT_STAGE}/usr/bin/jq
patchelf --force-rpath --set-rpath \$ORIGIN/${LIB_PATH}:\$ORIGIN/usr/${LIB_PATH} \
${CRAFT_STAGE}/Dotnet.Installer.Console
else
echo "Unsupported architecture (${CRAFT_ARCH_BUILD_FOR})"
exit 1
fi

patchelf --set-interpreter $INTERPRETER ${CRAFT_STAGE}/usr/bin/jq
patchelf --set-interpreter $INTERPRETER ${CRAFT_STAGE}/Dotnet.Installer.Console

dotnet-host:
plugin: nil
Expand All @@ -86,10 +102,22 @@ parts:
- dotnet-hostfxr-8.0
override-stage: |
craftctl default

if [ "${CRAFT_ARCH_BUILD_FOR}" = "amd64" ]; then
INTERPRETER="/snap/dotnet/current/lib64/ld-linux-x86-64.so.2"
RPATH="/snap/dotnet/current/usr/lib/x86_64-linux-gnu"
elif [ "${CRAFT_ARCH_BUILD_FOR}" = "arm64" ]; then
INTERPRETER="/snap/dotnet/current/lib/ld-linux-aarch64.so.1"
RPATH="/snap/dotnet/current/usr/lib/aarch64-linux-gnu:/snap/dotnet/current/lib/aarch64-linux-gnu"
else
echo "Unsupported architecture (${CRAFT_ARCH_BUILD_FOR})"
exit 1
fi

DOTNET_VERSION=$(craftctl get version)
patchelf --set-interpreter /snap/dotnet/current/lib64/ld-linux-x86-64.so.2 usr/lib/dotnet/dotnet
patchelf --force-rpath --set-rpath /snap/dotnet/current/usr/lib/x86_64-linux-gnu usr/lib/dotnet/dotnet
patchelf --force-rpath --set-rpath /snap/dotnet/current/usr/lib/x86_64-linux-gnu usr/lib/dotnet/host/fxr/${DOTNET_VERSION}/libhostfxr.so
patchelf --set-interpreter $INTERPRETER usr/lib/dotnet/dotnet
patchelf --force-rpath --set-rpath $RPATH usr/lib/dotnet/dotnet
patchelf --force-rpath --set-rpath $RPATH usr/lib/dotnet/host/fxr/${DOTNET_VERSION}/libhostfxr.so

netstandard-targeting-pack:
plugin: nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ namespace Dotnet.Installer.Core.Services.Contracts;
public interface ISnapService
{
bool IsSnapInstalled(string name, CancellationToken cancellationToken = default);
Task<InvocationResult> Install(string name, CancellationToken cancellationToken = default);
Task<InvocationResult> Remove(string name, bool purge = false, CancellationToken cancellationToken = default);
}
Task<Terminal.InvocationResult> Install(string name, CancellationToken cancellationToken = default);
Task<Terminal.InvocationResult> Remove(string name, bool purge = false, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ namespace Dotnet.Installer.Core.Services.Contracts;

public interface ISystemdService
{
Task<InvocationResult> DaemonReload();
Task<InvocationResult> EnableUnit(string unit);
Task<InvocationResult> DisableUnit(string unit);
Task<InvocationResult> StartUnit(string unit);
Task<InvocationResult> StopUnit(string unit);
Task<Terminal.InvocationResult> DaemonReload();
Task<Terminal.InvocationResult> EnableUnit(string unit);
Task<Terminal.InvocationResult> DisableUnit(string unit);
Task<Terminal.InvocationResult> StartUnit(string unit);
Task<Terminal.InvocationResult> StopUnit(string unit);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,21 @@ public bool IsSnapInstalled(string name, CancellationToken cancellationToken = d
return Directory.Exists(Path.Combine("/", "snap", name));
}

public async Task<InvocationResult> Install(string name, CancellationToken cancellationToken = default)
public Task<Terminal.InvocationResult> Install(string name, CancellationToken cancellationToken = default)
{
var result = await Terminal.Invoke("snap", "install", name);
return new InvocationResult(result == 0, "", "");
return Terminal.Invoke("snap", "install", name);
}

public async Task<InvocationResult> Remove(string name, bool purge = false, CancellationToken cancellationToken = default)
public Task<Terminal.InvocationResult> Remove(string name, bool purge = false, CancellationToken cancellationToken = default)
{
var arguments = new List<string>
{
"remove"
};

if (purge) arguments.Add("--purge");
arguments.Add(name);

var result = await Terminal.Invoke("snap", arguments.ToArray());
return new InvocationResult(result == 0, "", "");

return Terminal.Invoke("snap", arguments.ToArray());
mateusrodrigues marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,29 @@ public class SystemdService : ISystemdService
RedirectStandardError = true,
RedirectStandardOutput = true,
};
public async Task<InvocationResult> DaemonReload()

public Task<Terminal.InvocationResult> DaemonReload()
{
var result = await Terminal.Invoke("systemctl", _globalSystemdOptions, "daemon-reload");
return new InvocationResult(result == 0, string.Empty, string.Empty);
return Terminal.Invoke("systemctl", _globalSystemdOptions, "daemon-reload");
}

public async Task<InvocationResult> EnableUnit(string unit)
public Task<Terminal.InvocationResult> EnableUnit(string unit)
{
var result = await Terminal.Invoke("systemctl", _globalSystemdOptions, "enable", unit);
return new InvocationResult(result == 0, string.Empty, string.Empty);
return Terminal.Invoke("systemctl", _globalSystemdOptions, "enable", unit);
}

public async Task<InvocationResult> DisableUnit(string unit)
public Task<Terminal.InvocationResult> DisableUnit(string unit)
{
var result = await Terminal.Invoke("systemctl", _globalSystemdOptions, "disable", unit);
return new InvocationResult(result == 0, string.Empty, string.Empty);
return Terminal.Invoke("systemctl", _globalSystemdOptions, "disable", unit);
}

public async Task<InvocationResult> StartUnit(string unit)
public Task<Terminal.InvocationResult> StartUnit(string unit)
{
var result = await Terminal.Invoke("systemctl", _globalSystemdOptions, "start", unit);
return new InvocationResult(result == 0, string.Empty, string.Empty);
return Terminal.Invoke("systemctl", _globalSystemdOptions, "start", unit);
}

public async Task<InvocationResult> StopUnit(string unit)
public Task<Terminal.InvocationResult> StopUnit(string unit)
{
var result = await Terminal.Invoke("systemctl", _globalSystemdOptions, "stop", unit);
return new InvocationResult(result == 0, string.Empty, string.Empty);
return Terminal.Invoke("systemctl", _globalSystemdOptions, "stop", unit);
}
}
8 changes: 0 additions & 8 deletions src/Dotnet.Installer.Core/Types/InvocationResult.cs

This file was deleted.

38 changes: 35 additions & 3 deletions src/Dotnet.Installer.Core/Types/Terminal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ namespace Dotnet.Installer.Core.Types;

public static class Terminal
{
public static async Task<int> Invoke(string program, params string[] arguments)
public static async Task<InvocationResult> Invoke(string program, params string[] arguments)
{
return await Invoke(program, options: null, arguments);
}

public static async Task<int> Invoke(string program, InvocationOptions? options = default,
public static async Task<InvocationResult> Invoke(string program, InvocationOptions? options = default,
params string[] arguments)
{
options ??= InvocationOptions.Default;
Expand All @@ -28,7 +28,16 @@ public static async Task<int> Invoke(string program, InvocationOptions? options
process.Start();
await process.WaitForExitAsync();

return process.ExitCode;
return new InvocationResult
{
ExitCode = process.ExitCode,
RedirectedStandardError = options.RedirectStandardError,
RedirectedStandardOutput = options.RedirectStandardOutput,
StandardError = options.RedirectStandardError ?
await process.StandardError.ReadToEndAsync() : default,
StandardOutput = options.RedirectStandardOutput ?
await process.StandardOutput.ReadToEndAsync() : default
};
}

public class InvocationOptions
Expand All @@ -38,4 +47,27 @@ public class InvocationOptions
public bool RedirectStandardOutput { get; set; } = false;
public bool RedirectStandardError { get; set; } = false;
}

public class InvocationResult
{
public InvocationResult()
{ }

public InvocationResult(int exitCode, string standardOutput, string standardError)
{
ExitCode = exitCode;
StandardOutput = standardOutput;
StandardError = standardError;

RedirectedStandardError = true;
RedirectedStandardOutput = true;
}

public bool IsSuccess => ExitCode == 0;
public int ExitCode { get; init; }
public bool RedirectedStandardOutput { get; init; }
public bool RedirectedStandardError { get; init; }
public string? StandardOutput { get; init; }
public string? StandardError { get; init; }
}
}
Loading