puppet 6.12.0-x64-mingw32 → 6.17.0-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (412) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +2 -7
  3. data/CONTRIBUTING.md +7 -13
  4. data/Gemfile +4 -2
  5. data/Gemfile.lock +39 -36
  6. data/README.md +18 -25
  7. data/ext/project_data.yaml +1 -1
  8. data/ext/windows/service/daemon.rb +3 -3
  9. data/lib/puppet.rb +52 -13
  10. data/lib/puppet/agent.rb +20 -14
  11. data/lib/puppet/application/agent.rb +26 -17
  12. data/lib/puppet/application/describe.rb +7 -5
  13. data/lib/puppet/application/device.rb +2 -2
  14. data/lib/puppet/application/filebucket.rb +19 -15
  15. data/lib/puppet/application/plugin.rb +1 -0
  16. data/lib/puppet/application/resource.rb +1 -1
  17. data/lib/puppet/application/ssl.rb +4 -4
  18. data/lib/puppet/configurer.rb +65 -69
  19. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  20. data/lib/puppet/confine.rb +1 -1
  21. data/lib/puppet/context/trusted_information.rb +14 -8
  22. data/lib/puppet/daemon.rb +13 -27
  23. data/lib/puppet/defaults.rb +154 -58
  24. data/lib/puppet/environments.rb +27 -20
  25. data/lib/puppet/face/facts.rb +8 -5
  26. data/lib/puppet/face/help.rb +29 -3
  27. data/lib/puppet/face/module/search.rb +5 -0
  28. data/lib/puppet/face/plugin.rb +2 -2
  29. data/lib/puppet/file_serving/http_metadata.rb +14 -2
  30. data/lib/puppet/file_serving/metadata.rb +4 -1
  31. data/lib/puppet/file_serving/terminus_selector.rb +7 -8
  32. data/lib/puppet/file_system/file_impl.rb +14 -10
  33. data/lib/puppet/file_system/memory_file.rb +6 -0
  34. data/lib/puppet/file_system/memory_impl.rb +13 -0
  35. data/lib/puppet/file_system/uniquefile.rb +12 -16
  36. data/lib/puppet/file_system/windows.rb +7 -10
  37. data/lib/puppet/forge.rb +1 -1
  38. data/lib/puppet/forge/cache.rb +1 -1
  39. data/lib/puppet/forge/repository.rb +4 -7
  40. data/lib/puppet/functions/call.rb +1 -1
  41. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  42. data/lib/puppet/functions/filter.rb +1 -0
  43. data/lib/puppet/functions/reduce.rb +2 -4
  44. data/lib/puppet/http.rb +5 -0
  45. data/lib/puppet/http/client.rb +293 -73
  46. data/lib/puppet/http/errors.rb +2 -0
  47. data/lib/puppet/http/external_client.rb +90 -0
  48. data/lib/puppet/http/redirector.rb +43 -7
  49. data/lib/puppet/http/resolver.rb +46 -3
  50. data/lib/puppet/http/resolver/server_list.rb +76 -16
  51. data/lib/puppet/http/resolver/settings.rb +23 -3
  52. data/lib/puppet/http/resolver/srv.rb +29 -3
  53. data/lib/puppet/http/response.rb +87 -1
  54. data/lib/puppet/http/retry_after_handler.rb +39 -0
  55. data/lib/puppet/http/service.rb +151 -7
  56. data/lib/puppet/http/service/ca.rb +76 -14
  57. data/lib/puppet/http/service/compiler.rb +319 -0
  58. data/lib/puppet/http/service/file_server.rb +206 -0
  59. data/lib/puppet/http/service/report.rb +49 -23
  60. data/lib/puppet/http/session.rb +103 -7
  61. data/lib/puppet/indirector.rb +1 -1
  62. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  63. data/lib/puppet/indirector/catalog/rest.rb +34 -0
  64. data/lib/puppet/indirector/facts/rest.rb +42 -0
  65. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  66. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  67. data/lib/puppet/indirector/file_content/http.rb +5 -0
  68. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  69. data/lib/puppet/indirector/file_metadata/http.rb +27 -8
  70. data/lib/puppet/indirector/file_metadata/rest.rb +52 -0
  71. data/lib/puppet/indirector/json.rb +1 -1
  72. data/lib/puppet/indirector/msgpack.rb +1 -1
  73. data/lib/puppet/indirector/node/rest.rb +24 -0
  74. data/lib/puppet/indirector/report/rest.rb +19 -0
  75. data/lib/puppet/indirector/report/yaml.rb +23 -0
  76. data/lib/puppet/indirector/request.rb +1 -1
  77. data/lib/puppet/indirector/rest.rb +12 -0
  78. data/lib/puppet/indirector/status/rest.rb +18 -0
  79. data/lib/puppet/loaders.rb +6 -0
  80. data/lib/puppet/metatype/manager.rb +80 -80
  81. data/lib/puppet/network/http/api/indirected_routes.rb +1 -1
  82. data/lib/puppet/network/http/api/master/v3/environment.rb +3 -0
  83. data/lib/puppet/network/http/base_pool.rb +7 -2
  84. data/lib/puppet/network/http/compression.rb +7 -0
  85. data/lib/puppet/network/http/connection.rb +6 -0
  86. data/lib/puppet/network/http/connection_adapter.rb +184 -0
  87. data/lib/puppet/network/http/nocache_pool.rb +2 -0
  88. data/lib/puppet/network/http/pool.rb +13 -6
  89. data/lib/puppet/network/http_pool.rb +2 -1
  90. data/lib/puppet/node/environment.rb +11 -1
  91. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  92. data/lib/puppet/pal/pal_impl.rb +4 -29
  93. data/lib/puppet/parser/ast/leaf.rb +5 -5
  94. data/lib/puppet/parser/ast/pops_bridge.rb +6 -15
  95. data/lib/puppet/parser/compiler.rb +43 -33
  96. data/lib/puppet/parser/compiler/catalog_validator/env_relationship_validator.rb +2 -0
  97. data/lib/puppet/parser/compiler/catalog_validator/site_validator.rb +2 -0
  98. data/lib/puppet/parser/environment_compiler.rb +4 -1
  99. data/lib/puppet/parser/functions.rb +18 -13
  100. data/lib/puppet/parser/functions/filter.rb +1 -0
  101. data/lib/puppet/parser/resource.rb +3 -2
  102. data/lib/puppet/parser/resource/param.rb +6 -0
  103. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  104. data/lib/puppet/pops/evaluator/evaluator_impl.rb +6 -6
  105. data/lib/puppet/pops/issues.rb +5 -0
  106. data/lib/puppet/pops/loader/puppet_plan_instantiator.rb +12 -3
  107. data/lib/puppet/pops/loaders.rb +7 -5
  108. data/lib/puppet/pops/parser/evaluating_parser.rb +5 -7
  109. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -0
  110. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  111. data/lib/puppet/pops/types/type_calculator.rb +24 -0
  112. data/lib/puppet/pops/validation/checker4_0.rb +11 -1
  113. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  114. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  115. data/lib/puppet/provider/aix_object.rb +4 -2
  116. data/lib/puppet/provider/group/aix.rb +1 -0
  117. data/lib/puppet/provider/group/groupadd.rb +57 -24
  118. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  119. data/lib/puppet/provider/package/aix.rb +17 -2
  120. data/lib/puppet/provider/package/apt.rb +78 -4
  121. data/lib/puppet/provider/package/aptitude.rb +1 -1
  122. data/lib/puppet/provider/package/dnfmodule.rb +69 -15
  123. data/lib/puppet/provider/package/dpkg.rb +14 -7
  124. data/lib/puppet/provider/package/fink.rb +20 -3
  125. data/lib/puppet/provider/package/gem.rb +41 -7
  126. data/lib/puppet/provider/package/openbsd.rb +13 -1
  127. data/lib/puppet/provider/package/pacman.rb +2 -5
  128. data/lib/puppet/provider/package/pip.rb +143 -48
  129. data/lib/puppet/provider/package/pip3.rb +0 -2
  130. data/lib/puppet/provider/package/pkg.rb +18 -5
  131. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  132. data/lib/puppet/provider/package/pkgng.rb +16 -4
  133. data/lib/puppet/provider/package/portage.rb +2 -2
  134. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  135. data/lib/puppet/provider/package/rpm.rb +6 -213
  136. data/lib/puppet/provider/package/yum.rb +109 -25
  137. data/lib/puppet/provider/package/zypper.rb +59 -1
  138. data/lib/puppet/provider/service/systemd.rb +22 -4
  139. data/lib/puppet/provider/service/windows.rb +23 -7
  140. data/lib/puppet/provider/user/aix.rb +1 -0
  141. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  142. data/lib/puppet/provider/user/useradd.rb +22 -12
  143. data/lib/puppet/reports/http.rb +15 -9
  144. data/lib/puppet/reports/store.rb +1 -1
  145. data/lib/puppet/resource.rb +2 -1
  146. data/lib/puppet/resource/type.rb +8 -0
  147. data/lib/puppet/resource/type_collection.rb +20 -16
  148. data/lib/puppet/runtime.rb +31 -1
  149. data/lib/puppet/settings.rb +4 -0
  150. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  151. data/lib/puppet/ssl.rb +1 -0
  152. data/lib/puppet/ssl/certificate.rb +2 -1
  153. data/lib/puppet/ssl/host.rb +4 -4
  154. data/lib/puppet/ssl/oids.rb +1 -0
  155. data/lib/puppet/ssl/ssl_context.rb +2 -2
  156. data/lib/puppet/ssl/ssl_provider.rb +20 -1
  157. data/lib/puppet/ssl/state_machine.rb +81 -35
  158. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  159. data/lib/puppet/test/test_helper.rb +15 -11
  160. data/lib/puppet/transaction/report.rb +2 -2
  161. data/lib/puppet/transaction/resource_harness.rb +1 -1
  162. data/lib/puppet/trusted_external.rb +29 -1
  163. data/lib/puppet/type.rb +18 -6
  164. data/lib/puppet/type/file.rb +51 -13
  165. data/lib/puppet/type/file/checksum.rb +4 -4
  166. data/lib/puppet/type/file/source.rb +51 -60
  167. data/lib/puppet/type/group.rb +2 -2
  168. data/lib/puppet/type/package.rb +102 -10
  169. data/lib/puppet/type/service.rb +55 -8
  170. data/lib/puppet/type/user.rb +3 -28
  171. data/lib/puppet/util.rb +39 -15
  172. data/lib/puppet/util/at_fork.rb +1 -1
  173. data/lib/puppet/util/autoload.rb +4 -18
  174. data/lib/puppet/util/checksums.rb +19 -4
  175. data/lib/puppet/util/fileparsing.rb +2 -2
  176. data/lib/puppet/util/instance_loader.rb +14 -10
  177. data/lib/puppet/util/log/destinations.rb +2 -11
  178. data/lib/puppet/util/package/version/debian.rb +175 -0
  179. data/lib/puppet/util/package/version/gem.rb +15 -0
  180. data/lib/puppet/util/package/version/pip.rb +167 -0
  181. data/lib/puppet/util/package/version/range.rb +53 -0
  182. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  183. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  184. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  185. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  186. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  187. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  188. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  189. data/lib/puppet/util/package/version/rpm.rb +73 -0
  190. data/lib/puppet/util/pidlock.rb +36 -10
  191. data/lib/puppet/util/platform.rb +5 -0
  192. data/lib/puppet/util/plist.rb +6 -0
  193. data/lib/puppet/util/provider_features.rb +1 -1
  194. data/lib/puppet/util/reference.rb +1 -1
  195. data/lib/puppet/util/rpm_compare.rb +193 -0
  196. data/lib/puppet/util/storage.rb +0 -1
  197. data/lib/puppet/util/windows/adsi.rb +2 -2
  198. data/lib/puppet/util/windows/api_types.rb +45 -32
  199. data/lib/puppet/util/windows/eventlog.rb +1 -6
  200. data/lib/puppet/util/windows/principal.rb +8 -6
  201. data/lib/puppet/util/windows/process.rb +15 -14
  202. data/lib/puppet/util/windows/registry.rb +11 -11
  203. data/lib/puppet/util/windows/security.rb +1 -0
  204. data/lib/puppet/util/windows/service.rb +43 -26
  205. data/lib/puppet/util/windows/sid.rb +3 -3
  206. data/lib/puppet/util/windows/user.rb +23 -8
  207. data/lib/puppet/util/yaml.rb +1 -1
  208. data/lib/puppet/version.rb +1 -1
  209. data/locales/puppet.pot +707 -574
  210. data/man/man5/puppet.conf.5 +74 -14
  211. data/man/man8/puppet-agent.8 +7 -7
  212. data/man/man8/puppet-apply.8 +1 -1
  213. data/man/man8/puppet-catalog.8 +1 -1
  214. data/man/man8/puppet-config.8 +1 -1
  215. data/man/man8/puppet-describe.8 +1 -1
  216. data/man/man8/puppet-device.8 +2 -2
  217. data/man/man8/puppet-doc.8 +1 -1
  218. data/man/man8/puppet-epp.8 +1 -1
  219. data/man/man8/puppet-facts.8 +1 -1
  220. data/man/man8/puppet-filebucket.8 +17 -2
  221. data/man/man8/puppet-generate.8 +1 -1
  222. data/man/man8/puppet-help.8 +6 -3
  223. data/man/man8/puppet-key.8 +1 -1
  224. data/man/man8/puppet-lookup.8 +1 -1
  225. data/man/man8/puppet-man.8 +1 -1
  226. data/man/man8/puppet-module.8 +4 -1
  227. data/man/man8/puppet-node.8 +1 -1
  228. data/man/man8/puppet-parser.8 +1 -1
  229. data/man/man8/puppet-plugin.8 +1 -1
  230. data/man/man8/puppet-report.8 +1 -1
  231. data/man/man8/puppet-resource.8 +1 -1
  232. data/man/man8/puppet-script.8 +1 -1
  233. data/man/man8/puppet-ssl.8 +2 -2
  234. data/man/man8/puppet-status.8 +1 -1
  235. data/man/man8/puppet.8 +2 -2
  236. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  237. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  238. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  239. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  240. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list.txt} +8 -0
  241. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  242. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  243. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  244. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  245. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_fetch_if_not_on_the_local_disk.yml +1 -102
  246. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_not_update_if_content_on_disk_is_up-to-date.yml +1 -106
  247. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -106
  248. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_mtime_is_older_on_disk.yml +1 -102
  249. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -98
  250. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_not_on_the_local_disk.yml +1 -102
  251. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_not_update_if_mtime_is_newer_on_disk.yml +1 -102
  252. data/spec/integration/application/agent_spec.rb +483 -0
  253. data/spec/integration/application/apply_spec.rb +132 -3
  254. data/spec/integration/application/filebucket_spec.rb +190 -0
  255. data/spec/integration/application/plugin_spec.rb +73 -0
  256. data/spec/integration/configurer_spec.rb +26 -7
  257. data/spec/integration/defaults_spec.rb +1 -2
  258. data/spec/integration/http/client_spec.rb +47 -37
  259. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  260. data/spec/integration/indirector/report/yaml.rb +83 -0
  261. data/spec/integration/module_tool/forge_spec.rb +2 -15
  262. data/spec/integration/network/http_pool_spec.rb +93 -20
  263. data/spec/integration/node/environment_spec.rb +15 -0
  264. data/spec/integration/parser/compiler_spec.rb +11 -0
  265. data/spec/integration/type/file_spec.rb +1 -1
  266. data/spec/integration/util/windows/adsi_spec.rb +6 -1
  267. data/spec/integration/util/windows/registry_spec.rb +7 -7
  268. data/spec/integration/util/windows/user_spec.rb +40 -5
  269. data/spec/lib/puppet/test_ca.rb +2 -2
  270. data/spec/lib/puppet_spec/https.rb +16 -7
  271. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  272. data/spec/shared_contexts/https.rb +29 -0
  273. data/spec/unit/agent_spec.rb +80 -26
  274. data/spec/unit/application/agent_spec.rb +9 -5
  275. data/spec/unit/application/apply_spec.rb +2 -12
  276. data/spec/unit/application/describe_spec.rb +88 -50
  277. data/spec/unit/application/device_spec.rb +2 -2
  278. data/spec/unit/application/filebucket_spec.rb +22 -2
  279. data/spec/unit/application/resource_spec.rb +2 -2
  280. data/spec/unit/configurer/fact_handler_spec.rb +4 -8
  281. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  282. data/spec/unit/configurer_spec.rb +17 -18
  283. data/spec/unit/context/trusted_information_spec.rb +25 -2
  284. data/spec/unit/daemon_spec.rb +5 -64
  285. data/spec/unit/defaults_spec.rb +25 -2
  286. data/spec/unit/environments_spec.rb +65 -28
  287. data/spec/unit/face/facts_spec.rb +24 -20
  288. data/spec/unit/face/module/search_spec.rb +17 -0
  289. data/spec/unit/face/plugin_spec.rb +12 -10
  290. data/spec/unit/file_serving/http_metadata_spec.rb +37 -14
  291. data/spec/unit/file_serving/terminus_selector_spec.rb +45 -26
  292. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  293. data/spec/unit/file_system_spec.rb +26 -2
  294. data/spec/unit/functions/lookup_spec.rb +13 -0
  295. data/spec/unit/http/client_spec.rb +327 -35
  296. data/spec/unit/http/external_client_spec.rb +201 -0
  297. data/spec/unit/http/resolver_spec.rb +34 -2
  298. data/spec/unit/http/response_spec.rb +75 -0
  299. data/spec/unit/http/service/ca_spec.rb +53 -11
  300. data/spec/unit/http/service/compiler_spec.rb +627 -0
  301. data/spec/unit/http/service/file_server_spec.rb +308 -0
  302. data/spec/unit/http/service/report_spec.rb +27 -9
  303. data/spec/unit/http/service_spec.rb +98 -5
  304. data/spec/unit/http/session_spec.rb +190 -7
  305. data/spec/unit/indirector/catalog/compiler_spec.rb +47 -29
  306. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  307. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  308. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  309. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  310. data/spec/unit/indirector/file_metadata/http_spec.rb +194 -0
  311. data/spec/unit/indirector/file_metadata/rest_spec.rb +110 -2
  312. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  313. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  314. data/spec/unit/indirector/request_spec.rb +1 -1
  315. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  316. data/spec/unit/indirector/rest_spec.rb +13 -0
  317. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  318. data/spec/unit/interface_spec.rb +3 -3
  319. data/spec/unit/network/http/api/indirected_routes_spec.rb +2 -1
  320. data/spec/unit/network/http/connection_spec.rb +559 -175
  321. data/spec/unit/network/http/nocache_pool_spec.rb +25 -3
  322. data/spec/unit/network/http/pool_spec.rb +89 -11
  323. data/spec/unit/network/http_pool_spec.rb +63 -57
  324. data/spec/unit/network/http_spec.rb +1 -1
  325. data/spec/unit/node/environment_spec.rb +16 -0
  326. data/spec/unit/node/facts_spec.rb +2 -1
  327. data/spec/unit/node_spec.rb +7 -4
  328. data/spec/unit/parser/ast/block_expression_spec.rb +1 -1
  329. data/spec/unit/parser/environment_compiler_spec.rb +7 -0
  330. data/spec/unit/parser/scope_spec.rb +1 -1
  331. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +15 -1
  332. data/spec/unit/pops/loaders/loaders_spec.rb +1 -1
  333. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  334. data/spec/unit/pops/types/type_calculator_spec.rb +1 -11
  335. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  336. data/spec/unit/provider/aix_object_spec.rb +16 -2
  337. data/spec/unit/provider/group/groupadd_spec.rb +181 -56
  338. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  339. data/spec/unit/provider/package/aix_spec.rb +29 -0
  340. data/spec/unit/provider/package/apt_spec.rb +43 -2
  341. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  342. data/spec/unit/provider/package/dnfmodule_spec.rb +76 -15
  343. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  344. data/spec/unit/provider/package/gem_spec.rb +40 -0
  345. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  346. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  347. data/spec/unit/provider/package/pip_spec.rb +68 -19
  348. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  349. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  350. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  351. data/spec/unit/provider/package/portage_spec.rb +5 -0
  352. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  353. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  354. data/spec/unit/provider/package/yum_spec.rb +292 -0
  355. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  356. data/spec/unit/provider/service/init_spec.rb +1 -0
  357. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  358. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  359. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  360. data/spec/unit/provider/service/systemd_spec.rb +92 -12
  361. data/spec/unit/provider/service/windows_spec.rb +22 -14
  362. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  363. data/spec/unit/provider/user/openbsd_spec.rb +1 -0
  364. data/spec/unit/provider/user/useradd_spec.rb +43 -24
  365. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  366. data/spec/unit/puppet_pal_2pec.rb +0 -26
  367. data/spec/unit/puppet_pal_catalog_spec.rb +46 -0
  368. data/spec/unit/puppet_spec.rb +47 -0
  369. data/spec/unit/reports/http_spec.rb +70 -52
  370. data/spec/unit/resource_spec.rb +3 -3
  371. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  372. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  373. data/spec/unit/ssl/certificate_spec.rb +7 -0
  374. data/spec/unit/ssl/host_spec.rb +4 -2
  375. data/spec/unit/ssl/oids_spec.rb +1 -0
  376. data/spec/unit/ssl/ssl_provider_spec.rb +69 -43
  377. data/spec/unit/ssl/state_machine_spec.rb +99 -13
  378. data/spec/unit/test/test_helper_spec.rb +17 -0
  379. data/spec/unit/transaction/persistence_spec.rb +1 -10
  380. data/spec/unit/transaction/report_spec.rb +5 -1
  381. data/spec/unit/transaction_spec.rb +0 -2
  382. data/spec/unit/type/file/ensure_spec.rb +1 -2
  383. data/spec/unit/type/file/source_spec.rb +89 -38
  384. data/spec/unit/type/file_spec.rb +122 -96
  385. data/spec/unit/type/package_spec.rb +8 -0
  386. data/spec/unit/type/service_spec.rb +185 -8
  387. data/spec/unit/type/user_spec.rb +1 -2
  388. data/spec/unit/type_spec.rb +50 -0
  389. data/spec/unit/util/at_fork_spec.rb +3 -2
  390. data/spec/unit/util/autoload_spec.rb +2 -1
  391. data/spec/unit/util/checksums_spec.rb +16 -0
  392. data/spec/unit/util/log/destinations_spec.rb +1 -29
  393. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  394. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  395. data/spec/unit/util/package/version/range_spec.rb +175 -0
  396. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  397. data/spec/unit/util/pidlock_spec.rb +112 -42
  398. data/spec/unit/util/plist_spec.rb +20 -0
  399. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  400. data/spec/unit/util/storage_spec.rb +1 -8
  401. data/spec/unit/util/windows/adsi_spec.rb +4 -4
  402. data/spec/unit/util/windows/api_types_spec.rb +104 -40
  403. data/spec/unit/util/windows/service_spec.rb +4 -4
  404. data/spec/unit/util/windows/sid_spec.rb +2 -2
  405. data/spec/unit/util_spec.rb +3 -3
  406. data/spec/unit/x509/cert_provider_spec.rb +1 -1
  407. data/tasks/generate_cert_fixtures.rake +15 -1
  408. data/tasks/manpages.rake +5 -35
  409. metadata +73 -12
  410. data/COMMITTERS.md +0 -244
  411. data/spec/integration/faces/plugin_spec.rb +0 -61
  412. data/spec/integration/test/test_helper_spec.rb +0 -31
