class Omnibus::Project
Attributes
Public Class Methods
@param [String] name
the name to the project definition to load from disk
@return [Project]
# File lib/omnibus/project.rb, line 33 def load(name, manifest = nil) loaded_projects[name] ||= begin filepath = Omnibus.project_path(name) if filepath.nil? raise MissingProject.new(name) else log.internal(log_key) do "Loading project `#{name}' from `#{filepath}'." end end instance = new(filepath, manifest) instance.evaluate_file(filepath) instance.load_dependencies instance end end
# File lib/omnibus/project.rb, line 80 def initialize(filepath = nil, manifest = nil) @filepath = filepath @manifest = manifest end
Reset cached project information.
# File lib/omnibus/project.rb, line 55 def reset! @loaded_projects = nil end
Private Class Methods
The list of projects loaded thus far.
@return [Hash<String, Project>]
# File lib/omnibus/project.rb, line 66 def loaded_projects @loaded_projects ||= {} end
Public Instance Methods
Comparator for two projects (name
)
@return [1, 0, -1]
# File lib/omnibus/project.rb, line 1037 def <=>(other) name <=> other.name end
Determine if two projects are identical.
@param [Project] other
@return [true, false]
# File lib/omnibus/project.rb, line 1209 def ==(other) hash == other.hash end
# File lib/omnibus/project.rb, line 1075 def build FileUtils.rm_rf(install_dir) FileUtils.mkdir_p(install_dir) Licensing.create_incrementally(self) do |license_collector| softwares.each do |software| software.build_me([license_collector]) end # If nothing has dirtied the cache, checkout the last cache dir restore_complete_build unless dirty? end write_json_manifest write_text_manifest HealthCheck.run!(self) package_me compress_me end
Set or retrieve the git revision of the omnibus project being built.
If not set by the user, and the current workding directory is a git directory, it will return the revision of the current working directory.
# File lib/omnibus/project.rb, line 394 def build_git_revision(val = NULL) if null?(val) @build_git_revision ||= get_local_revision else @build_git_revision = val end end
Set or retrieve the build iteration of the project. Defaults to 1
if not otherwise set.
@example
build_iteration 5
@param [Fixnum] val
the build iteration number
@return [Fixnum]
# File lib/omnibus/project.rb, line 415 def build_iteration(val = NULL) if null?(val) @build_iteration || 1 else @build_iteration = val end end
Download and build the project. Preserved for backwards compatibility.
# File lib/omnibus/project.rb, line 1125 def build_me # Download all softwares in parallel download build end
Set or retrieve the version of the project.
@example Using a string
build_version '1.0.0'
@example From git
build_version do source :git end
@example From the version of a dependency
build_version do source :version, from_dependency: 'chef' end
@example From git of a dependency
build_version do source :git, from_dependency: 'chef' end
When using the :git
source, by default the output format of the build_version
is semver. This can be modified using the :output_format
parameter to any of the methods of BuildVersion
. For example:
build version do source :git, from_dependency: 'chef' output_format :git_describe end
@see Omnibus::BuildVersion
@see Omnibus::BuildVersionDSL
@param [String] val
the build version to set
@param [Proc] block
the block to run when constructing the +build_version+
@return [String]
# File lib/omnibus/project.rb, line 368 def build_version(val = NULL, &block) if block && !null?(val) raise Error, "You cannot specify additional parameters to " \ "#build_version when a block is given!" end if block @build_version_dsl = BuildVersionDSL.new(&block) else if null?(val) @build_version_dsl.build_version else @build_version_dsl = BuildVersionDSL.new(val) end end end
The DSL for this build version.
@return [BuildVersionDSL]
# File lib/omnibus/project.rb, line 971 def build_version_dsl @build_version_dsl end
Generate a version manifest of the loaded software sources.
@returns [Omnibus::Manifest]
# File lib/omnibus/project.rb, line 1055 def built_manifest log.info(log_key) { "Building version manifest" } m = Omnibus::Manifest.new(build_version, build_git_revision, license) softwares.each do |software| m.add(software.name, software.manifest_entry) end m end
Add or override a customization for the compressor with the given id
. When given multiple blocks with the same id
, they are evaluated _in order_, so the last block evaluated will take precedence over the previous ones.
@example With customization
compress :dmg do window_bounds '10, 20, 30, 40' end
@example Without customization
compress :tgz
If multiple compress
blocks are specified, the “most prefered” one for the current system will be used.
@param [Symbol] id
the id of the compressor to customize
# File lib/omnibus/project.rb, line 466 def compress(id, &block) if block compressors[id] << block else compressors[id] << Proc.new {} end end
# File lib/omnibus/project.rb, line 1165 def compress_me destination = File.expand_path("pkg", Config.project_root) # Create the destination directory unless File.directory?(destination) FileUtils.mkdir_p(destination) end # Evaluate any compressor-specific blocks, in order. compressors[compressor.id].each do |block| compressor.evaluate(&block) end # Run the actual compressor compressor.run! # Copy the compressed package and metadata back into the workspace, if it # exists package_path = File.join(Config.package_dir, compressor.package_name) if File.file?(package_path) FileUtils.cp(package_path, destination) FileUtils.cp("#{package_path}.metadata.json", destination) end end
Instantiate a new instance of the best compressor for this system.
@return [~Compressor::Base]
# File lib/omnibus/project.rb, line 962 def compressor @compressor ||= Compressor.for_current_system(compressors.keys).new(self) end
The list of compressors, in the following format:
{ id: [#<Proc:0x001>, #<Proc:0x002>], # ... }
@return [Hash<Symbol, Array<Proc>>]
the compressor blocks, indexed by key
# File lib/omnibus/project.rb, line 953 def compressors @compressors ||= Hash.new { |h, k| h[k] = [] } end
Add a config file.
@example
config_file '/path/to/config.rb'
@param [String] val
the name of a config file of your software
@return [Array<String>]
the list of current config files
# File lib/omnibus/project.rb, line 659 def config_file(val) config_files << val config_files.dup end
The list of config files for this software.
@return [Array<String>]
# File lib/omnibus/project.rb, line 858 def config_files @config_files ||= [] end
Add to the list of packages this one conflicts with.
@example
conflicts 'foo' conflicts 'bar'
@param [String] val
the conflict to add
@return [Array<String>]
the list of conflicts
# File lib/omnibus/project.rb, line 322 def conflict(val) conflicts << val conflicts.dup end
The list of things this project conflicts with.
@return [Array<String>]
# File lib/omnibus/project.rb, line 887 def conflicts @conflicts ||= [] end
The software definition which dirtied this project.
@return [Software, nil]
# File lib/omnibus/project.rb, line 1019 def culprit @culprit end
The default root where a project should be installed. On Windows-based systems, this value defaults to C:
. On non-Windows systems, this value defaults to /opt
.
@example
install_dir "#{default_root}/chef" #=> Produces +C:/chef+ on Windows and #=> +/opt/chef+ on Linux
@return [String]
# File lib/omnibus/project.rb, line 198 def default_root if windows? "C:" else "/opt" end end
The list of software dependencies for this project. These is the software that comprises your project, and is distinct from runtime dependencies.
@see dependency
@param [Array<String>]
@return [Array<String>]
# File lib/omnibus/project.rb, line 838 def dependencies @dependencies ||= [] end
Add a software dependency.
Note that this is a *build time* dependency. If you need to specify an external dependency that is required at runtime, see {#runtime_dependency} instead.
@example
dependency 'foo' dependency 'bar'
@param [String] val
the name of a Software dependency
@return [Array<String>]
the list of dependencies
# File lib/omnibus/project.rb, line 601 def dependency(val) dependencies << val dependencies.dup end
Indicates whether the given software
is defined as a software component of this project.
@param [String, Software] software
the software or name of the software to find
@return [true, false]
# File lib/omnibus/project.rb, line 984 def dependency?(software) name = software.is_a?(Software) ? software.name : software dependencies.include?(name) end
Set or retrieve the project description.
@example
description 'This is my description'
@param [String] val
the project description
@return [String]
# File lib/omnibus/project.rb, line 279 def description(val = NULL) if null?(val) @description || "The full stack of #{name}" else @description = val end end
Dirty the cache for this project. This can be called by other projects, install path cache, or software definitions to invalidate the cache for this project.
@param [Software] software
the software that dirtied the cache
@return [true, false]
# File lib/omnibus/project.rb, line 1008 def dirty!(software) raise ProjectAlreadyDirty.new(self) if culprit @culprit = software end
Determine if the cache for this project is dirty.
@return [true, false]
# File lib/omnibus/project.rb, line 1028 def dirty? !!culprit end
# File lib/omnibus/project.rb, line 1064 def download # Setting abort_on_exception to false because it was causing # errors by shutting down the main thread when encountering a cache miss # in S3 and falling back to the internal source repo ThreadPool.new(Config.workers, false) do |pool| softwares.each do |software| pool.schedule { software.fetch } end end end
Add a new exclusion pattern for a list of files or folders to exclude when making the package.
@example
exclude '.git'
@param [String] pattern
the thing to exclude
@return [Array<String>]
the list of current exclusions
# File lib/omnibus/project.rb, line 641 def exclude(pattern) exclusions << pattern exclusions.dup end
The list of exclusions for this project.
@return [Array<String>]
# File lib/omnibus/project.rb, line 905 def exclusions @exclusions ||= [] end
Add other files or dirs outside of install_dir
. These files retain their relative paths inside the scratch directory:
/path/to/foo.txt #=> /tmp/package/path/to/foo.txt
@example
extra_package_file '/path/to/file'
@param [String] val
the name of a dir or file to include in build
@return [Array<String>]
the list of current extra package files
# File lib/omnibus/project.rb, line 681 def extra_package_file(val) extra_package_files << val extra_package_files.dup end
The list of files and directories used to build this project.
@return [Array<String>]
# File lib/omnibus/project.rb, line 867 def extra_package_files(val = NULL) @extra_package_files ||= [] end
The path (on disk) where this project came from. Warning: this can be nil
if a project was dynamically created!
@return [String, nil]
# File lib/omnibus/project.rb, line 848 def filepath @filepath end
Path to the /files
directory in the omnibus project. This directory can contain arbitrary files used by the project.
@example
patch = File.join(files_path, 'rubygems', 'patch.rb')
@return [String]
path to the files directory
# File lib/omnibus/project.rb, line 217 def files_path File.expand_path("#{Config.project_root}/files") end
Set or retrieve a friendly name for the project. This defaults to the capitalized name if not specified.
@example
friendly_name 'Chef'
@param [String] val
the name to set
@return [String]
# File lib/omnibus/project.rb, line 127 def friendly_name(val = NULL) if null?(val) @friendly_name || name.capitalize else @friendly_name = val end end
The unique “hash” for this project.
@see (shasum
)
@return [Fixnum]
# File lib/omnibus/project.rb, line 1198 def hash shasum.hash end
[Required] Set or retrive the package homepage.
@example
homepage 'https://www.getchef.com'
@raise [MissingRequiredAttribute] if a value was not set before being
subsequently retrieved
@param [String] val
the homepage for the project
@return [String]
# File lib/omnibus/project.rb, line 259 def homepage(val = NULL) if null?(val) @homepage || raise(MissingRequiredAttribute.new(self, :homepage, "https://www.getchef.com")) else @homepage = val end end
[Required] Set or retrieve the path at which the project should be installed by the generated package.
Even on Windows-based systems, this path should be the Unix-like path, since that’s what Ruby expects. In the event ++ is used as a file separator, it will be replaced with /
. This method also attempts to remove duplicate slashes which might be caused as a result of string interpolation.
@example
install_dir '/opt/chef'
@raise [MissingRequiredAttribute] if a value was not set before being
subsequently retrieved
@param [String] val
the install path to set
@return [String]
# File lib/omnibus/project.rb, line 178 def install_dir(val = NULL) if null?(val) @install_dir || raise(MissingRequiredAttribute.new(self, :install_dir, "/opt/chef")) else @install_dir = val.tr('\\', "/").squeeze("/").chomp("/") # rubocop:disable Style/StringLiterals end end
Location of json-formated version manifest, written at at the end of the build. If no path is specified install_dir
/version-manifest.json is used.
@example
json_manifest_path
@return [String]
# File lib/omnibus/project.rb, line 774 def json_manifest_path(path = NULL) if null?(path) @json_manifest_path || File.join(install_dir, "version-manifest.json") else @json_manifest_path = path end end
The library for this Omnibus
project.
@return [Library]
# File lib/omnibus/project.rb, line 994 def library @library ||= Library.new(self) end
Set or retrieve the {#license} of the project.
@example
license 'Apache 2.0'
@param [String] val
the license to set for the project.
@return [String]
# File lib/omnibus/project.rb, line 711 def license(val = NULL) if null?(val) @license || "Unspecified" else @license = val end end
Set or retrieve the location of the {#license_file} of the project. It can either be a relative path inside the project source directory or a URL.
@example
license_file 'LICENSES/artistic.txt'
@param [String] val
the location of the license file for the project.
@return [String]
# File lib/omnibus/project.rb, line 734 def license_file(val = NULL) if null?(val) @license_file else @license_file = val end end
Location of license file that omnibus will create and that will contain the information about the license of the project plus the details about the licenses of the software components included in the project.
If no path is specified install_dir/LICENSE is used.
@example
license_file_path
@return [String]
# File lib/omnibus/project.rb, line 755 def license_file_path(path = NULL) if null?(path) @license_file_path || File.join(install_dir, "LICENSE") else @license_file_path = File.join(install_dir, path) end end
Recursively load all the dependencies for this project.
@return [true]
# File lib/omnibus/project.rb, line 820 def load_dependencies dependencies.each do |dependency| Software.load(self, dependency, manifest) end true end
[Required] Set or retrieve the the package maintainer.
@example
maintainer 'Chef Software, Inc.'
@raise [MissingRequiredAttribute] if a value was not set before being
subsequently retrieved
@param [String] val
the name of the maintainer
@return [String]
# File lib/omnibus/project.rb, line 236 def maintainer(val = NULL) if null?(val) @maintainer || raise(MissingRequiredAttribute.new(self, :maintainer, "Chef Software, Inc.")) else @maintainer = val end end
[Required] Set or retrieve the name of the project.
@example
name 'chef'
@raise [MissingRequiredAttribute] if a value was not set before being
subsequently retrieved
@param [String] val
the name to set
@return [String]
# File lib/omnibus/project.rb, line 106 def name(val = NULL) if null?(val) @name || raise(MissingRequiredAttribute.new(self, :name, "hamlet")) else @name = val end end
A proxy method to the underlying Ohai
system.
@example
ohai['platform_family']
@return [Ohai]
# File lib/omnibus/project.rb, line 695 def ohai Ohai end
Set or retrieve the overrides hash for one piece of software being overridden. Calling it as a setter does not merge hash entries and it will set all the overrides for a given software definition.
@example
override 'chef', version: '1.2.3'
@param [Hash] val
the value to override
@return [Hash]
# File lib/omnibus/project.rb, line 512 def override(name, val = NULL) if null?(val) overrides[name.to_sym] else overrides[name.to_sym] = val end end
Retrieve the list of overrides for all software being overridden.
@return [Hash]
# File lib/omnibus/project.rb, line 914 def overrides @overrides ||= {} end
Add or override a customization for the packager with the given id
. When given multiple blocks with the same id
, they are evaluated _in order_, so the last block evaluated will take precedence over the previous ones.
@example
package :id do key 'value' end
@param [Symbol] id
the id of the packager to customize
# File lib/omnibus/project.rb, line 437 def package(id, &block) unless block raise InvalidValue.new(:package, "have a block") end packagers[id] << block end
Set or retrieve the group the package should install as. This varies with operating system and may be ignored if the underlying packager does not support it.
Defaults to +Ohai+. If +Ohai+ is nil
, it defaults to +“root”+.
@example
package_group 'build'
@param [String] val
the group to use for the package build
@return [String]
# File lib/omnibus/project.rb, line 537 def package_group(val = NULL) if null?(val) @package_group || Ohai["root_group"] || "root" else @package_group = val end end
# File lib/omnibus/project.rb, line 1134 def package_me destination = File.expand_path("pkg", Config.project_root) # Create the destination directory unless File.directory?(destination) FileUtils.mkdir_p(destination) end packagers_for_system.each do |packager| # Evaluate any packager-specific blocks, in order. packagers[packager.id].each do |block| packager.evaluate(&block) end if packager.skip_packager log.info(log_key) { "Skipping #{packager.id} per project configuration." } next end # Run the actual packager packager.run! # Copy the generated package and metadata back into the workspace package_path = File.join(Config.package_dir, packager.package_name) FileUtils.cp(package_path, destination, preserve: true) FileUtils.cp("#{package_path}.metadata.json", destination, preserve: true) end end
Set or retrieve the package name of the project. Defaults to the package name defaults to the project name.
@example
package_name 'com.chef.project'
@param [String] val
the package name to set
@return [String]
# File lib/omnibus/project.rb, line 148 def package_name(val = NULL) if null?(val) @package_name || name else @package_name = val end end
The path to the package scripts directory for this project. These are optional scripts that can be bundled into the resulting package for running at various points in the package management lifecycle.
These scripts and their names vary with operating system.
@return [String]
# File lib/omnibus/project.rb, line 575 def package_scripts_path(arg = NULL) if null?(arg) @package_scripts_path || "#{Config.project_root}/package-scripts/#{name}" else @package_scripts_path = File.expand_path(arg) end end
Set or retrieve the user the package should install as. This varies with operating system, and may be ignored if the underlying packager does not support it.
Defaults to +“root”+.
@example
package_user 'build'
@param [String] val
the user to use for the package build
@return [String]
# File lib/omnibus/project.rb, line 490 def package_user(val = NULL) if null?(val) @package_user || "root" else @package_user = val end end
The list of packagers, in the following format:
{ id: [#<Proc:0x001>, #<Proc:0x002>], # ... }
@return [Hash<Symbol, Array<Proc>>]
the packager blocks, indexed by key
# File lib/omnibus/project.rb, line 929 def packagers @packagers ||= Hash.new { |h, k| h[k] = [] } end
Instantiate new instances of the best packagers for this system.
@return [[~Packager::Base]]
# File lib/omnibus/project.rb, line 938 def packagers_for_system @packagers_for_system ||= Packager.for_current_system.map { |p| p.new(self) } end
Add to the list of packages this one replaces.
This should only be used when renaming a package and obsoleting the old name of the package. **Setting this to the same name as package_name
will cause RPM upgrades to fail.**
@example
replace 'the-old-package'
@param [String] val
the name of the package to replace
@return [String]
# File lib/omnibus/project.rb, line 303 def replace(val = NULL) replaces << val replaces.dup end
The list of things this project replaces with.
@return [Array<String>]
# File lib/omnibus/project.rb, line 896 def replaces @replaces ||= [] end
Set or retrieve the path to the resources on disk for use in packagers.
@example
resources_path '/path/to/resources'
@param [String] val
the path where resources live
@return [String]
# File lib/omnibus/project.rb, line 557 def resources_path(val = NULL) if null?(val) @resources_path || "#{Config.project_root}/resources/#{name}" else @resources_path = File.expand_path(val) end end
# File lib/omnibus/project.rb, line 1095 def restore_complete_build if Config.use_git_caching log.info(log_key) { "Cache not dirtied, restoring last marker" } GitCache.new(softwares.last).restore_from_cache end end
The list of software dependencies for this project.
These is the software that is used at runtime for your project.
@return [Array<String>]
# File lib/omnibus/project.rb, line 878 def runtime_dependencies @runtime_dependencies ||= [] end
Add a package that is a runtime dependency of this project.
This is distinct from a build-time dependency, which should correspond to a software definition.
@example
runtime_dependency 'foo'
@param [String] val
the name of the runtime dependency
@return [Array<String>]
the list of runtime dependencies
# File lib/omnibus/project.rb, line 622 def runtime_dependency(val) runtime_dependencies << val runtime_dependencies.dup end
The unique SHA256 for this project.
A project is defined by its name, its build_version
, its install_dir
, and any overrides (as JSON). Additionally, if provided, the actual file contents are included in the SHA to ensure uniqueness.
@return [String]
# File lib/omnibus/project.rb, line 1223 def shasum @shasum ||= begin digest = Digest::SHA256.new update_with_string(digest, name) update_with_string(digest, install_dir) update_with_string(digest, FFI_Yajl::Encoder.encode(overrides)) if filepath && File.exist?(filepath) update_with_file_contents(digest, filepath) else update_with_string(digest, "<DYNAMIC>") end digest.hexdigest end end
Cache the build order so we don’t re-compute
@return [Array<Omnibus::Software>]
# File lib/omnibus/project.rb, line 1046 def softwares @softwares ||= library.build_order end
Location of text-formatted manifest. (install_dir
/version-manifest.txt if none is provided)
This manifest uses the same format used by the ‘version-manifest’ software definition in omnibus-software.
@example
text_manifest_path
@return [String]
# File lib/omnibus/project.rb, line 795 def text_manifest_path(path = NULL) if null?(path) @text_manifest_path || File.join(install_dir, "version-manifest.txt") else @text_manifest_path = path end end
# File lib/omnibus/project.rb, line 1102 def write_json_manifest File.open(json_manifest_path, "w") do |f| f.write(FFI_Yajl::Encoder.encode(built_manifest.to_hash, pretty: true)) end end
Writes a text manifest to the text_manifest_path. This uses the same method as the “version-manifest” software definition in omnibus-software.
# File lib/omnibus/project.rb, line 1113 def write_text_manifest File.open(text_manifest_path, "w") do |f| f.puts "#{name} #{build_version}" f.puts "" f.puts Omnibus::Reports.pretty_version_map(self) end end
Private Instance Methods
@!endgroup
# File lib/omnibus/project.rb, line 1247 def get_local_revision GitRepository.new("./").revision rescue StandardError "unknown" end
The log key for this project, overriden to include the name of the project for build output.
@return [String]
# File lib/omnibus/project.rb, line 1259 def log_key @log_key ||= "#{super}: #{name}" end