diff --git a/lib/fpm/package/deb.rb b/lib/fpm/package/deb.rb index a29d1948ed..c996bfcb10 100644 --- a/lib/fpm/package/deb.rb +++ b/lib/fpm/package/deb.rb @@ -79,6 +79,19 @@ class FPM::Package::Deb < FPM::Package value end + option "--compression-level", "[0-9]", "Select a compression level. 0 is none or minimal. 9 is max compression.", + # Specify which compression level to use on the compressor backend, when building a package + :default => nil do |value| + valint = value.to_i + # if self.attributes[:deb_compression].nil? + # raise "Can't specify a compression level with compression disabled" + # end + unless value =~ /^\d$/ && valint >= 0 && valint <= 9 + raise "Invalid compression level '#{value}'. Valid values are integers between 0 and 9 inclusive." + end + valint + end + option "--dist", "DIST-TAG", "Set the deb distribution.", :default => "unstable" # Take care about the case when we want custom control file but still use fpm ... @@ -210,6 +223,11 @@ class FPM::Package::Deb < FPM::Package next File.expand_path(file) end + option "--systemd-path", "FILEPATH", "Relative path to the systemd service directory", + :default => "lib/systemd/system" do |file| + next file.gsub(/^\/*/, '') + end + option "--systemd-enable", :flag , "Enable service on install or upgrade", :default => false option "--systemd-auto-start", :flag , "Start service after install or upgrade", :default => false @@ -534,7 +552,7 @@ def output(output_path) raise FPM::InvalidPackageConfiguration, "Invalid systemd unit file extension: #{extname}. Expected .service or .timer, or no extension." end - dest_systemd = staging_path("lib/systemd/system/#{name_with_extension}") + dest_systemd = staging_path(File.join(attributes[:deb_systemd_path], "#{name_with_extension}")) mkdir_p(File.dirname(dest_systemd)) FileUtils.cp(systemd, dest_systemd) File.chmod(0644, dest_systemd) @@ -646,7 +664,8 @@ def output(output_path) extname = File.extname(systemd) name_with_extension = extname.empty? ? "#{name}.service" : name - dest_systemd = staging_path("lib/systemd/system/#{name_with_extension}") + dest_systemd = staging_path(File.join(attributes[:deb_systemd_path], "#{name_with_extension}")) + mkdir_p(File.dirname(dest_systemd)) FileUtils.cp(systemd, dest_systemd) File.chmod(0644, dest_systemd) @@ -660,22 +679,29 @@ def output(output_path) datatar = build_path("data.tar.gz") controltar = build_path("control.tar.gz") compression_flags = ["-z"] + # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date + compressor_options = {"GZIP" => "-#{self.attributes[:deb_compression_level] || 9}" + + "#{'n' if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?}"} when "bzip2" datatar = build_path("data.tar.bz2") controltar = build_path("control.tar.gz") compression_flags = ["-j"] + compressor_options = {"BZIP" => "-#{self.attributes[:deb_compression_level] || 9}"} when "xz" datatar = build_path("data.tar.xz") controltar = build_path("control.tar.xz") compression_flags = ["-J"] + compressor_options = {"XZ_OPT" => "-#{self.attributes[:deb_compression_level] || 3}"} when "zst" datatar = build_path("data.tar.zst") controltar = build_path("control.tar.zst") compression_flags = ["-I zstd"] + compressor_options = {"ZSTD_CLEVEL" => "-#{self.attributes[:deb_compression_level] || 3}"} when "none" datatar = build_path("data.tar") controltar = build_path("control.tar") compression_flags = [] + compressor_options = {} else raise FPM::InvalidPackageConfiguration, "Unknown compression type '#{self.attributes[:deb_compression]}'" @@ -684,9 +710,8 @@ def output(output_path) if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil? # Use gnu tar options to force deterministic file order and timestamp args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])] - # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date - args.unshift({"GZIP" => "-9n"}) end + args.unshift(compressor_options) safesystem(*args) # pack up the .deb, which is just an 'ar' archive with 3 files @@ -956,15 +981,21 @@ def write_control_tarball when "gz", "bzip2", nil controltar = "control.tar.gz" compression_flags = ["-z"] + # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date + compressor_options = {"GZIP" => "-#{self.attributes[:deb_compression_level] || 9}" + + "#{'n' if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil?}"} when "xz" controltar = "control.tar.xz" compression_flags = ["-J"] + compressor_options = {"XZ_OPT" => "-#{self.attributes[:deb_compression_level] || 3}"} when "zst" controltar = "control.tar.zst" compression_flags = ["-I zstd"] + compressor_options = {"ZSTD_CLEVEL" => "-#{self.attributes[:deb_compression_level] || 3}"} when "none" controltar = "control.tar" compression_flags = [] + compressor_options = {} else raise FPM::InvalidPackageConfiguration, "Unknown compression type '#{self.attributes[:deb_compression]}'" @@ -979,9 +1010,8 @@ def write_control_tarball if tar_cmd_supports_sort_names_and_set_mtime? and not attributes[:source_date_epoch].nil? # Force deterministic file order and timestamp args += ["--sort=name", ("--mtime=@%s" % attributes[:source_date_epoch])] - # gnu tar obeys GZIP environment variable with options for gzip; -n = forget original filename and date - args.unshift({"GZIP" => "-9n"}) end + args.unshift(compressor_options) safesystem(*args) end diff --git a/lib/fpm/package/python.rb b/lib/fpm/package/python.rb index 5754a053d4..9808f5fd31 100644 --- a/lib/fpm/package/python.rb +++ b/lib/fpm/package/python.rb @@ -79,7 +79,7 @@ class FPM::Package::Python < FPM::Package option "--setup-py-arguments", "setup_py_argument", "Arbitrary argument(s) to be passed to setup.py", :multivalued => true, :attribute_name => :python_setup_py_arguments, - :default => [] + :default => [] option "--internal-pip", :flag, "Use the pip module within python to install modules - aka 'python -m pip'. This is the recommended usage since Python 3.4 (2014) instead of invoking the 'pip' script", :attribute_name => :python_internal_pip, @@ -171,13 +171,19 @@ def download_if_necessary(package, version=nil) # behind a directory with the Python package extracted and ready to be used. # For example, `pip download ... Django` puts `Django-4.0.4.tar.tz` into the build_path directory. # If we expect `pip` to leave an unknown-named file in the `build_path` directory, let's check for - # a single file and unpack it. I don't know if it will /always/ be a .tar.gz though. - files = ::Dir.glob(File.join(build_path, "*.tar.gz")) + # a single file and unpack it. + files = ::Dir.glob(File.join(build_path, "*.{tar.gz,zip}")) if files.length != 1 raise "Unexpected directory layout after `pip download ...`. This might be an fpm bug? The directory is #{build_path}" end - safesystem("tar", "-zxf", files[0], "-C", target) + if files[0].end_with?("tar.gz") + safesystem("tar", "-zxf", files[0], "-C", target) + elsif files[0].end_with?("zip") + safesystem("unzip", files[0], "-d", target) + else + raise "Unexpected file format after `pip download ...`. This might be an fpm bug? The file is #{files[0]}" + end else # no pip, use easy_install logger.debug("no pip, defaulting to easy_install", :easy_install => attributes[:python_easyinstall]) @@ -230,7 +236,7 @@ def load_package_info(setup_py) output = ::Dir.chdir(setup_dir) do tmp = build_path("metadata.json") - setup_cmd = "env PYTHONPATH=#{pylib}:$PYTHONPATH #{attributes[:python_bin]} " \ + setup_cmd = "env PYTHONPATH=#{pylib.shellescape}:$PYTHONPATH #{attributes[:python_bin]} " \ "setup.py --command-packages=pyfpm get_metadata --output=#{tmp}" if attributes[:python_obey_requirements_txt?] diff --git a/lib/fpm/package/rpm.rb b/lib/fpm/package/rpm.rb index 861568bc06..79069e651e 100644 --- a/lib/fpm/package/rpm.rb +++ b/lib/fpm/package/rpm.rb @@ -275,6 +275,24 @@ def iteration return @iteration ? @iteration : 1 end # def iteration + # Generate a generic changelog or return an existing definition + def changelog + if attributes[:rpm_changelog] + return attributes[:rpm_changelog] + end + + reldate = if attributes[:source_date_epoch].nil? + Time.now() + else + Time.at(attributes[:source_date_epoch].to_i) + end + changed = reldate.strftime("%a %b %_e %Y") + changev = "#{version}-#{iteration}" + changev += "%{?dist}" if attributes[:rpm_dist] + + "* #{changed} #{maintainer} - #{changev}\n- Package created with FPM\n" + end + # See FPM::Package#converted_from def converted_from(origin) if origin == FPM::Package::Gem diff --git a/spec/fpm/package/rpm_spec.rb b/spec/fpm/package/rpm_spec.rb index 77d62abc9d..015a801f4a 100644 --- a/spec/fpm/package/rpm_spec.rb +++ b/spec/fpm/package/rpm_spec.rb @@ -484,6 +484,45 @@ def subject.render_template; @rpmspec = template("rpm.erb").result(binding); end File.unlink(@target) end end # dist + + context "changelog" do + it "should generate a changelog in the release" do + subject.name = "example" + subject.attributes[:rpm_dist] = 'rhel' + subject.version = "1.2.3" + subject.maintainer = "Spec Test " + @target = Stud::Temporary.pathname + + # Write RPM + subject.output(@target) + + @rpm = ::RPM::File.new(@target) + insist { @rpm.tags[:changelogname] } == [ "Spec Test - 1.2.3-1.rhel" ] + insist { @rpm.tags[:changelogtext] } == [ "- Package created with FPM" ] + + File.unlink(@target) + end + + it "should have the changelog in the release" do + subject.name = "example" + subject.attributes[:rpm_changelog] = < - 1.0-1 +- First example package +CHANGELOG + subject.version = "1.0" + @target = Stud::Temporary.pathname + + # Write RPM + subject.output(@target) + + @rpm = ::RPM::File.new(@target) + insist { @rpm.tags[:changelogtime] } == [ 1464696000 ] + insist { @rpm.tags[:changelogname] } == [ "Example Maintainers - 1.0-1" ] + insist { @rpm.tags[:changelogtext] } == [ "- First example package" ] + + File.unlink(@target) + end + end # changelog end # #output describe "prefix attribute" do diff --git a/templates/rpm.erb b/templates/rpm.erb index 0e851f26d9..584038f636 100644 --- a/templates/rpm.erb +++ b/templates/rpm.erb @@ -260,4 +260,4 @@ fi <% end -%> %changelog -<%= attributes[:rpm_changelog] %> +<%= changelog %>