bundler 2.2.29 → 2.5.16

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 (330) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1129 -4
  3. data/README.md +4 -8
  4. data/bundler.gemspec +11 -11
  5. data/exe/bundle +5 -26
  6. data/exe/bundler +1 -1
  7. data/lib/bundler/.document +1 -0
  8. data/lib/bundler/build_metadata.rb +4 -4
  9. data/lib/bundler/capistrano.rb +1 -1
  10. data/lib/bundler/checksum.rb +254 -0
  11. data/lib/bundler/ci_detector.rb +75 -0
  12. data/lib/bundler/cli/add.rb +4 -4
  13. data/lib/bundler/cli/binstubs.rb +10 -6
  14. data/lib/bundler/cli/cache.rb +1 -1
  15. data/lib/bundler/cli/check.rb +3 -3
  16. data/lib/bundler/cli/common.rb +13 -3
  17. data/lib/bundler/cli/config.rb +18 -8
  18. data/lib/bundler/cli/console.rb +5 -4
  19. data/lib/bundler/cli/doctor.rb +12 -5
  20. data/lib/bundler/cli/exec.rb +1 -1
  21. data/lib/bundler/cli/fund.rb +1 -1
  22. data/lib/bundler/cli/gem.rb +141 -48
  23. data/lib/bundler/cli/info.rb +27 -17
  24. data/lib/bundler/cli/init.rb +6 -2
  25. data/lib/bundler/cli/install.rb +22 -39
  26. data/lib/bundler/cli/issue.rb +5 -4
  27. data/lib/bundler/cli/lock.rb +36 -29
  28. data/lib/bundler/cli/open.rb +9 -9
  29. data/lib/bundler/cli/outdated.rb +19 -12
  30. data/lib/bundler/cli/platform.rb +8 -6
  31. data/lib/bundler/cli/plugin.rb +9 -15
  32. data/lib/bundler/cli/pristine.rb +38 -30
  33. data/lib/bundler/cli/show.rb +3 -3
  34. data/lib/bundler/cli/update.rb +12 -7
  35. data/lib/bundler/cli/viz.rb +1 -1
  36. data/lib/bundler/cli.rb +266 -285
  37. data/lib/bundler/compact_index_client/cache.rb +53 -67
  38. data/lib/bundler/compact_index_client/cache_file.rb +153 -0
  39. data/lib/bundler/compact_index_client/gem_parser.rb +7 -3
  40. data/lib/bundler/compact_index_client/parser.rb +84 -0
  41. data/lib/bundler/compact_index_client/updater.rb +83 -76
  42. data/lib/bundler/compact_index_client.rb +59 -87
  43. data/lib/bundler/constants.rb +9 -2
  44. data/lib/bundler/current_ruby.rb +12 -16
  45. data/lib/bundler/definition.rb +509 -319
  46. data/lib/bundler/dependency.rb +33 -71
  47. data/lib/bundler/digest.rb +71 -0
  48. data/lib/bundler/dsl.rb +88 -69
  49. data/lib/bundler/endpoint_specification.rb +32 -15
  50. data/lib/bundler/env.rb +5 -7
  51. data/lib/bundler/environment_preserver.rb +8 -22
  52. data/lib/bundler/errors.rb +101 -13
  53. data/lib/bundler/feature_flag.rb +0 -2
  54. data/lib/bundler/fetcher/base.rb +11 -11
  55. data/lib/bundler/fetcher/compact_index.rb +32 -52
  56. data/lib/bundler/fetcher/dependency.rb +3 -7
  57. data/lib/bundler/fetcher/downloader.rb +17 -16
  58. data/lib/bundler/fetcher/gem_remote_fetcher.rb +16 -0
  59. data/lib/bundler/fetcher/index.rb +2 -29
  60. data/lib/bundler/fetcher.rb +87 -79
  61. data/lib/bundler/force_platform.rb +18 -0
  62. data/lib/bundler/friendly_errors.rb +29 -40
  63. data/lib/bundler/gem_helper.rb +11 -23
  64. data/lib/bundler/gem_helpers.rb +30 -6
  65. data/lib/bundler/gem_version_promoter.rb +68 -109
  66. data/lib/bundler/graph.rb +9 -9
  67. data/lib/bundler/index.rb +71 -79
  68. data/lib/bundler/injector.rb +23 -11
  69. data/lib/bundler/inline.rb +11 -23
  70. data/lib/bundler/installer/gem_installer.rb +18 -11
  71. data/lib/bundler/installer/parallel_installer.rb +17 -65
  72. data/lib/bundler/installer/standalone.rb +56 -15
  73. data/lib/bundler/installer.rb +35 -61
  74. data/lib/bundler/lazy_specification.rb +92 -61
  75. data/lib/bundler/lockfile_generator.rb +12 -3
  76. data/lib/bundler/lockfile_parser.rb +137 -70
  77. data/lib/bundler/man/bundle-add.1 +19 -26
  78. data/lib/bundler/man/bundle-add.1.ronn +16 -4
  79. data/lib/bundler/man/bundle-binstubs.1 +4 -16
  80. data/lib/bundler/man/bundle-cache.1 +9 -24
  81. data/lib/bundler/man/bundle-cache.1.ronn +9 -2
  82. data/lib/bundler/man/bundle-check.1 +5 -12
  83. data/lib/bundler/man/bundle-check.1.ronn +3 -0
  84. data/lib/bundler/man/bundle-clean.1 +4 -11
  85. data/lib/bundler/man/bundle-clean.1.ronn +1 -1
  86. data/lib/bundler/man/bundle-config.1 +47 -224
  87. data/lib/bundler/man/bundle-config.1.ronn +40 -28
  88. data/lib/bundler/man/bundle-console.1 +35 -0
  89. data/lib/bundler/man/bundle-console.1.ronn +44 -0
  90. data/lib/bundler/man/bundle-doctor.1 +4 -18
  91. data/lib/bundler/man/bundle-exec.1 +16 -77
  92. data/lib/bundler/man/bundle-exec.1.ronn +8 -9
  93. data/lib/bundler/man/bundle-gem.1 +45 -72
  94. data/lib/bundler/man/bundle-gem.1.ronn +32 -5
  95. data/lib/bundler/man/bundle-help.1 +9 -0
  96. data/lib/bundler/man/bundle-help.1.ronn +12 -0
  97. data/lib/bundler/man/bundle-info.1 +5 -11
  98. data/lib/bundler/man/bundle-info.1.ronn +3 -3
  99. data/lib/bundler/man/bundle-init.1 +6 -11
  100. data/lib/bundler/man/bundle-init.1.ronn +2 -0
  101. data/lib/bundler/man/bundle-inject.1 +8 -18
  102. data/lib/bundler/man/bundle-inject.1.ronn +3 -1
  103. data/lib/bundler/man/bundle-install.1 +32 -155
  104. data/lib/bundler/man/bundle-install.1.ronn +11 -33
  105. data/lib/bundler/man/bundle-list.1 +4 -19
  106. data/lib/bundler/man/bundle-lock.1 +5 -29
  107. data/lib/bundler/man/bundle-open.1 +18 -18
  108. data/lib/bundler/man/bundle-open.1.ronn +9 -1
  109. data/lib/bundler/man/bundle-outdated.1 +17 -72
  110. data/lib/bundler/man/bundle-outdated.1.ronn +13 -18
  111. data/lib/bundler/man/bundle-platform.1 +16 -28
  112. data/lib/bundler/man/bundle-platform.1.ronn +14 -7
  113. data/lib/bundler/man/bundle-plugin.1 +58 -0
  114. data/lib/bundler/man/bundle-plugin.1.ronn +63 -0
  115. data/lib/bundler/man/bundle-pristine.1 +5 -16
  116. data/lib/bundler/man/bundle-remove.1 +4 -14
  117. data/lib/bundler/man/bundle-show.1 +3 -10
  118. data/lib/bundler/man/bundle-update.1 +19 -138
  119. data/lib/bundler/man/bundle-update.1.ronn +2 -1
  120. data/lib/bundler/man/bundle-version.1 +22 -0
  121. data/lib/bundler/man/bundle-version.1.ronn +24 -0
  122. data/lib/bundler/man/bundle-viz.1 +6 -15
  123. data/lib/bundler/man/bundle-viz.1.ronn +2 -0
  124. data/lib/bundler/man/bundle.1 +17 -51
  125. data/lib/bundler/man/bundle.1.ronn +12 -7
  126. data/lib/bundler/man/gemfile.5 +130 -346
  127. data/lib/bundler/man/gemfile.5.ronn +121 -86
  128. data/lib/bundler/man/index.txt +4 -0
  129. data/lib/bundler/match_metadata.rb +17 -0
  130. data/lib/bundler/match_platform.rb +1 -2
  131. data/lib/bundler/match_remote_metadata.rb +29 -0
  132. data/lib/bundler/mirror.rb +8 -10
  133. data/lib/bundler/plugin/api/source.rb +9 -13
  134. data/lib/bundler/plugin/index.rb +13 -5
  135. data/lib/bundler/plugin/installer/git.rb +0 -4
  136. data/lib/bundler/plugin/installer/path.rb +18 -0
  137. data/lib/bundler/plugin/installer/rubygems.rb +0 -8
  138. data/lib/bundler/plugin/installer.rb +42 -19
  139. data/lib/bundler/plugin/source_list.rb +4 -4
  140. data/lib/bundler/plugin.rb +16 -7
  141. data/lib/bundler/process_lock.rb +1 -1
  142. data/lib/bundler/remote_specification.rb +11 -5
  143. data/lib/bundler/resolver/base.rb +111 -0
  144. data/lib/bundler/resolver/candidate.rb +82 -0
  145. data/lib/bundler/resolver/incompatibility.rb +15 -0
  146. data/lib/bundler/resolver/package.rb +81 -0
  147. data/lib/bundler/resolver/root.rb +25 -0
  148. data/lib/bundler/resolver/spec_group.rb +53 -66
  149. data/lib/bundler/resolver.rb +419 -307
  150. data/lib/bundler/retry.rb +1 -1
  151. data/lib/bundler/ruby_dsl.rb +42 -7
  152. data/lib/bundler/ruby_version.rb +16 -22
  153. data/lib/bundler/rubygems_ext.rb +250 -64
  154. data/lib/bundler/rubygems_gem_installer.rb +90 -64
  155. data/lib/bundler/rubygems_integration.rb +81 -190
  156. data/lib/bundler/runtime.rb +8 -13
  157. data/lib/bundler/safe_marshal.rb +31 -0
  158. data/lib/bundler/self_manager.rb +206 -0
  159. data/lib/bundler/settings.rb +139 -57
  160. data/lib/bundler/setup.rb +13 -1
  161. data/lib/bundler/shared_helpers.rb +67 -36
  162. data/lib/bundler/source/git/git_proxy.rb +285 -82
  163. data/lib/bundler/source/git.rb +81 -41
  164. data/lib/bundler/source/metadata.rb +17 -16
  165. data/lib/bundler/source/path/installer.rb +1 -22
  166. data/lib/bundler/source/path.rb +13 -25
  167. data/lib/bundler/source/rubygems/remote.rb +1 -1
  168. data/lib/bundler/source/rubygems.rb +164 -234
  169. data/lib/bundler/source/rubygems_aggregate.rb +1 -1
  170. data/lib/bundler/source.rb +7 -6
  171. data/lib/bundler/source_list.rb +40 -32
  172. data/lib/bundler/source_map.rb +15 -2
  173. data/lib/bundler/spec_set.rb +156 -46
  174. data/lib/bundler/stub_specification.rb +18 -5
  175. data/lib/bundler/templates/Executable +3 -5
  176. data/lib/bundler/templates/Executable.bundler +7 -12
  177. data/lib/bundler/templates/Executable.standalone +4 -4
  178. data/lib/bundler/templates/Gemfile +0 -2
  179. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +77 -29
  180. data/lib/bundler/templates/newgem/Cargo.toml.tt +7 -0
  181. data/lib/bundler/templates/newgem/Gemfile.tt +8 -2
  182. data/lib/bundler/templates/newgem/README.md.tt +7 -11
  183. data/lib/bundler/templates/newgem/Rakefile.tt +28 -4
  184. data/lib/bundler/templates/newgem/bin/console.tt +0 -4
  185. data/lib/bundler/templates/newgem/circleci/config.yml.tt +12 -0
  186. data/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +15 -0
  187. data/lib/bundler/templates/newgem/ext/newgem/extconf-c.rb.tt +10 -0
  188. data/lib/bundler/templates/newgem/ext/newgem/extconf-rust.rb.tt +6 -0
  189. data/lib/bundler/templates/newgem/ext/newgem/newgem.c.tt +1 -1
  190. data/lib/bundler/templates/newgem/ext/newgem/src/lib.rs.tt +12 -0
  191. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +13 -3
  192. data/lib/bundler/templates/newgem/gitignore.tt +3 -0
  193. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +13 -4
  194. data/lib/bundler/templates/newgem/newgem.gemspec.tt +25 -17
  195. data/lib/bundler/templates/newgem/rubocop.yml.tt +0 -5
  196. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  197. data/lib/bundler/templates/newgem/standard.yml.tt +3 -0
  198. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  199. data/lib/bundler/ui/rg_proxy.rb +1 -1
  200. data/lib/bundler/ui/shell.rb +38 -15
  201. data/lib/bundler/ui/silent.rb +21 -5
  202. data/lib/bundler/uri_credentials_filter.rb +2 -2
  203. data/lib/bundler/uri_normalizer.rb +23 -0
  204. data/lib/bundler/vendor/.document +1 -0
  205. data/lib/bundler/vendor/connection_pool/.document +1 -0
  206. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  207. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  208. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  209. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +56 -0
  210. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +92 -78
  211. data/lib/bundler/vendor/fileutils/.document +1 -0
  212. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  213. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +1340 -410
  214. data/lib/bundler/vendor/net-http-persistent/.document +1 -0
  215. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  216. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +4 -3
  217. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +23 -11
  218. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +1 -1
  219. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +57 -57
  220. data/lib/bundler/vendor/pub_grub/.document +1 -0
  221. data/lib/bundler/vendor/pub_grub/LICENSE.txt +21 -0
  222. data/lib/bundler/vendor/pub_grub/lib/pub_grub/assignment.rb +20 -0
  223. data/lib/bundler/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +189 -0
  224. data/lib/bundler/vendor/pub_grub/lib/pub_grub/failure_writer.rb +182 -0
  225. data/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb +150 -0
  226. data/lib/bundler/vendor/pub_grub/lib/pub_grub/package.rb +43 -0
  227. data/lib/bundler/vendor/pub_grub/lib/pub_grub/partial_solution.rb +121 -0
  228. data/lib/bundler/vendor/pub_grub/lib/pub_grub/rubygems.rb +45 -0
  229. data/lib/bundler/vendor/pub_grub/lib/pub_grub/solve_failure.rb +19 -0
  230. data/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb +61 -0
  231. data/lib/bundler/vendor/pub_grub/lib/pub_grub/term.rb +105 -0
  232. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version.rb +3 -0
  233. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_constraint.rb +129 -0
  234. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_range.rb +411 -0
  235. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_solver.rb +248 -0
  236. data/lib/bundler/vendor/pub_grub/lib/pub_grub/version_union.rb +178 -0
  237. data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +31 -0
  238. data/lib/bundler/vendor/thor/.document +1 -0
  239. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  240. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +3 -2
  241. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +1 -1
  242. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +1 -1
  243. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +12 -14
  244. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +16 -6
  245. data/lib/bundler/vendor/thor/lib/thor/actions.rb +21 -17
  246. data/lib/bundler/vendor/thor/lib/thor/base.rb +140 -14
  247. data/lib/bundler/vendor/thor/lib/thor/command.rb +13 -4
  248. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +10 -0
  249. data/lib/bundler/vendor/thor/lib/thor/error.rb +16 -20
  250. data/lib/bundler/vendor/thor/lib/thor/group.rb +1 -1
  251. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +1 -1
  252. data/lib/bundler/vendor/thor/lib/thor/nested_context.rb +2 -2
  253. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +20 -1
  254. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +33 -17
  255. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +27 -8
  256. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +63 -7
  257. data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +2 -2
  258. data/lib/bundler/vendor/thor/lib/thor/runner.rb +40 -30
  259. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +48 -154
  260. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +1 -46
  261. data/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb +29 -0
  262. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +0 -45
  263. data/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +134 -0
  264. data/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb +42 -0
  265. data/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb +38 -0
  266. data/lib/bundler/vendor/thor/lib/thor/shell.rb +2 -2
  267. data/lib/bundler/vendor/thor/lib/thor/util.rb +9 -8
  268. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  269. data/lib/bundler/vendor/thor/lib/thor.rb +155 -8
  270. data/lib/bundler/vendor/tsort/.document +1 -0
  271. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  272. data/lib/bundler/vendor/tsort/lib/tsort.rb +455 -0
  273. data/lib/bundler/vendor/uri/.document +1 -0
  274. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  275. data/lib/bundler/vendor/uri/lib/uri/common.rb +316 -207
  276. data/lib/bundler/vendor/uri/lib/uri/file.rb +7 -1
  277. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +2 -2
  278. data/lib/bundler/vendor/uri/lib/uri/generic.rb +33 -13
  279. data/lib/bundler/vendor/uri/lib/uri/http.rb +40 -3
  280. data/lib/bundler/vendor/uri/lib/uri/https.rb +2 -2
  281. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +2 -2
  282. data/lib/bundler/vendor/uri/lib/uri/ldaps.rb +2 -1
  283. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +2 -3
  284. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +16 -23
  285. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +105 -47
  286. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  287. data/lib/bundler/vendor/uri/lib/uri/ws.rb +83 -0
  288. data/lib/bundler/vendor/uri/lib/uri/wss.rb +23 -0
  289. data/lib/bundler/vendor/uri/lib/uri.rb +3 -3
  290. data/lib/bundler/vendored_net_http.rb +23 -0
  291. data/lib/bundler/vendored_persistent.rb +0 -36
  292. data/lib/bundler/{vendored_molinillo.rb → vendored_pub_grub.rb} +1 -1
  293. data/lib/bundler/vendored_timeout.rb +12 -0
  294. data/lib/bundler/{vendored_tmpdir.rb → vendored_tsort.rb} +1 -1
  295. data/lib/bundler/vendored_uri.rb +18 -1
  296. data/lib/bundler/version.rb +5 -1
  297. data/lib/bundler/vlad.rb +1 -1
  298. data/lib/bundler/worker.rb +7 -9
  299. data/lib/bundler/yaml_serializer.rb +21 -12
  300. data/lib/bundler.rb +114 -121
  301. metadata +87 -41
  302. data/lib/bundler/dep_proxy.rb +0 -55
  303. data/lib/bundler/gemdeps.rb +0 -29
  304. data/lib/bundler/psyched_yaml.rb +0 -22
  305. data/lib/bundler/templates/gems.rb +0 -8
  306. data/lib/bundler/templates/newgem/ext/newgem/extconf.rb.tt +0 -5
  307. data/lib/bundler/templates/newgem/travis.yml.tt +0 -6
  308. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
  309. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/resolution_state.rb +0 -57
  310. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +0 -88
  311. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/action.rb +0 -36
  312. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_edge_no_circular.rb +0 -66
  313. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/add_vertex.rb +0 -62
  314. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/delete_edge.rb +0 -63
  315. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/detach_vertex_named.rb +0 -61
  316. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/log.rb +0 -126
  317. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/set_payload.rb +0 -46
  318. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/tag.rb +0 -36
  319. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +0 -164
  320. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +0 -255
  321. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +0 -143
  322. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +0 -6
  323. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +0 -112
  324. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/ui.rb +0 -67
  325. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +0 -839
  326. data/lib/bundler/vendor/molinillo/lib/molinillo/resolver.rb +0 -46
  327. data/lib/bundler/vendor/molinillo/lib/molinillo/state.rb +0 -58
  328. data/lib/bundler/vendor/molinillo/lib/molinillo.rb +0 -11
  329. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +0 -154
  330. data/lib/bundler/version_ranges.rb +0 -122
