// Copyright (C) 2025, The Duplicati Team // https://duplicati.com, hello@duplicati.com // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. using System.Text.RegularExpressions; namespace ReleaseBuilder; /// /// The operating systems we can build for /// public enum OSType { /// /// The Windows OS /// Windows, /// /// The MacOS /// MacOS, /// /// Linux, any variant /// Linux } /// /// The system architecture /// public enum ArchType { /// /// An x86 64-bit architecture /// x64, /// /// An x86 32-bit architecture /// x86, /// /// The ARM-64 architecture /// Arm64, /// /// The ARM v7 architecture /// Arm7 } /// /// The different package types /// public enum PackageType { /// /// The basic ZIP package /// Zip, /// /// The Windows installer format /// MSI, /// /// The debian package format /// Deb, /// /// The Redhat package manager format /// RPM, /// /// Docker build /// Docker, /// /// Apple Disk Image /// DMG, /// /// The MacOS pkg format /// MacPkg, /// /// The synology Spk format /// SynologySpk } /// /// The interface type /// public enum InterfaceType { /// /// The GUI interface /// GUI, /// /// The commandline interface /// Cli, /// /// The agent interface /// Agent } /// /// Mapping of a package target /// /// The operating system /// The CPU architecture /// The interface type /// The installer package public record PackageTarget(OSType OS, ArchType Arch, InterfaceType Interface, PackageType Package) { /// /// Returns a string representation of the OS. /// /// The operating system /// The operating system id-string /// This is using .Net RID: https://learn.microsoft.com/en-us/dotnet/core/rid-catalog private static string OSToString(OSType os) => os switch { OSType.Windows => "win", OSType.Linux => "linux", OSType.MacOS => "osx", _ => throw new Exception("Not supported OS") }; /// /// Returns a string representation of the CPU architecture /// /// The architecture /// The CPU architecture id-string /// This is using .Net RID: https://learn.microsoft.com/en-us/dotnet/core/rid-catalog private static string ArchToString(ArchType arch) => arch switch { ArchType.x64 => "x64", ArchType.x86 => "x86", ArchType.Arm64 => "arm64", ArchType.Arm7 => "arm7", _ => throw new Exception("Not supported arch") }; /// /// Returns a string representation of the package type /// /// The package type /// The package type id-string private static string PackageToString(PackageType package) => package switch { PackageType.Zip => "zip", PackageType.MSI => "msi", PackageType.Deb => "deb", PackageType.RPM => "rpm", PackageType.DMG => "dmg", PackageType.MacPkg => "pkg", PackageType.SynologySpk => "spk", PackageType.Docker => "docker", _ => throw new Exception("Not supported package type") }; /// /// Returns a string representation of the interface type /// /// The interface type /// The interface type id-string private static string InterfaceToString(InterfaceType interfaceType) => interfaceType switch { InterfaceType.GUI => "gui", InterfaceType.Cli => "cli", InterfaceType.Agent => "agent", _ => throw new Exception("Not supported interface type") }; /// /// Gets the RID string for the operating system /// public string OSString => OSToString(OS); /// /// Gets the RID string for the CPU architecture /// public string ArchString => ArchToString(Arch); /// /// Gets the id string for the interface /// public string InterfaceString => InterfaceToString(Interface); /// /// Gets the id string for the package /// public string PackageString => PackageToString(Package); /// /// String map of operating system RIDs /// private static Dictionary OSTypeParse = Enum.GetValues().ToDictionary(OSToString, x => x, StringComparer.OrdinalIgnoreCase); /// /// String map of architecture RIDs /// private static Dictionary ArchTypeParse = Enum.GetValues().ToDictionary(ArchToString, x => x, StringComparer.OrdinalIgnoreCase); /// /// String map of package type ids /// private static Dictionary PackageTypeParse = Enum.GetValues().ToDictionary(PackageToString, x => x, StringComparer.OrdinalIgnoreCase); /// /// String map of interface type ids /// private static Dictionary InterfaceTypeParse = Enum.GetValues().ToDictionary(InterfaceToString, x => x, StringComparer.OrdinalIgnoreCase); /// /// The RID string for .Net build commands /// public string BuildArchString => $"{OSString}-{ArchString}"; /// /// The target string for the builds /// public string BuildTargetString => $"{BuildArchString}-{InterfaceString}"; /// /// The package string for the updater /// public string PackageTargetString => $"{BuildTargetString}.{PackageString}"; /// /// Parses a string representation of a package target /// /// The id to parse /// The matching the string public static PackageTarget ParsePackageId(string id) { var re = Regex.Match(id, @"(?\w+)-(?\w+)-(?\w+)\.(?\w+)"); if (!re.Success) throw new Exception($"Invalid package id: {id}"); if (!OSTypeParse.TryGetValue(re.Groups["os"].Value, out var os)) throw new Exception($"Not supported OS type: {re.Groups["os"].Value}"); if (!ArchTypeParse.TryGetValue(re.Groups["arch"].Value, out var arch)) throw new Exception($"Not supported Arch type: {re.Groups["arch"].Value}"); if (!InterfaceTypeParse.TryGetValue(re.Groups["int"].Value, out var interfaceType)) throw new Exception($"Not supported Interface type: {re.Groups["int"].Value}"); if (!PackageTypeParse.TryGetValue(re.Groups["package"].Value, out var package)) throw new Exception($"Not supported Package type: {re.Groups["package"].Value}"); return new PackageTarget(os, arch, interfaceType, package); } }