@@ -20,9 +20,9 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
20
20
  end
21
21
  end
22
22
 
23
- confine :operatingsystem => :gentoo
23
+ confine :osfamily => :gentoo
24
24
 
25
- defaultfor :operatingsystem => :gentoo
25
+ defaultfor :osfamily => :gentoo
26
26
 
27
27
  def self.instances
28
28
  result_format = self.eix_result_format
@@ -1,5 +1,3 @@
1
- require 'puppet/provider/package/gem'
2
-
3
1
  Puppet::Type.type(:package).provide :puppet_gem, :parent => :gem do
4
2
  desc "Puppet Ruby Gem support. This provider is useful for managing
5
3
  gems needed by the ruby provided in the puppet-agent package."
@@ -14,4 +12,10 @@ Puppet::Type.type(:package).provide :puppet_gem, :parent => :gem do
14
12
  else
15
13
  commands :gemcmd => "/opt/puppetlabs/puppet/bin/gem"
16
14
  end
15
+
16
+ def uninstall
17
+ super
18
+ Puppet.debug("Invalidating rubygems cache after uninstalling gem '#{resource[:name]}'")
19
+ Puppet::Util::Autoload.gem_source.clear_paths
20
+ end
17
21
  end
@@ -1,13 +1,17 @@
1
1
  require 'puppet/provider/package'
