qiniu2upyun 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +65 -0
- data/Rakefile +1 -0
- data/bin/qiniu2upyun +5 -0
- data/lib/qiniu2upyun.rb +32 -0
- data/lib/qiniu2upyun/cli.rb +48 -0
- data/lib/qiniu2upyun/config.rb +41 -0
- data/lib/qiniu2upyun/data.rb +34 -0
- data/lib/qiniu2upyun/error.rb +24 -0
- data/lib/qiniu2upyun/migrating.rb +88 -0
- data/lib/qiniu2upyun/qiniu.rb +116 -0
- data/lib/qiniu2upyun/record.rb +42 -0
- data/lib/qiniu2upyun/upyun.rb +88 -0
- data/lib/qiniu2upyun/utils.rb +36 -0
- data/lib/qiniu2upyun/version.rb +4 -0
- data/qiniu2upyun.gemspec +25 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b51e2995913626a163c38b05723c98395d812c21
|
4
|
+
data.tar.gz: 0fc4a3acf7422edbb0f080584d6a7895a780f07e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6356edc529786256f5bb9a8e500fa218300d3baabe0ab92a4cec067221630d05f228c412aea7df5a7a89951a6767089c9e25779ad1a9edd28df8ec98a2b152a3
|
7
|
+
data.tar.gz: c21b8e691fa3fdc5f09b0576f36861c8170bed517856c030eaa4176fbde373c5827fbcc7a6bafc6f41a6d2cbbefe52f3003ec9f76a00751cda3748bccafd45d1
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 zhouguangming
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Qiniu2Upyun
|
2
|
+
|
3
|
+
Migrate Qiniu to Upyun.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install qiniu2upyun
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
qiniu2upyun --help
|
12
|
+
|
13
|
+
Usage: qiniu2upyun [options]
|
14
|
+
-C, --config PATH Load PATH as a config file
|
15
|
+
(default: $HOME/.qiniu2upyun.yml)
|
16
|
+
-V, --version Show version
|
17
|
+
-h, --help Show help
|
18
|
+
|
19
|
+
## Config
|
20
|
+
|
21
|
+
# $HOME/.qiniu2upyun.yml
|
22
|
+
|
23
|
+
qiniu:
|
24
|
+
access_key: <your_access_key>
|
25
|
+
secret_key: <your_secret_key>
|
26
|
+
bucket: <your_bucket>
|
27
|
+
upyun:
|
28
|
+
username: <your_username>
|
29
|
+
password: <your_password>
|
30
|
+
bucket: <your_bucket>
|
31
|
+
|
32
|
+
## Snap
|
33
|
+
|
34
|
+
$ qiniu2upyun
|
35
|
+
|
36
|
+
Fetch '001.jpg` from qiniu:
|
37
|
+
Already exists in upyun and skip migrating.
|
38
|
+
|
39
|
+
Fetch '002.jpg` from qiniu:
|
40
|
+
Already exists in upyun and skip migrating.
|
41
|
+
|
42
|
+
Fetch '003.jpg` from qiniu:
|
43
|
+
Download |========================================| 100%
|
44
|
+
Upload |========================================| 100%
|
45
|
+
(2926510B/12.3s)
|
46
|
+
|
47
|
+
Fetch '004.jpg` from qiniu:
|
48
|
+
Download |========================================| 100%
|
49
|
+
Upload |========================================| 100%
|
50
|
+
(758846B/2.8s)
|
51
|
+
|
52
|
+
Fetch '005.jpg` from qiniu:
|
53
|
+
Download |========================================| 100%
|
54
|
+
Upload |========================================| 100%
|
55
|
+
(343525B/1.73s)
|
56
|
+
|
57
|
+
Complete, migrated 3 files and skipped 2 files in 17.24 seconds.
|
58
|
+
|
59
|
+
## Contributing
|
60
|
+
|
61
|
+
1. Fork it ( http://gitcafe.com/zgm/QINIU-to-UPYUN/)
|
62
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
63
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
64
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
65
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/qiniu2upyun
ADDED
data/lib/qiniu2upyun.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'base64'
|
4
|
+
require 'openssl'
|
5
|
+
require 'yaml'
|
6
|
+
require 'json'
|
7
|
+
require 'digest'
|
8
|
+
require 'time'
|
9
|
+
require 'tempfile'
|
10
|
+
require 'stringio'
|
11
|
+
require 'ruby-progressbar'
|
12
|
+
|
13
|
+
module Qiniu2Upyun
|
14
|
+
require_relative 'qiniu2upyun/version'
|
15
|
+
require_relative 'qiniu2upyun/qiniu'
|
16
|
+
require_relative 'qiniu2upyun/upyun'
|
17
|
+
require_relative 'qiniu2upyun/migrating'
|
18
|
+
require_relative 'qiniu2upyun/config'
|
19
|
+
require_relative 'qiniu2upyun/error'
|
20
|
+
require_relative 'qiniu2upyun/data'
|
21
|
+
require_relative 'qiniu2upyun/record'
|
22
|
+
require_relative 'qiniu2upyun/utils'
|
23
|
+
|
24
|
+
def self.migrate!(options={})
|
25
|
+
Config.load!(options.delete(:config))
|
26
|
+
|
27
|
+
qiniu = Qiniu.new(Config.qiniu)
|
28
|
+
upyun = Upyun.new(Config.upyun)
|
29
|
+
|
30
|
+
Migrating.new(qiniu, upyun).perform!
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Qiniu2Upyun
|
4
|
+
class CLI
|
5
|
+
DEFAULT_OPTIONS = {
|
6
|
+
config: "#{ENV['HOME']}/.qiniu2upyun.yml"
|
7
|
+
}
|
8
|
+
|
9
|
+
def parse
|
10
|
+
options = {}
|
11
|
+
|
12
|
+
parser = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: qiniu2upyun [options]"
|
14
|
+
|
15
|
+
opts.on("-C", "--config PATH",
|
16
|
+
"Load PATH as a config file",
|
17
|
+
"(default: #{DEFAULT_OPTIONS[:config]})") do |c|
|
18
|
+
|
19
|
+
options[:config] = c
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-V", "--version", "Show version") do |v|
|
23
|
+
require File.expand_path('../version', __FILE__)
|
24
|
+
|
25
|
+
puts "qiniu2upyun version #{Qiniu2Upyun::VERSION}"
|
26
|
+
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Show help") do |h|
|
31
|
+
puts opts
|
32
|
+
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
end.parse!
|
36
|
+
|
37
|
+
options
|
38
|
+
end
|
39
|
+
|
40
|
+
def run!
|
41
|
+
options = DEFAULT_OPTIONS.merge(parse)
|
42
|
+
|
43
|
+
require File.expand_path('../../qiniu2upyun', __FILE__)
|
44
|
+
|
45
|
+
Qiniu2Upyun.migrate!(options)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Config
|
3
|
+
class Qiniu
|
4
|
+
attr_reader :access_key, :secret_key, :bucket, :domain
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@access_key = options['access_key']
|
8
|
+
@secret_key = options['secret_key']
|
9
|
+
@bucket = options['bucket']
|
10
|
+
@domain = options['domain'] || default_domain
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_domain
|
14
|
+
"http://#{bucket}.qiniudn.com"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Upyun
|
19
|
+
attr_reader :username, :password, :bucket
|
20
|
+
|
21
|
+
def initialize(options)
|
22
|
+
@username = options['username']
|
23
|
+
@password = options['password']
|
24
|
+
@bucket = options['bucket']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
attr_reader :qiniu, :upyun
|
30
|
+
|
31
|
+
def load!(path)
|
32
|
+
raise NoConfigFileFoundError.new(path) unless File.exists?(path)
|
33
|
+
|
34
|
+
config = YAML.load_file(path)
|
35
|
+
|
36
|
+
@qiniu = Qiniu.new(config['qiniu'])
|
37
|
+
@upyun = Upyun.new(config['upyun'])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Data
|
3
|
+
attr_reader :io, :bar
|
4
|
+
|
5
|
+
def initialize(io, bar)
|
6
|
+
@io = io
|
7
|
+
@bar = bar
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(*args, &block)
|
11
|
+
result = io.read(*args, &block)
|
12
|
+
|
13
|
+
length = args.last.length
|
14
|
+
|
15
|
+
length > 0 ? bar.progress += length : bar.finish
|
16
|
+
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(*args, &block)
|
21
|
+
result = io.write(*args, &block)
|
22
|
+
|
23
|
+
bar.progress += result
|
24
|
+
|
25
|
+
bar.finish if bar.total == io.length
|
26
|
+
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method, *args, &block)
|
31
|
+
io.send(method)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class NoConfigFileFoundError < StandardError
|
3
|
+
def initialize(path)
|
4
|
+
@path = path
|
5
|
+
end
|
6
|
+
|
7
|
+
def message
|
8
|
+
"No config file found: #{@path}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ResponseError < StandardError
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
"<#{@response.code}: #{@response.body}>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class NoActionError < StandardError
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Migrating
|
3
|
+
attr_reader :from, :to, :record, :migrated_count, :skipped_count
|
4
|
+
|
5
|
+
def initialize(from, to)
|
6
|
+
@from = from
|
7
|
+
@to = to
|
8
|
+
@record = Record.new
|
9
|
+
@migrated_count = 0
|
10
|
+
@skipped_count = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def perform!
|
14
|
+
if from.is_a?(Qiniu) && to.is_a?(Upyun)
|
15
|
+
from_qiniu_to_upyun
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def from_qiniu_to_upyun
|
22
|
+
record.recording do |init_marker, init_key|
|
23
|
+
time = Time.now
|
24
|
+
|
25
|
+
if init_key
|
26
|
+
sources = get_sources(init_marker)
|
27
|
+
|
28
|
+
marker, items = sources['marker'], cut_items(sources['items'], init_key)
|
29
|
+
|
30
|
+
perform_items(items, init_marker)
|
31
|
+
else
|
32
|
+
marker = init_marker
|
33
|
+
end
|
34
|
+
|
35
|
+
while marker && (_marker = marker.dup)
|
36
|
+
sources = get_sources(marker)
|
37
|
+
|
38
|
+
marker, items = sources['marker'], sources['items']
|
39
|
+
|
40
|
+
perform_items(items, _marker)
|
41
|
+
end
|
42
|
+
|
43
|
+
puts "\nComplete, migrated %s files and skipped %s files in %.2f seconds.\n\n" %
|
44
|
+
[migrated_count.to_s.green, skipped_count.to_s.red, Time.now-time]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def perform_items(items, marker)
|
49
|
+
items.each do |item|
|
50
|
+
record.set(marker, item['key']) do
|
51
|
+
perform_item(item['key']) ? @migrated_count+=1 : @skipped_count+=1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def perform_item(key)
|
57
|
+
if to.exist?(key)
|
58
|
+
puts "\nFetch '#{key}` from #{from.name}:".red
|
59
|
+
|
60
|
+
puts " Already exists in #{to.name} and skip migrating.".red
|
61
|
+
|
62
|
+
false
|
63
|
+
else
|
64
|
+
puts "\nFetch '#{key}` from #{from.name}:".green
|
65
|
+
|
66
|
+
time = Time.now
|
67
|
+
|
68
|
+
data = from.download(key)
|
69
|
+
|
70
|
+
to.upload(key, data)
|
71
|
+
|
72
|
+
puts ("%60s" % "(#{data.length}B/#{(Time.now-time).round(2)}s)").green
|
73
|
+
|
74
|
+
true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_sources(marker)
|
79
|
+
marker == Record::START_MARKER ? sources = from.list : sources = from.list(marker: marker)
|
80
|
+
end
|
81
|
+
|
82
|
+
def cut_items(items, key)
|
83
|
+
index = items.index { |item| item['key'] == key }
|
84
|
+
|
85
|
+
index ? items.drop(index+1) : items
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Qiniu
|
3
|
+
attr_reader :config
|
4
|
+
|
5
|
+
HOST = 'http://rsf.qbox.me'
|
6
|
+
NAME = 'qiniu'
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
NAME
|
14
|
+
end
|
15
|
+
|
16
|
+
def list(params={})
|
17
|
+
uri = get_list_uri(params)
|
18
|
+
|
19
|
+
Net::HTTP.start(uri.host) do |http|
|
20
|
+
request = Net::HTTP::Post.new(uri)
|
21
|
+
|
22
|
+
set_headers(request, uri)
|
23
|
+
|
24
|
+
response = http.request(request)
|
25
|
+
|
26
|
+
if response.is_a?(Net::HTTPOK)
|
27
|
+
JSON.parse(response.body)
|
28
|
+
else
|
29
|
+
raise ResponseError.new(response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def download(key)
|
35
|
+
uri = get_download_uri(key)
|
36
|
+
|
37
|
+
Net::HTTP.start(uri.host) do |http|
|
38
|
+
request = Net::HTTP::Get.new(uri)
|
39
|
+
|
40
|
+
http.request(request) do |response|
|
41
|
+
data = get_data(key, response)
|
42
|
+
|
43
|
+
response.read_body { |chunk| data.write(chunk) }
|
44
|
+
|
45
|
+
data.io.rewind
|
46
|
+
|
47
|
+
return(data.io)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def set_headers(request, uri)
|
55
|
+
access_token = get_access_token(uri)
|
56
|
+
|
57
|
+
request['Authorization'] = access_token
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def get_data(key, response)
|
62
|
+
length = response['Content-Length'].to_i
|
63
|
+
|
64
|
+
bar = Utils.get_bar(length, 'Download')
|
65
|
+
|
66
|
+
if length > 1024 * 1024
|
67
|
+
Data.new(Tempfile.new(key), bar)
|
68
|
+
else
|
69
|
+
Data.new(StringIO.new, bar)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_list_uri(params)
|
74
|
+
default_params = {
|
75
|
+
bucket: config.bucket,
|
76
|
+
limit: 100,
|
77
|
+
marker: nil,
|
78
|
+
prefix: nil
|
79
|
+
}
|
80
|
+
|
81
|
+
query = URI.encode_www_form(default_params.merge(params))
|
82
|
+
|
83
|
+
uri = URI(URI.encode("#{HOST}/list?#{query}"))
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_download_uri(key)
|
87
|
+
url = "#{config.domain}/#{key}?e=#{Time.now.utc.to_i + 3600}"
|
88
|
+
|
89
|
+
uri = URI(URI.encode(url))
|
90
|
+
|
91
|
+
download_token = get_download_token(uri)
|
92
|
+
|
93
|
+
url = url.concat("&token=#{download_token}")
|
94
|
+
|
95
|
+
uri = URI(URI.encode(url))
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_download_token(uri)
|
99
|
+
get_sign(uri.to_s)
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_access_token(uri, body=nil)
|
103
|
+
"QBox #{get_sign("#{uri.request_uri}\n#{body}")}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_sign(signing_str)
|
107
|
+
digest = OpenSSL::Digest.new('sha1')
|
108
|
+
|
109
|
+
sign = OpenSSL::HMAC.digest(digest, config.secret_key, signing_str)
|
110
|
+
|
111
|
+
encoding_sign = Base64.urlsafe_encode64(sign)
|
112
|
+
|
113
|
+
"#{config.access_key}:#{encoding_sign}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Record
|
3
|
+
PATH = '/tmp/qiniu2upyun'
|
4
|
+
START_MARKER = '0'
|
5
|
+
|
6
|
+
def get
|
7
|
+
File.exists?(PATH) ? File.open(PATH, 'r').read.split(':') : [START_MARKER, nil]
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(marker, key)
|
11
|
+
yield if block_given?
|
12
|
+
|
13
|
+
File.open(PATH, 'w').write("#{marker}:#{key}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete
|
17
|
+
File.delete(PATH) if File.exists?(PATH)
|
18
|
+
end
|
19
|
+
|
20
|
+
def recording(&block)
|
21
|
+
marker, key = get
|
22
|
+
|
23
|
+
if key
|
24
|
+
puts "Migration is not completed on time.(marker: #{marker}, key: #{key})"
|
25
|
+
puts " 1: Continue"
|
26
|
+
puts " 2: Restart"
|
27
|
+
print "Input: "
|
28
|
+
|
29
|
+
case gets.chomp.to_i
|
30
|
+
when 1
|
31
|
+
when 2 then marker, key = START_MARKER, nil
|
32
|
+
else
|
33
|
+
raise NoActionError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
yield(marker, key)
|
38
|
+
|
39
|
+
delete
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
class Upyun
|
3
|
+
attr_reader :config
|
4
|
+
|
5
|
+
HOST = 'http://v0.api.upyun.com'
|
6
|
+
NAME = 'upyun'
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def name
|
13
|
+
NAME
|
14
|
+
end
|
15
|
+
|
16
|
+
def exist?(key)
|
17
|
+
info(key)
|
18
|
+
rescue ResponseError
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def upload(key, data)
|
23
|
+
uri = URI(URI.encode("#{HOST}/#{config.bucket}/#{key}"))
|
24
|
+
|
25
|
+
send_request(uri, 'PUT', data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def info(key)
|
29
|
+
uri = URI(URI.encode("#{HOST}/#{config.bucket}/#{key}"))
|
30
|
+
|
31
|
+
response = send_request(uri, 'HEAD')
|
32
|
+
|
33
|
+
response.is_a?(Net::HTTPOK) or raise ResponseError.new(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def send_request(uri, method, data=nil, headers={})
|
39
|
+
Net::HTTP.start(uri.host) do |http|
|
40
|
+
request = get_request(method, uri)
|
41
|
+
|
42
|
+
set_headers(request, uri, method, data, headers)
|
43
|
+
|
44
|
+
if data.nil?
|
45
|
+
http.request(request)
|
46
|
+
else
|
47
|
+
bar = Utils.get_bar(data.length, 'Upload')
|
48
|
+
|
49
|
+
request.body_stream = Data.new(data, bar)
|
50
|
+
|
51
|
+
http.request(request)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_request(method, uri)
|
57
|
+
Net::HTTP.const_get(method[0].concat(method[1..-1].downcase)).new(uri)
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_headers(request, uri, method, data, headers)
|
61
|
+
current = Time.now.utc.httpdate
|
62
|
+
|
63
|
+
content_length = data ? data.length : 0
|
64
|
+
|
65
|
+
sign = get_sign(method, current, uri, content_length)
|
66
|
+
|
67
|
+
default_headers = {
|
68
|
+
'Authorization' => sign,
|
69
|
+
'Date' => current,
|
70
|
+
'Content-Length' => content_length
|
71
|
+
}
|
72
|
+
|
73
|
+
headers = default_headers.merge(headers)
|
74
|
+
|
75
|
+
headers.each { |key, value| request[key] = value }
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_sign(method, current, uri, content_length)
|
79
|
+
digested_password = Digest::MD5.hexdigest(config.password)
|
80
|
+
|
81
|
+
signing_str = "#{method}&#{uri.path}&#{current}&#{content_length}&#{digested_password}"
|
82
|
+
|
83
|
+
sign = Digest::MD5.hexdigest(signing_str)
|
84
|
+
|
85
|
+
"UpYun #{config.username}:#{sign}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Qiniu2Upyun
|
2
|
+
module Utils
|
3
|
+
class << self
|
4
|
+
def get_bar(total, title)
|
5
|
+
ProgressBar.create(
|
6
|
+
title: ("%12s" % title),
|
7
|
+
length: 60,
|
8
|
+
total: total,
|
9
|
+
format: "%t |%B| %p%".green
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class String
|
17
|
+
def colorize(code)
|
18
|
+
"\e[#{code}m#{self}\e[0m"
|
19
|
+
end
|
20
|
+
|
21
|
+
def red
|
22
|
+
colorize(31)
|
23
|
+
end
|
24
|
+
|
25
|
+
def green
|
26
|
+
colorize(32)
|
27
|
+
end
|
28
|
+
|
29
|
+
def yellow
|
30
|
+
colorize(33)
|
31
|
+
end
|
32
|
+
|
33
|
+
def pink
|
34
|
+
colorize(35)
|
35
|
+
end
|
36
|
+
end
|
data/qiniu2upyun.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require File.expand_path('../lib/qiniu2upyun/version', __FILE__)
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "qiniu2upyun"
|
9
|
+
spec.version = Qiniu2Upyun::VERSION
|
10
|
+
spec.authors = ["zhouguangming"]
|
11
|
+
spec.email = ["zhouguangming1989@gmail.com"]
|
12
|
+
spec.summary = %q{Migrate Qiniu to Upyun.}
|
13
|
+
spec.description = %q{Migrate Qiniu to Upyun.}
|
14
|
+
spec.homepage = "https://gitcafe.com/zgm/QINIU-to-UPYUN"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_dependency "ruby-progressbar"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qiniu2upyun
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- zhouguangming
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: ruby-progressbar
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Migrate Qiniu to Upyun.
|
56
|
+
email:
|
57
|
+
- zhouguangming1989@gmail.com
|
58
|
+
executables:
|
59
|
+
- qiniu2upyun
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/qiniu2upyun
|
69
|
+
- lib/qiniu2upyun.rb
|
70
|
+
- lib/qiniu2upyun/cli.rb
|
71
|
+
- lib/qiniu2upyun/config.rb
|
72
|
+
- lib/qiniu2upyun/data.rb
|
73
|
+
- lib/qiniu2upyun/error.rb
|
74
|
+
- lib/qiniu2upyun/migrating.rb
|
75
|
+
- lib/qiniu2upyun/qiniu.rb
|
76
|
+
- lib/qiniu2upyun/record.rb
|
77
|
+
- lib/qiniu2upyun/upyun.rb
|
78
|
+
- lib/qiniu2upyun/utils.rb
|
79
|
+
- lib/qiniu2upyun/version.rb
|
80
|
+
- qiniu2upyun.gemspec
|
81
|
+
homepage: https://gitcafe.com/zgm/QINIU-to-UPYUN
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.2.2
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: Migrate Qiniu to Upyun.
|
105
|
+
test_files: []
|