@@ -3,106 +3,184 @@
3
3
  begin
4
4
  require 'rbconfig'
5
5
  rescue LoadError
6
- # for make mjit-headers
6
+ # for make rjit-headers
7
7
  end
8
8
 
9
+ # Namespace for file utility methods for copying, moving, removing, etc.
9
10
  #
10
- # = fileutils.rb
11
+ # == What's Here
11
12
  #
12
- # Copyright (c) 2000-2007 Minero Aoki
13
+ # First, what’s elsewhere. \Module \Bundler::FileUtils:
13
14
  #
14
- # This program is free software.
15
- # You can distribute/modify this program under the same terms of ruby.
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).
16
18
  #
17
- # == module Bundler::FileUtils
19
+ # Here, module \Bundler::FileUtils provides methods that are useful for:
18
20
  #
19
- # Namespace for several file utility methods for copying, moving, removing, etc.
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].
20
29
  #
21
- # === Module Functions
30
+ # === Creating
22
31
  #
23
- # require 'bundler/vendor/fileutils/lib/fileutils'
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
24
40
  #
25
- # Bundler::FileUtils.cd(dir, **options)
26
- # Bundler::FileUtils.cd(dir, **options) {|dir| block }
27
- # Bundler::FileUtils.pwd()
28
- # Bundler::FileUtils.mkdir(dir, **options)
29
- # Bundler::FileUtils.mkdir(list, **options)
30
- # Bundler::FileUtils.mkdir_p(dir, **options)
31
- # Bundler::FileUtils.mkdir_p(list, **options)
32
- # Bundler::FileUtils.rmdir(dir, **options)
33
- # Bundler::FileUtils.rmdir(list, **options)
34
- # Bundler::FileUtils.ln(target, link, **options)
35
- # Bundler::FileUtils.ln(targets, dir, **options)
36
- # Bundler::FileUtils.ln_s(target, link, **options)
37
- # Bundler::FileUtils.ln_s(targets, dir, **options)
38
- # Bundler::FileUtils.ln_sf(target, link, **options)
39
- # Bundler::FileUtils.cp(src, dest, **options)
40
- # Bundler::FileUtils.cp(list, dir, **options)
41
- # Bundler::FileUtils.cp_r(src, dest, **options)
42
- # Bundler::FileUtils.cp_r(list, dir, **options)
43
- # Bundler::FileUtils.mv(src, dest, **options)
44
- # Bundler::FileUtils.mv(list, dir, **options)
45
- # Bundler::FileUtils.rm(list, **options)
46
- # Bundler::FileUtils.rm_r(list, **options)
47
- # Bundler::FileUtils.rm_rf(list, **options)
48
- # Bundler::FileUtils.install(src, dest, **options)
49
- # Bundler::FileUtils.chmod(mode, list, **options)
50
- # Bundler::FileUtils.chmod_R(mode, list, **options)
51
- # Bundler::FileUtils.chown(user, group, list, **options)
52
- # Bundler::FileUtils.chown_R(user, group, list, **options)
53
- # Bundler::FileUtils.touch(list, **options)
41
+ # === Deleting
54
42
  #