2
+ require 'puppet/util/rpm_compare'
2
3
 
3
4
  # RPM packaging. Should work anywhere that has rpm installed.
4
5
  Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do
6
+ # provides Rpm parsing and comparison
7
+ include Puppet::Util::RpmCompare
8
+
5
9
  desc "RPM packaging support; should work anywhere with a working `rpm`
6
10
  binary.
7
11
 
8
12
  This provider supports the `install_options` and `uninstall_options`
9
13
  attributes, which allow command-line flags to be passed to rpm.
10
- These options should be specified as an array where each element is either a string or a hash."
14
+ These options should be specified as an array where each element is either a string or a hash."
11
15
 
12
16
  has_feature :versionable
13
17
  has_feature :install_options
@@ -23,31 +27,6 @@ These options should be specified as an array where each element is either a str
23
27
  self::NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch]
24
28
  self::MULTIVERSION_SEPARATOR = "; "
25
29
 
26
- ARCH_LIST = [
27
- 'noarch',
28
- 'i386',
29
- 'i686',
30
- 'ppc',
31
- 'ppc64',
32
- 'armv3l',
33
- 'armv4b',
34
- 'armv4l',
35
- 'armv4tl',
36
- 'armv5tel',
37
- 'armv5tejl',
38
- 'armv6l',
39
- 'armv7l',
40
- 'm68kmint',
41
- 's390',
42
- 's390x',
43
- 'ia64',
44
- 'x86_64',
45
- 'sh3',
46
- 'sh4',
47
- ]
48
-
49
- ARCH_REGEX = Regexp.new(ARCH_LIST.join('|\.'))
50
-
51
30
  commands :rpm => "rpm"
