class Omnibus::Packager::RPM
Constants
- SCRIPT_MAP
@return [Hash]
Public Instance Methods
The path to the BUILD
directory inside the staging directory.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 300 def build_dir @build_dir ||= File.join(staging_dir, "BUILD") end
Convert the path of a file in the staging directory to an entry for use in the spec file.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 469 def build_filepath(path) filepath = rpm_safe("/" + path.gsub("#{build_dir}/", "")) return if config_files.include?(filepath) full_path = build_dir + filepath.gsub("[%]", "%") # FileSyncer.glob quotes pathnames that contain spaces, which is a problem on el7 full_path.delete!('"') # Mark directories with the %dir directive to prevent rpmbuild from counting their contents twice. return mark_filesystem_directories(filepath) if !File.symlink?(full_path) && File.directory?(full_path) filepath end
Set or return the category for this package.
@example
category "databases"
@param [String] val
the category for this package
@return [String]
the category for this package
# File lib/omnibus/packagers/rpm.rb, line 192 def category(val = NULL) if null?(val) @category || "default" else unless val.is_a?(String) raise InvalidValue.new(:category, "be a String") end @category = val end end
Returns the RPM
spec “_binary_payload” line corresponding to the compression configuration.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 395 def compression compression_name = case compression_type when :bzip2 "bzdio" when :xz "xzdio" else # default to gzip "gzdio" end "w#{compression_level}.#{compression_name}" end
Set or return the compression level (1-9) for this package
@example
compression_level 6
@param [Integer] val
the compression level
@return [Integer]
the compression level for this package
# File lib/omnibus/packagers/rpm.rb, line 267 def compression_level(val = NULL) if null?(val) @compression_level || 9 else unless val.is_a?(Integer) && 1 <= val && 9 >= val raise InvalidValue.new(:compression_level, "be an Integer (between 1 and 9)") end @compression_level = val end end
Set or return the compression type (:gzip, :bzip2, :xz) for this package
@example
compression_type :xz
@param [Symbol] val
the compression type
@return [String]
the compression type for this package
# File lib/omnibus/packagers/rpm.rb, line 242 def compression_type(val = NULL) if null?(val) @compression_type || :gzip else unless val.is_a?(Symbol) && %i{gzip bzip2 xz}.member?(val) raise InvalidValue.new(:compression_type, "be a Symbol (:gzip, :bzip2, or :xz)") end @compression_type = val end end
Get a list of user-declared config files
@return [Array]
# File lib/omnibus/packagers/rpm.rb, line 309 def config_files @config_files ||= project.config_files.map { |file| rpm_safe(file) } end
Generate the RPM
file using rpmbuild
. Unlike debian,the fakeroot
command is not required for the package to be owned by root:root
. The rpmuser specified in the spec file dictates this.
@return [void]
# File lib/omnibus/packagers/rpm.rb, line 414 def create_rpm_file command = %{rpmbuild} command << %{ --target #{safe_architecture}} command << %{ -bb} command << %{ --buildroot #{staging_dir}/BUILD} command << %{ --define '_topdir #{staging_dir}'} command << " #{spec_file}" log.info(log_key) { "Creating .rpm file" } shellout!("#{command}") if signing_passphrase log.info(log_key) { "Signing enabled for .rpm file" } if File.exist?("#{ENV["HOME"]}/.rpmmacros") log.info(log_key) { "Detected .rpmmacros file at `#{ENV["HOME"]}'" } home = ENV["HOME"] else log.info(log_key) { "Using default .rpmmacros file from Omnibus" } # Generate a temporary home directory home = Dir.mktmpdir render_template(resource_path("rpmmacros.erb"), destination: "#{home}/.rpmmacros", variables: { gpg_name: "Opscode Packages", gpg_path: "#{ENV["HOME"]}/.gnupg", # TODO: Make this configurable }) end sign_cmd = "rpmsign --addsign #{rpm_file}" with_rpm_signing do |signing_script| log.info(log_key) { "Signing the built rpm file" } # RHEL 8 has gpg-agent running so we can skip the expect script since the agent # takes care of the passphrase entering on the signing if dist_tag != ".el8" && dist_tag != ".el9" sign_cmd.prepend("#{signing_script} \"").concat("\"") end shellout!("#{sign_cmd}", environment: { "HOME" => home }) end end FileSyncer.glob("#{staging_dir}/RPMS/**/*.rpm").each do |rpm| copy_file(rpm, Config.package_dir) end end
Set or return the dist_tag
for this package
The Dist Tag for this RPM
package as per the Fedora packaging guidlines.
@see fedoraproject.org/wiki/Packaging:DistTag
@example
dist_tag ".#{Omnibus::Metadata.platform_shortname}#{Omnibus::Metadata.platform_version}"
@param [String] val
the dist_tag for this package
@return [String]
the dist_tag for this package
# File lib/omnibus/packagers/rpm.rb, line 221 def dist_tag(val = NULL) if null?(val) @dist_tag || ".#{Omnibus::Metadata.platform_shortname}#{Omnibus::Metadata.platform_version}" else @dist_tag = val end end
Directories owned by the filesystem package: fedoraproject.org/wiki/Packaging:Guidelines#File_and_Directory_Ownership
@return [Array]
# File lib/omnibus/packagers/rpm.rb, line 319 def filesystem_directories @filesystem_directories ||= IO.readlines(resource_path("filesystem_list")).map(&:chomp) end
Set or return the license for this package.
@example
license "Apache 2.0"
@param [String] val
the license for this package
@return [String]
the license for this package
# File lib/omnibus/packagers/rpm.rb, line 142 def license(val = NULL) if null?(val) @license || project.license else unless val.is_a?(String) raise InvalidValue.new(:license, "be a String") end @license = val end end
Mark filesystem directories with ownership and permissions specified in the filesystem package git.fedorahosted.org/cgit/filesystem.git/plain/filesystem.spec
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 329 def mark_filesystem_directories(fsdir) if fsdir.eql?("/") || fsdir.eql?("/usr/lib") || fsdir.eql?("/usr/share/empty") "%dir %attr(0555,root,root) #{fsdir}" elsif filesystem_directories.include?(fsdir) "%dir %attr(0755,root,root) #{fsdir}" else "%dir #{fsdir}" end end
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 287 def package_name if dist_tag "#{safe_base_package_name}-#{safe_version}-#{safe_build_iteration}#{dist_tag}.#{safe_architecture}.rpm" else "#{safe_base_package_name}-#{safe_version}-#{safe_build_iteration}.#{safe_architecture}.rpm" end end
Set or return the priority for this package.
@example
priority "extra"
@param [String] val
the priority for this package
@return [String]
the priority for this package
# File lib/omnibus/packagers/rpm.rb, line 167 def priority(val = NULL) if null?(val) @priority || "extra" else unless val.is_a?(String) raise InvalidValue.new(:priority, "be a String") end @priority = val end end
The full path to the rpm file.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 496 def rpm_file "#{staging_dir}/RPMS/#{safe_architecture}/#{package_name}" end
Generate an RPM-safe name from the given string, doing the following:
-
Replace [ with [[] to make rpm not use globs
-
Replace * with [*] to make rpm not use globs
-
Replace ? with [?] to make rpm not use globs
-
Replace % with [%] to make rpm not expand macros
@param [String] string
the string to sanitize
# File lib/omnibus/packagers/rpm.rb, line 539 def rpm_safe(string) string = "\"#{string}\"" if string[/\s/] string.dup .gsub("[", "[\\[]") .gsub("*", "[*]") .gsub("?", "[?]") .gsub("%", "[%]") end
The architecture for this RPM
package.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 642 def safe_architecture case Ohai["kernel"]["machine"] when "i686" "i386" when "armv7l" # raspberry pi 3 CentOS "armv7hl" when "armv6l" if Ohai["platform"] == "pidora" "armv6hl" else "armv6l" end else Ohai["kernel"]["machine"] end end
Return the RPM-ready base package name, converting any invalid characters to dashes (-
).
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 555 def safe_base_package_name if project.package_name =~ /\A[a-z0-9\.\+\-]+\z/ project.package_name.dup else converted = project.package_name.downcase.gsub(/[^a-z0-9\.\+\-]+/, "-") log.warn(log_key) do "The `name' component of RPM package names can only include " \ "lowercase alphabetical characters (a-z), numbers (0-9), dots (.), " \ "plus signs (+), and dashes (-). Converting `#{project.package_name}' to " \ "`#{converted}'." end converted end end
This is actually just the regular build_iternation, but it felt lonely among all the other safe_*
methods.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 578 def safe_build_iteration project.build_iteration end
RPM
package versions cannot contain dashes, so we will convert them to underscores.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 588 def safe_version version = project.build_version.dup # RPM 4.10+ added support for using the tilde (~) as a way to mark # versions as lower priority in comparisons. More details on this # feature can be found here: # # http://rpm.org/ticket/56 # if version =~ /\-/ if Ohai["platform_family"] == "wrlinux" converted = version.tr("-", "_") # WRL has an elderly RPM version log.warn(log_key) do "Omnibus replaces dashes (-) with tildes (~) so pre-release " \ "versions get sorted earlier than final versions. However, the " \ "version of rpmbuild on Wind River Linux does not support this. " \ "All dashes will be replaced with underscores (_). Converting " \ "`#{project.build_version}' to `#{converted}'." end else converted = version.tr("-", "~") log.warn(log_key) do "Tildes hold special significance in the RPM package versions. " \ "They mark a version as lower priority in RPM's version compare " \ "logic. We'll replace all dashes (-) with tildes (~) so pre-release" \ "versions get sorted earlier then final versions. Converting" \ "`#{project.build_version}' to `#{converted}'." end end version = converted end if version =~ /\A[a-zA-Z0-9\.\+\~]+\z/ version else converted = version.gsub(/[^a-zA-Z0-9\.\+\~]+/, "_") log.warn(log_key) do "The `version' component of RPM package names can only include " \ "alphabetical characters (a-z, A-Z), numbers (0-9), dots (.), " \ "plus signs (+), tildes (~) and underscores (_). Converting " \ "`#{project.build_version}' to `#{converted}'." end converted end end
Set or return the signing passphrase. If this value is provided, Omnibus
will attempt to sign the RPM
.
@example
signing_passphrase "foo"
@param [String] val
the passphrase to use when signing the RPM
@return [String]
the RPM-signing passphrase
# File lib/omnibus/packagers/rpm.rb, line 96 def signing_passphrase(val = NULL) if null?(val) @signing_passphrase else @signing_passphrase = val end end
The full path to this spec file on disk.
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 487 def spec_file "#{staging_dir}/SPECS/#{package_name}.spec" end
Set or return the vendor who made this package.
@example
vendor "Seth Vargo <sethvargo@gmail.com>"
@param [String] val
the vendor who make this package
@return [String]
the vendor who make this package
# File lib/omnibus/packagers/rpm.rb, line 117 def vendor(val = NULL) if null?(val) @vendor || "Omnibus <omnibus@getchef.com>" else unless val.is_a?(String) raise InvalidValue.new(:vendor, "be a String") end @vendor = val end end
Render the rpm signing script with secure permissions, call the given block with the path to the script, and ensure deletion of the script from disk since it contains sensitive information.
@param [Proc] block
the block to call
@return [String]
# File lib/omnibus/packagers/rpm.rb, line 510 def with_rpm_signing(&block) directory = Dir.mktmpdir destination = "#{directory}/sign-rpm" render_template(resource_path("signing.erb"), destination: destination, mode: 0700, variables: { passphrase: signing_passphrase, }) # Yield the destination to the block yield(destination) ensure remove_file(destination) remove_directory(directory) end
Render an rpm spec file in +SPECS/#{name}.spec+ using the supplied ERB template.
@return [void]
# File lib/omnibus/packagers/rpm.rb, line 345 def write_rpm_spec # Create a map of scripts that exist and their contents scripts = SCRIPT_MAP.inject({}) do |hash, (source, destination)| path = File.join(project.package_scripts_path, source.to_s) if File.file?(path) hash[destination] = File.read(path) end hash end # Get a list of all files files = FileSyncer.glob("#{build_dir}/**/*") .map { |path| build_filepath(path) } render_template(resource_path("spec.erb"), destination: spec_file, variables: { name: safe_base_package_name, version: safe_version, iteration: safe_build_iteration, vendor: vendor, license: license, dist_tag: dist_tag, maintainer: project.maintainer, homepage: project.homepage, description: project.description, priority: priority, category: category, conflicts: project.conflicts, replaces: project.replaces, dependencies: project.runtime_dependencies, user: project.package_user, group: project.package_group, scripts: scripts, config_files: config_files, files: files, build_dir: build_dir, platform_family: Ohai["platform_family"], compression: compression, }) end