55
- # Possible <tt>options</tt> are:
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.
56
52
  #
57
- # <tt>:force</tt> :: forced operation (rewrite files if exist, remove
58
- # directories if not empty, etc.);
59
- # <tt>:verbose</tt> :: print command to be run, in bash syntax, before
60
- # performing it;
61
- # <tt>:preserve</tt> :: preserve object's group, user and modification
62
- # time on copying;
63
- # <tt>:noop</tt> :: no changes are made (usable in combination with
64
- # <tt>:verbose</tt> which will print the command to run)
53
+ # === Querying
65
54
  #
66
- # Each method documents the options that it honours. See also ::commands,
67
- # ::options and ::options_of methods to introspect which command have which
68
- # options.
55
+ # - ::pwd, ::getwd: Returns the path to the working directory.
56
+ # - ::uptodate?: Returns whether a given entry is newer than given other entries.
69
57
  #
70
- # All methods that have the concept of a "source" file or directory can take
71
- # either one file or a list of files in that argument. See the method
72
- # documentation for examples.
58
+ # === Setting
73
59
  #
74
- # There are some `low level' methods, which do not accept keyword arguments:
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.
75
67
  #
76
- # Bundler::FileUtils.copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
77
- # Bundler::FileUtils.copy_file(src, dest, preserve = false, dereference = true)
78
- # Bundler::FileUtils.copy_stream(srcstream, deststream)
79
- # Bundler::FileUtils.remove_entry(path, force = false)
80
- # Bundler::FileUtils.remove_entry_secure(path, force = false)
81
- # Bundler::FileUtils.remove_file(path, force = false)
82
- # Bundler::FileUtils.compare_file(path_a, path_b)
83
- # Bundler::FileUtils.compare_stream(stream_a, stream_b)
84
- # Bundler::FileUtils.uptodate?(file, cmp_list)
68
+ # === Comparing
85
69
  #
86
- # == module Bundler::FileUtils::Verbose
70
+ # - ::compare_file, ::cmp, ::identical?: Returns whether two entries are identical.
71
+ # - ::compare_stream: Returns whether two streams are identical.
87
72
  #
88
- # This module has all methods of Bundler::FileUtils module, but it outputs messages
89
- # before acting. This equates to passing the <tt>:verbose</tt> flag to methods
90
- # in Bundler::FileUtils.
73
+ # === Copying
91
74
  #
