lib/licensed/configuration.rb in licensed-2.8.0 vs lib/licensed/configuration.rb in licensed-2.9.0
- old
+ new
@@ -2,44 +2,43 @@
require "pathname"
module Licensed
class AppConfiguration < Hash
DEFAULT_CACHE_PATH = ".licenses".freeze
- DEFAULT_CONFIG_FILES = [
- ".licensed.yml".freeze,
- ".licensed.yaml".freeze,
- ".licensed.json".freeze
- ].freeze
+ # Returns the root for a configuration in following order of precendence:
+ # 1. explicitly configured "root" property
+ # 2. a found git repository root
+ # 3. the current directory
+ def self.root_for(configuration)
+ configuration["root"] || Licensed::Git.repository_root || Dir.pwd
+ end
+
def initialize(options = {}, inherited_options = {})
super()
# update order:
# 1. anything inherited from root config
- # 2. app defaults
- # 3. explicitly configured app settings
+ # 2. explicitly configured app settings
update(inherited_options)
- update(defaults_for(options, inherited_options))
update(options)
+ verify_arg "source_path"
self["sources"] ||= {}
self["reviewed"] ||= {}
self["ignored"] ||= {}
self["allowed"] ||= []
-
- # default the root to the git repository root,
- # or the current directory if no other options are available
- self["root"] ||= Licensed::Git.repository_root || Dir.pwd
-
- verify_arg "source_path"
- verify_arg "cache_path"
+ self["root"] = AppConfiguration.root_for(self)
+ # defaults to the directory name of the source path if not set
+ self["name"] ||= File.basename(self["source_path"])
+ # setting the cache path might need a valid app name
+ self["cache_path"] = detect_cache_path(options, inherited_options)
end
# Returns the path to the workspace root as a Pathname.
- # Defaults to Licensed::Git.repository_root if not explicitly set
def root
- Pathname.new(self["root"])
+ @root ||= Pathname.new(self["root"])
end
# Returns the path to the app cache directory as a Pathname
def cache_path
root.join(self["cache_path"])
@@ -100,29 +99,40 @@
self["allowed"] << license
end
private
- def defaults_for(options, inherited_options)
- name = options["name"] || File.basename(options["source_path"])
+ # Returns the cache path for the application based on:
+ # 1. An explicitly set cache path for the application, if set
+ # 2. An inherited root cache path joined with the app name
+ # 3. The default cache path joined with the app name
+ def detect_cache_path(options, inherited_options)
+ return options["cache_path"] unless options["cache_path"].to_s.empty?
+
cache_path = inherited_options["cache_path"] || DEFAULT_CACHE_PATH
- {
- "name" => name,
- "cache_path" => File.join(cache_path, name)
- }
+ File.join(cache_path, self["name"])
end
def verify_arg(property)
return if self[property]
raise Licensed::Configuration::LoadError,
"App #{self["name"]} is missing required property #{property}"
end
end
- class Configuration < AppConfiguration
+ class Configuration
+ DEFAULT_CONFIG_FILES = [
+ ".licensed.yml".freeze,
+ ".licensed.yaml".freeze,
+ ".licensed.json".freeze
+ ].freeze
+
class LoadError < StandardError; end
+ # An array of the applications in this licensed configuration.
+ attr_reader :apps
+
# Loads and returns a Licensed::Configuration object from the given path.
# The path can be relative or absolute, and can point at a file or directory.
# If the path given is a directory, the directory will be searched for a
# `config.yml` file.
def self.load_from(path)
@@ -131,25 +141,40 @@
Configuration.new(parse_config(config_path))
end
def initialize(options = {})
apps = options.delete("apps") || []
- super(default_options.merge(options))
-
- self["apps"] = apps.map { |app| AppConfiguration.new(app, options) }
+ apps << default_options.merge(options) if apps.empty?
+ apps = apps.flat_map { |app| self.class.expand_app_source_path(app) }
+ @apps = apps.map { |app| AppConfiguration.new(app, options) }
end
- # Returns an array of the applications for this licensed configuration.
- # If the configuration did not explicitly configure any applications,
- # return self as an application configuration.
- def apps
- return [self] if self["apps"].empty?
- self["apps"]
- end
-
private
+ def self.expand_app_source_path(app_config)
+ return app_config if app_config["source_path"].to_s.empty?
+
+ source_path = File.expand_path(app_config["source_path"], AppConfiguration.root_for(app_config))
+ expanded_source_paths = Dir.glob(source_path).select { |p| File.directory?(p) }
+ # return the original configuration if glob didn't result in multiple paths
+ return app_config if expanded_source_paths.size <= 1
+
+ # map the expanded paths to new application configurations
+ expanded_source_paths.map do |path|
+ config = app_config.merge("source_path" => path)
+
+ # update configured values for name and cache_path for uniqueness.
+ # this is only needed when values are explicitly set, AppConfiguration
+ # will handle configurations that don't have these explicitly set
+ dir_name = File.basename(path)
+ config["name"] = "#{config["name"]}-#{dir_name}" if config["name"]
+ config["cache_path"] = File.join(config["cache_path"], dir_name) if config["cache_path"]
+
+ config
+ end
+ end
+
# Find a default configuration file in the given directory.
# File preference is given by the order of elements in DEFAULT_CONFIG_FILES
#
# Raises Licensed::Configuration::LoadError if a file isn't found
def self.find_config(directory)
@@ -196,10 +221,10 @@
def default_options
# manually set a cache path without additional name
{
"source_path" => Dir.pwd,
- "cache_path" => DEFAULT_CACHE_PATH
+ "cache_path" => AppConfiguration::DEFAULT_CACHE_PATH
}
end
end
end