publish2cloud 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/publish2cloud.rb +1 -0
- data/lib/publish2cloud/publish2cloud.rb +177 -0
- data/lib/publish2cloud/railtie.rb +10 -0
- data/lib/publish2cloud/tasks.rb +22 -0
- data/lib/tasks/publish2cloud.rake +1 -0
- metadata +113 -0
@@ -0,0 +1 @@
|
|
1
|
+
require 'publish2cloud/railtie.rb' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'hmac-sha1' # on OS X: sudo gem install ruby-hmac
|
2
|
+
require 'net/https'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'base64'
|
6
|
+
require 'right_aws'
|
7
|
+
|
8
|
+
module Publish2Cloud
|
9
|
+
|
10
|
+
class Publisher
|
11
|
+
|
12
|
+
def initialize s3_access, s3_secret, s3_bucket, cf_distribution, max_age = nil
|
13
|
+
@s3_access = s3_access
|
14
|
+
@s3_secret = s3_secret
|
15
|
+
@s3_bucket = s3_bucket
|
16
|
+
@cf_distribution = cf_distribution
|
17
|
+
@max_age = max_age
|
18
|
+
end
|
19
|
+
|
20
|
+
def run urls
|
21
|
+
ensure_s3_bucket_exist
|
22
|
+
set_root 'index.html'
|
23
|
+
|
24
|
+
urls.each {|x|
|
25
|
+
uri = URI.parse(x)
|
26
|
+
if uri.path == "" or uri.path == "/"
|
27
|
+
s3_key = "index.html"
|
28
|
+
else
|
29
|
+
s3_key = uri.path[1..-1]
|
30
|
+
end
|
31
|
+
puts "#{x} -> #{s3_key}"
|
32
|
+
fetch_and_upload_to_s3 x, s3_key
|
33
|
+
invalidate [s3_key]
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
#http://aws.amazon.com/cloudfront/faqs/#How_long_will_Amazon_CloudFront_keep_my_files
|
38
|
+
#headers looks like this:
|
39
|
+
#{'Cache-Control' => public, max-age=86400', 'Content-Type' => 'text/html; charset=utf-8'}
|
40
|
+
#{'Cache-Control' => 'max-age=0, private, must-revalidate', 'Content-Type' => 'text/html; charset=utf-8'}
|
41
|
+
def fetch_and_upload_to_s3 url, s3_key
|
42
|
+
res = Net::HTTP.get_response URI.parse(url)
|
43
|
+
|
44
|
+
raise res.code if res.code != '200'
|
45
|
+
#puts res.body
|
46
|
+
|
47
|
+
s3= RightAws::S3.new(@s3_access, @s3_secret, {:logger => Logger.new('log/publish2cloud.log')})
|
48
|
+
bucket = s3.bucket(@s3_bucket)
|
49
|
+
if @max_age
|
50
|
+
headers = {'Cache-Control' => "public, max-age=#{@max_age}", 'Content-Type' => 'text/html; charset=utf-8'}
|
51
|
+
else
|
52
|
+
headers = {'Content-Type' => 'text/html; charset=utf-8'}
|
53
|
+
end
|
54
|
+
bucket.put(s3_key, res.body, {}, 'public-read', headers)
|
55
|
+
|
56
|
+
puts "Uploaded #{s3_key}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def invalidate paths_as_array
|
60
|
+
paths = nil
|
61
|
+
|
62
|
+
if paths_as_array.length > 0
|
63
|
+
paths = '<Path>/' + paths_as_array.join('</Path><Path>/') + '</Path>'
|
64
|
+
end
|
65
|
+
|
66
|
+
date = Time.now.utc
|
67
|
+
date = date.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
68
|
+
digest = HMAC::SHA1.new(@s3_secret)
|
69
|
+
digest << date
|
70
|
+
|
71
|
+
uri = URI.parse('https://cloudfront.amazonaws.com/2010-08-01/distribution/' + @cf_distribution + '/invalidation')
|
72
|
+
|
73
|
+
if paths != nil
|
74
|
+
req = Net::HTTP::Post.new(uri.path)
|
75
|
+
else
|
76
|
+
req = Net::HTTP::Get.new(uri.path)
|
77
|
+
end
|
78
|
+
|
79
|
+
req.initialize_http_header({
|
80
|
+
'x-amz-date' => date,
|
81
|
+
'Content-Type' => 'text/xml',
|
82
|
+
'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)]
|
83
|
+
})
|
84
|
+
|
85
|
+
if paths != nil
|
86
|
+
req.body = "<InvalidationBatch>" + paths + "<CallerReference>ref_#{Time.now.utc.to_i}</CallerReference></InvalidationBatch>"
|
87
|
+
end
|
88
|
+
|
89
|
+
#puts req.body
|
90
|
+
|
91
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
92
|
+
http.use_ssl = true
|
93
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
94
|
+
res = http.request(req)
|
95
|
+
|
96
|
+
# TODO: Check status code and pretty print the output
|
97
|
+
# Tip: pipe the output to | xmllint -format - |less for easier reading
|
98
|
+
#puts $STDERR res.code
|
99
|
+
#puts res.body
|
100
|
+
puts "Invalidated #{paths_as_array}"
|
101
|
+
return 0
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_root newobj
|
105
|
+
date = Time.now.utc
|
106
|
+
date = date.strftime("%a, %d %b %Y %H:%M:%S %Z")
|
107
|
+
digest = HMAC::SHA1.new(@s3_secret)
|
108
|
+
digest << date
|
109
|
+
|
110
|
+
uri = URI.parse('https://cloudfront.amazonaws.com/2010-08-01/distribution/' + @cf_distribution + '/config')
|
111
|
+
|
112
|
+
req = Net::HTTP::Get.new(uri.path)
|
113
|
+
|
114
|
+
req.initialize_http_header({
|
115
|
+
'x-amz-date' => date,
|
116
|
+
'Content-Type' => 'text/xml',
|
117
|
+
'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)]
|
118
|
+
})
|
119
|
+
|
120
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
121
|
+
http.use_ssl = true
|
122
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
123
|
+
res = http.request(req)
|
124
|
+
puts res
|
125
|
+
match = /<DefaultRootObject>(.*?)<\/DefaultRootObject>/.match(res.body)
|
126
|
+
currentobj = match ? match[1] : nil
|
127
|
+
|
128
|
+
if newobj == currentobj
|
129
|
+
puts "'#{currentobj}' is already the DefaultRootObject"
|
130
|
+
return -1
|
131
|
+
end
|
132
|
+
|
133
|
+
etag = res.header['etag']
|
134
|
+
|
135
|
+
req = Net::HTTP::Put.new(uri.path)
|
136
|
+
|
137
|
+
req.initialize_http_header({
|
138
|
+
'x-amz-date' => date,
|
139
|
+
'Content-Type' => 'text/xml',
|
140
|
+
'Authorization' => "AWS %s:%s" % [@s3_access, Base64.encode64(digest.digest)],
|
141
|
+
'If-Match' => etag
|
142
|
+
})
|
143
|
+
|
144
|
+
if currentobj == nil
|
145
|
+
regex = /<\/DistributionConfig>/
|
146
|
+
replace = "<DefaultRootObject>#{newobj}</DefaultRootObject></DistributionConfig>"
|
147
|
+
else
|
148
|
+
regex = /<DefaultRootObject>(.*?)<\/DefaultRootObject>/
|
149
|
+
replace = "<DefaultRootObject>#{newobj}</DefaultRootObject>"
|
150
|
+
end
|
151
|
+
|
152
|
+
req.body = res.body.gsub(regex, replace)
|
153
|
+
|
154
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
155
|
+
http.use_ssl = true
|
156
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
157
|
+
res = http.request(req)
|
158
|
+
|
159
|
+
puts res.code
|
160
|
+
puts res.body
|
161
|
+
return 0
|
162
|
+
end
|
163
|
+
|
164
|
+
def ensure_s3_bucket_exist
|
165
|
+
s3= RightAws::S3.new(@s3_access, @s3_secret, {:logger => Logger.new('log/publish2cloud.log')})
|
166
|
+
bucket = s3.bucket(@s3_bucket)
|
167
|
+
begin
|
168
|
+
bucket.keys
|
169
|
+
puts "Bucket '#{@s3_bucket}' exists"
|
170
|
+
rescue
|
171
|
+
puts "Going to creat '#{@s3_bucket}'"
|
172
|
+
RightAws::S3::Bucket.create(s3, @s3_bucket, true, 'public-read')
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'publish2cloud', 'publish2cloud'))
|
2
|
+
|
3
|
+
PUBLISH2CLOUD_CONFIG_FILE = Rails.root.join('config', 'publish2cloud.rb')
|
4
|
+
|
5
|
+
namespace :p2c do
|
6
|
+
desc "Publish2Cloud"
|
7
|
+
task :push do
|
8
|
+
|
9
|
+
require PUBLISH2CLOUD_CONFIG_FILE
|
10
|
+
p2c = Publish2Cloud::Publisher.new(P2C_S3_ACCESS_KEY_ID,
|
11
|
+
P2C_S3_SECRET_ACCESS_KEY,
|
12
|
+
P2C_S3_BUCKET,
|
13
|
+
P2C_CF_DISTRIBUTION_ID,
|
14
|
+
defined?(P2C_MAX_AGE) ? P2C_MAX_AGE : nil)
|
15
|
+
p2c.run P2C_URLS
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Analyze links of a given webpage"
|
19
|
+
task :analyze do
|
20
|
+
p ARGV
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'publish2cloud', 'tasks'))
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: publish2cloud
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Xue Yong Zhi
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-25 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: ruby-hmac
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: right_aws
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: nokogiri
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
description:
|
64
|
+
email:
|
65
|
+
- yong@intridea.com
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- lib/publish2cloud/publish2cloud.rb
|
74
|
+
- lib/publish2cloud/railtie.rb
|
75
|
+
- lib/publish2cloud/tasks.rb
|
76
|
+
- lib/publish2cloud.rb
|
77
|
+
- lib/tasks/publish2cloud.rake
|
78
|
+
has_rdoc: true
|
79
|
+
homepage:
|
80
|
+
licenses: []
|
81
|
+
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
hash: 3
|
93
|
+
segments:
|
94
|
+
- 0
|
95
|
+
version: "0"
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
requirements: []
|
106
|
+
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.3.7
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: publish2cloud
|
112
|
+
test_files: []
|
113
|
+
|