redcar 0.3.7.1 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. data/CHANGES +16 -0
  2. data/README.md +5 -0
  3. data/ROADMAP.md +7 -9
  4. data/Rakefile +55 -22
  5. data/lib/redcar.rb +12 -6
  6. data/lib/redcar/installer.rb +119 -44
  7. data/plugins/application/features/step_definitions/speedbar_steps.rb +62 -0
  8. data/plugins/application/features/step_definitions/tree_steps.rb +3 -3
  9. data/plugins/application/features/support/env.rb +2 -1
  10. data/plugins/application/lib/application/notebook.rb +53 -7
  11. data/plugins/application/lib/application/speedbar.rb +12 -0
  12. data/plugins/application/lib/application/tab.rb +16 -5
  13. data/plugins/application/lib/application/treebook.rb +21 -1
  14. data/plugins/application_swt/lib/application_swt.rb +12 -2
  15. data/plugins/application_swt/lib/application_swt/html_tab.rb +4 -0
  16. data/plugins/application_swt/lib/application_swt/notebook.rb +5 -3
  17. data/plugins/application_swt/lib/application_swt/speedbar.rb +15 -27
  18. data/plugins/application_swt/lib/application_swt/swt_wrapper.rb +1 -0
  19. data/plugins/application_swt/lib/application_swt/tab.rb +1 -0
  20. data/plugins/application_swt/lib/application_swt/treebook.rb +36 -8
  21. data/plugins/application_swt/lib/application_swt/window.rb +24 -18
  22. data/plugins/auto_completer/lib/auto_completer.rb +5 -20
  23. data/plugins/core/lib/core.rb +7 -4
  24. data/plugins/core/lib/core/observable_struct.rb +2 -2
  25. data/plugins/declarations/lib/declarations.rb +3 -17
  26. data/plugins/document_search/features/search.feature +163 -0
  27. data/plugins/document_search/features/support/env.rb +4 -0
  28. data/plugins/document_search/lib/document_search.rb +121 -0
  29. data/plugins/document_search/plugin.rb +8 -0
  30. data/plugins/edit_view/features/line_delimiter.feature +7 -0
  31. data/plugins/edit_view/features/step_definitions/editing_steps.rb +49 -1
  32. data/plugins/edit_view/features/step_definitions/tab_steps.rb +10 -11
  33. data/plugins/edit_view/features/switch_tabs.feature +61 -10
  34. data/plugins/edit_view/lib/edit_view.rb +4 -0
  35. data/plugins/edit_view/lib/edit_view/document.rb +56 -0
  36. data/plugins/edit_view/lib/edit_view/document/command.rb +1 -1
  37. data/plugins/edit_view/lib/edit_view/edit_tab.rb +0 -8
  38. data/plugins/edit_view_swt/lib/edit_view_swt.rb +4 -0
  39. data/plugins/html_view/lib/html_controller.rb +19 -1
  40. data/plugins/html_view/lib/html_view.rb +28 -1
  41. data/plugins/html_view/lib/html_view/html_tab.rb +10 -1
  42. data/plugins/plugin_manager_ui/lib/plugin_manager_ui.rb +3 -1
  43. data/plugins/project/features/open_directory_tree.feature +3 -3
  44. data/plugins/project/lib/project.rb +4 -6
  45. data/plugins/project/lib/project/commands.rb +17 -0
  46. data/plugins/project/lib/project/dir_controller.rb +2 -1
  47. data/plugins/project/lib/project/dir_mirror.rb +8 -0
  48. data/plugins/project/lib/project/manager.rb +2 -0
  49. data/plugins/project/plugin.rb +2 -1
  50. data/plugins/project/vendor/net-sftp/Manifest +55 -0
  51. data/plugins/project/vendor/net-sftp/Rakefile +30 -0
  52. data/plugins/project/vendor/net-sftp/lib/net/sftp.rb +70 -0
  53. data/plugins/project/vendor/net-sftp/lib/net/sftp/constants.rb +187 -0
  54. data/plugins/project/vendor/net-sftp/lib/net/sftp/errors.rb +39 -0
  55. data/plugins/project/vendor/net-sftp/lib/net/sftp/operations/dir.rb +93 -0
  56. data/plugins/project/vendor/net-sftp/lib/net/sftp/operations/download.rb +364 -0
  57. data/plugins/project/vendor/net-sftp/lib/net/sftp/operations/file.rb +176 -0
  58. data/plugins/project/vendor/net-sftp/lib/net/sftp/operations/file_factory.rb +60 -0
  59. data/plugins/project/vendor/net-sftp/lib/net/sftp/operations/upload.rb +387 -0
  60. data/plugins/project/vendor/net-sftp/lib/net/sftp/packet.rb +21 -0
  61. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol.rb +32 -0
  62. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/01/attributes.rb +315 -0
  63. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/01/base.rb +268 -0
  64. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/01/name.rb +43 -0
  65. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/02/base.rb +31 -0
  66. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/03/base.rb +35 -0
  67. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/04/attributes.rb +152 -0
  68. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/04/base.rb +94 -0
  69. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/04/name.rb +67 -0
  70. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/05/base.rb +66 -0
  71. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/06/attributes.rb +107 -0
  72. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/06/base.rb +63 -0
  73. data/plugins/project/vendor/net-sftp/lib/net/sftp/protocol/base.rb +50 -0
  74. data/plugins/project/vendor/net-sftp/lib/net/sftp/request.rb +91 -0
  75. data/plugins/project/vendor/net-sftp/lib/net/sftp/response.rb +76 -0
  76. data/plugins/project/vendor/net-sftp/lib/net/sftp/session.rb +951 -0
  77. data/plugins/project/vendor/net-sftp/lib/net/sftp/version.rb +18 -0
  78. data/plugins/project/vendor/net-sftp/setup.rb +1331 -0
  79. data/plugins/project/vendor/net-sftp/test/common.rb +171 -0
  80. data/plugins/project/vendor/net-sftp/test/protocol/01/test_attributes.rb +97 -0
  81. data/plugins/project/vendor/net-sftp/test/protocol/01/test_base.rb +210 -0
  82. data/plugins/project/vendor/net-sftp/test/protocol/01/test_name.rb +27 -0
  83. data/plugins/project/vendor/net-sftp/test/protocol/02/test_base.rb +26 -0
  84. data/plugins/project/vendor/net-sftp/test/protocol/03/test_base.rb +27 -0
  85. data/plugins/project/vendor/net-sftp/test/protocol/04/test_attributes.rb +148 -0
  86. data/plugins/project/vendor/net-sftp/test/protocol/04/test_base.rb +74 -0
  87. data/plugins/project/vendor/net-sftp/test/protocol/04/test_name.rb +53 -0
  88. data/plugins/project/vendor/net-sftp/test/protocol/05/test_base.rb +62 -0
  89. data/plugins/project/vendor/net-sftp/test/protocol/06/test_attributes.rb +124 -0
  90. data/plugins/project/vendor/net-sftp/test/protocol/06/test_base.rb +51 -0
  91. data/plugins/project/vendor/net-sftp/test/protocol/test_base.rb +42 -0
  92. data/plugins/project/vendor/net-sftp/test/test_all.rb +7 -0
  93. data/plugins/project/vendor/net-sftp/test/test_dir.rb +47 -0
  94. data/plugins/project/vendor/net-sftp/test/test_download.rb +252 -0
  95. data/plugins/project/vendor/net-sftp/test/test_file.rb +159 -0
  96. data/plugins/project/vendor/net-sftp/test/test_file_factory.rb +48 -0
  97. data/plugins/project/vendor/net-sftp/test/test_packet.rb +9 -0
  98. data/plugins/project/vendor/net-sftp/test/test_protocol.rb +17 -0
  99. data/plugins/project/vendor/net-sftp/test/test_request.rb +71 -0
  100. data/plugins/project/vendor/net-sftp/test/test_response.rb +53 -0
  101. data/plugins/project/vendor/net-sftp/test/test_session.rb +741 -0
  102. data/plugins/project/vendor/net-sftp/test/test_upload.rb +219 -0
  103. data/plugins/project/vendor/net-ssh/Manifest +110 -0
  104. data/plugins/project/vendor/net-ssh/Rakefile +85 -0
  105. data/plugins/project/vendor/net-ssh/Rudyfile +96 -0
  106. data/plugins/project/vendor/net-ssh/lib/net/ssh.rb +215 -0
  107. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/agent.rb +179 -0
  108. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/constants.rb +18 -0
  109. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/key_manager.rb +193 -0
  110. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  111. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  112. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  113. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/methods/password.rb +39 -0
  114. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  115. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/pageant.rb +183 -0
  116. data/plugins/project/vendor/net-ssh/lib/net/ssh/authentication/session.rb +134 -0
  117. data/plugins/project/vendor/net-ssh/lib/net/ssh/buffer.rb +340 -0
  118. data/plugins/project/vendor/net-ssh/lib/net/ssh/buffered_io.rb +198 -0
  119. data/plugins/project/vendor/net-ssh/lib/net/ssh/config.rb +202 -0
  120. data/plugins/project/vendor/net-ssh/lib/net/ssh/connection/channel.rb +630 -0
  121. data/plugins/project/vendor/net-ssh/lib/net/ssh/connection/constants.rb +33 -0
  122. data/plugins/project/vendor/net-ssh/lib/net/ssh/connection/session.rb +597 -0
  123. data/plugins/project/vendor/net-ssh/lib/net/ssh/connection/term.rb +178 -0
  124. data/plugins/project/vendor/net-ssh/lib/net/ssh/errors.rb +85 -0
  125. data/plugins/project/vendor/net-ssh/lib/net/ssh/key_factory.rb +102 -0
  126. data/plugins/project/vendor/net-ssh/lib/net/ssh/known_hosts.rb +129 -0
  127. data/plugins/project/vendor/net-ssh/lib/net/ssh/loggable.rb +61 -0
  128. data/plugins/project/vendor/net-ssh/lib/net/ssh/packet.rb +102 -0
  129. data/plugins/project/vendor/net-ssh/lib/net/ssh/prompt.rb +93 -0
  130. data/plugins/project/vendor/net-ssh/lib/net/ssh/proxy/command.rb +75 -0
  131. data/plugins/project/vendor/net-ssh/lib/net/ssh/proxy/errors.rb +14 -0
  132. data/plugins/project/vendor/net-ssh/lib/net/ssh/proxy/http.rb +94 -0
  133. data/plugins/project/vendor/net-ssh/lib/net/ssh/proxy/socks4.rb +70 -0
  134. data/plugins/project/vendor/net-ssh/lib/net/ssh/proxy/socks5.rb +142 -0
  135. data/plugins/project/vendor/net-ssh/lib/net/ssh/ruby_compat.rb +43 -0
  136. data/plugins/project/vendor/net-ssh/lib/net/ssh/service/forward.rb +288 -0
  137. data/plugins/project/vendor/net-ssh/lib/net/ssh/test.rb +89 -0
  138. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/channel.rb +129 -0
  139. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/extensions.rb +152 -0
  140. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/kex.rb +44 -0
  141. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/local_packet.rb +51 -0
  142. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/packet.rb +81 -0
  143. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/remote_packet.rb +38 -0
  144. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/script.rb +157 -0
  145. data/plugins/project/vendor/net-ssh/lib/net/ssh/test/socket.rb +64 -0
  146. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/algorithms.rb +384 -0
  147. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/cipher_factory.rb +97 -0
  148. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/constants.rb +30 -0
  149. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac.rb +31 -0
  150. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  151. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/md5.rb +12 -0
  152. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  153. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/none.rb +15 -0
  154. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  155. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  156. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/identity_cipher.rb +55 -0
  157. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/kex.rb +13 -0
  158. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  159. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  160. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/openssl.rb +128 -0
  161. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/packet_stream.rb +235 -0
  162. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/server_version.rb +71 -0
  163. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/session.rb +276 -0
  164. data/plugins/project/vendor/net-ssh/lib/net/ssh/transport/state.rb +206 -0
  165. data/plugins/project/vendor/net-ssh/lib/net/ssh/verifiers/lenient.rb +30 -0
  166. data/plugins/project/vendor/net-ssh/lib/net/ssh/verifiers/null.rb +12 -0
  167. data/plugins/project/vendor/net-ssh/lib/net/ssh/verifiers/strict.rb +53 -0
  168. data/plugins/project/vendor/net-ssh/lib/net/ssh/version.rb +62 -0
  169. data/plugins/project/vendor/net-ssh/net-ssh.gemspec +138 -0
  170. data/plugins/project/vendor/net-ssh/setup.rb +1585 -0
  171. data/plugins/project/vendor/net-ssh/support/arcfour_check.rb +20 -0
  172. data/plugins/project/vendor/net-ssh/support/ssh_tunnel_bug.rb +65 -0
  173. data/plugins/project/vendor/net-ssh/test/README.txt +42 -0
  174. data/plugins/project/vendor/net-ssh/test/authentication/methods/common.rb +28 -0
  175. data/plugins/project/vendor/net-ssh/test/authentication/methods/test_abstract.rb +51 -0
  176. data/plugins/project/vendor/net-ssh/test/authentication/methods/test_hostbased.rb +114 -0
  177. data/plugins/project/vendor/net-ssh/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  178. data/plugins/project/vendor/net-ssh/test/authentication/methods/test_password.rb +50 -0
  179. data/plugins/project/vendor/net-ssh/test/authentication/methods/test_publickey.rb +127 -0
  180. data/plugins/project/vendor/net-ssh/test/authentication/test_agent.rb +205 -0
  181. data/plugins/project/vendor/net-ssh/test/authentication/test_key_manager.rb +105 -0
  182. data/plugins/project/vendor/net-ssh/test/authentication/test_session.rb +93 -0
  183. data/plugins/project/vendor/net-ssh/test/common.rb +107 -0
  184. data/plugins/project/vendor/net-ssh/test/configs/eqsign +3 -0
  185. data/plugins/project/vendor/net-ssh/test/configs/exact_match +8 -0
  186. data/plugins/project/vendor/net-ssh/test/configs/host_plus +10 -0
  187. data/plugins/project/vendor/net-ssh/test/configs/multihost +4 -0
  188. data/plugins/project/vendor/net-ssh/test/configs/nohost +19 -0
  189. data/plugins/project/vendor/net-ssh/test/configs/numeric_host +4 -0
  190. data/plugins/project/vendor/net-ssh/test/configs/wild_cards +14 -0
  191. data/plugins/project/vendor/net-ssh/test/connection/test_channel.rb +467 -0
  192. data/plugins/project/vendor/net-ssh/test/connection/test_session.rb +488 -0
  193. data/plugins/project/vendor/net-ssh/test/manual/test_forward.rb +185 -0
  194. data/plugins/project/vendor/net-ssh/test/test_all.rb +9 -0
  195. data/plugins/project/vendor/net-ssh/test/test_buffer.rb +336 -0
  196. data/plugins/project/vendor/net-ssh/test/test_buffered_io.rb +63 -0
  197. data/plugins/project/vendor/net-ssh/test/test_config.rb +117 -0
  198. data/plugins/project/vendor/net-ssh/test/test_key_factory.rb +67 -0
  199. data/plugins/project/vendor/net-ssh/test/transport/hmac/test_md5.rb +39 -0
  200. data/plugins/project/vendor/net-ssh/test/transport/hmac/test_md5_96.rb +25 -0
  201. data/plugins/project/vendor/net-ssh/test/transport/hmac/test_none.rb +34 -0
  202. data/plugins/project/vendor/net-ssh/test/transport/hmac/test_sha1.rb +34 -0
  203. data/plugins/project/vendor/net-ssh/test/transport/hmac/test_sha1_96.rb +25 -0
  204. data/plugins/project/vendor/net-ssh/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  205. data/plugins/project/vendor/net-ssh/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  206. data/plugins/project/vendor/net-ssh/test/transport/test_algorithms.rb +302 -0
  207. data/plugins/project/vendor/net-ssh/test/transport/test_cipher_factory.rb +213 -0
  208. data/plugins/project/vendor/net-ssh/test/transport/test_hmac.rb +34 -0
  209. data/plugins/project/vendor/net-ssh/test/transport/test_identity_cipher.rb +40 -0
  210. data/plugins/project/vendor/net-ssh/test/transport/test_packet_stream.rb +441 -0
  211. data/plugins/project/vendor/net-ssh/test/transport/test_server_version.rb +78 -0
  212. data/plugins/project/vendor/net-ssh/test/transport/test_session.rb +315 -0
  213. data/plugins/project/vendor/net-ssh/test/transport/test_state.rb +173 -0
  214. data/plugins/redcar/plugin.rb +3 -1
  215. data/plugins/redcar/redcar.rb +108 -121
  216. data/plugins/redcar_debug/lib/redcar_debug.rb +2 -0
  217. data/plugins/runnables/lib/runnables.rb +80 -23
  218. data/plugins/runnables/lib/runnables/command_output_controller.rb +102 -0
  219. data/plugins/runnables/lib/runnables/running_process_checker.rb +34 -0
  220. data/plugins/runnables/{plugin_no_load.rb → plugin.rb} +2 -1
  221. data/plugins/runnables/vendor/session-2.4.0/HISTORY +73 -0
  222. data/plugins/runnables/vendor/session-2.4.0/README +89 -0
  223. data/plugins/runnables/vendor/session-2.4.0/TODO +3 -0
  224. data/plugins/runnables/vendor/session-2.4.0/VERSION +1 -0
  225. data/plugins/runnables/vendor/session-2.4.0/gemspec.rb +22 -0
  226. data/plugins/runnables/vendor/session-2.4.0/install.rb +143 -0
  227. data/plugins/runnables/vendor/session-2.4.0/lib/session.rb +757 -0
  228. data/plugins/runnables/vendor/session-2.4.0/sample/bash.rb +60 -0
  229. data/plugins/runnables/vendor/session-2.4.0/sample/driver.rb +47 -0
  230. data/plugins/runnables/vendor/session-2.4.0/sample/session_idl.rb +25 -0
  231. data/plugins/runnables/vendor/session-2.4.0/sample/session_sh.rb +29 -0
  232. data/plugins/runnables/vendor/session-2.4.0/sample/sh0.rb +23 -0
  233. data/plugins/runnables/vendor/session-2.4.0/sample/stdin.rb +17 -0
  234. data/plugins/runnables/vendor/session-2.4.0/sample/threadtest.rb +42 -0
  235. data/plugins/runnables/vendor/session-2.4.0/session-2.4.0.gem +0 -0
  236. data/plugins/runnables/vendor/session-2.4.0/test/session.rb +227 -0
  237. data/plugins/runnables/views/command_output.html.erb +32 -0
  238. data/plugins/task_manager/lib/task_manager.rb +2 -0
  239. data/plugins/textmate/lib/textmate/plist.rb +1 -1
  240. data/plugins/textmate/lib/textmate/snippet.rb +1 -0
  241. data/plugins/tree/lib/tree/mirror.rb +8 -1
  242. data/plugins/tree_view_swt/lib/tree_view_swt.rb +29 -2
  243. metadata +191 -6
  244. data/plugins/declarations/TODO +0 -3
  245. data/plugins/redcar/spec/redcar/redcar_spec.rb +0 -70
  246. data/plugins/redcar/spec/spec_helper.rb +0 -4