92
- # == module Bundler::FileUtils::NoWrite
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.
93
83
  #
94
- # This module has all methods of Bundler::FileUtils module, but never changes
95
- # files/directories. This equates to passing the <tt>:noop</tt> flag to methods
96
- # in Bundler::FileUtils.
84
+ # === Moving
97
85
  #
98
- # == module Bundler::FileUtils::DryRun
86
+ # - ::mv, ::move: Moves entries.
99
87
  #
100
- # This module has all methods of Bundler::FileUtils module, but never changes
101
- # files/directories. This equates to passing the <tt>:noop</tt> and
102
- # <tt>:verbose</tt> flags to methods in Bundler::FileUtils.
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].
103
181
  #
104
182
  module Bundler::FileUtils
105
- VERSION = "1.4.1"
183
+ VERSION = "1.7.2"
106
184
 
107
185
  def self.private_module_function(name) #:nodoc:
108
186
  module_function name
@@ -110,7 +188,11 @@ module Bundler::FileUtils
110
188
  end
111
189
 
112
190
  #
113
- # Returns the name of the current directory.
191
+ # Returns a string containing the path to the current directory:
192
+ #
193
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
194
+ #
195
+ # Related: Bundler::FileUtils.cd.
114
196
  #
115
197
  def pwd
116
198
  Dir.pwd
@@ -120,19 +202,38 @@ module Bundler::FileUtils
120
202
  alias getwd pwd
121
203
  module_function :getwd
122
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:
123
219
  #
124
- # Changes the current directory to the directory +dir+.
220
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
221
+ # Bundler::FileUtils.cd('..') { |arg| [arg, Bundler::FileUtils.pwd] } # => ["..", "/rdoc"]
222
+ # Bundler::FileUtils.pwd # => "/rdoc/fileutils"
125
223
  #
126
- # If this method is called with block, resumes to the previous
127
- # working directory after the block execution has finished.
224
+ # Keyword arguments:
128
225
  #
129
- # Bundler::FileUtils.cd('/') # change directory
226
+ # - <tt>verbose: true</tt> - prints an equivalent command:
130
227
  #
131
- # Bundler::FileUtils.cd('/', verbose: true) # change directory and report it
228
+ # Bundler::FileUtils.cd('..')
229
+ # Bundler::FileUtils.cd('fileutils')
132
230
  #
133
- # Bundler::FileUtils.cd('/') do # change directory
134
- # # ... # do something
135
- # end # return to original directory
231
+ # Output:
232
+ #
233
+ # cd ..
234
+ # cd fileutils
235
+ #
236
+ # Related: Bundler::FileUtils.pwd.
136
237
  #
137
238
  def cd(dir, verbose: nil, &block) # :yield: dir
138
239
  fu_output_message "cd #{dir}" if verbose
@@ -146,11 +247,19 @@ module Bundler::FileUtils
146
247
  module_function :chdir
147
248
 
148
249
  #
149
- # Returns true if +new+ is newer than all +old_list+.
150
- # Non-existent files are older than any file.
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
151
259
  #
152
- # Bundler::FileUtils.uptodate?('hello.o', %w(hello.c hello.h)) or \
153
- # system 'make hello.o'
260
+ # A non-existent file is considered to be infinitely old.
261
+ #
262
+ # Related: Bundler::FileUtils.touch.
154
263
  #
155
264
  def uptodate?(new, old_list)
156
265
  return false unless File.exist?(new)
@@ -170,12 +279,39 @@ module Bundler::FileUtils
170
279
  private_module_function :remove_trailing_slash
171
280
 
172
281
  #
173
- # Creates one or more directories.
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
174
310
  #
175
- # Bundler::FileUtils.mkdir 'test'
176
- # Bundler::FileUtils.mkdir %w(tmp data)
177
- # Bundler::FileUtils.mkdir 'notexist', noop: true # Does not really create.
178
- # Bundler::FileUtils.mkdir 'tmp', mode: 0700
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.
179
315
  #
180
316
  def mkdir(list, mode: nil, noop: nil, verbose: nil)
181
317
  list = fu_list(list)
@@ -189,40 +325,56 @@ module Bundler::FileUtils
189
325
  module_function :mkdir
190
326
 
191
327
  #
192
- # Creates a directory and all its parent directories.
193
- # For example,
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:
194
355
  #
195
- # Bundler::FileUtils.mkdir_p '/usr/local/lib/ruby'
356
+ # mkdir -p tmp0 tmp1
357
+ # mkdir -p -m 700 tmp2 tmp3
196
358
  #
197
- # causes to make following directories, if they do not exist.
359
+ # Raises an exception if for any reason a directory cannot be created.
198
360
  #
199
- # * /usr
200
- # * /usr/local
201
- # * /usr/local/lib
202
- # * /usr/local/lib/ruby
361
+ # Bundler::FileUtils.mkpath and Bundler::FileUtils.makedirs are aliases for Bundler::FileUtils.mkdir_p.
203
362
  #
204
- # You can pass several directories at a time in a list.
363
+ # Related: Bundler::FileUtils.mkdir.
205
364
  #
206
365
  def mkdir_p(list, mode: nil, noop: nil, verbose: nil)
207
366
  list = fu_list(list)
208
367
  fu_output_message "mkdir -p #{mode ? ('-m %03o ' % mode) : ''}#{list.join ' '}" if verbose
209
368
  return *list if noop
210
369
 
211
- list.map {|path| remove_trailing_slash(path)}.each do |path|
212
- # optimize for the most common case
213
- begin
214
- fu_mkdir path, mode
215
- next
216
- rescue SystemCallError
217
- next if File.directory?(path)
218
- end
370
+ list.each do |item|
371
+ path = remove_trailing_slash(item)
219
372
 
220
373
  stack = []
221
- until path == stack.last # dirname("/")=="/", dirname("C:/")=="C:/"
374
+ until File.directory?(path) || File.dirname(path) == path
222
375
  stack.push path
223
376
  path = File.dirname(path)
224
377
  end
225
- stack.pop # root directory should exist
226
378
  stack.reverse_each do |dir|
227
379
  begin
228
380
  fu_mkdir dir, mode
@@ -253,12 +405,39 @@ module Bundler::FileUtils
253
405
  private_module_function :fu_mkdir
254
406
 
255
407
  #
256
- # Removes one or more directories.
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:
257
428
  #
258
- # Bundler::FileUtils.rmdir 'somedir'
259
- # Bundler::FileUtils.rmdir %w(somedir anydir otherdir)
260
- # # Does not really remove directory; outputs message.
261
- # Bundler::FileUtils.rmdir 'somedir', verbose: true, noop: true
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].
262
441
  #
263
442
  def rmdir(list, parents: nil, noop: nil, verbose: nil)
264
443
  list = fu_list(list)
@@ -279,26 +458,60 @@ module Bundler::FileUtils
279
458
  end
280
459
  module_function :rmdir
281
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:
282
479
  #
283
- # :call-seq:
284
- # Bundler::FileUtils.ln(target, link, force: nil, noop: nil, verbose: nil)
285
- # Bundler::FileUtils.ln(target, dir, force: nil, noop: nil, verbose: nil)
286
- # Bundler::FileUtils.ln(targets, dir, force: nil, noop: nil, verbose: nil)
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"]
287
484
  #
288
- # In the first form, creates a hard link +link+ which points to +target+.
289
- # If +link+ already exists, raises Errno::EEXIST.
290
- # But if the +force+ option is set, overwrites +link+.
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+:
291
490
  #
292
- # Bundler::FileUtils.ln 'gcc', 'cc', verbose: true
293
- # Bundler::FileUtils.ln '/usr/bin/emacs21', '/usr/bin/emacs'
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"]
294
494
  #
295
- # In the second form, creates a link +dir/target+ pointing to +target+.
296
- # In the third form, creates several hard links in the directory +dir+,
297
- # pointing to each item in +targets+.
298
- # If +dir+ is not a directory, raises Errno::ENOTDIR.
495
+ # Keyword arguments:
299
496
  #
300
- # Bundler::FileUtils.cd '/sbin'
301
- # Bundler::FileUtils.ln %w(cp mv mkdir), '/bin' # Now /sbin/cp and /bin/cp are linked.
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).
302
515
  #
303
516
  def ln(src, dest, force: nil, noop: nil, verbose: nil)
304
517
  fu_output_message "ln#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -313,28 +526,103 @@ module Bundler::FileUtils
313
526
  alias link ln
314
527
  module_function :link
