rubygems-update 2.6.1 → 3.5.0

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 (801) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +5899 -0
  3. data/CODE_OF_CONDUCT.md +76 -35
  4. data/CONTRIBUTING.md +231 -0
  5. data/MAINTAINERS.txt +8 -0
  6. data/Manifest.txt +428 -216
  7. data/POLICIES.md +135 -0
  8. data/README.md +112 -0
  9. data/UPGRADING.md +15 -0
  10. data/bundler/CHANGELOG.md +4719 -0
  11. data/bundler/LICENSE.md +22 -0
  12. data/bundler/README.md +58 -0
  13. data/bundler/UPGRADING.md +222 -0
  14. data/bundler/bundler.gemspec +46 -0
  15. data/bundler/exe/bundle +29 -0
  16. data/bundler/exe/bundler +4 -0
  17. data/bundler/lib/bundler/.document +1 -0
  18. data/bundler/lib/bundler/build_metadata.rb +45 -0
  19. data/bundler/lib/bundler/capistrano.rb +22 -0
  20. data/bundler/lib/bundler/checksum.rb +245 -0
  21. data/bundler/lib/bundler/ci_detector.rb +75 -0
  22. data/bundler/lib/bundler/cli/add.rb +47 -0
  23. data/bundler/lib/bundler/cli/binstubs.rb +57 -0
  24. data/bundler/lib/bundler/cli/cache.rb +43 -0
  25. data/bundler/lib/bundler/cli/check.rb +40 -0
  26. data/bundler/lib/bundler/cli/clean.rb +25 -0
  27. data/bundler/lib/bundler/cli/common.rb +138 -0
  28. data/bundler/lib/bundler/cli/config.rb +204 -0
  29. data/bundler/lib/bundler/cli/console.rb +44 -0
  30. data/bundler/lib/bundler/cli/doctor.rb +157 -0
  31. data/bundler/lib/bundler/cli/exec.rb +88 -0
  32. data/bundler/lib/bundler/cli/fund.rb +36 -0
  33. data/bundler/lib/bundler/cli/gem.rb +471 -0
  34. data/bundler/lib/bundler/cli/info.rb +83 -0
  35. data/bundler/lib/bundler/cli/init.rb +51 -0
  36. data/bundler/lib/bundler/cli/inject.rb +60 -0
  37. data/bundler/lib/bundler/cli/install.rb +190 -0
  38. data/bundler/lib/bundler/cli/issue.rb +41 -0
  39. data/bundler/lib/bundler/cli/list.rb +66 -0
  40. data/bundler/lib/bundler/cli/lock.rb +73 -0
  41. data/bundler/lib/bundler/cli/open.rb +29 -0
  42. data/bundler/lib/bundler/cli/outdated.rb +297 -0
  43. data/bundler/lib/bundler/cli/platform.rb +48 -0
  44. data/bundler/lib/bundler/cli/plugin.rb +34 -0
  45. data/bundler/lib/bundler/cli/pristine.rb +60 -0
  46. data/bundler/lib/bundler/cli/remove.rb +17 -0
  47. data/bundler/lib/bundler/cli/show.rb +75 -0
  48. data/bundler/lib/bundler/cli/update.rb +123 -0
  49. data/bundler/lib/bundler/cli/viz.rb +31 -0
  50. data/bundler/lib/bundler/cli.rb +846 -0
  51. data/bundler/lib/bundler/compact_index_client/cache.rb +121 -0
  52. data/bundler/lib/bundler/compact_index_client/cache_file.rb +153 -0
  53. data/bundler/lib/bundler/compact_index_client/gem_parser.rb +32 -0
  54. data/bundler/lib/bundler/compact_index_client/updater.rb +115 -0
  55. data/bundler/lib/bundler/compact_index_client.rb +126 -0
  56. data/bundler/lib/bundler/constants.rb +7 -0
  57. data/bundler/lib/bundler/current_ruby.rb +92 -0
  58. data/bundler/lib/bundler/definition.rb +1005 -0
  59. data/bundler/lib/bundler/dependency.rb +101 -0
  60. data/bundler/lib/bundler/deployment.rb +69 -0
  61. data/bundler/lib/bundler/deprecate.rb +44 -0
  62. data/bundler/lib/bundler/digest.rb +71 -0
  63. data/bundler/lib/bundler/dsl.rb +601 -0
  64. data/bundler/lib/bundler/endpoint_specification.rb +147 -0
  65. data/bundler/lib/bundler/env.rb +148 -0
  66. data/bundler/lib/bundler/environment_preserver.rb +86 -0
  67. data/bundler/lib/bundler/errors.rb +233 -0
  68. data/bundler/lib/bundler/feature_flag.rb +53 -0
  69. data/bundler/lib/bundler/fetcher/base.rb +52 -0
  70. data/bundler/lib/bundler/fetcher/compact_index.rb +129 -0
  71. data/bundler/lib/bundler/fetcher/dependency.rb +78 -0
  72. data/bundler/lib/bundler/fetcher/downloader.rb +91 -0
  73. data/bundler/lib/bundler/fetcher/gem_remote_fetcher.rb +16 -0
  74. data/bundler/lib/bundler/fetcher/index.rb +25 -0
  75. data/bundler/lib/bundler/fetcher.rb +324 -0
  76. data/bundler/lib/bundler/force_platform.rb +18 -0
  77. data/bundler/lib/bundler/friendly_errors.rb +126 -0
  78. data/bundler/lib/bundler/gem_helper.rb +237 -0
  79. data/bundler/lib/bundler/gem_helpers.rb +127 -0
  80. data/bundler/lib/bundler/gem_tasks.rb +7 -0
  81. data/bundler/lib/bundler/gem_version_promoter.rb +145 -0
  82. data/bundler/lib/bundler/graph.rb +152 -0
  83. data/bundler/lib/bundler/index.rb +205 -0
  84. data/bundler/lib/bundler/injector.rb +287 -0
  85. data/bundler/lib/bundler/inline.rb +73 -0
  86. data/bundler/lib/bundler/installer/gem_installer.rb +84 -0
  87. data/bundler/lib/bundler/installer/parallel_installer.rb +202 -0
  88. data/bundler/lib/bundler/installer/standalone.rb +116 -0
  89. data/bundler/lib/bundler/installer.rb +267 -0
  90. data/bundler/lib/bundler/lazy_specification.rb +170 -0
  91. data/bundler/lib/bundler/lockfile_generator.rb +104 -0
  92. data/bundler/lib/bundler/lockfile_parser.rb +289 -0
  93. data/bundler/lib/bundler/man/.document +1 -0
  94. data/bundler/lib/bundler/man/bundle-add.1 +59 -0
  95. data/bundler/lib/bundler/man/bundle-add.1.ronn +58 -0
  96. data/bundler/lib/bundler/man/bundle-binstubs.1 +30 -0
  97. data/bundler/lib/bundler/man/bundle-binstubs.1.ronn +41 -0
  98. data/bundler/lib/bundler/man/bundle-cache.1 +40 -0
  99. data/bundler/lib/bundler/man/bundle-cache.1.ronn +79 -0
  100. data/bundler/lib/bundler/man/bundle-check.1 +22 -0
  101. data/bundler/lib/bundler/man/bundle-check.1.ronn +26 -0
  102. data/bundler/lib/bundler/man/bundle-clean.1 +17 -0
  103. data/bundler/lib/bundler/man/bundle-clean.1.ronn +18 -0
  104. data/bundler/lib/bundler/man/bundle-config.1 +321 -0
  105. data/bundler/lib/bundler/man/bundle-config.1.ronn +411 -0
  106. data/bundler/lib/bundler/man/bundle-console.1 +35 -0
  107. data/bundler/lib/bundler/man/bundle-console.1.ronn +44 -0
  108. data/bundler/lib/bundler/man/bundle-doctor.1 +30 -0
  109. data/bundler/lib/bundler/man/bundle-doctor.1.ronn +33 -0
  110. data/bundler/lib/bundler/man/bundle-exec.1 +104 -0
  111. data/bundler/lib/bundler/man/bundle-exec.1.ronn +151 -0
  112. data/bundler/lib/bundler/man/bundle-gem.1 +69 -0
  113. data/bundler/lib/bundler/man/bundle-gem.1.ronn +117 -0
  114. data/bundler/lib/bundler/man/bundle-help.1 +9 -0
  115. data/bundler/lib/bundler/man/bundle-help.1.ronn +12 -0
  116. data/bundler/lib/bundler/man/bundle-info.1 +14 -0
  117. data/bundler/lib/bundler/man/bundle-info.1.ronn +17 -0
  118. data/bundler/lib/bundler/man/bundle-init.1 +20 -0
  119. data/bundler/lib/bundler/man/bundle-init.1.ronn +31 -0
  120. data/bundler/lib/bundler/man/bundle-inject.1 +23 -0
  121. data/bundler/lib/bundler/man/bundle-inject.1.ronn +24 -0
  122. data/bundler/lib/bundler/man/bundle-install.1 +215 -0
  123. data/bundler/lib/bundler/man/bundle-install.1.ronn +383 -0
  124. data/bundler/lib/bundler/man/bundle-list.1 +35 -0
  125. data/bundler/lib/bundler/man/bundle-list.1.ronn +33 -0
  126. data/bundler/lib/bundler/man/bundle-lock.1 +60 -0
  127. data/bundler/lib/bundler/man/bundle-lock.1.ronn +94 -0
  128. data/bundler/lib/bundler/man/bundle-open.1 +32 -0
  129. data/bundler/lib/bundler/man/bundle-open.1.ronn +27 -0
  130. data/bundler/lib/bundler/man/bundle-outdated.1 +100 -0
  131. data/bundler/lib/bundler/man/bundle-outdated.1.ronn +106 -0
  132. data/bundler/lib/bundler/man/bundle-platform.1 +49 -0
  133. data/bundler/lib/bundler/man/bundle-platform.1.ronn +49 -0
  134. data/bundler/lib/bundler/man/bundle-plugin.1 +55 -0
  135. data/bundler/lib/bundler/man/bundle-plugin.1.ronn +59 -0
  136. data/bundler/lib/bundler/man/bundle-pristine.1 +23 -0
  137. data/bundler/lib/bundler/man/bundle-pristine.1.ronn +34 -0
  138. data/bundler/lib/bundler/man/bundle-remove.1 +21 -0
  139. data/bundler/lib/bundler/man/bundle-remove.1.ronn +23 -0
  140. data/bundler/lib/bundler/man/bundle-show.1 +16 -0
  141. data/bundler/lib/bundler/man/bundle-show.1.ronn +21 -0
  142. data/bundler/lib/bundler/man/bundle-update.1 +275 -0
  143. data/bundler/lib/bundler/man/bundle-update.1.ronn +351 -0
  144. data/bundler/lib/bundler/man/bundle-version.1 +22 -0
  145. data/bundler/lib/bundler/man/bundle-version.1.ronn +24 -0
  146. data/bundler/lib/bundler/man/bundle-viz.1 +30 -0
  147. data/bundler/lib/bundler/man/bundle-viz.1.ronn +32 -0
  148. data/bundler/lib/bundler/man/bundle.1 +102 -0
  149. data/bundler/lib/bundler/man/bundle.1.ronn +116 -0
  150. data/bundler/lib/bundler/man/gemfile.5 +470 -0
  151. data/bundler/lib/bundler/man/gemfile.5.ronn +552 -0
  152. data/bundler/lib/bundler/man/index.txt +29 -0
  153. data/bundler/lib/bundler/match_metadata.rb +17 -0
  154. data/bundler/lib/bundler/match_platform.rb +23 -0
  155. data/bundler/lib/bundler/match_remote_metadata.rb +29 -0
  156. data/bundler/lib/bundler/mirror.rb +221 -0
  157. data/bundler/lib/bundler/plugin/api/source.rb +321 -0
  158. data/bundler/lib/bundler/plugin/api.rb +81 -0
  159. data/bundler/lib/bundler/plugin/dsl.rb +53 -0
  160. data/bundler/lib/bundler/plugin/events.rb +61 -0
  161. data/bundler/lib/bundler/plugin/index.rb +193 -0
  162. data/bundler/lib/bundler/plugin/installer/git.rb +34 -0
  163. data/bundler/lib/bundler/plugin/installer/rubygems.rb +19 -0
  164. data/bundler/lib/bundler/plugin/installer.rb +112 -0
  165. data/bundler/lib/bundler/plugin/source_list.rb +31 -0
  166. data/bundler/lib/bundler/plugin.rb +359 -0
  167. data/bundler/lib/bundler/process_lock.rb +24 -0
  168. data/bundler/lib/bundler/remote_specification.rb +117 -0
  169. data/bundler/lib/bundler/resolver/base.rb +107 -0
  170. data/bundler/lib/bundler/resolver/candidate.rb +94 -0
  171. data/bundler/lib/bundler/resolver/incompatibility.rb +15 -0
  172. data/bundler/lib/bundler/resolver/package.rb +77 -0
  173. data/bundler/lib/bundler/resolver/root.rb +25 -0
  174. data/bundler/lib/bundler/resolver/spec_group.rb +79 -0
  175. data/bundler/lib/bundler/resolver.rb +462 -0
  176. data/bundler/lib/bundler/retry.rb +66 -0
  177. data/bundler/lib/bundler/ruby_dsl.rb +53 -0
  178. data/bundler/lib/bundler/ruby_version.rb +131 -0
  179. data/bundler/lib/bundler/rubygems_ext.rb +328 -0
  180. data/bundler/lib/bundler/rubygems_gem_installer.rb +137 -0
  181. data/bundler/lib/bundler/rubygems_integration.rb +493 -0
  182. data/bundler/lib/bundler/runtime.rb +307 -0
  183. data/bundler/lib/bundler/safe_marshal.rb +31 -0
  184. data/bundler/lib/bundler/self_manager.rb +186 -0
  185. data/bundler/lib/bundler/settings/validator.rb +102 -0
  186. data/bundler/lib/bundler/settings.rb +588 -0
  187. data/bundler/lib/bundler/setup.rb +33 -0
  188. data/bundler/lib/bundler/shared_helpers.rb +380 -0
  189. data/bundler/lib/bundler/similarity_detector.rb +63 -0
  190. data/bundler/lib/bundler/source/gemspec.rb +18 -0
  191. data/bundler/lib/bundler/source/git/git_proxy.rb +455 -0
  192. data/bundler/lib/bundler/source/git.rb +380 -0
  193. data/bundler/lib/bundler/source/metadata.rb +62 -0
  194. data/bundler/lib/bundler/source/path/installer.rb +53 -0
  195. data/bundler/lib/bundler/source/path.rb +261 -0
  196. data/bundler/lib/bundler/source/rubygems/remote.rb +68 -0
  197. data/bundler/lib/bundler/source/rubygems.rb +516 -0
  198. data/bundler/lib/bundler/source/rubygems_aggregate.rb +68 -0
  199. data/bundler/lib/bundler/source.rb +116 -0
  200. data/bundler/lib/bundler/source_list.rb +227 -0
  201. data/bundler/lib/bundler/source_map.rb +71 -0
  202. data/bundler/lib/bundler/spec_set.rb +247 -0
  203. data/bundler/lib/bundler/stub_specification.rb +119 -0
  204. data/bundler/lib/bundler/templates/.document +1 -0
  205. data/bundler/lib/bundler/templates/Executable +27 -0
  206. data/bundler/lib/bundler/templates/Executable.bundler +109 -0
  207. data/bundler/lib/bundler/templates/Executable.standalone +14 -0
  208. data/bundler/lib/bundler/templates/Gemfile +5 -0
  209. data/bundler/lib/bundler/templates/newgem/CHANGELOG.md.tt +5 -0
  210. data/bundler/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +84 -0
  211. data/bundler/lib/bundler/templates/newgem/Cargo.toml.tt +7 -0
  212. data/bundler/lib/bundler/templates/newgem/Gemfile.tt +26 -0
  213. data/bundler/lib/bundler/templates/newgem/LICENSE.txt.tt +21 -0
  214. data/bundler/lib/bundler/templates/newgem/README.md.tt +45 -0
  215. data/bundler/lib/bundler/templates/newgem/Rakefile.tt +67 -0
  216. data/bundler/lib/bundler/templates/newgem/bin/console.tt +11 -0
  217. data/bundler/lib/bundler/templates/newgem/bin/setup.tt +8 -0
  218. data/bundler/lib/bundler/templates/newgem/circleci/config.yml.tt +25 -0
  219. data/bundler/lib/bundler/templates/newgem/exe/newgem.tt +3 -0
  220. data/bundler/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +15 -0
  221. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +10 -0
  222. data/bundler/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt +6 -0
  223. data/bundler/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +9 -0
  224. data/bundler/lib/bundler/templates/newgem/ext/newgem/newgem.h.tt +6 -0
  225. data/bundler/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +12 -0
  226. data/bundler/lib/bundler/templates/newgem/github/workflows/main.yml.tt +37 -0
  227. data/bundler/lib/bundler/templates/newgem/gitignore.tt +23 -0
  228. data/bundler/lib/bundler/templates/newgem/gitlab-ci.yml.tt +18 -0
  229. data/bundler/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +9 -0
  230. data/bundler/lib/bundler/templates/newgem/lib/newgem.rb.tt +15 -0
  231. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +51 -0
  232. data/bundler/lib/bundler/templates/newgem/rspec.tt +3 -0
  233. data/bundler/lib/bundler/templates/newgem/rubocop.yml.tt +13 -0
  234. data/bundler/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  235. data/bundler/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +11 -0
  236. data/bundler/lib/bundler/templates/newgem/spec/spec_helper.rb.tt +15 -0
  237. data/bundler/lib/bundler/templates/newgem/standard.yml.tt +3 -0
  238. data/bundler/lib/bundler/templates/newgem/test/minitest/test_helper.rb.tt +6 -0
  239. data/bundler/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +13 -0
  240. data/bundler/lib/bundler/templates/newgem/test/test-unit/newgem_test.rb.tt +15 -0
  241. data/bundler/lib/bundler/templates/newgem/test/test-unit/test_helper.rb.tt +6 -0
  242. data/bundler/lib/bundler/ui/rg_proxy.rb +19 -0
  243. data/bundler/lib/bundler/ui/shell.rb +165 -0
  244. data/bundler/lib/bundler/ui/silent.rb +85 -0
  245. data/bundler/lib/bundler/ui.rb +9 -0
  246. data/bundler/lib/bundler/uri_credentials_filter.rb +43 -0
  247. data/bundler/lib/bundler/uri_normalizer.rb +23 -0
  248. data/bundler/lib/bundler/vendor/.document +1 -0
  249. data/bundler/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  250. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +174 -0
  251. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +3 -0
  252. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +56 -0
  253. data/bundler/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +175 -0
  254. data/bundler/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  255. data/bundler/lib/bundler/vendor/fileutils/lib/fileutils.rb +2694 -0
  256. data/bundler/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  257. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +41 -0
  258. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +65 -0
  259. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +79 -0
  260. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1073 -0
  261. data/bundler/lib/bundler/vendor/pub_grub/LICENSE.txt +21 -0
  262. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
  263. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +189 -0
  264. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
  265. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb +150 -0
  266. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/package.rb +43 -0
  267. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
  268. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
  269. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/solve_failure.rb +19 -0
  270. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb +60 -0
  271. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
  272. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
  273. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb +129 -0
  274. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb +411 -0
  275. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +248 -0
  276. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub/version_union.rb +178 -0
  277. data/bundler/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +31 -0
  278. data/bundler/lib/bundler/vendor/thor/LICENSE.md +20 -0
  279. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +105 -0
  280. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/create_link.rb +61 -0
  281. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +108 -0
  282. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +143 -0
  283. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +373 -0
  284. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +130 -0
  285. data/bundler/lib/bundler/vendor/thor/lib/thor/actions.rb +340 -0
  286. data/bundler/lib/bundler/vendor/thor/lib/thor/base.rb +825 -0
  287. data/bundler/lib/bundler/vendor/thor/lib/thor/command.rb +151 -0
  288. data/bundler/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +107 -0
  289. data/bundler/lib/bundler/vendor/thor/lib/thor/error.rb +106 -0
  290. data/bundler/lib/bundler/vendor/thor/lib/thor/group.rb +281 -0
  291. data/bundler/lib/bundler/vendor/thor/lib/thor/invocation.rb +178 -0
  292. data/bundler/lib/bundler/vendor/thor/lib/thor/line_editor/basic.rb +37 -0
  293. data/bundler/lib/bundler/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  294. data/bundler/lib/bundler/vendor/thor/lib/thor/line_editor.rb +17 -0
  295. data/bundler/lib/bundler/vendor/thor/lib/thor/nested_context.rb +29 -0
  296. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +89 -0
  297. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +195 -0
  298. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/option.rb +178 -0
  299. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/options.rb +293 -0
  300. data/bundler/lib/bundler/vendor/thor/lib/thor/parser.rb +4 -0
  301. data/bundler/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +72 -0
  302. data/bundler/lib/bundler/vendor/thor/lib/thor/runner.rb +335 -0
  303. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +388 -0
  304. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/color.rb +115 -0
  305. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb +29 -0
  306. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/html.rb +84 -0
  307. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb +49 -0
  308. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +134 -0
  309. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb +42 -0
  310. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb +38 -0
  311. data/bundler/lib/bundler/vendor/thor/lib/thor/shell.rb +81 -0
  312. data/bundler/lib/bundler/vendor/thor/lib/thor/util.rb +285 -0
  313. data/bundler/lib/bundler/vendor/thor/lib/thor/version.rb +3 -0
  314. data/bundler/lib/bundler/vendor/thor/lib/thor.rb +663 -0
  315. data/bundler/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  316. data/bundler/lib/bundler/vendor/tsort/lib/tsort.rb +455 -0
  317. data/bundler/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  318. data/bundler/lib/bundler/vendor/uri/lib/uri/common.rb +853 -0
  319. data/bundler/lib/bundler/vendor/uri/lib/uri/file.rb +100 -0
  320. data/bundler/lib/bundler/vendor/uri/lib/uri/ftp.rb +267 -0
  321. data/bundler/lib/bundler/vendor/uri/lib/uri/generic.rb +1588 -0
  322. data/bundler/lib/bundler/vendor/uri/lib/uri/http.rb +125 -0
  323. data/bundler/lib/bundler/vendor/uri/lib/uri/https.rb +23 -0
  324. data/bundler/lib/bundler/vendor/uri/lib/uri/ldap.rb +261 -0
  325. data/bundler/lib/bundler/vendor/uri/lib/uri/ldaps.rb +22 -0
  326. data/bundler/lib/bundler/vendor/uri/lib/uri/mailto.rb +293 -0
  327. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +539 -0
  328. data/bundler/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +183 -0
  329. data/bundler/lib/bundler/vendor/uri/lib/uri/version.rb +6 -0
  330. data/bundler/lib/bundler/vendor/uri/lib/uri/ws.rb +83 -0
  331. data/bundler/lib/bundler/vendor/uri/lib/uri/wss.rb +23 -0
  332. data/bundler/lib/bundler/vendor/uri/lib/uri.rb +104 -0
  333. data/bundler/lib/bundler/vendored_fileutils.rb +4 -0
  334. data/bundler/lib/bundler/vendored_net_http.rb +8 -0
  335. data/bundler/lib/bundler/vendored_persistent.rb +11 -0
  336. data/bundler/lib/bundler/vendored_pub_grub.rb +4 -0
  337. data/bundler/lib/bundler/vendored_thor.rb +8 -0
  338. data/bundler/lib/bundler/vendored_timeout.rb +8 -0
  339. data/bundler/lib/bundler/vendored_tsort.rb +4 -0
  340. data/bundler/lib/bundler/vendored_uri.rb +4 -0
  341. data/bundler/lib/bundler/version.rb +13 -0
  342. data/bundler/lib/bundler/vlad.rb +17 -0
  343. data/bundler/lib/bundler/worker.rb +117 -0
  344. data/bundler/lib/bundler/yaml_serializer.rb +93 -0
  345. data/bundler/lib/bundler.rb +665 -0
  346. data/{test/rubygems/bogussources.rb → exe/gem} +5 -2
  347. data/exe/update_rubygems +38 -0
  348. data/hide_lib_for_update/note.txt +0 -4
  349. data/lib/rubygems/available_set.rb +12 -12
  350. data/lib/rubygems/basic_specification.rb +75 -58
  351. data/lib/rubygems/bundler_version_finder.rb +77 -0
  352. data/lib/rubygems/ci_detector.rb +75 -0
  353. data/lib/rubygems/command.rb +144 -71
  354. data/lib/rubygems/command_manager.rb +64 -27
  355. data/lib/rubygems/commands/build_command.rb +88 -17
  356. data/lib/rubygems/commands/cert_command.rb +131 -83
  357. data/lib/rubygems/commands/check_command.rb +30 -27
  358. data/lib/rubygems/commands/cleanup_command.rb +57 -40
  359. data/lib/rubygems/commands/contents_command.rb +37 -39
  360. data/lib/rubygems/commands/dependency_command.rb +53 -65
  361. data/lib/rubygems/commands/environment_command.rb +32 -16
  362. data/lib/rubygems/commands/exec_command.rb +249 -0
  363. data/lib/rubygems/commands/fetch_command.rb +36 -19
  364. data/lib/rubygems/commands/generate_index_command.rb +40 -74
  365. data/lib/rubygems/commands/help_command.rb +22 -22
  366. data/lib/rubygems/commands/info_command.rb +38 -0
  367. data/lib/rubygems/commands/install_command.rb +67 -143
  368. data/lib/rubygems/commands/list_command.rb +10 -9
  369. data/lib/rubygems/commands/lock_command.rb +12 -14
  370. data/lib/rubygems/commands/mirror_command.rb +4 -4
  371. data/lib/rubygems/commands/open_command.rb +28 -26
  372. data/lib/rubygems/commands/outdated_command.rb +6 -6
  373. data/lib/rubygems/commands/owner_command.rb +51 -27
  374. data/lib/rubygems/commands/pristine_command.rb +99 -71
  375. data/lib/rubygems/commands/push_command.rb +53 -46
  376. data/lib/rubygems/commands/query_command.rb +21 -328
  377. data/lib/rubygems/commands/rdoc_command.rb +33 -33
  378. data/lib/rubygems/commands/search_command.rb +9 -9
  379. data/lib/rubygems/commands/server_command.rb +15 -76
  380. data/lib/rubygems/commands/setup_command.rb +370 -186
  381. data/lib/rubygems/commands/signin_command.rb +34 -0
  382. data/lib/rubygems/commands/signout_command.rb +32 -0
  383. data/lib/rubygems/commands/sources_command.rb +57 -41
  384. data/lib/rubygems/commands/specification_command.rb +38 -28
  385. data/lib/rubygems/commands/stale_command.rb +6 -5
  386. data/lib/rubygems/commands/uninstall_command.rb +96 -62
  387. data/lib/rubygems/commands/unpack_command.rb +44 -53
  388. data/lib/rubygems/commands/update_command.rb +155 -99
  389. data/lib/rubygems/commands/which_command.rb +14 -17
  390. data/lib/rubygems/commands/yank_command.rb +28 -32
  391. data/lib/rubygems/compatibility.rb +13 -32
  392. data/lib/rubygems/config_file.rb +214 -119
  393. data/lib/rubygems/core_ext/kernel_gem.rb +10 -16
  394. data/lib/rubygems/core_ext/kernel_require.rb +92 -90
  395. data/lib/rubygems/core_ext/kernel_warn.rb +49 -0
  396. data/lib/rubygems/core_ext/tcpsocket_init.rb +54 -0
  397. data/lib/rubygems/defaults.rb +184 -54
  398. data/lib/rubygems/dependency.rb +75 -62
  399. data/lib/rubygems/dependency_installer.rb +74 -230
  400. data/lib/rubygems/dependency_list.rb +32 -33
  401. data/lib/rubygems/deprecate.rb +113 -17
  402. data/lib/rubygems/doctor.rb +31 -31
  403. data/lib/rubygems/errors.rb +51 -13
  404. data/lib/rubygems/exceptions.rb +65 -35
  405. data/lib/rubygems/ext/build_error.rb +3 -1
  406. data/lib/rubygems/ext/builder.rb +103 -77
  407. data/lib/rubygems/ext/cargo_builder/link_flag_converter.rb +27 -0
  408. data/lib/rubygems/ext/cargo_builder.rb +360 -0
  409. data/lib/rubygems/ext/cmake_builder.rb +6 -7
  410. data/lib/rubygems/ext/configure_builder.rb +6 -9
  411. data/lib/rubygems/ext/ext_conf_builder.rb +40 -61
  412. data/lib/rubygems/ext/rake_builder.rb +18 -21
  413. data/lib/rubygems/ext.rb +8 -7
  414. data/lib/rubygems/gem_runner.rb +19 -21
  415. data/lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb +163 -0
  416. data/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +105 -0
  417. data/lib/rubygems/gemcutter_utilities/webauthn_poller.rb +78 -0
  418. data/lib/rubygems/gemcutter_utilities.rb +246 -43
  419. data/lib/rubygems/install_default_message.rb +3 -3
  420. data/lib/rubygems/install_message.rb +3 -3
  421. data/lib/rubygems/install_update_options.rb +104 -98
  422. data/lib/rubygems/installer.rb +407 -225
  423. data/lib/rubygems/installer_uninstaller_utils.rb +27 -0
  424. data/lib/rubygems/local_remote_options.rb +29 -32
  425. data/lib/rubygems/name_tuple.rb +18 -23
  426. data/lib/rubygems/net/http.rb +3 -0
  427. data/lib/rubygems/net-http/LICENSE.txt +22 -0
  428. data/lib/rubygems/net-http/lib/net/http/backward.rb +40 -0
  429. data/lib/rubygems/net-http/lib/net/http/exceptions.rb +34 -0
  430. data/lib/rubygems/net-http/lib/net/http/generic_request.rb +414 -0
  431. data/lib/rubygems/net-http/lib/net/http/header.rb +981 -0
  432. data/lib/rubygems/net-http/lib/net/http/proxy_delta.rb +17 -0
  433. data/lib/rubygems/net-http/lib/net/http/request.rb +88 -0
  434. data/lib/rubygems/net-http/lib/net/http/requests.rb +425 -0
  435. data/lib/rubygems/net-http/lib/net/http/response.rb +738 -0
  436. data/lib/rubygems/net-http/lib/net/http/responses.rb +1174 -0
  437. data/lib/rubygems/net-http/lib/net/http/status.rb +84 -0
  438. data/lib/rubygems/net-http/lib/net/http.rb +2496 -0
  439. data/lib/rubygems/net-http/lib/net/https.rb +23 -0
  440. data/lib/rubygems/net-protocol/LICENSE.txt +22 -0
  441. data/lib/rubygems/net-protocol/lib/net/protocol.rb +544 -0
  442. data/lib/rubygems/openssl.rb +7 -0
  443. data/lib/rubygems/optparse/.document +1 -0
  444. data/lib/rubygems/optparse/COPYING +56 -0
  445. data/lib/rubygems/optparse/lib/optionparser.rb +2 -0
  446. data/lib/rubygems/optparse/lib/optparse/ac.rb +54 -0
  447. data/lib/rubygems/optparse/lib/optparse/date.rb +18 -0
  448. data/lib/rubygems/optparse/lib/optparse/kwargs.rb +22 -0
  449. data/lib/rubygems/optparse/lib/optparse/shellwords.rb +7 -0
  450. data/lib/rubygems/optparse/lib/optparse/time.rb +11 -0
  451. data/lib/rubygems/optparse/lib/optparse/uri.rb +7 -0
  452. data/lib/rubygems/optparse/lib/optparse/version.rb +71 -0
  453. data/lib/rubygems/optparse/lib/optparse.rb +2330 -0
  454. data/lib/rubygems/optparse.rb +3 -0
  455. data/lib/rubygems/package/digest_io.rb +5 -7
  456. data/lib/rubygems/package/file_source.rb +6 -8
  457. data/lib/rubygems/package/io_source.rb +6 -4
  458. data/lib/rubygems/package/old.rb +19 -28
  459. data/lib/rubygems/package/source.rb +1 -1
  460. data/lib/rubygems/package/tar_header.rb +114 -93
  461. data/lib/rubygems/package/tar_reader/entry.rb +116 -22
  462. data/lib/rubygems/package/tar_reader.rb +18 -40
  463. data/lib/rubygems/package/tar_writer.rb +42 -56
  464. data/lib/rubygems/package.rb +245 -145
  465. data/lib/rubygems/package_task.rb +8 -14
  466. data/lib/rubygems/path_support.rb +21 -16
  467. data/lib/rubygems/platform.rb +135 -74
  468. data/lib/rubygems/psych_tree.rb +3 -2
  469. data/lib/rubygems/query_utils.rb +349 -0
  470. data/lib/rubygems/rdoc.rb +4 -326
  471. data/lib/rubygems/remote_fetcher.rb +99 -181
  472. data/lib/rubygems/request/connection_pools.rb +31 -24
  473. data/lib/rubygems/request/http_pool.rb +6 -7
  474. data/lib/rubygems/request/https_pool.rb +2 -3
  475. data/lib/rubygems/request.rb +103 -53
  476. data/lib/rubygems/request_set/gem_dependency_api.rb +182 -190
  477. data/lib/rubygems/request_set/lockfile/parser.rb +42 -52
  478. data/lib/rubygems/request_set/lockfile/tokenizer.rb +34 -24
  479. data/lib/rubygems/request_set/lockfile.rb +32 -35
  480. data/lib/rubygems/request_set.rb +115 -71
  481. data/lib/rubygems/requirement.rb +77 -68
  482. data/lib/rubygems/resolv/LICENSE.txt +22 -0
  483. data/lib/rubygems/resolv/lib/resolv.rb +3387 -0
  484. data/lib/rubygems/resolver/activation_request.rb +34 -61
  485. data/lib/rubygems/resolver/api_set/gem_parser.rb +24 -0
  486. data/lib/rubygems/resolver/api_set.rb +40 -32
  487. data/lib/rubygems/resolver/api_specification.rb +37 -18
  488. data/lib/rubygems/resolver/best_set.rb +15 -17
  489. data/lib/rubygems/resolver/composed_set.rb +9 -11
  490. data/lib/rubygems/resolver/conflict.rb +19 -33
  491. data/lib/rubygems/resolver/current_set.rb +2 -4
  492. data/lib/rubygems/resolver/dependency_request.rb +8 -9
  493. data/lib/rubygems/resolver/git_set.rb +8 -10
  494. data/lib/rubygems/resolver/git_specification.rb +11 -13
  495. data/lib/rubygems/resolver/index_set.rb +13 -15
  496. data/lib/rubygems/resolver/index_specification.rb +42 -11
  497. data/lib/rubygems/resolver/installed_specification.rb +9 -11
  498. data/lib/rubygems/resolver/installer_set.rb +87 -45
  499. data/lib/rubygems/resolver/local_specification.rb +5 -7
  500. data/lib/rubygems/resolver/lock_set.rb +13 -15
  501. data/lib/rubygems/resolver/lock_specification.rb +13 -15
  502. data/lib/rubygems/resolver/molinillo/LICENSE +9 -0
  503. data/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/resolution_state.rb +57 -0
  504. data/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb +88 -0
  505. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/action.rb +36 -0
  506. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +66 -0
  507. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +62 -0
  508. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +63 -0
  509. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +61 -0
  510. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/log.rb +126 -0
  511. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/set_payload.rb +46 -0
  512. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/tag.rb +36 -0
  513. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb +164 -0
  514. data/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +110 -146
  515. data/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb +83 -9
  516. data/lib/rubygems/resolver/molinillo/lib/molinillo/gem_metadata.rb +2 -1
  517. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb +13 -1
  518. data/lib/rubygems/resolver/molinillo/lib/molinillo/modules/ui.rb +3 -1
  519. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +552 -172
  520. data/lib/rubygems/resolver/molinillo/lib/molinillo/resolver.rb +3 -2
  521. data/lib/rubygems/resolver/molinillo/lib/molinillo/state.rb +12 -6
  522. data/lib/rubygems/resolver/molinillo/lib/molinillo.rb +6 -5
  523. data/lib/rubygems/resolver/molinillo.rb +2 -1
  524. data/lib/rubygems/resolver/requirement_list.rb +2 -2
  525. data/lib/rubygems/resolver/set.rb +3 -5
  526. data/lib/rubygems/resolver/source_set.rb +6 -7
  527. data/lib/rubygems/resolver/spec_specification.rb +16 -4
  528. data/lib/rubygems/resolver/specification.rb +25 -10
  529. data/lib/rubygems/resolver/stats.rb +1 -0
  530. data/lib/rubygems/resolver/vendor_set.rb +6 -8
  531. data/lib/rubygems/resolver/vendor_specification.rb +6 -8
  532. data/lib/rubygems/resolver.rb +121 -72
  533. data/lib/rubygems/s3_uri_signer.rb +177 -0
  534. data/lib/rubygems/safe_marshal/elements.rb +138 -0
  535. data/lib/rubygems/safe_marshal/reader.rb +306 -0
  536. data/lib/rubygems/safe_marshal/visitors/stream_printer.rb +31 -0
  537. data/lib/rubygems/safe_marshal/visitors/to_ruby.rb +385 -0
  538. data/lib/rubygems/safe_marshal/visitors/visitor.rb +74 -0
  539. data/lib/rubygems/safe_marshal.rb +74 -0
  540. data/lib/rubygems/safe_yaml.rb +36 -0
  541. data/lib/rubygems/security/policies.rb +49 -51
  542. data/lib/rubygems/security/policy.rb +46 -53
  543. data/lib/rubygems/security/signer.rb +86 -29
  544. data/lib/rubygems/security/trust_dir.rb +22 -24
  545. data/lib/rubygems/security.rb +101 -82
  546. data/lib/rubygems/security_option.rb +43 -0
  547. data/lib/rubygems/shellwords.rb +3 -0
  548. data/lib/rubygems/source/git.rb +40 -42
  549. data/lib/rubygems/source/installed.rb +5 -9
  550. data/lib/rubygems/source/local.rb +30 -33
  551. data/lib/rubygems/source/lock.rb +10 -10
  552. data/lib/rubygems/source/specific_file.rb +7 -9
  553. data/lib/rubygems/source/vendor.rb +3 -7
  554. data/lib/rubygems/source.rb +78 -68
  555. data/lib/rubygems/source_list.rb +11 -15
  556. data/lib/rubygems/spec_fetcher.rb +71 -83
  557. data/lib/rubygems/specification.rb +833 -1115
  558. data/lib/rubygems/specification_policy.rb +538 -0
  559. data/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem +21 -0
  560. data/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem +21 -0
  561. data/lib/rubygems/stub_specification.rb +55 -57
  562. data/lib/rubygems/text.rb +39 -27
  563. data/lib/rubygems/timeout/LICENSE.txt +22 -0
  564. data/lib/rubygems/timeout/lib/timeout.rb +199 -0
  565. data/lib/rubygems/timeout.rb +3 -0
  566. data/lib/rubygems/tsort/.document +1 -0
  567. data/lib/rubygems/tsort/LICENSE.txt +22 -0
  568. data/lib/rubygems/tsort/lib/tsort.rb +455 -0
  569. data/lib/rubygems/tsort.rb +3 -0
  570. data/lib/rubygems/uninstaller.rb +150 -87
  571. data/lib/rubygems/unknown_command_spell_checker.rb +21 -0
  572. data/lib/rubygems/update_suggestion.rb +56 -0
  573. data/lib/rubygems/uri.rb +126 -0
  574. data/lib/rubygems/uri_formatter.rb +4 -7
  575. data/lib/rubygems/user_interaction.rb +92 -146
  576. data/lib/rubygems/util/licenses.rb +712 -317
  577. data/lib/rubygems/util/list.rb +5 -2
  578. data/lib/rubygems/util.rb +58 -75
  579. data/lib/rubygems/validator.rb +26 -48
  580. data/lib/rubygems/version.rb +106 -56
  581. data/lib/rubygems/version_option.rb +22 -14
  582. data/lib/rubygems/yaml_serializer.rb +93 -0
  583. data/lib/rubygems.rb +427 -361
  584. data/rubygems-update.gemspec +38 -0
  585. data/setup.rb +13 -27
  586. metadata +500 -363
  587. data/.autotest +0 -71
  588. data/.document +0 -5
  589. data/.travis.yml +0 -46
  590. data/CONTRIBUTING.rdoc +0 -129
  591. data/CVE-2013-4287.txt +0 -35
  592. data/CVE-2013-4363.txt +0 -45
  593. data/CVE-2015-3900.txt +0 -40
  594. data/History.txt +0 -3105
  595. data/MAINTAINERS.md +0 -5
  596. data/POLICIES.rdoc +0 -61
  597. data/README.rdoc +0 -54
  598. data/Rakefile +0 -449
  599. data/UPGRADING.rdoc +0 -92
  600. data/appveyor.yml +0 -36
  601. data/bin/gem +0 -25
  602. data/bin/update_rubygems +0 -37
  603. data/lib/gauntlet_rubygems.rb +0 -51
  604. data/lib/rubygems/indexer.rb +0 -434
  605. data/lib/rubygems/installer_test_case.rb +0 -194
  606. data/lib/rubygems/mock_gem_ui.rb +0 -89
  607. data/lib/rubygems/package/tar_test_case.rb +0 -147
  608. data/lib/rubygems/psych_additions.rb +0 -10
  609. data/lib/rubygems/server.rb +0 -869
  610. data/lib/rubygems/source_local.rb +0 -6
  611. data/lib/rubygems/source_specific_file.rb +0 -5
  612. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot-2048.pem +0 -25
  613. data/lib/rubygems/ssl_certs/AddTrustExternalCARoot.pem +0 -32
  614. data/lib/rubygems/ssl_certs/Class3PublicPrimaryCertificationAuthority.pem +0 -14
  615. data/lib/rubygems/ssl_certs/DigiCertHighAssuranceEVRootCA.pem +0 -23
  616. data/lib/rubygems/ssl_certs/EntrustnetSecureServerCertificationAuthority.pem +0 -28
  617. data/lib/rubygems/ssl_certs/GeoTrustGlobalCA.pem +0 -20
  618. data/lib/rubygems/syck_hack.rb +0 -77
  619. data/lib/rubygems/test_case.rb +0 -1496
  620. data/lib/rubygems/test_utilities.rb +0 -384
  621. data/lib/ubygems.rb +0 -11
  622. data/test/rubygems/alternate_cert.pem +0 -18
  623. data/test/rubygems/alternate_cert_32.pem +0 -18
  624. data/test/rubygems/alternate_key.pem +0 -27
  625. data/test/rubygems/bad_rake.rb +0 -2
  626. data/test/rubygems/ca_cert.pem +0 -68
  627. data/test/rubygems/child_cert.pem +0 -18
  628. data/test/rubygems/child_cert_32.pem +0 -18
  629. data/test/rubygems/child_key.pem +0 -27
  630. data/test/rubygems/client.pem +0 -49
  631. data/test/rubygems/data/gem-private_key.pem +0 -27
  632. data/test/rubygems/data/gem-public_cert.pem +0 -20
  633. data/test/rubygems/data/null-type.gemspec.rz +0 -0
  634. data/test/rubygems/encrypted_private_key.pem +0 -30
  635. data/test/rubygems/expired_cert.pem +0 -18
  636. data/test/rubygems/fake_certlib/openssl.rb +0 -8
  637. data/test/rubygems/fix_openssl_warnings.rb +0 -13
  638. data/test/rubygems/foo/discover.rb +0 -1
  639. data/test/rubygems/future_cert.pem +0 -18
  640. data/test/rubygems/future_cert_32.pem +0 -18
  641. data/test/rubygems/good_rake.rb +0 -2
  642. data/test/rubygems/grandchild_cert.pem +0 -18
  643. data/test/rubygems/grandchild_cert_32.pem +0 -18
  644. data/test/rubygems/grandchild_key.pem +0 -27
  645. data/test/rubygems/invalid_client.pem +0 -49
  646. data/test/rubygems/invalid_issuer_cert.pem +0 -18
  647. data/test/rubygems/invalid_issuer_cert_32.pem +0 -18
  648. data/test/rubygems/invalid_key.pem +0 -27
  649. data/test/rubygems/invalid_signer_cert.pem +0 -18
  650. data/test/rubygems/invalid_signer_cert_32.pem +0 -18
  651. data/test/rubygems/invalidchild_cert.pem +0 -18
  652. data/test/rubygems/invalidchild_cert_32.pem +0 -18
  653. data/test/rubygems/invalidchild_key.pem +0 -27
  654. data/test/rubygems/plugin/exception/rubygems_plugin.rb +0 -3
  655. data/test/rubygems/plugin/load/rubygems_plugin.rb +0 -4
  656. data/test/rubygems/plugin/standarderror/rubygems_plugin.rb +0 -3
  657. data/test/rubygems/private_key.pem +0 -27
  658. data/test/rubygems/public_cert.pem +0 -18
  659. data/test/rubygems/public_cert_32.pem +0 -18
  660. data/test/rubygems/public_key.pem +0 -9
  661. data/test/rubygems/rubygems/commands/crash_command.rb +0 -6
  662. data/test/rubygems/rubygems_plugin.rb +0 -22
  663. data/test/rubygems/sff/discover.rb +0 -1
  664. data/test/rubygems/simple_gem.rb +0 -67
  665. data/test/rubygems/specifications/bar-0.0.2.gemspec +0 -9
  666. data/test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec +0 -0
  667. data/test/rubygems/ssl_cert.pem +0 -19
  668. data/test/rubygems/ssl_key.pem +0 -15
  669. data/test/rubygems/test_bundled_ca.rb +0 -59
  670. data/test/rubygems/test_config.rb +0 -24
  671. data/test/rubygems/test_deprecate.rb +0 -77
  672. data/test/rubygems/test_gem.rb +0 -1718
  673. data/test/rubygems/test_gem_available_set.rb +0 -130
  674. data/test/rubygems/test_gem_command.rb +0 -248
  675. data/test/rubygems/test_gem_command_manager.rb +0 -264
  676. data/test/rubygems/test_gem_commands_build_command.rb +0 -121
  677. data/test/rubygems/test_gem_commands_cert_command.rb +0 -671
  678. data/test/rubygems/test_gem_commands_check_command.rb +0 -69
  679. data/test/rubygems/test_gem_commands_cleanup_command.rb +0 -197
  680. data/test/rubygems/test_gem_commands_contents_command.rb +0 -240
  681. data/test/rubygems/test_gem_commands_dependency_command.rb +0 -230
  682. data/test/rubygems/test_gem_commands_environment_command.rb +0 -154
  683. data/test/rubygems/test_gem_commands_fetch_command.rb +0 -127
  684. data/test/rubygems/test_gem_commands_generate_index_command.rb +0 -51
  685. data/test/rubygems/test_gem_commands_help_command.rb +0 -75
  686. data/test/rubygems/test_gem_commands_install_command.rb +0 -1007
  687. data/test/rubygems/test_gem_commands_list_command.rb +0 -34
  688. data/test/rubygems/test_gem_commands_lock_command.rb +0 -69
  689. data/test/rubygems/test_gem_commands_mirror.rb +0 -20
  690. data/test/rubygems/test_gem_commands_open_command.rb +0 -70
  691. data/test/rubygems/test_gem_commands_outdated_command.rb +0 -33
  692. data/test/rubygems/test_gem_commands_owner_command.rb +0 -205
  693. data/test/rubygems/test_gem_commands_pristine_command.rb +0 -491
  694. data/test/rubygems/test_gem_commands_push_command.rb +0 -330
  695. data/test/rubygems/test_gem_commands_query_command.rb +0 -657
  696. data/test/rubygems/test_gem_commands_search_command.rb +0 -18
  697. data/test/rubygems/test_gem_commands_server_command.rb +0 -60
  698. data/test/rubygems/test_gem_commands_setup_command.rb +0 -136
  699. data/test/rubygems/test_gem_commands_sources_command.rb +0 -249
  700. data/test/rubygems/test_gem_commands_specification_command.rb +0 -251
  701. data/test/rubygems/test_gem_commands_stale_command.rb +0 -43
  702. data/test/rubygems/test_gem_commands_uninstall_command.rb +0 -283
  703. data/test/rubygems/test_gem_commands_unpack_command.rb +0 -209
  704. data/test/rubygems/test_gem_commands_update_command.rb +0 -514
  705. data/test/rubygems/test_gem_commands_which_command.rb +0 -87
  706. data/test/rubygems/test_gem_commands_yank_command.rb +0 -100
  707. data/test/rubygems/test_gem_config_file.rb +0 -491
  708. data/test/rubygems/test_gem_dependency.rb +0 -362
  709. data/test/rubygems/test_gem_dependency_installer.rb +0 -1235
  710. data/test/rubygems/test_gem_dependency_list.rb +0 -260
  711. data/test/rubygems/test_gem_dependency_resolution_error.rb +0 -29
  712. data/test/rubygems/test_gem_doctor.rb +0 -169
  713. data/test/rubygems/test_gem_ext_builder.rb +0 -341
  714. data/test/rubygems/test_gem_ext_cmake_builder.rb +0 -87
  715. data/test/rubygems/test_gem_ext_configure_builder.rb +0 -87
  716. data/test/rubygems/test_gem_ext_ext_conf_builder.rb +0 -211
  717. data/test/rubygems/test_gem_ext_rake_builder.rb +0 -65
  718. data/test/rubygems/test_gem_gem_runner.rb +0 -69
  719. data/test/rubygems/test_gem_gemcutter_utilities.rb +0 -235
  720. data/test/rubygems/test_gem_impossible_dependencies_error.rb +0 -62
  721. data/test/rubygems/test_gem_indexer.rb +0 -367
  722. data/test/rubygems/test_gem_install_update_options.rb +0 -197
  723. data/test/rubygems/test_gem_installer.rb +0 -1552
  724. data/test/rubygems/test_gem_local_remote_options.rb +0 -134
  725. data/test/rubygems/test_gem_name_tuple.rb +0 -45
  726. data/test/rubygems/test_gem_package.rb +0 -876
  727. data/test/rubygems/test_gem_package_old.rb +0 -90
  728. data/test/rubygems/test_gem_package_tar_header.rb +0 -147
  729. data/test/rubygems/test_gem_package_tar_reader.rb +0 -90
  730. data/test/rubygems/test_gem_package_tar_reader_entry.rb +0 -142
  731. data/test/rubygems/test_gem_package_tar_writer.rb +0 -264
  732. data/test/rubygems/test_gem_package_task.rb +0 -84
  733. data/test/rubygems/test_gem_path_support.rb +0 -121
  734. data/test/rubygems/test_gem_platform.rb +0 -308
  735. data/test/rubygems/test_gem_rdoc.rb +0 -270
  736. data/test/rubygems/test_gem_remote_fetcher.rb +0 -1051
  737. data/test/rubygems/test_gem_request.rb +0 -363
  738. data/test/rubygems/test_gem_request_connection_pools.rb +0 -130
  739. data/test/rubygems/test_gem_request_set.rb +0 -595
  740. data/test/rubygems/test_gem_request_set_gem_dependency_api.rb +0 -831
  741. data/test/rubygems/test_gem_request_set_lockfile.rb +0 -470
  742. data/test/rubygems/test_gem_request_set_lockfile_parser.rb +0 -549
  743. data/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb +0 -306
  744. data/test/rubygems/test_gem_requirement.rb +0 -387
  745. data/test/rubygems/test_gem_resolver.rb +0 -715
  746. data/test/rubygems/test_gem_resolver_activation_request.rb +0 -74
  747. data/test/rubygems/test_gem_resolver_api_set.rb +0 -209
  748. data/test/rubygems/test_gem_resolver_api_specification.rb +0 -145
  749. data/test/rubygems/test_gem_resolver_best_set.rb +0 -138
  750. data/test/rubygems/test_gem_resolver_composed_set.rb +0 -46
  751. data/test/rubygems/test_gem_resolver_conflict.rb +0 -88
  752. data/test/rubygems/test_gem_resolver_dependency_request.rb +0 -85
  753. data/test/rubygems/test_gem_resolver_git_set.rb +0 -190
  754. data/test/rubygems/test_gem_resolver_git_specification.rb +0 -114
  755. data/test/rubygems/test_gem_resolver_index_set.rb +0 -90
  756. data/test/rubygems/test_gem_resolver_index_specification.rb +0 -90
  757. data/test/rubygems/test_gem_resolver_installed_specification.rb +0 -50
  758. data/test/rubygems/test_gem_resolver_installer_set.rb +0 -258
  759. data/test/rubygems/test_gem_resolver_local_specification.rb +0 -46
  760. data/test/rubygems/test_gem_resolver_lock_set.rb +0 -64
  761. data/test/rubygems/test_gem_resolver_lock_specification.rb +0 -100
  762. data/test/rubygems/test_gem_resolver_requirement_list.rb +0 -21
  763. data/test/rubygems/test_gem_resolver_specification.rb +0 -65
  764. data/test/rubygems/test_gem_resolver_vendor_set.rb +0 -84
  765. data/test/rubygems/test_gem_resolver_vendor_specification.rb +0 -84
  766. data/test/rubygems/test_gem_security.rb +0 -307
  767. data/test/rubygems/test_gem_security_policy.rb +0 -541
  768. data/test/rubygems/test_gem_security_signer.rb +0 -209
  769. data/test/rubygems/test_gem_security_trust_dir.rb +0 -101
  770. data/test/rubygems/test_gem_server.rb +0 -409
  771. data/test/rubygems/test_gem_silent_ui.rb +0 -117
  772. data/test/rubygems/test_gem_source.rb +0 -242
  773. data/test/rubygems/test_gem_source_fetch_problem.rb +0 -20
  774. data/test/rubygems/test_gem_source_git.rb +0 -309
  775. data/test/rubygems/test_gem_source_installed.rb +0 -37
  776. data/test/rubygems/test_gem_source_list.rb +0 -118
  777. data/test/rubygems/test_gem_source_local.rb +0 -107
  778. data/test/rubygems/test_gem_source_lock.rb +0 -115
  779. data/test/rubygems/test_gem_source_specific_file.rb +0 -76
  780. data/test/rubygems/test_gem_source_vendor.rb +0 -32
  781. data/test/rubygems/test_gem_spec_fetcher.rb +0 -311
  782. data/test/rubygems/test_gem_specification.rb +0 -3519
  783. data/test/rubygems/test_gem_stream_ui.rb +0 -239
  784. data/test/rubygems/test_gem_stub_specification.rb +0 -217
  785. data/test/rubygems/test_gem_text.rb +0 -77
  786. data/test/rubygems/test_gem_uninstaller.rb +0 -485
  787. data/test/rubygems/test_gem_unsatisfiable_dependency_error.rb +0 -33
  788. data/test/rubygems/test_gem_uri_formatter.rb +0 -29
  789. data/test/rubygems/test_gem_util.rb +0 -40
  790. data/test/rubygems/test_gem_validator.rb +0 -46
  791. data/test/rubygems/test_gem_version.rb +0 -222
  792. data/test/rubygems/test_gem_version_option.rb +0 -152
  793. data/test/rubygems/test_kernel.rb +0 -86
  794. data/test/rubygems/test_require.rb +0 -322
  795. data/test/rubygems/wrong_key_cert.pem +0 -18
  796. data/test/rubygems/wrong_key_cert_32.pem +0 -18
  797. data/util/CL2notes +0 -56
  798. data/util/create_certs.rb +0 -157
  799. data/util/create_encrypted_key.rb +0 -17
  800. data/util/generate_spdx_license_list.rb +0 -51
  801. data/util/update_bundled_ca_certificates.rb +0 -118
