berkshelf 5.2.0 → 8.0.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +19 -47
  3. data/Rakefile +14 -4
  4. data/berkshelf.gemspec +61 -40
  5. data/bin/berks +2 -2
  6. data/lib/berkshelf/api-client.rb +1 -0
  7. data/lib/berkshelf/api_client/chef_server_connection.rb +29 -0
  8. data/lib/berkshelf/api_client/connection.rb +57 -0
  9. data/lib/berkshelf/api_client/errors.rb +10 -0
  10. data/lib/berkshelf/api_client/remote_cookbook.rb +56 -0
  11. data/lib/berkshelf/api_client/version.rb +5 -0
  12. data/lib/berkshelf/api_client.rb +24 -0
  13. data/lib/berkshelf/berksfile.rb +149 -122
  14. data/lib/berkshelf/cached_cookbook.rb +127 -24
  15. data/lib/berkshelf/chef_config_compat.rb +51 -0
  16. data/lib/berkshelf/chef_repo_universe.rb +47 -0
  17. data/lib/berkshelf/cli.rb +143 -174
  18. data/lib/berkshelf/commands/shelf.rb +20 -19
  19. data/lib/berkshelf/community_rest.rb +59 -94
  20. data/lib/berkshelf/config.rb +97 -127
  21. data/lib/berkshelf/cookbook_store.rb +7 -6
  22. data/lib/berkshelf/core_ext/file.rb +1 -1
  23. data/lib/berkshelf/core_ext/file_utils.rb +4 -4
  24. data/lib/berkshelf/core_ext.rb +1 -1
  25. data/lib/berkshelf/dependency.rb +25 -32
  26. data/lib/berkshelf/downloader.rb +66 -39
  27. data/lib/berkshelf/errors.rb +23 -17
  28. data/lib/berkshelf/file_syncer.rb +24 -47
  29. data/lib/berkshelf/formatters/human.rb +7 -5
  30. data/lib/berkshelf/formatters/json.rb +6 -6
  31. data/lib/berkshelf/installer.rb +120 -111
  32. data/lib/berkshelf/location.rb +14 -14
  33. data/lib/berkshelf/locations/base.rb +1 -1
  34. data/lib/berkshelf/locations/git.rb +16 -24
  35. data/lib/berkshelf/locations/github.rb +2 -2
  36. data/lib/berkshelf/locations/path.rb +2 -2
  37. data/lib/berkshelf/lockfile.rb +326 -328
  38. data/lib/berkshelf/logger.rb +64 -1
  39. data/lib/berkshelf/mixin/git.rb +6 -5
  40. data/lib/berkshelf/packager.rb +44 -10
  41. data/lib/berkshelf/resolver/graph.rb +1 -1
  42. data/lib/berkshelf/resolver.rb +4 -4
  43. data/lib/berkshelf/ridley_compat.rb +109 -0
  44. data/lib/berkshelf/shell.rb +2 -1
  45. data/lib/berkshelf/shell_out.rb +18 -0
  46. data/lib/berkshelf/source.rb +77 -33
  47. data/lib/berkshelf/source_uri.rb +4 -4
  48. data/lib/berkshelf/ssl_policies.rb +38 -0
  49. data/lib/berkshelf/thor.rb +1 -1
  50. data/lib/berkshelf/thor_ext/hash_with_indifferent_access.rb +1 -1
  51. data/lib/berkshelf/thor_ext.rb +1 -1
  52. data/lib/berkshelf/uploader.rb +106 -70
  53. data/lib/berkshelf/validator.rb +13 -5
  54. data/lib/berkshelf/version.rb +1 -1
  55. data/lib/berkshelf/visualizer.rb +16 -11
  56. data/lib/berkshelf.rb +106 -81
  57. data/spec/config/knife.rb +4 -4
  58. data/spec/data/trusted_certs/example.crt +22 -0
  59. data/spec/fixtures/Berksfile +3 -3
  60. data/spec/fixtures/complex-cookbook-path/cookbooks/app/metadata.rb +2 -0
  61. data/spec/fixtures/complex-cookbook-path/cookbooks/jenkins/metadata.rb +2 -0
  62. data/spec/fixtures/complex-cookbook-path/cookbooks/jenkins-config/metadata.rb +4 -0
  63. data/spec/fixtures/cookbook-path/jenkins-config/metadata.rb +3 -3
  64. data/spec/fixtures/cookbook-path-uploader/apt-2.3.6/metadata.rb +2 -0
  65. data/spec/fixtures/cookbook-path-uploader/build-essential-1.4.2/metadata.rb +2 -0
  66. data/spec/fixtures/cookbook-path-uploader/jenkins-2.0.3/metadata.rb +5 -0
  67. data/spec/fixtures/cookbook-path-uploader/jenkins-config-0.1.0/metadata.rb +4 -0
  68. data/spec/fixtures/cookbook-path-uploader/runit-1.5.8/metadata.rb +5 -0
  69. data/spec/fixtures/cookbook-path-uploader/yum-3.0.6/metadata.rb +2 -0
  70. data/spec/fixtures/cookbook-path-uploader/yum-epel-0.2.0/metadata.rb +3 -0
  71. data/spec/fixtures/cookbook-store/jenkins-2.0.3/metadata.rb +5 -5
  72. data/spec/fixtures/cookbook-store/jenkins-2.0.4/metadata.rb +4 -4
  73. data/spec/fixtures/cookbooks/example_cookbook/metadata.rb +3 -3
  74. data/spec/fixtures/cookbooks/example_cookbook-0.5.0/metadata.rb +3 -3
  75. data/spec/spec_helper.rb +56 -64
  76. data/spec/support/chef_api.rb +15 -16
  77. data/spec/support/chef_server.rb +71 -69
  78. data/spec/support/git.rb +59 -58
  79. data/spec/support/kitchen.rb +0 -14
  80. data/spec/support/matchers/file_system_matchers.rb +4 -5
  81. data/spec/support/matchers/filepath_matchers.rb +2 -2
  82. data/spec/support/path_helpers.rb +17 -17
  83. data/spec/support/shared_examples/formatter.rb +1 -1
  84. data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/attributes/default.rb +0 -0
  85. data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/files/default/file.h +0 -0
  86. data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/metadata.rb +2 -0
  87. data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/recipes/default.rb +0 -0
  88. data/spec/tmp/berkshelf/cookbooks/fake-0.1.0/templates/default/template.erb +0 -0
  89. data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/attributes/default.rb +0 -0
  90. data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/files/default/file.h +0 -0
  91. data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/metadata.rb +2 -0
  92. data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/recipes/default.rb +0 -0
  93. data/spec/tmp/berkshelf/cookbooks/fake-0.2.0/templates/default/template.erb +0 -0
  94. data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/attributes/default.rb +0 -0
  95. data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/files/default/file.h +0 -0
  96. data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/metadata.rb +2 -0
  97. data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/recipes/default.rb +0 -0
  98. data/spec/tmp/berkshelf/cookbooks/fake-1.0.0/templates/default/template.erb +0 -0
  99. data/spec/unit/berkshelf/berksfile_spec.rb +84 -105
  100. data/spec/unit/berkshelf/berkshelf/api_client/chef_server_connection_spec.rb +65 -0
  101. data/spec/unit/berkshelf/berkshelf/api_client/connection_spec.rb +157 -0
  102. data/spec/unit/berkshelf/berkshelf/api_client/remote_cookbook_spec.rb +23 -0
  103. data/spec/unit/berkshelf/berkshelf/api_client_spec.rb +9 -0
  104. data/spec/unit/berkshelf/cached_cookbook_spec.rb +45 -47
  105. data/spec/unit/berkshelf/chef_repo_universe_spec.rb +37 -0
  106. data/spec/unit/berkshelf/cli_spec.rb +7 -8
  107. data/spec/unit/berkshelf/community_rest_spec.rb +82 -90
  108. data/spec/unit/berkshelf/config_spec.rb +51 -22
  109. data/spec/unit/berkshelf/cookbook_store_spec.rb +41 -41
  110. data/spec/unit/berkshelf/core_ext/file_utils_spec.rb +7 -8
  111. data/spec/unit/berkshelf/core_ext/pathname_spec.rb +1 -1
  112. data/spec/unit/berkshelf/dependency_spec.rb +48 -48
  113. data/spec/unit/berkshelf/downloader_spec.rb +191 -34
  114. data/spec/unit/berkshelf/errors_spec.rb +3 -3
  115. data/spec/unit/berkshelf/file_syncer_spec.rb +87 -87
  116. data/spec/unit/berkshelf/formatters/base_spec.rb +23 -23
  117. data/spec/unit/berkshelf/formatters/human_spec.rb +2 -2
  118. data/spec/unit/berkshelf/formatters/json_spec.rb +2 -2
  119. data/spec/unit/berkshelf/formatters/null_spec.rb +3 -3
  120. data/spec/unit/berkshelf/installer_spec.rb +8 -8
  121. data/spec/unit/berkshelf/location_spec.rb +11 -11
  122. data/spec/unit/berkshelf/locations/base_spec.rb +35 -36
  123. data/spec/unit/berkshelf/locations/git_spec.rb +90 -93
  124. data/spec/unit/berkshelf/locations/path_spec.rb +40 -41
  125. data/spec/unit/berkshelf/lockfile_parser_spec.rb +71 -71
  126. data/spec/unit/berkshelf/lockfile_spec.rb +205 -211
  127. data/spec/unit/berkshelf/logger_spec.rb +3 -3
  128. data/spec/unit/berkshelf/mixin/logging_spec.rb +5 -5
  129. data/spec/unit/berkshelf/packager_spec.rb +2 -2
  130. data/spec/unit/berkshelf/resolver/graph_spec.rb +10 -8
  131. data/spec/unit/berkshelf/resolver_spec.rb +17 -17
  132. data/spec/unit/berkshelf/ridley_compat_spec.rb +16 -0
  133. data/spec/unit/berkshelf/shell_spec.rb +34 -34
  134. data/spec/unit/berkshelf/source_spec.rb +186 -20
  135. data/spec/unit/berkshelf/source_uri_spec.rb +1 -1
  136. data/spec/unit/berkshelf/ssl_policies_spec.rb +86 -0
  137. data/spec/unit/berkshelf/uploader_spec.rb +146 -64
  138. data/spec/unit/berkshelf/validator_spec.rb +23 -16
  139. data/spec/unit/berkshelf/visualizer_spec.rb +24 -15
  140. data/spec/unit/berkshelf_spec.rb +18 -18
  141. metadata +138 -289
  142. data/.gitignore +0 -29
  143. data/.travis.yml +0 -64
  144. data/CHANGELOG.legacy.md +0 -307
  145. data/CHANGELOG.md +0 -1358
  146. data/CONTRIBUTING.md +0 -64
  147. data/Gemfile.lock +0 -399
  148. data/Guardfile +0 -23
  149. data/PLUGINS.md +0 -25
  150. data/README.md +0 -70
  151. data/Thorfile +0 -61
  152. data/appveyor.yml +0 -31
  153. data/docs/berkshelf_for_newcomers.md +0 -65
  154. data/features/berksfile.feature +0 -46
  155. data/features/commands/apply.feature +0 -41
  156. data/features/commands/contingent.feature +0 -48
  157. data/features/commands/cookbook.feature +0 -35
  158. data/features/commands/info.feature +0 -99
  159. data/features/commands/init.feature +0 -27
  160. data/features/commands/install.feature +0 -636
  161. data/features/commands/list.feature +0 -78
  162. data/features/commands/outdated.feature +0 -130
  163. data/features/commands/package.feature +0 -17
  164. data/features/commands/search.feature +0 -17
  165. data/features/commands/shelf/list.feature +0 -32
  166. data/features/commands/shelf/show.feature +0 -143
  167. data/features/commands/shelf/uninstall.feature +0 -96
  168. data/features/commands/show.feature +0 -83
  169. data/features/commands/update.feature +0 -142
  170. data/features/commands/upload.feature +0 -426
  171. data/features/commands/vendor.feature +0 -111
  172. data/features/commands/verify.feature +0 -29
  173. data/features/commands/viz.feature +0 -66
  174. data/features/community_site.feature +0 -37
  175. data/features/config.feature +0 -111
  176. data/features/help.feature +0 -11
  177. data/features/json_formatter.feature +0 -161
  178. data/features/lifecycle.feature +0 -378
  179. data/features/lockfile.feature +0 -378
  180. data/features/step_definitions/berksfile_steps.rb +0 -39
  181. data/features/step_definitions/chef/config_steps.rb +0 -12
  182. data/features/step_definitions/chef_server_steps.rb +0 -60
  183. data/features/step_definitions/cli_steps.rb +0 -18
  184. data/features/step_definitions/config_steps.rb +0 -46
  185. data/features/step_definitions/environment_steps.rb +0 -7
  186. data/features/step_definitions/filesystem_steps.rb +0 -269
  187. data/features/step_definitions/gem_steps.rb +0 -13
  188. data/features/step_definitions/json_steps.rb +0 -23
  189. data/features/step_definitions/utility_steps.rb +0 -11
  190. data/features/support/aruba.rb +0 -12
  191. data/features/support/env.rb +0 -82
  192. data/generator_files/Berksfile.erb +0 -11
  193. data/generator_files/CHANGELOG.md.erb +0 -3
  194. data/generator_files/Gemfile.erb +0 -8
  195. data/generator_files/README.md.erb +0 -42
  196. data/generator_files/Thorfile.erb +0 -11
  197. data/generator_files/Vagrantfile.erb +0 -117
  198. data/generator_files/chefignore +0 -94
  199. data/generator_files/default_recipe.erb +0 -6
  200. data/generator_files/default_test.rb.erb +0 -11
  201. data/generator_files/gitignore.erb +0 -23
  202. data/generator_files/helpers.rb.erb +0 -7
  203. data/generator_files/licenses/apachev2.erb +0 -13
  204. data/generator_files/licenses/gplv2.erb +0 -15
  205. data/generator_files/licenses/gplv3.erb +0 -14
  206. data/generator_files/licenses/mit.erb +0 -20
  207. data/generator_files/licenses/reserved.erb +0 -3
  208. data/generator_files/metadata.rb.erb +0 -11
  209. data/lib/berkshelf/base_generator.rb +0 -43
  210. data/lib/berkshelf/commands/test_command.rb +0 -13
  211. data/lib/berkshelf/cookbook_generator.rb +0 -133
  212. data/lib/berkshelf/init_generator.rb +0 -195
  213. data/spec/fixtures/cookbooks/example_cookbook/.gitignore +0 -2
  214. data/spec/fixtures/cookbooks/example_cookbook/.kitchen.yml +0 -26
  215. data/spec/unit/berkshelf/cookbook_generator_spec.rb +0 -110
  216. data/spec/unit/berkshelf/init_generator_spec.rb +0 -263
