diff --git a/PupNet/Builders/AppImageBuilder.cs b/PupNet/Builders/AppImageBuilder.cs
index 71b8a58..18d1f9a 100644
--- a/PupNet/Builders/AppImageBuilder.cs
+++ b/PupNet/Builders/AppImageBuilder.cs
@@ -157,6 +157,11 @@ public override string? MetaBuildPath
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ yield break;
+ }
+
///
/// Implements.
///
diff --git a/PupNet/Builders/DebianBuilder.cs b/PupNet/Builders/DebianBuilder.cs
index 34772da..d297cd7 100644
--- a/PupNet/Builders/DebianBuilder.cs
+++ b/PupNet/Builders/DebianBuilder.cs
@@ -53,6 +53,34 @@ public DebianBuilder(ConfigurationReader conf)
var archiveDirectory = Path.Combine(OutputDirectory, OutputName);
cmd += $"--build \"{BuildRoot}\" \"{archiveDirectory}\"";
list.Add(cmd);
+
+ var extraPaths = new List();
+ if (Configuration.DebianPreInst.Count != 0)
+ {
+ extraPaths.Add(Path.Combine(BuildRoot, "DEBIAN/preinst"));
+ }
+
+ if (Configuration.DebianPostInst.Count != 0)
+ {
+ extraPaths.Add(Path.Combine(BuildRoot, "DEBIAN/postinst"));
+ }
+
+ if (Configuration.DebianPreRm.Count != 0)
+ {
+ extraPaths.Add(Path.Combine(BuildRoot, "DEBIAN/prerm"));
+ }
+
+ if (Configuration.DebianPostRm.Count != 0)
+ {
+ extraPaths.Add(Path.Combine(BuildRoot, "DEBIAN/postrm"));
+ }
+
+ if (extraPaths.Count > 0)
+ {
+ // set permission must be set before build command
+ list.Insert(0, $"chmod +x {string.Join(' ', extraPaths)}");
+ }
+
PackageCommands = list;
}
@@ -124,6 +152,53 @@ public override string Architecture
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ if (Configuration.DebianPreInst.Count != 0)
+ {
+ var sb = new StringBuilder();
+ foreach (var item in Configuration.DebianPreInst)
+ {
+ sb.AppendLine(item);
+ }
+
+ yield return (Path.Combine(BuildRoot, "DEBIAN/preinst"), sb.ToString());
+ }
+
+ if (Configuration.DebianPostInst.Count != 0)
+ {
+ var sb = new StringBuilder();
+ foreach (var item in Configuration.DebianPostInst)
+ {
+ sb.AppendLine(item);
+ }
+
+ yield return (Path.Combine(BuildRoot, "DEBIAN/postinst"), sb.ToString());
+ }
+
+ if (Configuration.DebianPreRm.Count != 0)
+ {
+ var sb = new StringBuilder();
+ foreach (var item in Configuration.DebianPreRm)
+ {
+ sb.AppendLine(item);
+ }
+
+ yield return (Path.Combine(BuildRoot, "DEBIAN/prerm"), sb.ToString());
+ }
+
+ if (Configuration.DebianPostRm.Count != 0)
+ {
+ var sb = new StringBuilder();
+ foreach (var item in Configuration.DebianPostRm)
+ {
+ sb.AppendLine(item);
+ }
+
+ yield return (Path.Combine(BuildRoot, "DEBIAN/postrm"), sb.ToString());
+ }
+ }
+
///
/// Implements.
///
diff --git a/PupNet/Builders/FlatpakBuilder.cs b/PupNet/Builders/FlatpakBuilder.cs
index d8e5f79..a206d67 100644
--- a/PupNet/Builders/FlatpakBuilder.cs
+++ b/PupNet/Builders/FlatpakBuilder.cs
@@ -120,6 +120,11 @@ public override string OutputName
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ yield break;
+ }
+
///
/// Implements.
///
diff --git a/PupNet/Builders/RpmBuilder.cs b/PupNet/Builders/RpmBuilder.cs
index ec837d4..731aee8 100644
--- a/PupNet/Builders/RpmBuilder.cs
+++ b/PupNet/Builders/RpmBuilder.cs
@@ -141,6 +141,11 @@ public override string Architecture
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ yield break;
+ }
+
///
/// Implements.
///
@@ -272,6 +277,11 @@ private string GetSpec()
sb.AppendLine($"License: {Configuration.AppLicenseId}");
sb.AppendLine($"Vendor: {Configuration.PublisherName}");
+ if (!string.IsNullOrEmpty(Configuration.RpmGroup))
+ {
+ sb.AppendLine($"Group: {Configuration.RpmGroup}");
+ }
+
if (!string.IsNullOrEmpty(Configuration.PublisherLinkUrl))
{
sb.AppendLine($"Url: {Configuration.PublisherLinkUrl}");
@@ -338,6 +348,50 @@ private string GetSpec()
}
*/
+ if (Configuration.RpmPre.Count != 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine("%pre");
+
+ foreach (var item in Configuration.RpmPre)
+ {
+ sb.AppendLine(item);
+ }
+ }
+
+ if (Configuration.RpmPost.Count != 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine("%post");
+
+ foreach (var item in Configuration.RpmPost)
+ {
+ sb.AppendLine(item);
+ }
+ }
+
+ if (Configuration.RpmPreUn.Count != 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine("%preun");
+
+ foreach (var item in Configuration.RpmPreUn)
+ {
+ sb.AppendLine(item);
+ }
+ }
+
+ if (Configuration.RpmPostUn.Count != 0)
+ {
+ sb.AppendLine();
+ sb.AppendLine("%postun");
+
+ foreach (var item in Configuration.RpmPostUn)
+ {
+ sb.AppendLine(item);
+ }
+ }
+
// https://stackoverflow.com/questions/57385249/in-an-rpm-files-section-is-it-possible-to-specify-a-directory-and-all-of-its-fi
sb.AppendLine();
sb.AppendLine("%files");
diff --git a/PupNet/Builders/SetupBuilder.cs b/PupNet/Builders/SetupBuilder.cs
index 78ba05e..4adbe89 100644
--- a/PupNet/Builders/SetupBuilder.cs
+++ b/PupNet/Builders/SetupBuilder.cs
@@ -93,6 +93,11 @@ public override string Architecture
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ yield break;
+ }
+
///
/// Implements.
///
diff --git a/PupNet/Builders/ZipBuilder.cs b/PupNet/Builders/ZipBuilder.cs
index b401c59..f43907b 100644
--- a/PupNet/Builders/ZipBuilder.cs
+++ b/PupNet/Builders/ZipBuilder.cs
@@ -79,6 +79,11 @@ public override string OutputName
///
public override string? ManifestBuildPath { get; }
+ public override IEnumerable<(string Path, string Content)> GetExtraContents()
+ {
+ yield break;
+ }
+
///
/// Implements.
///
diff --git a/PupNet/ConfigurationReader.cs b/PupNet/ConfigurationReader.cs
index e053b23..b7a55ef 100644
--- a/PupNet/ConfigurationReader.cs
+++ b/PupNet/ConfigurationReader.cs
@@ -167,9 +167,18 @@ private ConfigurationReader(ArgumentReader args, IniReader reader, bool assertPa
RpmAutoReq = GetBool(nameof(RpmAutoReq), RpmAutoReq);
RpmAutoProv = GetBool(nameof(RpmAutoProv), RpmAutoProv);
+ RpmGroup = GetOptional(nameof(RpmGroup), ValueFlags.None);
+ RpmPre = GetCollection(nameof(RpmPre), ValueFlags.MultiText);
+ RpmPost = GetCollection(nameof(RpmPost), ValueFlags.MultiText);
+ RpmPreUn = GetCollection(nameof(RpmPreUn), ValueFlags.MultiText);
+ RpmPostUn = GetCollection(nameof(RpmPostUn), ValueFlags.MultiText);
RpmRequires = GetCollection(nameof(RpmRequires), RpmRequires, ValueFlags.SafeNoSpace);
DebianRecommends = GetCollection(nameof(DebianRecommends), DebianRecommends, ValueFlags.SafeNoSpace);
+ DebianPreInst = GetCollection(nameof(DebianPreInst), DebianPreInst, ValueFlags.MultiText);
+ DebianPostInst = GetCollection(nameof(DebianPostInst), DebianPostInst, ValueFlags.MultiText);
+ DebianPreRm = GetCollection(nameof(DebianPreRm), DebianPreRm, ValueFlags.MultiText);
+ DebianPostRm = GetCollection(nameof(DebianPostRm), DebianPostRm, ValueFlags.MultiText);
FlatpakPlatformRuntime = GetMandatory(nameof(FlatpakPlatformRuntime), ValueFlags.StrictSafe);
FlatpakPlatformSdk = GetMandatory(nameof(FlatpakPlatformSdk), ValueFlags.StrictSafe);
@@ -270,11 +279,23 @@ private enum ValueFlags
public bool RpmAutoReq { get; } = false;
public bool RpmAutoProv { get; } = true;
+ public string? RpmGroup { get; }
+
+ public IReadOnlyCollection RpmPre { get; } = Array.Empty();
+ public IReadOnlyCollection RpmPost { get; } = Array.Empty();
+ public IReadOnlyCollection RpmPreUn { get; } = Array.Empty();
+ public IReadOnlyCollection RpmPostUn { get; } = Array.Empty();
+
public IReadOnlyCollection RpmRequires { get; } = new string[]
{ "krb5-libs", "libicu", "openssl-libs", "zlib" };
public IReadOnlyCollection DebianRecommends { get; } = new string[]
{ "libc6", "libgcc1", "libgcc-s1", "libgssapi-krb5-2", "libicu", "libssl", "libstdc++6", "libunwind", "zlib1g" };
+
+ public IReadOnlyCollection DebianPreInst { get; } = Array.Empty();
+ public IReadOnlyCollection DebianPostInst { get; } = Array.Empty();
+ public IReadOnlyCollection DebianPreRm { get; } = Array.Empty();
+ public IReadOnlyCollection DebianPostRm { get; } = Array.Empty();
public string? SetupGroupName { get; }
public bool SetupAdminInstall { get; }
@@ -582,6 +603,22 @@ public string ToString(DocStyles style)
$"Boolean (true or false) which specifies whether to build the RPM package with 'AutoProv' equal to yes or no.",
$"Refer: https://rpm-software-management.github.io/rpm/manual/spec.html"));
+ sb.Append(CreateHelpField(nameof(RpmGroup), RpmGroup, style,
+ $"The specified group must be in the list of groups known to RPM. This list is located in the file /usr/lib/rpm/GROUPS",
+ $"which is part of the rpm package."));
+
+ sb.Append(CreateHelpField(nameof(RpmPre), RpmPre, true, style,
+ "The script is executed before the package is installed into the system."));
+
+ sb.Append(CreateHelpField(nameof(RpmPost), RpmPost, true, style,
+ "The script is executed after the package is installed into the system."));
+
+ sb.Append(CreateHelpField(nameof(RpmPreUn), RpmPreUn, true, style,
+ "The script is executed before the package is removed from the system."));
+
+ sb.Append(CreateHelpField(nameof(RpmPostUn), RpmPostUn, true, style,
+ "The script is executed after the package is removed from the system."));
+
sb.Append(CreateHelpField(nameof(RpmRequires), RpmRequires, true, style,
$"Optional list of RPM dependencies. The list may include multiple values separated with semicolon or given",
$"in multi-line form. If empty, a self-contained dotnet package will successfully run on many (but not all)",
@@ -589,10 +626,8 @@ public string ToString(DocStyles style)
$"Default values are recommended for use with dotnet and RPM packages at the time of writing.",
$"For updated information, see: https://learn.microsoft.com/en-us/dotnet/core/install/linux-rhel#dependencies"));
-
-
sb.Append(CreateBreaker("DEBIAN OPTIONS", style));
-
+
sb.Append(CreateHelpField(nameof(DebianRecommends), DebianRecommends, true, style,
$"Optional list of Debian dependencies. The list may include multiple values separated with semicolon or given",
$"in multi-line form. If empty, a self-contained dotnet package will successfully run on many (but not all)",
@@ -600,7 +635,17 @@ public string ToString(DocStyles style)
$"Default values are recommended for use with dotnet and Debian packages at the time of writing.",
$"For updated information, see: https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu#dependencies"));
-
+ sb.Append(CreateHelpField(nameof(DebianPreInst), DebianPreInst, true, style,
+ "The script is executed before the package is installed into the system."));
+
+ sb.Append(CreateHelpField(nameof(DebianPostInst), DebianPostInst, true, style,
+ "The script is executed after the package is installed into the system."));
+
+ sb.Append(CreateHelpField(nameof(DebianPreRm), DebianPreRm, true, style,
+ "The script is executed before the package is removed from the system."));
+
+ sb.Append(CreateHelpField(nameof(DebianPostRm), DebianPostRm, true, style,
+ "The script is executed after the package is removed from the system."));
sb.Append(CreateBreaker("WINDOWS SETUP OPTIONS", style));
diff --git a/PupNet/PackageBuilder.cs b/PupNet/PackageBuilder.cs
index 666e034..f447cda 100644
--- a/PupNet/PackageBuilder.cs
+++ b/PupNet/PackageBuilder.cs
@@ -396,6 +396,8 @@ public string InstallExec
///
public abstract string? ManifestBuildPath { get; }
+ public abstract IEnumerable<(string Path, string Content)> GetExtraContents();
+
///
/// Gets the destination path of the LICENSE file in the build directory. This will cause
/// to be copied into .
@@ -579,6 +581,11 @@ public virtual void BuildPackage()
// may change after Create() and dotnet publish in some deployments.
Operations.WriteFile(ManifestBuildPath, ManifestContent);
+ foreach (var extraContent in GetExtraContents())
+ {
+ Operations.WriteFile(extraContent.Path, extraContent.Content);
+ }
+
Operations.Execute(PackageCommands);
}