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.



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

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

Instance Attribute Details

#indexObject (readonly)

Returns the value of attribute index.



37
38
39
# File 'lib/fog_site.rb', line 37

def index
  @index
end

#updated_pathsObject (readonly)

Returns the value of attribute updated_paths.



37
38
39
# File 'lib/fog_site.rb', line 37

def updated_paths
  @updated_paths
end

Class Method Details

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

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



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

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

Instance Method Details

#assert_not_nil(value, error) ⇒ Object

Raises:



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

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.



84
85
86
87
88
89
90
# File 'lib/fog_site.rb', line 84

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

#cdnObject



138
139
140
# File 'lib/fog_site.rb', line 138

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

#connectionObject



142
143
144
# File 'lib/fog_site.rb', line 142

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

#credentialsObject



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

def credentials
  {
    :provider              => 'AWS',
    :aws_access_key_id     => @site.access_key_id,
    :aws_secret_access_key => @site.secret_key
  }
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.



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

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.



74
75
76
77
78
79
80
# File 'lib/fog_site.rb', line 74

def make_directory
  domain = @site.domain_name
  puts "Using bucket: #{domain}".blue
  @directory = connection.directories.create :key => domain,
                                             :public => true
  connection.put_bucket_website(domain, 'index.html', :key => "404.html")
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.



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/fog_site.rb', line 55

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.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/fog_site.rb', line 97

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
      @updated_paths << ("/" + 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 )
      @updated_paths << ("/" + path)
    end
  end

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

#validateObject



67
68
69
70
# File 'lib/fog_site.rb', line 67

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.



124
125
126
127
128
# File 'lib/fog_site.rb', line 124

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