315
528
 
316
- #
317
- # Hard link +src+ to +dest+. If +src+ is a directory, this method links
318
- # all its contents recursively. If +dest+ is a directory, links
319
- # +src+ to +dest/src+.
320
- #
321
- # +src+ can be a list of files.
322
- #
323
- # If +dereference_root+ is true, this method dereference tree root.
324
- #
325
- # If +remove_destination+ is true, this method removes each destination file before copy.
326
- #
327
- # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true
328
- # Bundler::FileUtils.cp_lr 'lib/', site_ruby + '/mylib'
329
- #
330
- # # Examples of linking several files to target directory.
331
- # Bundler::FileUtils.cp_lr %w(mail.rb field.rb debug/), site_ruby + '/tmail'
332
- # Bundler::FileUtils.cp_lr Dir.glob('*.rb'), '/home/aamine/lib/ruby', noop: true, verbose: true
333
- #
334
- # # If you want to link all contents of a directory instead of the
335
- # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
336
- # # use the following code.
337
- # Bundler::FileUtils.cp_lr 'src/.', 'dest' # cp_lr('src', 'dest') makes dest/src, but this doesn't.
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].
338
626
  #
339
627
  def cp_lr(src, dest, noop: nil, verbose: nil,
340
628
  dereference_root: true, remove_destination: false)
@@ -346,27 +634,79 @@ module Bundler::FileUtils
346
634
  end
347
635
  module_function :cp_lr
348
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):
349
657
  #
350
- # :call-seq:
351
- # Bundler::FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil)
352
- # Bundler::FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil)
353
- # Bundler::FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil)
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
354
662
  #
355
- # In the first form, creates a symbolic link +link+ which points to +target+.
356
- # If +link+ already exists, raises Errno::EEXIST.
357
- # But if the <tt>force</tt> option is set, overwrites +link+.
663
+ # Bundler::FileUtils.ln_s('src1.txt', 'dest1.txt') # Raises Errno::EEXIST.
358
664
  #
359
- # Bundler::FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
360
- # Bundler::FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true
665
+ # If +dest+ is the path to a directory,
666
+ # creates a symbolic link at <tt>dest/src</tt> pointing to +src+:
361
667
  #
362
- # In the second form, creates a link +dir/target+ pointing to +target+.
363
- # In the third form, creates several symbolic links in the directory +dir+,
364
- # pointing to each item in +targets+.
365
- # If +dir+ is not a directory, raises Errno::ENOTDIR.
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
366
672
  #
367
- # Bundler::FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
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+:
368
676
  #
369
- def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
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
370
710
  fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
371
711
  return if noop
372
712
  fu_each_src_dest0(src, dest) do |s,d|
@@ -379,29 +719,95 @@ module Bundler::FileUtils
379
719
  alias symlink ln_s
380
720
  module_function :symlink
381
721
 
382
- #
383
- # :call-seq:
384
- # Bundler::FileUtils.ln_sf(*args)
385
- #
386
- # Same as
387
- #
388
- # Bundler::FileUtils.ln_s(*args, force: true)
722
+ # Like Bundler::FileUtils.ln_s, but always with keyword argument <tt>force: true</tt> given.
389
723
  #
390
724
  def ln_sf(src, dest, noop: nil, verbose: nil)
391
725
  ln_s src, dest, force: true, noop: noop, verbose: verbose
392
726
  end
393
727
  module_function :ln_sf
394
728
 
729
+ # Like Bundler::FileUtils.ln_s, but create links relative to +dest+.
395
730
  #
396
- # Hard links a file system entry +src+ to +dest+.
397
- # If +src+ is a directory, this method links its contents recursively.
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
398
783
  #
399
- # Both of +src+ and +dest+ must be a path name.
400
- # +src+ must exist, +dest+ must not exist.
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+:
401
786
  #
402
- # If +dereference_root+ is true, this method dereferences the tree root.
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
403
801
  #
404
- # If +remove_destination+ is true, this method removes each destination file before copy.
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).
405
811
  #
406
812
  def link_entry(src, dest, dereference_root = false, remove_destination = false)
407
813
  Entry_.new(src, nil, dereference_root).traverse do |ent|
@@ -412,16 +818,57 @@ module Bundler::FileUtils
412
818
  end
413
819
  module_function :link_entry
414
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
415
842
  #
416
- # Copies a file content +src+ to +dest+. If +dest+ is a directory,
417
- # copies +src+ to +dest/src+.
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+:
418
845
  #
419
- # If +src+ is a list of files, then +dest+ must be a directory.
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
420
852
  #
421
- # Bundler::FileUtils.cp 'eval.c', 'eval.c.org'
422
- # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6'
423
- # Bundler::FileUtils.cp %w(cgi.rb complex.rb date.rb), '/usr/lib/ruby/1.6', verbose: true
424
- # Bundler::FileUtils.cp 'symlink', 'dest' # copy content, "dest" is not a symlink
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].
425
872
  #
426
873
  def cp(src, dest, preserve: nil, noop: nil, verbose: nil)
427
874
  fu_output_message "cp#{preserve ? ' -p' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -435,30 +882,105 @@ module Bundler::FileUtils
435
882
  alias copy cp
436
883
  module_function :copy
437
884
 
438
- #
439
- # Copies +src+ to +dest+. If +src+ is a directory, this method copies
440
- # all its contents recursively. If +dest+ is a directory, copies
441
- # +src+ to +dest/src+.
442
- #
443
- # +src+ can be a list of files.
444
- #
445
- # If +dereference_root+ is true, this method dereference tree root.
446
- #
447
- # If +remove_destination+ is true, this method removes each destination file before copy.
448
- #
449
- # # Installing Ruby library "mylib" under the site_ruby
450
- # Bundler::FileUtils.rm_r site_ruby + '/mylib', force: true
451
- # Bundler::FileUtils.cp_r 'lib/', site_ruby + '/mylib'
452
- #
453
- # # Examples of copying several files to target directory.
454
- # Bundler::FileUtils.cp_r %w(mail.rb field.rb debug/), site_ruby + '/tmail'
455
- # Bundler::FileUtils.cp_r Dir.glob('*.rb'), '/home/foo/lib/ruby', noop: true, verbose: true
456
- #
457
- # # If you want to copy all contents of a directory instead of the
458
- # # directory itself, c.f. src/x -> dest/x, src/y -> dest/y,
459
- # # use following code.
460
- # Bundler::FileUtils.cp_r 'src/.', 'dest' # cp_r('src', 'dest') makes dest/src,
461
- # # but this doesn't.
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].
462
984
  #
463
985
  def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil,
464
986
  dereference_root: true, remove_destination: nil)
@@ -470,21 +992,50 @@ module Bundler::FileUtils
470
992
  end
471
993
  module_function :cp_r
472
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
473
1006
  #
474
- # Copies a file system entry +src+ to +dest+.
475
- # If +src+ is a directory, this method copies its contents recursively.
476
- # This method preserves file types, c.f. symlink, directory...
477
- # (FIFO, device files and etc. are not supported yet)
1007
+ # If +src+ is a directory, recursively copies +src+ to +dest+:
478
1008
  #
479
- # Both of +src+ and +dest+ must be a path name.
480
- # +src+ must exist, +dest+ must not exist.
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
481
1026
  #
482
- # If +preserve+ is true, this method preserves owner, group, and
483
- # modified time. Permissions are copied regardless +preserve+.
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.
484
1030
  #
485
- # If +dereference_root+ is true, this method dereference tree root.
1031
+ # Keyword arguments:
486
1032
  #
487
- # If +remove_destination+ is true, this method removes each destination file before copy.
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].
488
1039
  #
489
1040
  def copy_entry(src, dest, preserve = false, dereference_root = false, remove_destination = false)
490
1041
  if dereference_root
@@ -502,9 +1053,25 @@ module Bundler::FileUtils
502
1053
  end
503
1054
  module_function :copy_entry
504
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:
505
1068
  #
506
- # Copies file contents of +src+ to +dest+.
507
- # Both of +src+ and +dest+ must be a path name.
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].
508
1075
  #
509
1076
  def copy_file(src, dest, preserve = false, dereference = true)
510
1077
  ent = Entry_.new(src, nil, dereference)
@@ -513,25 +1080,79 @@ module Bundler::FileUtils
513
1080
  end
514
1081
  module_function :copy_file
515
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].
516
1085
  #
517
- # Copies stream +src+ to +dest+.
518
- # +src+ must respond to #read(n) and
519
- # +dest+ must respond to #write(str).
1086
+ # Related: {methods for copying}[rdoc-ref:FileUtils@Copying].
520
1087
  #
