lib/omnibus.rb (170 lines of code) (raw):
#
# Copyright 2012-2018 Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require "omnibus/core_extensions"
require "cleanroom"
require "pathname" unless defined?(Pathname)
require "omnibus/digestable"
require "omnibus/exceptions"
require "omnibus/sugarable"
require "omnibus/util"
require "omnibus/fetcher"
require "omnibus/version"
module Omnibus
#
# The path to the default configuration file.
#
# @return [String]
#
DEFAULT_CONFIG = "omnibus.rb".freeze
autoload :Builder, "omnibus/builder"
autoload :BuildVersion, "omnibus/build_version"
autoload :BuildVersionDSL, "omnibus/build_version_dsl"
autoload :BuildSystemMetadata, "omnibus/build_system_metadata"
autoload :Buildkite, "omnibus/build_system_metadata/buildkite"
autoload :Cleaner, "omnibus/cleaner"
autoload :Compressor, "omnibus/compressor"
autoload :Config, "omnibus/config"
autoload :Error, "omnibus/exceptions"
autoload :FileSyncer, "omnibus/file_syncer"
autoload :Generator, "omnibus/generator"
autoload :GitCache, "omnibus/git_cache"
autoload :HealthCheck, "omnibus/health_check"
autoload :Instrumentation, "omnibus/instrumentation"
autoload :Library, "omnibus/library"
autoload :Logger, "omnibus/logger"
autoload :Logging, "omnibus/logging"
autoload :Metadata, "omnibus/metadata"
autoload :NullArgumentable, "omnibus/null_argumentable"
autoload :Ohai, "omnibus/ohai"
autoload :Package, "omnibus/package"
autoload :Packager, "omnibus/packager"
autoload :Project, "omnibus/project"
autoload :Publisher, "omnibus/publisher"
autoload :Reports, "omnibus/reports"
autoload :S3Cache, "omnibus/s3_cache"
autoload :Software, "omnibus/software"
autoload :Templating, "omnibus/templating"
autoload :ThreadPool, "omnibus/thread_pool"
autoload :Licensing, "omnibus/licensing"
autoload :GitFetcher, "omnibus/fetchers/git_fetcher"
autoload :NetFetcher, "omnibus/fetchers/net_fetcher"
autoload :NullFetcher, "omnibus/fetchers/null_fetcher"
autoload :PathFetcher, "omnibus/fetchers/path_fetcher"
autoload :FileFetcher, "omnibus/fetchers/file_fetcher"
autoload :ArtifactoryPublisher, "omnibus/publishers/artifactory_publisher"
autoload :NullPublisher, "omnibus/publishers/null_publisher"
autoload :S3Publisher, "omnibus/publishers/s3_publisher"
autoload :Manifest, "omnibus/manifest"
autoload :ManifestEntry, "omnibus/manifest_entry"
autoload :ManifestDiff, "omnibus/manifest_diff"
autoload :ChangeLog, "omnibus/changelog"
autoload :GitRepository, "omnibus/git_repository"
autoload :SemanticVersion, "omnibus/semantic_version"
autoload :DependencyInformation, "omnibus/dependency_information"
module Command
autoload :Base, "omnibus/cli/base"
autoload :Cache, "omnibus/cli/cache"
autoload :Publish, "omnibus/cli/publish"
autoload :ChangeLog, "omnibus/cli/changelog"
end
class << self
#
# Reset the current Omnibus configuration. This is primary an internal API
# used in testing, but it can also be useful when Omnibus is used as a
# library.
#
# Note - this persists the +Logger+ object by default.
#
# @param [true, false] include_logger
# whether the logger object should be cleared as well
#
# @return [void]
#
def reset!(include_logger = false)
instance_variables.each do |instance_variable|
unless include_logger
next if instance_variable == :@logger
end
remove_instance_variable(instance_variable)
end
Config.reset!
# Clear caches on Project and Software
Project.reset!
Software.reset!
end
#
# The logger for this Omnibus instance.
#
# @example
# Omnibus.logger.debug { 'This is a message!' }
#
# @return [Logger]
#
def logger
@logger ||= Logger.new
end
#
# @api private
#
# Programatically set the logger for Omnibus.
#
# @param [Logger] logger
#
def logger=(logger)
@logger = logger
end
#
# The UI class for Omnibus.
#
# @return [Thor::Shell]
#
def ui
@ui ||= Thor::Base.shell.new
end
#
# Load in an Omnibus configuration file. Values will be merged with
# and override the defaults defined in {Config}.
#
# @param [String] file path to a configuration file to load
#
# @return [void]
#
def load_configuration(file)
Config.load(file)
end
#
# Locate an executable in the current $PATH.
#
# @return [String, nil]
# the path to the executable, or +nil+ if not present
#
def which(executable)
if File.file?(executable) && File.executable?(executable)
executable
elsif ENV["PATH"]
path = ENV["PATH"].split(File::PATH_SEPARATOR).find do |path|
File.executable?(File.join(path, executable))
end
path && File.expand_path(executable, path)
end
end
#
# All {Project} instances that have been loaded.
#
# @return [Array<:Project>]
#
def projects
project_map.map do |name, _|
Project.load(name)
end
end
#
# Load the {Project} instance with the given name.
#
# @param [String] name
# the name of the project to get
#
# @return [Project]
#
def project(name)
Project.load(name)
end
#
# The source root is the path to the root directory of the `omnibus` gem.
#
# @return [Pathname]
#
def source_root
@source_root ||= Pathname.new(File.expand_path("..", __dir__))
end
#
# The preferred filepath to a project with the given name on disk.
#
# @return [String, nil]
#
def project_path(name)
project_map[name.to_s]
end
#
# The preferred filepath to a software with the given name on disk.
#
# @return [String, nil]
#
def software_path(name)
software_map[name.to_s]
end
#
# The list of directories to search for the given +path+. These paths are
# returned **in order** of specificity.
#
# @param [String] path
# the subpath to search for
#
# @return [Array<String>]
#
def possible_paths_for(path)
possible_paths[path] ||= [
paths_from_project_root,
paths_from_local_software_dirs,
paths_from_software_gems,
].flatten.inject([]) do |array, directory|
destination = File.join(directory, path)
if File.directory?(destination)
array << destination
end
array
end
end
private
#
# The list of possible paths, cached as a hash for quick lookup.
#
# @see {Omnibus.possible_paths_for}
#
# @return [Hash]
#
def possible_paths
@possible_paths ||= {}
end
#
# Map the given file paths to the basename of their file, with the +.rb+
# extension removed.
#
# @example
# { 'foo' => '/path/to/foo' }
#
# @return [Hash<String, String>]
#
def basename_map(paths)
paths.inject({}) do |hash, directory|
Dir.glob("#{directory}/*.rb").each do |path|
name = File.basename(path, ".rb")
hash[name] ||= path
end
hash
end
end
#
# A hash of all softwares (by name) and their respective path on disk. These
# files are **in order**, meaning the software path is the **first**
# occurrence of the software in the list. If the same software is
# encountered a second time, it will be skipped.
#
# @example
# { 'preparation' => '/home/omnibus/project/config/software/preparation.rb' }
#
# @return [Hash<String, String>]
#
def software_map
@software_map ||= basename_map(possible_paths_for(Config.software_dir))
end
#
# A hash of all projects (by name) and their respective path on disk. These
# files are **in order**, meaning the project path is the **first**
# occurrence of the project in the list. If the same project is
# encountered a second time, it will be skipped.
#
# @example
# { 'chefdk' => '/home/omnibus/project/config/projects/chefdk.rb' }
#
# @return [Hash<String, String>]
#
def project_map
@project_map ||= basename_map(possible_paths_for(Config.project_dir))
end
#
# The list of all software paths to software from the project root. This is
# always a single value, but an array is returned for consistency with the
# other +software_paths_*+ methods.
#
# @see (Config#project_root)
# @see (Config#software_dir)
#
# @return [Array<String>]
#
def paths_from_project_root
@paths_from_project_root ||=
[Config.project_root]
end
#
# The list of all software paths on disk to software files. If relative
# paths are given, they are expanded relative to {Config#project_root}.
#
# @see (Config#local_software_dirs)
#
# @return [Array<String>]
#
def paths_from_local_software_dirs
@paths_from_local_software_dirs ||=
Array(Config.local_software_dirs).inject([]) do |array, path|
fullpath = File.expand_path(path, Config.project_root)
if File.directory?(fullpath)
array << fullpath
end
array
end
end
#
# The list of software paths from within the list of gems. These gems paths
# are loaded from disk using +Gem::Specification+. The latest version of
# the gem on disk is loaded. For this reason, it is recommended that you
# add these gems to your bundle and be nice to your co-workers.
#
# @see (Config#software_gems)
#
# @return [Array<String>]
#
def paths_from_software_gems
@paths_from_software_gems ||=
Array(Config.software_gems).inject([]) do |array, name|
if (spec = Gem::Specification.find_all_by_name(name).first)
array << File.expand_path(spec.gem_dir)
end
array
end
end
end
end