52
31
 
53
32
  if command('rpm')
@@ -204,200 +183,14 @@ These options should be specified as an array where each element is either a str
204
183
  join_options(resource[:uninstall_options])
205
184
  end
206
185
 
207
- # This is an attempt at implementing RPM's
208
- # lib/rpmvercmp.c rpmvercmp(a, b) in Ruby.
209
- #
210
- # Some of the things in here look REALLY
211
- # UGLY and/or arbitrary. Our goal is to
212
- # match how RPM compares versions, quirks
213
- # and all.
214
- #
215
- # I've kept a lot of C-like string processing
216
- # in an effort to keep this as identical to RPM
217
- # as possible.
218
- #
219
- # returns 1 if str1 is newer than str2,
220
- # 0 if they are identical
221
- # -1 if str1 is older than str2
222
- def rpmvercmp(str1, str2)
223
- return 0 if str1 == str2
224
-
225
- front_strip_re = /^[^A-Za-z0-9~]+/
226
-
227
- while str1.length > 0 or str2.length > 0
228
- # trim anything that's in front_strip_re and != '~' off the beginning of each string
229
- str1 = str1.gsub(front_strip_re, '')
230
- str2 = str2.gsub(front_strip_re, '')
231
-
232
- # "handle the tilde separator, it sorts before everything else"
233
- if str1 =~ /^~/ && str2 =~ /^~/
234
- # if they both have ~, strip it
235
- str1 = str1[1..-1]
236
- str2 = str2[1..-1]
237
- next
238
- elsif str1 =~ /^~/
239
- return -1
240
- elsif str2 =~ /^~/
241
- return 1
242
- end
243
-
244
- break if str1.length == 0 or str2.length == 0
245
-
246
- # "grab first completely alpha or completely numeric segment"
247
- isnum = false
248
- # if the first char of str1 is a digit, grab the chunk of continuous digits from each string
249
- if str1 =~ /^[0-9]+/
250
- if str1 =~ /^[0-9]+/
251
- segment1 = $~.to_s
252
- str1 = $~.post_match
253
- else
254
- segment1 = ''
255
- end
256
- if str2 =~ /^[0-9]+/
257
- segment2 = $~.to_s
258
- str2 = $~.post_match
259
- else
260
- segment2 = ''
261
- end
262
- isnum = true
263
- # else grab the chunk of continuous alphas from each string (which may be '')
264
- else
265
- if str1 =~ /^[A-Za-z]+/
266
- segment1 = $~.to_s
267
- str1 = $~.post_match
268
- else
269
- segment1 = ''
270
- end
271
- if str2 =~ /^[A-Za-z]+/
272
- segment2 = $~.to_s
273
- str2 = $~.post_match
274
- else
275
- segment2 = ''
276
- end
277
- end
278
-
279
- # if the segments we just grabbed from the strings are different types (i.e. one numeric one alpha),
280
- # where alpha also includes ''; "numeric segments are always newer than alpha segments"
281
- if segment2.length == 0
282
- return 1 if isnum
283
- return -1
284
- end
285
-
286
- if isnum
287
- # "throw away any leading zeros - it's a number, right?"
288
- segment1 = segment1.gsub(/^0+/, '')
289
- segment2 = segment2.gsub(/^0+/, '')
290
- # "whichever number has more digits wins"
291
- return 1 if segment1.length > segment2.length
292
- return -1 if segment1.length < segment2.length
293
- end
294
-
295
- # "strcmp will return which one is greater - even if the two segments are alpha
296
- # or if they are numeric. don't return if they are equal because there might
297
- # be more segments to compare"
298
- rc = segment1 <=> segment2
299
- return rc if rc != 0
300
- end #end while loop
301
-
302
- # if we haven't returned anything yet, "whichever version still has characters left over wins"
303
- if str1.length > str2.length
304
- return 1
305
- elsif str1.length < str2.length
306
- return -1
307
- else
308
- return 0
309
- end
310
- end
311
-
312
186
  def insync?(is)