521
1088
  def copy_stream(src, dest)
522
1089
  IO.copy_stream(src, dest)
523
1090
  end
524
1091
  module_function :copy_stream
525
1092
 
526
- #
527
- # Moves file(s) +src+ to +dest+. If +file+ and +dest+ exist on the different
528
- # disk partition, the file is copied then the original file is removed.
529
- #
530
- # Bundler::FileUtils.mv 'badname.rb', 'goodname.rb'
531
- # Bundler::FileUtils.mv 'stuff.rb', '/notexist/lib/ruby', force: true # no error
532
- #
533
- # Bundler::FileUtils.mv %w(junk.txt dust.txt), '/home/foo/.trash/'
534
- # Bundler::FileUtils.mv Dir.glob('test*.rb'), 'test', noop: true, verbose: true
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
535
1156
  #
536
1157
  def mv(src, dest, force: nil, noop: nil, verbose: nil, secure: nil)
537
1158
  fu_output_message "mv#{force ? ' -f' : ''} #{[src,dest].flatten.join ' '}" if verbose
@@ -565,13 +1186,32 @@ module Bundler::FileUtils
565
1186
  alias move mv
566
1187
  module_function :move
567
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.
568
1192
  #
569
- # Remove file(s) specified in +list+. This method cannot remove directories.
570
- # All StandardErrors are ignored when the :force option is set.
1193
+ # Argument +list+ or its elements
1194
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
571
1195
  #
572
- # Bundler::FileUtils.rm %w( junk.txt dust.txt )
573
- # Bundler::FileUtils.rm Dir.glob('*.so')
574
- # Bundler::FileUtils.rm 'NotExistFile', force: true # never raises exception
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].
575
1215
  #
576
1216
  def rm(list, force: nil, noop: nil, verbose: nil)
577
1217
  list = fu_list(list)
@@ -587,10 +1227,16 @@ module Bundler::FileUtils
587
1227
  alias remove rm
588
1228
  module_function :remove
589
1229
 
1230
+ # Equivalent to:
1231
+ #
1232
+ # Bundler::FileUtils.rm(list, force: true, **kwargs)
590
1233
  #
591
- # Equivalent to
1234
+ # Argument +list+ (a single path or an array of paths)
1235
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
592
1236
  #
593
- # Bundler::FileUtils.rm(list, force: true)
1237
+ # See Bundler::FileUtils.rm for keyword arguments.
1238
+ #
1239
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
594
1240
  #
595
1241
  def rm_f(list, noop: nil, verbose: nil)
596
1242
  rm list, force: true, noop: noop, verbose: verbose
@@ -600,24 +1246,55 @@ module Bundler::FileUtils
600
1246
  alias safe_unlink rm_f
601
1247
  module_function :safe_unlink
602
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:
603
1288
  #
604
- # remove files +list+[0] +list+[1]... If +list+[n] is a directory,
605
- # removes its all contents recursively. This method ignores
606
- # StandardError when :force option is set.
1289
+ # Bundler::FileUtils.rm_r(['src0.dat', 'src0.txt'], noop: true, verbose: true)
1290
+ # Bundler::FileUtils.rm_r('src1', noop: true, verbose: true)
607
1291
  #
608
- # Bundler::FileUtils.rm_r Dir.glob('/tmp/*')
609
- # Bundler::FileUtils.rm_r 'some_dir', force: true
1292
+ # Output:
610
1293
  #
611
- # WARNING: This method causes local vulnerability
612
- # if one of parent directories or removing directory tree are world
613
- # writable (including /tmp, whose permission is 1777), and the current
614
- # process has strong privilege such as Unix super user (root), and the
615
- # system has symbolic link. For secure removing, read the documentation
616
- # of remove_entry_secure carefully, and set :secure option to true.
617
- # Default is <tt>secure: false</tt>.
1294
+ # rm -r src0.dat src0.txt
1295
+ # rm -r src1
618
1296
  #
619
- # NOTE: This method calls remove_entry_secure if :secure option is set.
620
- # See also remove_entry_secure.
1297
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
621
1298
  #
622
1299
  def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil)
623
1300
  list = fu_list(list)
@@ -633,13 +1310,20 @@ module Bundler::FileUtils
633
1310
  end
634
1311
  module_function :rm_r
635
1312
 
1313
+ # Equivalent to:
636
1314
  #
637
- # Equivalent to
1315
+ # Bundler::FileUtils.rm_r(list, force: true, **kwargs)
638
1316
  #
639
- # Bundler::FileUtils.rm_r(list, force: true)
1317
+ # Argument +list+ or its elements
1318
+ # should be {interpretable as paths}[rdoc-ref:FileUtils@Path+Arguments].
640
1319
  #
641
- # WARNING: This method causes local vulnerability.
642
- # Read the documentation of rm_r first.
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].
643
1327
  #
644
1328
  def rm_rf(list, noop: nil, verbose: nil, secure: nil)
645
1329
  rm_r list, force: true, noop: noop, verbose: verbose, secure: secure
@@ -649,37 +1333,20 @@ module Bundler::FileUtils
649
1333
  alias rmtree rm_rf
650
1334
  module_function :rmtree
651
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.
652
1339
  #
653
- # This method removes a file system entry +path+. +path+ shall be a
654
- # regular file, a directory, or something. If +path+ is a directory,
655
- # remove it recursively. This method is required to avoid TOCTTOU
656
- # (time-of-check-to-time-of-use) local security vulnerability of rm_r.
657
- # #rm_r causes security hole when:
658
- #
659
- # * Parent directory is world writable (including /tmp).
660
- # * Removing directory tree includes world writable directory.
661
- # * The system has symbolic link.
662
- #
663
- # To avoid this security hole, this method applies special preprocess.
664
- # If +path+ is a directory, this method chown(2) and chmod(2) all
665
- # removing directories. This requires the current process is the
666
- # owner of the removing whole directory tree, or is the super user (root).
1340
+ # Argument +path+
1341
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
667
1342
  #
668
- # WARNING: You must ensure that *ALL* parent directories cannot be
669
- # moved by other untrusted users. For example, parent directories
670
- # should not be owned by untrusted users, and should not be world
671
- # writable except when the sticky bit set.
1343
+ # Avoids a local vulnerability that can exist in certain circumstances;
1344
+ # see {Avoiding the TOCTTOU Vulnerability}[rdoc-ref:FileUtils@Avoiding+the+TOCTTOU+Vulnerability].
672
1345
  #
673
- # WARNING: Only the owner of the removing directory tree, or Unix super
674
- # user (root) should invoke this method. Otherwise this method does not
675
- # work.
1346
+ # Optional argument +force+ specifies whether to ignore
1347
+ # raised exceptions of StandardError and its descendants.
676
1348
  #
677
- # For details of this security vulnerability, see Perl's case:
678
- #
679
- # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0448
680
- # * https://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2004-0452
681
- #
682
- # For fileutils.rb, this vulnerability is reported in [ruby-dev:26100].
1349
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
683
1350
  #
684
1351
  def remove_entry_secure(path, force = false)
685
1352
  unless fu_have_symlink?
@@ -767,12 +1434,17 @@ module Bundler::FileUtils
767
1434
  end
768
1435
  private_module_function :fu_stat_identical_entry?
769
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.
770
1440
  #
771
- # This method removes a file system entry +path+.
772
- # +path+ might be a regular file, a directory, or something.
773
- # If +path+ is a directory, remove it recursively.
1441
+ # Argument +path+
1442
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
774
1443
  #
775
- # See also remove_entry_secure.
1444
+ # Optional argument +force+ specifies whether to ignore
1445
+ # raised exceptions of StandardError and its descendants.
1446
+ #
1447
+ # Related: Bundler::FileUtils.remove_entry_secure.
776
1448
  #
777
1449
  def remove_entry(path, force = false)
778
1450
  Entry_.new(path).postorder_traverse do |ent|
@@ -787,9 +1459,16 @@ module Bundler::FileUtils
787
1459
  end
788
1460
  module_function :remove_entry
789
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].
790
1467
  #
791
- # Removes a file +path+.
792
- # This method ignores StandardError if +force+ is true.
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].
793
1472
  #
794
1473
  def remove_file(path, force = false)
795
1474
  Entry_.new(path).remove_file
@@ -798,20 +1477,32 @@ module Bundler::FileUtils
798
1477
  end
799
1478
  module_function :remove_file
800
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.
801
1489
  #
802
- # Removes a directory +dir+ and its contents recursively.
803
- # This method ignores StandardError if +force+ is true.
1490
+ # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting].
804
1491
  #
