class Vanagon::Component

Attributes

activate_triggers[RW]

activate_triggers is a one-dimentional Array of Strings, describing scripts that should be executed when a package identifies an activate trigger

build[RW]

build will hold an Array of the commands required to build a given component

build_dir[RW]

the optional name of a directory to build a component in; most likely to be used for cmake projects, which do not like to be configured or compiled in their own top-level directories.

build_requires[RW]

build_requires holds an Array with a list of the dependencies that a given component needs satisfied before it can be built.

check[RW]

check will hold an Array of the commands required to validate/test a given component

cleanup_source[RW]

cleanup_source contains whatever value a given component’s Source has specified as instructions for cleaning up after a build is completed. usually a String, but not required to be.

configure[RW]

how should this component be configured?

conflicts[RW]

conflicts holds an Array of OpenStructs that describe a package that a given component will replace on installation.

directories[RW]

directories holds an Array with a list of expected directories that will be packed into the resulting artifact’s bill of materials.

dirname[RW]

holds the expected directory name of a given component, once it’s been unpacked/decompressed. For git repos, it’s usually the directory that they were cloned to. For the outlying flat files, it’ll end up being defined explicitly as the string ‘./’

environment[RW]

holds a Vanagon::Environment object, to map out any desired environment variables that should be rendered into the Makefile

extract_with[RW]

The specific tools or command line invocations that should be used to extract a given component’s sources

homepage[RW]
install[RW]

install will hold an Array of the commands required to install a given component

install_only[RW]