313
187
  return false if [:purged, :absent].include?(is)
314
188
  return false if is.include?(self.class::MULTIVERSION_SEPARATOR) && !@resource[:install_only]
315
189
 
316
190
  should = resource[:ensure]
317
191
  is.split(self.class::MULTIVERSION_SEPARATOR).any? do |version|
318
- 0 == self.rpm_compareEVR(rpm_parse_evr(should), rpm_parse_evr(version))
319
- end
320
- end
321
-
322
- # parse a rpm "version" specification
323
- # this re-implements rpm's
324
- # rpmUtils.miscutils.stringToVersion() in ruby
325
- def rpm_parse_evr(s)
326
- ei = s.index(':')
327
- if ei
328
- e = s[0,ei]
329
- s = s[ei+1,s.length]
330
- else
331
- e = nil
332
- end
333
- begin
334
- e = String(Integer(e))
335
- rescue
336
- # If there are non-digits in the epoch field, default to nil
337
- e = nil
338
- end
339
- ri = s.index('-')
340
- if ri
341
- v = s[0,ri]
342
- r = s[ri+1,s.length]
343
- arch = r.scan(ARCH_REGEX)[0]
344
- if arch
345
- a = arch.delete('.')
346
- r.gsub!(ARCH_REGEX, '')
347
- end
348
- else
349
- v = s
350
- r = nil
351
- end
352
- return { :epoch => e, :version => v, :release => r, :arch => a }
353
- end
354
-
355
- # how rpm compares two package versions:
356
- # rpmUtils.miscutils.compareEVR(), which massages data types and then calls
357
- # rpm.labelCompare(), found in rpm.git/python/header-py.c, which
358
- # sets epoch to 0 if null, then compares epoch, then ver, then rel
359
- # using compare_values() and returns the first non-0 result, else 0.
360
- # This function combines the logic of compareEVR() and labelCompare().
361
- #
362
- # "version_should" can be v, v-r, or e:v-r.
363
- # "version_is" will always be at least v-r, can be e:v-r
364
- def rpm_compareEVR(should_hash, is_hash)
365
- # pass on to rpm labelCompare
366
-
367
- if !should_hash[:epoch].nil?
368
- rc = compare_values(should_hash[:epoch], is_hash[:epoch])
369
- return rc unless rc == 0
370
- end
371
-
372
- rc = compare_values(should_hash[:version], is_hash[:version])
373
- return rc unless rc == 0
374
-
375
- # here is our special case, PUP-1244.
376
- # if should_hash[:release] is nil (not specified by the user),
377
- # and comparisons up to here are equal, return equal. We need to
378
- # evaluate to whatever level of detail the user specified, so we
379
- # don't end up upgrading or *downgrading* when not intended.
380
- #
381
- # This should NOT be triggered if we're trying to ensure latest.
382
- return 0 if should_hash[:release].nil?
383
-
384
- rc = compare_values(should_hash[:release], is_hash[:release])
385
-
386
- return rc
387
- end
388
-
389
- # this method is a native implementation of the
390
- # compare_values function in rpm's python bindings,
391
- # found in python/header-py.c, as used by rpm.
392
- def compare_values(s1, s2)
393
- if s1.nil? && s2.nil?
394
- return 0
395
- elsif ( not s1.nil? ) && s2.nil?
396
- return 1
397
- elsif s1.nil? && (not s2.nil?)
398
- return -1
192
+ 0 == rpm_compareEVR(should, version)
399
193
  end