805
1492
  def remove_dir(path, force = false)
806
1493
  remove_entry path, force # FIXME?? check if it is a directory
807
1494
  end
808
1495
  module_function :remove_dir
809
1496
 
1497
+ # Returns +true+ if the contents of files +a+ and +b+ are identical,
1498
+ # +false+ otherwise.
810
1499
  #
811
- # Returns true if the contents of a file +a+ and a file +b+ are identical.
1500
+ # Arguments +a+ and +b+
1501
+ # should be {interpretable as a path}[rdoc-ref:FileUtils@Path+Arguments].
812
1502
  #
813
- # Bundler::FileUtils.compare_file('somefile', 'somefile') #=> true
814
- # Bundler::FileUtils.compare_file('/dev/null', '/dev/urandom') #=> false
1503
+ # Bundler::FileUtils.identical? and Bundler::FileUtils.cmp are aliases for Bundler::FileUtils.compare_file.
1504
+ #
1505
+ # Related: Bundler::FileUtils.compare_stream.
815
1506
  #
816
1507
  def compare_file(a, b)
817
1508
  return false unless File.size(a) == File.size(b)
@@ -828,19 +1519,19 @@ module Bundler::FileUtils
828
1519
  module_function :identical?
829
1520
  module_function :cmp
830
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].
831
1527
  #
832
- # Returns true if the contents of a stream +a+ and +b+ are identical.
1528
+ # Related: Bundler::FileUtils.compare_file.
833
1529
  #
834
1530
  def compare_stream(a, b)
835
1531
  bsize = fu_stream_blksize(a, b)
836
1532
 
837
- if RUBY_VERSION > "2.4"
838
- sa = String.new(capacity: bsize)
839
- sb = String.new(capacity: bsize)
840
- else
841
- sa = String.new
842
- sb = String.new
843
- end
1533
+ sa = String.new(capacity: bsize)
1534
+ sb = String.new(capacity: bsize)
844
1535
 
845
1536
  begin
846
1537
  a.read(bsize, sa)
@@ -851,13 +1542,69 @@ module Bundler::FileUtils
851
1542
  end
852
1543
  module_function :compare_stream
853
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:
854
1585
  #
855
- # If +src+ is not same as +dest+, copies it and changes the permission
856
- # mode to +mode+. If +dest+ is a directory, destination is +dest+/+src+.
857
- # This method removes destination before copy.
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:
858
1596
  #
859
- # Bundler::FileUtils.install 'ruby', '/usr/local/bin/ruby', mode: 0755, verbose: true
860
- # Bundler::FileUtils.install 'lib.rb', '/usr/local/lib/ruby/site_ruby', verbose: true
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].
861
1608
  #
862
1609
  def install(src, dest, mode: nil, owner: nil, group: nil, preserve: nil,
863
1610
  noop: nil, verbose: nil)
@@ -877,7 +1624,13 @@ module Bundler::FileUtils
877
1624
  st = File.stat(s)
878
1625
  unless File.exist?(d) and compare_file(s, d)
879
1626
  remove_file d, true
880
- copy_file s, d
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
881
1634
  File.utime st.atime, st.mtime, d if preserve
882
1635
  File.chmod fu_mode(mode, st), d if mode
883
1636
  File.chown uid, gid, d if uid or gid
@@ -917,11 +1670,8 @@ module Bundler::FileUtils
917
1670
  private_module_function :apply_mask
918
1671
 
919
1672
  def symbolic_modes_to_i(mode_sym, path) #:nodoc:
920
- mode = if File::Stat === path
921
- path.mode
922
- else
923
- File.stat(path).mode
924
- end
1673
+ path = File.stat(path) unless File::Stat === path
1674
+ mode = path.mode
925
1675
  mode_sym.split(/,/).inject(mode & 07777) do |current_mode, clause|
926
1676
  target, *actions = clause.split(/([=+-])/)
927
1677
  raise ArgumentError, "invalid file mode: #{mode_sym}" if actions.empty?
@@ -938,7 +1688,7 @@ module Bundler::FileUtils
938
1688
  when "x"
939
1689
  mask | 0111
940
1690
  when "X"
941
- if FileTest.directory? path
1691
+ if path.directory?
942
1692
  mask | 0111
943
1693
  else
944
1694
  mask
@@ -978,37 +1728,78 @@ module Bundler::FileUtils
978
1728
  end
979
1729
  private_module_function :mode_to_s
980
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.
981
1802
  #
982
- # Changes permission bits on the named files (in +list+) to the bit pattern
983
- # represented by +mode+.
984
- #
985
- # +mode+ is the symbolic and absolute mode can be used.
986
- #
987
- # Absolute mode is
988
- # Bundler::FileUtils.chmod 0755, 'somecommand'
989
- # Bundler::FileUtils.chmod 0644, %w(my.rb your.rb his.rb her.rb)
990
- # Bundler::FileUtils.chmod 0755, '/usr/bin/ruby', verbose: true
991
- #
992
- # Symbolic mode is
993
- # Bundler::FileUtils.chmod "u=wrx,go=rx", 'somecommand'
994
- # Bundler::FileUtils.chmod "u=wr,go=rr", %w(my.rb your.rb his.rb her.rb)
995
- # Bundler::FileUtils.chmod "u=wrx,go=rx", '/usr/bin/ruby', verbose: true
996
- #
997
- # "a" :: is user, group, other mask.
998
- # "u" :: is user's mask.
999
- # "g" :: is group's mask.
1000
- # "o" :: is other's mask.
1001
- # "w" :: is write permission.
1002
- # "r" :: is read permission.
1003
- # "x" :: is execute permission.
1004
- # "X" ::
1005
- # is execute permission for directories only, must be used in conjunction with "+"
1006
- # "s" :: is uid, gid.
1007
- # "t" :: is sticky bit.
1008
- # "+" :: is added to a class given the specified mode.
1009
- # "-" :: Is removed from a given class given mode.
1010
- # "=" :: Is the exact nature of the class will be given a specified mode.
1011
-
1012
1803
  def chmod(mode, list, noop: nil, verbose: nil)
1013
1804
  list = fu_list(list)
1014
1805
  fu_output_message sprintf('chmod %s %s', mode_to_s(mode), list.join(' ')) if verbose
@@ -1019,12 +1810,7 @@ module Bundler::FileUtils
1019
1810
  end
1020
1811
  module_function :chmod
1021
1812
 
1022
- #
1023
- # Changes permission bits on the named files (in +list+)
1024
- # to the bit pattern represented by +mode+.
1025
- #
1026
- # Bundler::FileUtils.chmod_R 0700, "/tmp/app.#{$$}"
1027
- # Bundler::FileUtils.chmod_R "u=wrx", "/tmp/app.#{$$}"
1813
+ # Like Bundler::FileUtils.chmod, but changes permissions recursively.
1028
1814
  #
1029
1815
  def chmod_R(mode, list, noop: nil, verbose: nil, force: nil)
1030
1816
  list = fu_list(list)
@@ -1044,15 +1830,68 @@ module Bundler::FileUtils
1044
1830
  end
1045
1831
  module_function :chmod_R
1046
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.
1047
1853
  #
1048
- # Changes owner and group on the named files (in +list+)
1049
- # to the user +user+ and the group +group+. +user+ and +group+
1050
- # may be an ID (Integer/String) or a name (String).
1051
- # If +user+ or +group+ is nil, this method does not change
1052
- # the attribute.
1854
+ # Examples:
1053
1855
  #
1054
- # Bundler::FileUtils.chown 'root', 'staff', '/usr/local/bin/ruby'
1055
- # Bundler::FileUtils.chown nil, 'bin', Dir.glob('/usr/bin/*'), verbose: true
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.
1056
1895
  #
1057
1896
  def chown(user, group, list, noop: nil, verbose: nil)
1058
1897
  list = fu_list(list)
@@ -1068,15 +1907,7 @@ module Bundler::FileUtils
1068
1907
  end
1069
1908
  module_function :chown
1070
1909
 
1071
- #
1072
- # Changes owner and group on the named files (in +list+)
1073
- # to the user +user+ and the group +group+ recursively.
1074
- # +user+ and +group+ may be an ID (Integer/String) or
1075
- # a name (String). If +user+ or +group+ is nil, this
1076
- # method does not change the attribute.
1077
- #
1078
- # Bundler::FileUtils.chown_R 'www', 'www', '/var/www/htdocs'
1079
- # Bundler::FileUtils.chown_R 'cvs', 'cvs', '/var/cvs', verbose: true
1910
+ # Like Bundler::FileUtils.chown, but changes owner and group recursively.
1080
1911
  #