@@ -1,5 +1,68 @@
1
1
  module Berkshelf
2
- class Logger < Ridley::Logging::Logger
2
+ class Logger < Logger
3
+ def initialize(device = STDOUT)
4
+ super
5
+ self.level = Logger::WARN
6
+ @filter_params = []
7
+ end
8
+
9
+ # Reimplements Logger#add adding message filtering. The info,
10
+ # warn, debug, error, and fatal methods all call add.
11
+ #
12
+ # @param [Fixnum] severity
13
+ # an integer measuing the severity - Logger::INFO, etc.
14
+ # @param [String] message = nil
15
+ # the message to log
16
+ # @param [String] progname = nil
17
+ # the program name performing the logging
18
+ # @param &block
19
+ # a block that will be evaluated (for complicated logging)
20
+ #
21
+ # @example
22
+ # log.filter_param("hello")
23
+ # log.info("hello world!") => "FILTERED world!"
24
+ #
25
+ # @return [Boolean]
26
+ def add(severity, message = nil, progname = nil, &block)
27
+ severity ||= Logger::UNKNOWN
28
+ if @logdev.nil? || severity < (@level)
29
+ return true
30
+ end
31
+
32
+ progname ||= @progname
33
+ if message.nil?
34
+ if block_given?
35
+ message = yield
36
+ else
37
+ message = progname
38
+ progname = @progname
39
+ end
40
+ end
41
+ @logdev.write(
42
+ format_message(format_severity(severity), Time.now, progname, filter(message))
43
+ )
44
+ true
45
+ end
46
+
47
+ def filter_params
48
+ @filter_params.dup
49
+ end
50
+
51
+ def filter_param(param)
52
+ @filter_params << param unless filter_params.include?(param)
53
+ end
54
+
55
+ def clear_filter_params
56
+ @filter_params.clear
57
+ end
58
+
59
+ def filter(message)
60
+ filter_params.each do |param|
61
+ message.gsub!(param.to_s, "FILTERED")
62
+ end
63
+ message
64
+ end
65
+
3
66
  alias_method :fatal, :error