When dealing with compiled artifacts generated by setting ‘project.generate_archives true`, you only need to install the component. By setting install_only to true the component ’build’ will exclude the unpack, patch, configure, build, and check steps.

install_triggers[RW]

install_triggers is a one-dimensional Array of OpenStructs, describing scripts that should be executed when a package is installed or upgraded

interest_triggers[RW]

interest_triggers is a one-dimensional Array of OpenStructs, describing scripts that should be executed when a package identifies an interest trigger

license[RW]
mirrors[RW]
name[RW]

The name, version, primary source, supplementary sources, associated patches, upstream URL (for fetching the source), homepage, and license of a given component

options[RW]

used to hold the checksum settings or other weirdo metadata related to building a given component (git ref, sha, etc.). Probably conflicts or collides with settings to some degree.

patches[RW]
platform[RW]

the platform that a given component will be built for – due to the fact that Ruby is pass-by-reference, it’s usually just a reference to the same Platform object that the overall Project object also contains. This is a definite code smell, and should be slated for refactoring ASAP because it’s going to have weird side-effects if the underlying pass-by-reference assumptions change.

postinstall_actions[RW]

postinstall_actions is a two-dimensional Array, describing scripts that should be executed after a given component is installed.

postinstall_required_actions[RW]

postinstall_required_actions is a two-dimensional Array, describing scripts that must be executed successfully after a given component is installed.

postremove_actions[RW]

preinstall_actions is a two-dimensional Array, describing scripts that should be executed after a given component is uninstalled.

preinstall_actions[RW]

preinstall_actions is a two-dimensional Array, describing scripts that should be executed before a given component is installed.

preremove_actions[RW]

preremove_actions is a two-dimensional Array, describing scripts that should be executed before a given component is uninstalled.

provides[RW]

provides holds an Array of OpenStructs that describe any capabilities that a given component will provide beyond the its filesystem payload.

replaces[RW]

replaces holds an Array of OpenStructs that describe a package that a given component will replace on installation.

requires[RW]

requires holds an Array with a list of all dependencies that a given component needs satisfied before it can be installed.

service[RW]

holds an OpenStruct describing all of the particular details about how any services associated with a given component should be defined.

settings[RW]

holds a OpenStruct, or an Array, or maybe it’s a Hash? It’s often overloaded as a freeform key-value lookup for platforms that require additional configuration beyond the “basic” component attributes. it’s pretty heavily overloaded and should maybe be refactored before Vanagon 1.0.0 is tagged.

source[RW]
sources[RW]
url[RW]
version[RW]

Public Class Methods

load_component(name, configdir, settings, platform) click to toggle source

Loads a given component from the configdir

@param name [String] the name of the component @param configdir [String] the path to the component config file @param settings [Hash] the settings to be used in the component @param platform [Vanagon::Platform] the platform to build the component for @return [Vanagon::Component] the component as specified in the component config @raise if the instance_eval on Component fails, the exception is reraised

# File lib/vanagon/component.rb, line 140
def self.load_component(name, configdir, settings, platform)
  compfile = File.join(configdir, "#{name}.rb")
  dsl = Vanagon::Component::DSL.new(name, settings, platform)
  dsl.instance_eval(File.read(compfile), compfile, 1)
  dsl._component
rescue StandardError => e
  VanagonLogger.error "Error loading project '#{name}' using '#{compfile}':"
  VanagonLogger.error e
  VanagonLogger.error e.backtrace.join("\n")
  raise e
end
new(name, settings, platform) click to toggle source

Component constructor.

@param name [String] the name of the component @param settings [Hash] the settings to be used in the component @param platform [Vanagon::Platform] the platform to build the component for @return [Vanagon::Component] the component with the given settings and platform

# File lib/vanagon/component.rb, line 158
def initialize(name, settings, platform) # rubocop:disable Metrics/AbcSize
  @name = name
  @settings = settings
  @platform = platform
  @options = {}
  @build_requires = []
  @requires = []
  @configure = []
  @install = []
  @build = []
  @check = []
  @patches = []
  @files = Set.new
  @ghost_files = Set.new
  @directories = []
  @replaces = []
  @provides = []
  @conflicts = []
  @environment = Vanagon::Environment.new
  @sources = []
  @preinstall_actions = []
  @install_triggers = []
  @interest_triggers = []
  @activate_triggers = []
  @postinstall_required_actions = []
  @postinstall_actions = []
  @preremove_actions = []
  @postremove_actions = []
  @install_only = false
  @service = []
end

Public Instance Methods

add_file(file) click to toggle source

Adds the given file to the list of files and returns @files.

@param file [Vanagon::Common::Pathname] file to add to a component’s list of files @return [Set, nil] Returns @files if file is successfully added to @files

or nil if file already exists
# File lib/vanagon/component.rb, line 195
def add_file(file)
  @files.add file
end
add_rpm_ghost_file(file) click to toggle source

Adds the given file to the list of %ghost files to be added to an rpm spec’s %files.

@param file [Vanagon::Common::Pathname] file to add to the ghost file set. @return [Set, nil] Returns @ghost_files if the file is successfully added

to @ghost_files or nil if the file already exists.
# File lib/vanagon/component.rb, line 205
def add_rpm_ghost_file(file)
  @ghost_files.add file
end
configfiles() click to toggle source

Retrieve all items from @files explicitly marked as configuration files

@return [Set] all files explicitly marked as configuration files

# File lib/vanagon/component.rb, line 230
def configfiles
  @files.select(&:configfile?)
end
delete_file(file) click to toggle source

Deletes the given file from the list of files and returns @files.

@param file [String] path of file to delete from a component’s list of files @return [Set, nil] Returns @files if file is successfully deleted

from @files or nil if file doesn't exist; this matches strictly on
the path of a given file, and ignores other attributes like :mode,
:owner, or :group.
# File lib/vanagon/component.rb, line 216
def delete_file(file)
  @files.delete_if { |this_file| this_file.path == file }
end
environment_variables() click to toggle source
# File lib/vanagon/component.rb, line 437
def environment_variables
  environment.map { |key, value| %(export #{key}="#{value}") }
end
fetch_mirrors(options) click to toggle source

Retrieve upstream source file from a mirror, by randomly iterating through mirrors until there’s no more mirrors left. Will warn if the mirror’s URI cannot be resolved or if the URI cannot be retrieved. Does not suppress any errors from Vanagon::Component::Source.

@return [Boolean] return True if the source can be retrieved,

or False otherwise. This is because because each subclass of
Vanagon::Component::Source returns an inconsistent value
if #fetch is successful.
# File lib/vanagon/component.rb, line 261
def fetch_mirrors(options)
  mirrors.to_a.shuffle.each do |mirror|
    begin
      VanagonLogger.info %(Attempting to fetch from mirror URL "#{mirror}")
      @source = Vanagon::Component::Source.source(mirror, **options)
      return true if source.fetch
    rescue Vanagon::InvalidSource
      # This means that the URL was not a git repo or a valid downloadable file,
      # which means either the URL is incorrect, or we don't have access to that
      # resource. Return false, so that the pkg.url value can be used instead.
      VanagonLogger.error %(Invalid source "#{mirror}")
    rescue SocketError
      # SocketError means that there was no DNS/name resolution
      # for whatever remote protocol the mirror tried to use.
      VanagonLogger.error %(Unable to resolve mirror URL "#{mirror}")
    rescue StandardError
      # Source retrieval does not consistently return a meaningful
      # namespaced error message, which means we're brute-force rescuing
      # StandardError. Also, we want to handle other unexpected things when
      # we try reaching out to the URL, so that we can gracefully return
      # false and fall back to fetching the pkg.url value instead.
      VanagonLogger.error %(Unable to retrieve mirror URL "#{mirror}")
    end
  end
  false
end
fetch_url(options) click to toggle source

Retrieve upstream source file from the canonical URL. Does not suppress any errors from Vanagon::Component::Source.

@return [Boolean] return True if the source can be retrieved,

or False otherwise
# File lib/vanagon/component.rb, line 293
def fetch_url(options)
  VanagonLogger.info %(Attempting to fetch from canonical URL "#{url}")
  @source = Vanagon::Component::Source.source(url, **options)
  # Explicitly coerce the return value of #source.fetch,
  # because each subclass of Vanagon::Component::Source returns
  # an inconsistent value if #fetch is successful.
  !!source.fetch
end
files() click to toggle source

Retrieve all items from @files not marked as configuration files

@return [Set] all files not marked as configuration files

# File lib/vanagon/component.rb, line 223
def files
  @files.reject(&:configfile?)
end
force_version() click to toggle source

Force version determination for components

If the component doesn’t already have a version set (which normally happens for git sources), the source will be fetched into a temporary directory to attempt to figure out the version if the source type supports :version. This directory will be cleaned once the get_sources method returns

@raise Vanagon::Error raises a vanagon error if we’re unable to determine the version

# File lib/vanagon/component.rb, line 407
def force_version
  if @version.nil?
    Dir.mktmpdir do |dir|
      get_source(dir)
    end
  end
  raise Vanagon::Error, "Unable to determine source version for component #{@name}!" if @version.nil?
  @version
end
get_build_dir() click to toggle source

Expands the build directory

# File lib/vanagon/component.rb, line 347
def get_build_dir
  if @build_dir
    File.join(@dirname, @build_dir)
  else
    @dirname
  end
end
get_dependency_hash() click to toggle source
# File lib/vanagon/component.rb, line 355
def get_dependency_hash
  { name => { 'version' => version, 'url' => url, 'ref' => options[:ref] }.delete_if { |_, v| !v } }
end
get_environment() click to toggle source

Prints the environment in a way suitable for use in a Makefile or shell script. This is deprecated, because all Env. Vars. are moving directly into the Makefile (and out of recipe subshells).

@return [String] environment suitable for inclusion in a Makefile @deprecated

# File lib/vanagon/component.rb, line 423
    def get_environment
      VanagonLogger.info <<-WARNING.undent
        #get_environment is deprecated; environment variables have been moved
        into the Makefile, and should not be used within a Makefile's recipe.
        The #get_environment method will be removed by Vanagon 1.0.0.
      WARNING

      if environment.empty?
        ": no environment variables defined"
      else
        environment_variables
      end
    end
get_patches(patch_root) click to toggle source

Fetches patches if any are provided for the project.

@param patch_root [String] working directory to put the patches into

# File lib/vanagon/component.rb, line 387
def get_patches(patch_root)
  return if @patches.empty?
  @patches.each do |patch|
    patch_assembly_path = File.join(patch_root, patch.assembly_path)
    if File.exist?(patch_assembly_path)
      raise Vanagon::Error, "Duplicate patch files detected, '#{patch.origin_path}' would have overwritten '#{patch.assembly_path}'. Ensure all patch file names within a component are unique."
    end
    patch_target_directory = File.dirname(patch_assembly_path)
    FileUtils.mkdir_p(patch_target_directory)
    FileUtils.cp(patch.origin_path, patch_assembly_path)
  end
end
get_source(workdir) click to toggle source

Fetches the primary source for the component. As a side effect, also sets @extract_with, @dirname and @version for the component for use in the makefile template

@param workdir [String] working directory to put the source into

# File lib/vanagon/component.rb, line 317
def get_source(workdir) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
  opts = options.merge({ workdir: workdir, dirname: dirname })
  if url || !mirrors.empty?
    if ENV['VANAGON_USE_MIRRORS'] == 'n' or ENV['VANAGON_USE_MIRRORS'] == 'false'
      fetch_url(opts)
    else
      fetch_mirrors(opts) || fetch_url(opts)
    end
    source.verify
    extract_with << source.extract(platform.tar) if source.respond_to? :extract

    @cleanup_source = source.cleanup if source.respond_to?(:cleanup)
    @dirname ||= source.dirname

    # Git based sources probably won't set the version, so we load it if it hasn't been already set
    if source.respond_to?(:version)
      @version ||= source.version
    end
  else
    VanagonLogger.info "No source given for component '#{@name}'"

    # If there is no source, we don't want to try to change directories, so we just change to the current directory.
    @dirname = './'

    # If there is no source, there is nothing to do to extract
    extract_with << ': no source, so nothing to extract'
  end
end
get_sources(workdir) click to toggle source

Fetches secondary sources for the component. These are just dumped into the workdir currently.

@param workdir [String] working directory to put the source into

# File lib/vanagon/component.rb, line 362
def get_sources(workdir) # rubocop:disable Metrics/AbcSize
  sources.each do |source|
    src = Vanagon::Component::Source.source(
      source.url, workdir: workdir, ref: source.ref, sum: source.sum
    )
    src.fetch
    src.verify
    if source.erb
      erb_file(src.file, File.join(File.dirname(src.file), File.basename(src.file, ".erb")), true)
    end
    # set src.file to only be populated with the basename instead of entire file path
    src.file = File.basename(src.url)
    extract_with << src.extract(platform.tar) if src.respond_to? :extract
  end
end
rpm_ghost_files() click to toggle source

Retrieve all the files intended as %ghost entries for an rpm spec %files section.

@return [Array] of all the rpm %ghost files.

# File lib/vanagon/component.rb, line 238
def rpm_ghost_files
  @ghost_files.to_a
end
rules(project, platform) click to toggle source
# File lib/vanagon/component.rb, line 441
def rules(project, platform)
  Vanagon::Component::Rules.new(self, project, platform)
end

Private Instance Methods

deprecated_rewrite_url() click to toggle source

This method is deprecated and private. It will return a rewritten URL if there’s any value for url and a rewrite rule for that URL has been set

# File lib/vanagon/component.rb, line 305
def deprecated_rewrite_url
  return nil unless url
  rewritten_url = Vanagon::Component::Source::Rewrite.parse_and_rewrite(url)
  url == rewritten_url ? nil : rewritten_url
end