1081
1912
  def chown_R(user, group, list, noop: nil, verbose: nil, force: nil)
1082
1913
  list = fu_list(list)
@@ -1127,12 +1958,50 @@ module Bundler::FileUtils
1127
1958
  end
1128
1959
  private_module_function :fu_get_gid
1129
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'])
1130
1985
  #
1131
- # Updates modification time (mtime) and access time (atime) of file(s) in
1132
- # +list+. Files are created if they don't exist.
1986
+ # Keyword arguments:
1133
1987
  #
1134
- # Bundler::FileUtils.touch 'timestamp'
1135
- # Bundler::FileUtils.touch Dir.glob('*.c'); system 'make'
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?.
1136
2005
  #
1137
2006
  def touch(list, noop: nil, verbose: nil, mtime: nil, nocreate: nil)
1138
2007
  list = fu_list(list)
@@ -1290,14 +2159,9 @@ module Bundler::FileUtils
1290
2159
 
1291
2160
  def entries
1292
2161
  opts = {}
1293
- opts[:encoding] = ::Encoding::UTF_8 if fu_windows?
2162
+ opts[:encoding] = fu_windows? ? ::Encoding::UTF_8 : path.encoding
1294
2163
 
1295
- files = if Dir.respond_to?(:children)
1296
- Dir.children(path, **opts)
1297
- else
1298
- Dir.entries(path(), **opts)
1299
- .reject {|n| n == '.' or n == '..' }
1300
- end
2164
+ files = Dir.children(path, **opts)
1301
2165
 
1302
2166
  untaint = RUBY_VERSION < '2.7'
1303
2167
  files.map {|n| Entry_.new(prefix(), join(rel(), untaint ? n.untaint : n)) }
@@ -1345,6 +2209,7 @@ module Bundler::FileUtils
1345
2209
  else
1346
2210
  File.chmod mode, path()
1347
2211
  end
2212
+ rescue Errno::EOPNOTSUPP
1348
2213
  end
1349
2214
 
1350
2215
  def chown(uid, gid)
@@ -1439,7 +2304,7 @@ module Bundler::FileUtils
1439
2304
  if st.symlink?
1440
2305
  begin
1441
2306
  File.lchmod mode, path
1442
- rescue NotImplementedError
2307
+ rescue NotImplementedError, Errno::EOPNOTSUPP
1443
2308
  end
1444
2309
  else
1445
2310
  File.chmod mode, path
@@ -1498,13 +2363,21 @@ module Bundler::FileUtils
1498
2363
 
1499
2364
  def postorder_traverse
1500
2365
  if directory?
1501
- entries().each do |ent|
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|
1502
2376
  ent.postorder_traverse do |e|
1503
2377
  yield e
1504
2378
  end
1505
2379
  end
1506
2380
  end
1507
- ensure
1508
2381
  yield self
1509
2382
  end
1510
2383
 
@@ -1559,7 +2432,15 @@ module Bundler::FileUtils
1559
2432
  def join(dir, base)
1560
2433
  return File.path(dir) if not base or base == '.'
1561
2434
  return File.path(base) if not dir or dir == '.'
1562
- File.join(dir, base)
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
1563
2444
  end
1564
2445
 
1565
2446
  if File::ALT_SEPARATOR
@@ -1590,15 +2471,15 @@ module Bundler::FileUtils
1590
2471
  end
1591
2472
  private_module_function :fu_each_src_dest
1592
2473
 
1593
- def fu_each_src_dest0(src, dest) #:nodoc:
2474
+ def fu_each_src_dest0(src, dest, target_directory = true) #:nodoc:
1594
2475
  if tmp = Array.try_convert(src)
1595
2476
  tmp.each do |s|
1596
2477
  s = File.path(s)
1597
- yield s, File.join(dest, File.basename(s))
2478
+ yield s, (target_directory ? File.join(dest, File.basename(s)) : dest)
1598
2479
  end
1599
2480
  else
1600
2481
  src = File.path(src)
1601
- if File.directory?(dest)
2482
+ if target_directory and File.directory?(dest)
1602
2483
  yield src, File.join(dest, File.basename(src))
1603
2484
  else
1604
2485
  yield src, File.path(dest)
@@ -1614,7 +2495,7 @@ module Bundler::FileUtils
1614
2495
 
1615
2496
  def fu_output_message(msg) #:nodoc:
1616
2497
  output = @fileutils_output if defined?(@fileutils_output)
1617
- output ||= $stderr
2498
+ output ||= $stdout
1618
2499
  if defined?(@fileutils_label)
1619
2500
  msg = @fileutils_label + msg
1620
2501
  end
@@ -1622,6 +2503,56 @@ module Bundler::FileUtils
1622
2503
  end
1623
2504
  private_module_function :fu_output_message
1624
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
+
1625
2556
  # This hash table holds command options.
1626
2557
  OPT_TABLE = {} #:nodoc: internal use only
1627
2558
  (private_instance_methods & methods(false)).inject(OPT_TABLE) {|tbl, name|
@@ -1631,50 +2562,49 @@ module Bundler::FileUtils
1631
2562
 
1632
2563
  public
1633
2564
 
2565
+ # Returns an array of the string names of \Bundler::FileUtils methods
2566
+ # that accept one or more keyword arguments:
1634
2567
  #
1635
- # Returns an Array of names of high-level methods that accept any keyword
1636
- # arguments.
1637
- #
1638
- # p Bundler::FileUtils.commands #=> ["chmod", "cp", "cp_r", "install", ...]
2568
+ # Bundler::FileUtils.commands.sort.take(3) # => ["cd", "chdir", "chmod"]
1639
2569
  #
1640
2570
  def self.commands
1641
2571
  OPT_TABLE.keys
1642
2572
  end
1643
2573
 
2574
+ # Returns an array of the string keyword names:
1644
2575
  #
1645
- # Returns an Array of option names.
1646
- #
1647
- # p Bundler::FileUtils.options #=> ["noop", "force", "verbose", "preserve", "mode"]
2576
+ # Bundler::FileUtils.options.take(3) # => ["noop", "verbose", "force"]
1648
2577
  #
1649
2578
  def self.options
1650
2579
  OPT_TABLE.values.flatten.uniq.map {|sym| sym.to_s }
1651
2580
  end
1652
2581
 
2582
+ # Returns +true+ if method +mid+ accepts the given option +opt+, +false+ otherwise;
2583
+ # the arguments may be strings or symbols:
1653
2584
  #
1654
- # Returns true if the method +mid+ have an option +opt+.
1655
- #
1656
- # p Bundler::FileUtils.have_option?(:cp, :noop) #=> true
1657
- # p Bundler::FileUtils.have_option?(:rm, :force) #=> true
1658
- # p Bundler::FileUtils.have_option?(:rm, :preserve) #=> false
2585
+ # Bundler::FileUtils.have_option?(:chmod, :noop) # => true
2586
+ # Bundler::FileUtils.have_option?('chmod', 'secure') # => false
1659
2587
  #
1660
2588
  def self.have_option?(mid, opt)
1661
2589
  li = OPT_TABLE[mid.to_s] or raise ArgumentError, "no such method: #{mid}"
1662
2590
  li.include?(opt)
1663
2591
  end
1664
2592
 
2593
+ # Returns an array of the string keyword name for method +mid+;
2594
+ # the argument may be a string or a symbol:
1665
2595
  #
1666
- # Returns an Array of option names of the method +mid+.
1667
- #
1668
- # p Bundler::FileUtils.options_of(:rm) #=> ["noop", "verbose", "force"]
2596
+ # Bundler::FileUtils.options_of(:rm) # => ["force", "noop", "verbose"]
2597
+ # Bundler::FileUtils.options_of('mv') # => ["force", "noop", "verbose", "secure"]
1669
2598
  #
1670
2599
  def self.options_of(mid)
1671
2600
  OPT_TABLE[mid.to_s].map {|sym| sym.to_s }
1672
2601
  end
1673
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:
1674
2606
  #
1675
- # Returns an Array of methods names which have the option +opt+.
1676
- #
1677
- # p Bundler::FileUtils.collect_method(:preserve) #=> ["cp", "cp_r", "copy", "install"]
2607
+ # Bundler::FileUtils.collect_method(:preserve) # => ["cp", "copy", "cp_r", "install"]
1678
2608
  #
1679
2609
  def self.collect_method(opt)
1680
2610
  OPT_TABLE.keys.select {|m| OPT_TABLE[m].include?(opt) }