Class: Teapot::Configuration
- Inherits:
-
Definition
- Object
- Definition
- Teapot::Configuration
- Defined in:
- lib/teapot/configuration.rb
Overview
A configuration represents a mapping between package/dependency names and actual source locations. Usually, there is only one configuration, but in some cases it is useful to have more than one, e.g. one for local development using local source code, one for continuous integration, and one for deployment.
Defined Under Namespace
Classes: Import
Constant Summary collapse
- DEFAULT_OPTIONS =
{ :import => true }.freeze
Instance Attribute Summary collapse
-
#imports ⇒ Object
readonly
A list of other configurations to include when materialising the list of packages.
-
#options ⇒ Object
readonly
Options used to bind packages to this configuration.
-
#packages ⇒ Object
readonly
A list of packages which are required by this configuration.
-
#visibility ⇒ Object
readonly
Controls how the configuration is exposed in the context.
Attributes inherited from Definition
#context, #description, #name, #package
Instance Method Summary collapse
-
#[](key) ⇒ Object
Get a configuration option.
-
#[]=(key, value) ⇒ Object
Set a configuration option.
- #freeze ⇒ Object
-
#group ⇒ Object
Create a group for configuration options which will be only be active within the group block.
-
#import(name, explicit = true) ⇒ Object
Specifies that this package will import additional configuration records from another definition.
-
#initialize(context, package, name, packages = [], options = nil) ⇒ Configuration
constructor
A new instance of Configuration.
-
#load_all ⇒ Object
Load all packages defined by this configuration.
- #lock_path ⇒ Object
- #lock_store ⇒ Object
-
#materialize ⇒ Object
Process all import directives and return a new configuration based on the current configuration.
-
#merge(configuration, options) ⇒ Object
Merge an external configuration into this configuration.
-
#packages_path ⇒ Object
The path where packages will be located when fetched.
-
#platforms_path ⇒ Object
The path where built products will be installed.
- #public! ⇒ Object
- #public? ⇒ Boolean
-
#require(name, options = nil) ⇒ Object
Specifies that this configuration depends on an external package of some sort.
- #to_s ⇒ Object
-
#top! ⇒ Object
Conceptually, a configuration belongs to a package.
Methods inherited from Definition
Constructor Details
#initialize(context, package, name, packages = [], options = nil) ⇒ Configuration
Returns a new instance of Configuration.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/teapot/configuration.rb', line 39 def initialize(context, package, name, packages = [], = nil) super context, package, name if @options = else @options = DEFAULT_OPTIONS.dup end @packages = IdentitySet.new(packages) @imports = IdentitySet.new @visibility = :private end |
Instance Attribute Details
#imports ⇒ Object (readonly)
A list of other configurations to include when materialising the list of packages.
81 82 83 |
# File 'lib/teapot/configuration.rb', line 81 def imports @imports end |
#options ⇒ Object (readonly)
Options used to bind packages to this configuration.
75 76 77 |
# File 'lib/teapot/configuration.rb', line 75 def @options end |
#packages ⇒ Object (readonly)
A list of packages which are required by this configuration.
78 79 80 |
# File 'lib/teapot/configuration.rb', line 78 def packages @packages end |
#visibility ⇒ Object (readonly)
Controls how the configuration is exposed in the context.
64 65 66 |
# File 'lib/teapot/configuration.rb', line 64 def visibility @visibility end |
Instance Method Details
#[](key) ⇒ Object
Get a configuration option.
116 117 118 |
# File 'lib/teapot/configuration.rb', line 116 def [] key @options[key] end |
#[]=(key, value) ⇒ Object
Set a configuration option.
111 112 113 |
# File 'lib/teapot/configuration.rb', line 111 def []= key, value @options[key] = value end |
#freeze ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/teapot/configuration.rb', line 54 def freeze @options.freeze @packages.freeze @imports.freeze @visibility.freeze super end |
#group ⇒ Object
Create a group for configuration options which will be only be active within the group block.
102 103 104 105 106 107 108 |
# File 'lib/teapot/configuration.rb', line 102 def group = @options.dup yield @options = end |
#import(name, explicit = true) ⇒ Object
Specifies that this package will import additional configuration records from another definition.
97 98 99 |
# File 'lib/teapot/configuration.rb', line 97 def import(name, explicit = true) @imports << Import.new(name, explicit, @options.dup) end |
#load_all ⇒ Object
Load all packages defined by this configuration.
139 140 141 142 143 |
# File 'lib/teapot/configuration.rb', line 139 def load_all @packages.each do |package| @context.load(package) end end |
#lock_path ⇒ Object
130 131 132 |
# File 'lib/teapot/configuration.rb', line 130 def lock_path context.root + "#{@name}-lock.yml" end |
#lock_store ⇒ Object
134 135 136 |
# File 'lib/teapot/configuration.rb', line 134 def lock_store @lock_store ||= YAML::Store.new(lock_path.to_s) end |
#materialize ⇒ Object
Process all import directives and return a new configuration based on the current configuration. Import directives bring packages and other import directives from the specififed configuration definition.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/teapot/configuration.rb', line 151 def materialize # Potentially no materialization is required: return false if @imports.count == 0 # Avoid loops in the dependency chain: imported = IdentitySet.new # Enumerate all imports and attempt to resolve the packages: begin updated = false # Before trying to materialize, we should load all possible packages: @packages.each do |package| @context.load(package) rescue nil end imports = @imports @imports = IdentitySet.new imports.each do |import| named_configuration = @context.configurations[import.name] # So we don't get into some crazy cycle: next if imported.include? import # It would be nice if we could detect cycles and issue an error to the user. However, sometimes the case above is not hit at the point where the cycle begins - it isn't clear at what point the user explicitly created a cycle, and what configuration actually ends up being imported a second time. if named_configuration && named_configuration != self # Mark this as resolved imported << import updated = self.merge(named_configuration, import.) || updated else # It couldn't be resolved and hasn't already been resolved... @imports << import end end end while updated return true end |
#merge(configuration, options) ⇒ Object
Merge an external configuration into this configuration. We won’t override already defined packages.
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/teapot/configuration.rb', line 194 def merge(configuration, ) updated = false configuration.packages.each do |external_package| # The top level configuration will override packages that are defined by imported configurations. This is desirable behaviour, as it allows us to flatten the configuration but provide overrides if required. unless @packages.include? external_package = .merge(external_package.) @packages << Package.new(packages_path + external_package.name, external_package.name, ) updated = true end end configuration.imports.each do |external_import| unless @imports.include? external_import = .merge(external_import.) @imports << Import.new(external_import.name, external_import.explicit, ) updated = true end end return updated end |
#packages_path ⇒ Object
The path where packages will be located when fetched.
121 122 123 |
# File 'lib/teapot/configuration.rb', line 121 def packages_path context.root + "teapot/packages/#{name}" end |
#platforms_path ⇒ Object
The path where built products will be installed.
126 127 128 |
# File 'lib/teapot/configuration.rb', line 126 def platforms_path context.root + "teapot/platforms/#{name}" end |
#public! ⇒ Object
70 71 72 |
# File 'lib/teapot/configuration.rb', line 70 def public! @visibility = :public end |
#public? ⇒ Boolean
66 67 68 |
# File 'lib/teapot/configuration.rb', line 66 def public? @visibility == :public end |
#require(name, options = nil) ⇒ Object
Specifies that this configuration depends on an external package of some sort.
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/teapot/configuration.rb', line 84 def require(name, = nil) = ? @options.merge() : @options.dup @packages << Package.new(packages_path + name.to_s, name, ) if [:import] == true import(name, false) elsif String === [:import] import([:import]) end end |
#to_s ⇒ Object
221 222 223 |
# File 'lib/teapot/configuration.rb', line 221 def to_s "#<#{self.class} #{@name.dump} visibility=#{@visibility}>" end |
#top! ⇒ Object
Conceptually, a configuration belongs to a package. Primarily, a configuration lists dependent packages, but this also includes itself as the dependencies are purely target based, e.g. this configuration has access to any targets exposed by its own package.
146 147 148 |
# File 'lib/teapot/configuration.rb', line 146 def top! @packages << @package end |