Class: FogSite::Deployer

Inherits:
Object
  • Object
show all
Defined in:
lib/fog_site.rb

Overview

Used to actually execute a deploy. This object is not safe for reuse - the ‘@index` and `@updated_paths` stay dirty after a deploy to allow debugging and inspection by client scripts.

Defined Under Namespace

Classes: UsageError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(site) ⇒ Deployer

Returns a new instance of Deployer.



50
51
52
53
54
# File 'lib/fog_site.rb', line 50

def initialize( site )
  @site = site
  @index = {}
  @updated_paths = []
end

Instance Attribute Details

#indexObject (readonly)

Returns the value of attribute index.



41
42
43
# File 'lib/fog_site.rb', line 41

def index
  @index
end

#updated_pathsObject (readonly)

Returns the value of attribute updated_paths.



41
42
43
# File 'lib/fog_site.rb', line 41

def updated_paths
  @updated_paths
end

Class Method Details

.run(site, options = {}) ⇒ Object

Run a single deploy. Creates a new ‘Deployer` and calls `run`.



45
46
47
48
# File 'lib/fog_site.rb', line 45

def self.run( site, options = {} )
  deployer = Deployer.new( site )
  deployer.run
end

Instance Method Details

#assert_not_nil(value, error) ⇒ Object

Raises:



173
174
175
# File 'lib/fog_site.rb', line 173

def assert_not_nil( value, error )
  raise UsageError.new( error ) unless value
end

#build_indexObject

Build an index of all the local files and their md5 sums. This will be used to decide what needs to be deployed.



92
93
94
95
96
97
98
# File 'lib/fog_site.rb', line 92

def build_index
  Dir["**/*"].each do |path|
    unless File.directory?( path )
      @index[path] = Digest::MD5.file(path).to_s
    end
  end
end

#cdnObject



153
154
155
# File 'lib/fog_site.rb', line 153

def cdn
  @cdn ||= Fog::CDN.new( cdn_credentials )
end

#cdn_credentialsObject



169
170
171
# File 'lib/fog_site.rb', line 169

def cdn_credentials
  credentials.delete_if { |k, v| k == :region }
end

#connectionObject



157
158
159
# File 'lib/fog_site.rb', line 157

def connection
  @connection ||= Fog::Storage.new( credentials )
end

#credentialsObject



161
162
163
164
165
166
167
# File 'lib/fog_site.rb', line 161

def credentials
  {
    :provider              => 'AWS',
    :aws_access_key_id     => @site.access_key_id,
    :aws_secret_access_key => @site.secret_key
  }.merge @site.fog_options
end

#invalidate_cache(distribution_id) ⇒ Object

Compose and post a cache invalidation request to CloudFront. This will ensure that all CloudFront distributions get the latest content quickly.



147
148
149
150
151
# File 'lib/fog_site.rb', line 147

def invalidate_cache( distribution_id )
  unless @updated_paths.empty?
    cdn.post_invalidation distribution_id, @updated_paths
  end
end

#make_directoryObject

Creates an S3 bucket for web site serving, using ‘index.html` and `404.html` as our special pages.



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/fog_site.rb', line 78

def make_directory
  domain = @site.domain_name
  puts "Using bucket: #{domain}".blue
  @directory = connection.directories.get domain
  unless @directory
    puts "Creating nw bucket.".red
    @directory = connection.directories.create :key => domain,
                                              :public => true
  end
  connection.put_bucket_website(domain, 'index.html', :key => "404.html")
end

#mark_updated(path) ⇒ Object



131
132
133
134
135
136
# File 'lib/fog_site.rb', line 131

def mark_updated( path )
  @updated_paths << path
  if path =~ /\/index\.html$/
    @updated_paths << path.sub( /index\.html$/, '' )
  end
end

#runObject

Validate our ‘Site`, create a and configure a bucket, build the index, sync the files and (finally) invalidate all paths which have been updated on the content distribution network.



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/fog_site.rb', line 59

def run
  validate
  make_directory
  Dir.chdir @site.path do
    build_index
    sync_remote
    if( @site.distribution_id )
      invalidate_cache(@site.distribution_id)
    end
  end
end

#sync_remoteObject

Synchronize our local copy of the site with the remote one. This uses the index to detect what has been changed and upload only new/updated files. Helpful debugging information is emitted, and we’re left with a populated ‘updated_paths` instance variable which can be used to invalidate cached content.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/fog_site.rb', line 105

def sync_remote
  @directory.files.each do |remote_file|
    path = remote_file.key
    local_file_md5 = @index[path]

    if local_file_md5.nil? and @site.destroy_old_files
      puts "#{path}: deleted".red
      remote_file.destroy
      mark_updated( "/#{path}" )
    elsif local_file_md5 == remote_file.etag
      puts "#{path}: unchanged".white
      @index.delete( path )
    else
      puts "#{path}: updated".green
      write_file( path )
      @index.delete( path )
      mark_updated( "/#{path}" )
    end
  end

  @index.each do |path, md5|
    puts "#{path}: new".green
    write_file( path )
  end
end

#validateObject



71
72
73
74
# File 'lib/fog_site.rb', line 71

def validate
  assert_not_nil @site.access_key_id, "No AccessKeyId specified"
  assert_not_nil @site.secret_key, "No SecretKey specified"
end

#write_file(path) ⇒ Object

Push a single file out to S3.



139
140
141
142
143
# File 'lib/fog_site.rb', line 139

def write_file( path )
  @directory.files.create :key => path,
                          :body => File.open( path ),
                          :public => true
end