halite 1.0.0.rc.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +20 -0
- data/.travis.yml +14 -4
- data/.yardopts +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +30 -8
- data/LICENSE +202 -202
- data/README.md +104 -2
- data/Rakefile +25 -5
- data/gemfiles/default.gemfile +17 -0
- data/gemfiles/master.gemfile +21 -0
- data/halite.gemspec +21 -10
- data/lib/berkshelf/halite.rb +25 -0
- data/lib/berkshelf/locations/gem.rb +84 -0
- data/lib/halite.rb +34 -4
- data/lib/halite/berkshelf/helper.rb +8 -2
- data/lib/halite/berkshelf/source.rb +9 -1
- data/lib/halite/converter.rb +34 -10
- data/lib/halite/converter/chef.rb +43 -0
- data/lib/halite/converter/libraries.rb +93 -26
- data/lib/halite/converter/metadata.rb +48 -10
- data/lib/halite/converter/misc.rb +43 -0
- data/lib/halite/dependencies.rb +48 -8
- data/lib/halite/error.rb +20 -0
- data/lib/halite/gem.rb +106 -21
- data/lib/halite/helper_base.rb +129 -0
- data/lib/halite/rake_helper.rb +46 -60
- data/lib/halite/rake_tasks.rb +17 -1
- data/lib/halite/spec_helper.rb +403 -54
- data/lib/halite/spec_helper/patcher.rb +130 -0
- data/lib/halite/spec_helper/runner.rb +57 -9
- data/lib/halite/version.rb +19 -1
- data/spec/converter/chef_spec.rb +54 -0
- data/spec/converter/libraries_spec.rb +131 -123
- data/spec/converter/metadata_spec.rb +61 -8
- data/spec/converter/misc_spec.rb +61 -0
- data/spec/converter_spec.rb +21 -6
- data/spec/dependencies_spec.rb +64 -10
- data/spec/example_resources/poise.rb +42 -0
- data/spec/example_resources/simple.rb +48 -0
- data/spec/{data/gems/test1/lib → fixtures/cookbooks/test1/files/halite_gem}/test1.rb +0 -0
- data/spec/{data/gems/test1/lib → fixtures/cookbooks/test1/files/halite_gem}/test1/version.rb +0 -0
- data/spec/fixtures/cookbooks/test1/libraries/default.rb +4 -0
- data/spec/{data/integration_cookbooks → fixtures/cookbooks}/test1/metadata.rb +0 -0
- data/spec/{data/gems/test2/chef → fixtures/cookbooks/test2}/attributes.rb +0 -0
- data/spec/{data/gems/test2/lib → fixtures/cookbooks/test2/files/halite_gem}/test2.rb +0 -0
- data/spec/{data/gems/test2/lib → fixtures/cookbooks/test2/files/halite_gem}/test2/resource.rb +0 -0
- data/spec/{data/gems/test2/lib → fixtures/cookbooks/test2/files/halite_gem}/test2/version.rb +0 -0
- data/spec/fixtures/cookbooks/test2/libraries/default.rb +3 -0
- data/spec/{data/integration_cookbooks → fixtures/cookbooks}/test2/metadata.rb +1 -1
- data/spec/{data/gems/test2/chef → fixtures/cookbooks/test2}/recipes/default.rb +0 -0
- data/spec/{data/gems/test2/chef → fixtures/cookbooks/test2}/templates/default/conf.erb +0 -0
- data/spec/{data/gems/test3/lib → fixtures/cookbooks/test3/files/halite_gem}/test3.rb +0 -0
- data/spec/{data/gems/test3/lib → fixtures/cookbooks/test3/files/halite_gem}/test3/dsl.rb +0 -0
- data/spec/{data/gems/test3/lib → fixtures/cookbooks/test3/files/halite_gem}/test3/version.rb +0 -0
- data/spec/fixtures/cookbooks/test3/libraries/default.rb +4 -0
- data/spec/{data/integration_cookbooks → fixtures/cookbooks}/test3/metadata.rb +0 -0
- data/spec/{data/gems/test3/chef → fixtures/cookbooks/test3}/recipes/default.rb +0 -0
- data/spec/{data → fixtures}/gems/test1/Rakefile +0 -0
- data/spec/fixtures/gems/test1/lib/test1.rb +2 -0
- data/spec/fixtures/gems/test1/lib/test1/version.rb +3 -0
- data/spec/{data → fixtures}/gems/test1/test1.gemspec +0 -0
- data/spec/{data → fixtures}/gems/test2/Rakefile +0 -0
- data/spec/{data/integration_cookbooks/test2 → fixtures/gems/test2/chef}/attributes.rb +0 -0
- data/spec/{data/integration_cookbooks/test2 → fixtures/gems/test2/chef}/recipes/default.rb +0 -0
- data/spec/{data/integration_cookbooks/test2 → fixtures/gems/test2/chef}/templates/default/conf.erb +0 -0
- data/spec/fixtures/gems/test2/lib/test2.rb +4 -0
- data/spec/{data/integration_cookbooks/test2/libraries/test2__resource.rb → fixtures/gems/test2/lib/test2/resource.rb} +1 -2
- data/spec/fixtures/gems/test2/lib/test2/version.rb +3 -0
- data/spec/{data → fixtures}/gems/test2/test2.gemspec +0 -0
- data/spec/{data → fixtures}/gems/test3/Rakefile +0 -0
- data/spec/{data/integration_cookbooks/test3 → fixtures/gems/test3/chef}/recipes/default.rb +0 -0
- data/spec/fixtures/gems/test3/lib/test3.rb +4 -0
- data/spec/{data/integration_cookbooks/test3/libraries/test3__dsl.rb → fixtures/gems/test3/lib/test3/dsl.rb} +1 -2
- data/spec/fixtures/gems/test3/lib/test3/version.rb +3 -0
- data/spec/{data → fixtures}/gems/test3/test3.gemspec +1 -0
- data/spec/gem_spec.rb +41 -31
- data/spec/integration_spec.rb +58 -82
- data/spec/runner_spec.rb +108 -0
- data/spec/spec_helper.rb +19 -26
- data/spec/spec_helper_spec.rb +238 -0
- metadata +124 -151
- data/lib/halite/converter/other.rb +0 -19
- data/lib/halite/converter/readme.rb +0 -20
- data/spec/converter/other_spec.rb +0 -56
- data/spec/converter/readme_spec.rb +0 -55
- data/spec/data/integration_cookbooks/test1/libraries/test1.rb +0 -3
- data/spec/data/integration_cookbooks/test1/libraries/test1__version.rb +0 -4
- data/spec/data/integration_cookbooks/test2/libraries/test2.rb +0 -5
- data/spec/data/integration_cookbooks/test2/libraries/test2__version.rb +0 -4
- data/spec/data/integration_cookbooks/test3/libraries/test3.rb +0 -5
- data/spec/data/integration_cookbooks/test3/libraries/test3__version.rb +0 -4
@@ -0,0 +1,130 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2015, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'chef/resource'
|
18
|
+
|
19
|
+
|
20
|
+
module Halite
|
21
|
+
module SpecHelper
|
22
|
+
# Utility methods to patch a resource or provider class in to Chef for the
|
23
|
+
# duration of a block.
|
24
|
+
#
|
25
|
+
# @since 1.0.0
|
26
|
+
# @api private
|
27
|
+
module Patcher
|
28
|
+
# Patch a class in to Chef for the duration of a block.
|
29
|
+
#
|
30
|
+
# @param name [String, Symbol] Name to create in snake-case (eg. :my_name).
|
31
|
+
# @param klass [Class] Class to patch in.
|
32
|
+
# @param mod [Module] Optional module to create a constant in.
|
33
|
+
# @param block [Proc] Block to execute while the patch is available.
|
34
|
+
# @return [void]
|
35
|
+
def self.patch(name, klass, mod=nil, &block)
|
36
|
+
patch_descendants_tracker(klass) do
|
37
|
+
patch_node_map(name, klass) do
|
38
|
+
patch_recipe_dsl(name, klass) do
|
39
|
+
if mod
|
40
|
+
patch_module(mod, name, klass, &block)
|
41
|
+
else
|
42
|
+
block.call
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Patch an object in to a global namespace for the duration of a block.
|
50
|
+
#
|
51
|
+
# @param mod [Module] Namespace to patch in to.
|
52
|
+
# @param name [String, Symbol] Name to create in snake-case (eg. :my_name).
|
53
|
+
# @param obj Object to patch in.
|
54
|
+
# @param block [Proc] Block to execute while the name is available.
|
55
|
+
# @return [void]
|
56
|
+
def self.patch_module(mod, name, obj, &block)
|
57
|
+
class_name = Chef::Mixin::ConvertToClassName.convert_to_class_name(name.to_s)
|
58
|
+
if mod.const_defined?(class_name, false)
|
59
|
+
old_class = mod.const_get(class_name, false)
|
60
|
+
# We are only allowed to patch over things installed by patch_module
|
61
|
+
raise "#{mod.name}::#{class_name} is already defined" if !old_class.instance_variable_get(:@poise_patch_module)
|
62
|
+
# Remove it before setting to avoid the redefinition warning
|
63
|
+
mod.send(:remove_const, class_name)
|
64
|
+
end
|
65
|
+
# Tag our objects so we know we are allowed to overwrite those, but not other stuff.
|
66
|
+
obj.instance_variable_set(:@poise_patch_module, true)
|
67
|
+
mod.const_set(class_name, obj)
|
68
|
+
begin
|
69
|
+
block.call
|
70
|
+
ensure
|
71
|
+
# Same as above, have to remove before set because warnings
|
72
|
+
mod.send(:remove_const, class_name)
|
73
|
+
mod.const_set(class_name, old_class) if old_class
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Patch an object in to Chef's DescendantsTracker system for the duration
|
78
|
+
# of a code block.
|
79
|
+
#
|
80
|
+
# @param klass [Class] Class to patch in.
|
81
|
+
# @param block [Proc] Block to execute while the patch is available.
|
82
|
+
# @return [void]
|
83
|
+
def self.patch_descendants_tracker(klass, &block)
|
84
|
+
begin
|
85
|
+
# Re-add to tracking.
|
86
|
+
Chef::Mixin::DescendantsTracker.store_inherited(klass.superclass, klass)
|
87
|
+
block.call
|
88
|
+
ensure
|
89
|
+
# Clean up after ourselves.
|
90
|
+
Chef::Mixin::DescendantsTracker.direct_descendants(klass.superclass).delete(klass)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Patch a class in to its node_map.
|
95
|
+
#
|
96
|
+
# @param name [Symbol] Name to patch in.
|
97
|
+
# @param klass [Class] Resource class to patch in.
|
98
|
+
# @param block [Proc] Block to execute while the patch is available.
|
99
|
+
# @return [void]
|
100
|
+
def self.patch_node_map(name, klass, &block)
|
101
|
+
begin
|
102
|
+
# Technically this is set to true on >=12.4, but this should work.
|
103
|
+
klass.node_map.set(name, klass)
|
104
|
+
block.call
|
105
|
+
ensure
|
106
|
+
# Sigh.
|
107
|
+
klass.node_map.instance_variable_get(:@map).delete(name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Patch a resource in to Chef's recipe DSL for the duration of a code
|
112
|
+
# block. This is a no-op before Chef 12.4.
|
113
|
+
#
|
114
|
+
# @param name [Symbol] Name to patch in.
|
115
|
+
# @param klass [Class] Resource class to patch in.
|
116
|
+
# @param block [Proc] Block to execute while the patch is available.
|
117
|
+
# @return [void]
|
118
|
+
def self.patch_recipe_dsl(name, klass, &block)
|
119
|
+
return block.call unless defined?(Chef::DSL::Resources.add_resource_dsl) && klass < Chef::Resource
|
120
|
+
begin
|
121
|
+
Chef::DSL::Resources.add_resource_dsl(name)
|
122
|
+
block.call
|
123
|
+
ensure
|
124
|
+
Chef::DSL::Resources.remove_resource_dsl(name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -14,28 +14,76 @@
|
|
14
14
|
# limitations under the License.
|
15
15
|
#
|
16
16
|
|
17
|
+
require 'chef/mixin/shell_out' # ಠ_ಠ Missing upstream require
|
17
18
|
require 'chef/recipe'
|
19
|
+
require 'chefspec/mixins/normalize' # ಠ_ಠ Missing upstream require
|
20
|
+
require 'chefspec/solo_runner'
|
21
|
+
|
22
|
+
require 'halite/error'
|
23
|
+
require 'halite/gem'
|
24
|
+
|
18
25
|
|
19
26
|
module Halite
|
20
27
|
module SpecHelper
|
28
|
+
# ChefSpec runner class with Halite customizations. This adds attribute
|
29
|
+
# options, Halite synthetic cookbook injection, and block-based recipes.
|
30
|
+
#
|
31
|
+
# @since 1.0.0
|
21
32
|
class Runner < ChefSpec::SoloRunner
|
22
|
-
def self.converge(&block)
|
23
|
-
|
24
|
-
|
33
|
+
def self.converge(*recipe_names, &block)
|
34
|
+
options = if recipe_names.last.is_a?(Hash)
|
35
|
+
# Was called with options
|
36
|
+
recipe_names.pop
|
37
|
+
else
|
38
|
+
{}
|
39
|
+
end
|
40
|
+
new(options).tap do |instance|
|
41
|
+
instance.converge(*recipe_names, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize(options={})
|
46
|
+
super(options) do |node|
|
47
|
+
# Allow inserting arbitrary attribute data in to the node
|
48
|
+
node.attributes.default = Chef::Mixin::DeepMerge.merge(node.attributes.default, options[:default_attributes]) if options[:default_attributes]
|
49
|
+
node.attributes.normal = Chef::Mixin::DeepMerge.merge(node.attributes.normal, options[:normal_attributes]) if options[:normal_attributes]
|
50
|
+
node.attributes.override = Chef::Mixin::DeepMerge.merge(node.attributes.override, options[:override_attributes]) if options[:override_attributes]
|
51
|
+
# Store the gemspec for later use
|
52
|
+
@halite_gemspec = options[:halite_gemspec]
|
25
53
|
end
|
26
54
|
end
|
27
55
|
|
28
|
-
def converge(&block)
|
29
|
-
|
30
|
-
|
31
|
-
|
56
|
+
def converge(*recipe_names, &block)
|
57
|
+
raise Halite::Error.new('Cannot pass both recipe names and a recipe block to converge') if !recipe_names.empty? && block
|
58
|
+
super(*recipe_names) do
|
59
|
+
add_halite_cookbook(node, @halite_gemspec) if @halite_gemspec
|
60
|
+
if block
|
61
|
+
recipe = Chef::Recipe.new(nil, nil, run_context)
|
62
|
+
recipe.instance_exec(&block)
|
63
|
+
end
|
32
64
|
end
|
33
65
|
end
|
34
66
|
|
35
67
|
private
|
36
68
|
|
37
|
-
|
38
|
-
|
69
|
+
def add_halite_cookbook(node, gemspec)
|
70
|
+
gem_data = Halite::Gem.new(gemspec)
|
71
|
+
# Catch any dependency loops.
|
72
|
+
return if run_context.cookbook_collection.include?(gem_data.cookbook_name)
|
73
|
+
run_context.cookbook_collection[gem_data.cookbook_name] = gem_data.as_cookbook_version
|
74
|
+
gem_data.cookbook_dependencies.each do |dep|
|
75
|
+
add_halite_cookbook(node, dep.spec) if dep.spec
|
76
|
+
end
|
77
|
+
# Load attributes if any.
|
78
|
+
gem_data.each_file('chef/attributes') do |_full_path, rel_path|
|
79
|
+
raise Halite::Error.new("Chef does not support nested attribute files: #{rel_path}") if rel_path.include?(File::SEPARATOR)
|
80
|
+
name = File.basename(rel_path, '.rb')
|
81
|
+
node.include_attribute("#{gem_data.cookbook_name}::#{name}")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Don't try to autodetect the calling cookbook.
|
86
|
+
def calling_cookbook_path(_kaller)
|
39
87
|
File.expand_path('../empty', __FILE__)
|
40
88
|
end
|
41
89
|
end
|
data/lib/halite/version.rb
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2015, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
|
1
18
|
module Halite
|
2
|
-
|
19
|
+
# Halite version.
|
20
|
+
VERSION = '1.0.0'
|
3
21
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2015, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
|
19
|
+
describe Halite::Converter::Chef do
|
20
|
+
describe '#write' do
|
21
|
+
let(:files) { [] }
|
22
|
+
let(:gem_data) do
|
23
|
+
instance_double('Halite::Gem').tap do |d|
|
24
|
+
allow(d).to receive(:each_file) do |&block|
|
25
|
+
files.each {|path| block.call(File.join('/source', path), path) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
subject { described_class.write(gem_data, '/test') }
|
30
|
+
|
31
|
+
context 'with a single file' do
|
32
|
+
let(:files) { ['recipes/default.rb'] }
|
33
|
+
|
34
|
+
it do
|
35
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/recipes')
|
36
|
+
expect(FileUtils).to receive(:copy).with('/source/recipes/default.rb', '/test/recipes/default.rb', preserve: true)
|
37
|
+
subject
|
38
|
+
end
|
39
|
+
end # /context with a single file
|
40
|
+
|
41
|
+
context 'with multiple files' do
|
42
|
+
let(:files) { ['attributes.rb', 'recipes/default.rb', 'templates/default/conf.erb'] }
|
43
|
+
|
44
|
+
it do
|
45
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/recipes')
|
46
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/templates/default')
|
47
|
+
expect(FileUtils).to receive(:copy).with('/source/attributes.rb', '/test/attributes.rb', preserve: true)
|
48
|
+
expect(FileUtils).to receive(:copy).with('/source/recipes/default.rb', '/test/recipes/default.rb', preserve: true)
|
49
|
+
expect(FileUtils).to receive(:copy).with('/source/templates/default/conf.erb', '/test/templates/default/conf.erb', preserve: true)
|
50
|
+
subject
|
51
|
+
end
|
52
|
+
end # /context with multiple files
|
53
|
+
end # /describe #write
|
54
|
+
end
|
@@ -1,152 +1,160 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2015, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
1
17
|
require 'spec_helper'
|
2
18
|
require 'halite/converter/libraries'
|
3
19
|
|
4
20
|
describe Halite::Converter::Libraries do
|
21
|
+
describe '#generate_bootstrap' do
|
22
|
+
let(:gem_data) { instance_double('Halite::Gem', license_header: '') }
|
23
|
+
let(:entry_points) { [] }
|
24
|
+
subject { described_class.generate_bootstrap(gem_data, entry_points) }
|
5
25
|
|
6
|
-
|
7
|
-
let(:data) { '' }
|
8
|
-
let(:entry_point) { false }
|
9
|
-
let(:cookbook_dependencies) { [] }
|
10
|
-
subject { described_class.generate(double(name: 'mygem', cookbook_dependencies: cookbook_dependencies.map {|dep| Halite::Dependencies::Dependency.new(dep, nil, :dependencies) }), data, entry_point) }
|
11
|
-
|
12
|
-
context 'with a single require' do
|
13
|
-
let(:data) { "x = 1\nrequire 'mygem/version'\n" }
|
26
|
+
context 'with defaults' do
|
14
27
|
it { is_expected.to eq <<-EOH }
|
15
|
-
|
16
|
-
|
17
|
-
end
|
28
|
+
raise 'Halite is not compatible with no_lazy_load false, please set no_lazy_load true in your Chef configuration file.' unless Chef::Config[:no_lazy_load]
|
29
|
+
$LOAD_PATH << File.expand_path('../../files/halite_gem', __FILE__)
|
18
30
|
EOH
|
19
|
-
end # /context with
|
31
|
+
end # /context with defaults
|
20
32
|
|
21
|
-
context 'with
|
22
|
-
|
33
|
+
context 'with a license header' do
|
34
|
+
before do
|
35
|
+
allow(gem_data).to receive(:license_header).and_return("# Copyright me.\n")
|
36
|
+
end
|
23
37
|
it { is_expected.to eq <<-EOH }
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
# Copyright me.
|
39
|
+
raise 'Halite is not compatible with no_lazy_load false, please set no_lazy_load true in your Chef configuration file.' unless Chef::Config[:no_lazy_load]
|
40
|
+
$LOAD_PATH << File.expand_path('../../files/halite_gem', __FILE__)
|
27
41
|
EOH
|
28
|
-
end
|
42
|
+
end
|
29
43
|
|
30
|
-
context 'with
|
31
|
-
let(:
|
32
|
-
let(:entry_point) { true }
|
33
|
-
it { is_expected.to eq <<-EOH }
|
34
|
-
ENV['HALITE_LOAD'] = '1'; begin; x = 1
|
35
|
-
require_relative 'mygem__version'
|
36
|
-
ensure; ENV.delete('HALITE_LOAD'); end
|
37
|
-
EOH
|
38
|
-
end # /context with an entry point
|
39
|
-
|
40
|
-
context 'with a big script' do
|
41
|
-
let(:data) { <<-EOH }
|
42
|
-
require 'mygem/something'
|
43
|
-
require 'mygem/utils'
|
44
|
-
require 'activesupport' # ಠ_ಠ
|
45
|
-
class Resource
|
46
|
-
attribute :source
|
47
|
-
end
|
48
|
-
EOH
|
49
|
-
it { is_expected.to eq <<-EOH }
|
50
|
-
if ENV['HALITE_LOAD']; require_relative 'mygem__something'
|
51
|
-
require_relative 'mygem__utils'
|
52
|
-
require 'activesupport' # ಠ_ಠ
|
53
|
-
class Resource
|
54
|
-
attribute :source
|
55
|
-
end
|
56
|
-
end
|
57
|
-
EOH
|
58
|
-
end # /context with a big script
|
59
|
-
|
60
|
-
context 'with external dependencies' do
|
61
|
-
let(:cookbook_dependencies) { ['other'] }
|
62
|
-
let(:data) { <<-EOH }
|
63
|
-
require 'mygem/something'
|
64
|
-
require 'mygem/utils'
|
65
|
-
require "mygem"
|
66
|
-
require 'other'
|
67
|
-
class Resource
|
68
|
-
attribute :source
|
69
|
-
end
|
70
|
-
EOH
|
44
|
+
context 'with entry points' do
|
45
|
+
let(:entry_points) { %w{mygem/one mygem/two} }
|
71
46
|
it { is_expected.to eq <<-EOH }
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
class Resource
|
77
|
-
attribute :source
|
78
|
-
end
|
79
|
-
end
|
47
|
+
raise 'Halite is not compatible with no_lazy_load false, please set no_lazy_load true in your Chef configuration file.' unless Chef::Config[:no_lazy_load]
|
48
|
+
$LOAD_PATH << File.expand_path('../../files/halite_gem', __FILE__)
|
49
|
+
require "mygem/one"
|
50
|
+
require "mygem/two"
|
80
51
|
EOH
|
81
|
-
end # /context with
|
82
|
-
end # /describe #
|
52
|
+
end # /context with entry points
|
53
|
+
end # /describe #generate_bootstrap
|
83
54
|
|
84
|
-
describe '#
|
55
|
+
describe '#write_libraries' do
|
85
56
|
let(:library_files) { [] }
|
86
|
-
let(:
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
-
spec
|
93
|
-
end
|
94
|
-
before do
|
95
|
-
first = true
|
96
|
-
library_files.each do |path|
|
97
|
-
input_sentinel = double("content of #{path}")
|
98
|
-
output_sentinel = double("generated output for #{path}")
|
99
|
-
allow(IO).to receive(:read).with(File.join('/source', path)).and_return(input_sentinel)
|
100
|
-
allow(described_class).to receive(:generate).with(spec, input_sentinel, first).and_return(output_sentinel)
|
101
|
-
first = false
|
102
|
-
output << output_sentinel
|
57
|
+
let(:gem_data) do
|
58
|
+
instance_double('Halite::Gem').tap do |d|
|
59
|
+
allow(d).to receive(:each_library_file) do |&block|
|
60
|
+
library_files.each {|path| block.call(File.join('/source', path), path) }
|
61
|
+
end
|
103
62
|
end
|
104
|
-
allow(File).to receive(:directory?).and_return(false) # Always blank
|
105
63
|
end
|
64
|
+
subject { described_class.write_libraries(gem_data, '/test') }
|
106
65
|
|
107
66
|
context 'with a single file' do
|
108
|
-
let(:library_files) {
|
109
|
-
|
110
|
-
|
111
|
-
expect(
|
112
|
-
|
113
|
-
described_class.write(spec, '/test')
|
67
|
+
let(:library_files) { %w{mygem.rb} }
|
68
|
+
it do
|
69
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/files/halite_gem')
|
70
|
+
expect(FileUtils).to receive(:copy).with('/source/mygem.rb', '/test/files/halite_gem/mygem.rb', preserve: true)
|
71
|
+
subject
|
114
72
|
end
|
115
73
|
end # /context with a single file
|
116
74
|
|
117
|
-
context 'with multiple files' do
|
118
|
-
let(:library_files) {
|
119
|
-
|
120
|
-
|
121
|
-
expect(
|
122
|
-
expect(
|
123
|
-
expect(
|
124
|
-
expect(
|
125
|
-
|
75
|
+
context 'with a multiple files' do
|
76
|
+
let(:library_files) { %w{mygem.rb mygem/one.rb mygem/two.rb} }
|
77
|
+
it do
|
78
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/files/halite_gem')
|
79
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/files/halite_gem/mygem').twice
|
80
|
+
expect(FileUtils).to receive(:copy).with('/source/mygem.rb', '/test/files/halite_gem/mygem.rb', preserve: true)
|
81
|
+
expect(FileUtils).to receive(:copy).with('/source/mygem/one.rb', '/test/files/halite_gem/mygem/one.rb', preserve: true)
|
82
|
+
expect(FileUtils).to receive(:copy).with('/source/mygem/two.rb', '/test/files/halite_gem/mygem/two.rb', preserve: true)
|
83
|
+
subject
|
126
84
|
end
|
127
|
-
end # /context with multiple files
|
128
|
-
|
129
|
-
context 'with an explicit entry point name' do
|
130
|
-
let(:library_files) { ['mygem.rb', 'other.rb'] }
|
85
|
+
end # /context with a multiple files
|
86
|
+
end # /describe #write_libraries
|
131
87
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
88
|
+
describe '#find_default_entry_points' do
|
89
|
+
let(:library_files) { [] }
|
90
|
+
let(:gem_data) do
|
91
|
+
instance_double('Halite::Gem').tap do |d|
|
92
|
+
allow(d).to receive(:each_library_file) do |&block|
|
93
|
+
library_files.each {|path| block.call(File.join('/source', path), path) }
|
94
|
+
end
|
137
95
|
end
|
138
|
-
end
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
it
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
96
|
+
end
|
97
|
+
subject { described_class.find_default_entry_points(gem_data) }
|
98
|
+
|
99
|
+
context 'with no default entry points' do
|
100
|
+
let(:library_files) { %w{mygem.rb} }
|
101
|
+
it { is_expected.to eq [] }
|
102
|
+
end # /context with no default entry points
|
103
|
+
|
104
|
+
context 'with a single entry point' do
|
105
|
+
let(:library_files) { %w{mygem.rb mygem/cheftie.rb} }
|
106
|
+
it { is_expected.to eq ['mygem/cheftie'] }
|
107
|
+
end # /context with a single entry point
|
108
|
+
|
109
|
+
context 'with multiple entry points' do
|
110
|
+
let(:library_files) { %w{mygem.rb mygem/cheftie.rb mygem/other.rb mygem/other/cheftie.rb} }
|
111
|
+
it { is_expected.to eq ['mygem/cheftie', 'mygem/other/cheftie'] }
|
112
|
+
end # /context with multiple entry points
|
113
|
+
end # /describe #find_default_entry_points
|
114
|
+
|
115
|
+
describe '#write_bootstrap' do
|
116
|
+
let(:entry_point) { nil }
|
117
|
+
let(:spec) { instance_double('Gem::Specification', metadata: {})}
|
118
|
+
let(:gem_data) { instance_double('Halite::Gem', spec: spec) }
|
119
|
+
let(:output) { double('output sentinel') }
|
120
|
+
subject { described_class.write_bootstrap(gem_data, '/test', entry_point) }
|
121
|
+
|
122
|
+
context 'with defaults' do
|
123
|
+
it do
|
124
|
+
expect(described_class).to receive(:find_default_entry_points).with(gem_data).and_return([])
|
125
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/libraries')
|
126
|
+
expect(described_class).to receive(:generate_bootstrap).with(gem_data, []).and_return(output)
|
127
|
+
expect(IO).to receive(:write).with('/test/libraries/default.rb', output)
|
128
|
+
subject
|
148
129
|
end
|
149
|
-
end # /context with
|
130
|
+
end # /context with defaults
|
131
|
+
|
132
|
+
context 'with an explicit entry point' do
|
133
|
+
let(:entry_point) { 'mygem/one' }
|
134
|
+
it do
|
135
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/libraries')
|
136
|
+
expect(described_class).to receive(:generate_bootstrap).with(gem_data, ['mygem/one']).and_return(output)
|
137
|
+
expect(IO).to receive(:write).with('/test/libraries/default.rb', output)
|
138
|
+
subject
|
139
|
+
end
|
140
|
+
end # /context with an explicit entry point
|
141
|
+
|
142
|
+
context 'with metadata entry points' do
|
143
|
+
it do
|
144
|
+
allow(spec).to receive(:metadata).and_return({'halite_entry_point' => 'mygem/one mygem/two'})
|
145
|
+
expect(FileUtils).to receive(:mkdir_p).with('/test/libraries')
|
146
|
+
expect(described_class).to receive(:generate_bootstrap).with(gem_data, ['mygem/one', 'mygem/two']).and_return(output)
|
147
|
+
expect(IO).to receive(:write).with('/test/libraries/default.rb', output)
|
148
|
+
subject
|
149
|
+
end
|
150
|
+
end # /context with metadata entry points
|
151
|
+
end # /describe #write_bootstrap
|
150
152
|
|
153
|
+
describe '#write' do
|
154
|
+
it do
|
155
|
+
expect(described_class).to receive(:write_libraries)
|
156
|
+
expect(described_class).to receive(:write_bootstrap)
|
157
|
+
described_class.write(nil, nil)
|
158
|
+
end
|
151
159
|
end # /describe #write
|
152
160
|
end
|