puppet 6.11.1 → 6.16.0

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 (395) hide show
  1. checksums.yaml +4 -4
  2. data/CODEOWNERS +3 -8
  3. data/CONTRIBUTING.md +7 -13
  4. data/Gemfile +1 -0
  5. data/Gemfile.lock +39 -36
  6. data/README.md +17 -24
  7. data/ext/build_defaults.yaml +1 -0
  8. data/ext/project_data.yaml +1 -1
  9. data/ext/windows/service/daemon.rb +25 -20
  10. data/lib/puppet.rb +52 -13
  11. data/lib/puppet/agent.rb +20 -14
  12. data/lib/puppet/application/agent.rb +12 -14
  13. data/lib/puppet/application/describe.rb +7 -5
  14. data/lib/puppet/application/device.rb +2 -2
  15. data/lib/puppet/application/filebucket.rb +19 -15
  16. data/lib/puppet/application/plugin.rb +1 -0
  17. data/lib/puppet/application/resource.rb +1 -1
  18. data/lib/puppet/application/ssl.rb +4 -4
  19. data/lib/puppet/concurrent.rb +2 -0
  20. data/lib/puppet/concurrent/lock.rb +16 -0
  21. data/lib/puppet/concurrent/synchronized.rb +15 -0
  22. data/lib/puppet/concurrent/thread_local_singleton.rb +14 -0
  23. data/lib/puppet/configurer.rb +85 -83
  24. data/lib/puppet/configurer/plugin_handler.rb +10 -1
  25. data/lib/puppet/context/trusted_information.rb +14 -8
  26. data/lib/puppet/daemon.rb +13 -27
  27. data/lib/puppet/defaults.rb +158 -40
  28. data/lib/puppet/environments.rb +30 -20
  29. data/lib/puppet/error.rb +9 -1
  30. data/lib/puppet/face/facts.rb +8 -5
  31. data/lib/puppet/face/help.rb +29 -3
  32. data/lib/puppet/face/module/search.rb +5 -0
  33. data/lib/puppet/face/plugin.rb +2 -2
  34. data/lib/puppet/file_serving/http_metadata.rb +1 -1
  35. data/lib/puppet/file_system/file_impl.rb +13 -9
  36. data/lib/puppet/file_system/memory_file.rb +6 -0
  37. data/lib/puppet/file_system/memory_impl.rb +13 -0
  38. data/lib/puppet/file_system/uniquefile.rb +4 -0
  39. data/lib/puppet/file_system/windows.rb +7 -10
  40. data/lib/puppet/forge.rb +3 -3
  41. data/lib/puppet/forge/errors.rb +2 -2
  42. data/lib/puppet/forge/repository.rb +31 -86
  43. data/lib/puppet/functions/call.rb +1 -1
  44. data/lib/puppet/functions/camelcase.rb +2 -2
  45. data/lib/puppet/functions/epp.rb +4 -4
  46. data/lib/puppet/functions/eyaml_lookup_key.rb +13 -8
  47. data/lib/puppet/functions/filter.rb +1 -0
  48. data/lib/puppet/functions/find_file.rb +9 -9
  49. data/lib/puppet/functions/find_template.rb +63 -0
  50. data/lib/puppet/functions/inline_epp.rb +5 -5
  51. data/lib/puppet/functions/reduce.rb +2 -4
  52. data/lib/puppet/http.rb +7 -0
  53. data/lib/puppet/http/client.rb +341 -54
  54. data/lib/puppet/http/errors.rb +2 -0
  55. data/lib/puppet/http/external_client.rb +90 -0
  56. data/lib/puppet/http/redirector.rb +34 -0
  57. data/lib/puppet/http/resolver.rb +57 -1
  58. data/lib/puppet/http/resolver/server_list.rb +98 -0
  59. data/lib/puppet/http/resolver/settings.rb +23 -2
  60. data/lib/puppet/http/resolver/srv.rb +36 -4
  61. data/lib/puppet/http/response.rb +68 -1
  62. data/lib/puppet/http/retry_after_handler.rb +39 -0
  63. data/lib/puppet/http/service.rb +179 -3
  64. data/lib/puppet/http/service/ca.rb +84 -21
  65. data/lib/puppet/http/service/compiler.rb +319 -0
  66. data/lib/puppet/http/service/file_server.rb +206 -0
  67. data/lib/puppet/http/service/report.rb +66 -0
  68. data/lib/puppet/http/session.rb +106 -31
  69. data/lib/puppet/indirector/catalog/compiler.rb +10 -0
  70. data/lib/puppet/indirector/catalog/rest.rb +34 -0
  71. data/lib/puppet/indirector/facts/rest.rb +42 -0
  72. data/lib/puppet/indirector/file_bucket_file/file.rb +1 -1
  73. data/lib/puppet/indirector/file_bucket_file/rest.rb +48 -0
  74. data/lib/puppet/indirector/file_content/http.rb +5 -0
  75. data/lib/puppet/indirector/file_content/rest.rb +30 -0
  76. data/lib/puppet/indirector/file_metadata/http.rb +4 -4
  77. data/lib/puppet/indirector/file_metadata/rest.rb +52 -0
  78. data/lib/puppet/indirector/json.rb +1 -1
  79. data/lib/puppet/indirector/msgpack.rb +1 -1
  80. data/lib/puppet/indirector/node/rest.rb +24 -0
  81. data/lib/puppet/indirector/report/rest.rb +19 -0
  82. data/lib/puppet/indirector/report/yaml.rb +23 -0
  83. data/lib/puppet/indirector/rest.rb +12 -0
  84. data/lib/puppet/indirector/status/rest.rb +18 -0
  85. data/lib/puppet/loaders.rb +6 -0
  86. data/lib/puppet/metatype/manager.rb +80 -80
  87. data/lib/puppet/network/http/base_pool.rb +19 -1
  88. data/lib/puppet/network/http/compression.rb +7 -0
  89. data/lib/puppet/network/http/connection.rb +6 -0
  90. data/lib/puppet/network/http/connection_adapter.rb +182 -0
  91. data/lib/puppet/network/http/nocache_pool.rb +2 -0
  92. data/lib/puppet/network/http/pool.rb +13 -6
  93. data/lib/puppet/network/http_pool.rb +2 -1
  94. data/lib/puppet/node/environment.rb +24 -8
  95. data/lib/puppet/pal/catalog_compiler.rb +5 -0
  96. data/lib/puppet/pal/pal_impl.rb +9 -29
  97. data/lib/puppet/parser/ast/pops_bridge.rb +6 -11
  98. data/lib/puppet/parser/compiler.rb +42 -32
  99. data/lib/puppet/parser/functions.rb +18 -13
  100. data/lib/puppet/parser/functions/epp.rb +3 -3
  101. data/lib/puppet/parser/functions/filter.rb +1 -0
  102. data/lib/puppet/parser/functions/inline_epp.rb +5 -5
  103. data/lib/puppet/pops/evaluator/access_operator.rb +2 -2
  104. data/lib/puppet/pops/evaluator/evaluator_impl.rb +1 -1
  105. data/lib/puppet/pops/evaluator/runtime3_support.rb +1 -1
  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/lookup/invocation.rb +10 -3
  109. data/lib/puppet/pops/model/pn_transformer.rb +5 -9
  110. data/lib/puppet/pops/parser/evaluating_parser.rb +8 -11
  111. data/lib/puppet/pops/serialization/json_path.rb +3 -3
  112. data/lib/puppet/pops/time/timespan.rb +3 -5
  113. data/lib/puppet/pops/types/p_object_type_extension.rb +10 -0
  114. data/lib/puppet/pops/types/string_converter.rb +6 -9
  115. data/lib/puppet/pops/types/type_calculator.rb +30 -10
  116. data/lib/puppet/pops/types/type_formatter.rb +9 -11
  117. data/lib/puppet/pops/types/type_parser.rb +3 -3
  118. data/lib/puppet/pops/validation/checker4_0.rb +1 -1
  119. data/lib/puppet/pops/validation/tasks_checker.rb +5 -1
  120. data/lib/puppet/provider/aix_object.rb +4 -2
  121. data/lib/puppet/provider/group/aix.rb +1 -0
  122. data/lib/puppet/provider/group/groupadd.rb +57 -24
  123. data/lib/puppet/provider/group/windows_adsi.rb +3 -3
  124. data/lib/puppet/provider/package/aix.rb +17 -2
  125. data/lib/puppet/provider/package/apt.rb +78 -4
  126. data/lib/puppet/provider/package/dnfmodule.rb +69 -15
  127. data/lib/puppet/provider/package/dpkg.rb +14 -7
  128. data/lib/puppet/provider/package/fink.rb +20 -3
  129. data/lib/puppet/provider/package/gem.rb +41 -7
  130. data/lib/puppet/provider/package/openbsd.rb +13 -1
  131. data/lib/puppet/provider/package/pacman.rb +2 -5
  132. data/lib/puppet/provider/package/pip.rb +143 -48
  133. data/lib/puppet/provider/package/pip3.rb +0 -2
  134. data/lib/puppet/provider/package/pkg.rb +18 -5
  135. data/lib/puppet/provider/package/pkgdmg.rb +1 -1
  136. data/lib/puppet/provider/package/pkgng.rb +16 -4
  137. data/lib/puppet/provider/package/portage.rb +5 -5
  138. data/lib/puppet/provider/package/puppet_gem.rb +6 -2
  139. data/lib/puppet/provider/package/rpm.rb +6 -213
  140. data/lib/puppet/provider/package/yum.rb +108 -24
  141. data/lib/puppet/provider/package/zypper.rb +59 -1
  142. data/lib/puppet/provider/package_targetable.rb +5 -4
  143. data/lib/puppet/provider/service/systemd.rb +23 -5
  144. data/lib/puppet/provider/user/aix.rb +1 -0
  145. data/lib/puppet/provider/user/directoryservice.rb +30 -5
  146. data/lib/puppet/provider/user/hpux.rb +1 -1
  147. data/lib/puppet/provider/user/useradd.rb +11 -8
  148. data/lib/puppet/reports/http.rb +13 -9
  149. data/lib/puppet/reports/store.rb +1 -1
  150. data/lib/puppet/resource/type_collection.rb +20 -16
  151. data/lib/puppet/runtime.rb +32 -1
  152. data/lib/puppet/settings.rb +4 -0
  153. data/lib/puppet/settings/http_extra_headers_setting.rb +25 -0
  154. data/lib/puppet/ssl.rb +1 -0
  155. data/lib/puppet/ssl/certificate.rb +2 -1
  156. data/lib/puppet/ssl/host.rb +4 -4
  157. data/lib/puppet/ssl/oids.rb +1 -0
  158. data/lib/puppet/ssl/ssl_provider.rb +20 -0
  159. data/lib/puppet/ssl/state_machine.rb +81 -35
  160. data/lib/puppet/ssl/verifier_adapter.rb +9 -1
  161. data/lib/puppet/test/test_helper.rb +7 -1
  162. data/lib/puppet/transaction.rb +33 -11
  163. data/lib/puppet/transaction/report.rb +2 -2
  164. data/lib/puppet/transaction/resource_harness.rb +1 -1
  165. data/lib/puppet/type.rb +7 -2
  166. data/lib/puppet/type/file.rb +13 -0
  167. data/lib/puppet/type/file/data_sync.rb +5 -1
  168. data/lib/puppet/type/file/source.rb +49 -58
  169. data/lib/puppet/type/group.rb +5 -4
  170. data/lib/puppet/type/package.rb +102 -10
  171. data/lib/puppet/type/service.rb +6 -8
  172. data/lib/puppet/type/user.rb +6 -30
  173. data/lib/puppet/util.rb +34 -11
  174. data/lib/puppet/util/at_fork.rb +1 -1
  175. data/lib/puppet/util/autoload.rb +4 -18
  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/logging.rb +30 -18
  179. data/lib/puppet/util/package/version/debian.rb +175 -0
  180. data/lib/puppet/util/package/version/gem.rb +15 -0
  181. data/lib/puppet/util/package/version/pip.rb +167 -0
  182. data/lib/puppet/util/package/version/range.rb +53 -0
  183. data/lib/puppet/util/package/version/range/eq.rb +14 -0
  184. data/lib/puppet/util/package/version/range/gt.rb +14 -0
  185. data/lib/puppet/util/package/version/range/gt_eq.rb +14 -0
  186. data/lib/puppet/util/package/version/range/lt.rb +14 -0
  187. data/lib/puppet/util/package/version/range/lt_eq.rb +14 -0
  188. data/lib/puppet/util/package/version/range/min_max.rb +21 -0
  189. data/lib/puppet/util/package/version/range/simple.rb +11 -0
  190. data/lib/puppet/util/package/version/rpm.rb +73 -0
  191. data/lib/puppet/util/pidlock.rb +36 -10
  192. data/lib/puppet/util/platform.rb +5 -0
  193. data/lib/puppet/util/plist.rb +6 -0
  194. data/lib/puppet/util/rpm_compare.rb +193 -0
  195. data/lib/puppet/util/storage.rb +0 -1
  196. data/lib/puppet/util/windows/adsi.rb +50 -20
  197. data/lib/puppet/util/windows/process.rb +15 -14
  198. data/lib/puppet/util/windows/security.rb +1 -0
  199. data/lib/puppet/util/windows/sid.rb +3 -3
  200. data/lib/puppet/util/yaml.rb +1 -1
  201. data/lib/puppet/version.rb +1 -1
  202. data/lib/puppet/x509/cert_provider.rb +9 -5
  203. data/locales/puppet.pot +640 -521
  204. data/man/man5/puppet.conf.5 +88 -9
  205. data/man/man8/puppet-agent.8 +6 -6
  206. data/man/man8/puppet-apply.8 +1 -1
  207. data/man/man8/puppet-catalog.8 +1 -1
  208. data/man/man8/puppet-config.8 +1 -1
  209. data/man/man8/puppet-describe.8 +1 -1
  210. data/man/man8/puppet-device.8 +2 -2
  211. data/man/man8/puppet-doc.8 +1 -1
  212. data/man/man8/puppet-epp.8 +1 -1
  213. data/man/man8/puppet-facts.8 +1 -1
  214. data/man/man8/puppet-filebucket.8 +17 -2
  215. data/man/man8/puppet-generate.8 +1 -1
  216. data/man/man8/puppet-help.8 +6 -3
  217. data/man/man8/puppet-key.8 +1 -1
  218. data/man/man8/puppet-lookup.8 +1 -1
  219. data/man/man8/puppet-man.8 +1 -1
  220. data/man/man8/puppet-module.8 +4 -1
  221. data/man/man8/puppet-node.8 +1 -1
  222. data/man/man8/puppet-parser.8 +1 -1
  223. data/man/man8/puppet-plugin.8 +1 -1
  224. data/man/man8/puppet-report.8 +1 -1
  225. data/man/man8/puppet-resource.8 +1 -1
  226. data/man/man8/puppet-script.8 +1 -1
  227. data/man/man8/puppet-ssl.8 +2 -2
  228. data/man/man8/puppet-status.8 +1 -1
  229. data/man/man8/puppet.8 +2 -2
  230. data/spec/fixtures/ssl/unknown-127.0.0.1-key.pem +67 -0
  231. data/spec/fixtures/ssl/unknown-127.0.0.1.pem +48 -0
  232. data/spec/fixtures/ssl/unknown-ca-key.pem +67 -0
  233. data/spec/fixtures/ssl/unknown-ca.pem +59 -0
  234. data/spec/fixtures/unit/forge/bacula.json +76 -0
  235. data/spec/fixtures/unit/provider/package/dnfmodule/{dnf-module-list-installed.txt → dnf-module-list.txt} +8 -0
  236. data/spec/fixtures/unit/provider/package/pkgng/pkg.version +2 -0
  237. data/spec/fixtures/unit/provider/package/yum/yum-check-update-subscription-manager.txt +9 -0
  238. data/spec/fixtures/unit/provider/package/zypper/zypper-search-uninstalled.out +13 -0
  239. data/spec/fixtures/unit/provider/service/systemd/list_unit_files_services +9 -0
  240. 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
  241. 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
  242. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_md5/should_update_if_content_differs_on_disk.yml +1 -106
  243. 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
  244. data/spec/fixtures/vcr/cassettes/Puppet_Type_File/when_sourcing/from_http/using_mtime/should_fetch_if_no_header_specified.yml +1 -98
  245. 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
  246. 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
  247. data/spec/integration/application/agent_spec.rb +394 -0
  248. data/spec/integration/application/apply_spec.rb +132 -3
  249. data/spec/integration/application/filebucket_spec.rb +190 -0
  250. data/spec/integration/application/plugin_spec.rb +73 -0
  251. data/spec/integration/configurer_spec.rb +26 -7
  252. data/spec/integration/http/client_spec.rb +154 -0
  253. data/spec/integration/indirector/facts/facter_spec.rb +4 -0
  254. data/spec/integration/indirector/report/yaml.rb +83 -0
  255. data/spec/integration/module_tool/forge_spec.rb +51 -0
  256. data/spec/integration/network/http_pool_spec.rb +76 -20
  257. data/spec/integration/node/environment_spec.rb +15 -0
  258. data/spec/integration/util/windows/adsi_spec.rb +6 -1
  259. data/spec/lib/puppet/test_ca.rb +2 -2
  260. data/spec/lib/puppet_spec/https.rb +20 -9
  261. data/spec/lib/puppet_spec/puppetserver.rb +119 -0
  262. data/spec/shared_contexts/https.rb +29 -0
  263. data/spec/spec_helper.rb +6 -2
  264. data/spec/unit/agent_spec.rb +80 -26
  265. data/spec/unit/application/agent_spec.rb +9 -5
  266. data/spec/unit/application/apply_spec.rb +2 -12
  267. data/spec/unit/application/describe_spec.rb +88 -50
  268. data/spec/unit/application/device_spec.rb +2 -2
  269. data/spec/unit/application/filebucket_spec.rb +22 -2
  270. data/spec/unit/application/resource_spec.rb +2 -2
  271. data/spec/unit/concurrent/lock_spec.rb +29 -0
  272. data/spec/unit/configurer/fact_handler_spec.rb +0 -4
  273. data/spec/unit/configurer/plugin_handler_spec.rb +36 -19
  274. data/spec/unit/configurer_spec.rb +400 -406
  275. data/spec/unit/context/trusted_information_spec.rb +17 -0
  276. data/spec/unit/daemon_spec.rb +5 -64
  277. data/spec/unit/defaults_spec.rb +38 -4
  278. data/spec/unit/environments_spec.rb +65 -28
  279. data/spec/unit/face/facts_spec.rb +24 -20
  280. data/spec/unit/face/module/search_spec.rb +17 -0
  281. data/spec/unit/face/plugin_spec.rb +12 -10
  282. data/spec/unit/file_system/uniquefile_spec.rb +11 -0
  283. data/spec/unit/file_system_spec.rb +26 -2
  284. data/spec/unit/forge/errors_spec.rb +1 -1
  285. data/spec/unit/forge/forge_spec.rb +12 -54
  286. data/spec/unit/forge/module_release_spec.rb +19 -6
  287. data/spec/unit/forge/repository_spec.rb +63 -157
  288. data/spec/unit/forge_spec.rb +46 -116
  289. data/spec/unit/functions/find_template_spec.rb +69 -0
  290. data/spec/unit/functions/lookup_spec.rb +13 -0
  291. data/spec/unit/http/client_spec.rb +395 -27
  292. data/spec/unit/http/external_client_spec.rb +201 -0
  293. data/spec/unit/http/resolver_spec.rb +81 -12
  294. data/spec/unit/http/response_spec.rb +69 -0
  295. data/spec/unit/http/service/ca_spec.rb +100 -7
  296. data/spec/unit/http/service/compiler_spec.rb +627 -0
  297. data/spec/unit/http/service/file_server_spec.rb +308 -0
  298. data/spec/unit/http/service/report_spec.rb +118 -0
  299. data/spec/unit/http/service_spec.rb +117 -4
  300. data/spec/unit/http/session_spec.rb +237 -19
  301. data/spec/unit/indirector/catalog/compiler_spec.rb +47 -29
  302. data/spec/unit/indirector/catalog/rest_spec.rb +59 -2
  303. data/spec/unit/indirector/facts/rest_spec.rb +79 -24
  304. data/spec/unit/indirector/file_bucket_file/rest_spec.rb +82 -2
  305. data/spec/unit/indirector/file_content/rest_spec.rb +53 -2
  306. data/spec/unit/indirector/file_metadata/http_spec.rb +167 -0
  307. data/spec/unit/indirector/file_metadata/rest_spec.rb +110 -2
  308. data/spec/unit/indirector/node/rest_spec.rb +57 -2
  309. data/spec/unit/indirector/report/rest_spec.rb +58 -51
  310. data/spec/unit/indirector/resource/ral_spec.rb +7 -8
  311. data/spec/unit/indirector/rest_spec.rb +13 -0
  312. data/spec/unit/indirector/status/rest_spec.rb +43 -2
  313. data/spec/unit/network/http/connection_spec.rb +549 -176
  314. data/spec/unit/network/http/nocache_pool_spec.rb +25 -3
  315. data/spec/unit/network/http/pool_spec.rb +89 -11
  316. data/spec/unit/network/http_pool_spec.rb +63 -57
  317. data/spec/unit/network/http_spec.rb +1 -1
  318. data/spec/unit/node/environment_spec.rb +16 -0
  319. data/spec/unit/node/facts_spec.rb +2 -1
  320. data/spec/unit/node_spec.rb +7 -4
  321. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +8 -3
  322. data/spec/unit/pops/serialization/to_from_hr_spec.rb +6 -1
  323. data/spec/unit/pops/validator/validator_spec.rb +7 -2
  324. data/spec/unit/provider/aix_object_spec.rb +16 -2
  325. data/spec/unit/provider/group/groupadd_spec.rb +181 -56
  326. data/spec/unit/provider/group/windows_adsi_spec.rb +43 -10
  327. data/spec/unit/provider/package/aix_spec.rb +29 -0
  328. data/spec/unit/provider/package/apt_spec.rb +43 -2
  329. data/spec/unit/provider/package/aptitude_spec.rb +1 -0
  330. data/spec/unit/provider/package/dnfmodule_spec.rb +76 -15
  331. data/spec/unit/provider/package/dpkg_spec.rb +28 -6
  332. data/spec/unit/provider/package/gem_spec.rb +40 -0
  333. data/spec/unit/provider/package/openbsd_spec.rb +17 -0
  334. data/spec/unit/provider/package/pacman_spec.rb +6 -21
  335. data/spec/unit/provider/package/pip_spec.rb +68 -19
  336. data/spec/unit/provider/package/pkg_spec.rb +15 -1
  337. data/spec/unit/provider/package/pkgdmg_spec.rb +1 -1
  338. data/spec/unit/provider/package/pkgng_spec.rb +38 -0
  339. data/spec/unit/provider/package/portage_spec.rb +9 -4
  340. data/spec/unit/provider/package/puppet_gem_spec.rb +8 -0
  341. data/spec/unit/provider/package/rpm_spec.rb +0 -212
  342. data/spec/unit/provider/package/yum_spec.rb +292 -0
  343. data/spec/unit/provider/package/zypper_spec.rb +84 -0
  344. data/spec/unit/provider/package_targetable_spec.rb +60 -0
  345. data/spec/unit/provider/service/init_spec.rb +1 -0
  346. data/spec/unit/provider/service/openbsd_spec.rb +9 -0
  347. data/spec/unit/provider/service/openwrt_spec.rb +1 -0
  348. data/spec/unit/provider/service/redhat_spec.rb +9 -0
  349. data/spec/unit/provider/service/systemd_spec.rb +92 -12
  350. data/spec/unit/provider/user/directoryservice_spec.rb +41 -0
  351. data/spec/unit/provider/user/hpux_spec.rb +2 -2
  352. data/spec/unit/provider/user/useradd_spec.rb +21 -8
  353. data/spec/unit/provider/user/windows_adsi_spec.rb +3 -3
  354. data/spec/unit/puppet_pal_2pec.rb +0 -26
  355. data/spec/unit/puppet_pal_catalog_spec.rb +46 -0
  356. data/spec/unit/puppet_spec.rb +47 -0
  357. data/spec/unit/reports/http_spec.rb +70 -52
  358. data/spec/unit/settings/autosign_setting_spec.rb +1 -1
  359. data/spec/unit/settings/http_extra_headers_spec.rb +64 -0
  360. data/spec/unit/ssl/certificate_spec.rb +7 -0
  361. data/spec/unit/ssl/host_spec.rb +4 -2
  362. data/spec/unit/ssl/oids_spec.rb +1 -0
  363. data/spec/unit/ssl/ssl_provider_spec.rb +71 -0
  364. data/spec/unit/ssl/state_machine_spec.rb +99 -13
  365. data/spec/unit/transaction/persistence_spec.rb +1 -10
  366. data/spec/unit/transaction/report_spec.rb +4 -0
  367. data/spec/unit/transaction_spec.rb +45 -1
  368. data/spec/unit/type/file/content_spec.rb +9 -3
  369. data/spec/unit/type/file/ensure_spec.rb +1 -2
  370. data/spec/unit/type/file/source_spec.rb +86 -35
  371. data/spec/unit/type/package_spec.rb +8 -0
  372. data/spec/unit/type/service_spec.rb +9 -8
  373. data/spec/unit/type/user_spec.rb +1 -2
  374. data/spec/unit/util/at_fork_spec.rb +3 -2
  375. data/spec/unit/util/autoload_spec.rb +2 -1
  376. data/spec/unit/util/log/destinations_spec.rb +1 -29
  377. data/spec/unit/util/log_spec.rb +0 -138
  378. data/spec/unit/util/logging_spec.rb +200 -0
  379. data/spec/unit/util/package/version/debian_spec.rb +83 -0
  380. data/spec/unit/util/package/version/pip_spec.rb +464 -0
  381. data/spec/unit/util/package/version/range_spec.rb +175 -0
  382. data/spec/unit/util/package/version/rpm_spec.rb +121 -0
  383. data/spec/unit/util/pidlock_spec.rb +112 -42
  384. data/spec/unit/util/plist_spec.rb +20 -0
  385. data/spec/unit/util/rpm_compare_spec.rb +196 -0
  386. data/spec/unit/util/storage_spec.rb +1 -8
  387. data/spec/unit/util/windows/adsi_spec.rb +55 -4
  388. data/spec/unit/util/windows/sid_spec.rb +2 -2
  389. data/spec/unit/x509/cert_provider_spec.rb +24 -4
  390. data/tasks/generate_cert_fixtures.rake +15 -1
  391. data/tasks/manpages.rake +6 -35
  392. metadata +92 -12
  393. data/COMMITTERS.md +0 -244
  394. data/spec/integration/faces/plugin_spec.rb +0 -61
  395. data/spec/lib/puppet_spec/validators.rb +0 -37
