berkshelf 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/.gitignore +20 -0
  2. data/.rbenv-version +1 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +23 -0
  5. data/LICENSE +22 -0
  6. data/README.rdoc +102 -0
  7. data/Thorfile +47 -0
  8. data/berkshelf.gemspec +39 -0
  9. data/features/config.sample.yml +3 -0
  10. data/features/init_command.feature +40 -0
  11. data/features/install.feature +55 -0
  12. data/features/lockfile.feature +22 -0
  13. data/features/step_definitions/chef_server_steps.rb +13 -0
  14. data/features/step_definitions/cli_steps.rb +56 -0
  15. data/features/step_definitions/filesystem_steps.rb +79 -0
  16. data/features/support/env.rb +55 -0
  17. data/features/update.feature +23 -0
  18. data/features/upload_command.feature +43 -0
  19. data/features/without.feature +25 -0
  20. data/lib/berkshelf.rb +90 -0
  21. data/lib/berkshelf/berksfile.rb +170 -0
  22. data/lib/berkshelf/cached_cookbook.rb +253 -0
  23. data/lib/berkshelf/cookbook_source.rb +139 -0
  24. data/lib/berkshelf/cookbook_source/git_location.rb +54 -0
  25. data/lib/berkshelf/cookbook_source/path_location.rb +27 -0
  26. data/lib/berkshelf/cookbook_source/site_location.rb +206 -0
  27. data/lib/berkshelf/cookbook_store.rb +77 -0
  28. data/lib/berkshelf/core_ext.rb +3 -0
  29. data/lib/berkshelf/core_ext/file.rb +14 -0
  30. data/lib/berkshelf/core_ext/kernel.rb +33 -0
  31. data/lib/berkshelf/core_ext/pathname.rb +24 -0
  32. data/lib/berkshelf/downloader.rb +92 -0
  33. data/lib/berkshelf/dsl.rb +39 -0
  34. data/lib/berkshelf/errors.rb +20 -0
  35. data/lib/berkshelf/generator_files/Berksfile.erb +3 -0
  36. data/lib/berkshelf/generator_files/chefignore +44 -0
  37. data/lib/berkshelf/git.rb +70 -0
  38. data/lib/berkshelf/init_generator.rb +38 -0
  39. data/lib/berkshelf/lockfile.rb +42 -0
  40. data/lib/berkshelf/resolver.rb +176 -0
  41. data/lib/berkshelf/tx_result.rb +12 -0
  42. data/lib/berkshelf/tx_result_set.rb +37 -0
  43. data/lib/berkshelf/uploader.rb +153 -0
  44. data/lib/berkshelf/version.rb +3 -0
  45. data/lib/chef/knife/berks_init.rb +29 -0
  46. data/lib/chef/knife/berks_install.rb +27 -0
  47. data/lib/chef/knife/berks_update.rb +23 -0
  48. data/lib/chef/knife/berks_upload.rb +39 -0
  49. data/spec/fixtures/Berksfile +3 -0
  50. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/README.md +12 -0
  51. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +6 -0
  52. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/recipes/default.rb +8 -0
  53. data/spec/fixtures/cookbooks/example_cookbook/README.md +12 -0
  54. data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +6 -0
  55. data/spec/fixtures/cookbooks/example_cookbook/recipes/default.rb +8 -0
  56. data/spec/fixtures/cookbooks/invalid_ruby_files-1.0.0/recipes/default.rb +1 -0
  57. data/spec/fixtures/cookbooks/invalid_template_files-1.0.0/templates/default/broken.erb +1 -0
  58. data/spec/fixtures/cookbooks/nginx-0.100.5/README.md +77 -0
  59. data/spec/fixtures/cookbooks/nginx-0.100.5/attributes/default.rb +65 -0
  60. data/spec/fixtures/cookbooks/nginx-0.100.5/definitions/nginx_site.rb +35 -0
  61. data/spec/fixtures/cookbooks/nginx-0.100.5/files/default/mime.types +73 -0
  62. data/spec/fixtures/cookbooks/nginx-0.100.5/files/ubuntu/mime.types +73 -0
  63. data/spec/fixtures/cookbooks/nginx-0.100.5/libraries/nginxlib.rb +1 -0
  64. data/spec/fixtures/cookbooks/nginx-0.100.5/metadata.rb +91 -0
  65. data/spec/fixtures/cookbooks/nginx-0.100.5/providers/defprovider.rb +1 -0
  66. data/spec/fixtures/cookbooks/nginx-0.100.5/recipes/default.rb +59 -0
  67. data/spec/fixtures/cookbooks/nginx-0.100.5/resources/defresource.rb +1 -0
  68. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/nginx.pill.erb +15 -0
  69. data/spec/fixtures/cookbooks/nginx-0.100.5/templates/default/plugins/nginx.rb.erb +66 -0
  70. data/spec/fixtures/lockfile_spec/with_lock/Berksfile +1 -0
  71. data/spec/fixtures/lockfile_spec/without_lock/Berksfile.lock +5 -0
  72. data/spec/spec_helper.rb +92 -0
  73. data/spec/support/chef_api.rb +27 -0
  74. data/spec/support/matchers/file_system_matchers.rb +115 -0
  75. data/spec/support/matchers/filepath_matchers.rb +19 -0
  76. data/spec/unit/berkshelf/cached_cookbook_spec.rb +420 -0
  77. data/spec/unit/berkshelf/cookbook_source/git_location_spec.rb +59 -0
  78. data/spec/unit/berkshelf/cookbook_source/path_location_spec.rb +34 -0
  79. data/spec/unit/berkshelf/cookbook_source/site_location_spec.rb +166 -0
  80. data/spec/unit/berkshelf/cookbook_source_spec.rb +194 -0
  81. data/spec/unit/berkshelf/cookbook_store_spec.rb +71 -0
  82. data/spec/unit/berkshelf/cookbookfile_spec.rb +160 -0
  83. data/spec/unit/berkshelf/downloader_spec.rb +82 -0
  84. data/spec/unit/berkshelf/dsl_spec.rb +42 -0
  85. data/spec/unit/berkshelf/git_spec.rb +63 -0
  86. data/spec/unit/berkshelf/init_generator_spec.rb +52 -0
  87. data/spec/unit/berkshelf/lockfile_spec.rb +25 -0
  88. data/spec/unit/berkshelf/resolver_spec.rb +126 -0
  89. data/spec/unit/berkshelf/tx_result_set_spec.rb +77 -0
  90. data/spec/unit/berkshelf/tx_result_spec.rb +21 -0
  91. data/spec/unit/berkshelf/uploader_spec.rb +71 -0
  92. data/spec/unit/berkshelf_spec.rb +29 -0
  93. metadata +411 -0