400
- return rpmvercmp(s1, s2)
401
194
  end
402
195
 
403
196
  private
@@ -1,4 +1,11 @@
1
+ require 'puppet/util/package/version/range'
2
+ require 'puppet/util/package/version/rpm'
3
+ require 'puppet/util/rpm_compare'
4
+
1
5
  Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
6
+ # provides Rpm parsing and comparison
7
+ include Puppet::Util::RpmCompare
8
+
2
9
  desc "Support via `yum`.
3
10
 
4
11
  Using this provider's `uninstallable` feature will not remove dependent packages. To
@@ -10,6 +17,9 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
10
17
 
11
18
  has_feature :install_options, :versionable, :virtual_packages, :install_only
12
19
 
20
+ RPM_VERSION = Puppet::Util::Package::Version::Rpm
21
+ RPM_VERSION_RANGE = Puppet::Util::Package::Version::Range
22
+
13
23
  commands :cmd => "yum", :rpm => "rpm"
14
24
 
15
25
  if command('rpm')
@@ -25,6 +35,36 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
25
35
  defaultfor :operatingsystem => :amazon
26
36
  defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
27
37
 
38
+ def insync?(is)
39
+ return false if [:purged, :absent].include?(is)
40
+ return false if is.include?(self.class::MULTIVERSION_SEPARATOR) && !@resource[:install_only]
41
+
42
+ should = @resource[:ensure]
43
+ if should.is_a?(String)
44
+ begin
45
+ should_version = RPM_VERSION_RANGE.parse(should, RPM_VERSION)
46
+
47
+ if should_version.is_a?(RPM_VERSION_RANGE::Eq)
48
+ return super
49
+ end
50
+ rescue RPM_VERSION_RANGE::ValidationFailure, RPM_VERSION::ValidationFailure
51
+ Puppet.debug("Cannot parse #{should} as a RPM version range")
52
+ return super
53
+ end
54
+
55
+ is.split(self.class::MULTIVERSION_SEPARATOR).any? do |version|
56
+ begin
57
+ is_version = RPM_VERSION.parse(version)
58
+ should_version.include?(is_version)
59
+ rescue RPM_VERSION::ValidationFailure
60
+ Puppet.debug("Cannot parse #{is} as a RPM version")
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ VERSION_REGEX = /^(?:(\d+):)?(\S+)-(\S+)$/
67
+
28
68
  def self.prefetch(packages)