@@ -0,0 +1,2694 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'rbconfig'
5
+ rescue LoadError
6
+ # for make rjit-headers
7
+ end
8
+
9
+ # Namespace for file utility methods for copying, moving, removing, etc.
10
+ #
11
+ # == What's Here
12
+ #
13
+ # First, what’s elsewhere. \Module \Bundler::FileUtils:
14
+ #
15
+ # - Inherits from {class Object}[https://docs.ruby-lang.org/en/master/Object.html].
16
+ # - Supplements {class File}[https://docs.ruby-lang.org/en/master/File.html]
17
+ # (but is not included or extended there).
18
+ #
19
+ # Here, module \Bundler::FileUtils provides methods that are useful for:
20
+ #
21
+ # - {Creating}[rdoc-ref:FileUtils@Creating].
22
+ # - {Deleting}[rdoc-ref:FileUtils@Deleting].
23
+ # - {Querying}[rdoc-ref:FileUtils@Querying].
24
+ # - {Setting}[rdoc-ref:FileUtils@Setting].
25
+ # - {Comparing}[rdoc-ref:FileUtils@Comparing].
26
+ # - {Copying}[rdoc-ref:FileUtils@Copying].
27
+ # - {Moving}[rdoc-ref:FileUtils@Moving].
28
+ # - {Options}[rdoc-ref:FileUtils@Options].
29
+ #
30
+ # === Creating
31
+ #
32
+ # - ::mkdir: Creates directories.
33
+ # - ::mkdir_p, ::makedirs, ::mkpath: Creates directories,
34
+ # also creating ancestor directories as needed.
35
+ # - ::link_entry: Creates a hard link.
36
+ # - ::ln, ::link: Creates hard links.
37
+ # - ::ln_s, ::symlink: Creates symbolic links.
38
+ # - ::ln_sf: Creates symbolic links, overwriting if necessary.
39
+ # - ::ln_sr: Creates symbolic links relative to targets
40
+ #
41
+ # === Deleting
42
+ #
43
+ # - ::remove_dir: Removes a directory and its descendants.
44
+ # - ::remove_entry: Removes an entry, including its descendants if it is a directory.
45
+ # - ::remove_entry_secure: Like ::remove_entry, but removes securely.
46
+ # - ::remove_file: Removes a file entry.
47
+ # - ::rm, ::remove: Removes entries.
48
+ # - ::rm_f, ::safe_unlink: Like ::rm, but removes forcibly.
49
+ # - ::rm_r: Removes entries and their descendants.
50
+ # - ::rm_rf, ::rmtree: Like ::rm_r, but removes forcibly.
51
+ # - ::rmdir: Removes directories.
52
+ #
53
+ # === Querying
54
+ #
55
+ # - ::pwd, ::getwd: Returns the path to the working directory.
56
+ # - ::uptodate?: Returns whether a given entry is newer than given other entries.
57
+ #
58
+ # === Setting
59
+ #
60
+ # - ::cd, ::chdir: Sets the working directory.
61
+ # - ::chmod: Sets permissions for an entry.
62
+ # - ::chmod_R: Sets permissions for an entry and its descendants.
63
+ # - ::chown: Sets the owner and group for entries.
64
+ # - ::chown_R: Sets the owner and group for entries and their descendants.
65
+ # - ::touch: Sets modification and access times for entries,
66
+ # creating if necessary.
67
+ #
68
+ # === Comparing
69
+ #
70
+ # - ::compare_file, ::cmp, ::identical?: Returns whether two entries are identical.
71
+ # - ::compare_stream: Returns whether two streams are identical.
72
+ #
73
+ # === Copying
74
+ #
75
+ # - ::copy_entry: Recursively copies an entry.
76
+ # - ::copy_file: Copies an entry.
77
+ # - ::copy_stream: Copies a stream.
78
+ # - ::cp, ::copy: Copies files.
79
+ # - ::cp_lr: Recursively creates hard links.
80
+ # - ::cp_r: Recursively copies files, retaining mode, owner, and group.
81
+ # - ::install: Recursively copies files, optionally setting mode,
82
+ # owner, and group.
83
+ #
84
+ # === Moving
85
+ #
86
+ # - ::mv, ::move: Moves entries.
87
+ #
88
+ # === Options
89
+ #
90
+ # - ::collect_method: Returns the names of methods that accept a given option.
91
+ # - ::commands: Returns the names of methods that accept options.
92
+ # - ::have_option?: Returns whether a given method accepts a given option.
93
+ # - ::options: Returns all option names.
94
+ # - ::options_of: Returns the names of the options for a given method.
95
+ #
96
+ # == Path Arguments
97
+ #
98
+ # Some methods in \Bundler::FileUtils accept _path_ arguments,
99
+ # which are interpreted as paths to filesystem entries:
100
+ #
101
+ # - If the argument is a string, that value is the path.
102
+ # - If the argument has method +:to_path+, it is converted via that method.
103
+ # - If the argument has method +:to_str+, it is converted via that method.
104
+ #
105
+ # == About the Examples
106
+ #
107
+ # Some examples here involve trees of file entries.
108
+ # For these, we sometimes display trees using the
109
+ # {tree command-line utility}[https://en.wikipedia.org/wiki/Tree_(command)],
110
+ # which is a recursive directory-listing utility that produces
111
+ # a depth-indented listing of files and directories.
112
+ #
113
+ # We use a helper method to launch the command and control the format:
114
+ #
115
+ # def tree(dirpath = '.')
116
+ # command = "tree --noreport --charset=ascii #{dirpath}"
117
+ # system(command)
118
+ # end
119
+ #
120
+ # To illustrate:
121
+ #
122
+ # tree('src0')
123
+ # # => src0
124
+ # # |-- sub0
125
+ # # | |-- src0.txt
126
+ # # | `-- src1.txt
127
+ # # `-- sub1
128
+ # # |-- src2.txt
129
+ # # `-- src3.txt
130
+ #
131
+ # == Avoiding the TOCTTOU Vulnerability
132
+ #
133
+ # For certain methods that recursively remove entries,
134
+ # there is a potential vulnerability called the
135
+ # {Time-of-check to time-of-use}[https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use],
136
+ # or TOCTTOU, vulnerability that can exist when:
137
+ #
138
+ # - An ancestor directory of the entry at the target path is world writable;
139
+ # such directories include <tt>/tmp</tt>.
140
+ # - The directory tree at the target path includes:
141
+ #
142
+ # - A world-writable descendant directory.
143
+ # - A symbolic link.
144
+ #
145
+ # To avoid that vulnerability, you can use this method to remove entries:
146
+ #
147
+ # - Bundler::FileUtils.remove_entry_secure: removes recursively
148
+ # if the target path points to a directory.
149
+ #
150
+ # Also available are these methods,
151
+ # each of which calls \Bundler::FileUtils.remove_entry_secure:
152
+ #
153
+ # - Bundler::FileUtils.rm_r with keyword argument <tt>secure: true</tt>.
154
+ # - Bundler::FileUtils.rm_rf with keyword argument <tt>secure: true</tt>.
155
+ #
156
+ # Finally, this method for moving entries calls \Bundler::FileUtils.remove_entry_secure
157
+ # if the source and destination are on different file systems
158
+ # (which means that the "move" is really a copy and remove):
159
+ #
160
+ # - Bundler::FileUtils.mv with keyword argument <tt>secure: true</tt>.
161
+ #
162
+ # \Method \Bundler::FileUtils.remove_entry_secure removes securely
163
+ # by applying a special pre-process:
164
+ #
165
+ # - If the target path points to a directory, this method uses methods
166
+ # {File#chown}[https://docs.ruby-lang.org/en/master/File.html#method-i-chown]
167
+ # and {File#chmod}[https://docs.ruby-lang.org/en/master/File.html#method-i-chmod]
168
+ # in removing directories.
169
+ # - The owner of the target directory should be either the current process
170
+ # or the super user (root).
171
+ #
172
+ # WARNING: You must ensure that *ALL* parent directories cannot be
173
+ # moved by other untrusted users. For example, parent directories
174
+ # should not be owned by untrusted users, and should not be world
175
+ # writable except when the sticky bit is set.
176
+ #
177
+ # For details of this security vulnerability, see Perl cases:
178
+ #
179
+ # - {CVE-2005-0448}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448].
180
+ # - {CVE-2004-0452}[https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452].
181
+ #
182
+ module Bundler::FileUtils
183
+ VERSION = "1.7.2"
184
+
185
+ def self.private_module_function(name) #:nodoc:
186
+ module_function name
187
+ private_class_method name
188
+ end
189
+
190
+ #
191
+ # Returns a string containing the path to the current directory:
192
+ #
193
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
194
+ #
195
+ # Related: Bundler::FileUtils.cd.
196
+ #
197
+ def pwd
198
+ Dir.pwd
199
+ end
200
+ module_function :pwd
201
+
202
+ alias getwd pwd
203
+ module_function :getwd
204
+
205
+ # Changes the working directory to the given +dir+, which
206
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments]:
207
+ #
208
+ # With no block given,
209
+ # changes the current directory to the directory at +dir+; returns zero:
210
+ #
211
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
212
+ # Bundler::FileUtils.cd('..')
213
+ # Bundler::FileUtils.pwd # => "/rdoc"
214
+ # Bundler::FileUtils.cd('fileutils')
215
+ #
216
+ # With a block given, changes the current directory to the directory
217
+ # at +dir+, calls the block with argument +dir+,
218
+ # and restores the original current directory; returns the block's value:
219
+ #
220
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
221
+ # Bundler::FileUtils.cd('..') { |arg| [arg, Bundler::FileUtils.pwd] } # => ["..", "/rdoc"]
222
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
223
+ #
224
+ # Keyword arguments:
225
+ #
226
+ # - <tt>verbose: true</tt> - prints an equivalent command:
227
+ #
228
+ # Bundler::FileUtils.cd('..')
229
+ # Bundler::FileUtils.cd('fileutils')
230
+ #
231
+ # Output:
232
+ #
233
+ # cd ..
234
+ # cd fileutils
235
+ #
236
+ # Related: Bundler::FileUtils.pwd.
237
+ #
238
+ def cd(dir, verbose: nil, &block) # :yield: dir
239
+ fu_output_message "cd #{dir}" if verbose
240
+ result = Dir.chdir(dir, &block)
241
+ fu_output_message 'cd -' if verbose and block
242
+ result
243
+ end
244
+ module_function :cd
245
+
246
+ alias chdir cd
247
+ module_function :chdir
248
+
249
+ #
250
+ # Returns +true+ if the file at path +new+
251
+ # is newer than all the files at paths in array +old_list+;
252
+ # +false+ otherwise.
253
+ #
254
+ # Argument +new+ and the elements of +old_list+
255
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments]:
256
+ #
257
+ # Bundler::FileUtils.uptodate?('Rakefile', ['Gemfile', 'README.md']) # => true
258
+ # Bundler::FileUtils.uptodate?('Gemfile', ['Rakefile', 'README.md']) # => false
259
+ #
260
+ # A non-existent file is considered to be infinitely old.
261
+ #
262
+ # Related: Bundler::FileUtils.touch.
263
+ #
264
+ def uptodate?(new, old_list)
265
+ return false unless File.exist?(new)
266
+ new_time = File.mtime(new)
267
+ old_list.each do |old|
268
+ if File.exist?(old)
269
+ return false unless new_time > File.mtime(old)
270
+ end
271
+ end
272
+ true
273
+ end
274
+ module_function :uptodate?
275
+
276
+ def remove_trailing_slash(dir) #:nodoc:
277
+ dir == '/' ? dir : dir.chomp(?/)
278
+ end
279
+ private_module_function :remove_trailing_slash
280
+
281
+ #
282
+ # Creates directories at the paths in the given +list+
283
+ # (a single path or an array of paths);
284
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
285
+ #
286
+ # Argument +list+ or its elements
287
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
288
+ #
289
+ # With no keyword arguments, creates a directory at each +path+ in +list+
290
+ # by calling: <tt>Dir.mkdir(path, mode)</tt>;
291
+ # see {Dir.mkdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-mkdir]:
292
+ #
293
+ # Bundler::FileUtils.mkdir(%w[tmp0 tmp1]) # => ["tmp0", "tmp1"]
294
+ # Bundler::FileUtils.mkdir('tmp4') # => ["tmp4"]
295
+ #
296
+ # Keyword arguments:
297
+ #
298
+ # - <tt>mode: <i>mode</i></tt> - also calls <tt>File.chmod(mode, path)</tt>;
299
+ # see {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod].
300
+ # - <tt>noop: true</tt> - does not create directories.
301
+ # - <tt>verbose: true</tt> - prints an equivalent command:
302
+ #
303
+ # Bundler::FileUtils.mkdir(%w[tmp0 tmp1], verbose: true)
304
+ # Bundler::FileUtils.mkdir(%w[tmp2 tmp3], mode: 0700, verbose: true)
305
+ #
306
+ # Output:
307
+ #
308
+ # mkdir tmp0 tmp1
309
+ # mkdir -m 700 tmp2 tmp3
310
+ #
311
+ # Raises an exception if any path points to an existing
312
+ # file or directory, or if for any reason a directory cannot be created.
313
+ #
314
+ # Related: Bundler::FileUtils.mkdir_p.
315
+ #
316
+ def mkdir(list, mode: nil, noop: nil, verbose: nil)
317
+ list = fu_list(list)
318
+ fu_output_message "mkdir #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
319
+ return if noop
320
+
321
+ list.each do |dir|
322
+ fu_mkdir dir, mode
323
+ end
324
+ end
325
+ module_function :mkdir
326
+
327
+ #
328
+ # Creates directories at the paths in the given +list+
329
+ # (a single path or an array of paths),
330
+ # also creating ancestor directories as needed;
331
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
332
+ #
333
+ # Argument +list+ or its elements
334
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
335
+ #
336
+ # With no keyword arguments, creates a directory at each +path+ in +list+,
337
+ # along with any needed ancestor directories,
338
+ # by calling: <tt>Dir.mkdir(path, mode)</tt>;
339
+ # see {Dir.mkdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-mkdir]:
340
+ #
341
+ # Bundler::FileUtils.mkdir_p(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
342
+ # Bundler::FileUtils.mkdir_p('tmp4/tmp5') # => ["tmp4/tmp5"]
343
+ #
344
+ # Keyword arguments:
345
+ #
346
+ # - <tt>mode: <i>mode</i></tt> - also calls <tt>File.chmod(mode, path)</tt>;
347
+ # see {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod].
348
+ # - <tt>noop: true</tt> - does not create directories.
349
+ # - <tt>verbose: true</tt> - prints an equivalent command:
350
+ #
351
+ # Bundler::FileUtils.mkdir_p(%w[tmp0 tmp1], verbose: true)
352
+ # Bundler::FileUtils.mkdir_p(%w[tmp2 tmp3], mode: 0700, verbose: true)
353
+ #
354
+ # Output:
355
+ #
356
+ # mkdir -p tmp0 tmp1
357
+ # mkdir -p -m 700 tmp2 tmp3
358
+ #
359
+ # Raises an exception if for any reason a directory cannot be created.
360
+ #
361
+ # Bundler::FileUtils.mkpath and Bundler::FileUtils.makedirs are aliases for Bundler::FileUtils.mkdir_p.
362
+ #
363
+ # Related: Bundler::FileUtils.mkdir.
364
+ #
365
+ def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
366
+ list = fu_list(list)
367
+ fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
368
+ return *list if noop
369
+
370
+ list.each do |item|
371
+ path = remove_trailing_slash(item)
372
+
373
+ stack = []
374
+ until File.directory?(path) || File.dirname(path) == path
375
+ stack.push path
376
+ path = File.dirname(path)
377
+ end
378
+ stack.reverse_each do |dir|
379
+ begin
380
+ fu_mkdir dir, mode
381
+ rescue SystemCallError
382
+ raise unless File.directory?(dir)
383
+ end
384
+ end
385
+ end
386
+
387
+ return *list
388
+ end
389
+ module_function :mkdir_p
390
+
391
+ alias mkpath mkdir_p
392
+ alias makedirs mkdir_p
393
+ module_function :mkpath
394
+ module_function :makedirs
395
+
396
+ def fu_mkdir(path, mode) #:nodoc:
397
+ path = remove_trailing_slash(path)
398
+ if mode
399
+ Dir.mkdir path, mode
400
+ File.chmod mode, path
401
+ else
402
+ Dir.mkdir path
403
+ end
404
+ end
405
+ private_module_function :fu_mkdir
406
+
407
+ #
408
+ # Removes directories at the paths in the given +list+
409
+ # (a single path or an array of paths);
410
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
411
+ #
412
+ # Argument +list+ or its elements
413
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
414
+ #
415
+ # With no keyword arguments, removes the directory at each +path+ in +list+,
416
+ # by calling: <tt>Dir.rmdir(path)</tt>;
417
+ # see {Dir.rmdir}[https://docs.ruby-lang.org/en/master/Dir.html#method-c-rmdir]:
418
+ #
419
+ # Bundler::FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3]) # => ["tmp0/tmp1", "tmp2/tmp3"]
420
+ # Bundler::FileUtils.rmdir('tmp4/tmp5') # => ["tmp4/tmp5"]
421
+ #
422
+ # Keyword arguments:
423
+ #
424
+ # - <tt>parents: true</tt> - removes successive ancestor directories
425
+ # if empty.
426
+ # - <tt>noop: true</tt> - does not remove directories.
427
+ # - <tt>verbose: true</tt> - prints an equivalent command:
428
+ #
429
+ # Bundler::FileUtils.rmdir(%w[tmp0/tmp1 tmp2/tmp3], parents: true, verbose: true)
430
+ # Bundler::FileUtils.rmdir('tmp4/tmp5', parents: true, verbose: true)
431
+ #
432
+ # Output:
433
+ #
434
+ # rmdir -p tmp0/tmp1 tmp2/tmp3
435
+ # rmdir -p tmp4/tmp5
436
+ #
437
+ # Raises an exception if a directory does not exist
438
+ # or if for any reason a directory cannot be removed.
439
+ #
440
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
441
+ #
442
+ def rmdir(list, parents: nil, noop: nil, verbose: nil)
443
+ list = fu_list(list)
444
+ fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose
445
+ return if noop
446
+ list.each do |dir|
447
+ Dir.rmdir(dir = remove_trailing_slash(dir))
448
+ if parents
449
+ begin
450
+ until (parent = File.dirname(dir)) == '.' or parent == dir
451
+ dir = parent
452
+ Dir.rmdir(dir)
453
+ end
454
+ rescue Errno::ENOTEMPTY, Errno::EEXIST, Errno::ENOENT
455
+ end
456
+ end
457
+ end
458
+ end
459
+ module_function :rmdir
460
+
461
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link].
462
+ #
463
+ # Arguments +src+ (a single path or an array of paths)
464
+ # and +dest+ (a single path)
465
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
466
+ #
467
+ # When +src+ is the path to an existing file
468
+ # and +dest+ is the path to a non-existent file,
469
+ # creates a hard link at +dest+ pointing to +src+; returns zero:
470
+ #
471
+ # Dir.children('tmp0/') # => ["t.txt"]
472
+ # Dir.children('tmp1/') # => []
473
+ # Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk') # => 0
474
+ # Dir.children('tmp1/') # => ["t.lnk"]
475
+ #
476
+ # When +src+ is the path to an existing file
477
+ # and +dest+ is the path to an existing directory,
478
+ # creates a hard link at <tt>dest/src</tt> pointing to +src+; returns zero:
479
+ #
480
+ # Dir.children('tmp2') # => ["t.dat"]
481
+ # Dir.children('tmp3') # => []
482
+ # Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3') # => 0
483
+ # Dir.children('tmp3') # => ["t.dat"]
484
+ #
485
+ # When +src+ is an array of paths to existing files
486
+ # and +dest+ is the path to an existing directory,
487
+ # then for each path +target+ in +src+,
488
+ # creates a hard link at <tt>dest/target</tt> pointing to +target+;
489
+ # returns +src+:
490
+ #
491
+ # Dir.children('tmp4/') # => []
492
+ # Bundler::FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/') # => ["tmp0/t.txt", "tmp2/t.dat"]
493
+ # Dir.children('tmp4/') # => ["t.dat", "t.txt"]
494
+ #
495
+ # Keyword arguments:
496
+ #
497
+ # - <tt>force: true</tt> - overwrites +dest+ if it exists.
498
+ # - <tt>noop: true</tt> - does not create links.
499
+ # - <tt>verbose: true</tt> - prints an equivalent command:
500
+ #
501
+ # Bundler::FileUtils.ln('tmp0/t.txt', 'tmp1/t.lnk', verbose: true)
502
+ # Bundler::FileUtils.ln('tmp2/t.dat', 'tmp3', verbose: true)
503
+ # Bundler::FileUtils.ln(['tmp0/t.txt', 'tmp2/t.dat'], 'tmp4/', verbose: true)
504
+ #
505
+ # Output:
506
+ #
507
+ # ln tmp0/t.txt tmp1/t.lnk
508
+ # ln tmp2/t.dat tmp3
509
+ # ln tmp0/t.txt tmp2/t.dat tmp4/
510
+ #
511
+ # Raises an exception if +dest+ is the path to an existing file
512
+ # and keyword argument +force+ is not +true+.
513
+ #
514
+ # Related: Bundler::FileUtils.link_entry (has different options).
515
+ #
516
+ def ln(src, dest, force: nil, noop: nil, verbose: nil)
517
+ fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
518
+ return if noop
519
+ fu_each_src_dest0(src, dest) do |s,d|
520
+ remove_file d, true if force
521
+ File.link s, d
522
+ end
523
+ end
524
+ module_function :ln
525
+
526
+ alias link ln
527
+ module_function :link
528
+
529
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link].
530
+ #
531
+ # Arguments +src+ (a single path or an array of paths)
532
+ # and +dest+ (a single path)
533
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
534
+ #
535
+ # If +src+ is the path to a directory and +dest+ does not exist,
536
+ # creates links +dest+ and descendents pointing to +src+ and its descendents:
537
+ #
538
+ # tree('src0')
539
+ # # => src0
540
+ # # |-- sub0
541
+ # # | |-- src0.txt
542
+ # # | `-- src1.txt
543
+ # # `-- sub1
544
+ # # |-- src2.txt
545
+ # # `-- src3.txt
546
+ # File.exist?('dest0') # => false
547
+ # Bundler::FileUtils.cp_lr('src0', 'dest0')
548
+ # tree('dest0')
549
+ # # => dest0
550
+ # # |-- sub0
551
+ # # | |-- src0.txt
552
+ # # | `-- src1.txt
553
+ # # `-- sub1
554
+ # # |-- src2.txt
555
+ # # `-- src3.txt
556
+ #
557
+ # If +src+ and +dest+ are both paths to directories,
558
+ # creates links <tt>dest/src</tt> and descendents
559
+ # pointing to +src+ and its descendents:
560
+ #
561
+ # tree('src1')
562
+ # # => src1
563
+ # # |-- sub0
564
+ # # | |-- src0.txt
565
+ # # | `-- src1.txt
566
+ # # `-- sub1
567
+ # # |-- src2.txt
568
+ # # `-- src3.txt
569
+ # Bundler::FileUtils.mkdir('dest1')
570
+ # Bundler::FileUtils.cp_lr('src1', 'dest1')
571
+ # tree('dest1')
572
+ # # => dest1
573
+ # # `-- src1
574
+ # # |-- sub0
575
+ # # | |-- src0.txt
576
+ # # | `-- src1.txt
577
+ # # `-- sub1
578
+ # # |-- src2.txt
579
+ # # `-- src3.txt
580
+ #
581
+ # If +src+ is an array of paths to entries and +dest+ is the path to a directory,
582
+ # for each path +filepath+ in +src+, creates a link at <tt>dest/filepath</tt>
583
+ # pointing to that path:
584
+ #
585
+ # tree('src2')
586
+ # # => src2
587
+ # # |-- sub0
588
+ # # | |-- src0.txt
589
+ # # | `-- src1.txt
590
+ # # `-- sub1
591
+ # # |-- src2.txt
592
+ # # `-- src3.txt
593
+ # Bundler::FileUtils.mkdir('dest2')
594
+ # Bundler::FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2')
595
+ # tree('dest2')
596
+ # # => dest2
597
+ # # |-- sub0
598
+ # # | |-- src0.txt
599
+ # # | `-- src1.txt
600
+ # # `-- sub1
601
+ # # |-- src2.txt
602
+ # # `-- src3.txt
603
+ #
604
+ # Keyword arguments:
605
+ #
606
+ # - <tt>dereference_root: false</tt> - if +src+ is a symbolic link,
607
+ # does not dereference it.
608
+ # - <tt>noop: true</tt> - does not create links.
609
+ # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
610
+ # - <tt>verbose: true</tt> - prints an equivalent command:
611
+ #
612
+ # Bundler::FileUtils.cp_lr('src0', 'dest0', noop: true, verbose: true)
613
+ # Bundler::FileUtils.cp_lr('src1', 'dest1', noop: true, verbose: true)
614
+ # Bundler::FileUtils.cp_lr(['src2/sub0', 'src2/sub1'], 'dest2', noop: true, verbose: true)
615
+ #
616
+ # Output:
617
+ #
618
+ # cp -lr src0 dest0
619
+ # cp -lr src1 dest1
620
+ # cp -lr src2/sub0 src2/sub1 dest2
621
+ #
622
+ # Raises an exception if +dest+ is the path to an existing file or directory
623
+ # and keyword argument <tt>remove_destination: true</tt> is not given.
624
+ #
625
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
626
+ #
627
+ def cp_lr(src, dest, noop: nil, verbose: nil,
628
+ dereference_root: true, remove_destination: false)
629
+ fu_output_message "cp -lr#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
630
+ return if noop
631
+ fu_each_src_dest(src, dest) do |s, d|
632
+ link_entry s, d, dereference_root, remove_destination
633
+ end
634
+ end
635
+ module_function :cp_lr
636
+
637
+ # Creates {symbolic links}[https://en.wikipedia.org/wiki/Symbolic_link].
638
+ #
639
+ # Arguments +src+ (a single path or an array of paths)
640
+ # and +dest+ (a single path)
641
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
642
+ #
643
+ # If +src+ is the path to an existing file:
644
+ #
645
+ # - When +dest+ is the path to a non-existent file,
646
+ # creates a symbolic link at +dest+ pointing to +src+:
647
+ #
648
+ # Bundler::FileUtils.touch('src0.txt')
649
+ # File.exist?('dest0.txt') # => false
650
+ # Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt')
651
+ # File.symlink?('dest0.txt') # => true
652
+ #
653
+ # - When +dest+ is the path to an existing file,
654
+ # creates a symbolic link at +dest+ pointing to +src+
655
+ # if and only if keyword argument <tt>force: true</tt> is given
656
+ # (raises an exception otherwise):
657
+ #
658
+ # Bundler::FileUtils.touch('src1.txt')
659
+ # Bundler::FileUtils.touch('dest1.txt')
660
+ # Bundler::FileUtils.ln_s('src1.txt', 'dest1.txt', force: true)
661
+ # FileTest.symlink?('dest1.txt') # => true
662
+ #
663
+ # Bundler::FileUtils.ln_s('src1.txt', 'dest1.txt') # Raises Errno::EEXIST.
664
+ #
665
+ # If +dest+ is the path to a directory,
666
+ # creates a symbolic link at <tt>dest/src</tt> pointing to +src+:
667
+ #
668
+ # Bundler::FileUtils.touch('src2.txt')
669
+ # Bundler::FileUtils.mkdir('destdir2')
670
+ # Bundler::FileUtils.ln_s('src2.txt', 'destdir2')
671
+ # File.symlink?('destdir2/src2.txt') # => true
672
+ #
673
+ # If +src+ is an array of paths to existing files and +dest+ is a directory,
674
+ # for each child +child+ in +src+ creates a symbolic link <tt>dest/child</tt>
675
+ # pointing to +child+:
676
+ #
677
+ # Bundler::FileUtils.mkdir('srcdir3')
678
+ # Bundler::FileUtils.touch('srcdir3/src0.txt')
679
+ # Bundler::FileUtils.touch('srcdir3/src1.txt')
680
+ # Bundler::FileUtils.mkdir('destdir3')
681
+ # Bundler::FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3')
682
+ # File.symlink?('destdir3/src0.txt') # => true
683
+ # File.symlink?('destdir3/src1.txt') # => true
684
+ #
685
+ # Keyword arguments:
686
+ #
687
+ # - <tt>force: true</tt> - overwrites +dest+ if it exists.
688
+ # - <tt>relative: false</tt> - create links relative to +dest+.
689
+ # - <tt>noop: true</tt> - does not create links.
690
+ # - <tt>verbose: true</tt> - prints an equivalent command:
691
+ #
692
+ # Bundler::FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
693
+ # Bundler::FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
694
+ # Bundler::FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
695
+ # Bundler::FileUtils.ln_s(['srcdir3/src0.txt', 'srcdir3/src1.txt'], 'destdir3', noop: true, verbose: true)
696
+ #
697
+ # Output:
698
+ #
699
+ # ln -s src0.txt dest0.txt
700
+ # ln -s src1.txt destdir1
701
+ # ln -sf src2.txt dest2.txt
702
+ # ln -s srcdir3/src0.txt srcdir3/src1.txt destdir3
703
+ #
704
+ # Related: Bundler::FileUtils.ln_sf.
705
+ #
706
+ def ln_s(src, dest, force: nil, relative: false, target_directory: true, noop: nil, verbose: nil)
707
+ if relative
708
+ return ln_sr(src, dest, force: force, noop: noop, verbose: verbose)
709
+ end
710
+ fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
711
+ return if noop
712
+ fu_each_src_dest0(src, dest) do |s,d|
713
+ remove_file d, true if force
714
+ File.symlink s, d
715
+ end
716
+ end
717
+ module_function :ln_s
718
+
719
+ alias symlink ln_s
720
+ module_function :symlink
721
+
722
+ # Like Bundler::FileUtils.ln_s, but always with keyword argument <tt>force: true</tt> given.
723
+ #
724
+ def ln_sf(src, dest, noop: nil, verbose: nil)
725
+ ln_s src, dest, force: true, noop: noop, verbose: verbose
726
+ end
727
+ module_function :ln_sf
728
+
729
+ # Like Bundler::FileUtils.ln_s, but create links relative to +dest+.
730
+ #
731
+ def ln_sr(src, dest, target_directory: true, force: nil, noop: nil, verbose: nil)
732
+ options = "#{force ? 'f' : ''}#{target_directory ? '' : 'T'}"
733
+ dest = File.path(dest)
734
+ srcs = Array(src)
735
+ link = proc do |s, target_dir_p = true|
736
+ s = File.path(s)
737
+ if target_dir_p
738
+ d = File.join(destdirs = dest, File.basename(s))
739
+ else
740
+ destdirs = File.dirname(d = dest)
741
+ end
742
+ destdirs = fu_split_path(File.realpath(destdirs))
743
+ if fu_starting_path?(s)
744
+ srcdirs = fu_split_path((File.realdirpath(s) rescue File.expand_path(s)))
745
+ base = fu_relative_components_from(srcdirs, destdirs)
746
+ s = File.join(*base)
747
+ else
748
+ srcdirs = fu_clean_components(*fu_split_path(s))
749
+ base = fu_relative_components_from(fu_split_path(Dir.pwd), destdirs)
750
+ while srcdirs.first&. == ".." and base.last&.!=("..") and !fu_starting_path?(base.last)
751
+ srcdirs.shift
752
+ base.pop
753
+ end
754
+ s = File.join(*base, *srcdirs)
755
+ end
756
+ fu_output_message "ln -s#{options} #{s} #{d}" if verbose
757
+ next if noop
758
+ remove_file d, true if force
759
+ File.symlink s, d
760
+ end
761
+ case srcs.size
762
+ when 0
763
+ when 1
764
+ link[srcs[0], target_directory && File.directory?(dest)]
765
+ else
766
+ srcs.each(&link)
767
+ end
768
+ end
769
+ module_function :ln_sr
770
+
771
+ # Creates {hard links}[https://en.wikipedia.org/wiki/Hard_link]; returns +nil+.
772
+ #
773
+ # Arguments +src+ and +dest+
774
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
775
+ #
776
+ # If +src+ is the path to a file and +dest+ does not exist,
777
+ # creates a hard link at +dest+ pointing to +src+:
778
+ #
779
+ # Bundler::FileUtils.touch('src0.txt')
780
+ # File.exist?('dest0.txt') # => false
781
+ # Bundler::FileUtils.link_entry('src0.txt', 'dest0.txt')
782
+ # File.file?('dest0.txt') # => true
783
+ #
784
+ # If +src+ is the path to a directory and +dest+ does not exist,
785
+ # recursively creates hard links at +dest+ pointing to paths in +src+:
786
+ #
787
+ # Bundler::FileUtils.mkdir_p(['src1/dir0', 'src1/dir1'])
788
+ # src_file_paths = [
789
+ # 'src1/dir0/t0.txt',
790
+ # 'src1/dir0/t1.txt',
791
+ # 'src1/dir1/t2.txt',
792
+ # 'src1/dir1/t3.txt',
793
+ # ]
794
+ # Bundler::FileUtils.touch(src_file_paths)
795
+ # File.directory?('dest1') # => true
796
+ # Bundler::FileUtils.link_entry('src1', 'dest1')
797
+ # File.file?('dest1/dir0/t0.txt') # => true
798
+ # File.file?('dest1/dir0/t1.txt') # => true
799
+ # File.file?('dest1/dir1/t2.txt') # => true
800
+ # File.file?('dest1/dir1/t3.txt') # => true
801
+ #
802
+ # Keyword arguments:
803
+ #
804
+ # - <tt>dereference_root: true</tt> - dereferences +src+ if it is a symbolic link.
805
+ # - <tt>remove_destination: true</tt> - removes +dest+ before creating links.
806
+ #
807
+ # Raises an exception if +dest+ is the path to an existing file or directory
808
+ # and keyword argument <tt>remove_destination: true</tt> is not given.
809
+ #
810
+ # Related: Bundler::FileUtils.ln (has different options).
811
+ #
812
+ def link_entry(src, dest, dereference_root = false, remove_destination = false)
813
+ Entry_.new(src, nil, dereference_root).traverse do |ent|
814
+ destent = Entry_.new(dest, ent.rel, false)
815
+ File.unlink destent.path if remove_destination && File.file?(destent.path)
816
+ ent.link destent.path
817
+ end
818
+ end
819
+ module_function :link_entry
820
+
821
+ # Copies files.
822
+ #
823
+ # Arguments +src+ (a single path or an array of paths)
824
+ # and +dest+ (a single path)
825
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
826
+ #
827
+ # If +src+ is the path to a file and +dest+ is not the path to a directory,
828
+ # copies +src+ to +dest+:
829
+ #
830
+ # Bundler::FileUtils.touch('src0.txt')
831
+ # File.exist?('dest0.txt') # => false
832
+ # Bundler::FileUtils.cp('src0.txt', 'dest0.txt')
833
+ # File.file?('dest0.txt') # => true
834
+ #
835
+ # If +src+ is the path to a file and +dest+ is the path to a directory,
836
+ # copies +src+ to <tt>dest/src</tt>:
837
+ #
838
+ # Bundler::FileUtils.touch('src1.txt')
839
+ # Bundler::FileUtils.mkdir('dest1')
840
+ # Bundler::FileUtils.cp('src1.txt', 'dest1')
841
+ # File.file?('dest1/src1.txt') # => true
842
+ #
843
+ # If +src+ is an array of paths to files and +dest+ is the path to a directory,
844
+ # copies from each +src+ to +dest+:
845
+ #
846
+ # src_file_paths = ['src2.txt', 'src2.dat']
847
+ # Bundler::FileUtils.touch(src_file_paths)
848
+ # Bundler::FileUtils.mkdir('dest2')
849
+ # Bundler::FileUtils.cp(src_file_paths, 'dest2')
850
+ # File.file?('dest2/src2.txt') # => true
851
+ # File.file?('dest2/src2.dat') # => true
852
+ #
853
+ # Keyword arguments:
854
+ #
855
+ # - <tt>preserve: true</tt> - preserves file times.
856
+ # - <tt>noop: true</tt> - does not copy files.
857
+ # - <tt>verbose: true</tt> - prints an equivalent command:
858
+ #
859
+ # Bundler::FileUtils.cp('src0.txt', 'dest0.txt', noop: true, verbose: true)
860
+ # Bundler::FileUtils.cp('src1.txt', 'dest1', noop: true, verbose: true)
861
+ # Bundler::FileUtils.cp(src_file_paths, 'dest2', noop: true, verbose: true)
862
+ #
863
+ # Output:
864
+ #
865
+ # cp src0.txt dest0.txt
866
+ # cp src1.txt dest1
867
+ # cp src2.txt src2.dat dest2
868
+ #
869
+ # Raises an exception if +src+ is a directory.
870
+ #
871
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
872
+ #
873
+ def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
874
+ fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
875
+ return if noop
876
+ fu_each_src_dest(src, dest) do |s, d|
877
+ copy_file s, d, preserve
878
+ end
879
+ end
880
+ module_function :cp
881
+
882
+ alias copy cp
883
+ module_function :copy
884
+
885
+ # Recursively copies files.
886
+ #
887
+ # Arguments +src+ (a single path or an array of paths)
888
+ # and +dest+ (a single path)
889
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
890
+ #
891
+ # The mode, owner, and group are retained in the copy;
892
+ # to change those, use Bundler::FileUtils.install instead.
893
+ #
894
+ # If +src+ is the path to a file and +dest+ is not the path to a directory,
895
+ # copies +src+ to +dest+:
896
+ #
897
+ # Bundler::FileUtils.touch('src0.txt')
898
+ # File.exist?('dest0.txt') # => false
899
+ # Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt')
900
+ # File.file?('dest0.txt') # => true
901
+ #
902
+ # If +src+ is the path to a file and +dest+ is the path to a directory,
903
+ # copies +src+ to <tt>dest/src</tt>:
904
+ #
905
+ # Bundler::FileUtils.touch('src1.txt')
906
+ # Bundler::FileUtils.mkdir('dest1')
907
+ # Bundler::FileUtils.cp_r('src1.txt', 'dest1')
908
+ # File.file?('dest1/src1.txt') # => true
909
+ #
910
+ # If +src+ is the path to a directory and +dest+ does not exist,
911
+ # recursively copies +src+ to +dest+:
912
+ #
913
+ # tree('src2')
914
+ # # => src2
915
+ # # |-- dir0
916
+ # # | |-- src0.txt
917
+ # # | `-- src1.txt
918
+ # # `-- dir1
919
+ # # |-- src2.txt
920
+ # # `-- src3.txt
921
+ # Bundler::FileUtils.exist?('dest2') # => false
922
+ # Bundler::FileUtils.cp_r('src2', 'dest2')
923
+ # tree('dest2')
924
+ # # => dest2
925
+ # # |-- dir0
926
+ # # | |-- src0.txt
927
+ # # | `-- src1.txt
928
+ # # `-- dir1
929
+ # # |-- src2.txt
930
+ # # `-- src3.txt
931
+ #
932
+ # If +src+ and +dest+ are paths to directories,
933
+ # recursively copies +src+ to <tt>dest/src</tt>:
934
+ #
935
+ # tree('src3')
936
+ # # => src3
937
+ # # |-- dir0
938
+ # # | |-- src0.txt
939
+ # # | `-- src1.txt
940
+ # # `-- dir1
941
+ # # |-- src2.txt
942
+ # # `-- src3.txt
943
+ # Bundler::FileUtils.mkdir('dest3')
944
+ # Bundler::FileUtils.cp_r('src3', 'dest3')
945
+ # tree('dest3')
946
+ # # => dest3
947
+ # # `-- src3
948
+ # # |-- dir0
949
+ # # | |-- src0.txt
950
+ # # | `-- src1.txt
951
+ # # `-- dir1
952
+ # # |-- src2.txt
953
+ # # `-- src3.txt
954
+ #
955
+ # If +src+ is an array of paths and +dest+ is a directory,
956
+ # recursively copies from each path in +src+ to +dest+;
957
+ # the paths in +src+ may point to files and/or directories.
958
+ #
959
+ # Keyword arguments:
960
+ #
961
+ # - <tt>dereference_root: false</tt> - if +src+ is a symbolic link,
962
+ # does not dereference it.
963
+ # - <tt>noop: true</tt> - does not copy files.
964
+ # - <tt>preserve: true</tt> - preserves file times.
965
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
966
+ # - <tt>verbose: true</tt> - prints an equivalent command:
967
+ #
968
+ # Bundler::FileUtils.cp_r('src0.txt', 'dest0.txt', noop: true, verbose: true)
969
+ # Bundler::FileUtils.cp_r('src1.txt', 'dest1', noop: true, verbose: true)
970
+ # Bundler::FileUtils.cp_r('src2', 'dest2', noop: true, verbose: true)
971
+ # Bundler::FileUtils.cp_r('src3', 'dest3', noop: true, verbose: true)
972
+ #
973
+ # Output:
974
+ #
975
+ # cp -r src0.txt dest0.txt
976
+ # cp -r src1.txt dest1
977
+ # cp -r src2 dest2
978
+ # cp -r src3 dest3
979
+ #
980
+ # Raises an exception of +src+ is the path to a directory
981
+ # and +dest+ is the path to a file.
982
+ #
983
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
984
+ #
985
+ def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
986
+ dereference_root: true, remove_destination: nil)
987
+ fu_output_message "cp -r#{preserve ? 'p' : ''}#{remove_destination ? ' --remove-destination' : ''} #{[src,dest].flatten.join ' '}" if verbose
988
+ return if noop
989
+ fu_each_src_dest(src, dest) do |s, d|
990
+ copy_entry s, d, preserve, dereference_root, remove_destination
991
+ end
992
+ end
993
+ module_function :cp_r
994
+
995
+ # Recursively copies files from +src+ to +dest+.
996
+ #
997
+ # Arguments +src+ and +dest+
998
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
999
+ #
1000
+ # If +src+ is the path to a file, copies +src+ to +dest+:
1001
+ #
1002
+ # Bundler::FileUtils.touch('src0.txt')
1003
+ # File.exist?('dest0.txt') # => false
1004
+ # Bundler::FileUtils.copy_entry('src0.txt', 'dest0.txt')
1005
+ # File.file?('dest0.txt') # => true
1006
+ #
1007
+ # If +src+ is a directory, recursively copies +src+ to +dest+:
1008
+ #
1009
+ # tree('src1')
1010
+ # # => src1
1011
+ # # |-- dir0
1012
+ # # | |-- src0.txt
1013
+ # # | `-- src1.txt
1014
+ # # `-- dir1
1015
+ # # |-- src2.txt
1016
+ # # `-- src3.txt
1017
+ # Bundler::FileUtils.copy_entry('src1', 'dest1')
1018
+ # tree('dest1')
1019
+ # # => dest1
1020
+ # # |-- dir0
1021
+ # # | |-- src0.txt
1022
+ # # | `-- src1.txt
1023
+ # # `-- dir1
1024
+ # # |-- src2.txt
1025
+ # # `-- src3.txt
1026
+ #
1027
+ # The recursive copying preserves file types for regular files,
1028
+ # directories, and symbolic links;
1029
+ # other file types (FIFO streams, device files, etc.) are not supported.
1030
+ #
1031
+ # Keyword arguments:
1032
+ #
1033
+ # - <tt>dereference_root: true</tt> - if +src+ is a symbolic link,
1034
+ # follows the link.
1035
+ # - <tt>preserve: true</tt> - preserves file times.
1036
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
1037
+ #
1038
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
1039
+ #
1040
+ def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
1041
+ if dereference_root
1042
+ src = File.realpath(src)
1043
+ end
1044
+
1045
+ Entry_.new(src, nil, false).wrap_traverse(proc do |ent|
1046
+ destent = Entry_.new(dest, ent.rel, false)
1047
+ File.unlink destent.path if remove_destination && (File.file?(destent.path) || File.symlink?(destent.path))
1048
+ ent.copy destent.path
1049
+ end, proc do |ent|
1050
+ destent = Entry_.new(dest, ent.rel, false)
1051
+ ent.copy_metadata destent.path if preserve
1052
+ end)
1053
+ end
1054
+ module_function :copy_entry
1055
+
1056
+ # Copies file from +src+ to +dest+, which should not be directories.
1057
+ #
1058
+ # Arguments +src+ and +dest+
1059
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1060
+ #
1061
+ # Examples:
1062
+ #
1063
+ # Bundler::FileUtils.touch('src0.txt')
1064
+ # Bundler::FileUtils.copy_file('src0.txt', 'dest0.txt')
1065
+ # File.file?('dest0.txt') # => true
1066
+ #
1067
+ # Keyword arguments:
1068
+ #
1069
+ # - <tt>dereference: false</tt> - if +src+ is a symbolic link,
1070
+ # does not follow the link.
1071
+ # - <tt>preserve: true</tt> - preserves file times.
1072
+ # - <tt>remove_destination: true</tt> - removes +dest+ before copying files.
1073
+ #
1074
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
1075
+ #
1076
+ def copy_file(src, dest, preserve = false, dereference = true)
1077
+ ent = Entry_.new(src, nil, dereference)
1078
+ ent.copy_file dest
1079
+ ent.copy_metadata dest if preserve
1080
+ end
1081
+ module_function :copy_file
1082
+
1083
+ # Copies \IO stream +src+ to \IO stream +dest+ via
1084
+ # {IO.copy_stream}[https://docs.ruby-lang.org/en/master/IO.html#method-c-copy_stream].
1085
+ #
1086
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
1087
+ #
1088
+ def copy_stream(src, dest)
1089
+ IO.copy_stream(src, dest)
1090
+ end
1091
+ module_function :copy_stream
1092
+
1093
+ # Moves entries.
1094
+ #
1095
+ # Arguments +src+ (a single path or an array of paths)
1096
+ # and +dest+ (a single path)
1097
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1098
+ #
1099
+ # If +src+ and +dest+ are on different file systems,
1100
+ # first copies, then removes +src+.
1101
+ #
1102
+ # May cause a local vulnerability if not called with keyword argument
1103
+ # <tt>secure: true</tt>;
1104
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
1105
+ #
1106
+ # If +src+ is the path to a single file or directory and +dest+ does not exist,
1107
+ # moves +src+ to +dest+:
1108
+ #
1109
+ # tree('src0')
1110
+ # # => src0
1111
+ # # |-- src0.txt
1112
+ # # `-- src1.txt
1113
+ # File.exist?('dest0') # => false
1114
+ # Bundler::FileUtils.mv('src0', 'dest0')
1115
+ # File.exist?('src0') # => false
1116
+ # tree('dest0')
1117
+ # # => dest0
1118
+ # # |-- src0.txt
1119
+ # # `-- src1.txt
1120
+ #
1121
+ # If +src+ is an array of paths to files and directories
1122
+ # and +dest+ is the path to a directory,
1123
+ # copies from each path in the array to +dest+:
1124
+ #
1125
+ # File.file?('src1.txt') # => true
1126
+ # tree('src1')
1127
+ # # => src1
1128
+ # # |-- src.dat
1129
+ # # `-- src.txt
1130
+ # Dir.empty?('dest1') # => true
1131
+ # Bundler::FileUtils.mv(['src1.txt', 'src1'], 'dest1')
1132
+ # tree('dest1')
1133
+ # # => dest1
1134
+ # # |-- src1
1135
+ # # | |-- src.dat
1136
+ # # | `-- src.txt
1137
+ # # `-- src1.txt
1138
+ #
1139
+ # Keyword arguments:
1140
+ #
1141
+ # - <tt>force: true</tt> - if the move includes removing +src+
1142
+ # (that is, if +src+ and +dest+ are on different file systems),
1143
+ # ignores raised exceptions of StandardError and its descendants.
1144
+ # - <tt>noop: true</tt> - does not move files.
1145
+ # - <tt>secure: true</tt> - removes +src+ securely;
1146
+ # see details at Bundler::FileUtils.remove_entry_secure.
1147
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1148
+ #
1149
+ # Bundler::FileUtils.mv('src0', 'dest0', noop: true, verbose: true)
1150
+ # Bundler::FileUtils.mv(['src1.txt', 'src1'], 'dest1', noop: true, verbose: true)
1151
+ #
1152
+ # Output:
1153
+ #
1154
+ # mv src0 dest0
1155
+ # mv src1.txt src1 dest1
1156
+ #
1157
+ def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
1158
+ fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
1159
+ return if noop
1160
+ fu_each_src_dest(src, dest) do |s, d|
1161
+ destent = Entry_.new(d, nil, true)
1162
+ begin
1163
+ if destent.exist?
1164
+ if destent.directory?
1165
+ raise Errno::EEXIST, d
1166
+ end
1167
+ end
1168
+ begin
1169
+ File.rename s, d
1170
+ rescue Errno::EXDEV,
1171
+ Errno::EPERM # move from unencrypted to encrypted dir (ext4)
1172
+ copy_entry s, d, true
1173
+ if secure
1174
+ remove_entry_secure s, force
1175
+ else
1176
+ remove_entry s, force
1177
+ end
1178
+ end
1179
+ rescue SystemCallError
1180
+ raise unless force
1181
+ end
1182
+ end
1183
+ end
1184
+ module_function :mv
1185
+
1186
+ alias move mv
1187
+ module_function :move
1188
+
1189
+ # Removes entries at the paths in the given +list+
1190
+ # (a single path or an array of paths)
1191
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
1192
+ #
1193
+ # Argument +list+ or its elements
1194
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1195
+ #
1196
+ # With no keyword arguments, removes files at the paths given in +list+:
1197
+ #
1198
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
1199
+ # Bundler::FileUtils.rm(['src0.dat', 'src0.txt']) # => ["src0.dat", "src0.txt"]
1200
+ #
1201
+ # Keyword arguments:
1202
+ #
1203
+ # - <tt>force: true</tt> - ignores raised exceptions of StandardError
1204
+ # and its descendants.
1205
+ # - <tt>noop: true</tt> - does not remove files; returns +nil+.
1206
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1207
+ #
1208
+ # Bundler::FileUtils.rm(['src0.dat', 'src0.txt'], noop: true, verbose: true)
1209
+ #
1210
+ # Output:
1211
+ #
1212
+ # rm src0.dat src0.txt
1213
+ #
1214
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1215
+ #
1216
+ def rm(list, force: nil, noop: nil, verbose: nil)
1217
+ list = fu_list(list)
1218
+ fu_output_message "rm#{force ? ' -f' : ''} #{list.join ' '}" if verbose
1219
+ return if noop
1220
+
1221
+ list.each do |path|
1222
+ remove_file path, force
1223
+ end
1224
+ end
1225
+ module_function :rm
1226
+
1227
+ alias remove rm
1228
+ module_function :remove
1229
+
1230
+ # Equivalent to:
1231
+ #
1232
+ # Bundler::FileUtils.rm(list, force: true, **kwargs)
1233
+ #
1234
+ # Argument +list+ (a single path or an array of paths)
1235
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1236
+ #
1237
+ # See Bundler::FileUtils.rm for keyword arguments.
1238
+ #
1239
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1240
+ #
1241
+ def rm_f(list, noop: nil, verbose: nil)
1242
+ rm list, force: true, noop: noop, verbose: verbose
1243
+ end
1244
+ module_function :rm_f
1245
+
1246
+ alias safe_unlink rm_f
1247
+ module_function :safe_unlink
1248
+
1249
+ # Removes entries at the paths in the given +list+
1250
+ # (a single path or an array of paths);
1251
+ # returns +list+, if it is an array, <tt>[list]</tt> otherwise.
1252
+ #
1253
+ # Argument +list+ or its elements
1254
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1255
+ #
1256
+ # May cause a local vulnerability if not called with keyword argument
1257
+ # <tt>secure: true</tt>;
1258
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
1259
+ #
1260
+ # For each file path, removes the file at that path:
1261
+ #
1262
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
1263
+ # Bundler::FileUtils.rm_r(['src0.dat', 'src0.txt'])
1264
+ # File.exist?('src0.txt') # => false
1265
+ # File.exist?('src0.dat') # => false
1266
+ #
1267
+ # For each directory path, recursively removes files and directories:
1268
+ #
1269
+ # tree('src1')
1270
+ # # => src1
1271
+ # # |-- dir0
1272
+ # # | |-- src0.txt
1273
+ # # | `-- src1.txt
1274
+ # # `-- dir1
1275
+ # # |-- src2.txt
1276
+ # # `-- src3.txt
1277
+ # Bundler::FileUtils.rm_r('src1')
1278
+ # File.exist?('src1') # => false
1279
+ #
1280
+ # Keyword arguments:
1281
+ #
1282
+ # - <tt>force: true</tt> - ignores raised exceptions of StandardError
1283
+ # and its descendants.
1284
+ # - <tt>noop: true</tt> - does not remove entries; returns +nil+.
1285
+ # - <tt>secure: true</tt> - removes +src+ securely;
1286
+ # see details at Bundler::FileUtils.remove_entry_secure.
1287
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1288
+ #
1289
+ # Bundler::FileUtils.rm_r(['src0.dat', 'src0.txt'], noop: true, verbose: true)
1290
+ # Bundler::FileUtils.rm_r('src1', noop: true, verbose: true)
1291
+ #
1292
+ # Output:
1293
+ #
1294
+ # rm -r src0.dat src0.txt
1295
+ # rm -r src1
1296
+ #
1297
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1298
+ #
1299
+ def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
1300
+ list = fu_list(list)
1301
+ fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose
1302
+ return if noop
1303
+ list.each do |path|
1304
+ if secure
1305
+ remove_entry_secure path, force
1306
+ else
1307
+ remove_entry path, force
1308
+ end
1309
+ end
1310
+ end
1311
+ module_function :rm_r
1312
+
1313
+ # Equivalent to:
1314
+ #
1315
+ # Bundler::FileUtils.rm_r(list, force: true, **kwargs)
1316
+ #
1317
+ # Argument +list+ or its elements
1318
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1319
+ #
1320
+ # May cause a local vulnerability if not called with keyword argument
1321
+ # <tt>secure: true</tt>;
1322
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
1323
+ #
1324
+ # See Bundler::FileUtils.rm_r for keyword arguments.
1325
+ #
1326
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1327
+ #
1328
+ def rm_rf(list, noop: nil, verbose: nil, secure: nil)
1329
+ rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
1330
+ end
1331
+ module_function :rm_rf
1332
+
1333
+ alias rmtree rm_rf
1334
+ module_function :rmtree
1335
+
1336
+ # Securely removes the entry given by +path+,
1337
+ # which should be the entry for a regular file, a symbolic link,
1338
+ # or a directory.
1339
+ #
1340
+ # Argument +path+
1341
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1342
+ #
1343
+ # Avoids a local vulnerability that can exist in certain circumstances;
1344
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
1345
+ #
1346
+ # Optional argument +force+ specifies whether to ignore
1347
+ # raised exceptions of StandardError and its descendants.
1348
+ #
1349
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1350
+ #
1351
+ def remove_entry_secure(path, force = false)
1352
+ unless fu_have_symlink?
1353
+ remove_entry path, force
1354
+ return
1355
+ end
1356
+ fullpath = File.expand_path(path)
1357
+ st = File.lstat(fullpath)
1358
+ unless st.directory?
1359
+ File.unlink fullpath
1360
+ return
1361
+ end
1362
+ # is a directory.
1363
+ parent_st = File.stat(File.dirname(fullpath))
1364
+ unless parent_st.world_writable?
1365
+ remove_entry path, force
1366
+ return
1367
+ end
1368
+ unless parent_st.sticky?
1369
+ raise ArgumentError, "parent directory is world writable, Bundler::FileUtils#remove_entry_secure does not work; abort: #{path.inspect} (parent directory mode #{'%o' % parent_st.mode})"
1370
+ end
1371
+
1372
+ # freeze tree root
1373
+ euid = Process.euid
1374
+ dot_file = fullpath + "/."
1375
+ begin
1376
+ File.open(dot_file) {|f|
1377
+ unless fu_stat_identical_entry?(st, f.stat)
1378
+ # symlink (TOC-to-TOU attack?)
1379
+ File.unlink fullpath
1380
+ return
1381
+ end
1382
+ f.chown euid, -1
1383
+ f.chmod 0700
1384
+ }
1385
+ rescue Errno::EISDIR # JRuby in non-native mode can't open files as dirs
1386
+ File.lstat(dot_file).tap {|fstat|
1387
+ unless fu_stat_identical_entry?(st, fstat)
1388
+ # symlink (TOC-to-TOU attack?)
1389
+ File.unlink fullpath
1390
+ return
1391
+ end
1392
+ File.chown euid, -1, dot_file
1393
+ File.chmod 0700, dot_file
1394
+ }
1395
+ end
1396
+
1397
+ unless fu_stat_identical_entry?(st, File.lstat(fullpath))
1398
+ # TOC-to-TOU attack?
1399
+ File.unlink fullpath
1400
+ return
1401
+ end
1402
+
1403
+ # ---- tree root is frozen ----
1404
+ root = Entry_.new(path)
1405
+ root.preorder_traverse do |ent|
1406
+ if ent.directory?
1407
+ ent.chown euid, -1
1408
+ ent.chmod 0700
1409
+ end
1410
+ end
1411
+ root.postorder_traverse do |ent|
1412
+ begin
1413
+ ent.remove
1414
+ rescue
1415
+ raise unless force
1416
+ end
1417
+ end
1418
+ rescue
1419
+ raise unless force
1420
+ end
1421
+ module_function :remove_entry_secure
1422
+
1423
+ def fu_have_symlink? #:nodoc:
1424
+ File.symlink nil, nil
1425
+ rescue NotImplementedError
1426
+ return false
1427
+ rescue TypeError
1428
+ return true
1429
+ end
1430
+ private_module_function :fu_have_symlink?
1431
+
1432
+ def fu_stat_identical_entry?(a, b) #:nodoc:
1433
+ a.dev == b.dev and a.ino == b.ino
1434
+ end
1435
+ private_module_function :fu_stat_identical_entry?
1436
+
1437
+ # Removes the entry given by +path+,
1438
+ # which should be the entry for a regular file, a symbolic link,
1439
+ # or a directory.
1440
+ #
1441
+ # Argument +path+
1442
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1443
+ #
1444
+ # Optional argument +force+ specifies whether to ignore
1445
+ # raised exceptions of StandardError and its descendants.
1446
+ #
1447
+ # Related: Bundler::FileUtils.remove_entry_secure.
1448
+ #
1449
+ def remove_entry(path, force = false)
1450
+ Entry_.new(path).postorder_traverse do |ent|
1451
+ begin
1452
+ ent.remove
1453
+ rescue
1454
+ raise unless force
1455
+ end
1456
+ end
1457
+ rescue
1458
+ raise unless force
1459
+ end
1460
+ module_function :remove_entry
1461
+
1462
+ # Removes the file entry given by +path+,
1463
+ # which should be the entry for a regular file or a symbolic link.
1464
+ #
1465
+ # Argument +path+
1466
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1467
+ #
1468
+ # Optional argument +force+ specifies whether to ignore
1469
+ # raised exceptions of StandardError and its descendants.
1470
+ #
1471
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1472
+ #
1473
+ def remove_file(path, force = false)
1474
+ Entry_.new(path).remove_file
1475
+ rescue
1476
+ raise unless force
1477
+ end
1478
+ module_function :remove_file
1479
+
1480
+ # Recursively removes the directory entry given by +path+,
1481
+ # which should be the entry for a regular file, a symbolic link,
1482
+ # or a directory.
1483
+ #
1484
+ # Argument +path+
1485
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1486
+ #
1487
+ # Optional argument +force+ specifies whether to ignore
1488
+ # raised exceptions of StandardError and its descendants.
1489
+ #
1490
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
1491
+ #
1492
+ def remove_dir(path, force = false)
1493
+ remove_entry path, force # FIXME?? check if it is a directory
1494
+ end
1495
+ module_function :remove_dir
1496
+
1497
+ # Returns +true+ if the contents of files +a+ and +b+ are identical,
1498
+ # +false+ otherwise.
1499
+ #
1500
+ # Arguments +a+ and +b+
1501
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1502
+ #
1503
+ # Bundler::FileUtils.identical? and Bundler::FileUtils.cmp are aliases for Bundler::FileUtils.compare_file.
1504
+ #
1505
+ # Related: Bundler::FileUtils.compare_stream.
1506
+ #
1507
+ def compare_file(a, b)
1508
+ return false unless File.size(a) == File.size(b)
1509
+ File.open(a, 'rb') {|fa|
1510
+ File.open(b, 'rb') {|fb|
1511
+ return compare_stream(fa, fb)
1512
+ }
1513
+ }
1514
+ end
1515
+ module_function :compare_file
1516
+
1517
+ alias identical? compare_file
1518
+ alias cmp compare_file
1519
+ module_function :identical?
1520
+ module_function :cmp
1521
+
1522
+ # Returns +true+ if the contents of streams +a+ and +b+ are identical,
1523
+ # +false+ otherwise.
1524
+ #
1525
+ # Arguments +a+ and +b+
1526
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
1527
+ #
1528
+ # Related: Bundler::FileUtils.compare_file.
1529
+ #
1530
+ def compare_stream(a, b)
1531
+ bsize = fu_stream_blksize(a, b)
1532
+
1533
+ sa = String.new(capacity: bsize)
1534
+ sb = String.new(capacity: bsize)
1535
+
1536
+ begin
1537
+ a.read(bsize, sa)
1538
+ b.read(bsize, sb)
1539
+ return true if sa.empty? && sb.empty?
1540
+ end while sa == sb
1541
+ false
1542
+ end
1543
+ module_function :compare_stream
1544
+
1545
+ # Copies a file entry.
1546
+ # See {install(1)}[https://man7.org/linux/man-pages/man1/install.1.html].
1547
+ #
1548
+ # Arguments +src+ (a single path or an array of paths)
1549
+ # and +dest+ (a single path)
1550
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments];
1551
+ #
1552
+ # If the entry at +dest+ does not exist, copies from +src+ to +dest+:
1553
+ #
1554
+ # File.read('src0.txt') # => "aaa\n"
1555
+ # File.exist?('dest0.txt') # => false
1556
+ # Bundler::FileUtils.install('src0.txt', 'dest0.txt')
1557
+ # File.read('dest0.txt') # => "aaa\n"
1558
+ #
1559
+ # If +dest+ is a file entry, copies from +src+ to +dest+, overwriting:
1560
+ #
1561
+ # File.read('src1.txt') # => "aaa\n"
1562
+ # File.read('dest1.txt') # => "bbb\n"
1563
+ # Bundler::FileUtils.install('src1.txt', 'dest1.txt')
1564
+ # File.read('dest1.txt') # => "aaa\n"
1565
+ #
1566
+ # If +dest+ is a directory entry, copies from +src+ to <tt>dest/src</tt>,
1567
+ # overwriting if necessary:
1568
+ #
1569
+ # File.read('src2.txt') # => "aaa\n"
1570
+ # File.read('dest2/src2.txt') # => "bbb\n"
1571
+ # Bundler::FileUtils.install('src2.txt', 'dest2')
1572
+ # File.read('dest2/src2.txt') # => "aaa\n"
1573
+ #
1574
+ # If +src+ is an array of paths and +dest+ points to a directory,
1575
+ # copies each path +path+ in +src+ to <tt>dest/path</tt>:
1576
+ #
1577
+ # File.file?('src3.txt') # => true
1578
+ # File.file?('src3.dat') # => true
1579
+ # Bundler::FileUtils.mkdir('dest3')
1580
+ # Bundler::FileUtils.install(['src3.txt', 'src3.dat'], 'dest3')
1581
+ # File.file?('dest3/src3.txt') # => true
1582
+ # File.file?('dest3/src3.dat') # => true
1583
+ #
1584
+ # Keyword arguments:
1585
+ #
1586
+ # - <tt>group: <i>group</i></tt> - changes the group if not +nil+,
1587
+ # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown].
1588
+ # - <tt>mode: <i>permissions</i></tt> - changes the permissions.
1589
+ # using {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod].
1590
+ # - <tt>noop: true</tt> - does not copy entries; returns +nil+.
1591
+ # - <tt>owner: <i>owner</i></tt> - changes the owner if not +nil+,
1592
+ # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown].
1593
+ # - <tt>preserve: true</tt> - preserve timestamps
1594
+ # using {File.utime}[https://docs.ruby-lang.org/en/master/File.html#method-c-utime].
1595
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1596
+ #
1597
+ # Bundler::FileUtils.install('src0.txt', 'dest0.txt', noop: true, verbose: true)
1598
+ # Bundler::FileUtils.install('src1.txt', 'dest1.txt', noop: true, verbose: true)
1599
+ # Bundler::FileUtils.install('src2.txt', 'dest2', noop: true, verbose: true)
1600
+ #
1601
+ # Output:
1602
+ #
1603
+ # install -c src0.txt dest0.txt
1604
+ # install -c src1.txt dest1.txt
1605
+ # install -c src2.txt dest2
1606
+ #
1607
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
1608
+ #
1609
+ def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
1610
+ noop: nil, verbose: nil)
1611
+ if verbose
1612
+ msg = +"install -c"
1613
+ msg << ' -p' if preserve
1614
+ msg << ' -m ' << mode_to_s(mode) if mode
1615
+ msg << " -o #{owner}" if owner
1616
+ msg << " -g #{group}" if group
1617
+ msg << ' ' << [src,dest].flatten.join(' ')
1618
+ fu_output_message msg
1619
+ end
1620
+ return if noop
1621
+ uid = fu_get_uid(owner)
1622
+ gid = fu_get_gid(group)
1623
+ fu_each_src_dest(src, dest) do |s, d|
1624
+ st = File.stat(s)
1625
+ unless File.exist?(d) and compare_file(s, d)
1626
+ remove_file d, true
1627
+ if d.end_with?('/')
1628
+ mkdir_p d
1629
+ copy_file s, d + File.basename(s)
1630
+ else
1631
+ mkdir_p File.expand_path('..', d)
1632
+ copy_file s, d
1633
+ end
1634
+ File.utime st.atime, st.mtime, d if preserve
1635
+ File.chmod fu_mode(mode, st), d if mode
1636
+ File.chown uid, gid, d if uid or gid
1637
+ end
1638
+ end
1639
+ end
1640
+ module_function :install
1641
+
1642
+ def user_mask(target) #:nodoc:
1643
+ target.each_char.inject(0) do |mask, chr|
1644
+ case chr
1645
+ when "u"
1646
+ mask | 04700
1647
+ when "g"
1648
+ mask | 02070
1649
+ when "o"
1650
+ mask | 01007
1651
+ when "a"
1652
+ mask | 07777
1653
+ else
1654
+ raise ArgumentError, "invalid `who' symbol in file mode: #{chr}"
1655
+ end
1656
+ end
1657
+ end
1658
+ private_module_function :user_mask
1659
+
1660
+ def apply_mask(mode, user_mask, op, mode_mask) #:nodoc:
1661
+ case op
1662
+ when '='
1663
+ (mode & ~user_mask) | (user_mask & mode_mask)
1664
+ when '+'
1665
+ mode | (user_mask & mode_mask)
1666
+ when '-'
1667
+ mode & ~(user_mask & mode_mask)
1668
+ end
1669
+ end
1670
+ private_module_function :apply_mask
1671
+
1672
+ def symbolic_modes_to_i(mode_sym, path) #:nodoc:
1673
+ path = File.stat(path) unless File::Stat === path
1674
+ mode = path.mode
1675
+ mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause|
1676
+ target, *actions = clause.split(/([=+-])/)
1677
+ raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty?
1678
+ target = 'a' if target.empty?
1679
+ user_mask = user_mask(target)
1680
+ actions.each_slice(2) do |op, perm|
1681
+ need_apply = op == '='
1682
+ mode_mask = (perm || '').each_char.inject(0) do |mask, chr|
1683
+ case chr
1684
+ when "r"
1685
+ mask | 0444
1686
+ when "w"
1687
+ mask | 0222
1688
+ when "x"
1689
+ mask | 0111
1690
+ when "X"
1691
+ if path.directory?
1692
+ mask | 0111
1693
+ else
1694
+ mask
1695
+ end
1696
+ when "s"
1697
+ mask | 06000
1698
+ when "t"
1699
+ mask | 01000
1700
+ when "u", "g", "o"
1701
+ if mask.nonzero?
1702
+ current_mode = apply_mask(current_mode, user_mask, op, mask)
1703
+ end
1704
+ need_apply = false
1705
+ copy_mask = user_mask(chr)
1706
+ (current_mode & copy_mask) / (copy_mask & 0111) * (user_mask & 0111)
1707
+ else
1708
+ raise ArgumentError, "invalid `perm' symbol in file mode: #{chr}"
1709
+ end
1710
+ end
1711
+
1712
+ if mode_mask.nonzero? || need_apply
1713
+ current_mode = apply_mask(current_mode, user_mask, op, mode_mask)
1714
+ end
1715
+ end
1716
+ current_mode
1717
+ end
1718
+ end
1719
+ private_module_function :symbolic_modes_to_i
1720
+
1721
+ def fu_mode(mode, path) #:nodoc:
1722
+ mode.is_a?(String) ? symbolic_modes_to_i(mode, path) : mode
1723
+ end
1724
+ private_module_function :fu_mode
1725
+
1726
+ def mode_to_s(mode) #:nodoc:
1727
+ mode.is_a?(String) ? mode : "%o" % mode
1728
+ end
1729
+ private_module_function :mode_to_s
1730
+
1731
+ # Changes permissions on the entries at the paths given in +list+
1732
+ # (a single path or an array of paths)
1733
+ # to the permissions given by +mode+;
1734
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise:
1735
+ #
1736
+ # - Modifies each entry that is a regular file using
1737
+ # {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod].
1738
+ # - Modifies each entry that is a symbolic link using
1739
+ # {File.lchmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-lchmod].
1740
+ #
1741
+ # Argument +list+ or its elements
1742
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1743
+ #
1744
+ # Argument +mode+ may be either an integer or a string:
1745
+ #
1746
+ # - \Integer +mode+: represents the permission bits to be set:
1747
+ #
1748
+ # Bundler::FileUtils.chmod(0755, 'src0.txt')
1749
+ # Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'])
1750
+ #
1751
+ # - \String +mode+: represents the permissions to be set:
1752
+ #
1753
+ # The string is of the form <tt>[targets][[operator][perms[,perms]]</tt>, where:
1754
+ #
1755
+ # - +targets+ may be any combination of these letters:
1756
+ #
1757
+ # - <tt>'u'</tt>: permissions apply to the file's owner.
1758
+ # - <tt>'g'</tt>: permissions apply to users in the file's group.
1759
+ # - <tt>'o'</tt>: permissions apply to other users not in the file's group.
1760
+ # - <tt>'a'</tt> (the default): permissions apply to all users.
1761
+ #
1762
+ # - +operator+ may be one of these letters:
1763
+ #
1764
+ # - <tt>'+'</tt>: adds permissions.
1765
+ # - <tt>'-'</tt>: removes permissions.
1766
+ # - <tt>'='</tt>: sets (replaces) permissions.
1767
+ #
1768
+ # - +perms+ (may be repeated, with separating commas)
1769
+ # may be any combination of these letters:
1770
+ #
1771
+ # - <tt>'r'</tt>: Read.
1772
+ # - <tt>'w'</tt>: Write.
1773
+ # - <tt>'x'</tt>: Execute (search, for a directory).
1774
+ # - <tt>'X'</tt>: Search (for a directories only;
1775
+ # must be used with <tt>'+'</tt>)
1776
+ # - <tt>'s'</tt>: Uid or gid.
1777
+ # - <tt>'t'</tt>: Sticky bit.
1778
+ #
1779
+ # Examples:
1780
+ #
1781
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt')
1782
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby')
1783
+ #
1784
+ # Keyword arguments:
1785
+ #
1786
+ # - <tt>noop: true</tt> - does not change permissions; returns +nil+.
1787
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1788
+ #
1789
+ # Bundler::FileUtils.chmod(0755, 'src0.txt', noop: true, verbose: true)
1790
+ # Bundler::FileUtils.chmod(0644, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
1791
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', 'src1.txt', noop: true, verbose: true)
1792
+ # Bundler::FileUtils.chmod('u=wrx,go=rx', '/usr/bin/ruby', noop: true, verbose: true)
1793
+ #
1794
+ # Output:
1795
+ #
1796
+ # chmod 755 src0.txt
1797
+ # chmod 644 src0.txt src0.dat
1798
+ # chmod u=wrx,go=rx src1.txt
1799
+ # chmod u=wrx,go=rx /usr/bin/ruby
1800
+ #
1801
+ # Related: Bundler::FileUtils.chmod_R.
1802
+ #
1803
+ def chmod(mode, list, noop: nil, verbose: nil)
1804
+ list = fu_list(list)
1805
+ fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
1806
+ return if noop
1807
+ list.each do |path|
1808
+ Entry_.new(path).chmod(fu_mode(mode, path))
1809
+ end
1810
+ end
1811
+ module_function :chmod
1812
+
1813
+ # Like Bundler::FileUtils.chmod, but changes permissions recursively.
1814
+ #
1815
+ def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
1816
+ list = fu_list(list)
1817
+ fu_output_message sprintf('chmod -R%s %s %s',
1818
+ (force ? 'f' : ''),
1819
+ mode_to_s(mode), list.join(' ')) if verbose
1820
+ return if noop
1821
+ list.each do |root|
1822
+ Entry_.new(root).traverse do |ent|
1823
+ begin
1824
+ ent.chmod(fu_mode(mode, ent.path))
1825
+ rescue
1826
+ raise unless force
1827
+ end
1828
+ end
1829
+ end
1830
+ end
1831
+ module_function :chmod_R
1832
+
1833
+ # Changes the owner and group on the entries at the paths given in +list+
1834
+ # (a single path or an array of paths)
1835
+ # to the given +user+ and +group+;
1836
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise:
1837
+ #
1838
+ # - Modifies each entry that is a regular file using
1839
+ # {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown].
1840
+ # - Modifies each entry that is a symbolic link using
1841
+ # {File.lchown}[https://docs.ruby-lang.org/en/master/File.html#method-c-lchown].
1842
+ #
1843
+ # Argument +list+ or its elements
1844
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1845
+ #
1846
+ # User and group:
1847
+ #
1848
+ # - Argument +user+ may be a user name or a user id;
1849
+ # if +nil+ or +-1+, the user is not changed.
1850
+ # - Argument +group+ may be a group name or a group id;
1851
+ # if +nil+ or +-1+, the group is not changed.
1852
+ # - The user must be a member of the group.
1853
+ #
1854
+ # Examples:
1855
+ #
1856
+ # # One path.
1857
+ # # User and group as string names.
1858
+ # File.stat('src0.txt').uid # => 1004
1859
+ # File.stat('src0.txt').gid # => 1004
1860
+ # Bundler::FileUtils.chown('user2', 'group1', 'src0.txt')
1861
+ # File.stat('src0.txt').uid # => 1006
1862
+ # File.stat('src0.txt').gid # => 1005
1863
+ #
1864
+ # # User and group as uid and gid.
1865
+ # Bundler::FileUtils.chown(1004, 1004, 'src0.txt')
1866
+ # File.stat('src0.txt').uid # => 1004
1867
+ # File.stat('src0.txt').gid # => 1004
1868
+ #
1869
+ # # Array of paths.
1870
+ # Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'])
1871
+ #
1872
+ # # Directory (not recursive).
1873
+ # Bundler::FileUtils.chown('user2', 'group1', '.')
1874
+ #
1875
+ # Keyword arguments:
1876
+ #
1877
+ # - <tt>noop: true</tt> - does not change permissions; returns +nil+.
1878
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1879
+ #
1880
+ # Bundler::FileUtils.chown('user2', 'group1', 'src0.txt', noop: true, verbose: true)
1881
+ # Bundler::FileUtils.chown(1004, 1004, 'src0.txt', noop: true, verbose: true)
1882
+ # Bundler::FileUtils.chown(1006, 1005, ['src0.txt', 'src0.dat'], noop: true, verbose: true)
1883
+ # Bundler::FileUtils.chown('user2', 'group1', path, noop: true, verbose: true)
1884
+ # Bundler::FileUtils.chown('user2', 'group1', '.', noop: true, verbose: true)
1885
+ #
1886
+ # Output:
1887
+ #
1888
+ # chown user2:group1 src0.txt
1889
+ # chown 1004:1004 src0.txt
1890
+ # chown 1006:1005 src0.txt src0.dat
1891
+ # chown user2:group1 src0.txt
1892
+ # chown user2:group1 .
1893
+ #
1894
+ # Related: Bundler::FileUtils.chown_R.
1895
+ #
1896
+ def chown(user, group, list, noop: nil, verbose: nil)
1897
+ list = fu_list(list)
1898
+ fu_output_message sprintf('chown %s %s',
1899
+ (group ? "#{user}:#{group}" : user || ':'),
1900
+ list.join(' ')) if verbose
1901
+ return if noop
1902
+ uid = fu_get_uid(user)
1903
+ gid = fu_get_gid(group)
1904
+ list.each do |path|
1905
+ Entry_.new(path).chown uid, gid
1906
+ end
1907
+ end
1908
+ module_function :chown
1909
+
1910
+ # Like Bundler::FileUtils.chown, but changes owner and group recursively.
1911
+ #
1912
+ def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
1913
+ list = fu_list(list)
1914
+ fu_output_message sprintf('chown -R%s %s %s',
1915
+ (force ? 'f' : ''),
1916
+ (group ? "#{user}:#{group}" : user || ':'),
1917
+ list.join(' ')) if verbose
1918
+ return if noop
1919
+ uid = fu_get_uid(user)
1920
+ gid = fu_get_gid(group)
1921
+ list.each do |root|
1922
+ Entry_.new(root).traverse do |ent|
1923
+ begin
1924
+ ent.chown uid, gid
1925
+ rescue
1926
+ raise unless force
1927
+ end
1928
+ end
1929
+ end
1930
+ end
1931
+ module_function :chown_R
1932
+
1933
+ def fu_get_uid(user) #:nodoc:
1934
+ return nil unless user
1935
+ case user
1936
+ when Integer
1937
+ user
1938
+ when /\A\d+\z/
1939
+ user.to_i
1940
+ else
1941
+ require 'etc'
1942
+ Etc.getpwnam(user) ? Etc.getpwnam(user).uid : nil
1943
+ end
1944
+ end
1945
+ private_module_function :fu_get_uid
1946
+
1947
+ def fu_get_gid(group) #:nodoc:
1948
+ return nil unless group
1949
+ case group
1950
+ when Integer
1951
+ group
1952
+ when /\A\d+\z/
1953
+ group.to_i
1954
+ else
1955
+ require 'etc'
1956
+ Etc.getgrnam(group) ? Etc.getgrnam(group).gid : nil
1957
+ end
1958
+ end
1959
+ private_module_function :fu_get_gid
1960
+
1961
+ # Updates modification times (mtime) and access times (atime)
1962
+ # of the entries given by the paths in +list+
1963
+ # (a single path or an array of paths);
1964
+ # returns +list+ if it is an array, <tt>[list]</tt> otherwise.
1965
+ #
1966
+ # By default, creates an empty file for any path to a non-existent entry;
1967
+ # use keyword argument +nocreate+ to raise an exception instead.
1968
+ #
1969
+ # Argument +list+ or its elements
1970
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
1971
+ #
1972
+ # Examples:
1973
+ #
1974
+ # # Single path.
1975
+ # f = File.new('src0.txt') # Existing file.
1976
+ # f.atime # => 2022-06-10 11:11:21.200277 -0700
1977
+ # f.mtime # => 2022-06-10 11:11:21.200277 -0700
1978
+ # Bundler::FileUtils.touch('src0.txt')
1979
+ # f = File.new('src0.txt')
1980
+ # f.atime # => 2022-06-11 08:28:09.8185343 -0700
1981
+ # f.mtime # => 2022-06-11 08:28:09.8185343 -0700
1982
+ #
1983
+ # # Array of paths.
1984
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'])
1985
+ #
1986
+ # Keyword arguments:
1987
+ #
1988
+ # - <tt>mtime: <i>time</i></tt> - sets the entry's mtime to the given time,
1989
+ # instead of the current time.
1990
+ # - <tt>nocreate: true</tt> - raises an exception if the entry does not exist.
1991
+ # - <tt>noop: true</tt> - does not touch entries; returns +nil+.
1992
+ # - <tt>verbose: true</tt> - prints an equivalent command:
1993
+ #
1994
+ # Bundler::FileUtils.touch('src0.txt', noop: true, verbose: true)
1995
+ # Bundler::FileUtils.touch(['src0.txt', 'src0.dat'], noop: true, verbose: true)
1996
+ # Bundler::FileUtils.touch(path, noop: true, verbose: true)
1997
+ #
1998
+ # Output:
1999
+ #
2000
+ # touch src0.txt
2001
+ # touch src0.txt src0.dat
2002
+ # touch src0.txt
2003
+ #
2004
+ # Related: Bundler::FileUtils.uptodate?.
2005
+ #
2006
+ def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
2007
+ list = fu_list(list)
2008
+ t = mtime
2009
+ if verbose
2010
+ fu_output_message "touch #{nocreate ? '-c ' : ''}#{t ? t.strftime('-t %Y%m%d%H%M.%S ') : ''}#{list.join ' '}"
2011
+ end
2012
+ return if noop
2013
+ list.each do |path|
2014
+ created = nocreate
2015
+ begin
2016
+ File.utime(t, t, path)
2017
+ rescue Errno::ENOENT
2018
+ raise if created
2019
+ File.open(path, 'a') {
2020
+ ;
2021
+ }
2022
+ created = true
2023
+ retry if t
2024
+ end
2025
+ end
2026
+ end
2027
+ module_function :touch
2028
+
2029
+ private
2030
+
2031
+ module StreamUtils_
2032
+ private
2033
+
2034
+ case (defined?(::RbConfig) ? ::RbConfig::CONFIG['host_os'] : ::RUBY_PLATFORM)
2035
+ when /mswin|mingw/
2036
+ def fu_windows?; true end
2037
+ else
2038
+ def fu_windows?; false end
2039
+ end
2040
+
2041
+ def fu_copy_stream0(src, dest, blksize = nil) #:nodoc:
2042
+ IO.copy_stream(src, dest)
2043
+ end
2044
+
2045
+ def fu_stream_blksize(*streams)
2046
+ streams.each do |s|
2047
+ next unless s.respond_to?(:stat)
2048
+ size = fu_blksize(s.stat)
2049
+ return size if size
2050
+ end
2051
+ fu_default_blksize()
2052
+ end
2053
+
2054
+ def fu_blksize(st)
2055
+ s = st.blksize
2056
+ return nil unless s
2057
+ return nil if s == 0
2058
+ s
2059
+ end
2060
+
2061
+ def fu_default_blksize
2062
+ 1024
2063
+ end
2064
+ end
2065
+
2066
+ include StreamUtils_
2067
+ extend StreamUtils_
2068
+
2069
+ class Entry_ #:nodoc: internal use only
2070
+ include StreamUtils_
2071
+
2072
+ def initialize(a, b = nil, deref = false)
2073
+ @prefix = @rel = @path = nil
2074
+ if b
2075
+ @prefix = a
2076
+ @rel = b
2077
+ else
2078
+ @path = a
2079
+ end
2080
+ @deref = deref
2081
+ @stat = nil
2082
+ @lstat = nil
2083
+ end
2084
+
2085
+ def inspect
2086
+ "\#<#{self.class} #{path()}>"
2087
+ end
2088
+
2089
+ def path
2090
+ if @path
2091
+ File.path(@path)
2092
+ else
2093
+ join(@prefix, @rel)
2094
+ end
2095
+ end
2096
+
2097
+ def prefix
2098
+ @prefix || @path
2099
+ end
2100
+
2101
+ def rel
2102
+ @rel
2103
+ end
2104
+
2105
+ def dereference?
2106
+ @deref
2107
+ end
2108
+
2109
+ def exist?
2110
+ begin
2111
+ lstat
2112
+ true
2113
+ rescue Errno::ENOENT
2114
+ false
2115
+ end
2116
+ end
2117
+
2118
+ def file?
2119
+ s = lstat!
2120
+ s and s.file?
2121
+ end
2122
+
2123
+ def directory?
2124
+ s = lstat!
2125
+ s and s.directory?
2126
+ end
2127
+
2128
+ def symlink?
2129
+ s = lstat!
2130
+ s and s.symlink?
2131
+ end
2132
+
2133
+ def chardev?
2134
+ s = lstat!
2135
+ s and s.chardev?
2136
+ end
2137
+
2138
+ def blockdev?
2139
+ s = lstat!
2140
+ s and s.blockdev?
2141
+ end
2142
+
2143
+ def socket?
2144
+ s = lstat!
2145
+ s and s.socket?
2146
+ end
2147
+
2148
+ def pipe?
2149
+ s = lstat!
2150
+ s and s.pipe?
2151
+ end
2152
+
2153
+ S_IF_DOOR = 0xD000
2154
+
2155
+ def door?
2156
+ s = lstat!
2157
+ s and (s.mode & 0xF000 == S_IF_DOOR)
2158
+ end
2159
+
2160
+ def entries
2161
+ opts = {}
2162
+ opts[:encoding] = fu_windows? ? ::Encoding::UTF_8 : path.encoding
2163
+
2164
+ files = Dir.children(path, **opts)
2165
+
2166
+ untaint = RUBY_VERSION < '2.7'
2167
+ files.map {|n| Entry_.new(prefix(), join(rel(), untaint ? n.untaint : n)) }
2168
+ end
2169
+
2170
+ def stat
2171
+ return @stat if @stat
2172
+ if lstat() and lstat().symlink?
2173
+ @stat = File.stat(path())
2174
+ else
2175
+ @stat = lstat()
2176
+ end
2177
+ @stat
2178
+ end
2179
+
2180
+ def stat!
2181
+ return @stat if @stat
2182
+ if lstat! and lstat!.symlink?
2183
+ @stat = File.stat(path())
2184
+ else
2185
+ @stat = lstat!
2186
+ end
2187
+ @stat
2188
+ rescue SystemCallError
2189
+ nil
2190
+ end
2191
+
2192
+ def lstat
2193
+ if dereference?
2194
+ @lstat ||= File.stat(path())
2195
+ else
2196
+ @lstat ||= File.lstat(path())
2197
+ end
2198
+ end
2199
+
2200
+ def lstat!
2201
+ lstat()
2202
+ rescue SystemCallError
2203
+ nil
2204
+ end
2205
+
2206
+ def chmod(mode)
2207
+ if symlink?
2208
+ File.lchmod mode, path() if have_lchmod?
2209
+ else
2210
+ File.chmod mode, path()
2211
+ end
2212
+ rescue Errno::EOPNOTSUPP
2213
+ end
2214
+
2215
+ def chown(uid, gid)
2216
+ if symlink?
2217
+ File.lchown uid, gid, path() if have_lchown?
2218
+ else
2219
+ File.chown uid, gid, path()
2220
+ end
2221
+ end
2222
+
2223
+ def link(dest)
2224
+ case
2225
+ when directory?
2226
+ if !File.exist?(dest) and descendant_directory?(dest, path)
2227
+ raise ArgumentError, "cannot link directory %s to itself %s" % [path, dest]
2228
+ end
2229
+ begin
2230
+ Dir.mkdir dest
2231
+ rescue
2232
+ raise unless File.directory?(dest)
2233
+ end
2234
+ else
2235
+ File.link path(), dest
2236
+ end
2237
+ end
2238
+
2239
+ def copy(dest)
2240
+ lstat
2241
+ case
2242
+ when file?
2243
+ copy_file dest
2244
+ when directory?
2245
+ if !File.exist?(dest) and descendant_directory?(dest, path)
2246
+ raise ArgumentError, "cannot copy directory %s to itself %s" % [path, dest]
2247
+ end
2248
+ begin
2249
+ Dir.mkdir dest
2250
+ rescue
2251
+ raise unless File.directory?(dest)
2252
+ end
2253
+ when symlink?
2254
+ File.symlink File.readlink(path()), dest
2255
+ when chardev?, blockdev?
2256
+ raise "cannot handle device file"
2257
+ when socket?
2258
+ begin
2259
+ require 'socket'
2260
+ rescue LoadError
2261
+ raise "cannot handle socket"
2262
+ else
2263
+ raise "cannot handle socket" unless defined?(UNIXServer)
2264
+ end
2265
+ UNIXServer.new(dest).close
2266
+ File.chmod lstat().mode, dest
2267
+ when pipe?
2268
+ raise "cannot handle FIFO" unless File.respond_to?(:mkfifo)
2269
+ File.mkfifo dest, lstat().mode
2270
+ when door?
2271
+ raise "cannot handle door: #{path()}"
2272
+ else
2273
+ raise "unknown file type: #{path()}"
2274
+ end
2275
+ end
2276
+
2277
+ def copy_file(dest)
2278
+ File.open(path()) do |s|
2279
+ File.open(dest, 'wb', s.stat.mode) do |f|
2280
+ IO.copy_stream(s, f)
2281
+ end
2282
+ end
2283
+ end
2284
+
2285
+ def copy_metadata(path)
2286
+ st = lstat()
2287
+ if !st.symlink?
2288
+ File.utime st.atime, st.mtime, path
2289
+ end
2290
+ mode = st.mode
2291
+ begin
2292
+ if st.symlink?
2293
+ begin
2294
+ File.lchown st.uid, st.gid, path
2295
+ rescue NotImplementedError
2296
+ end
2297
+ else
2298
+ File.chown st.uid, st.gid, path
2299
+ end
2300
+ rescue Errno::EPERM, Errno::EACCES
2301
+ # clear setuid/setgid
2302
+ mode &= 01777
2303
+ end
2304
+ if st.symlink?
2305
+ begin
2306
+ File.lchmod mode, path
2307
+ rescue NotImplementedError, Errno::EOPNOTSUPP
2308
+ end
2309
+ else
2310
+ File.chmod mode, path
2311
+ end
2312
+ end
2313
+
2314
+ def remove
2315
+ if directory?
2316
+ remove_dir1
2317
+ else
2318
+ remove_file
2319
+ end
2320
+ end
2321
+
2322
+ def remove_dir1
2323
+ platform_support {
2324
+ Dir.rmdir path().chomp(?/)
2325
+ }
2326
+ end
2327
+
2328
+ def remove_file
2329
+ platform_support {
2330
+ File.unlink path
2331
+ }
2332
+ end
2333
+
2334
+ def platform_support
2335
+ return yield unless fu_windows?
2336
+ first_time_p = true
2337
+ begin
2338
+ yield
2339
+ rescue Errno::ENOENT
2340
+ raise
2341
+ rescue => err
2342
+ if first_time_p
2343
+ first_time_p = false
2344
+ begin
2345
+ File.chmod 0700, path() # Windows does not have symlink
2346
+ retry
2347
+ rescue SystemCallError
2348
+ end
2349
+ end
2350
+ raise err
2351
+ end
2352
+ end
2353
+
2354
+ def preorder_traverse
2355
+ stack = [self]
2356
+ while ent = stack.pop
2357
+ yield ent
2358
+ stack.concat ent.entries.reverse if ent.directory?
2359
+ end
2360
+ end
2361
+
2362
+ alias traverse preorder_traverse
2363
+
2364
+ def postorder_traverse
2365
+ if directory?
2366
+ begin
2367
+ children = entries()
2368
+ rescue Errno::EACCES
2369
+ # Failed to get the list of children.
2370
+ # Assuming there is no children, try to process the parent directory.
2371
+ yield self
2372
+ return
2373
+ end
2374
+
2375
+ children.each do |ent|
2376
+ ent.postorder_traverse do |e|
2377
+ yield e
2378
+ end
2379
+ end
2380
+ end
2381
+ yield self
2382
+ end
2383
+
2384
+ def wrap_traverse(pre, post)
2385
+ pre.call self
2386
+ if directory?
2387
+ entries.each do |ent|
2388
+ ent.wrap_traverse pre, post
2389
+ end
2390
+ end
2391
+ post.call self
2392
+ end
2393
+
2394
+ private
2395
+
2396
+ @@fileutils_rb_have_lchmod = nil
2397
+
2398
+ def have_lchmod?
2399
+ # This is not MT-safe, but it does not matter.
2400
+ if @@fileutils_rb_have_lchmod == nil
2401
+ @@fileutils_rb_have_lchmod = check_have_lchmod?
2402
+ end
2403
+ @@fileutils_rb_have_lchmod
2404
+ end
2405
+
2406
+ def check_have_lchmod?
2407
+ return false unless File.respond_to?(:lchmod)
2408
+ File.lchmod 0
2409
+ return true
2410
+ rescue NotImplementedError
2411
+ return false
2412
+ end
2413
+
2414
+ @@fileutils_rb_have_lchown = nil
2415
+
2416
+ def have_lchown?
2417
+ # This is not MT-safe, but it does not matter.
2418
+ if @@fileutils_rb_have_lchown == nil
2419
+ @@fileutils_rb_have_lchown = check_have_lchown?
2420
+ end
2421
+ @@fileutils_rb_have_lchown
2422
+ end
2423
+
2424
+ def check_have_lchown?
2425
+ return false unless File.respond_to?(:lchown)
2426
+ File.lchown nil, nil
2427
+ return true
2428
+ rescue NotImplementedError
2429
+ return false
2430
+ end
2431
+
2432
+ def join(dir, base)
2433
+ return File.path(dir) if not base or base == '.'
2434
+ return File.path(base) if not dir or dir == '.'
2435
+ begin
2436
+ File.join(dir, base)
2437
+ rescue EncodingError
2438
+ if fu_windows?
2439
+ File.join(dir.encode(::Encoding::UTF_8), base.encode(::Encoding::UTF_8))
2440
+ else
2441
+ raise
2442
+ end
2443
+ end
2444
+ end
2445
+
2446
+ if File::ALT_SEPARATOR
2447
+ DIRECTORY_TERM = "(?=[/#{Regexp.quote(File::ALT_SEPARATOR)}]|\\z)"
2448
+ else
2449
+ DIRECTORY_TERM = "(?=/|\\z)"
2450
+ end
2451
+
2452
+ def descendant_directory?(descendant, ascendant)
2453
+ if File::FNM_SYSCASE.nonzero?
2454
+ File.expand_path(File.dirname(descendant)).casecmp(File.expand_path(ascendant)) == 0
2455
+ else
2456
+ File.expand_path(File.dirname(descendant)) == File.expand_path(ascendant)
2457
+ end
2458
+ end
2459
+ end # class Entry_
2460
+
2461
+ def fu_list(arg) #:nodoc:
2462
+ [arg].flatten.map {|path| File.path(path) }
2463
+ end
2464
+ private_module_function :fu_list
2465
+
2466
+ def fu_each_src_dest(src, dest) #:nodoc:
2467
+ fu_each_src_dest0(src, dest) do |s, d|
2468
+ raise ArgumentError, "same file: #{s} and #{d}" if fu_same?(s, d)
2469
+ yield s, d
2470
+ end
2471
+ end
2472
+ private_module_function :fu_each_src_dest
2473
+
2474
+ def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
2475
+ if tmp = Array.try_convert(src)
2476
+ tmp.each do |s|
2477
+ s = File.path(s)
2478
+ yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
2479
+ end
2480
+ else
2481
+ src = File.path(src)
2482
+ if target_directory and File.directory?(dest)
2483
+ yield src, File.join(dest, File.basename(src))
2484
+ else
2485
+ yield src, File.path(dest)
2486
+ end
2487
+ end
2488
+ end
2489
+ private_module_function :fu_each_src_dest0
2490
+
2491
+ def fu_same?(a, b) #:nodoc:
2492
+ File.identical?(a, b)
2493
+ end
2494
+ private_module_function :fu_same?
2495
+
2496
+ def fu_output_message(msg) #:nodoc:
2497
+ output = @fileutils_output if defined?(@fileutils_output)
2498
+ output ||= $stdout
2499
+ if defined?(@fileutils_label)
2500
+ msg = @fileutils_label + msg
2501
+ end
2502
+ output.puts msg
2503
+ end
2504
+ private_module_function :fu_output_message
2505
+
2506
+ def fu_split_path(path)
2507
+ path = File.path(path)
2508
+ list = []
2509
+ until (parent, base = File.split(path); parent == path or parent == ".")
2510
+ list << base
2511
+ path = parent
2512
+ end
2513
+ list << path
2514
+ list.reverse!
2515
+ end
2516
+ private_module_function :fu_split_path
2517
+
2518
+ def fu_relative_components_from(target, base) #:nodoc:
2519
+ i = 0
2520
+ while target[i]&.== base[i]
2521
+ i += 1
2522
+ end
2523
+ Array.new(base.size-i, '..').concat(target[i..-1])
2524
+ end
2525
+ private_module_function :fu_relative_components_from
2526
+
2527
+ def fu_clean_components(*comp)
2528
+ comp.shift while comp.first == "."
2529
+ return comp if comp.empty?
2530
+ clean = [comp.shift]
2531
+ path = File.join(*clean, "") # ending with File::SEPARATOR
2532
+ while c = comp.shift
2533
+ if c == ".." and clean.last != ".." and !(fu_have_symlink? && File.symlink?(path))
2534
+ clean.pop
2535
+ path.chomp!(%r((?<=\A|/)[^/]+/\z), "")
2536
+ else
2537
+ clean << c
2538
+ path << c << "/"
2539
+ end
2540
+ end
2541
+ clean
2542
+ end
2543
+ private_module_function :fu_clean_components
2544
+
2545
+ if fu_windows?
2546
+ def fu_starting_path?(path)
2547
+ path&.start_with?(%r(\w:|/))
2548
+ end
2549
+ else
2550
+ def fu_starting_path?(path)
2551
+ path&.start_with?("/")
2552
+ end
2553
+ end
2554
+ private_module_function :fu_starting_path?
2555
+
2556
+ # This hash table holds command options.
2557
+ OPT_TABLE = {} #:nodoc: internal use only
2558
+ (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name|
2559
+ (tbl[name.to_s] = instance_method(name).parameters).map! {|t, n| n if t == :key}.compact!
2560
+ tbl
2561
+ }
2562
+
2563
+ public
2564
+
2565
+ # Returns an array of the string names of \Bundler::FileUtils methods
2566
+ # that accept one or more keyword arguments:
2567
+ #
2568
+ # Bundler::FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]
2569
+ #
2570
+ def self.commands
2571
+ OPT_TABLE.keys
2572
+ end
2573
+
2574
+ # Returns an array of the string keyword names:
2575
+ #
2576
+ # Bundler::FileUtils.options.take(3) # => ["noop", "verbose", "force"]
2577
+ #
2578
+ def self.options
2579
+ OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
2580
+ end
2581
+
2582
+ # Returns +true+ if method +mid+ accepts the given option +opt+, +false+ otherwise;
2583
+ # the arguments may be strings or symbols:
2584
+ #
2585
+ # Bundler::FileUtils.have_option?(:chmod, :noop) # => true
2586
+ # Bundler::FileUtils.have_option?('chmod', 'secure') # => false
2587
+ #
2588
+ def self.have_option?(mid, opt)
2589
+ li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
2590
+ li.include?(opt)
2591
+ end
2592
+
2593
+ # Returns an array of the string keyword name for method +mid+;
2594
+ # the argument may be a string or a symbol:
2595
+ #
2596
+ # Bundler::FileUtils.options_of(:rm) # => ["force", "noop", "verbose"]
2597
+ # Bundler::FileUtils.options_of('mv') # => ["force", "noop", "verbose", "secure"]
2598
+ #
2599
+ def self.options_of(mid)
2600
+ OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
2601
+ end
2602
+
2603
+ # Returns an array of the string method names of the methods
2604
+ # that accept the given keyword option +opt+;
2605
+ # the argument must be a symbol:
2606
+ #
2607
+ # Bundler::FileUtils.collect_method(:preserve) # => ["cp", "copy", "cp_r", "install"]
2608
+ #
2609
+ def self.collect_method(opt)
2610
+ OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }
2611
+ end
2612
+
2613
+ private
2614
+
2615
+ LOW_METHODS = singleton_methods(false) - collect_method(:noop).map(&:intern) # :nodoc:
2616
+ module LowMethods # :nodoc: internal use only
2617
+ private
2618
+ def _do_nothing(*)end
2619
+ ::Bundler::FileUtils::LOW_METHODS.map {|name| alias_method name, :_do_nothing}
2620
+ end
2621
+
2622
+ METHODS = singleton_methods() - [:private_module_function, # :nodoc:
2623
+ :commands, :options, :have_option?, :options_of, :collect_method]
2624
+
2625
+ #
2626
+ # This module has all methods of Bundler::FileUtils module, but it outputs messages
2627
+ # before acting. This equates to passing the <tt>:verbose</tt> flag to
2628
+ # methods in Bundler::FileUtils.
2629
+ #
2630
+ module Verbose
2631
+ include Bundler::FileUtils
2632
+ names = ::Bundler::FileUtils.collect_method(:verbose)
2633
+ names.each do |name|
2634
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
2635
+ def #{name}(*args, **options)
2636
+ super(*args, **options, verbose: true)
2637
+ end
2638
+ EOS
2639
+ end
2640
+ private(*names)
2641
+ extend self
2642
+ class << self
2643
+ public(*::Bundler::FileUtils::METHODS)
2644
+ end
2645
+ end
2646
+
2647
+ #
2648
+ # This module has all methods of Bundler::FileUtils module, but never changes
2649
+ # files/directories. This equates to passing the <tt>:noop</tt> flag
2650
+ # to methods in Bundler::FileUtils.
2651
+ #
2652
+ module NoWrite
2653
+ include Bundler::FileUtils
2654
+ include LowMethods
2655
+ names = ::Bundler::FileUtils.collect_method(:noop)
2656
+ names.each do |name|
2657
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
2658
+ def #{name}(*args, **options)
2659
+ super(*args, **options, noop: true)
2660
+ end
2661
+ EOS
2662
+ end
2663
+ private(*names)
2664
+ extend self
2665
+ class << self
2666
+ public(*::Bundler::FileUtils::METHODS)
2667
+ end
2668
+ end
2669
+
2670
+ #
2671
+ # This module has all methods of Bundler::FileUtils module, but never changes
2672
+ # files/directories, with printing message before acting.
2673
+ # This equates to passing the <tt>:noop</tt> and <tt>:verbose</tt> flag
2674
+ # to methods in Bundler::FileUtils.
2675
+ #
2676
+ module DryRun
2677
+ include Bundler::FileUtils
2678
+ include LowMethods
2679
+ names = ::Bundler::FileUtils.collect_method(:noop)
2680
+ names.each do |name|
2681
+ module_eval(<<-EOS, __FILE__, __LINE__ + 1)
2682
+ def #{name}(*args, **options)
2683
+ super(*args, **options, noop: true, verbose: true)
2684
+ end
2685
+ EOS
2686
+ end
2687
+ private(*names)
2688
+ extend self
2689
+ class << self
2690
+ public(*::Bundler::FileUtils::METHODS)
2691
+ end
2692
+ end
2693
+
2694
+ end