diff --git a/lib/fpm/package/srpm.rb b/lib/fpm/package/srpm.rb
new file mode 100644
index 00000000..f7a59c52
--- /dev/null
+++ b/lib/fpm/package/srpm.rb
@@ -0,0 +1,243 @@
+require "fpm/namespace"
+require "fpm/package"
+require "fpm/errors"
+require "fpm/util"
+
+# For handling conversion
+require "fpm/package/cpan"
+
+class FPM::Package::SRPM < FPM::Package
+ def output(output_path)
+ source_archive = ::Dir.glob(build_path("*")).select(&File.method(:file?)).first
+ source_archive_dirname = `tar -ztf #{Shellwords.escape(source_archive)}` \
+ .split("\n").map { |path| path.split("/").first }.uniq.first
+
+ # Generate an rpm spec with Source0: <source_archive>
+ rpmspec = template("srpm.erb").result(binding)
+
+ # Copied from rpm.rb ---
+ %w(BUILD RPMS SRPMS SOURCES SPECS).each { |d| FileUtils.mkdir_p(build_path(d)) }
+ args = ["rpmbuild", "-bs"]
+
+ if %x{uname -m}.chomp != self.architecture
+ rpm_target = self.architecture
+ end
+
+ # issue #309
+ if !attributes[:rpm_os].nil?
+ rpm_target = "#{architecture}-unknown-#{attributes[:rpm_os]}"
+ end
+
+ # issue #707
+ if !rpm_target.nil?
+ args += ["--target", rpm_target]
+ end
+
+ # set the rpm dist tag
+ args += ["--define", "dist .#{attributes[:rpm_dist]}"] if attributes[:rpm_dist]
+
+ args += [
+ "--define", "buildroot #{build_path}/BUILD",
+ "--define", "_topdir #{build_path}",
+ "--define", "_sourcedir #{build_path}",
+ "--define", "_rpmdir #{build_path}/RPMS",
+ "--define", "_tmppath #{attributes[:workdir]}"
+ ]
+
+ args += ["--sign"] if attributes[:rpm_sign?]
+
+ if attributes[:rpm_auto_add_directories?]
+ fs_dirs_list = File.join(template_dir, "rpm", "filesystem_list")
+ fs_dirs = File.readlines(fs_dirs_list).reject { |x| x =~ /^\s*#/}.map { |x| x.chomp }
+ fs_dirs.concat((attributes[:auto_add_exclude_directories] or []))
+
+ Find.find(staging_path) do |path|
+ next if path == staging_path
+ if File.directory? path and !File.symlink? path
+ add_path = path.gsub(/^#{staging_path}/,'')
+ self.directories << add_path if not fs_dirs.include? add_path
+ end
+ end
+ else
+ self.directories = self.directories.map { |x| self.prefixed_path(x) }
+ alldirs = []
+ self.directories.each do |path|
+ Find.find(File.join(staging_path, path)) do |subpath|
+ if File.directory? subpath and !File.symlink? subpath
+ alldirs << subpath.gsub(/^#{staging_path}/, '')
+ end
+ end
+ end
+ self.directories = alldirs
+ end
+
+ # include external config files
+ (attributes[:config_files] or []).each do |conf|
+ dest_conf = File.join(staging_path, conf)
+
+ if File.exist?(dest_conf)
+ logger.debug("Using --config-file from staging area", :path => conf)
+ elsif File.exist?(conf)
+ logger.info("Copying --config-file from local path", :path => conf)
+ FileUtils.mkdir_p(File.dirname(dest_conf))
+ FileUtils.cp_r conf, dest_conf
+ else
+ logger.error("Failed to find given --config-file", :path => conf)
+ raise "Could not find config file '#{conf}' in staging area or on host. This can happen if you specify `--config-file '#{conf}'` but this file does not exist in the source package and also does not exist in filesystem."
+ end
+ end
+
+ # scan all conf file paths for files and add them
+ allconfigs = []
+ self.config_files.each do |path|
+ cfg_path = File.join(staging_path, path)
+ raise "Config file path #{cfg_path} does not exist" unless File.exist?(cfg_path)
+ Find.find(cfg_path) do |p|
+ allconfigs << p.gsub("#{staging_path}/", '') if File.file? p
+ end
+ end
+ allconfigs.sort!.uniq!
+
+ self.config_files = allconfigs.map { |x| File.join("/", x) }
+
+ # add init script if present
+ (attributes[:rpm_init_list] or []).each do |init|
+ name = File.basename(init, ".init")
+ dest_init = File.join(staging_path, "etc/init.d/#{name}")
+ FileUtils.mkdir_p(File.dirname(dest_init))
+ FileUtils.cp init, dest_init
+ File.chmod(0755, dest_init)
+ end
+
+ (attributes[:rpm_rpmbuild_define] or []).each do |define|
+ args += ["--define", define]
+ end
+
+ # copy all files from staging to BUILD dir
+ # [#1538] Be sure to preserve the original timestamps.
+ Find.find(staging_path) do |path|
+ src = path.gsub(/^#{staging_path}/, '')
+ dst = File.join(build_path, "BUILD", src)
+ copy_entry(path, dst, preserve=true)
+ end
+
+ specfile = File.join(build_path("SPECS"), "#{name}.spec")
+ File.write(specfile, rpmspec)
+
+ edit_file(specfile) if attributes[:edit?]
+
+ args << specfile
+
+ logger.info("Running rpmbuild", :args => args)
+ safesystem(*args)
+
+ ::Dir["#{build_path}/SRPMS/**/*.rpm"].each do |rpmpath|
+ # This should only output one rpm, should we verify this?
+ FileUtils.cp(rpmpath, output_path)
+ end
+ end
+
+ def converted_from(origin)
+ if origin == FPM::Package::CPAN
+ # Fun hack to find the instance of the origin class
+ # So we can find the build_path
+ input = nil
+ ObjectSpace.each_object { |x| input = x if x.is_a?(origin) }
+ if input.nil?
+ raise "Something bad happened. Couldn't find origin package in memory? This is a bug."
+ end
+
+ # Pick the first file found, should be a tarball.
+ source_archive = ::Dir.glob(File.join(input.build_path, "*")).select(&File.method(:file?)).first
+ #FileUtils.copy_entry(source_archive, build_path)
+ File.link(source_archive, build_path(File.basename(source_archive)))
+ #FileUtils.copy_entry(source_archive, build_path)
+ end
+ end
+
+ def summary
+ if !attributes[:rpm_summary]
+ return @description.split("\n").find { |line| !line.strip.empty? } || "_"
+ end
+
+ return attributes[:rpm_summary]
+ end # def summary
+
+ def prefix
+ if attributes[:prefix] and attributes[:prefix] != '/'
+ return attributes[:prefix].chomp('/')
+ else
+ return "/"
+ end
+ end # def prefix
+
+ def to_s(format=nil)
+ if format.nil?
+ format = if attributes[:rpm_dist]
+ "NAME-VERSION-ITERATION.DIST.src.rpm"
+ else
+ "NAME-VERSION-ITERATION.src.rpm"
+ end
+ end
+ return super(format.gsub("DIST", to_s_dist))
+ end # def to_s
+
+ def to_s_dist
+ attributes[:rpm_dist] ? "#{attributes[:rpm_dist]}" : "DIST";
+ end
+
+ # This method ensures a default value for iteration if none is provided.
+ def iteration
+ if @iteration.kind_of?(String) and @iteration.include?("-")
+ logger.warn("Package iteration '#{@iteration}' includes dashes, converting" \
+ " to underscores. rpmbuild does not allow the dashes in the package iteration (called 'Release' in rpm)")
+ @iteration = @iteration.gsub(/-/, "_")
+ end
+
+ return @iteration ? @iteration : 1
+ end # def iteration
+
+ def version
+ if @version.kind_of?(String) and @version.include?("-")
+ logger.warn("Package version '#{@version}' includes dashes, converting" \
+ " to underscores")
+ @version = @version.gsub(/-/, "_")
+ end
+
+ return @version
+ end
+
+ # The default epoch value must be nil, see #381
+ def epoch
+ return @epoch if @epoch.is_a?(Numeric)
+
+ if @epoch.nil? or @epoch.empty?
+ return nil
+ end
+
+ return @epoch
+ end # def epoch
+
+ # Handle any architecture naming conversions.
+ # For example, debian calls amd64 what redhat calls x86_64, this
+ # method fixes those types of things.
+ def architecture
+ case @architecture
+ when nil
+ return %x{uname -m}.chomp # default to current arch
+ when "amd64" # debian and redhat disagree on architecture names
+ return "x86_64"
+ when "arm64" # debian and redhat disagree on architecture names
+ return "aarch64"
+ when "native"
+ return %x{uname -m}.chomp # 'native' is current arch
+ when "all"
+ # Translate fpm "all" arch to what it means in RPM.
+ return "noarch"
+ else
+ return @architecture
+ end
+ end # def architecture
+
+ public(:output)
+end # class FPM::Target::Deb
diff --git a/templates/srpm.erb b/templates/srpm.erb
new file mode 100644
index 00000000..a7e7209d
--- /dev/null
+++ b/templates/srpm.erb
@@ -0,0 +1,233 @@
+# Hello packaging friend!
+
+# Allow building noarch packages that contain binaries
+%define _binaries_in_noarch_packages_terminate_build 0
+
+<% (attributes[:rpm_filter_from_requires] or []).each do |reqfilter| -%>
+%filter_from_requires <%= reqfilter %>
+<% end -%>
+<% (attributes[:rpm_filter_from_provides] or []).each do |provfilter| -%>
+%filter_from_provides <%= provfilter %>
+<% end -%>
+<% if !(attributes[:rpm_filter_from_requires] or []).empty? or !(attributes[:rpm_filter_from_provides] or []).empty?-%>
+%filter_setup
+<% end -%>
+
+Name: <%= name %>
+Version: <%= version %>
+<% if epoch -%>
+Epoch: <%= epoch %>
+<% end -%>
+Release: <%= iteration or 1 %><%= "%{?dist}" if attributes[:rpm_dist] %>
+<%# use the first line of the description as the summary -%>
+Summary: <%= summary %>
+<% if !attributes[:rpm_autoreqprov?] -%>
+AutoReqProv: no
+<% else -%>
+AutoReqProv: yes
+<% end -%>
+<% if attributes[:rpm_autoreq?] -%>
+AutoReq: yes
+<% end -%>
+<% if attributes[:rpm_autoprov?] -%>
+AutoProv: yes
+<% end -%>
+# Seems specifying BuildRoot is required on older rpmbuild (like on CentOS 5)
+# fpm passes '--define buildroot ...' on the commandline, so just reuse that.
+BuildRoot: %buildroot
+<% if !prefix.nil? and !prefix.empty? %>
+Prefix: <%= prefix %>
+<% end -%>
+
+Group: <%= category %>
+<%# Sometimes the 'license' field has multiple lines... Hack around it.
+ # While technically yes this means we are 'modifying' the license,
+ # since the job of FPM is to get shit done and that this is only
+ # modifying whitespace, it should be reasonably OK. -%>
+License: <%= license.gsub("\n", " ") %>
+<% if !vendor.nil? and !vendor.empty? -%>
+Vendor: <%= vendor %>
+<% end -%>
+<% if !url.nil? and !url.empty? -%>
+URL: <%= url %>
+<%else -%>
+URL: http://nourlgiven.example.com/
+<% end -%>
+Packager: <%= maintainer %>
+
+Source0: <%= source_archive %>
+
+<% if !attributes[:no_depends?] -%>
+<% dependencies.each do |req| -%>
+Requires: <%= req %>
+<% end -%>
+<% (attributes[:rpm_tag] or []).each do |tag| -%>
+<%= tag %>
+<% end -%>
+<% end -%>
+<% provides.each do |prov| -%>
+Provides: <%= prov %>
+<% end -%>
+<% conflicts.each do |conflict| -%>
+Conflicts: <%= conflict %>
+<% end -%>
+<% replaces.each do |repl| -%>
+<%# The closes equivalent in RPM to "replaces" is "Obsoletes" -%>
+Obsoletes: <%= repl %>
+<% end -%>
+<%# rpm rejects descriptions with blank lines (even between content), so hack
+ around it by replacing blank lines with ' .' -%>
+%description
+<%= description.gsub(/^\s*$/, " .") %>
+
+%prep
+%autosetup -n <%= source_archive_dirname %>
+
+%build
+mkdir -p ./cpan
+cpanm -L ./cpan . --installdeps
+
+perl Makefile.PL
+make
+
+%install
+%make_install
+
+<%# This next section puts any %pre, %post, %preun, %postun, %verifyscript, %pretrans or %posttrans scripts %>
+<%
+ scriptmap = {
+ :rpm_verifyscript => "verifyscript",
+ :rpm_posttrans => "posttrans",
+ :rpm_pretrans => "pretrans"
+ }
+-%>
+<% if script?(:before_upgrade) or script?(:after_upgrade) -%>
+<% if script?(:before_upgrade) or script?(:before_install) -%>
+%pre <% if attributes[:rpm_macro_expansion?] -%><%= " -e " %> <% end %>
+upgrade() {
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<% if script?(:before_upgrade) -%>
+<%= script(:before_upgrade) %>
+<% end -%>
+}
+_install() {
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<% if script?(:before_install) -%>
+<%= script(:before_install) %>
+<% end -%>
+}
+if [ "${1}" -eq 1 ]
+then
+ # "before install" goes here
+ _install
+elif [ "${1}" -gt 1 ]
+then
+ # "before upgrade" goes here
+ upgrade
+fi
+<% end -%>
+<% if script?(:after_upgrade) or script?(:after_install) -%>
+%post <% if attributes[:rpm_macro_expansion?] -%><%= " -e " %> <% end %>
+upgrade() {
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<% if script?(:after_upgrade) -%>
+<%= script(:after_upgrade) %>
+<% end -%>
+}
+_install() {
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<% if script?(:after_install) -%>
+<%= script(:after_install) %>
+<% end -%>
+}
+if [ "${1}" -eq 1 ]
+then
+ # "after install" goes here
+ _install
+elif [ "${1}" -gt 1 ]
+then
+ # "after upgrade" goes here
+ upgrade
+fi
+<% end -%>
+<% if script?(:before_remove) -%>
+%preun <% if attributes[:rpm_macro_expansion?] -%><%= " -e " %> <% end %>
+if [ "${1}" -eq 0 ]
+then
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<%= script(:before_remove) %>
+fi
+<% end -%>
+<% if script?(:after_remove) -%>
+%postun <% if attributes[:rpm_macro_expansion?] -%><%= " -e " %> <% end %>
+if [ "${1}" -eq 0 ]
+then
+<%# Making sure that at least one command is in the function -%>
+<%# avoids a lot of potential errors, including the case that -%>
+<%# the script is non-empty, but just whitespace and/or comments -%>
+ :
+<%= script(:after_remove) %>
+fi
+<% end -%>
+<% else
+ other_scriptmap = {
+ :before_install => "pre",
+ :after_install => "post",
+ :before_remove => "preun",
+ :after_remove => "postun"
+ }
+ scriptmap.merge!(other_scriptmap)
+ end
+-%>
+<% scriptmap.each do |name, rpmname| -%>
+<% if script?(name) -%>
+%<%= rpmname -%> <%= ' -e' if attributes[:rpm_macro_expansion?] %>
+<%= script(name) %>
+<% end -%>
+<% end -%>
+
+<%# This section adds any triggers, as ordered in the command line -%>
+<%
+ triggermap = {
+ :before_install => "prein",
+ :after_install => "in",
+ :before_uninstall => "un",
+ :after_target_uninstall => "postun"
+ }
+ triggermap.each do |name, rpmtype|
+ (attributes["rpm_trigger_#{name}".to_sym] or []).each do |trigger_name, trigger_script, trigger_scriptprog| -%>
+%trigger<%= rpmtype -%> <%= trigger_scriptprog -%> -- <%= trigger_name %>
+<%= trigger_script %>
+<% end -%>
+<% end -%>
+
+%files
+%defattr(<%= attributes[:rpm_defattrfile] %>,<%= attributes[:rpm_user] || "root" %>,<%= attributes[:rpm_group] || "root" %>,<%= attributes[:rpm_defattrdir] %>)
+<%# Output config files and then regular files. -%>
+<% config_files.each do |path| -%>
+%config(noreplace) <%= rpm_file_entry(path) %>
+<% end -%>
+<%# list directories %>
+<% directories.each do |path| -%>
+%dir <%= rpm_file_entry(path) %>
+<% end -%>
+<%# list only files, not directories? -%>
+/
+
+%changelog
+<%= attributes[:rpm_changelog] %>