29
69
  raise Puppet::Error, _("The yum provider can only be used as root") if Process.euid != 0
30
70
  super
@@ -86,23 +126,24 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
86
126
  end
87
127
 
88
128
  def self.parse_updates(str)
89
- # Strip off all content before the first blank line
90
- body = str.partition(/^\s*\n/m).last
129
+ # Strip off all content that contains Obsoleting, Security: or Update
130
+ body = str.partition(/^(Obsoleting|Security:|Update)/).first
91
131
 
92
132
  updates = Hash.new { |h, k| h[k] = [] }
93
- body.split.each_slice(3) do |tuple|
94
- break if tuple[0] =~ /^(Obsoleting|Security:|Update)/
95
- break unless tuple[1] =~ /^(?:(\d+):)?(\S+)-(\S+)$/
96
- hash = update_to_hash(*tuple[0..1])
97
- # Create entries for both the package name without a version and a
98
- # version since yum considers those as mostly interchangeable.
99
- short_name = hash[:name]
100
- long_name = "#{hash[:name]}.#{hash[:arch]}"
101
-
102
- updates[short_name] << hash
103
- updates[long_name] << hash
104
- end
105
133
 
134
+ body.split(/^\s*\n/).each do |line|
135
+ line.split.each_slice(3) do |tuple|
136
+ next unless tuple[0].include?('.') && tuple[1] =~ VERSION_REGEX
137
+
138
+ hash = update_to_hash(*tuple[0..1])
139
+ # Create entries for both the package name without a version and a
140
+ # version since yum considers those as mostly interchangeable.
141
+ short_name = hash[:name]
142
+ long_name = "#{hash[:name]}.#{hash[:arch]}"
143
+ updates[short_name] << hash
144
+ updates[long_name] << hash
145
+ end
146
+ end
106
147
  updates