@@ -0,0 +1,79 @@
1
+ require 'aruba/api'
2
+
3
+ World(Aruba::Api)
4
+
5
+ Given /^a cookbook named "(.*?)"$/ do |name|
6
+ steps %{
7
+ Given a directory named "#{name}"
8
+ And an empty file named "#{name}/metadata.rb"
9
+ }
10
+ end
11
+
12
+ Given /^I do not have a Berksfile$/ do
13
+ in_current_dir { FileUtils.rm_f(Berkshelf::DEFAULT_FILENAME) }
14
+ end
15
+
16
+ Given /^I do not have a Berksfile\.lock$/ do
17
+ in_current_dir { FileUtils.rm_f(Berkshelf::Lockfile::DEFAULT_FILENAME) }
18
+ end
19
+
20
+ Given /^the cookbook "(.*?)" has the file "(.*?)" with:$/ do |cookbook_name, file_name, content|
21
+ write_file(File.join(cookbook_name, file_name), content)
22
+ end
23
+
24
+ Then /^the cookbook store should have the cookbooks:$/ do |cookbooks|
25
+ cookbooks.raw.each do |name, version|
26
+ cookbook_store.should have_structure {
27
+ directory "#{name}-#{version}" do
28
+ file "metadata.rb" do
29
+ contains version
30
+ end
31
+ end
32
+ }
33
+ end
34
+ end
35
+
36
+ Then /^the cookbook store should not have the cookbooks:$/ do |cookbooks|
37
+ cookbooks.raw.each do |name, version|
38
+ cookbook_store.should_not have_structure {
39
+ directory "#{name}-#{version}"
40
+ }
41
+ end
42
+ end
43
+
44
+ Then /^the cookbook "(.*?)" should have the following files:$/ do |name, files|
45
+ check_file_presence(files.raw.map{|file_row| File.join(name, file_row[0])}, true)
46
+ end
47
+
48
+ Then /^the file "(.*?)" in the cookbook "(.*?)" should contain:$/ do |file_name, cookbook_name, content|
49
+ Pathname.new(current_dir).join(cookbook_name).should have_structure {
50
+ file "Berksfile" do
51
+ contains content
52
+ end
53
+ file ".chefignore"
54
+ }
55
+ end
56
+
57
+ Then /^the directory "(.*?)" should have the following files:$/ do |name, files|
58
+ check_file_presence(files.raw.map{|file_row| File.join(name, file_row[0])}, true)
59
+ end
60
+
61
+ Then /^the directory "(.*?)" should not have the following files:$/ do |name, files|
62
+ check_file_presence(files.raw.map{|file_row| File.join(name, file_row[0])}, false)
63
+ end
64
+
65
+ Then /^the file "(.*?)" in the directory "(.*?)" should not contain:$/ do |file_name, directory_name, content|
66
+ Pathname.new(current_dir).join(directory_name).should_not have_structure {
67
+ file "Berksfile" do
68
+ contains content
69
+ end
70
+ }
71
+ end
72
+
73
+ Then /^the current directory should have the following files:$/ do |files|
74
+ check_file_presence(files.raw.map{|file_row| file_row[0]}, true)
75
+ end
76
+
77
+ Then /^the current directory should not have the following files:$/ do |files|
78
+ check_file_presence(files.raw.map{|file_row| file_row[0]}, false)
79
+ end
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+ require 'spork'
5
+
6
+ Spork.prefork do
7
+ require 'rspec'
8
+ require 'pp'
9
+ require 'aruba/cucumber'
10
+ require 'vcr'
11
+
12
+ APP_ROOT = File.expand_path('../../../', __FILE__)
13
+
14
+ ENV["BERKSHELF_PATH"] = File.join(APP_ROOT, "tmp", "berkshelf")
15
+
16
+ Dir[File.join(APP_ROOT, "spec/support/**/*.rb")].each {|f| require f}
17
+
18
+ Around do |scenario, block|
19
+ VCR.use_cassette(scenario.title) do
20
+ block.call
21
+ end
22
+ end
23
+
24
+ Before do
25
+ Chef::Config[:chef_server_url] = config['chef_server_url']
26
+ Chef::Config[:client_key] = config['client_key']
27
+ Chef::Config[:node_name] = config['node_name']
28
+ clean_cookbook_store
29
+ @aruba_io_wait_seconds = 5
30
+ end
31
+
32
+ Before('@slow_process') do
33
+ @aruba_timeout_seconds = 15
34
+ @aruba_io_wait_seconds = 10
35
+ end
36
+
37
+ def cookbook_store
38
+ Pathname.new(ENV["BERKSHELF_PATH"])
39
+ end
40
+
41
+ def clean_cookbook_store
42
+ FileUtils.rm_rf(cookbook_store)
43
+ FileUtils.mkdir_p(cookbook_store)
44
+ end
45
+
46
+ def config
47
+ @config ||= YAML.load(File.read(File.join(APP_ROOT, "features", "config.yml")))
48
+ rescue Errno::ENOENT
49
+ raise "Please create a config file at features/config.yml from the sample found at features/config.sample.yml"
50
+ end
51
+ end
52
+
53
+ Spork.each_run do
54
+ require 'berkshelf'
55
+ end
@@ -0,0 +1,23 @@
1
+ Feature: update
2
+ As a user
3
+ I want a way to update the versions without clearing out the files I've downloaded
4
+ So that I can update faster than a clean install
5
+
6
+ Scenario: knife berkshelf update
7
+ Given I write to "Berksfile" with:
8
+ """
9
+ cookbook "mysql"
10
+ """
11
+ Given I write to "Berksfile.lock" with:
12
+ """
13
+ cookbook 'mysql', :locked_version => '0.0.1'
14
+ cookbook 'openssl', :locked_version => '0.0.1'
15
+ """
16
+ When I run the update command
17
+ Then the file "Berksfile.lock" should contain exactly:
18
+ """
19
+ cookbook 'mysql', :locked_version => '1.2.6'
20
+ cookbook 'openssl', :locked_version => '1.0.0'
21
+ cookbook 'chef_handler', :locked_version => '1.0.6'
22
+ cookbook 'windows', :locked_version => '1.3.0'
23
+ """
@@ -0,0 +1,43 @@
1
+ Feature: upload command
2
+ As a Berkshelf CLI user
3
+ I need a way to upload cookbooks to a Chef server that I have installed into my Bookshelf
4
+ So they are available to Chef clients
5
+
6
+ @wip @slow_process
7
+ Scenario: running the upload command when the Sources in the Berksfile are already installed
8
+ Given I write to "Berksfile" with:
9
+ """
10
+ cookbook "mysql", "1.2.4"
11
+ """
12
+ And the Chef server does not have the cookbooks:
13
+ | mysql | 1.2.4 |
14
+ | openssl | 1.0.0 |
15
+ And I run the install command
16
+ When I run the upload command
17
+ Then the output should not contain "Using mysql (1.2.4)"
18
+ And the output should not contain "Using openssl (1.0.0)"
19
+ And the output should contain "Uploading mysql (1.2.4) to:"
20
+ And the output should contain "Uploading openssl (1.0.0) to:"
21
+ And the Chef server should have the cookbooks:
22
+ | mysql | 1.2.4 |
23
+ | openssl | 1.0.0 |
24
+ And the exit status should be 0
25
+
26
+ @slow_process
27
+ Scenario: running the upload command when the Sources in the Berksfile have not been installed
28
+ Given I write to "Berksfile" with:
29
+ """
30
+ cookbook "mysql", "1.2.4"
31
+ """
32
+ And the Chef server does not have the cookbooks:
33
+ | mysql | 1.2.4 |
34
+ | openssl | 1.0.0 |
35
+ When I run the upload command
36
+ Then the output should contain "Installing mysql (1.2.4) from site:"
37
+ And the output should contain "Installing openssl (1.0.0) from site:"
38
+ And the output should contain "Uploading mysql (1.2.4) to:"
39
+ And the output should contain "Uploading openssl (1.0.0) to:"
40
+ And the Chef server should have the cookbooks:
41
+ | mysql | 1.2.4 |
42
+ | openssl | 1.0.0 |
43
+ And the exit status should be 0
@@ -0,0 +1,25 @@
1
+ Feature: --without block
2
+ As a user
3
+ I want to be able to exclude blocks in my Berksfile
4
+ So I can have cookbooks organized for use in different situations in a single Berksfile
5
+
6
+ @slow_process
7
+ Scenario: Exclude a block
8
+ Given I write to "Berksfile" with:
9
+ """
10
+ group :notme do
11
+ cookbook "nginx", "= 0.101.2"
12
+ end
13
+
14
+ cookbook "mysql", "= 1.2.4"
15
+
16
+ group :takeme do
17
+ cookbook "ntp", "= 1.1.8"
18
+ end
19
+ """
20
+ When I run `knife berks install --without notme`
21
+ Then the cookbook store should have the cookbooks:
22
+ | mysql | 1.2.4 |
23
+ | ntp | 1.1.8 |
24
+ And the cookbook store should not have the cookbooks:
25
+ | nginx | 0.101.2 |
@@ -0,0 +1,90 @@
1
+ require 'pathname'
2
+ require 'dep_selector'
3
+ require 'zlib'
4
+ require 'archive/tar/minitar'
5
+ require 'chef/knife'
6
+ require 'chef/rest'
7
+ require 'chef/platform'
8
+ require 'chef/cookbook/metadata'
9
+
10
+ require 'berkshelf/version'
11
+ require 'berkshelf/core_ext'
12
+ require 'berkshelf/errors'
13
+
14
+ Chef::Config[:cache_options][:path] = Dir.mktmpdir
15
+
16
+ module Berkshelf
17
+ DEFAULT_STORE_PATH = File.expand_path("~/.berkshelf").freeze
18
+ DEFAULT_FILENAME = 'Berksfile'.freeze
19
+
20
+ autoload :DSL, 'berkshelf/dsl'
21
+ autoload :Git, 'berkshelf/git'
22
+ autoload :Berksfile, 'berkshelf/berksfile'
23
+ autoload :Lockfile, 'berkshelf/lockfile'
24
+ autoload :InitGenerator, 'berkshelf/init_generator'
25
+ autoload :CookbookSource, 'berkshelf/cookbook_source'
26
+ autoload :CookbookStore, 'berkshelf/cookbook_store'
27
+ autoload :CachedCookbook, 'berkshelf/cached_cookbook'
28
+ autoload :TXResult, 'berkshelf/tx_result'
29
+ autoload :TXResultSet, 'berkshelf/tx_result_set'
30
+ autoload :Downloader, 'berkshelf/downloader'
31
+ autoload :Uploader, 'berkshelf/uploader'
32
+ autoload :Resolver, 'berkshelf/resolver'
33
+
34
+ class << self
35
+ attr_accessor :ui
36
+ attr_accessor :cookbook_store
37
+ attr_accessor :downloader
38
+
39
+ def root
40
+ File.join(File.dirname(__FILE__), '..')
41
+ end
42
+
43
+ def ui
44
+ @ui ||= Chef::Knife::UI.new(null_stream, null_stream, STDIN, {})
45
+ end
46
+
47
+ # Returns the filepath to the location Cookbooks will be downloaded to
48
+ # or uploaded from. By default this is '~/.berkshelf' but can be overridden
49
+ # by specifying a value for the ENV variable 'BERKSHELF_PATH'.
50
+ #
51
+ # @return [String]
52
+ def berkshelf_path
53
+ ENV["BERKSHELF_PATH"] || DEFAULT_STORE_PATH
54
+ end
55
+
56
+ def cookbook_store
57
+ @cookbook_store ||= CookbookStore.new(berkshelf_path)
58
+ end
59
+
60
+ def downloader
61
+ @downloader ||= Downloader.new(cookbook_store)
62
+ end
63
+
64
+ # Ascend the directory structure from the given path to find a
65
+ # metadata.rb file of a Chef Cookbook. If no metadata.rb file
66
+ # was found, nil is returned.
67
+ #
68
+ # @return [Pathname]
69
+ # path to metadata.rb
70
+ def find_metadata(path = Dir.pwd)
71
+ path = Pathname.new(path)
72
+ path.ascend do |potential_root|
73
+ if potential_root.entries.collect(&:to_s).include?('metadata.rb')
74
+ return potential_root.join('metadata.rb')
75
+ end
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def null_stream
82
+ @null ||= begin
83
+ strm = STDOUT.clone
84
+ strm.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
85
+ strm.sync = true
86
+ strm
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,170 @@
1
+ module Berkshelf
2
+ # @author Jamie Winsor <jamie@vialstudios.com>
3
+ class Berksfile
4
+ include DSL
5
+
6
+ class << self
7
+ def from_file(file)
8
+ content = File.read(file)
9
+ read(content)
10
+ rescue Errno::ENOENT => e
11
+ raise BerksfileNotFound, "No Berksfile or Berksfile.lock found at: #{file}"
12
+ end
13
+
14
+ def read(content)
15
+ object = new
16
+ object.instance_eval(content)
17
+
18
+ object
19
+ end
20
+
21
+ # @param [Array] sources
22
+ # an array of sources to filter
23
+ # @param [Array, Symbol] excluded
24
+ # an array of symbols or a symbol representing the group or group(s)
25
+ # to exclude
26
+ #
27
+ # @return [Array<Berkshelf::CookbookSource>]
28
+ # an array of sources that are not members of the excluded group(s)
29
+ def filter_sources(sources, excluded)
30
+ excluded = Array(excluded)
31
+ excluded.collect!(&:to_sym)
32
+
33
+ sources.select { |source| (excluded & source.groups).empty? }
34
+ end
35
+ end
36
+
37
+ def initialize
38
+ @sources = Hash.new
39
+ end
40
+
41
+ # Add the given source to the sources array. A DuplicateSourceDefined
42
+ # exception will be raised if a source is added whose name conflicts
43
+ # with a source who has already been added.
44
+ #
45
+ # @param [Berkshelf::CookbookSource] source
46
+ # the source to add
47
+ #
48
+ # @return [Array<Berkshelf::CookbookSource]
49
+ def add_source(source)
50
+ raise DuplicateSourceDefined if has_source?(source)
51
+ @sources[source.to_s] = source
52
+ end
53
+
54
+ # @param [#to_s] source
55
+ # the source to remove
56
+ #
57
+ # @return [Berkshelf::CookbookSource]
58
+ def remove_source(source)
59
+ @sources.delete(source.to_s)
60
+ end
61
+
62
+ # @param [#to_s] source
63
+ # the source to check presence of
64
+ #
65
+ # @return [Boolean]
66
+ def has_source?(source)
67
+ @sources.has_key?(source.to_s)
68
+ end
69
+
70
+ # @param [Hash] options
71
+ # a hash of options
72
+ #
73
+ # Options:
74
+ # exclude: An array of groups to exclude from the returned Array
75
+ # of sources
76
+ #
77
+ # @return [Array<Berkshelf::CookbookSource>]
78
+ def sources(options = {})
79
+ l_sources = @sources.collect { |name, source| source }.flatten
80
+
81
+ if options[:exclude]
82
+ self.class.filter_sources(l_sources, options[:exclude])
83
+ else
84
+ l_sources
85
+ end
86
+ end
87
+
88
+ # @return [Hash]
89
+ # a hash containing group names as keys and an array of CookbookSources
90
+ # that are a member of that group as values
91
+ #
92
+ # Example:
93
+ # {
94
+ # nautilus: [
95
+ # #<Berkshelf::CookbookSource @name="nginx">,
96
+ # #<Berkshelf::CookbookSource @name="mysql">,
97
+ # ],
98
+ # skarner: [
99
+ # #<Berkshelf::CookbookSource @name="nginx">
100
+ # ]
101
+ # }
102
+ def groups
103
+ {}.tap do |groups|
104
+ @sources.each_pair do |name, source|
105
+ source.groups.each do |group|
106
+ groups[group] ||= []
107
+ groups[group] << source
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ # @param [String] name
114
+ # name of the source to return
115
+ #
116
+ # @return [Berkshelf::CookbookSource]
117
+ def [](name)
118
+ @sources[name]
119
+ end
120
+ alias_method :get_source, :[]
121
+
122
+ # @param [Hash] options
123
+ # a hash of options
124
+ #
125
+ # Options:
126
+ # without: An array of groups to exclude which will cause any sources
127
+ # marked as a member of the group to not be installed
128
+ def install(options = {})
129
+ resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without]))
130
+ resolver.resolve
131
+ write_lockfile(resolver.sources) unless lockfile_present?
132
+ end
133
+
134
+ # @param [String] chef_server_url
135
+ # the full URL to the Chef Server to upload to
136
+ #
137
+ # Example:
138
+ # "https://api.opscode.com/organizations/vialstudios"
139
+ #
140
+ # @param [Hash] options
141
+ # a hash of options
142
+ #
143
+ # Options:
144
+ # without: An array of groups to exclude which will cause any sources
145
+ # marked as a member of the group to not be installed
146
+ # force: Upload the Cookbook even if the version already exists and is
147
+ # frozen on the target Chef Server
148
+ # freeze: Freeze the uploaded Cookbook on the Chef Server so that it
149
+ # cannot be overwritten
150
+ def upload(chef_server_url, options = {})
151
+ uploader = Uploader.new(Berkshelf.cookbook_store, chef_server_url)
152
+ resolver = Resolver.new(Berkshelf.downloader, sources(exclude: options[:without]))
153
+
154
+ resolver.resolve.each do |name, version|
155
+ Berkshelf.ui.info "Uploading #{name} (#{version}) to: #{chef_server_url}"
156
+ uploader.upload!(name, version, options)
157
+ end
158
+ end
159
+
160
+ private
161
+
162
+ def lockfile_present?
163
+ File.exist?(Berkshelf::Lockfile::DEFAULT_FILENAME)
164
+ end
165
+
166
+ def write_lockfile(sources)
167
+ Berkshelf::Lockfile.new(sources).write
168
+ end
169
+ end
170
+ end