ale 0.0.3.pre3 → 0.0.3.pre4
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.
- data/README.md +2 -11
- data/ale.gemspec +3 -2
- data/lib/ale.rb +1 -0
- data/lib/ale/bucket.rb +130 -0
- data/lib/ale/cli.rb +16 -2
- data/lib/ale/uploader.rb +20 -13
- data/lib/ale/version.rb +1 -1
- data/lib/templates/website_configuration.xml +8 -0
- metadata +21 -8
data/README.md
CHANGED
@@ -10,15 +10,6 @@ Installation
|
|
10
10
|
|
11
11
|
gem install ale
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
Getting Started
|
14
|
+
---------------
|
15
15
|
|
16
|
-
Getting a S3 bucket set up for websites takes a little bit of work up front,
|
17
|
-
but it is something you only have to do once and then it is smooth saling.
|
18
|
-
Starting by logging into (S3 console)[http://console.aws.amazon.com/] and
|
19
|
-
creating a bucket with the same name as the URL for you website. Make sure
|
20
|
-
that the bucket includes a subdomain (like 'www', for example). Once you've
|
21
|
-
created your bucket, click on *Properties* nears the top and then on the
|
22
|
-
tab named *Website*. Check the box labeled *Enabled* and then fill in
|
23
|
-
the text box for *Index Document* (something like `index.html` works well).
|
24
|
-
That's it for S3.
|
data/ale.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.files = `git ls-files`.split("\n")
|
19
19
|
s.require_paths = ['lib']
|
20
20
|
|
21
|
-
s.add_dependency('
|
22
|
-
s.add_dependency('
|
21
|
+
s.add_dependency('crack', '~> 0.3.1')
|
22
|
+
s.add_dependency('net-http-persistent', '~> 2.1')
|
23
|
+
s.add_dependency('thor', '~> 0.14.6')
|
23
24
|
end
|
data/lib/ale.rb
CHANGED
data/lib/ale/bucket.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'crack'
|
3
|
+
require 'mime/types'
|
4
|
+
require 'net/http/persistent'
|
5
|
+
require 'time'
|
6
|
+
|
7
|
+
module Ale
|
8
|
+
class Bucket
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def create(name)
|
13
|
+
self.new(name).tap {|bucket| bucket.create }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(name)
|
18
|
+
@name = name
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates the bucket on S3. It does not throw an error if the bucket
|
22
|
+
# already exsists.
|
23
|
+
#
|
24
|
+
def create
|
25
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
26
|
+
request.add_field('x-amz-acl', 'private')
|
27
|
+
send(uri, request)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Allows the bucket to be used to host websites.
|
31
|
+
#
|
32
|
+
def enable_website
|
33
|
+
uri = uri(query: 'website')
|
34
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
35
|
+
request.body = File.read(File.expand_path('../../templates/website_configuration.xml', __FILE__))
|
36
|
+
send(uri, request)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns true of the bucket exsists on S3.
|
40
|
+
#
|
41
|
+
def exists?
|
42
|
+
request = Net::HTTP::Head.new(uri.request_uri)
|
43
|
+
send(uri, request) do |response|
|
44
|
+
return response.class == Net::HTTPOK
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns an array of all of the objects in the bucket.
|
49
|
+
#
|
50
|
+
def objects
|
51
|
+
uri = uri(prefix: 'prefix=/')
|
52
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
53
|
+
send(uri, request) do |response|
|
54
|
+
list = Crack::XML.parse(response.body)
|
55
|
+
# Make sure we're returning an Array.
|
56
|
+
return [list['ListBucketResult']['Contents']].flatten.compact
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Removes an object form the bucket.
|
61
|
+
#
|
62
|
+
def remove(key)
|
63
|
+
uri = uri(key)
|
64
|
+
request = Net::HTTP::Delete.new(uri.request_uri)
|
65
|
+
send(uri, request)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Uploads a file to the specified key on S3.
|
69
|
+
#
|
70
|
+
def upload(file, key, permissions = 'private')
|
71
|
+
uri = uri(key)
|
72
|
+
file = File.open(file, 'rb')
|
73
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
74
|
+
request.add_field('Content-Length', file.size)
|
75
|
+
request.add_field('Content-Type', MIME::Types.of(file.path))
|
76
|
+
request.add_field('x-amz-acl', permissions)
|
77
|
+
request.body_stream = file
|
78
|
+
send(uri, request)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# Creates an authorization string for the request.
|
84
|
+
# http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
|
85
|
+
#
|
86
|
+
def authorization(uri, request)
|
87
|
+
string_to_sign = "#{request.class::METHOD}\n"
|
88
|
+
string_to_sign << "\n"
|
89
|
+
string_to_sign << "#{request['Content-Type']}\n"
|
90
|
+
string_to_sign << "#{request['Date']}\n"
|
91
|
+
|
92
|
+
amz_headers = request.to_hash.collect {|h,v| "#{h}:#{v.join(',')}" if h =~ /x-amz-/ }.compact.sort
|
93
|
+
string_to_sign << amz_headers.join("\n") << "\n" unless amz_headers.empty?
|
94
|
+
|
95
|
+
string_to_sign << uri.request_uri
|
96
|
+
|
97
|
+
digest = OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), Ale::Config.amazon_secret_access_key, string_to_sign)
|
98
|
+
signature = Base64.encode64(digest).chomp
|
99
|
+
|
100
|
+
"AWS #{Ale::Config.amazon_access_key_id}:#{signature}"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Helps construct URIs for interacting the S3's REST API.
|
104
|
+
#
|
105
|
+
def uri(options_or_path = {}, options = {})
|
106
|
+
if options_or_path.is_a?(Hash)
|
107
|
+
options, path = options_or_path, '/'
|
108
|
+
else
|
109
|
+
path = options_or_path
|
110
|
+
end
|
111
|
+
path = URI.escape(path.sub(/^\//, ''))
|
112
|
+
URI::HTTP.build(options.merge(host: 's3.amazonaws.com', path: "/#{name}/#{path}"))
|
113
|
+
end
|
114
|
+
|
115
|
+
def connection
|
116
|
+
@_connection ||= Net::HTTP::Persistent.new("ale/#{name}")
|
117
|
+
end
|
118
|
+
|
119
|
+
# Send a request object to the URI passed in.
|
120
|
+
#
|
121
|
+
def send(uri, request, &block)
|
122
|
+
unless request.to_hash.key?('Content-Type')
|
123
|
+
request.add_field('Content-Type', 'application/x-www-form-urlencoded')
|
124
|
+
end
|
125
|
+
request.add_field('Date', Time.now.utc.rfc822)
|
126
|
+
request.add_field('Authorization', authorization(uri, request))
|
127
|
+
connection.request(uri, request, &block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/ale/cli.rb
CHANGED
@@ -33,6 +33,21 @@ module Ale
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
desc 'setup', 'Creates the bucket on S3 and enabled it for websites'
|
37
|
+
def setup
|
38
|
+
opts = options.dup
|
39
|
+
|
40
|
+
Ale.alefile = opts[:alefile]
|
41
|
+
Ale::Config.load(Ale.alefile)
|
42
|
+
|
43
|
+
say("Setting up website for bucket: #{Ale::Config.bucket}")
|
44
|
+
uploader.setup!
|
45
|
+
rescue AlefileNotFound
|
46
|
+
say('Count not locale Alefile', :red)
|
47
|
+
rescue BucketNotSpecified
|
48
|
+
say('No bucket specificed in Alefile', :red)
|
49
|
+
end
|
50
|
+
|
36
51
|
desc 'upload', 'Uploads the built site to S3'
|
37
52
|
method_option 'alefile', :type => :string, :banner =>
|
38
53
|
'Use the specified alefile instead of Alefile'
|
@@ -42,9 +57,8 @@ module Ale
|
|
42
57
|
Ale.alefile = opts[:alefile]
|
43
58
|
Ale::Config.load(Ale.alefile)
|
44
59
|
|
45
|
-
uploader.upload!
|
46
|
-
|
47
60
|
say("Uploading site in #{uploader.site.directory}")
|
61
|
+
uploader.upload!
|
48
62
|
rescue AlefileNotFound
|
49
63
|
say('Count not locale Alefile', :red)
|
50
64
|
rescue BucketNotFound
|
data/lib/ale/uploader.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
require 'aws-sdk'
|
2
|
-
|
3
1
|
module Ale
|
4
2
|
class Uploader
|
5
3
|
attr_reader :site
|
6
4
|
|
5
|
+
def setup!
|
6
|
+
Ale::Bucket.create(Ale::Config.bucket)
|
7
|
+
bucket.enable_website
|
8
|
+
end
|
9
|
+
|
7
10
|
def initialize(site)
|
8
11
|
@site = site
|
9
12
|
end
|
@@ -18,7 +21,7 @@ module Ale
|
|
18
21
|
def bucket
|
19
22
|
return @bucket unless @bucket.nil?
|
20
23
|
raise Ale::BucketNotSpecified if Ale::Config.bucket.empty?
|
21
|
-
@bucket =
|
24
|
+
@bucket = Ale::Bucket.new(Ale::Config.bucket)
|
22
25
|
raise Ale::BucketNotFound unless @bucket.exists?
|
23
26
|
@bucket
|
24
27
|
end
|
@@ -45,7 +48,7 @@ module Ale
|
|
45
48
|
end
|
46
49
|
|
47
50
|
def permissions(file)
|
48
|
-
private_files.include?(file) ?
|
51
|
+
private_files.include?(file) ? 'private' : 'public-read'
|
49
52
|
end
|
50
53
|
|
51
54
|
def private_files
|
@@ -58,9 +61,9 @@ module Ale
|
|
58
61
|
|
59
62
|
def remove_stale_files_from_s3
|
60
63
|
bucket.objects.each do |object|
|
61
|
-
unless files.include?("#{site.directory}/#{object
|
62
|
-
puts "Deleting old file #{object
|
63
|
-
object
|
64
|
+
unless files.include?("#{site.directory}/#{object['Key']}")
|
65
|
+
puts "Deleting old file #{object['Key']}"
|
66
|
+
bucket.remove(object['Key'])
|
64
67
|
end
|
65
68
|
end
|
66
69
|
end
|
@@ -69,17 +72,21 @@ module Ale
|
|
69
72
|
files.each do |file|
|
70
73
|
unless File.directory?(file)
|
71
74
|
key = key_name(file)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
+
keys_on_s3 = bucket.objects.map {|object| object['Key']}
|
76
|
+
|
77
|
+
if keys_on_s3.include?(key)
|
78
|
+
object = bucket.objects.find {|obj| obj['Key'] == key }
|
79
|
+
last_modified = Time.parse(object['LastModified'])
|
80
|
+
|
81
|
+
if last_modified < File.mtime(file)
|
75
82
|
puts "Updating file #{key}"
|
76
|
-
|
83
|
+
bucket.upload(file, key, permissions(file))
|
77
84
|
else
|
78
85
|
puts "File #{key} is already on S3"
|
79
86
|
end
|
80
87
|
else
|
81
|
-
puts "Uploading
|
82
|
-
|
88
|
+
puts "Uploading file #{key}"
|
89
|
+
bucket.upload(file, key, permissions(file))
|
83
90
|
end
|
84
91
|
end
|
85
92
|
end
|
data/lib/ale/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.3.
|
4
|
+
version: 0.0.3.pre4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: crack
|
16
|
+
requirement: &70280802231900 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 0.3.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70280802231900
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: net-http-persistent
|
27
|
+
requirement: &70280802230400 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.1'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70280802230400
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: thor
|
27
|
-
requirement: &
|
38
|
+
requirement: &70280802227160 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
40
|
requirements:
|
30
41
|
- - ~>
|
@@ -32,7 +43,7 @@ dependencies:
|
|
32
43
|
version: 0.14.6
|
33
44
|
type: :runtime
|
34
45
|
prerelease: false
|
35
|
-
version_requirements: *
|
46
|
+
version_requirements: *70280802227160
|
36
47
|
description: Takes a static site and uploads it to Amazon's S3.
|
37
48
|
email: jeremy@jeremyboles.com
|
38
49
|
executables:
|
@@ -47,12 +58,14 @@ files:
|
|
47
58
|
- ale.gemspec
|
48
59
|
- bin/ale
|
49
60
|
- lib/ale.rb
|
61
|
+
- lib/ale/bucket.rb
|
50
62
|
- lib/ale/cli.rb
|
51
63
|
- lib/ale/config.rb
|
52
64
|
- lib/ale/site.rb
|
53
65
|
- lib/ale/uploader.rb
|
54
66
|
- lib/ale/version.rb
|
55
67
|
- lib/templates/Alefile
|
68
|
+
- lib/templates/website_configuration.xml
|
56
69
|
- test/ale_defaults_test.rb
|
57
70
|
- test/test_helper.rb
|
58
71
|
homepage: https://github.com/jeremyboles/ale
|