microstatic 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,3 +5,6 @@ The microstatic gem turns generating your static site and deploying it to S3 int
5
5
  ## Credits
6
6
 
7
7
  The s3 deployment code was originally written by [Giles Alexander](http://twitter.com/gga)
8
+
9
+ ## TODO
10
+ - DONE! create Route 53 subdomain on demand
@@ -1,17 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'microstatic'
4
+ require 'microstatic/cli'
4
5
 
5
- if ARGV.empty?
6
- puts 'please specify a bucket name'
7
- exit 1
8
- end
6
+ require 'pry' if ENV.has_key? 'PRY_PLEASE'
9
7
 
10
- bucket_name = ARGV[0]
11
-
12
- bucket_creator = Microstatic::S3BucketCreator.new( Microstatic.aws_creds_from_env )
13
-
14
- puts "creating bucket #{bucket_name} ..."
15
- bucket_creator.create( bucket_name )
16
-
17
- puts "done"
8
+ Microstatic::CLI.start(ARGV)
@@ -1,9 +1,11 @@
1
1
  require "microstatic/version"
2
2
 
3
+ require 'microstatic/config'
3
4
  require 'microstatic/uses_fog'
4
5
 
5
6
  require "microstatic/s3_deployer"
6
7
  require "microstatic/s3_bucket_creator"
8
+ require "microstatic/route53_dns"
7
9
 
8
10
  module Microstatic
9
11
  def self.aws_creds_from_env
@@ -0,0 +1,72 @@
1
+ require 'thor'
2
+ require 'rainbow'
3
+
4
+ module Microstatic
5
+ class CLI < Thor
6
+ desc "setup <APP_NAME>", "do the needful to get started hosting your static site. S3, Route 53, whatever it takes."
7
+ def setup( app_name = false )
8
+ app_name ||= inferred_app_name
9
+ bucket_name = subdomain_for(app_name)
10
+
11
+ bucket = bucket( bucket_name )
12
+ # TODO: pass bucket through to dns setup so we don't have to look it up again
13
+ dns( app_name )
14
+
15
+ # TODO: add Rakefile, Gemfile, etc for doing a rake deploy using this gem
16
+ end
17
+
18
+ desc "bucket <BUCKET_NAME>", "create an S3 bucket which can host your static site"
19
+ def bucket( bucket_name = false )
20
+ bucket_name ||= guess_bucket_name
21
+ # TODO: check it doesn't already exist for you
22
+ # TODO: check bucket_name looks like a site name (e.g. foo.thepete.net, not just foo)
23
+ # TODO: handle the bucket name already being taken by someone else
24
+ # TODO: fail gracefully if aws creds not available
25
+
26
+ describe_operation( "create S3 bucket '#{bucket_name}'" ) do
27
+ S3BucketCreator.new( config.aws_creds ).create( bucket_name )
28
+ end
29
+ end
30
+
31
+ desc "dns <APP_NAME>", "create a Route 53 entry pointing to the S3 bucket containing your static site"
32
+ def dns( app_name = false )
33
+ app_name ||= inferred_app_name
34
+ bucket_name = subdomain_for(app_name)
35
+
36
+ describe_operation( "create Route 53 entry '#{bucket_name}'" ) do
37
+ Route53Dns.new( config.aws_creds ).add_s3_record_for_bucket( bucket_name )
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def guess_bucket_name
44
+ subdomain_for( inferred_app_name )
45
+ end
46
+
47
+ def subdomain_for( app_name )
48
+ "#{app_name}.#{config.site_name}"
49
+ end
50
+
51
+ def inferred_app_name
52
+ File.basename(Dir.pwd)
53
+ end
54
+
55
+ def config
56
+ Config.automagic
57
+ end
58
+
59
+ def describe_operation( operation_desc )
60
+ STDOUT.print " #{operation_desc} ..."
61
+ yield
62
+ STDOUT.puts "\r- #{operation_desc} "+CHECKMARK
63
+ rescue
64
+ STDOUT.puts "\r- #{operation_desc} "+SADMARK
65
+ raise
66
+ end
67
+
68
+ CHECKMARK="\u2713".color(:green)
69
+ SADMARK="\u2718".color(:red)
70
+
71
+ end
72
+ end
@@ -0,0 +1,28 @@
1
+ module Microstatic
2
+ class Config
3
+ def self.automagic
4
+ #in the future this'll try to create a config based on
5
+ #various diff. files, in priority order?
6
+ self.new
7
+ end
8
+
9
+ def site_name
10
+ ENV.fetch('MICROSTATIC_SITE_NAME')
11
+ end
12
+
13
+ def aws_creds
14
+ {
15
+ :access_key_id => aws_access_key_id,
16
+ :secret_access_key => aws_secret_access_key
17
+ }
18
+ end
19
+
20
+ def aws_access_key_id
21
+ ENV.fetch('AWS_ACCESS_KEY_ID')
22
+ end
23
+
24
+ def aws_secret_access_key
25
+ ENV.fetch('AWS_SECRET_ACCESS_KEY')
26
+ end
27
+ end
28
+ end
@@ -39,7 +39,7 @@ class S3DeployTask < ::Rake::TaskLib
39
39
  end
40
40
  end
41
41
 
42
- def self.s3_deploy_task(opts)
42
+ def self.s3_deploy_task(opts = {})
43
43
  task = S3DeployTask.new( opts )
44
44
  yield task if block_given?
45
45
  task.define
@@ -0,0 +1,42 @@
1
+ module Microstatic
2
+
3
+ class Route53Dns
4
+ include UsesFog
5
+
6
+ def initialize( aws_creds )
7
+ check_and_store_aws_creds(aws_creds)
8
+ end
9
+
10
+ def add_s3_record_for_bucket( bucket_name, hostname = false )
11
+ subdomain ||= bucket_name
12
+
13
+ zone = parent_zone_for_subdomain( subdomain )
14
+ cname_value = website_endpoint_for_bucket_named( bucket_name )
15
+
16
+ record = zone.records.create(
17
+ :name => subdomain,
18
+ :value => cname_value,
19
+ :type => 'CNAME',
20
+ :ttl => 86400
21
+ )
22
+ record
23
+ end
24
+
25
+ private
26
+
27
+ def website_endpoint_for_bucket_named( bucket_name )
28
+ bucket = connection.directories.get(bucket_name)
29
+
30
+ # per http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteEndpoints.html
31
+ #TODO: get endpoint from API, or get this logic merged into fog
32
+ bucket_website_endpoint = "#{bucket.key}.s3-website-#{bucket.location}.amazonaws.com"
33
+ end
34
+
35
+ def parent_zone_for_subdomain( subdomain )
36
+ zone_name = subdomain.split(".")[1..-1].push("").join(".")
37
+ dns.zones.find{ |x| x.domain == zone_name }
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -8,9 +8,12 @@ class S3BucketCreator
8
8
  end
9
9
 
10
10
  def create( bucket_name )
11
- connection.put_bucket( bucket_name )
12
- connection.put_bucket_acl( bucket_name, 'public-read' )
13
- connection.put_bucket_website( bucket_name, 'index.html', :key => '404.html' )
11
+ # TODO: can we create a new directory without eagerly fetch the list of all dirs?
12
+ directory = connection.directories.create( :key => bucket_name, :public => true )
13
+ # TODO: can I do this by calling a method on directory?
14
+ connection.put_bucket_website( directory.key, 'index.html', :key => '404.html' )
15
+
16
+ directory
14
17
  end
15
18
  end
16
19
 
@@ -31,7 +31,7 @@ class S3Deployer
31
31
 
32
32
  if !s3_object
33
33
  log_action('CREATE', s3_key)
34
- connection.put_object( @bucket, s3_key, file.open, 'x-amz-acl' => 'public-read' )
34
+ put_file( s3_key, file )
35
35
  else
36
36
  s3_md5 = s3_object.headers['ETag'].sub(/"(.*)"/,'\1')
37
37
  local_md5 = Digest::MD5.hexdigest( file.read )
@@ -40,11 +40,17 @@ class S3Deployer
40
40
  log_action('NO CHANGE', s3_key)
41
41
  else
42
42
  log_action('UPDATE', s3_key)
43
- connection.put_object( @bucket, s3_key, file.open )
43
+ put_file( s3_key, file )
44
44
  end
45
45
  end
46
46
  end
47
47
 
48
+ private
49
+
50
+ def put_file( s3_key, file )
51
+ connection.put_object( @bucket, s3_key, file.open, 'x-amz-acl' => 'public-read', 'x-amz-storage-class' => 'REDUCED_REDUNDANCY' )
52
+ end
53
+
48
54
  def log_action(action,file)
49
55
  message = action.to_s.rjust(10) + " " + file
50
56
  puts message
@@ -10,8 +10,18 @@ module Microstatic
10
10
  @aws_creds = aws_creds
11
11
  end
12
12
 
13
+ # TODO: rename connection to storage
13
14
  def connection
14
15
  @_connection ||= Fog::Storage.new({
16
+ :provider => 'AWS',
17
+ :aws_access_key_id => @aws_creds.fetch(:access_key_id),
18
+ :aws_secret_access_key => @aws_creds.fetch(:secret_access_key),
19
+ :path_style => true
20
+ })
21
+ end
22
+
23
+ def dns
24
+ @_dns ||= Fog::DNS.new({
15
25
  :provider => 'AWS',
16
26
  :aws_access_key_id => @aws_creds.fetch(:access_key_id),
17
27
  :aws_secret_access_key => @aws_creds.fetch(:secret_access_key)
@@ -1,3 +1,3 @@
1
1
  module Microstatic
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -16,6 +16,8 @@ Gem::Specification.new do |gem|
16
16
  gem.version = Microstatic::VERSION
17
17
 
18
18
  gem.add_runtime_dependency "fog", ">=1"
19
+ gem.add_runtime_dependency "thor", ">=0.15" # 0.15 is an arbitrary guess at what might be API-compatible
20
+ gem.add_runtime_dependency "rainbow", ">= 1.1"
19
21
 
20
22
  gem.add_development_dependency "rake"
21
23
  gem.add_development_dependency "bundler"
@@ -1,3 +1,10 @@
1
1
  require_relative '../../lib/microstatic'
2
+ # require_relative '../../lib/microstatic/uses_fog'
2
3
 
4
+ if ENV['FOG_MOCK']
5
+ Fog.mock!
6
+ include Microstatic::UsesFog
7
+ check_and_store_aws_creds(Microstatic.aws_creds_from_env)
8
+ connection.directories.create(:key => 'microstatic-test-bucket')
9
+ end
3
10
  require 'pry'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: microstatic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-02 00:00:00.000000000 Z
12
+ date: 2013-12-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
@@ -27,6 +27,38 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0.15'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0.15'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rainbow
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '1.1'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
30
62
  - !ruby/object:Gem::Dependency
31
63
  name: rake
32
64
  requirement: !ruby/object:Gem::Requirement
@@ -109,7 +141,10 @@ files:
109
141
  - Rakefile
110
142
  - bin/microstatic
111
143
  - lib/microstatic.rb
144
+ - lib/microstatic/cli.rb
145
+ - lib/microstatic/config.rb
112
146
  - lib/microstatic/rake.rb
147
+ - lib/microstatic/route53_dns.rb
113
148
  - lib/microstatic/s3_bucket_creator.rb
114
149
  - lib/microstatic/s3_deployer.rb
115
150
  - lib/microstatic/uses_fog.rb
@@ -135,7 +170,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
170
  version: '0'
136
171
  segments:
137
172
  - 0
138
- hash: 2953068700068104113
173
+ hash: 3071074031925254256
139
174
  required_rubygems_version: !ruby/object:Gem::Requirement
140
175
  none: false
141
176
  requirements:
@@ -144,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
179
  version: '0'
145
180
  segments:
146
181
  - 0
147
- hash: 2953068700068104113
182
+ hash: 3071074031925254256
148
183
  requirements: []
149
184
  rubyforge_project:
150
185
  rubygems_version: 1.8.25