4
67
 
5
68
  def deprecate(message)
@@ -1,8 +1,9 @@
1
- require 'buff/shell_out'
1
+ require_relative "../shell_out"
2
2
 
3
3
  module Berkshelf
4
4
  module Mixin
5
5
  module Git
6
+ include Berkshelf::ShellOut
6
7
  # Perform a git command.
7
8
  #
8
9
  # @param [String] command
@@ -12,14 +13,14 @@ module Berkshelf
12
13
  #
13
14
  # @raise [String]
14
15
  # the +$stdout+ from the command
15
- def git(command, error = true)
16
- unless Berkshelf.which('git') || Berkshelf.which('git.exe') || Berkshelf.which('git.bat')
16
+ def git(command, error = true, **kwargs)
17
+ unless Berkshelf.which("git") || Berkshelf.which("git.exe") || Berkshelf.which("git.bat")
17
18
  raise GitNotInstalled.new
18
19
  end
19
20
 
20
- response = Buff::ShellOut.shell_out(%|git #{command}|)
21
+ response = shell_out(%{git #{command}}, **kwargs)
21
22
 
22
- if error && !response.success?
23
+ if response.error?
23
24
  raise GitCommandError.new(command, cache_path, response.stderr)
24
25
  end
25
26
 
@@ -1,5 +1,6 @@
1
- require 'archive/tar/minitar'
2
- require 'zlib'
1
+ require "minitar"
2
+ require "find" unless defined?(Find)
3
+ require "zlib" unless defined?(Zlib)
3
4
 
4
5
  module Berkshelf
5
6
  # A class for archiving and compressing directory containing one or more cookbooks.
@@ -15,7 +16,7 @@ module Berkshelf
15
16
  class Packager
16
17
  class << self
17
18
  def validate_destination(path)
18
- path = path.to_s
19
+ path.to_s
19
20
  end
20
21
  end
21
22
 
@@ -40,9 +41,17 @@ module Berkshelf
40
41
  # @return [String]
41
42
  # path to the generated archive
42
43
  def run(source)
43
- Dir.chdir(source.to_s) do |dir|
44
- tgz = Zlib::GzipWriter.new(File.open(out_file, "wb"))
45
- Archive::Tar::Minitar.pack(".", tgz)
44
+ begin
45
+ dest = Zlib::GzipWriter.open(out_file)
46
+ tar = RelativeTarWriter.new(dest, source)
47
+ Find.find(source) do |entry|
48
+ next if source == entry
49
+
50
+ Minitar.pack_file(entry, tar)
51
+ end
52
+ ensure
53
+ tar.close
54
+ dest.close
46
55
  end
47
56
 
48
57
  out_file
@@ -64,10 +73,35 @@ module Berkshelf
64
73
 
65
74
  private
66
75
 
67
- # @return [String]
68
- attr_reader :out_dir
76
+ # @return [String]
77
+ attr_reader :out_dir
78
+
79
+ # @return [String]
80
+ attr_reader :filename
81
+
82
+ # A private decorator for Minitar::Writer that
83
+ # turns absolute paths into relative ones.
84
+ class RelativeTarWriter < SimpleDelegator # :nodoc:
85
+ def initialize(io, base_path)
86
+ @base_path = Pathname.new(base_path)
87
+ super(Minitar::Writer.new(io))
88
+ end
89
+
90
+ %w{add_file add_file_simple mkdir}.each do |method|
91
+ class_eval <<~RUBY
92
+ def #{method}(name, *opts, &block)
93
+ super(relative_path(name), *opts, &block)
94
+ end
95
+ RUBY
96
+ end
97
+
98
+ private
69
99
 
70
- # @return [String]
71
- attr_reader :filename
100
+ attr_reader :base_path
101
+
102
+ def relative_path(path)
103
+ Pathname.new(path).relative_path_from(base_path).to_s
104
+ end
105
+ end
72
106
  end
73
107
  end
@@ -50,7 +50,7 @@ module Berkshelf
50
50
  # @return [Array<Berkshelf::RemoteCookbook>]
51
51
  def universe(sources)
52
52
  cookbooks = []
53
- Array(sources).each { |source| cookbooks = cookbooks | source.universe }
53
+ Array(sources).each { |source| cookbooks |= source.universe }
54
54
  cookbooks
55
55
  end
56
56
  end
@@ -1,7 +1,7 @@
1
1
  module Berkshelf
2
2
  class Resolver
3
3
 
4
- require_relative 'resolver/graph'
4
+ require_relative "resolver/graph"
5
5
 
6
6
  extend Forwardable
7
7
 
@@ -21,7 +21,7 @@ module Berkshelf
21
21
  def initialize(berksfile, demands = [])
22
22
  @berksfile = berksfile
23
23
  @graph = Graph.new
24
- @demands = Array.new
24
+ @demands = []
25
25
 
26
26
  Array(demands).each { |demand| add_demand(demand) }
27
27
  compute_solver_engine(berksfile)
@@ -75,7 +75,7 @@ module Berkshelf
75
75
  graph.populate_store
76
76
  graph.populate(berksfile.sources)
77
77
 
78
- Solve.it!(graph, demand_array, ENV['DEBUG_RESOLVER'] ? { ui: Berkshelf.ui } : {}).collect do |name, version|
78
+ Solve.it!(graph, demand_array, ENV["DEBUG_RESOLVER"] ? { ui: Berkshelf.ui } : {}).collect do |name, version|
79
79
  dependency = get_demand(name) || Dependency.new(berksfile, name)
80
80
  dependency.locked_version = version
81
81
 
@@ -93,7 +93,7 @@ module Berkshelf
93
93
  # @return [Dependency]
94
94
  def [](demand)
95
95
  name = demand.respond_to?(:name) ? demand.name : demand.to_s
96
- demands.find { |demand| demand.name == name }
96
+ demands.find { |d| d.name == name }
97
97
  end
98
98
  alias_method :get_demand, :[]
99
99
 
@@ -0,0 +1,109 @@
1
+ require "chef/server_api"
2
+ require "chef/http/simple_json"
3
+ require "chef/http/simple"
4
+ require_relative "api_client/errors"
5
+ require "chef/config"
6
+ require "chef/cookbook_manifest"
7
+
8
+ module Berkshelf
9
+ module RidleyCompatAPI
10
+ def initialize(**opts)
11
+ opts = opts.dup
12
+ opts[:ssl] ||= {}
13
+ chef_opts = {}
14
+ chef_opts[:rest_timeout] = opts[:timeout] if opts[:timeout] # opts[:open_timeout] is ignored on purpose
15
+ chef_opts[:headers] = opts[:headers] if opts[:headers]
16
+ chef_opts[:client_name] = opts[:client_name] if opts[:client_name]
17
+ chef_opts[:signing_key_filename] = opts[:client_key] if opts[:client_key]
18
+ chef_opts[:verify_api_cert] = opts[:ssl][:verify] || opts[:ssl][:verify].nil?
19
+ chef_opts[:ssl_verify_mode] = chef_opts[:verify_api_cert] ? :verify_peer : :verify_none
20
+ chef_opts[:ssl_ca_path] = opts[:ssl][:ca_path] if opts[:ssl][:ca_path]
21
+ chef_opts[:ssl_ca_file] = opts[:ssl][:ca_file] if opts[:ssl][:ca_file]
22
+ chef_opts[:ssl_client_cert] = opts[:ssl][:client_cert] if opts[:ssl][:client_cert]
23
+ chef_opts[:ssl_client_key] = opts[:ssl][:client_key] if opts[:ssl][:client_key]
24
+ chef_opts[:version_class] = opts[:version_class] if opts[:version_class]
25
+ # chef/http/ssl_policies.rb reads only from Chef::Config and not from the opts in the constructor
26
+ Chef::Config[:verify_api_cert] = chef_opts[:verify_api_cert]
27
+ Chef::Config[:ssl_verify_mode] = chef_opts[:ssl_verify_mode]
28
+ super(opts[:server_url].to_s, **chef_opts)
29
+ end
30
+
31
+ # for compat with Ridley::Connection
32
+ def server_url
33
+ url
34
+ end
35
+
36
+ def get(url)
37
+ super(url)
38
+ rescue Net::HTTPExceptions => e
39
+ case e.response.code
40
+ when "404"
41
+ raise Berkshelf::APIClient::ServiceNotFound, "service not found at: #{url}"
42
+ when /^5/
43
+ raise Berkshelf::APIClient::ServiceUnavailable, "service unavailable at: #{url}"
44
+ else
45
+ raise Berkshelf::APIClient::BadResponse, "bad response #{e.response}"
46
+ end
47
+ rescue Errno::ETIMEDOUT, Timeout::Error
48
+ raise Berkshelf::APIClient::TimeoutError, "Unable to connect to: #{url}"
49
+ rescue Errno::EHOSTUNREACH, Errno::ECONNREFUSED => e
50
+ raise Berkshelf::APIClient::ServiceUnavailable, e
51
+ end
52
+
53
+ module ClassMethods
54
+ def new_client(**opts, &block)
55
+ client = new(**opts)
56
+ yield client
57
+ # ensure
58
+ # FIXME: does Chef::HTTP support close anywhere? this will just leak open fds
59
+ end
60
+ end
61
+
62
+ def self.included(klass)
63
+ klass.extend ClassMethods
64
+ end
65
+
66
+ end
67
+
68
+ # This is for simple HTTP
69
+ class RidleyCompatSimple < ::Chef::ServerAPI
70
+ use Chef::HTTP::Decompressor
71
+ use Chef::HTTP::CookieManager
72
+ use Chef::HTTP::ValidateContentLength
73
+
74
+ include RidleyCompatAPI
75
+ end
76
+
77
+ # This is for JSON-REST
78
+ class RidleyCompatJSON < ::Chef::HTTP::SimpleJSON
79
+ use Chef::HTTP::JSONInput
80
+ use Chef::HTTP::JSONOutput
81
+ use Chef::HTTP::CookieManager
82
+ use Chef::HTTP::Decompressor
83
+ use Chef::HTTP::RemoteRequestID
84
+ use Chef::HTTP::ValidateContentLength
85
+
86
+ include RidleyCompatAPI
87
+ end
88
+
89
+ # RidleyCompat is the ServerAPI, but we inherit from Chef::HTTP::Simple and then include all our middlewares
90
+ # and then need to include our own CompatAPI. The end result is a ridley-esque way of talking to a chef server.
91
+ class RidleyCompat < ::Chef::HTTP::Simple
92
+ use Chef::HTTP::JSONInput
93
+ use Chef::HTTP::JSONOutput
94
+ use Chef::HTTP::CookieManager
95
+ use Chef::HTTP::Decompressor
96
+ use Chef::HTTP::Authenticator
97
+ use Chef::HTTP::RemoteRequestID
98
+ use Chef::HTTP::APIVersions if defined?(Chef::HTTP::APIVersions)
99
+ use Chef::HTTP::ValidateContentLength
100
+
101
+ include RidleyCompatAPI
102
+
103
+ def initialize(**opts)
104
+ opts[:version_class] = Chef::CookbookManifestVersions
105
+ super(**opts)
106
+ end
107
+
108
+ end
109
+ end
@@ -1,4 +1,4 @@
1
- require 'thor'
1
+ require "thor" unless defined?(Thor)
2
2
 
3
3
  module Berkshelf
4
4
  # Subclass the current shell (which is different based on the OS)
@@ -15,6 +15,7 @@ module Berkshelf
15
15
 
16
16
  def say(*args)
17
17
  return if quiet?
18
+
18
19
  super(*args)
19
20
  end
20
21
  alias_method :info, :say
@@ -0,0 +1,18 @@
1
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
2
+
3
+ module Berkshelf
4
+ module ShellOut
5
+ def shell_out(*args, **options)
6
+ cmd = Mixlib::ShellOut.new(*args, **options)
7
+ cmd.run_command
8
+ cmd
9
+ end
10
+
11
+ def shell_out!(*args, **options)
12
+ cmd = Mixlib::ShellOut.new(*args, **options)
13
+ cmd.run_command
14
+ cmd.error!
15
+ cmd
16
+ end
17
+ end
18
+ end
@@ -1,44 +1,80 @@
1
- require 'berkshelf/api-client'
1
+ require_relative "api-client"
2
+ require_relative "chef_repo_universe"
3
+ require_relative "ssl_policies"
4
+ require "openssl" unless defined?(OpenSSL)
2
5
 
3
6
  module Berkshelf
4
7
  class Source
5
8
  include Comparable
6
9
 
7
- attr_accessor :source
10
+ attr_accessor :type
11
+ attr_accessor :uri_string
12
+ attr_accessor :options
8
13
 
14
+ # @param [Berkshelf::Berksfile] berksfile
9
15
  # @param [String, Berkshelf::SourceURI] source
10
- def initialize(source)
11
- @source = source
12
- @universe = nil
16
+ def initialize(berksfile, source, **options)
17
+ @options = { timeout: api_timeout, open_timeout: [(api_timeout / 10), 3].max, ssl: {} }
18
+ @options.update(options)
19
+ case source
20
+ when String
21
+ # source "https://supermarket.chef.io/"
22
+ @type = :supermarket
23
+ @uri_string = source
24
+ when :chef_server
25
+ # source :chef_server
26
+ @type = :chef_server
27
+ @uri_string = options[:url] || Berkshelf::Config.instance.chef.chef_server_url
28
+ when Hash
29
+ # source type: uri, option: value, option: value
30
+ source = source.dup
31
+ @type, @uri_string = source.shift
32
+ @options.update(source)
33
+ end
34
+ # Default options for some source types.
35
+ case @type
36
+ when :chef_server
37
+ @options[:client_name] ||= Berkshelf::Config.instance.chef.node_name
38
+ @options[:client_key] ||= Berkshelf::Config.instance.chef.client_key
39
+ when :artifactory
40
+ @options[:api_key] ||= Berkshelf::Config.instance.chef.artifactory_api_key || ENV["ARTIFACTORY_API_KEY"]
41
+ when :chef_repo
42
+ @options[:path] = uri_string
43
+ # If given a relative path, expand it against the Berksfile's folder.
44
+ @options[:path] = File.expand_path(@options[:path], File.dirname(berksfile ? berksfile.filepath : Dir.pwd))
45
+ # Lie because this won't actually parse as a URI.
46
+ @uri_string = "file://#{@options[:path]}"
47
+ end
48
+ # Set some default SSL options.
49
+ Berkshelf::Config.instance.ssl.each do |key, value|
50
+ @options[:ssl][key.to_sym] = value unless @options[:ssl].include?(key.to_sym)
51
+ end
52
+ @options[:ssl][:cert_store] = ssl_policy.store if ssl_policy.store
53
+ @universe = nil
54
+ end
55
+
56
+ def ssl_policy
57
+ @ssl_policy ||= SSLPolicy.new
13
58
  end
14
59
 
15
60
  def api_client
16
- @api_client ||= begin
17
- if source == :chef_server
18
- APIClient.chef_server(
19
- ssl: Berkshelf::Config.instance.ssl,
20
- timeout: api_timeout,
21
- open_timeout: [(api_timeout / 10), 3].max,
22
- client_name: Berkshelf::Config.instance.chef.node_name,
23
- server_url: Berkshelf::Config.instance.chef.chef_server_url,
24
- client_key: Berkshelf::Config.instance.chef.client_key,
25
- )
26
- else
27
- APIClient.new(uri,
28
- timeout: api_timeout,
29
- open_timeout: [(api_timeout / 10), 3].max,
30
- ssl: Berkshelf::Config.instance.ssl
31
- )
32
- end
61
+ @api_client ||= case type
62
+ when :chef_server
63
+ APIClient.chef_server(server_url: uri.to_s, **options)
64
+ when :artifactory
65
+ # Don't accidentally mutate the options.
66
+ client_options = options.dup
67
+ api_key = client_options.delete(:api_key)
68
+ APIClient.new(uri, headers: { "X-Jfrog-Art-Api" => api_key }, **client_options)
69
+ when :chef_repo
70
+ ChefRepoUniverse.new(uri_string, **options)
71
+ else
72
+ APIClient.new(uri, **options)
33
73
  end
34
74
  end
35
75
 
36
76
  def uri
37
- @uri ||= if source == :chef_server
38
- SourceURI.parse(Berkshelf::Config.instance.chef.chef_server_url)
39
- else
40
- SourceURI.parse(source)
41
- end
77
+ @uri ||= SourceURI.parse(uri_string)
42
78
  end
43
79
 
44
80
  # Forcefully obtain the universe from the API endpoint and assign it to {#universe}. This
@@ -48,7 +84,7 @@ module Berkshelf
48
84
  def build_universe
49
85
  @universe = api_client.universe
50
86
  rescue => ex
51
- @universe = Array.new
87
+ @universe = []
52
88
  raise ex
53
89
  end
54
90
 
@@ -96,7 +132,7 @@ module Berkshelf
96
132
  #
97
133
  # @return [APIClient::RemoteCookbook]
98
134
  def latest(name)
99
- versions(name).sort.last
135
+ versions(name).max
100
136
  end
101
137
 
102
138
  # @param [String] name
@@ -107,20 +143,28 @@ module Berkshelf
107
143
  end
108
144
 
109
145
  def to_s
110
- "#{uri}"
146
+ case type
147
+ when :supermarket
148
+ uri.to_s
149
+ when :chef_repo
150
+ options[:path]
151
+ else
152
+ "#{type}: #{uri}"
153
+ end
111
154
  end
112
155
 
113
156
  def inspect
114
- "#<#{self.class.name} uri: #{@uri.to_s.inspect}>"
157
+ "#<#{self.class.name} #{type}: #{uri.to_s.inspect}, #{options.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}>"
115
158
  end
116
159
 
117
160
  def hash
118
- @uri.host.hash
161
+ [type, uri_string, options].hash
119
162
  end
120
163
 
121
164
  def ==(other)
122
165
  return false unless other.is_a?(self.class)
123
- uri == other.uri
166
+
167
+ type == other.type && uri == other.uri
124
168
  end
125
169
 
126
170
  private
@@ -1,4 +1,4 @@
1
- require 'addressable/uri'
1
+ require "addressable/uri" unless defined?(Addressable::URI)
2
2
 
3
3
  module Berkshelf
4
4
  class SourceURI < Addressable::URI
@@ -22,14 +22,14 @@ module Berkshelf
22
22
  end
23
23
  end
24
24
 
25
- VALID_SCHEMES = [ "http", "https" ].freeze
25
+ VALID_SCHEMES = %w{http https file}.freeze
26
26
 
27
27
  # @raise [Berkshelf::InvalidSourceURI]
28
28
  def validate
29
29
  super
30
30
 
31
- unless VALID_SCHEMES.include?(self.scheme)
32
- raise InvalidSourceURI.new(self, "invalid URI scheme '#{self.scheme}'. Valid schemes: #{VALID_SCHEMES}")
31
+ unless VALID_SCHEMES.include?(scheme)
32
+ raise InvalidSourceURI.new(self, "invalid URI scheme '#{scheme}'. Valid schemes: #{VALID_SCHEMES}")
33
33
  end
34
34
  rescue Addressable::URI::InvalidURIError => ex
35
35
  raise InvalidSourceURI.new(self, ex)
@@ -0,0 +1,38 @@
1
+ require "openssl" unless defined?(OpenSSL)
2
+
3
+ module Berkshelf
4
+ class SSLPolicy
5
+
6
+ # @return [Store]
7
+ # Holds trusted CA certificates used to verify peer certificates
8
+ attr_reader :store
9
+
10
+ def initialize
11
+ @store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
12
+
13
+ set_custom_certs if ::File.exist?(trusted_certs_dir)
14
+ end
15
+
16
+ def add_trusted_cert(cert)
17
+ @store.add_cert(cert)
18
+ rescue OpenSSL::X509::StoreError => e
19
+ raise e unless e.message.match(/cert already in hash table/)
20
+ end
21
+
22
+ def trusted_certs_dir
23
+ config_dir = Berkshelf.config.chef.trusted_certs_dir.to_s.tr("\\", "/")
24
+ if config_dir.empty? || !::File.exist?(config_dir)
25
+ File.join(ENV["HOME"], ".chef", "trusted_certs")
26
+ else
27
+ config_dir
28
+ end
29
+ end
30
+
31
+ def set_custom_certs
32
+ ::Dir.glob("#{trusted_certs_dir}/{*.crt,*.pem}").each do |cert|
33
+ cert = OpenSSL::X509::Certificate.new(IO.read(cert))
34
+ add_trusted_cert(cert)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1 +1 @@
1
- require 'berkshelf/cli'
1
+ require_relative "cli"
@@ -1,5 +1,5 @@
1
1
  class Thor
2
- module CoreExt #:nodoc:
2
+ module CoreExt # :nodoc:
3
3
  class HashWithIndifferentAccess < ::Hash
4
4
  def has_key?(key)
5
5
  super(convert_key(key))
@@ -1,3 +1,3 @@
1
1
  Dir["#{File.dirname(__FILE__)}/thor_ext/*.rb"].sort.each do |path|
2
- require_relative "thor_ext/#{File.basename(path, '.rb')}"
2
+ require_relative "thor_ext/#{File.basename(path, ".rb")}"
3
3
  end