bundler 2.2.29 → 2.5.16

Sign up to get free protection for your applications and to get access to all the features.
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) }