@@ -51,7 +51,11 @@ module Puppet
51
51
  desc "Whether a service should be enabled to start at boot.
52
52
  This property behaves differently depending on the platform;
53
53
  wherever possible, it relies on local tools to enable or disable
54
- a given service. Default values depend on the platform."
54
+ a given service. Default values depend on the platform.
55
+
56
+ If you don't specify a value for the `enable` attribute, Puppet leaves
57
+ that aspect of the service alone and your operating system determines
58
+ the behavior."
55
59
 
56
60
  newvalue(:true, :event => :service_enabled) do
57
61
  provider.enable
@@ -80,14 +84,8 @@ module Puppet
80
84
  provider.delayed_start
81
85
  end
82
86
 
83
- # This only makes sense on systemd systems. Static services cannot be enabled
84
- # or disabled manually.
85
87
  def insync?(current)
86
- if provider.respond_to?(:cached_enabled?) && provider.cached_enabled? == 'static'
87
- Puppet.debug("Unable to enable or disable static service #{@resource[:name]}")
88
- return true
89
- end
90
-
88
+ return provider.enabled_insync?(current) if provider.respond_to?(:enabled_insync?)
91
89
  super(current)
92
90
  end
93
91
 
@@ -51,7 +51,7 @@ module Puppet
51
51
  feature :manages_aix_lam,
