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] %>