Class: VagrantPlugins::XenServer::MyUtil::Uploader
- Inherits:
-
Object
- Object
- VagrantPlugins::XenServer::MyUtil::Uploader
- Defined in:
- lib/vagrant-xenserver/util/uploader.rb
Overview
This class uploads files using various protocols by subprocessing to cURL. cURL is a much more capable and complete upload tool than a hand-rolled Ruby library, so we defer to its expertise.
Constant Summary collapse
- USER_AGENT =
Custom user agent provided to cURL so that requests to URL shorteners are properly tracked.
"VagrantXenserver/1.0"
Instance Attribute Summary collapse
-
#destination ⇒ Object
readonly
Returns the value of attribute destination.
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Instance Method Summary collapse
- #execute_curl(options, subprocess_options, &data_proc) ⇒ Object
-
#initialize(source, destination, options = nil) ⇒ Uploader
constructor
A new instance of Uploader.
-
#options ⇒ Array<Array, Hash>
Returns the varoius cURL and subprocess options.
-
#upload! ⇒ Object
This executes the actual upload, uploading the source file to the destination with the given options used to initialize this class.
Constructor Details
#initialize(source, destination, options = nil) ⇒ Uploader
Returns a new instance of Uploader.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 23 def initialize(source, destination, =nil) ||= {} @logger = Log4r::Logger.new("vagrant::xenserver::util::uploader") @source = source.to_s @destination = destination.to_s begin url = URI.parse(@destination) if url.scheme && url.scheme.start_with?("http") && url.user auth = "#{url.user}" auth += ":#{url.password}" if url.password url.user = nil url.password = nil [:auth] ||= auth @destination = url.to_s end rescue URI::InvalidURIError # Ignore, since its clearly not HTTP end # Get the various optional values @auth = [:auth] @ca_cert = [:ca_cert] @ca_path = [:ca_path] @continue = [:continue] @headers = [:headers] @insecure = [:insecure] @ui = [:ui] @client_cert = [:client_cert] end |
Instance Attribute Details
#destination ⇒ Object (readonly)
Returns the value of attribute destination.
21 22 23 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 21 def destination @destination end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
20 21 22 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 20 def source @source end |
Instance Method Details
#execute_curl(options, subprocess_options, &data_proc) ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 144 def execute_curl(, , &data_proc) = .dup << # Create the callback that is called if we are interrupted interrupted = false int_callback = Proc.new do @logger.info("Uploader interrupted!") interrupted = true end # Execute! result = Vagrant::Util::Busy.busy(int_callback) do Vagrant::Util::Subprocess.execute("curl", *, &data_proc) end # If the upload was interrupted, then raise a specific error raise Errors::UploaderInterrupted if interrupted # If it didn't exit successfully, we need to parse the data and # show an error message. if result.exit_code != 0 @logger.warn("Uploader exit code: #{result.exit_code}") parts = result.stderr.split(/\n*curl:\s+\(\d+\)\s*/, 2) parts[1] ||= "" raise Errors::UploaderError, message: parts[1].chomp end result end |
#options ⇒ Array<Array, Hash>
Returns the varoius cURL and subprocess options.
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 178 def # Build the list of parameters to execute with cURL = [ "--fail", "--location", "--max-redirs", "10", "--user-agent", USER_AGENT, ] += ["--cacert", @ca_cert] if @ca_cert += ["--capath", @ca_path] if @ca_path += ["--continue-at", "-"] if @continue << "--insecure" if @insecure << "--cert" << @client_cert if @client_cert << "-u" << @auth if @auth if @headers Array(@headers).each do |header| << "-H" << header end end # Specify some options for the subprocess = {} # If we're in Vagrant, then we use the packaged CA bundle if Vagrant.in_installer? [:env] ||= {} [:env]["CURL_CA_BUNDLE"] = File.("cacert.pem", ENV["VAGRANT_INSTALLER_EMBEDDED_DIR"]) end return [, ] end |
#upload! ⇒ Object
This executes the actual upload, uploading the source file to the destination with the given options used to initialize this class.
If this method returns without an exception, the upload succeeded. An exception will be raised if the upload failed.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/vagrant-xenserver/util/uploader.rb', line 61 def upload! , = self. += ["--output", "dummy"] << @destination += ["-T", @source] # This variable can contain the proc that'll be sent to # the subprocess execute. data_proc = nil if @ui # If we're outputting progress, then setup the subprocess to # tell us output so we can parse it out. [:notify] = :stderr progress_data = "" progress_regexp = /(\r(.+?))\r/ # Setup the proc that'll receive the real-time data from # the uploader. data_proc = Proc.new do |type, data| # Type will always be "stderr" because that is the only # type of data we're subscribed for notifications. # Accumulate progress_data progress_data << data while true # If we have a full amount of column data (two "\r") then # we report new progress reports. Otherwise, just keep # accumulating. match = progress_regexp.match(progress_data) break if !match data = match[2] progress_data.gsub!(match[1], "") # Ignore the first \r and split by whitespace to grab the columns columns = data.strip.split(/\s+/) # COLUMN DATA: # # 0 - % total # 1 - Total size # 2 - % received # 3 - Received size # 4 - % transferred # 5 - Transferred size # 6 - Average download speed # 7 - Average upload speed # 9 - Total time # 9 - Time spent # 10 - Time left # 11 - Current speed output = "Progress: #{columns[0]}% (Rate: #{columns[11]}/s, Estimated time remaining: #{columns[10]})" @ui.clear_line @ui.detail(output, new_line: false) end end end @logger.info("Uploader starting upload: ") @logger.info(" -- Source: #{@source}") @logger.info(" -- Destination: #{@destination}") begin execute_curl(, , &data_proc) ensure # If we're outputting to the UI, clear the output to # avoid lingering progress meters. if @ui @ui.clear_line # Windows doesn't clear properly for some reason, so we just # output one more newline. # @ui.detail("") if Platform.windows? end end # Everything succeeded true end |