Class: Jets::Cfn::Upload

Inherits:
Object
  • Object
show all
Includes:
ActionView::Helpers::NumberHelper, AwsServices
Defined in:
lib/jets/cfn/upload.rb

Constant Summary collapse

CONTENT_TYPES_BY_EXTENSION =
{
  '.css'  => 'text/css',
  '.html' => 'text/html',
  '.js'   => 'application/javascript',
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AwsServices

#apigateway, #aws_lambda, #aws_options, #cfn, #dynamodb, #logs, #s3, #s3_resource, #sns, #sqs, #sts

Methods included from AwsServices::StackStatus

#lookup, #stack_exists?, #stack_in_progress?

Methods included from AwsServices::GlobalMemoist

included

Constructor Details

#initialize(bucket_name) ⇒ Upload

Returns a new instance of Upload.



12
13
14
# File 'lib/jets/cfn/upload.rb', line 12

def initialize(bucket_name)
  @bucket_name = bucket_name
end

Instance Attribute Details

#bucket_nameObject (readonly)

Returns the value of attribute bucket_name.



10
11
12
# File 'lib/jets/cfn/upload.rb', line 10

def bucket_name
  @bucket_name
end

Instance Method Details

#add_rack_assets(public_folders) ⇒ Object



69
70
71
72
# File 'lib/jets/cfn/upload.rb', line 69

def add_rack_assets(public_folders)
  return public_folders unless Jets.rack?
  public_folders + %w[rack/public]
end

#cache_controlObject

If cache_control is provided, then it will set the entire cache-control header. If only max_age is provided, then we’ll generate a cache_control header. Using max_age is the shorter and simply way of setting the cache_control header.



136
137
138
139
140
141
142
143
# File 'lib/jets/cfn/upload.rb', line 136

def cache_control
  cache_control = Jets.config.assets.cache_control
  unless cache_control
    max_age = Jets.config.assets.max_age # defaults to 3600 in jets/application.rb
    cache_control = "public, max-age=#{max_age}"
  end
  cache_control
end

#content_type_headers(full_path) ⇒ Object



105
106
107
108
109
110
111
112
113
# File 'lib/jets/cfn/upload.rb', line 105

def content_type_headers(full_path)
  ext = File.extname(full_path)
  content_type = CONTENT_TYPES_BY_EXTENSION[ext] || Rack::Mime.mime_type(ext)
  if content_type
    { content_type: content_type }
  else
    {}
  end
end

#identical_on_s3?(full_path) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/jets/cfn/upload.rb', line 120

def identical_on_s3?(full_path)
  local_md5 = ::Digest::MD5.file(full_path)
  key = s3_key(full_path)
  begin
    resp = s3.head_object(bucket: bucket_name, key: key)
  rescue Aws::S3::Errors::NotFound
    return false
  end

  remote_md5 = resp.etag.delete_prefix('"').delete_suffix('"')
  local_md5 == remote_md5
end

#pretty_time(total_seconds) ⇒ Object



146
147
148
149
150
151
152
153
154
# File 'lib/jets/cfn/upload.rb', line 146

def pretty_time(total_seconds)
  minutes = (total_seconds / 60) % 60
  seconds = total_seconds % 60
  if total_seconds < 60
    "#{seconds.to_i}s"
  else
    "#{minutes.to_i}m #{seconds.to_i}s"
  end
end

#s3_key(full_path) ⇒ Object



115
116
117
118
# File 'lib/jets/cfn/upload.rb', line 115

def s3_key(full_path)
  relative_path = full_path.sub("#{Jets.root}/", '')
  "jets/#{relative_path}"
end

#uploadObject



16
17
18
19
20
# File 'lib/jets/cfn/upload.rb', line 16

def upload
  upload_cfn_templates
  upload_zip_files
  upload_assets
end

#upload_asset_folder(folder) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/jets/cfn/upload.rb', line 74

def upload_asset_folder(folder)
  expression = "#{Jets.root}/#{folder}/**/*"
  group_size = 10
  Dir.glob(expression).each_slice(group_size) do |paths|
    threads = []
    paths.each do |full_path|
      next unless File.file?(full_path)

      threads << Thread.new do
        upload_to_s3(full_path)
      end
    end
    threads.each(&:join)
  end
end

#upload_assetsObject



54
55
56
57
58
59
# File 'lib/jets/cfn/upload.rb', line 54

def upload_assets
  puts "Checking for modified public assets and uploading to S3."
  start_time = Time.now
  upload_public_assets
  puts "Time for public assets to s3: #{pretty_time(Time.now-start_time).color(:green)}"
end

#upload_cfn_templatesObject



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/jets/cfn/upload.rb', line 22

def upload_cfn_templates
  puts "Uploading CloudFormation templates to S3."
  expression = "#{Jets::Naming.template_path_prefix}-*"
  Dir.glob(expression).each do |path|
    next unless File.file?(path)

    key = "jets/cfn-templates/#{File.basename(path)}"
    obj = s3_resource.bucket(bucket_name).object(key)
    obj.upload_file(path)
  end
end

#upload_public_assetsObject



61
62
63
64
65
66
67
# File 'lib/jets/cfn/upload.rb', line 61

def upload_public_assets
  public_folders = %w[public]
  public_folders = add_rack_assets(public_folders)
  public_folders.each do |folder|
    upload_asset_folder(folder)
  end
end

#upload_to_s3(full_path) ⇒ Object



90
91
92
93
94
95
96
97
98
# File 'lib/jets/cfn/upload.rb', line 90

def upload_to_s3(full_path)
  return if identical_on_s3?(full_path) && !ENV['JETS_ASSET_UPLOAD_FORCE']

  key = s3_key(full_path)
  obj = s3_resource.bucket(bucket_name).object(key)
  content_type = content_type_headers(full_path)
  puts "Uploading and setting content type for s3://#{bucket_name}/#{key} content_type #{content_type[:content_type].inspect}"
  obj.upload_file(full_path, { acl: "public-read", cache_control: cache_control }.merge(content_type))
end

#upload_zip_file(path) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/jets/cfn/upload.rb', line 42

def upload_zip_file(path)
  file_size = number_to_human_size(File.size(path))

  puts "Uploading #{path} (#{file_size}) to S3"
  start_time = Time.now
  s3_key = "jets/code/#{File.basename(path)}"
  obj = s3_resource.bucket(bucket_name).object(s3_key)
  obj.upload_file(path)
  puts "Uploaded to s3://#{bucket_name}/#{s3_key}".color(:green)
  puts "Time to upload code to s3: #{pretty_time(Time.now-start_time).color(:green)}"
end

#upload_zip_filesObject



34
35
36
37
38
39
40
# File 'lib/jets/cfn/upload.rb', line 34

def upload_zip_files
  puts "Uploading code zip files to S3."
  zip_area = "#{Jets.build_root}/stage/zips"
  Dir.glob("#{zip_area}/*").each do |file|
    upload_zip_file(file)
  end
end