107
148
  end
108
149
 
@@ -117,7 +158,7 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
117
158
  raise _("Failed to parse package name and architecture from '%{pkgname}'") % { pkgname: pkgname }
118
159
  end
119
160
 
120
- match = pkgversion.match(/^(?:(\d+):)?(\S+)-(\S+)$/)
161
+ match = pkgversion.match(VERSION_REGEX)
121
162
  epoch = match[1] || '0'
122
163
  version = match[2]
123
164
  release = match[3]
@@ -151,6 +192,44 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
151
192
  'update'
152
193
  end
153
194
 
195
+ def best_version(should)
196
+ if should.is_a?(String)
197
+ begin
198
+ should_range = RPM_VERSION_RANGE.parse(should, RPM_VERSION)
199
+ if should_range.is_a?(RPM_VERSION_RANGE::Eq)
200
+ return should
201
+ end
202
+ rescue RPM_VERSION_RANGE::ValidationFailure, RPM_VERSION::ValidationFailure
203
+ Puppet.debug("Cannot parse #{should} as a RPM version range")
204
+ return should
205
+ end
206
+ sorted_versions = SortedSet.new
207
+ available_versions(@resource[:name]).each do |version|
208
+ begin
209
+ rpm_version = RPM_VERSION.parse(version)
210
+ sorted_versions << rpm_version if should_range.include?(rpm_version)
211
+ rescue RPM_VERSION::ValidationFailure
212
+ Puppet.debug("Cannot parse #{version} as a RPM version")
213
+ end
214
+ end
215
+
216
+ version = sorted_versions.entries.last
217
+
218
+ if version
219
+ version = version.to_s.sub(/^\d+:/, '')
220
+ return version
221
+ end
222
+
223
+ Puppet.debug("No available version for package #{@resource[:name]} is included in range #{should_range}")
224
+ should
225
+ end
226
+ end
227
+
228
+ def available_versions(package_name)
229
+ output = execute("yum list #{package_name} --showduplicates | sed -e '1,/Available Packages/ d' | awk '{print $2}'")
230
+ output.split("\n")
231
+ end
232
+
154
233
  def install
155
234
  wanted = @resource[:name]
156
235
  error_level = self.class.error_level
@@ -195,10 +274,11 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
195
274
  self.debug "Installing directly from #{wanted}"
196
275
  else
197
276
  # No explicit source was specified, so add the package version
277
+ should = best_version(should)
198
278
  wanted += "-#{should}"
199
- if wanted.scan(ARCH_REGEX)
279
+ if wanted.scan(self.class::ARCH_REGEX)
200
280
  self.debug "Detected Arch argument in package! - Moving arch to end of version string"
201
- wanted.gsub!(/(.+)(#{ARCH_REGEX})(.+)/,'\1\3\2')
281
+ wanted.gsub!(/(.+)(#{self.class::ARCH_REGEX})(.+)/,'\1\3\2')
202
282
  end
203
283
  end
204
284
  current_package = self.query
@@ -206,10 +286,10 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
206
286
  if @resource[:install_only]
207
287
  self.debug "Updating package #{@resource[:name]} from version #{current_package[:ensure]} to #{should} as install_only packages are never downgraded"
208
288
  operation = update_command
209
- elsif rpm_compareEVR(rpm_parse_evr(should), rpm_parse_evr(current_package[:ensure])) < 0
289
+ elsif rpm_compareEVR(should, current_package[:ensure]) < 0
210
290
  self.debug "Downgrading package #{@resource[:name]} from version #{current_package[:ensure]} to #{should}"
211
291
  operation = :downgrade
212
- elsif rpm_compareEVR(rpm_parse_evr(should), rpm_parse_evr(current_package[:ensure])) > 0
292
+ elsif rpm_compareEVR(should, current_package[:ensure]) > 0
213
293
  self.debug "Upgrading package #{@resource[:name]} from version #{current_package[:ensure]} to #{should}"
214
294
  operation = update_command
215
295
  end
@@ -222,7 +302,7 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
222
302
  command = [command(:cmd)] + no_debug + ["-e", error_level, "-y", install_options, operation, wanted].compact
223
303
  output = execute(command)
224
304
 
225
- if output =~ /^No package #{wanted} available\.$/
305
+ if output.to_s =~ /^No package #{wanted} available\.$/
226
306
  raise Puppet::Error, _("Could not find package %{wanted}") % { wanted: wanted }
227
307
  end
228
308
 
@@ -286,12 +366,16 @@ defaultfor :osfamily => :redhat, :operatingsystemmajrelease => (4..7).to_a
286
366
  # @param key [String] The key to look for in all contained hashes
287
367
  # @return [Array<String>] All hash values with the given key.
288
368
  def scan_options(options, key)
289
- return [] if options.nil?
290
- options.inject([]) do |repos, opt|
291
- if opt.is_a? Hash and opt[key]
292
- repos << opt[key]
369
+ return [] unless options.is_a?(Enumerable)
370
+ values = options.map do | repo |
371
+ value = if repo.is_a?(String)
372
+ next unless repo.include?('=')
373
+ Hash[*repo.strip.split('=')] # make it a hash
374
+ else
375
+ repo
293
376
  end
294
- repos
377
+ value[key]
295
378
  end
379
+ values.compact.uniq
296
380
  end
297
381
  end