chef-dk 0.13.21 → 0.14.25

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 (336) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +186 -186
  3. data/Gemfile +37 -14
  4. data/Gemfile.lock +178 -72
  5. data/LICENSE +201 -201
  6. data/README.md +11 -148
  7. data/acceptance/.shared/kitchen_acceptance/.kitchen.digitalocean.yml +27 -27
  8. data/acceptance/.shared/kitchen_acceptance/.kitchen.ec2.yml +288 -288
  9. data/acceptance/.shared/kitchen_acceptance/.kitchen.vagrant.yml +52 -52
  10. data/acceptance/.shared/kitchen_acceptance/libraries/kitchen.rb +51 -51
  11. data/acceptance/.shared/kitchen_acceptance/metadata.rb +1 -1
  12. data/acceptance/Gemfile +2 -1
  13. data/acceptance/Gemfile.lock +39 -42
  14. data/acceptance/README.md +132 -132
  15. data/acceptance/trivial/.acceptance/acceptance-cookbook/.gitignore +2 -2
  16. data/acceptance/trivial/.acceptance/acceptance-cookbook/metadata.rb +2 -2
  17. data/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/destroy.rb +1 -1
  18. data/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/provision.rb +1 -1
  19. data/acceptance/trivial/.acceptance/acceptance-cookbook/recipes/verify.rb +1 -1
  20. data/acceptance/trivial/.kitchen.yml +7 -7
  21. data/acceptance/trivial/test/integration/chefdk-current-install/inspec/chef_client_spec.rb +5 -5
  22. data/bin/chef +25 -25
  23. data/lib/chef-dk.rb +19 -19
  24. data/lib/chef-dk/authenticated_http.rb +40 -40
  25. data/lib/chef-dk/chef_runner.rb +107 -107
  26. data/lib/chef-dk/cli.rb +200 -200
  27. data/lib/chef-dk/command/base.rb +79 -79
  28. data/lib/chef-dk/command/clean_policy_cookbooks.rb +116 -116
  29. data/lib/chef-dk/command/clean_policy_revisions.rb +113 -113
  30. data/lib/chef-dk/command/delete_policy.rb +122 -122
  31. data/lib/chef-dk/command/delete_policy_group.rb +122 -122
  32. data/lib/chef-dk/command/diff.rb +316 -316
  33. data/lib/chef-dk/command/env.rb +90 -90
  34. data/lib/chef-dk/command/exec.rb +45 -45
  35. data/lib/chef-dk/command/export.rb +157 -157
  36. data/lib/chef-dk/command/gem.rb +47 -47
  37. data/lib/chef-dk/command/generate.rb +120 -120
  38. data/lib/chef-dk/command/generator_commands.rb +83 -80
  39. data/lib/chef-dk/command/generator_commands/app.rb +107 -107
  40. data/lib/chef-dk/command/generator_commands/attribute.rb +37 -37
  41. data/lib/chef-dk/command/generator_commands/base.rb +148 -148
  42. data/lib/chef-dk/command/generator_commands/cookbook.rb +153 -153
  43. data/lib/chef-dk/command/generator_commands/cookbook_code_file.rb +100 -100
  44. data/lib/chef-dk/command/generator_commands/cookbook_file.rb +45 -45
  45. data/lib/chef-dk/command/generator_commands/generator_generator.rb +177 -177
  46. data/lib/chef-dk/command/generator_commands/lwrp.rb +36 -36
  47. data/lib/chef-dk/command/generator_commands/policyfile.rb +127 -127
  48. data/lib/chef-dk/command/generator_commands/recipe.rb +36 -36
  49. data/lib/chef-dk/command/generator_commands/repo.rb +125 -125
  50. data/lib/chef-dk/command/generator_commands/template.rb +46 -46
  51. data/lib/chef-dk/command/install.rb +121 -121
  52. data/lib/chef-dk/command/provision.rb +438 -438
  53. data/lib/chef-dk/command/push.rb +118 -118
  54. data/lib/chef-dk/command/push_archive.rb +126 -126
  55. data/lib/chef-dk/command/shell_init.rb +180 -180
  56. data/lib/chef-dk/command/show_policy.rb +165 -165
  57. data/lib/chef-dk/command/undelete.rb +155 -155
  58. data/lib/chef-dk/command/update.rb +148 -148
  59. data/lib/chef-dk/command/verify.rb +106 -29
  60. data/lib/chef-dk/completions/bash.sh.erb +5 -5
  61. data/lib/chef-dk/completions/chef.fish.erb +10 -10
  62. data/lib/chef-dk/completions/zsh.zsh.erb +21 -21
  63. data/lib/chef-dk/component_test.rb +30 -1
  64. data/lib/chef-dk/configurable.rb +69 -69
  65. data/lib/chef-dk/cookbook_metadata.rb +45 -45
  66. data/lib/chef-dk/cookbook_omnifetch.rb +32 -32
  67. data/lib/chef-dk/cookbook_profiler/git.rb +151 -151
  68. data/lib/chef-dk/cookbook_profiler/identifiers.rb +72 -72
  69. data/lib/chef-dk/cookbook_profiler/null_scm.rb +32 -32
  70. data/lib/chef-dk/exceptions.rb +129 -129
  71. data/lib/chef-dk/generator.rb +163 -163
  72. data/lib/chef-dk/helpers.rb +159 -159
  73. data/lib/chef-dk/pager.rb +106 -106
  74. data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +138 -138
  75. data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +54 -54
  76. data/lib/chef-dk/policyfile/community_cookbook_source.rb +97 -97
  77. data/lib/chef-dk/policyfile/comparison_base.rb +124 -124
  78. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +154 -154
  79. data/lib/chef-dk/policyfile/cookbook_locks.rb +466 -466
  80. data/lib/chef-dk/policyfile/cookbook_sources.rb +22 -22
  81. data/lib/chef-dk/policyfile/delivery_supermarket_source.rb +90 -90
  82. data/lib/chef-dk/policyfile/differ.rb +266 -266
  83. data/lib/chef-dk/policyfile/dsl.rb +261 -261
  84. data/lib/chef-dk/policyfile/lister.rb +232 -232
  85. data/lib/chef-dk/policyfile/null_cookbook_source.rb +45 -45
  86. data/lib/chef-dk/policyfile/read_cookbook_for_compat_mode_upload.rb +124 -124
  87. data/lib/chef-dk/policyfile/reports/install.rb +70 -70
  88. data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -58
  89. data/lib/chef-dk/policyfile/reports/upload.rb +70 -70
  90. data/lib/chef-dk/policyfile/solution_dependencies.rb +298 -298
  91. data/lib/chef-dk/policyfile/storage_config.rb +100 -100
  92. data/lib/chef-dk/policyfile/undo_record.rb +142 -142
  93. data/lib/chef-dk/policyfile/undo_stack.rb +130 -130
  94. data/lib/chef-dk/policyfile/uploader.rb +213 -213
  95. data/lib/chef-dk/policyfile_compiler.rb +419 -419
  96. data/lib/chef-dk/policyfile_lock.rb +552 -552
  97. data/lib/chef-dk/policyfile_services/clean_policies.rb +95 -95
  98. data/lib/chef-dk/policyfile_services/clean_policy_cookbooks.rb +125 -125
  99. data/lib/chef-dk/policyfile_services/export_repo.rb +421 -421
  100. data/lib/chef-dk/policyfile_services/install.rb +126 -126
  101. data/lib/chef-dk/policyfile_services/push.rb +114 -114
  102. data/lib/chef-dk/policyfile_services/push_archive.rb +204 -204
  103. data/lib/chef-dk/policyfile_services/rm_policy.rb +142 -142
  104. data/lib/chef-dk/policyfile_services/rm_policy_group.rb +86 -86
  105. data/lib/chef-dk/policyfile_services/show_policy.rb +237 -237
  106. data/lib/chef-dk/policyfile_services/undelete.rb +108 -108
  107. data/lib/chef-dk/policyfile_services/update_attributes.rb +104 -104
  108. data/lib/chef-dk/service_exception_inspectors.rb +25 -25
  109. data/lib/chef-dk/service_exception_inspectors/base.rb +40 -40
  110. data/lib/chef-dk/service_exception_inspectors/http.rb +121 -121
  111. data/lib/chef-dk/service_exceptions.rb +143 -143
  112. data/lib/chef-dk/shell_out.rb +36 -36
  113. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +3 -3
  114. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +102 -102
  115. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README-policy.md +9 -9
  116. data/lib/chef-dk/skeletons/code_generator/files/default/cookbook_readmes/README.md +54 -54
  117. data/lib/chef-dk/skeletons/code_generator/files/default/gitignore +16 -16
  118. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +28 -28
  119. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/README.md +27 -27
  120. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +7 -7
  121. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/metadata.rb +3 -3
  122. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +8 -8
  123. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/README.md +58 -58
  124. data/lib/chef-dk/skeletons/code_generator/files/default/repo/data_bags/example/example_item.json +3 -3
  125. data/lib/chef-dk/skeletons/code_generator/files/default/repo/dot-chef-repo.txt +6 -6
  126. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/README.md +9 -9
  127. data/lib/chef-dk/skeletons/code_generator/files/default/repo/environments/example.json +12 -12
  128. data/lib/chef-dk/skeletons/code_generator/files/default/repo/policies/README.md +24 -24
  129. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/README.md +9 -9
  130. data/lib/chef-dk/skeletons/code_generator/files/default/repo/roles/example.json +12 -12
  131. data/lib/chef-dk/skeletons/code_generator/files/default/serverspec_spec_helper.rb +8 -8
  132. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +2 -2
  133. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper_policyfile.rb +2 -2
  134. data/lib/chef-dk/skeletons/code_generator/metadata.rb +8 -8
  135. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +97 -97
  136. data/lib/chef-dk/skeletons/code_generator/recipes/attribute.rb +12 -12
  137. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +117 -117
  138. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook_file.rb +24 -24
  139. data/lib/chef-dk/skeletons/code_generator/recipes/lwrp.rb +23 -23
  140. data/lib/chef-dk/skeletons/code_generator/recipes/policyfile.rb +8 -8
  141. data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +27 -27
  142. data/lib/chef-dk/skeletons/code_generator/recipes/repo.rb +67 -67
  143. data/lib/chef-dk/skeletons/code_generator/recipes/template.rb +32 -32
  144. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.all_rights.erb +3 -3
  145. data/lib/chef-dk/skeletons/code_generator/templates/default/{LICENSE.apache2.erb → LICENSE.apachev2.erb} +201 -201
  146. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv2.erb +339 -339
  147. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.gplv3.erb +674 -674
  148. data/lib/chef-dk/skeletons/code_generator/templates/default/LICENSE.mit.erb +21 -21
  149. data/lib/chef-dk/skeletons/code_generator/templates/default/Policyfile.rb.erb +25 -25
  150. data/lib/chef-dk/skeletons/code_generator/templates/default/README.md.erb +4 -4
  151. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +21 -21
  152. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen_policyfile.yml.erb +32 -32
  153. data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +7 -7
  154. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +5 -5
  155. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe_spec.rb.erb +20 -20
  156. data/lib/chef-dk/skeletons/code_generator/templates/default/repo/gitignore.erb +11 -11
  157. data/lib/chef-dk/skeletons/code_generator/templates/default/serverspec_default_spec.rb.erb +9 -9
  158. data/lib/chef-dk/ui.rb +58 -58
  159. data/lib/chef-dk/version.rb +1 -1
  160. data/lib/kitchen/provisioner/policyfile_zero.rb +195 -195
  161. data/omnibus_overrides.rb +19 -11
  162. data/spec/shared/a_file_generator.rb +125 -125
  163. data/spec/shared/a_generated_file.rb +12 -12
  164. data/spec/shared/command_with_ui_object.rb +11 -11
  165. data/spec/shared/custom_generator_cookbook.rb +130 -130
  166. data/spec/shared/fixture_cookbook_checksums.rb +47 -47
  167. data/spec/shared/setup_git_cookbooks.rb +53 -53
  168. data/spec/spec_helper.rb +51 -51
  169. data/spec/test_helpers.rb +84 -84
  170. data/spec/unit/chef_runner_spec.rb +139 -139
  171. data/spec/unit/cli_spec.rb +357 -357
  172. data/spec/unit/command/base_spec.rb +173 -169
  173. data/spec/unit/command/clean_policy_cookbooks_spec.rb +181 -181
  174. data/spec/unit/command/clean_policy_revisions_spec.rb +181 -181
  175. data/spec/unit/command/delete_policy_group_spec.rb +207 -207
  176. data/spec/unit/command/delete_policy_spec.rb +207 -207
  177. data/spec/unit/command/diff_spec.rb +312 -312
  178. data/spec/unit/command/env_spec.rb +52 -52
  179. data/spec/unit/command/exec_spec.rb +179 -179
  180. data/spec/unit/command/export_spec.rb +200 -200
  181. data/spec/unit/command/generate_spec.rb +142 -142
  182. data/spec/unit/command/generator_commands/app_spec.rb +169 -169
  183. data/spec/unit/command/generator_commands/attribute_spec.rb +32 -32
  184. data/spec/unit/command/generator_commands/base_spec.rb +136 -136
  185. data/spec/unit/command/generator_commands/cookbook_file_spec.rb +32 -32
  186. data/spec/unit/command/generator_commands/cookbook_spec.rb +450 -450
  187. data/spec/unit/command/generator_commands/generator_generator_spec.rb +229 -229
  188. data/spec/unit/command/generator_commands/lwrp_spec.rb +32 -32
  189. data/spec/unit/command/generator_commands/policyfile_spec.rb +225 -225
  190. data/spec/unit/command/generator_commands/recipe_spec.rb +34 -34
  191. data/spec/unit/command/generator_commands/repo_spec.rb +374 -367
  192. data/spec/unit/command/generator_commands/template_spec.rb +32 -32
  193. data/spec/unit/command/install_spec.rb +179 -179
  194. data/spec/unit/command/provision_spec.rb +592 -592
  195. data/spec/unit/command/push_archive_spec.rb +153 -153
  196. data/spec/unit/command/push_spec.rb +199 -199
  197. data/spec/unit/command/shell_init_spec.rb +329 -329
  198. data/spec/unit/command/show_policy_spec.rb +235 -235
  199. data/spec/unit/command/undelete_spec.rb +246 -246
  200. data/spec/unit/command/update_spec.rb +275 -275
  201. data/spec/unit/command/verify_spec.rb +15 -6
  202. data/spec/unit/commands_map_spec.rb +57 -57
  203. data/spec/unit/component_test_spec.rb +128 -126
  204. data/spec/unit/configurable_spec.rb +41 -41
  205. data/spec/unit/cookbook_metadata_spec.rb +98 -98
  206. data/spec/unit/cookbook_profiler/git_spec.rb +176 -176
  207. data/spec/unit/cookbook_profiler/identifiers_spec.rb +83 -83
  208. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_one.rb +9 -9
  209. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_two.rb +9 -9
  210. data/spec/unit/fixtures/command/cli_test_command.rb +26 -26
  211. data/spec/unit/fixtures/command/explicit_path_example.rb +7 -7
  212. data/spec/unit/fixtures/configurable/test_config_loader.rb +5 -5
  213. data/spec/unit/fixtures/configurable/test_configurable.rb +10 -10
  214. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  215. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +3 -3
  216. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  217. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/chefignore +96 -96
  218. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  219. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  220. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/.kitchen.yml +16 -16
  221. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +3 -3
  222. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/README.md +4 -4
  223. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/chefignore +96 -96
  224. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/metadata.rb +8 -8
  225. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/recipes/default.rb +8 -8
  226. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/.kitchen.yml +16 -16
  227. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +3 -3
  228. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/README.md +4 -4
  229. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/chefignore +96 -96
  230. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/metadata.rb +8 -8
  231. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/recipes/default.rb +8 -8
  232. data/spec/unit/fixtures/cookbooks_api/pruned_small_universe.json +1321 -1321
  233. data/spec/unit/fixtures/cookbooks_api/small_universe.json +2987 -2987
  234. data/spec/unit/fixtures/cookbooks_api/universe.json +1 -1
  235. data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +36 -36
  236. data/spec/unit/fixtures/dev_cookbooks/README.md +16 -16
  237. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/integration_test +2 -2
  238. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/verify_me +5 -5
  239. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef/verify_me +3 -3
  240. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/test-kitchen/verify_me +2 -2
  241. data/spec/unit/fixtures/example_cookbook/.gitignore +17 -17
  242. data/spec/unit/fixtures/example_cookbook/.kitchen.yml +16 -16
  243. data/spec/unit/fixtures/example_cookbook/Berksfile +3 -3
  244. data/spec/unit/fixtures/example_cookbook/README.md +4 -4
  245. data/spec/unit/fixtures/example_cookbook/chefignore +96 -96
  246. data/spec/unit/fixtures/example_cookbook/metadata.rb +8 -8
  247. data/spec/unit/fixtures/example_cookbook/recipes/default.rb +8 -8
  248. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.gitignore +17 -17
  249. data/spec/unit/fixtures/example_cookbook_metadata_json_only/.kitchen.yml +16 -16
  250. data/spec/unit/fixtures/example_cookbook_metadata_json_only/Berksfile +3 -3
  251. data/spec/unit/fixtures/example_cookbook_metadata_json_only/README.md +4 -4
  252. data/spec/unit/fixtures/example_cookbook_metadata_json_only/chefignore +96 -96
  253. data/spec/unit/fixtures/example_cookbook_metadata_json_only/metadata.json +5 -5
  254. data/spec/unit/fixtures/example_cookbook_metadata_json_only/recipes/default.rb +8 -8
  255. data/spec/unit/fixtures/example_cookbook_no_metadata/.gitignore +17 -17
  256. data/spec/unit/fixtures/example_cookbook_no_metadata/.kitchen.yml +16 -16
  257. data/spec/unit/fixtures/example_cookbook_no_metadata/Berksfile +3 -3
  258. data/spec/unit/fixtures/example_cookbook_no_metadata/README.md +4 -4
  259. data/spec/unit/fixtures/example_cookbook_no_metadata/chefignore +96 -96
  260. data/spec/unit/fixtures/example_cookbook_no_metadata/recipes/default.rb +8 -8
  261. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/README.md +4 -4
  262. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/chefignore +96 -96
  263. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/metadata.rb +8 -8
  264. data/spec/unit/fixtures/local_path_cookbooks/another-local-cookbook/recipes/default.rb +8 -8
  265. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/Berksfile +3 -3
  266. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/README.md +4 -4
  267. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/chefignore +96 -96
  268. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/metadata.rb +9 -9
  269. data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/recipes/default.rb +8 -8
  270. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/.kitchen.yml +16 -16
  271. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +3 -3
  272. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/README.md +4 -4
  273. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/chefignore +96 -96
  274. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/metadata.rb +8 -8
  275. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/recipes/default.rb +8 -8
  276. data/spec/unit/fixtures/local_path_cookbooks/metadata-missing/README.md +2 -2
  277. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -16
  278. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -4
  279. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -8
  280. data/spec/unit/fixtures/local_path_cookbooks/noignore-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -8
  281. data/spec/unit/generator_spec.rb +119 -120
  282. data/spec/unit/helpers_spec.rb +92 -92
  283. data/spec/unit/pager_spec.rb +119 -119
  284. data/spec/unit/policyfile/chef_repo_cookbook_source_spec.rb +93 -93
  285. data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +34 -34
  286. data/spec/unit/policyfile/community_cookbook_source_spec.rb +84 -84
  287. data/spec/unit/policyfile/comparison_base_spec.rb +343 -343
  288. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +277 -277
  289. data/spec/unit/policyfile/cookbook_locks_spec.rb +529 -529
  290. data/spec/unit/policyfile/delivery_supermarket_source_spec.rb +130 -130
  291. data/spec/unit/policyfile/differ_spec.rb +687 -687
  292. data/spec/unit/policyfile/lister_spec.rb +272 -272
  293. data/spec/unit/policyfile/null_cookbook_source_spec.rb +35 -35
  294. data/spec/unit/policyfile/read_cookbook_for_compat_mode_upload_spec.rb +92 -92
  295. data/spec/unit/policyfile/reports/install_spec.rb +115 -115
  296. data/spec/unit/policyfile/reports/upload_spec.rb +96 -96
  297. data/spec/unit/policyfile/solution_dependencies_spec.rb +145 -145
  298. data/spec/unit/policyfile/storage_config_spec.rb +172 -172
  299. data/spec/unit/policyfile/undo_record_spec.rb +260 -260
  300. data/spec/unit/policyfile/undo_stack_spec.rb +266 -266
  301. data/spec/unit/policyfile/uploader_spec.rb +410 -410
  302. data/spec/unit/policyfile_demands_spec.rb +1203 -1203
  303. data/spec/unit/policyfile_evaluation_spec.rb +642 -642
  304. data/spec/unit/policyfile_lock_build_spec.rb +1056 -1056
  305. data/spec/unit/policyfile_lock_install_spec.rb +138 -138
  306. data/spec/unit/policyfile_lock_serialization_spec.rb +425 -425
  307. data/spec/unit/policyfile_lock_validation_spec.rb +611 -611
  308. data/spec/unit/policyfile_services/clean_policies_spec.rb +236 -236
  309. data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +275 -275
  310. data/spec/unit/policyfile_services/export_repo_spec.rb +481 -481
  311. data/spec/unit/policyfile_services/install_spec.rb +211 -211
  312. data/spec/unit/policyfile_services/push_archive_spec.rb +378 -378
  313. data/spec/unit/policyfile_services/push_spec.rb +233 -233
  314. data/spec/unit/policyfile_services/rm_policy_group_spec.rb +241 -241
  315. data/spec/unit/policyfile_services/rm_policy_spec.rb +266 -266
  316. data/spec/unit/policyfile_services/show_policy_spec.rb +889 -889
  317. data/spec/unit/policyfile_services/undelete_spec.rb +304 -304
  318. data/spec/unit/policyfile_services/update_attributes_spec.rb +217 -217
  319. data/spec/unit/service_exception_inspectors/base_spec.rb +43 -43
  320. data/spec/unit/service_exception_inspectors/http_spec.rb +140 -140
  321. data/spec/unit/shell_out_spec.rb +34 -34
  322. data/spec/unit/tasks/helpers_spec.rb +75 -0
  323. data/tasks/bin/bundle-platform +0 -0
  324. data/tasks/bin/bundle-platform.bat +0 -0
  325. data/tasks/bin/create-override-gemfile +110 -0
  326. data/tasks/bundle.rb +27 -11
  327. data/tasks/bundle_util.rb +6 -5
  328. data/tasks/dependencies.rb +97 -122
  329. data/tasks/gemfile_util.rb +357 -66
  330. data/tasks/helpers.rb +47 -0
  331. data/tasks/version.rb +1 -5
  332. data/version_policy.rb +66 -41
  333. data/warning.txt +9 -9
  334. metadata +7 -5
  335. data/Gemfile.windows +0 -34
  336. data/Gemfile.windows.lock +0 -936