@@ -0,0 +1,39 @@
1
+ module Net; module SFTP
2
+
3
+ # The base exception class for the SFTP system.
4
+ class Exception < RuntimeError; end
5
+
6
+ # A exception class for reporting a non-success result of an operation.
7
+ class StatusException < Net::SFTP::Exception
8
+
9
+ # The response object that caused the exception.
10
+ attr_reader :response
11
+
12
+ # The error code (numeric)
13
+ attr_reader :code
14
+
15
+ # The description of the error
16
+ attr_reader :description
17
+
18
+ # Any incident-specific text given when the exception was raised
19
+ attr_reader :text
20
+
21
+ # Create a new status exception that reports the given code and
22
+ # description.
23
+ def initialize(response, text=nil)
24
+ @response, @text = response, text
25
+ @code = response.code
26
+ @description = response.message
27
+ @description = Response::MAP[@code] if @description.nil? || @description.empty?
28
+ end
29
+
30
+ # Override the default message format, to include the code and
31
+ # description.
32
+ def message
33
+ m = super.dup
34
+ m << " #{text}" if text
35
+ m << " (#{code}, #{description.inspect})"
36
+ end
37
+
38
+ end
39
+ end; end
@@ -0,0 +1,93 @@
1
+ require 'net/ssh/loggable'
2
+
3
+ module Net; module SFTP; module Operations
4
+
5
+ # A convenience class for working with remote directories. It provides methods
6
+ # for searching and enumerating directory entries, similarly to the standard
7
+ # ::Dir class.
8
+ #
9
+ # sftp.dir.foreach("/remote/path") do |entry|
10
+ # puts entry.name
11
+ # end
12
+ #
13
+ # p sftp.dir.entries("/remote/path").map { |e| e.name }
14
+ #
15
+ # sftp.dir.glob("/remote/path", "**/*.rb") do |entry|
16
+ # puts entry.name
17
+ # end
18
+ class Dir
19
+ # The SFTP session object that drives this directory factory.
20
+ attr_reader :sftp
21
+
22
+ # Create a new instance on top of the given SFTP session instance.
23
+ def initialize(sftp)
24
+ @sftp = sftp
25
+ end
26
+
27
+ # Calls the block once for each entry in the named directory on the
28
+ # remote server. Yields a Name object to the block, rather than merely
29
+ # the name of the entry.
30
+ def foreach(path)
31
+ handle = sftp.opendir!(path)
32
+ while entries = sftp.readdir!(handle)
33
+ entries.each { |entry| yield entry }
34
+ end
35
+ return nil
36
+ ensure
37
+ sftp.close!(handle) if handle
38
+ end
39
+
40
+ # Returns an array of Name objects representing the items in the given
41
+ # remote directory, +path+.
42
+ def entries(path)
43
+ results = []
44
+ foreach(path) { |entry| results << entry }
45
+ return results
46
+ end
47
+
48
+ # Works as ::Dir.glob, matching (possibly recursively) all directory
49
+ # entries under +path+ against +pattern+. If a block is given, matches
50
+ # will be yielded to the block as they are found; otherwise, they will
51
+ # be returned in an array when the method finishes.
52
+ #
53
+ # Because working over an SFTP connection is always going to be slower than
54
+ # working purely locally, don't expect this method to perform with the
55
+ # same level of alacrity that ::Dir.glob does; it will work best for
56
+ # shallow directory hierarchies with relatively few directories, though
57
+ # it should be able to handle modest numbers of files in each directory.
58
+ def glob(path, pattern, flags=0)
59
+ flags |= ::File::FNM_PATHNAME
60
+ path = path.chop if path[-1,1] == "/"
61
+
62
+ results = [] unless block_given?
63
+ queue = entries(path).reject { |e| e.name == "." || e.name == ".." }
64
+ while queue.any?
65
+ entry = queue.shift
66
+
67
+ if entry.directory? && !%w(. ..).include?(::File.basename(entry.name))
68
+ queue += entries("#{path}/#{entry.name}").map do |e|
69
+ e.name.replace("#{entry.name}/#{e.name}")
70
+ e
71
+ end
72
+ end
73
+
74
+ if ::File.fnmatch(pattern, entry.name, flags)
75
+ if block_given?
76
+ yield entry
77
+ else
78
+ results << entry
79
+ end
80
+ end
81
+ end
82
+
83
+ return results unless block_given?
84
+ end
85
+
86
+ # Identical to calling #glob with a +flags+ parameter of 0 and no block.
87
+ # Simply returns the matched entries as an array.
88
+ def [](path, pattern)
89
+ glob(path, pattern, 0)
90
+ end
91
+ end
92
+
93
+ end; end; end
@@ -0,0 +1,364 @@
1
+ require 'net/ssh/loggable'
2
+
3
+ module Net; module SFTP; module Operations
4
+
5
+ # A general purpose downloader module for Net::SFTP. It can download files
6
+ # into IO objects, or directly to files on the local file system. It can
7
+ # even download entire directory trees via SFTP, and provides a flexible
8
+ # progress reporting mechanism.
9
+ #
10
+ # To download a single file from the remote server, simply specify both the
11
+ # remote and local paths:
12
+ #
13
+ # downloader = sftp.download("/path/to/remote.txt", "/path/to/local.txt")
14
+ #
15
+ # By default, this operates asynchronously, so if you want to block until
16
+ # the download finishes, you can use the 'bang' variant:
17
+ #
18
+ # sftp.download!("/path/to/remote.txt", "/path/to/local.txt")
19
+ #
20
+ # Or, if you have multiple downloads that you want to run in parallel, you can
21
+ # employ the #wait method of the returned object:
22
+ #
23
+ # dls = %w(file1 file2 file3).map { |f| sftp.download("remote/#{f}", f) }
24
+ # dls.each { |d| d.wait }
25
+ #
26
+ # To download an entire directory tree, recursively, simply specify :recursive => true:
27
+ #
28
+ # sftp.download!("/path/to/remotedir", "/path/to/local", :recursive => true)
29
+ #
30
+ # This will download "/path/to/remotedir", it's contents, it's subdirectories,
31
+ # and their contents, recursively, to "/path/to/local" on the local host.
32
+ # (If you specify :recursive => true and the source is not a directory,
33
+ # you'll get an error!)
34
+ #
35
+ # If you want to pull the contents of a file on the remote server, and store
36
+ # the data in memory rather than immediately to disk, you can pass an IO
37
+ # object as the destination:
38
+ #
39
+ # require 'stringio'
40
+ # io = StringIO.new
41
+ # sftp.download!("/path/to/remote", io)
42
+ #
43
+ # This will only work for single-file downloads. Trying to do so with
44
+ # :recursive => true will cause an error.
45
+ #
46
+ # The following options are supported:
47
+ #
48
+ # * <tt>:progress</tt> - either a block or an object to act as a progress
49
+ # callback. See the discussion of "progress monitoring" below.
50
+ # * <tt>:requests</tt> - the number of pending SFTP requests to allow at
51
+ # any given time. When downloading an entire directory tree recursively,
52
+ # this will default to 16. Setting this higher might improve throughput.
53
+ # Reducing it will reduce throughput.
54
+ # * <tt>:read_size</tt> - the maximum number of bytes to read at a time
55
+ # from the source. Increasing this value might improve throughput. It
56
+ # defaults to 32,000 bytes.
57
+ #
58
+ # == Progress Monitoring
59
+ #
60
+ # Sometimes it is desirable to track the progress of a download. There are
61
+ # two ways to do this: either using a callback block, or a special custom
62
+ # object.
63
+ #
64
+ # Using a block it's pretty straightforward:
65
+ #
66
+ # sftp.download!("remote", "local") do |event, downloader, *args|
67
+ # case event
68
+ # when :open then
69
+ # # args[0] : file metadata
70
+ # puts "starting download: #{args[0].remote} -> #{args[0].local} (#{args[0].size} bytes}"
71
+ # when :get then
72
+ # # args[0] : file metadata
73
+ # # args[1] : byte offset in remote file
74
+ # # args[2] : data that was received
75
+ # puts "writing #{args[2].length} bytes to #{args[0].local} starting at #{args[1]}"
76
+ # when :close then
77
+ # # args[0] : file metadata
78
+ # puts "finished with #{args[0].remote}"
79
+ # when :mkdir then
80
+ # # args[0] : local path name
81
+ # puts "creating directory #{args[0]}"
82
+ # when :finish then
83
+ # puts "all done!"
84
+ # end
85
+ #
86
+ # However, for more complex implementations (e.g., GUI interfaces and such)
87
+ # a block can become cumbersome. In those cases, you can create custom
88
+ # handler objects that respond to certain methods, and then pass your handler
89
+ # to the downloader:
90
+ #
91
+ # class CustomHandler
92
+ # def on_open(downloader, file)
93
+ # puts "starting download: #{file.remote} -> #{file.local} (#{file.size} bytes)"
94
+ # end
95
+ #
96
+ # def on_get(downloader, file, offset, data)
97
+ # puts "writing #{data.length} bytes to #{file.local} starting at #{offset}"
98
+ # end
99
+ #
100
+ # def on_close(downloader, file)
101
+ # puts "finished with #{file.remote}"
102
+ # end
103
+ #
104
+ # def on_mkdir(downloader, path)
105
+ # puts "creating directory #{path}"
106
+ # end
107
+ #
108
+ # def on_finish(downloader)
109
+ # puts "all done!"
110
+ # end
111
+ # end
112
+ #
113
+ # sftp.download!("remote", "local", :progress => CustomHandler.new)
114
+ #
115
+ # If you omit any of those methods, the progress updates for those missing
116
+ # events will be ignored. You can create a catchall method named "call" for
117
+ # those, instead.
118
+ class Download
119
+ include Net::SSH::Loggable
120
+
121
+ # The destination of the download (the name of a file or directory on
122
+ # the local server, or an IO object)
123
+ attr_reader :local
124
+
125
+ # The source of the download (the name of a file or directory on the
126
+ # remote server)
127
+ attr_reader :remote
128
+
129
+ # The hash of options that was given to this Download instance.
130
+ attr_reader :options
131
+
132
+ # The SFTP session instance that drives this download.
133
+ attr_reader :sftp
134
+
135
+ # The properties hash for this object
136
+ attr_reader :properties
137
+
138
+ # Instantiates a new downloader process on top of the given SFTP session.
139
+ # +local+ is either an IO object that should receive the data, or a string
140
+ # identifying the target file or directory on the local host. +remote+ is
141
+ # a string identifying the location on the remote host that the download
142
+ # should source.
143
+ #
144
+ # This will return immediately, and requires that the SSH event loop be
145
+ # run in order to effect the download. (See #wait.)
146
+ def initialize(sftp, local, remote, options={}, &progress)
147
+ @sftp = sftp
148
+ @local = local
149
+ @remote = remote
150
+ @progress = progress || options[:progress]
151
+ @options = options
152
+ @active = 0
153
+ @properties = options[:properties] || {}
154
+
155
+ self.logger = sftp.logger
156
+
157
+ if recursive? && local.respond_to?(:write)
158
+ raise ArgumentError, "cannot download a directory tree in-memory"
159
+ end
160
+
161
+ @stack = [Entry.new(remote, local, recursive?)]
162
+ process_next_entry
163
+ end
164
+
165
+ # Returns the value of the :recursive key in the options hash that was
166
+ # given when the object was instantiated.
167
+ def recursive?
168
+ options[:recursive]
169
+ end
170
+
171
+ # Returns true if there are any active requests or pending files or
172
+ # directories.
173
+ def active?
174
+ @active > 0 || stack.any?
175
+ end
176
+
177
+ # Forces the transfer to stop.
178
+ def abort!
179
+ @active = 0
180
+ @stack.clear
181
+ end
182
+
183
+ # Runs the SSH event loop for as long as the downloader is active (see
184
+ # #active?). This can be used to block until the download completes.
185
+ def wait
186
+ sftp.loop { active? }
187
+ self
188
+ end
189
+
190
+ # Returns the property with the given name. This allows Download instances
191
+ # to store their own state when used as part of a state machine.
192
+ def [](name)
193
+ @properties[name.to_sym]
194
+ end
195
+
196
+ # Sets the given property to the given name. This allows Download instances
197
+ # to store their own state when used as part of a state machine.
198
+ def []=(name, value)
199
+ @properties[name.to_sym] = value
200
+ end
201
+
202
+ private
203
+
204
+ # A simple struct for encapsulating information about a single remote
205
+ # file or directory that needs to be downloaded.
206
+ Entry = Struct.new(:remote, :local, :directory, :size, :handle, :offset, :sink)
207
+
208
+ #--
209
+ # "ruby -w" hates private attributes, so we have to do these longhand
210
+ #++
211
+
212
+ # The stack of Entry instances, indicating which files and directories
213
+ # on the remote host remain to be downloaded.
214
+ def stack; @stack; end
215
+
216
+ # The progress handler for this instance. Possibly nil.
217
+ def progress; @progress; end
218
+
219
+ # The default read size.
220
+ DEFAULT_READ_SIZE = 32_000
221
+
222
+ # The number of bytes to read at a time from remote files.
223
+ def read_size
224
+ options[:read_size] || DEFAULT_READ_SIZE
225
+ end
226
+
227
+ # The number of simultaneou SFTP requests to use to effect the download.
228
+ # Defaults to 16 for recursive downloads.
229
+ def requests
230
+ options[:requests] || (recursive? ? 16 : 2)
231
+ end
232
+
233
+ # Enqueues as many files and directories from the stack as possible
234
+ # (see #requests).
235
+ def process_next_entry
236
+ while stack.any? && requests > @active
237
+ entry = stack.shift
238
+ @active += 1
239
+
240
+ if entry.directory
241
+ update_progress(:mkdir, entry.local)
242
+ ::Dir.mkdir(entry.local) unless ::File.directory?(entry.local)
243
+ request = sftp.opendir(entry.remote, &method(:on_opendir))
244
+ request[:entry] = entry
245
+ else
246
+ open_file(entry)
247
+ end
248
+ end
249
+
250
+ update_progress(:finish) if !active?
251
+ end
252
+
253
+ # Called when a remote directory is "opened" for reading, e.g. to
254
+ # enumerate its contents. Starts an readdir operation if the opendir
255
+ # operation was successful.
256
+ def on_opendir(response)
257
+ entry = response.request[:entry]
258
+ raise "opendir #{entry.remote}: #{response}" unless response.ok?
259
+ entry.handle = response[:handle]
260
+ request = sftp.readdir(response[:handle], &method(:on_readdir))
261
+ request[:parent] = entry
262
+ end
263
+
264
+ # Called when the next batch of items is read from a directory on the
265
+ # remote server. If any items were read, they are added to the queue
266
+ # and #process_next_entry is called.
267
+ def on_readdir(response)
268
+ entry = response.request[:parent]
269
+ if response.eof?
270
+ request = sftp.close(entry.handle, &method(:on_closedir))
271
+ request[:parent] = entry
272
+ elsif !response.ok?
273
+ raise "readdir #{entry.remote}: #{response}"
274
+ else
275
+ response[:names].each do |item|
276
+ next if item.name == "." || item.name == ".."
277
+ stack << Entry.new(::File.join(entry.remote, item.name), ::File.join(entry.local, item.name), item.directory?, item.attributes.size)
278
+ end
279
+
280
+ # take this opportunity to enqueue more requests
281
+ process_next_entry
282
+
283
+ request = sftp.readdir(entry.handle, &method(:on_readdir))
284
+ request[:parent] = entry
285
+ end
286
+ end
287
+
288
+ # Called when a file is to be opened for reading from the remote server.
289
+ def open_file(entry)
290
+ update_progress(:open, entry)
291
+ request = sftp.open(entry.remote, &method(:on_open))
292
+ request[:entry] = entry
293
+ end
294
+
295
+ # Called when a directory handle is closed.
296
+ def on_closedir(response)
297
+ @active -= 1
298
+ entry = response.request[:parent]
299
+ raise "close #{entry.remote}: #{response}" unless response.ok?
300
+ process_next_entry
301
+ end
302
+
303
+ # Called when a file has been opened. This will call #download_next_chunk
304
+ # to initiate the data transfer.
305
+ def on_open(response)
306
+ entry = response.request[:entry]
307
+ raise "open #{entry.remote}: #{response}" unless response.ok?
308
+
309
+ entry.handle = response[:handle]
310
+ entry.sink = entry.local.respond_to?(:write) ? entry.local : ::File.open(entry.local, "wb")
311
+ entry.offset = 0
312
+
313
+ download_next_chunk(entry)
314
+ end
315
+
316
+ # Initiates a read of the next #read_size bytes from the file.
317
+ def download_next_chunk(entry)
318
+ request = sftp.read(entry.handle, entry.offset, read_size, &method(:on_read))
319
+ request[:entry] = entry
320
+ request[:offset] = entry.offset
321
+ entry.offset += read_size
322
+ end
323
+
324
+ # Called when a read from a file finishes. If the read was successful
325
+ # and returned data, this will call #download_next_chunk to read the
326
+ # next bit from the file. Otherwise the file will be closed.
327
+ def on_read(response)
328
+ entry = response.request[:entry]
329
+
330
+ if response.eof?
331
+ update_progress(:close, entry)
332
+ entry.sink.close
333
+ request = sftp.close(entry.handle, &method(:on_close))
334
+ request[:entry] = entry
335
+ elsif !response.ok?
336
+ raise "read #{entry.remote}: #{response}"
337
+ else
338
+ update_progress(:get, entry, response.request[:offset], response[:data])
339
+ entry.sink.write(response[:data])
340
+ download_next_chunk(entry)
341
+ end
342
+ end
343
+
344
+ # Called when a file handle is closed.
345
+ def on_close(response)
346
+ @active -= 1
347
+ entry = response.request[:entry]
348
+ raise "close #{entry.remote}: #{response}" unless response.ok?
349
+ process_next_entry
350
+ end
351
+
352
+ # If a progress callback or object has been set, this will report
353
+ # the progress to that callback or object.
354
+ def update_progress(hook, *args)
355
+ on = "on_#{hook}"
356
+ if progress.respond_to?(on)
357
+ progress.send(on, self, *args)
358
+ elsif progress.respond_to?(:call)
359
+ progress.call(hook, self, *args)
360
+ end
361
+ end
362
+ end
363
+
364
+ end; end; end