Skip to content

Commit

Permalink
Merge pull request #17 from canonical/feat/arm64-enablement
Browse files Browse the repository at this point in the history
Add `arm64` support to .NET snap
  • Loading branch information
mateusrodrigues authored Oct 15, 2024
2 parents aaee004 + 29cedc1 commit 49b4e6a
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 100 deletions.
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]
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
- 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/*
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
6 changes: 3 additions & 3 deletions src/Dotnet.Installer.Core/Services/Contracts/ISnapService.cs
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);
}
10 changes: 5 additions & 5 deletions src/Dotnet.Installer.Core/Services/Contracts/ISystemdService.cs
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());
}
}
}
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

0 comments on commit 49b4e6a

Please sign in to comment.