@@ -1,552 +1,552 @@
1
- # -*- coding: UTF-8 -*-
2
- #
3
- # Copyright:: Copyright (c) 2014 Chef Software Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require 'digest/sha2'
20
-
21
- require 'chef-dk/policyfile/storage_config'
22
- require 'chef-dk/policyfile/cookbook_locks'
23
- require 'chef-dk/policyfile/solution_dependencies'
24
- require 'chef-dk/ui'
25
-
26
- module ChefDK
27
-
28
- class PolicyfileLock
29
-
30
- class InstallReport
31
-
32
- attr_reader :ui
33
- attr_reader :policyfile_lock
34
-
35
- def initialize(ui: nil, policyfile_lock: nil)
36
- @ui = ui
37
- @policyfile_lock = policyfile_lock
38
-
39
- @cookbook_name_width = nil
40
- @cookbook_version_width = nil
41
- end
42
-
43
- def installing_fixed_version_cookbook(cookbook_spec)
44
- verb = cookbook_spec.installed? ? "Using " : "Installing"
45
- ui.msg("#{verb} #{format_fixed_version_cookbook(cookbook_spec)}")
46
- end
47
-
48
- def installing_cookbook(cookbook_lock)
49
- verb = cookbook_lock.installed? ? "Using " : "Installing"
50
- ui.msg("#{verb} #{format_cookbook(cookbook_lock)}")
51
- end
52
-
53
- private
54
-
55
- def format_cookbook(cookbook_lock)
56
- "#{cookbook_lock.name.ljust(cookbook_name_width)} #{cookbook_lock.version.to_s.ljust(cookbook_version_width)}"
57
- end
58
-
59
- def cookbook_name_width
60
- policyfile_lock.cookbook_locks.map { |name, _| name.size }.max
61
- end
62
-
63
- def cookbook_version_width
64
- policyfile_lock.cookbook_locks.map { |_, lock| lock.version.size }.max
65
- end
66
- end
67
-
68
- RUN_LIST_ITEM_FORMAT = /\Arecipe\[[^\s]+::[^\s]+\]\Z/.freeze
69
-
70
- def self.build(storage_config)
71
- lock = new(storage_config)
72
- yield lock
73
- lock
74
- end
75
-
76
- def self.build_from_compiler(compiler, storage_config)
77
- lock = new(storage_config)
78
- lock.build_from_compiler(compiler)
79
- lock
80
- end
81
-
82
- include Policyfile::StorageConfigDelegation
83
-
84
- attr_accessor :name
85
- attr_accessor :run_list
86
- attr_accessor :named_run_lists
87
- attr_accessor :default_attributes
88
- attr_accessor :override_attributes
89
-
90
- attr_reader :solution_dependencies
91
-
92
- attr_reader :storage_config
93
-
94
- attr_reader :cookbook_locks
95
-
96
- attr_reader :install_report
97
-
98
- def initialize(storage_config, ui: nil)
99
- @name = nil
100
- @run_list = []
101
- @named_run_lists = {}
102
- @cookbook_locks = {}
103
- @relative_paths_root = Dir.pwd
104
- @storage_config = storage_config
105
- @ui = ui || UI.null
106
-
107
- @default_attributes = {}
108
- @override_attributes = {}
109
-
110
- @solution_dependencies = Policyfile::SolutionDependencies.new
111
- @install_report = InstallReport.new(ui: @ui, policyfile_lock: self)
112
- end
113
-
114
- def lock_data_for(cookbook_name)
115
- @cookbook_locks[cookbook_name]
116
- end
117
-
118
- def cached_cookbook(name)
119
- cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
120
- yield cached_cookbook if block_given?
121
- @cookbook_locks[name] = cached_cookbook
122
- end
123
-
124
- def local_cookbook(name)
125
- local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
126
- yield local_cookbook if block_given?
127
- @cookbook_locks[name] = local_cookbook
128
- end
129
-
130
- def dependencies
131
- yield solution_dependencies
132
- end
133
-
134
- def to_lock
135
- {}.tap do |lock|
136
- lock["revision_id"] = revision_id
137
- lock["name"] = name
138
- lock["run_list"] = run_list
139
- lock["named_run_lists"] = named_run_lists unless named_run_lists.empty?
140
- lock["cookbook_locks"] = cookbook_locks_for_lockfile
141
- lock["default_attributes"] = default_attributes
142
- lock["override_attributes"] = override_attributes
143
- lock["solution_dependencies"] = solution_dependencies.to_lock
144
- end
145
- end
146
-
147
- # Returns a fingerprint of the PolicyfileLock by computing the SHA1 hash of
148
- # #canonical_revision_string
149
- def revision_id
150
- Digest::SHA256.new.hexdigest(canonical_revision_string)
151
- end
152
-
153
- # Generates a string representation of the lock data in a specialized
154
- # format suitable for generating a checksum of the lock itself. Only data
155
- # that modifies the behavior of a chef-client using the lockfile is
156
- # included in this format; for example, a modification to the source
157
- # options in a `Policyfile.rb` that yields identical code (such as
158
- # switching to a github fork at the same revision) will not cause a change
159
- # in the PolicyfileLock's canonical_revision_string.
160
- #
161
- # This format is intended to be used only for generating an identifier for
162
- # a particular revision of a PolicyfileLock. It should not be used as a
163
- # serialization format, and is not guaranteed to be a stable interface.
164
- def canonical_revision_string
165
- canonical_rev_text = ""
166
-
167
- canonical_rev_text << "name:#{name}\n"
168
-
169
- run_list.each do |item|
170
- canonical_rev_text << "run-list-item:#{item}\n"
171
- end
172
-
173
- named_run_lists.each do |name, run_list|
174
- run_list.each do |item|
175
- canonical_rev_text << "named-run-list:#{name};run-list-item:#{item}\n"
176
- end
177
- end
178
-
179
- cookbook_locks_for_lockfile.each do |name, lock|
180
- canonical_rev_text << "cookbook:#{name};id:#{lock["identifier"]}\n"
181
- end
182
-
183
- canonical_rev_text << "default_attributes:#{canonicalize(default_attributes)}\n"
184
-
185
- canonical_rev_text << "override_attributes:#{canonicalize(override_attributes)}\n"
186
-
187
- canonical_rev_text
188
- end
189
-
190
- def cookbook_locks_for_lockfile
191
- cookbook_locks.inject({}) do |locks_map, (name, location_spec)|
192
- location_spec.validate!
193
- location_spec.gather_profile_data
194
- locks_map[name] = location_spec.to_lock
195
- locks_map
196
- end
197
- end
198
-
199
- def validate_cookbooks!
200
- cookbook_locks.each do |name, cookbook_lock|
201
- cookbook_lock.validate!
202
- cookbook_lock.refresh!
203
- end
204
-
205
- # Check that versions and dependencies are still valid. First we need to
206
- # refresh the dependency info for everything that has changed, then we
207
- # check that the new versions and dependencies are valid for the working
208
- # set of cookbooks. We can't do this in a single loop because the user
209
- # may have modified two cookbooks such that the versions and constraints
210
- # are only valid when both changes are considered together.
211
- cookbook_locks.each do |name, cookbook_lock|
212
- if cookbook_lock.updated?
213
- solution_dependencies.update_cookbook_dep(name, cookbook_lock.version, cookbook_lock.dependencies)
214
- end
215
- end
216
- cookbook_locks.each do |name, cookbook_lock|
217
- if cookbook_lock.updated?
218
- solution_dependencies.test_conflict!(cookbook_lock.name, cookbook_lock.version)
219
- end
220
- end
221
-
222
- true
223
- end
224
-
225
- def build_from_compiler(compiler)
226
- @name = compiler.name
227
-
228
- @run_list = compiler.normalized_run_list
229
-
230
- @named_run_lists = compiler.normalized_named_run_lists
231
-
232
- compiler.all_cookbook_location_specs.each do |cookbook_name, spec|
233
- if spec.mirrors_canonical_upstream?
234
- cached_cookbook(cookbook_name) do |cached_cb|
235
- cached_cb.cache_key = spec.cache_key
236
- cached_cb.origin = spec.uri
237
- cached_cb.source_options = spec.source_options_for_lock
238
- end
239
- else
240
- local_cookbook(cookbook_name) do |local_cb|
241
- local_cb.source = spec.relative_path
242
- local_cb.source_options = spec.source_options_for_lock
243
- end
244
- end
245
- end
246
-
247
- @default_attributes = compiler.default_attributes
248
- @override_attributes = compiler.override_attributes
249
-
250
- @solution_dependencies = compiler.solution_dependencies
251
-
252
- self
253
- end
254
-
255
- def build_from_lock_data(lock_data)
256
- set_name_from_lock_data(lock_data)
257
- set_run_list_from_lock_data(lock_data)
258
- set_named_run_lists_from_lock_data(lock_data)
259
- set_cookbook_locks_from_lock_data(lock_data)
260
- set_attributes_from_lock_data(lock_data)
261
- set_solution_dependencies_from_lock_data(lock_data)
262
- self
263
- end
264
-
265
- def build_from_archive(lock_data)
266
- set_name_from_lock_data(lock_data)
267
- set_run_list_from_lock_data(lock_data)
268
- set_named_run_lists_from_lock_data(lock_data)
269
- set_cookbook_locks_as_archives_from_lock_data(lock_data)
270
- set_attributes_from_lock_data(lock_data)
271
- set_solution_dependencies_from_lock_data(lock_data)
272
- self
273
- end
274
-
275
- def install_cookbooks
276
- # note: duplicates PolicyfileCompiler#ensure_cache_dir_exists
277
- ensure_cache_dir_exists
278
-
279
- cookbook_locks.each do |cookbook_name, cookbook_lock|
280
- install_report.installing_cookbook(cookbook_lock)
281
- cookbook_lock.install_locked
282
- end
283
- end
284
-
285
- def ensure_cache_dir_exists
286
- # note: duplicates PolicyfileCompiler#ensure_cache_dir_exists
287
- unless File.exist?(cache_path)
288
- FileUtils.mkdir_p(cache_path)
289
- end
290
- end
291
-
292
- private
293
-
294
- # Generates a canonical JSON representation of the attributes. Based on
295
- # http://wiki.laptop.org/go/Canonical_JSON but not quite as strict, yet.
296
- #
297
- # In particular:
298
- # - String encoding stuff isn't normalized
299
- # - We allow floats that fit within the range/precision requirements of
300
- # IEEE 754-2008 binary64 (double precision) numbers.
301
- # - +/- Infinity and NaN are banned, but float/numeric size aren't checked.
302
- # numerics should be in range [-(2**53)+1, (2**53)-1] to comply with
303
- # IEEE 754-2008
304
- #
305
- # Recursive, so absurd nesting levels could cause a SystemError. Invalid
306
- # input will cause an InvalidPolicyfileAttribute exception.
307
- def canonicalize(attributes)
308
- unless attributes.kind_of?(Hash)
309
- raise "Top level attributes must be a Hash (you gave: #{attributes})"
310
- end
311
- canonicalize_elements(attributes)
312
- end
313
-
314
- def canonicalize_elements(item)
315
- case item
316
- when Hash
317
- # Hash keys will sort differently based on the encoding, but after a
318
- # JSON round trip everything will be UTF-8, so we have to normalize the
319
- # keys to UTF-8 first so that the sort order uses the UTF-8 strings.
320
- item_with_normalized_keys = item.inject({}) do |normalized_item, (key, value)|
321
- validate_attr_key(key)
322
- normalized_item[key.encode('utf-8')] = value
323
- normalized_item
324
- end
325
- elements = item_with_normalized_keys.keys.sort.map do |key|
326
- k = '"' << key << '":'
327
- v = canonicalize_elements(item_with_normalized_keys[key])
328
- k << v
329
- end
330
- "{" << elements.join(',') << "}"
331
- when String
332
- '"' << item.encode('utf-8') << '"'
333
- when Array
334
- elements = item.map { |i| canonicalize_elements(i) }
335
- '[' << elements.join(',') << ']'
336
- when Integer
337
- item.to_s
338
- when Float
339
- unless item.finite?
340
- raise InvalidPolicyfileAttribute, "Floating point numbers cannot be infinite or NaN. You gave #{item.inspect}"
341
- end
342
- # Support for floats assumes that any implementation of our JSON
343
- # canonicalization routine will use IEEE-754 doubles. In decimal terms,
344
- # doubles give 15-17 digits of precision, so we err on the safe side
345
- # and only use 15 digits in the string conversion. We use the `g`
346
- # format, which is a documented-enough "do what I mean" where floats
347
- # >= 0.1 and < precsion are represented as floating point literals, and
348
- # other numbers use the exponent notation with a lowercase 'e'. Note
349
- # that both Ruby and Erlang document what their `g` does but have some
350
- # differences both subtle and non-subtle:
351
- #
352
- # ```ruby
353
- # format("%.15g", 0.1) #=> "0.1"
354
- # format("%.15g", 1_000_000_000.0) #=> "1000000000"
355
- # ```
356
- #
357
- # Whereas:
358
- #
359
- # ```erlang
360
- # lists:flatten(io_lib:format("~.15g", [0.1])). %=> "0.100000000000000"
361
- # lists:flatten(io_lib:format("~.15e", [1000000000.0])). %=> "1.00000000000000e+9"
362
- # ```
363
- #
364
- # Other implementations should normalize to ruby's %.15g behavior.
365
- Kernel.format("%.15g", item)
366
- when NilClass
367
- "null"
368
- when TrueClass
369
- "true"
370
- when FalseClass
371
- "false"
372
- else
373
- raise InvalidPolicyfileAttribute,
374
- "Invalid type in attributes. Only Hash, Array, String, Integer, Float, true, false, and nil are accepted. You gave #{item.inspect} (#{item.class})"
375
- end
376
- end
377
-
378
- def validate_attr_key(key)
379
- unless key.kind_of?(String)
380
- raise InvalidPolicyfileAttribute,
381
- "Attribute keys must be Strings (other types are not allowed in JSON). You gave: #{key.inspect} (#{key.class})"
382
- end
383
- end
384
-
385
- def set_name_from_lock_data(lock_data)
386
- name_attribute = lock_data["name"]
387
-
388
- raise InvalidLockfile, "lockfile does not have a `name' attribute" if name_attribute.nil?
389
-
390
- unless name_attribute.kind_of?(String)
391
- raise InvalidLockfile, "lockfile's name attribute must be a String (got: #{name_attribute.inspect})"
392
- end
393
-
394
- if name_attribute.empty?
395
- raise InvalidLockfile, "lockfile's name attribute cannot be an empty string"
396
- end
397
-
398
- @name = name_attribute
399
-
400
- end
401
-
402
- def set_run_list_from_lock_data(lock_data)
403
- run_list_attribute = lock_data["run_list"]
404
-
405
- raise InvalidLockfile, "lockfile does not have a run_list attribute" if run_list_attribute.nil?
406
-
407
- unless run_list_attribute.kind_of?(Array)
408
- raise InvalidLockfile, "lockfile's run_list must be an array of run list items (got: #{run_list_attribute.inspect})"
409
- end
410
-
411
- bad_run_list_items = run_list_attribute.select { |e| e !~ RUN_LIST_ITEM_FORMAT }
412
-
413
- unless bad_run_list_items.empty?
414
- msg = "lockfile's run_list items must be formatted like `recipe[$COOKBOOK_NAME::$RECIPE_NAME]'. Invalid items: `#{bad_run_list_items.join("' `")}'"
415
- raise InvalidLockfile, msg
416
- end
417
-
418
- @run_list = run_list_attribute
419
- end
420
-
421
- def set_named_run_lists_from_lock_data(lock_data)
422
- return unless lock_data.key?("named_run_lists")
423
-
424
- lock_data_named_run_lists = lock_data["named_run_lists"]
425
-
426
- unless lock_data_named_run_lists.kind_of?(Hash)
427
- msg = "lockfile's named_run_lists must be a Hash (JSON object). (got: #{lock_data_named_run_lists.inspect})"
428
- raise InvalidLockfile, msg
429
- end
430
-
431
- lock_data_named_run_lists.each do |name, run_list|
432
- unless name.kind_of?(String)
433
- msg = "Keys in lockfile's named_run_lists must be Strings. (got: #{name.inspect})"
434
- raise InvalidLockfile, msg
435
- end
436
- unless run_list.kind_of?(Array)
437
- msg = "Values in lockfile's named_run_lists must be Arrays. (got: #{run_list.inspect})"
438
- raise InvalidLockfile, msg
439
- end
440
- bad_run_list_items = run_list.select { |e| e !~ RUN_LIST_ITEM_FORMAT }
441
- unless bad_run_list_items.empty?
442
- msg = "lockfile's run_list items must be formatted like `recipe[$COOKBOOK_NAME::$RECIPE_NAME]'. Invalid items: `#{bad_run_list_items.join("' `")}'"
443
- raise InvalidLockfile, msg
444
- end
445
- end
446
- @named_run_lists = lock_data_named_run_lists
447
- end
448
-
449
- def set_cookbook_locks_from_lock_data(lock_data)
450
- cookbook_lock_data = lock_data["cookbook_locks"]
451
-
452
- if cookbook_lock_data.nil?
453
- raise InvalidLockfile, "lockfile does not have a cookbook_locks attribute"
454
- end
455
-
456
- unless cookbook_lock_data.kind_of?(Hash)
457
- raise InvalidLockfile, "lockfile's cookbook_locks attribute must be a Hash (JSON object). (got: #{cookbook_lock_data.inspect})"
458
- end
459
-
460
- lock_data["cookbook_locks"].each do |name, lock_info|
461
- build_cookbook_lock_from_lock_data(name, lock_info)
462
- end
463
- end
464
-
465
- def set_cookbook_locks_as_archives_from_lock_data(lock_data)
466
- cookbook_lock_data = lock_data["cookbook_locks"]
467
-
468
- if cookbook_lock_data.nil?
469
- raise InvalidLockfile, "lockfile does not have a cookbook_locks attribute"
470
- end
471
-
472
- unless cookbook_lock_data.kind_of?(Hash)
473
- raise InvalidLockfile, "lockfile's cookbook_locks attribute must be a Hash (JSON object). (got: #{cookbook_lock_data.inspect})"
474
- end
475
-
476
- lock_data["cookbook_locks"].each do |name, lock_info|
477
- build_cookbook_lock_as_archive_from_lock_data(name, lock_info)
478
- end
479
- end
480
-
481
- def set_attributes_from_lock_data(lock_data)
482
- default_attr_data = lock_data["default_attributes"]
483
-
484
- if default_attr_data.nil?
485
- raise InvalidLockfile, "lockfile does not have a `default_attributes` attribute"
486
- end
487
-
488
- unless default_attr_data.kind_of?(Hash)
489
- raise InvalidLockfile, "lockfile's `default_attributes` attribute must be a Hash (JSON object). (got: #{default_attr_data.inspect})"
490
- end
491
-
492
- override_attr_data = lock_data["override_attributes"]
493
-
494
- if override_attr_data.nil?
495
- raise InvalidLockfile, "lockfile does not have a `override_attributes` attribute"
496
- end
497
-
498
- unless override_attr_data.kind_of?(Hash)
499
- raise InvalidLockfile, "lockfile's `override_attributes` attribute must be a Hash (JSON object). (got: #{override_attr_data.inspect})"
500
- end
501
-
502
- @default_attributes = default_attr_data
503
- @override_attributes = override_attr_data
504
- end
505
-
506
- def set_solution_dependencies_from_lock_data(lock_data)
507
- soln_deps = lock_data["solution_dependencies"]
508
-
509
- if soln_deps.nil?
510
- raise InvalidLockfile, "lockfile does not have a solution_dependencies attribute"
511
- end
512
-
513
- unless soln_deps.kind_of?(Hash)
514
- raise InvalidLockfile, "lockfile's solution_dependencies attribute must be a Hash (JSON object). (got: #{soln_deps.inspect})"
515
- end
516
-
517
- s = Policyfile::SolutionDependencies.from_lock(lock_data["solution_dependencies"])
518
- @solution_dependencies = s
519
- end
520
-
521
- def build_cookbook_lock_from_lock_data(name, lock_info)
522
- unless lock_info.kind_of?(Hash)
523
- raise InvalidLockfile, "lockfile cookbook_locks entries must be a Hash (JSON object). (got: #{lock_info.inspect})"
524
- end
525
-
526
- if lock_info["cache_key"].nil?
527
- local_cookbook(name).build_from_lock_data(lock_info)
528
- else
529
- cached_cookbook(name).build_from_lock_data(lock_info)
530
- end
531
- end
532
-
533
- def build_cookbook_lock_as_archive_from_lock_data(name, lock_info)
534
- unless lock_info.kind_of?(Hash)
535
- raise InvalidLockfile, "lockfile cookbook_locks entries must be a Hash (JSON object). (got: #{lock_info.inspect})"
536
- end
537
-
538
- if lock_info["cache_key"].nil?
539
- local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
540
- local_cookbook.build_from_lock_data(lock_info)
541
- archived = Policyfile::ArchivedCookbook.new(local_cookbook, storage_config)
542
- @cookbook_locks[name] = archived
543
- else
544
- cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
545
- cached_cookbook.build_from_lock_data(lock_info)
546
- archived = Policyfile::ArchivedCookbook.new(cached_cookbook, storage_config)
547
- @cookbook_locks[name] = archived
548
- end
549
- end
550
-
551
- end
552
- end
1
+ # -*- coding: UTF-8 -*-
2
+ #
3
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'digest/sha2'
20
+
21
+ require 'chef-dk/policyfile/storage_config'
22
+ require 'chef-dk/policyfile/cookbook_locks'
23
+ require 'chef-dk/policyfile/solution_dependencies'
24
+ require 'chef-dk/ui'
25
+
26
+ module ChefDK
27
+
28
+ class PolicyfileLock
29
+
30
+ class InstallReport
31
+
32
+ attr_reader :ui
33
+ attr_reader :policyfile_lock
34
+
35
+ def initialize(ui: nil, policyfile_lock: nil)
36
+ @ui = ui
37
+ @policyfile_lock = policyfile_lock
38
+
39
+ @cookbook_name_width = nil
40
+ @cookbook_version_width = nil
41
+ end
42
+
43
+ def installing_fixed_version_cookbook(cookbook_spec)
44
+ verb = cookbook_spec.installed? ? "Using " : "Installing"
45
+ ui.msg("#{verb} #{format_fixed_version_cookbook(cookbook_spec)}")
46
+ end
47
+
48
+ def installing_cookbook(cookbook_lock)
49
+ verb = cookbook_lock.installed? ? "Using " : "Installing"
50
+ ui.msg("#{verb} #{format_cookbook(cookbook_lock)}")
51
+ end
52
+
53
+ private
54
+
55
+ def format_cookbook(cookbook_lock)
56
+ "#{cookbook_lock.name.ljust(cookbook_name_width)} #{cookbook_lock.version.to_s.ljust(cookbook_version_width)}"
57
+ end
58
+
59
+ def cookbook_name_width
60
+ policyfile_lock.cookbook_locks.map { |name, _| name.size }.max
61
+ end
62
+
63
+ def cookbook_version_width
64
+ policyfile_lock.cookbook_locks.map { |_, lock| lock.version.size }.max
65
+ end
66
+ end
67
+
68
+ RUN_LIST_ITEM_FORMAT = /\Arecipe\[[^\s]+::[^\s]+\]\Z/.freeze
69
+
70
+ def self.build(storage_config)
71
+ lock = new(storage_config)
72
+ yield lock
73
+ lock
74
+ end
75
+
76
+ def self.build_from_compiler(compiler, storage_config)
77
+ lock = new(storage_config)
78
+ lock.build_from_compiler(compiler)
79
+ lock
80
+ end
81
+
82
+ include Policyfile::StorageConfigDelegation
83
+
84
+ attr_accessor :name
85
+ attr_accessor :run_list
86
+ attr_accessor :named_run_lists
87
+ attr_accessor :default_attributes
88
+ attr_accessor :override_attributes
89
+
90
+ attr_reader :solution_dependencies
91
+
92
+ attr_reader :storage_config
93
+
94
+ attr_reader :cookbook_locks
95
+
96
+ attr_reader :install_report
97
+
98
+ def initialize(storage_config, ui: nil)
99
+ @name = nil
100
+ @run_list = []
101
+ @named_run_lists = {}
102
+ @cookbook_locks = {}
103
+ @relative_paths_root = Dir.pwd
104
+ @storage_config = storage_config
105
+ @ui = ui || UI.null
106
+
107
+ @default_attributes = {}
108
+ @override_attributes = {}
109
+
110
+ @solution_dependencies = Policyfile::SolutionDependencies.new
111
+ @install_report = InstallReport.new(ui: @ui, policyfile_lock: self)
112
+ end
113
+
114
+ def lock_data_for(cookbook_name)
115
+ @cookbook_locks[cookbook_name]
116
+ end
117
+
118
+ def cached_cookbook(name)
119
+ cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
120
+ yield cached_cookbook if block_given?
121
+ @cookbook_locks[name] = cached_cookbook
122
+ end
123
+
124
+ def local_cookbook(name)
125
+ local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
126
+ yield local_cookbook if block_given?
127
+ @cookbook_locks[name] = local_cookbook
128
+ end
129
+
130
+ def dependencies
131
+ yield solution_dependencies
132
+ end
133
+
134
+ def to_lock
135
+ {}.tap do |lock|
136
+ lock["revision_id"] = revision_id
137
+ lock["name"] = name
138
+ lock["run_list"] = run_list
139
+ lock["named_run_lists"] = named_run_lists unless named_run_lists.empty?
140
+ lock["cookbook_locks"] = cookbook_locks_for_lockfile
141
+ lock["default_attributes"] = default_attributes
142
+ lock["override_attributes"] = override_attributes
143
+ lock["solution_dependencies"] = solution_dependencies.to_lock
144
+ end
145
+ end
146
+
147
+ # Returns a fingerprint of the PolicyfileLock by computing the SHA1 hash of
148
+ # #canonical_revision_string
149
+ def revision_id
150
+ Digest::SHA256.new.hexdigest(canonical_revision_string)
151
+ end
152
+
153
+ # Generates a string representation of the lock data in a specialized
154
+ # format suitable for generating a checksum of the lock itself. Only data
155
+ # that modifies the behavior of a chef-client using the lockfile is
156
+ # included in this format; for example, a modification to the source
157
+ # options in a `Policyfile.rb` that yields identical code (such as
158
+ # switching to a github fork at the same revision) will not cause a change
159
+ # in the PolicyfileLock's canonical_revision_string.
160
+ #
161
+ # This format is intended to be used only for generating an identifier for
162
+ # a particular revision of a PolicyfileLock. It should not be used as a
163
+ # serialization format, and is not guaranteed to be a stable interface.
164
+ def canonical_revision_string
165
+ canonical_rev_text = ""
166
+
167
+ canonical_rev_text << "name:#{name}\n"
168
+
169
+ run_list.each do |item|
170
+ canonical_rev_text << "run-list-item:#{item}\n"
171
+ end
172
+
173
+ named_run_lists.each do |name, run_list|
174
+ run_list.each do |item|
175
+ canonical_rev_text << "named-run-list:#{name};run-list-item:#{item}\n"
176
+ end
177
+ end
178
+
179
+ cookbook_locks_for_lockfile.each do |name, lock|
180
+ canonical_rev_text << "cookbook:#{name};id:#{lock["identifier"]}\n"
181
+ end
182
+
183
+ canonical_rev_text << "default_attributes:#{canonicalize(default_attributes)}\n"
184
+
185
+ canonical_rev_text << "override_attributes:#{canonicalize(override_attributes)}\n"
186
+
187
+ canonical_rev_text
188
+ end
189
+
190
+ def cookbook_locks_for_lockfile
191
+ cookbook_locks.inject({}) do |locks_map, (name, location_spec)|
192
+ location_spec.validate!
193
+ location_spec.gather_profile_data
194
+ locks_map[name] = location_spec.to_lock
195
+ locks_map
196
+ end
197
+ end
198
+
199
+ def validate_cookbooks!
200
+ cookbook_locks.each do |name, cookbook_lock|
201
+ cookbook_lock.validate!
202
+ cookbook_lock.refresh!
203
+ end
204
+
205
+ # Check that versions and dependencies are still valid. First we need to
206
+ # refresh the dependency info for everything that has changed, then we
207
+ # check that the new versions and dependencies are valid for the working
208
+ # set of cookbooks. We can't do this in a single loop because the user
209
+ # may have modified two cookbooks such that the versions and constraints
210
+ # are only valid when both changes are considered together.
211
+ cookbook_locks.each do |name, cookbook_lock|
212
+ if cookbook_lock.updated?
213
+ solution_dependencies.update_cookbook_dep(name, cookbook_lock.version, cookbook_lock.dependencies)
214
+ end
215
+ end
216
+ cookbook_locks.each do |name, cookbook_lock|
217
+ if cookbook_lock.updated?
218
+ solution_dependencies.test_conflict!(cookbook_lock.name, cookbook_lock.version)
219
+ end
220
+ end
221
+
222
+ true
223
+ end
224
+
225
+ def build_from_compiler(compiler)
226
+ @name = compiler.name
227
+
228
+ @run_list = compiler.normalized_run_list
229
+
230
+ @named_run_lists = compiler.normalized_named_run_lists
231
+
232
+ compiler.all_cookbook_location_specs.each do |cookbook_name, spec|
233
+ if spec.mirrors_canonical_upstream?
234
+ cached_cookbook(cookbook_name) do |cached_cb|
235
+ cached_cb.cache_key = spec.cache_key
236
+ cached_cb.origin = spec.uri
237
+ cached_cb.source_options = spec.source_options_for_lock
238
+ end
239
+ else
240
+ local_cookbook(cookbook_name) do |local_cb|
241
+ local_cb.source = spec.relative_path
242
+ local_cb.source_options = spec.source_options_for_lock
243
+ end
244
+ end
245
+ end
246
+
247
+ @default_attributes = compiler.default_attributes
248
+ @override_attributes = compiler.override_attributes
249
+
250
+ @solution_dependencies = compiler.solution_dependencies
251
+
252
+ self
253
+ end
254
+
255
+ def build_from_lock_data(lock_data)
256
+ set_name_from_lock_data(lock_data)
257
+ set_run_list_from_lock_data(lock_data)
258
+ set_named_run_lists_from_lock_data(lock_data)
259
+ set_cookbook_locks_from_lock_data(lock_data)
260
+ set_attributes_from_lock_data(lock_data)
261
+ set_solution_dependencies_from_lock_data(lock_data)
262
+ self
263
+ end
264
+
265
+ def build_from_archive(lock_data)
266
+ set_name_from_lock_data(lock_data)
267
+ set_run_list_from_lock_data(lock_data)
268
+ set_named_run_lists_from_lock_data(lock_data)
269
+ set_cookbook_locks_as_archives_from_lock_data(lock_data)
270
+ set_attributes_from_lock_data(lock_data)
271
+ set_solution_dependencies_from_lock_data(lock_data)
272
+ self
273
+ end
274
+
275
+ def install_cookbooks
276
+ # note: duplicates PolicyfileCompiler#ensure_cache_dir_exists
277
+ ensure_cache_dir_exists
278
+
279
+ cookbook_locks.each do |cookbook_name, cookbook_lock|
280
+ install_report.installing_cookbook(cookbook_lock)
281
+ cookbook_lock.install_locked
282
+ end
283
+ end
284
+
285
+ def ensure_cache_dir_exists
286
+ # note: duplicates PolicyfileCompiler#ensure_cache_dir_exists
287
+ unless File.exist?(cache_path)
288
+ FileUtils.mkdir_p(cache_path)
289
+ end
290
+ end
291
+
292
+ private
293
+
294
+ # Generates a canonical JSON representation of the attributes. Based on
295
+ # http://wiki.laptop.org/go/Canonical_JSON but not quite as strict, yet.
296
+ #
297
+ # In particular:
298
+ # - String encoding stuff isn't normalized
299
+ # - We allow floats that fit within the range/precision requirements of
300
+ # IEEE 754-2008 binary64 (double precision) numbers.
301
+ # - +/- Infinity and NaN are banned, but float/numeric size aren't checked.
302
+ # numerics should be in range [-(2**53)+1, (2**53)-1] to comply with
303
+ # IEEE 754-2008
304
+ #
305
+ # Recursive, so absurd nesting levels could cause a SystemError. Invalid
306
+ # input will cause an InvalidPolicyfileAttribute exception.
307
+ def canonicalize(attributes)
308
+ unless attributes.kind_of?(Hash)
309
+ raise "Top level attributes must be a Hash (you gave: #{attributes})"
310
+ end
311
+ canonicalize_elements(attributes)
312
+ end
313
+
314
+ def canonicalize_elements(item)
315
+ case item
316
+ when Hash
317
+ # Hash keys will sort differently based on the encoding, but after a
318
+ # JSON round trip everything will be UTF-8, so we have to normalize the
319
+ # keys to UTF-8 first so that the sort order uses the UTF-8 strings.
320
+ item_with_normalized_keys = item.inject({}) do |normalized_item, (key, value)|
321
+ validate_attr_key(key)
322
+ normalized_item[key.encode('utf-8')] = value
323
+ normalized_item
324
+ end
325
+ elements = item_with_normalized_keys.keys.sort.map do |key|
326
+ k = '"' << key << '":'
327
+ v = canonicalize_elements(item_with_normalized_keys[key])
328
+ k << v
329
+ end
330
+ "{" << elements.join(',') << "}"
331
+ when String
332
+ '"' << item.encode('utf-8') << '"'
333
+ when Array
334
+ elements = item.map { |i| canonicalize_elements(i) }
335
+ '[' << elements.join(',') << ']'
336
+ when Integer
337
+ item.to_s
338
+ when Float
339
+ unless item.finite?
340
+ raise InvalidPolicyfileAttribute, "Floating point numbers cannot be infinite or NaN. You gave #{item.inspect}"
341
+ end
342
+ # Support for floats assumes that any implementation of our JSON
343
+ # canonicalization routine will use IEEE-754 doubles. In decimal terms,
344
+ # doubles give 15-17 digits of precision, so we err on the safe side
345
+ # and only use 15 digits in the string conversion. We use the `g`
346
+ # format, which is a documented-enough "do what I mean" where floats
347
+ # >= 0.1 and < precsion are represented as floating point literals, and
348
+ # other numbers use the exponent notation with a lowercase 'e'. Note
349
+ # that both Ruby and Erlang document what their `g` does but have some
350
+ # differences both subtle and non-subtle:
351
+ #
352
+ # ```ruby
353
+ # format("%.15g", 0.1) #=> "0.1"
354
+ # format("%.15g", 1_000_000_000.0) #=> "1000000000"
355
+ # ```
356
+ #
357
+ # Whereas:
358
+ #
359
+ # ```erlang
360
+ # lists:flatten(io_lib:format("~.15g", [0.1])). %=> "0.100000000000000"
361
+ # lists:flatten(io_lib:format("~.15e", [1000000000.0])). %=> "1.00000000000000e+9"
362
+ # ```
363
+ #
364
+ # Other implementations should normalize to ruby's %.15g behavior.
365
+ Kernel.format("%.15g", item)
366
+ when NilClass
367
+ "null"
368
+ when TrueClass
369
+ "true"
370
+ when FalseClass
371
+ "false"
372
+ else
373
+ raise InvalidPolicyfileAttribute,
374
+ "Invalid type in attributes. Only Hash, Array, String, Integer, Float, true, false, and nil are accepted. You gave #{item.inspect} (#{item.class})"
375
+ end
376
+ end
377
+
378
+ def validate_attr_key(key)
379
+ unless key.kind_of?(String)
380
+ raise InvalidPolicyfileAttribute,
381
+ "Attribute keys must be Strings (other types are not allowed in JSON). You gave: #{key.inspect} (#{key.class})"
382
+ end
383
+ end
384
+
385
+ def set_name_from_lock_data(lock_data)
386
+ name_attribute = lock_data["name"]
387
+
388
+ raise InvalidLockfile, "lockfile does not have a `name' attribute" if name_attribute.nil?
389
+
390
+ unless name_attribute.kind_of?(String)
391
+ raise InvalidLockfile, "lockfile's name attribute must be a String (got: #{name_attribute.inspect})"
392
+ end
393
+
394
+ if name_attribute.empty?
395
+ raise InvalidLockfile, "lockfile's name attribute cannot be an empty string"
396
+ end
397
+
398
+ @name = name_attribute
399
+
400
+ end
401
+
402
+ def set_run_list_from_lock_data(lock_data)
403
+ run_list_attribute = lock_data["run_list"]
404
+
405
+ raise InvalidLockfile, "lockfile does not have a run_list attribute" if run_list_attribute.nil?
406
+
407
+ unless run_list_attribute.kind_of?(Array)
408
+ raise InvalidLockfile, "lockfile's run_list must be an array of run list items (got: #{run_list_attribute.inspect})"
409
+ end
410
+
411
+ bad_run_list_items = run_list_attribute.select { |e| e !~ RUN_LIST_ITEM_FORMAT }
412
+
413
+ unless bad_run_list_items.empty?
414
+ msg = "lockfile's run_list items must be formatted like `recipe[$COOKBOOK_NAME::$RECIPE_NAME]'. Invalid items: `#{bad_run_list_items.join("' `")}'"
415
+ raise InvalidLockfile, msg
416
+ end
417
+
418
+ @run_list = run_list_attribute
419
+ end
420
+
421
+ def set_named_run_lists_from_lock_data(lock_data)
422
+ return unless lock_data.key?("named_run_lists")
423
+
424
+ lock_data_named_run_lists = lock_data["named_run_lists"]
425
+
426
+ unless lock_data_named_run_lists.kind_of?(Hash)
427
+ msg = "lockfile's named_run_lists must be a Hash (JSON object). (got: #{lock_data_named_run_lists.inspect})"
428
+ raise InvalidLockfile, msg
429
+ end
430
+
431
+ lock_data_named_run_lists.each do |name, run_list|
432
+ unless name.kind_of?(String)
433
+ msg = "Keys in lockfile's named_run_lists must be Strings. (got: #{name.inspect})"
434
+ raise InvalidLockfile, msg
435
+ end
436
+ unless run_list.kind_of?(Array)
437
+ msg = "Values in lockfile's named_run_lists must be Arrays. (got: #{run_list.inspect})"
438
+ raise InvalidLockfile, msg
439
+ end
440
+ bad_run_list_items = run_list.select { |e| e !~ RUN_LIST_ITEM_FORMAT }
441
+ unless bad_run_list_items.empty?
442
+ msg = "lockfile's run_list items must be formatted like `recipe[$COOKBOOK_NAME::$RECIPE_NAME]'. Invalid items: `#{bad_run_list_items.join("' `")}'"
443
+ raise InvalidLockfile, msg
444
+ end
445
+ end
446
+ @named_run_lists = lock_data_named_run_lists
447
+ end
448
+
449
+ def set_cookbook_locks_from_lock_data(lock_data)
450
+ cookbook_lock_data = lock_data["cookbook_locks"]
451
+
452
+ if cookbook_lock_data.nil?
453
+ raise InvalidLockfile, "lockfile does not have a cookbook_locks attribute"
454
+ end
455
+
456
+ unless cookbook_lock_data.kind_of?(Hash)
457
+ raise InvalidLockfile, "lockfile's cookbook_locks attribute must be a Hash (JSON object). (got: #{cookbook_lock_data.inspect})"
458
+ end
459
+
460
+ lock_data["cookbook_locks"].each do |name, lock_info|
461
+ build_cookbook_lock_from_lock_data(name, lock_info)
462
+ end
463
+ end
464
+
465
+ def set_cookbook_locks_as_archives_from_lock_data(lock_data)
466
+ cookbook_lock_data = lock_data["cookbook_locks"]
467
+
468
+ if cookbook_lock_data.nil?
469
+ raise InvalidLockfile, "lockfile does not have a cookbook_locks attribute"
470
+ end
471
+
472
+ unless cookbook_lock_data.kind_of?(Hash)
473
+ raise InvalidLockfile, "lockfile's cookbook_locks attribute must be a Hash (JSON object). (got: #{cookbook_lock_data.inspect})"
474
+ end
475
+
476
+ lock_data["cookbook_locks"].each do |name, lock_info|
477
+ build_cookbook_lock_as_archive_from_lock_data(name, lock_info)
478
+ end
479
+ end
480
+
481
+ def set_attributes_from_lock_data(lock_data)
482
+ default_attr_data = lock_data["default_attributes"]
483
+
484
+ if default_attr_data.nil?
485
+ raise InvalidLockfile, "lockfile does not have a `default_attributes` attribute"
486
+ end
487
+
488
+ unless default_attr_data.kind_of?(Hash)
489
+ raise InvalidLockfile, "lockfile's `default_attributes` attribute must be a Hash (JSON object). (got: #{default_attr_data.inspect})"
490
+ end
491
+
492
+ override_attr_data = lock_data["override_attributes"]
493
+
494
+ if override_attr_data.nil?
495
+ raise InvalidLockfile, "lockfile does not have a `override_attributes` attribute"
496
+ end
497
+
498
+ unless override_attr_data.kind_of?(Hash)
499
+ raise InvalidLockfile, "lockfile's `override_attributes` attribute must be a Hash (JSON object). (got: #{override_attr_data.inspect})"
500
+ end
501
+
502
+ @default_attributes = default_attr_data
503
+ @override_attributes = override_attr_data
504
+ end
505
+
506
+ def set_solution_dependencies_from_lock_data(lock_data)
507
+ soln_deps = lock_data["solution_dependencies"]
508
+
509
+ if soln_deps.nil?
510
+ raise InvalidLockfile, "lockfile does not have a solution_dependencies attribute"
511
+ end
512
+
513
+ unless soln_deps.kind_of?(Hash)
514
+ raise InvalidLockfile, "lockfile's solution_dependencies attribute must be a Hash (JSON object). (got: #{soln_deps.inspect})"
515
+ end
516
+
517
+ s = Policyfile::SolutionDependencies.from_lock(lock_data["solution_dependencies"])
518
+ @solution_dependencies = s
519
+ end
520
+
521
+ def build_cookbook_lock_from_lock_data(name, lock_info)
522
+ unless lock_info.kind_of?(Hash)
523
+ raise InvalidLockfile, "lockfile cookbook_locks entries must be a Hash (JSON object). (got: #{lock_info.inspect})"
524
+ end
525
+
526
+ if lock_info["cache_key"].nil?
527
+ local_cookbook(name).build_from_lock_data(lock_info)
528
+ else
529
+ cached_cookbook(name).build_from_lock_data(lock_info)
530
+ end
531
+ end
532
+
533
+ def build_cookbook_lock_as_archive_from_lock_data(name, lock_info)
534
+ unless lock_info.kind_of?(Hash)
535
+ raise InvalidLockfile, "lockfile cookbook_locks entries must be a Hash (JSON object). (got: #{lock_info.inspect})"
536
+ end
537
+
538
+ if lock_info["cache_key"].nil?
539
+ local_cookbook = Policyfile::LocalCookbook.new(name, storage_config)
540
+ local_cookbook.build_from_lock_data(lock_info)
541
+ archived = Policyfile::ArchivedCookbook.new(local_cookbook, storage_config)
542
+ @cookbook_locks[name] = archived
543
+ else
544
+ cached_cookbook = Policyfile::CachedCookbook.new(name, storage_config)
545
+ cached_cookbook.build_from_lock_data(lock_info)
546
+ archived = Policyfile::ArchivedCookbook.new(cached_cookbook, storage_config)
547
+ @cookbook_locks[name] = archived
548
+ end
549
+ end
550
+
551
+ end
552
+ end