fog_site 0.0.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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "http://rubygems.org"
2
+
3
+ group :development do
4
+ gem "bundler", "~> 1.0.0"
5
+ gem "jeweler", "~> 1.6.4"
6
+ end
7
+
8
+ gem "fog", ">= 0.10.0"
9
+ gem "colorize"
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Brian P O'Rourke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # fog_site #
2
+
3
+ *fog_site* is a simple utility gem for deploying a static site to Amazon S3 and
4
+ CloudFront using the *fog* gem.
5
+
6
+ To make deployments fast, this gem calculates the MD5 sum of every file locally
7
+ and compares them against the information stored on S3 (in the 'etag' property
8
+ of the S3 object). Files are only uploaded if the etag has changed.
9
+
10
+ ## Usage ##
11
+
12
+ Create a new site
13
+
14
+ site = FogSite.new "www.stovepipeapp.com"
15
+
16
+ Decide what you want to deploy
17
+
18
+ site.path = "/home/bpo/stovepipe"
19
+
20
+ Decide whether to destroy resources that aren't local
21
+
22
+ site.destroy_old_files = true
23
+
24
+ If you're using CloudFront, specify a distribution ID:
25
+
26
+ site.distribution_id = "Z99120CAFEBABE"
27
+
28
+ And push it to the cloud
29
+
30
+ site.deploy!
31
+
32
+ All local settings for a site can be passed into the `new_site` method:
33
+
34
+ FogSite.new "stovepipeapp.com", :path => "/home/bpo/stovepipe",
35
+ :destroy_old_files => true
36
+
37
+ AWS credentials are read from the environment variables `AWSAccessKeyId` and
38
+ `AWSSecretKey`, but can also be set programmatically:
39
+
40
+ site = FogSite.new "stovepipeapp.com"
41
+ site.access_key_id = "E7L8CCM59BFXJOAMEAPT"
42
+ site.secret_key = "t5nszajv3y8u4zI/LtP/r5xUmPnqAT/Tv2n7Xr7n"
43
+
44
+ ## Notes ##
45
+
46
+ ### Choice of Domains ###
47
+ You can't point a CNAME to the apex of a zone, which means you can't use S3 +
48
+ CloudFront to deploy to 'foo.com', you can only deploy to a subdomain like
49
+ 'www.foo.com'. If you want to have a URL like 'foo.com' work, you'll need to set
50
+ up a lightweight server that can accept requests for 'foo.com' and send a 301
51
+ permanent redirect to www.foo.com.
52
+
53
+ ### Cloudfront Cache Invalidation ###
54
+
55
+ This gem uses cache invalidation to force new content to be refreshed by
56
+ CloudFront distributions. This works just fine, but if your content changes
57
+ often, it's better (and cheaper) to use versioning. See the CloudFront developer
58
+ guide for details on how to implement a versioning system.
59
+
60
+ ## Copyright ##
61
+
62
+ Copyright (c) 2011 Brian P O'Rourke. See LICENSE.txt for
63
+ further details.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "fog_site"
18
+ gem.homepage = "http://github.com/bpo/fog_site"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Deploys static sites to S3 using fog}
21
+ gem.description = %Q{Simple utility gem for deploying static sites to S3 and CloudFront using fog.}
22
+ gem.email = "bpo@somnambulance.net"
23
+ gem.authors = ["Brian P O'Rourke"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
data/lib/fog_site.rb ADDED
@@ -0,0 +1,157 @@
1
+ require 'fog'
2
+ require "colorize"
3
+
4
+ #
5
+ # A FogSite represents a site to be deployed to S3 and CloudFront. This object
6
+ # is a simple data structure, which is deployed with a `FogSite::Deployer`
7
+ #
8
+ class FogSite
9
+ attr_reader :domain_name
10
+ attr_writer :access_key_id, :secret_key
11
+ attr_accessor :path, :destroy_old_files, :distribution_id
12
+
13
+ def initialize( domain_name, attributes_map = {})
14
+ @domain_name = domain_name
15
+ attributes_map.each do |name, val|
16
+ setter = (name.to_s + "=").to_sym
17
+ self.send(setter, val)
18
+ end
19
+ end
20
+
21
+ def access_key_id
22
+ @access_key_id || ENV["AWSAccessKeyId"]
23
+ end
24
+
25
+ def secret_key
26
+ @secret_key || ENV["AWSSecretKey"]
27
+ end
28
+
29
+ def deploy!
30
+ Deployer.run(self)
31
+ end
32
+
33
+ # Used to actually execute a deploy. This object is not safe for reuse - the
34
+ # `@index` and `@updated_paths` stay dirty after a deploy to allow debugging
35
+ # and inspection by client scripts.
36
+ class Deployer
37
+ attr_reader :index, :updated_paths
38
+ class UsageError < StandardError ; end
39
+
40
+ # Run a single deploy. Creates a new `Deployer` and calls `run`.
41
+ def self.run( site, options = {} )
42
+ deployer = Deployer.new( site )
43
+ deployer.run
44
+ end
45
+
46
+ def initialize( site )
47
+ @site = site
48
+ @index = {}
49
+ @updated_paths = []
50
+ end
51
+
52
+ # Validate our `Site`, create a and configure a bucket, build the index,
53
+ # sync the files and (finally) invalidate all paths which have been updated
54
+ # on the content distribution network.
55
+ def run
56
+ validate
57
+ make_directory
58
+ Dir.chdir @site.path do
59
+ build_index
60
+ sync_remote
61
+ if( @site.distribution_id )
62
+ invalidate_cache(@site.distribution_id)
63
+ end
64
+ end
65
+ end
66
+
67
+ def validate
68
+ assert_not_nil @site.access_key_id, "No AccessKeyId specified"
69
+ assert_not_nil @site.secret_key, "No SecretKey specified"
70
+ end
71
+
72
+ # Creates an S3 bucket for web site serving, using `index.html` and
73
+ # `404.html` as our special pages.
74
+ def make_directory
75
+ domain = @site.domain_name
76
+ puts "Using bucket: #{domain}".blue
77
+ @directory = connection.directories.create :key => domain,
78
+ :public => true
79
+ connection.put_bucket_website(domain, 'index.html', :key => "404.html")
80
+ end
81
+
82
+ # Build an index of all the local files and their md5 sums. This will be
83
+ # used to decide what needs to be deployed.
84
+ def build_index
85
+ Dir["**/*"].each do |path|
86
+ unless File.directory?( path )
87
+ @index[path] = Digest::MD5.file(path).to_s
88
+ end
89
+ end
90
+ end
91
+
92
+ # Synchronize our local copy of the site with the remote one. This uses the
93
+ # index to detect what has been changed and upload only new/updated files.
94
+ # Helpful debugging information is emitted, and we're left with a populated
95
+ # `updated_paths` instance variable which can be used to invalidate cached
96
+ # content.
97
+ def sync_remote
98
+ @directory.files.each do |remote_file|
99
+ path = remote_file.key
100
+ local_file_md5 = @index[path]
101
+
102
+ if local_file_md5.nil? and @site.destroy_old_files
103
+ puts "#{path}: deleted".red
104
+ remote_file.destroy
105
+ elsif local_file_md5 == remote_file.etag
106
+ puts "#{path}: unchanged".white
107
+ @index.delete( path )
108
+ else
109
+ puts "#{path}: updated".green
110
+ write_file( path )
111
+ @index.delete( path )
112
+ @updated_paths << ("/" + path)
113
+ end
114
+ end
115
+
116
+ @index.each do |path, md5|
117
+ puts "#{path}: new".green
118
+ write_file( path )
119
+ end
120
+ end
121
+
122
+ # Push a single file out to S3.
123
+ def write_file( path )
124
+ @directory.files.create :key => path,
125
+ :body => File.open( path ),
126
+ :public => true
127
+ end
128
+
129
+ # Compose and post a cache invalidation request to CloudFront. This will
130
+ # ensure that all CloudFront distributions get the latest content quickly.
131
+ def invalidate_cache( distribution_id )
132
+ unless @updated_paths.empty?
133
+ cdn.post_invalidation distribution_id, @updated_paths
134
+ end
135
+ end
136
+
137
+ def cdn
138
+ @cdn ||= Fog::CDN.new( credentials )
139
+ end
140
+
141
+ def connection
142
+ @connection ||= Fog::Storage.new( credentials )
143
+ end
144
+
145
+ def credentials
146
+ {
147
+ :provider => 'AWS',
148
+ :aws_access_key_id => @site.access_key_id,
149
+ :aws_secret_access_key => @site.secret_key
150
+ }
151
+ end
152
+
153
+ def assert_not_nil( value, error )
154
+ raise UsageError.new( error ) unless value
155
+ end
156
+ end
157
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'fog_site'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFogSite < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fog_site
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ version: 0.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian P O'Rourke
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-22 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 55
30
+ segments:
31
+ - 0
32
+ - 10
33
+ - 0
34
+ version: 0.10.0
35
+ name: fog
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :runtime
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ name: colorize
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ type: :development
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 23
60
+ segments:
61
+ - 1
62
+ - 0
63
+ - 0
64
+ version: 1.0.0
65
+ name: bundler
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ prerelease: false
69
+ type: :development
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 7
76
+ segments:
77
+ - 1
78
+ - 6
79
+ - 4
80
+ version: 1.6.4
81
+ name: jeweler
82
+ version_requirements: *id004
83
+ description: Simple utility gem for deploying static sites to S3 and CloudFront using fog.
84
+ email: bpo@somnambulance.net
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files:
90
+ - LICENSE.txt
91
+ - README.md
92
+ files:
93
+ - .document
94
+ - Gemfile
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - VERSION
99
+ - lib/fog_site.rb
100
+ - test/helper.rb
101
+ - test/test_fog_site.rb
102
+ has_rdoc: true
103
+ homepage: http://github.com/bpo/fog_site
104
+ licenses:
105
+ - MIT
106
+ post_install_message:
107
+ rdoc_options: []
108
+
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 3
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ requirements: []
130
+
131
+ rubyforge_project:
132
+ rubygems_version: 1.6.2
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: Deploys static sites to S3 using fog
136
+ test_files: []
137
+