From d6fe3013ab52c92542b0cda917dd11cce8a292fa Mon Sep 17 00:00:00 2001 From: Mbucari Date: Wed, 17 May 2023 15:08:24 -0600 Subject: [PATCH] RPM build --- .github/workflows/build-linux.yml | 71 ++++++--- .github/workflows/build-windows.yml | 3 +- .github/workflows/build.yml | 22 ++- .releaseindex.json | 14 +- Scripts/{Bundle_Linux.sh => Bundle_Debian.sh} | 0 Scripts/Bundle_Redhat.sh | 140 ++++++++++++++++++ Source/AppScaffolding/LibationScaffolding.cs | 13 +- .../LibationFileManager/IInteropFunctions.cs | 1 + .../NullInteropFunctions.cs | 1 + .../LoadByOS/LinuxConfigApp/LinuxInterop.cs | 5 +- .../LoadByOS/MacOSConfigApp/MacOSInterop.cs | 2 + .../LoadByOS/WindowsConfigApp/WinInterop.cs | 3 + 12 files changed, 242 insertions(+), 33 deletions(-) rename Scripts/{Bundle_Linux.sh => Bundle_Debian.sh} (100%) create mode 100644 Scripts/Bundle_Redhat.sh diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 3f3a8fd0..86468524 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -15,6 +15,21 @@ on: description: 'Skip running unit tests' required: false default: true + runs_on: + type: string + description: 'The GitHub hosted runner to use' + required: true + OS: + type: string + description: > + The operating system targeted by the build. + + There must be a corresponding Bundle_$OS.sh script file in ./Scripts + required: true + architecture: + type: string + description: 'CPU architecture targeted by the build.' + required: true env: DOTNET_CONFIGURATION: 'Release' @@ -23,11 +38,8 @@ env: jobs: build: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - arch: [x64, arm64] + name: '${{ inputs.OS }}-${{ inputs.architecture }}' + runs-on: ${{ inputs.runs_on }} steps: - uses: actions/checkout@v3 - name: Setup .NET @@ -48,6 +60,7 @@ jobs: version="$(grep -Eio -m 1 '.*' ./Source/AppScaffolding/AppScaffolding.csproj | sed -r 's/<\/?Version>//g')" fi echo "version=${version}" >> "${GITHUB_OUTPUT}" + - name: Unit test if: ${{ inputs.run_unit_tests }} working-directory: ./Source @@ -56,52 +69,64 @@ jobs: - name: Publish id: publish working-directory: ./Source - run: | - os=${{ matrix.os }} - target_os="$(echo ${os/-latest/} | sed 's/ubuntu/linux/')" - display_os="$(echo ${target_os/macos/macOS} | sed 's/linux/Linux/')" + run: | + if [[ "${{ inputs.OS }}" == "MacOS" ]] + then + display_os="macOS" + RUNTIME_ID="osx-${{ inputs.architecture }}" + else + display_os="Linux" + RUNTIME_ID="linux-${{ inputs.architecture }}" + fi + + OUTPUT="bin/Publish/${display_os}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }}" + echo "display_os=${display_os}" >> $GITHUB_OUTPUT - RUNTIME_IDENTIFIER="$(echo ${target_os/macos/osx})-${{ matrix.arch }}" - echo "$RUNTIME_IDENTIFIER" + echo "Runtime Identifier: $RUNTIME_ID" + echo "Output Directory: $OUTPUT" + dotnet publish \ LibationAvalonia/LibationAvalonia.csproj \ - --runtime "$RUNTIME_IDENTIFIER" \ + --runtime $RUNTIME_ID \ --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ + --output $OUTPUT \ -p:PublishProfile=LibationAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml dotnet publish \ LoadByOS/${display_os}ConfigApp/${display_os}ConfigApp.csproj \ - --runtime "$RUNTIME_IDENTIFIER" \ + --runtime $RUNTIME_ID \ --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ + --output $OUTPUT \ -p:PublishProfile=LoadByOS/Properties/${display_os}ConfigApp/PublishProfiles/${display_os}Profile.pubxml dotnet publish \ LibationCli/LibationCli.csproj \ - --runtime "$RUNTIME_IDENTIFIER" \ + --runtime $RUNTIME_ID \ --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ + --output $OUTPUT \ -p:PublishProfile=LibationCli/Properties/PublishProfiles/${display_os}Profile.pubxml dotnet publish \ HangoverAvalonia/HangoverAvalonia.csproj \ - --runtime "$RUNTIME_IDENTIFIER" \ + --runtime $RUNTIME_ID \ --configuration ${{ env.DOTNET_CONFIGURATION }} \ - --output bin/Publish/${display_os}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} \ + --output $OUTPUT \ -p:PublishProfile=HangoverAvalonia/Properties/PublishProfiles/${display_os}Profile.pubxml + - name: Build bundle id: bundle - working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ matrix.arch }}-${{ env.RELEASE_NAME }} + working-directory: ./Source/bin/Publish/${{ steps.publish.outputs.display_os }}-${{ inputs.architecture }}-${{ env.RELEASE_NAME }} run: | BUNDLE_DIR=$(pwd) echo "Bundle dir: ${BUNDLE_DIR}" cd .. - SCRIPT=../../../Scripts/Bundle_${{ steps.publish.outputs.display_os }}.sh + SCRIPT=../../../Scripts/Bundle_${{ inputs.OS }}.sh chmod +rx ${SCRIPT} - ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ matrix.arch }}" + ${SCRIPT} "${BUNDLE_DIR}" "${{ steps.get_version.outputs.version }}" "${{ inputs.architecture }}" artifact=$(ls ./bundle) echo "artifact=${artifact}" >> "${GITHUB_OUTPUT}" + - name: Publish bundle uses: actions/upload-artifact@v3 with: name: ${{ steps.bundle.outputs.artifact }} path: ./Source/bin/Publish/bundle/${{ steps.bundle.outputs.artifact }} - if-no-files-found: error \ No newline at end of file + if-no-files-found: error + retention-days: 7 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 605016a1..a14c5a38 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -22,6 +22,7 @@ env: jobs: build: + name: '${{ matrix.os }}-${{ matrix.release_name }}' runs-on: windows-latest strategy: matrix: @@ -110,4 +111,4 @@ jobs: name: ${{ steps.zip.outputs.artifact }}.zip path: ./Source/bin/Publish/${{ steps.zip.outputs.artifact }}.zip if-no-files-found: error - + retention-days: 7 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6cf9787..ce1186ac 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,14 +17,34 @@ on: default: true jobs: + windows: uses: ./.github/workflows/build-windows.yml with: version_override: ${{ inputs.version_override }} run_unit_tests: ${{ inputs.run_unit_tests }} - + linux: + strategy: + matrix: + OS: [Redhat, Debian] + architecture: [x64, arm64] uses: ./.github/workflows/build-linux.yml with: version_override: ${{ inputs.version_override }} + runs_on: ubuntu-latest + OS: ${{ matrix.OS }} + architecture: ${{ matrix.architecture }} + run_unit_tests: ${{ inputs.run_unit_tests }} + + macos: + strategy: + matrix: + architecture: [x64, arm64] + uses: ./.github/workflows/build-linux.yml + with: + version_override: ${{ inputs.version_override }} + runs_on: macos-latest + OS: MacOS + architecture: ${{ matrix.architecture }} run_unit_tests: ${{ inputs.run_unit_tests }} diff --git a/.releaseindex.json b/.releaseindex.json index 5e44f230..9d9dea23 100644 --- a/.releaseindex.json +++ b/.releaseindex.json @@ -1,8 +1,10 @@ { - "WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip", - "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip", - "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb", - "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz", - "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb", - "MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz" + "WindowsClassic": "Classic-Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-classic\\.zip", + "WindowsAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-win(dows)?-chardonnay\\.zip", + "LinuxAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.deb", + "LinuxAvalonia_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-amd64\\.rpm", + "MacOSAvalonia": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-x64\\.tgz", + "LinuxAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.deb", + "LinuxAvalonia_Arm64_RPM": "Libation\\.\\d+\\.\\d+\\.\\d+-linux-chardonnay-arm64\\.rpm", + "MacOSAvalonia_Arm64": "Libation\\.\\d+\\.\\d+\\.\\d+-macOS-chardonnay-arm64\\.tgz" } diff --git a/Scripts/Bundle_Linux.sh b/Scripts/Bundle_Debian.sh similarity index 100% rename from Scripts/Bundle_Linux.sh rename to Scripts/Bundle_Debian.sh diff --git a/Scripts/Bundle_Redhat.sh b/Scripts/Bundle_Redhat.sh new file mode 100644 index 00000000..77bb4769 --- /dev/null +++ b/Scripts/Bundle_Redhat.sh @@ -0,0 +1,140 @@ +#!/bin/bash + +BIN_DIR=$1; shift +VERSION=$1; shift +ARCH=$1; shift + +if [ -z "$BIN_DIR" ] +then + echo "This script must be called with a the Libation Linux bins directory as an argument." + exit +fi + +if [ ! -d "$BIN_DIR" ] +then + echo "The directory \"$BIN_DIR\" does not exist." + exit +fi + +if [ -z "$VERSION" ] +then + echo "This script must be called with the Libation version number as an argument." + exit +fi + +if [ -z "$ARCH" ] +then + echo "This script must be called with the Libation cpu architecture as an argument." + exit +fi + +contains() { case "$1" in *"$2"*) true ;; *) false ;; esac } + +if ! contains "$BIN_DIR" "$ARCH" +then + echo "This script must be called with a Libation binaries for ${ARCH}." + exit +fi + +BASEDIR=$(pwd) + +delfiles=('libmp3lame.arm64.dylib' 'libmp3lame.x64.dylib' 'libmp3lame.x64.dll' 'libmp3lame.x86.dll' 'ffmpegaac.arm64.dylib' 'ffmpegaac.x64.dylib' 'ffmpegaac.x64.dll' 'ffmpegaac.x86.dll' 'LinuxConfigApp' 'LinuxConfigApp.deps.json' 'LinuxConfigApp.runtimeconfig.json') +if [[ "$ARCH" == "x64" ]] +then + delfiles+=('libmp3lame.arm64.so' 'ffmpegaac.arm64.so') + ARCH_RPM="x86_64" + ARCH="amd64" +else + delfiles+=('libmp3lame.x64.so' 'ffmpegaac.x64.so') + ARCH_RPM="aarch64" +fi + +notinstalled=('libcoreclrtraceptprovider.so' 'libation_glass.svg' 'Libation.desktop') + +mkdir -p ~/rpmbuild/SPECS +mkdir ~/rpmbuild/BUILD +mkdir ~/rpmbuild/RPMS + +echo "Name: libation +Version: ${VERSION} +Release: 1 +Summary: Liberate your Audible Library + +License: GPLv3+ +URL: https://github.com/rmcrackan/Libation +Source0: https://github.com/rmcrackan/Libation + +Requires: bash + + +%define __os_install_post %{nil} + +%description +Liberate your Audible Library + +%install +mkdir -p %{buildroot}%{_libdir}/%{name} +mkdir -p %{buildroot}%{_datadir}/icons/hicolor/scalable/apps +mkdir -p %{buildroot}%{_datadir}/applications + +if test -f 'libcoreclrtraceptprovider.so'; then + rm 'libcoreclrtraceptprovider.so' +fi + +touch appsettings.json +chmod 666 appsettings.json + +install -m 666 libation_glass.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/libation.svg +install -m 666 Libation.desktop %{buildroot}%{_datadir}/applications/Libation.desktop + +rm libation_glass.svg +rm Libation.desktop + +install * %{buildroot}%{_libdir}/%{name}/ + +%post + +ln -s %{_libdir}/%{name}/Libation %{_bindir}/libation +ln -s %{_libdir}/%{name}/Hangover %{_bindir}/hangover +ln -s %{_libdir}/%{name}/LibationCli %{_bindir}/libationcli + +gtk-update-icon-cache -f %{_datadir}/icons/hicolor/ + +%postun + +rm %{_bindir}/libation +rm %{_bindir}/hangover +rm %{_bindir}/libationcli + +if ! grep -q 'fs.inotify.max_user_instances=524288' /etc/sysctl.conf; then + echo fs.inotify.max_user_instances=524288 | tee -a /etc/sysctl.conf && sysctl -p +fi + +%files +%{_datadir}/icons/hicolor/scalable/apps/libation.svg +%{_datadir}/applications/Libation.desktop +%{_libdir}/%{name}/appsettings.json" >> ~/rpmbuild/SPECS/libation.spec + + +cd "$BIN_DIR" + +for f in *; do + if [[ " ${delfiles[*]} " =~ " ${f} " ]]; then + echo "Deleting $f" + elif [[ ! " ${notinstalled[*]} " =~ " ${f} " ]]; then + echo "%{_libdir}/%{name}/${f}" >> ~/rpmbuild/SPECS/libation.spec + cp $f ~/rpmbuild/BUILD/ + else + cp $f ~/rpmbuild/BUILD/ + fi +done + +cd ~/rpmbuild/SPECS/ +rpmbuild -bb --target $ARCH_RPM libation.spec + +cd $BASEDIR +RPM_FILE=$(ls ~/rpmbuild/RPMS/${ARCH_RPM}) + +mkdir bundle + +mv ~/rpmbuild/RPMS/${ARCH_RPM}/$RPM_FILE "./bundle/Libation.${VERSION}-linux-chardonnay-${ARCH}.rpm" diff --git a/Source/AppScaffolding/LibationScaffolding.cs b/Source/AppScaffolding/LibationScaffolding.cs index efaaf63b..a0b1d9c9 100644 --- a/Source/AppScaffolding/LibationScaffolding.cs +++ b/Source/AppScaffolding/LibationScaffolding.cs @@ -330,7 +330,18 @@ namespace AppScaffolding //Download the release index var bts = await gitHubClient.Repository.Content.GetRawContent(ownerAccount, repoName, ".releaseindex.json"); var releaseIndex = JObject.Parse(System.Text.Encoding.ASCII.GetString(bts)); - var regexPattern = releaseIndex.Value(ReleaseIdentifier.ToString()); + + string regexPattern; + + try + { + regexPattern = releaseIndex.Value(InteropFactory.Create().ReleaseIdentifier); + } + catch + { + regexPattern = releaseIndex.Value(ReleaseIdentifier.ToString()); + } + var regex = new System.Text.RegularExpressions.Regex(regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase); //https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-the-latest-release diff --git a/Source/LibationFileManager/IInteropFunctions.cs b/Source/LibationFileManager/IInteropFunctions.cs index 7b0df53c..4ec5a896 100644 --- a/Source/LibationFileManager/IInteropFunctions.cs +++ b/Source/LibationFileManager/IInteropFunctions.cs @@ -16,6 +16,7 @@ namespace LibationFileManager Process RunAsRoot(string exe, string args); void InstallUpgrade(string upgradeBundle); bool CanUpgrade { get; } + string ReleaseIdentifier { get; } } public class WebViewNavigationEventArgs : EventArgs diff --git a/Source/LibationFileManager/NullInteropFunctions.cs b/Source/LibationFileManager/NullInteropFunctions.cs index aba0b46f..5bab7361 100644 --- a/Source/LibationFileManager/NullInteropFunctions.cs +++ b/Source/LibationFileManager/NullInteropFunctions.cs @@ -15,6 +15,7 @@ namespace LibationFileManager public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); public bool CanUpgrade => throw new PlatformNotSupportedException(); + public string ReleaseIdentifier => throw new PlatformNotSupportedException(); public Process RunAsRoot(string exe, string args) => throw new PlatformNotSupportedException(); public void InstallUpgrade(string updateBundle) => throw new PlatformNotSupportedException(); } diff --git a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs index d3d76482..988a3309 100644 --- a/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs +++ b/Source/LoadByOS/LinuxConfigApp/LinuxInterop.cs @@ -1,4 +1,5 @@ -using LibationFileManager; +using AppScaffolding; +using LibationFileManager; using System.Diagnostics; namespace LinuxConfigApp @@ -24,6 +25,8 @@ namespace LinuxConfigApp public void SetFolderIcon(string image, string directory) => throw new PlatformNotSupportedException(); public void DeleteFolderIcon(string directory) => throw new PlatformNotSupportedException(); + public string ReleaseIdentifier => LibationScaffolding.ReleaseIdentifier.ToString() + (File.Exists("/bin/yum") ? "_RPM" : ""); + //only run the auto upgrader if the current app was installed from the //.deb package. Try to detect this by checking if the symlink exists. public bool CanUpgrade => Directory.Exists("/usr/lib/libation"); diff --git a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs index 0cc75660..e7ca21ef 100644 --- a/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs +++ b/Source/LoadByOS/MacOSConfigApp/MacOSInterop.cs @@ -24,6 +24,8 @@ namespace MacOSConfigApp //the running process, so don't upgrade unless it's "installed" in /Applications public bool CanUpgrade => Directory.Exists(AppPath); + public string ReleaseIdentifier => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString(); + public void InstallUpgrade(string upgradeBundle) { Serilog.Log.Information($"Extracting upgrade bundle to {AppPath}"); diff --git a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs index bf8eae77..d99f3cb6 100644 --- a/Source/LoadByOS/WindowsConfigApp/WinInterop.cs +++ b/Source/LoadByOS/WindowsConfigApp/WinInterop.cs @@ -25,6 +25,9 @@ namespace WindowsConfigApp => new DirectoryInfo(directory)?.DeleteIcon(); public bool CanUpgrade => true; + + public string ReleaseIdentifier => AppScaffolding.LibationScaffolding.ReleaseIdentifier.ToString(); + public void InstallUpgrade(string upgradeBundle) { var thisExe = Environment.ProcessPath;