52
52
  "The provider can manage AIX Loadable Authentication Module (LAM) system."
53
53
 
54
- feature :libuser,
54
+ feature :manages_local_users_and_groups,
55
55
  "Allows local users to be managed on systems that also use some other
56
56
  remote Name Service Switch (NSS) method of managing accounts."
57
57
 
@@ -493,25 +493,6 @@ module Puppet
493
493
  provider.exists?
494
494
  end
495
495
 
496
- def retrieve
497
- absent = false
498
- properties.inject({}) { |prophash, property|
499
- current_value = :absent
500
-
501
- if absent
502
- prophash[property] = :absent
503
- else
504
- current_value = property.retrieve
505
- prophash[property] = current_value
506
- end
507
-
508
- if property.name == :ensure and current_value == :absent
509
- absent = true
510
- end
511
- prophash
512
- }
513
- end
514
-
515
496
  newproperty(:roles, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
516
497
  desc "The roles the user has. Multiple roles should be
517
498
  specified as an array."
@@ -626,7 +607,8 @@ module Puppet
626
607
  end
627
608
 
628
609
  newparam(:ia_load_module, :required_features => :manages_aix_lam) do
629
- desc "The name of the I&A module to use to manage this user."
610
+ desc "The name of the I&A module to use to manage this user.
611
+ This should be set to `files` if managing local users."
630
612
  end
631
613
 
632
614
  newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
@@ -687,10 +669,10 @@ module Puppet
687
669
  end
688
670
 
689
671
  newparam(:forcelocal, :boolean => true,
690
- :required_features => :libuser,
672
+ :required_features => :manages_local_users_and_groups,
691
673
  :parent => Puppet::Parameter::Boolean) do
692
674
  desc "Forces the management of local accounts when accounts are also
693
- being managed by some other Name Service Switch (NSS).
675
+ being managed by some other Name Service Switch (NSS). For AIX, refer to the `ia_load_module` parameter.
694
676
 
695
677
  This option relies on your operating system's implementation of `luser*` commands, such as `luseradd` , and `lgroupadd`, `lusermod`. The `forcelocal` option could behave unpredictably in some circumstances. If the tools it depends on are not available, it might have no effect at all."
696
678
  defaultto false
@@ -754,17 +736,11 @@ module Puppet
754
736
  value = test_sym if [:true, :false].include? test_sym
755
737
 
756
738
  return [] if value == :false
757
- home = resource[:home]
758
- if value == :true and not home
759
- raise ArgumentError, _("purge_ssh_keys can only be true for users with a defined home directory")
760
- end
739
+ home = resource[:home] || Dir.home(resource[:name])
761
740
 
762
741
  return [ "#{home}/.ssh/authorized_keys" ] if value == :true
763
742
  # value is an array - munge each value
764
743
  [ value ].flatten.map do |entry|
765
- if entry =~ /^~|^%h/ and not home
766
- raise ArgumentError, _("purge_ssh_keys value '%{value}' meta character ~ or %{home_placeholder} only allowed for users with a defined home directory") % { value: value, home_placeholder: '%h' }
767
- end
768
744
  # make sure frozen value is duplicated by using a gsub, second mutating gsub! is then ok
769
745
  entry = entry.gsub(/^~\//, "#{home}/")
770
746
  entry.gsub!(/^%h\//, "#{home}/")
@@ -526,21 +526,44 @@ module Util
526
526
 
527
527
  module_function :thinmark
528
528
 
529
+ PUPPET_STACK_INSERTION_FRAME = /.*puppet_stack\.rb.*in.*`stack'/
530
+
529
531
  # utility method to get the current call stack and format it to a human-readable string (which some IDEs/editors
530
532
  # will recognize as links to the line numbers in the trace)
531
- def self.pretty_backtrace(backtrace = caller(1))
532
- backtrace.collect do |line|
533
- _, path, rest = /^(.*):(\d+.*)$/.match(line).to_a
534
- # If the path doesn't exist - like in one test, and like could happen in
535
- # the world - we should just tolerate it and carry on. --daniel 2012-09-05
536
- # Also, if we don't match, just include the whole line.
537
- if path
538
- path = Pathname(path).realpath rescue path
539
- "#{path}:#{rest}"
533
+ def self.pretty_backtrace(backtrace = caller(1), puppetstack = [])
534
+ format_backtrace_array(backtrace, puppetstack).join("\n")
535
+ end
536
+
537
+ # arguments may be a Ruby stack, with an optional Puppet stack argument,
538
+ # or just a Puppet stack.
539
+ # stacks may be an Array of Strings "/foo.rb:0 in `blah'" or
540
+ # an Array of Arrays that represent a frame: ["/foo.pp", 0]
541
+ def self.format_backtrace_array(primary_stack, puppetstack = [])
542
+ primary_stack.flat_map do |frame|
543
+ frame = format_puppetstack_frame(frame) if frame.is_a?(Array)
544
+ primary_frame = resolve_stackframe(frame)
545
+
546
+ if primary_frame =~ PUPPET_STACK_INSERTION_FRAME && !puppetstack.empty?
547
+ [resolve_stackframe(format_puppetstack_frame(puppetstack.shift)),
548
+ primary_frame]
540
549
  else
541
- line
550
+ primary_frame
542
551
  end
543
- end.join("\n")
552
+ end
553
+ end
554
+
555
+ def self.resolve_stackframe(frame)
556
+ _, path, rest = /^(.*):(\d+.*)$/.match(frame).to_a
557
+ if path
558
+ path = Pathname(path).realpath rescue path
559
+ "#{path}:#{rest}"
560
+ else
561
+ frame
562
+ end
563
+ end
564
+
565
+ def self.format_puppetstack_frame(file_and_lineno)
566
+ file_and_lineno.join(':')
544
567
  end
545
568
 
546
569
  # Replace a file, securely. This takes a block, and passes it the file
@@ -13,7 +13,7 @@ require 'puppet'
13
13
  # service.
14
14
  module Puppet::Util::AtFork
15
15
  @handler_class = loop do
16
- if Facter.value(:operatingsystem) == 'Solaris'
16
+ if Puppet::Util::Platform.solaris?
17
17
  begin
18
18
  require 'puppet/util/at_fork/solaris'
19
19
  # using break to return a value from the loop block
@@ -2,6 +2,7 @@ require 'pathname'
2
2
  require 'puppet/util/rubygems'
3
3
  require 'puppet/util/warnings'
4
4
  require 'puppet/pops/adaptable'
5
+ require 'puppet/concurrent/synchronized'
5
6
 
6
7
  # An adapter that ties the module_directories cache to the environment where the modules are parsed. This
7
8
  # adapter ensures that the life-cycle of this cache doesn't exceed the life-cycle of the environment.
@@ -13,6 +14,9 @@ end
13
14
 
14
15
  # Autoload paths, either based on names or all at once.
15
16
  class Puppet::Util::Autoload
17
+ include Puppet::Concurrent::Synchronized
18
+ extend Puppet::Concurrent::Synchronized
19
+
16
20
  @loaded = {}
17
21
 
18
22
  class << self
@@ -124,19 +128,6 @@ class Puppet::Util::Autoload
124
128
  end.directories
125
129
  end
126
130
 
127
- # @api private
128
- def vendored_modules
129
- dir = Puppet[:vendormoduledir]
130
- if dir && File.directory?(dir)
131
- Dir.entries(dir)
132
- .reject { |f| f =~ /^\./ }
133
- .collect { |f| File.join(dir, f, "lib") }
134
- .find_all { |d| FileTest.directory?(d) }
135
- else
136
- []
137
- end
138
- end
139
-
140
131
  # @api private
141
132
  def gem_directories
142
133
  gem_source.directories
@@ -164,11 +155,6 @@ class Puppet::Util::Autoload
164
155
  # "app_defaults_initialized?" method on the main puppet Settings object.
165
156
  # --cprice 2012-03-16
166
157
  if Puppet.settings.app_defaults_initialized?
167
- unless @initialized
168
- $LOAD_PATH.unshift(Puppet[:libdir])
169
- $LOAD_PATH.concat(vendored_modules)
170
- @initialized = true
171
- end
172
158
  gem_directories + module_directories(env) + $LOAD_PATH
173
159
  else
174
160
  gem_directories + $LOAD_PATH
@@ -1,5 +1,6 @@
1
1
  require 'puppet/util/autoload'
2
2
  require 'puppet/util'
3
+ require 'puppet/concurrent/lock'
3
4
 
4
5
  # A module that can easily autoload things for us. Uses an instance
5
6
  # of Puppet::Util::Autoload
@@ -18,6 +19,7 @@ module Puppet::Util::InstanceLoader
18
19
  type = type.intern
19
20
  @instances[type] = {}
20
21
  @autoloaders[type] = Puppet::Util::Autoload.new(self, path)
22
+ @instance_loader_lock = Puppet::Concurrent::Lock.new
21
23
 
22
24
  # Now define our new simple methods
23
25
  unless respond_to?(type)
@@ -44,19 +46,21 @@ module Puppet::Util::InstanceLoader
44
46
 
45
47
  # Retrieve an already-loaded instance, or attempt to load our instance.
46
48
  def loaded_instance(type, name)
47
- name = name.intern
48
- instances = instance_hash(type)
49
- return nil unless instances
50
- unless instances.include? name
51
- if instance_loader(type).load(name, Puppet.lookup(:current_environment))
52
- unless instances.include? name
53
- Puppet.warning(_("Loaded %{type} file for %{name} but %{type} was not defined") % { type: type, name: name })
49
+ @instance_loader_lock.synchronize do
50
+ name = name.intern
51
+ instances = instance_hash(type)
52
+ return nil unless instances
53
+ unless instances.include? name
54
+ if instance_loader(type).load(name, Puppet.lookup(:current_environment))
55
+ unless instances.include? name
56
+ Puppet.warning(_("Loaded %{type} file for %{name} but %{type} was not defined") % { type: type, name: name })
57
+ return nil
58
+ end
59
+ else
54
60
  return nil
55
61
  end
56
- else
57
- return nil
58
62
  end
63
+ instances[name]
59
64
  end
60
- instances[name]
61
65
  end
62
66
  end
@@ -47,7 +47,7 @@ Puppet::Util::Log.newdesttype :file do
47
47
  require 'fileutils'
48
48
 
49
49
  def self.match?(obj)
50
- Puppet::Util.absolute_path?(obj)
50
+ obj.is_a?(String) && Puppet::Util.absolute_path?(obj)
51
51
  end
52
52
 
53
53
  def close
@@ -91,18 +91,9 @@ Puppet::Util::Log.newdesttype :file do
91
91
  end
92
92
  end
93
93
 
94
- file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
94
+ file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
95
95
  file.puts('[') if need_array_start
96
96
 
97
- # Give ownership to the user and group puppet will run as
98
- if Puppet.features.root? && !Puppet::Util::Platform.windows? && !file_exists
99
- begin
100
- FileUtils.chown(Puppet[:user], Puppet[:group], path)
101
- rescue ArgumentError, Errno::EPERM
102
- Puppet.err _("Unable to set ownership to %{user}:%{group} for log file: %{path}") % { user: Puppet[:user], group: Puppet[:group], path: path }
103
- end
104
- end
105
-
106
97
  @file = file
107
98
 
108
99
  @autoflush = Puppet[:autoflush]
@@ -48,12 +48,13 @@ module Logging
48
48
  # wish to log a message at all; in this case it is likely that you are only calling this method in order
49
49
  # to take advantage of the backtrace logging.
50
50
  def log_exception(exception, message = :default, options = {})
51
- trace = Puppet[:trace] || options[:trace]
52
51
  level = options[:level] || :err
52
+ combined_trace = Puppet[:trace] || options[:trace]
53
+ puppet_trace = Puppet[:puppet_trace] || options[:puppet_trace]
54
+
53
55
  if message == :default && exception.is_a?(Puppet::ParseErrorWithIssue)
54
56
  # Retain all detailed info and keep plain message and stacktrace separate
55
- backtrace = []
56
- build_exception_trace(backtrace, exception, trace)
57
+ backtrace = build_exception_trace(exception, combined_trace, puppet_trace)
57
58
  Puppet::Util::Log.create({
58
59
  :level => level,
59
60
  :source => log_source,
@@ -67,28 +68,27 @@ module Logging
67
68
  :node => exception.node
68
69
  }.merge(log_metadata))
69
70
  else
70
- send_log(level, format_exception(exception, message, trace))
71
+ send_log(level, format_exception(exception, message, combined_trace, puppet_trace))
71
72
  end
72
73
  end
73
74
 
74
- def build_exception_trace(arr, exception, trace = true)
75
- if trace and exception.backtrace
76
- exception.backtrace.each do |line|
77
- arr << line =~ /^(.+):(\d+.*)$/ ? ("#{Pathname($1).realpath}:#{$2}" rescue line) : line
78
- end
79
- end
75
+ def build_exception_trace(exception, combined_trace = true, puppet_trace = false)
76
+ built_trace = format_backtrace(exception, combined_trace, puppet_trace)
77
+
80
78
  if exception.respond_to?(:original)
81
79
  original = exception.original
82
80
  unless original.nil?
83
- arr << _('Wrapped exception:')
84
- arr << original.message
85
- build_exception_trace(arr, original, trace)
81
+ built_trace << _('Wrapped exception:')
82
+ built_trace << original.message
83
+ built_trace += build_exception_trace(original, combined_trace, puppet_trace)
86
84
  end
87
85
  end
86
+
87
+ built_trace
88
88
  end
89
89
  private :build_exception_trace
90
90
 
91
- def format_exception(exception, message = :default, trace = true)
91
+ def format_exception(exception, message = :default, combined_trace = true, puppet_trace = false)
92
92
  arr = []
93
93
  case message
94
94
  when :default
@@ -99,16 +99,28 @@ module Logging
99
99
  arr << message
100
100
  end
101
101
 
102
- if trace and exception.backtrace
103
- arr << Puppet::Util.pretty_backtrace(exception.backtrace)
104
- end
102
+ arr += format_backtrace(exception, combined_trace, puppet_trace)
103
+
105
104
  if exception.respond_to?(:original) and exception.original
106
105
  arr << _("Wrapped exception:")
107
- arr << format_exception(exception.original, :default, trace)
106
+ arr << format_exception(exception.original, :default, combined_trace, puppet_trace)
108
107
  end
108
+
109
109
  arr.flatten.join("\n")
110
110
  end
111
111
 
112
+ def format_backtrace(exception, combined_trace, puppet_trace)
113
+ puppetstack = exception.respond_to?(:puppetstack) ? exception.puppetstack : []
114
+
115
+ if combined_trace and exception.backtrace
116
+ Puppet::Util.format_backtrace_array(exception.backtrace, puppetstack)
117
+ elsif puppet_trace && !puppetstack.empty?
118
+ Puppet::Util.format_backtrace_array(puppetstack)
119
+ else
120
+ []
121
+ end
122
+ end
123
+
112
124
  def log_and_raise(exception, message)
113
125
  log_exception(exception, message)
114
126
  raise exception, message + "\n" + exception.to_s, exception.backtrace
@@ -0,0 +1,175 @@
1
+ module Puppet::Util::Package::Version
2
+ class Debian < Numeric
3
+ include Comparable
4
+
5
+ # Version string matching regexes
6
+ REGEX_EPOCH = '(?:([0-9]+):)?'
7
+ # alphanumerics and the characters . + - ~ , starts with a digit, ~ only of debian_revision is present
8
+ REGEX_UPSTREAM_VERSION = '([\.\+~0-9a-zA-Z-]+?)'
9
+ #alphanumerics and the characters + . ~
10
+ REGEX_DEBIAN_REVISION = '(?:-([\.\+~0-9a-zA-Z]*))?'
11
+
12
+ REGEX_FULL = REGEX_EPOCH + REGEX_UPSTREAM_VERSION + REGEX_DEBIAN_REVISION.freeze
13
+ REGEX_FULL_RX = /\A#{REGEX_FULL}\Z/
14
+
15
+ class ValidationFailure < ArgumentError; end
16
+
17
+ def self.parse(ver)
18
+ raise ValidationFailure, "Unable to parse '#{ver}' as a string" unless ver.is_a?(String)
19
+
20
+ match, epoch, upstream_version, debian_revision = *ver.match(REGEX_FULL_RX)
21
+
22
+ raise ValidationFailure, "Unable to parse '#{ver}' as a debian version identifier" unless match
23
+
24
+ new(epoch.to_i, upstream_version, debian_revision).freeze
25
+ end
26
+
27
+ def to_s
28
+ s = @upstream_version
29
+ s = "#{@epoch}:#{s}" if @epoch != 0
30
+ s = "#{s}-#{@debian_revision}" if @debian_revision
31
+ s
32
+ end
33
+ alias inspect to_s
34
+
35
+ def eql?(other)
36
+ other.is_a?(self.class) &&
37
+ @epoch.eql?(other.epoch) &&
38
+ @upstream_version.eql?(other.upstream_version) &&
39
+ @debian_revision.eql?(other.debian_revision)
40
+ end
41
+ alias == eql?
42
+
43
+ def <=>(other)
44
+ return nil unless other.is_a?(self.class)
45
+ cmp = @epoch <=> other.epoch
46
+ if cmp == 0
47
+ cmp = compare_upstream_version(other)
48
+ if cmp == 0
49
+ cmp = compare_debian_revision(other)
50
+ end
51
+ end
52
+ cmp
53
+ end
54
+
55
+ attr_reader :epoch, :upstream_version, :debian_revision
56
+
57
+ private
58
+
59
+ def initialize(epoch, upstream_version, debian_revision)
60
+ @epoch = epoch
61
+ @upstream_version = upstream_version
62
+ @debian_revision = debian_revision
63
+ end
64
+
65
+ def compare_upstream_version(other)
66
+ mine = @upstream_version
67
+ yours = other.upstream_version
68
+ compare_debian_versions(mine, yours)
69
+ end
70
+
71
+ def compare_debian_revision(other)
72
+ mine = @debian_revision
73
+ yours = other.debian_revision
74
+ compare_debian_versions(mine, yours)
75
+ end
76
+
77
+ def compare_debian_versions(mine, yours)
78
+ # First the initial part of each string consisting entirely of non-digit characters is determined.
79
+ # These two parts (one of which may be empty) are compared lexically. If a difference is found it is
80
+ # returned. The lexical comparison is a comparison of ASCII values modified so that all the letters
81
+ # sort earlier than all the non-letters and so that a tilde sorts before anything, even the end of a
82
+ # part. For example, the following parts are in sorted order from earliest to latest: ~~, ~~a, ~, the
83
+ # empty part, a.
84
+ #
85
+ # Then the initial part of the remainder of each string which consists entirely of digit characters
86
+ # is determined. The numerical values of these two parts are compared, and any difference found is
87
+ # returned as the result of the comparison. For these purposes an empty string (which can only occur
88
+ # at the end of one or both version strings being compared) counts as zero.
89
+ #
90
+ # These two steps (comparing and removing initial non-digit strings and initial digit strings) are
91
+ # repeated until a difference is found or both strings are exhausted.
92
+
93
+ mine_index = 0
94
+ yours_index = 0
95
+ cmp = 0
96
+ mine ||= ''
97
+ yours ||= ''
98
+ while mine_index < mine.length && yours_index < yours.length && cmp == 0
99
+ #handle ~
100
+ _mymatch, mytilde = *match_tildes(mine.slice(mine_index..-1))
101
+ mytilde ||= ''
102
+
103
+ _yoursmatch, yourstilde = *match_tildes(yours.slice(yours_index..-1))
104
+ yourstilde ||= ''
105
+
106
+ cmp = -1 * (mytilde.length <=> yourstilde.length)
107
+ mine_index += mytilde.length
108
+ yours_index += yourstilde.length
109
+
110
+ if cmp == 0 # handle letters
111
+
112
+ _mymatch, myletters = *match_letters(mine.slice(mine_index..-1))
113
+ myletters ||= ''
114
+
115
+ _yoursmatch, yoursletters = *match_letters(yours.slice(yours_index..-1))
116
+ yoursletters ||= ''
117
+
118
+ cmp = myletters <=> yoursletters
119
+ mine_index += myletters.length
120
+ yours_index += yoursletters.length
121
+
122
+ if cmp == 0 # handle nonletters except tilde
123
+ _mymatch, mynon_letters = *match_non_letters(mine.slice(mine_index..-1))
124
+ mynon_letters ||= ''
125
+
126
+ _yoursmatch, yoursnon_letters = *match_non_letters(yours.slice(yours_index..-1))
127
+ yoursnon_letters ||= ''
128
+
129
+ cmp = mynon_letters <=> yoursnon_letters
130
+ mine_index += mynon_letters.length
131
+ yours_index += yoursnon_letters.length
132
+
133
+ if cmp == 0 # handle digits
134
+ _mymatch, mydigits = *match_digits(mine.slice(mine_index..-1))
135
+ mydigits ||= ''
136
+
137
+ _yoursmatch, yoursdigits = *match_digits(yours.slice(yours_index..-1))
138
+ yoursdigits ||= ''
139
+
140
+ cmp = mydigits.to_i <=> yoursdigits.to_i
141
+ mine_index += mydigits.length
142
+ yours_index += yoursdigits.length
143
+ end
144
+ end
145
+ end
146
+ end
147
+ if cmp == 0
148
+ if mine_index < mine.length && match_tildes(mine[mine_index])
149
+ cmp = -1
150
+ elsif yours_index < yours.length && match_tildes(yours[yours_index])
151
+ cmp = 1
152
+ else
153
+ cmp = mine.length <=> yours.length
154
+ end
155
+ end
156
+ cmp
157
+ end
158
+
159
+ def match_digits(a)
160
+ a.match(/^([0-9]+)/)
161
+ end
162
+
163
+ def match_non_letters(a)
164
+ a.match(/^([\.\+-]+)/)
165
+ end
166
+
167
+ def match_tildes(a)
168
+ a.match(/^(~+)/)
169
+ end
170
+
171
+ def match_letters(a)
172
+ a.match(/^([A-Za-z]+)/)
173
+ end
174
+ end
175
+ end