publish2cloud 0.1.0

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.
@@ -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,10 @@
1
+ require 'publish2cloud'
2
+ require 'rails'
3
+
4
+ module Publish2Cloud
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load 'publish2cloud/tasks.rb'
8
+ end
9
+ end
10
+ 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
+