Class: Lono::AppFile::Build::LambdaLayer::RubyPackager

Inherits:
Object
  • Object
show all
Includes:
Utils::Rsync
Defined in:
lib/lono/app_file/build/lambda_layer/ruby_packager.rb

Overview

Based on jets

Instance Method Summary collapse

Methods included from Utils::Rsync

#check_rsync_installed!, #rsync, #sh

Constructor Details

#initialize(blueprint, registry_item) ⇒ RubyPackager

Returns a new instance of RubyPackager.

[View source]

6
7
8
9
10
11
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 6

def initialize(blueprint, registry_item)
  @blueprint, @registry_item = blueprint, registry_item

  @registry_name = @registry_item.name.sub(/\/$/,'')
  @app_root = "#{Lono.blueprint_root}/app/files/#{@registry_name}"
end

Instance Method Details

#buildObject

[View source]

13
14
15
16
17
18
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 13

def build
  return unless gemfile_exist?

  bundle_install
  package
end

#build_areaObject

[View source]

136
137
138
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 136

def build_area
  "#{Lono.config.output_path}/#{@blueprint}/lambda_layers/#{@registry_name}"
end

#bundle_installObject

Installs gems on the current target system: both compiled and non-compiled. If user is on a macosx machine, macosx gems will be installed. If user is on a linux machine, linux gems will be installed.

Copies Gemfile* to /tmp/jets/demo/cache folder and installs gems with bundle install from there.

We take the time to copy Gemfile and bundle into a separate directory because it gets left around to act as a ‘cache’. So, when the builds the project gets built again not all the gems from get installed from the beginning.

[View source]

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 70

def bundle_install
  puts "Bundling: running bundle install in cache area: #{cache_area}."

  rsync(output_area, cache_area)

  # Uncomment out to always remove the cache/vendor/gems to debug
  # FileUtils.rm_rf("#{cache_area}/vendor/gems")

  # Remove .bundle folder so .bundle/config doesnt affect how gems are packages
  # Not using BUNDLE_IGNORE_CONFIG=1 to allow home ~/.bundle/config to affect bundling though.
  # This is useful if you have private gems sources that require authentication. Example:
  #
  #    bundle config gems.myprivatesource.com user:pass
  #

  FileUtils.rm_rf("#{cache_area}/.bundle")
  require "bundler" # dynamically require bundler so user can use any bundler
  setup_bundle_config(cache_area)
  Bundler.with_unbundled_env do
    sh "cd #{cache_area} && env bundle install"
  end

  remove_bundled_with("#{cache_area}/Gemfile.lock")
  # Fixes really tricky bug where Gemfile and Gemfile.lock is out-of-sync. Details: https://gist.github.com/tongueroo/b5b0d0c924a4a1633eee514795e4b04b
  FileUtils.cp("#{cache_area}/Gemfile.lock", "#{Lono.config.output_path}/#{@blueprint}/files/#{@registry_name}/Gemfile.lock")

  puts 'Bundle install success.'
end

#cache_areaObject

[View source]

140
141
142
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 140

def cache_area
  "#{build_area}/cache"
end

#consolidate_gems_to_optObject

Also restructure the folder from:

vendor/gems/ruby/2.5.0

To:

ruby/gems/2.5.0

For Lambda Layer structure

[View source]

33
34
35
36
37
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 33

def consolidate_gems_to_opt
  src = "#{cache_area}/vendor/gems/ruby/#{ruby_folder}"
  dest = "#{opt_area}/ruby/gems/#{ruby_folder}"
  rsync_and_link(src, dest)
end

#gemfile_exist?Boolean

Returns:

  • (Boolean)
[View source]

148
149
150
151
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 148

def gemfile_exist?
  gemfile_path = "#{@app_root}/Gemfile"
  File.exist?(gemfile_path)
end

#opt_areaObject

[View source]

144
145
146
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 144

def opt_area
  "#{build_area}/opt"
end

#output_areaObject

[View source]

132
133
134
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 132

def output_area
  "#{Lono.config.output_path}/#{@blueprint}/files/#{@registry_name}"
end

#packageObject

We consolidate all gems to opt

[View source]

21
22
23
24
25
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 21

def package
  setup_bundle_config(output_area)
  # copy_cache_gems # TODO: might not need this cache
  consolidate_gems_to_opt
end

#remove_bundled_with(gemfile_lock) ⇒ Object

Remove the BUNDLED WITH line since we don’t control the bundler gem version on AWS Lambda And this can cause issues with require ‘bundler/setup’

[View source]

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 101

def remove_bundled_with(gemfile_lock)
  lines = IO.readlines(gemfile_lock)

  # amount is the number of lines to remove
  new_lines, capture, count, amount = [], true, 0, 2
  lines.each do |l|
    capture = false if l.include?('BUNDLED WITH')
    if capture
      new_lines << l
    end
    if capture == false
      count += 1
      capture = count > amount # renable capture
    end
  end

  content = new_lines.join('')
  IO.write(gemfile_lock, content)
end
[View source]

39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 39

def rsync_and_link(src, dest)
  FileUtils.mkdir_p(dest)
  rsync(src, dest)

  # create symlink in output path not the cache path
  symlink_dest = "#{output_area}/vendor/gems/ruby/#{ruby_folder}"
  puts "symlink_dest #{symlink_dest}"
  FileUtils.rm_rf(symlink_dest) # blow away original 2.5.0 folder

  # Create symlink that will point to the gems in the Lambda Layer:
  #   stage/opt/ruby/gems/2.5.0 -> /opt/ruby/gems/2.5.0
  FileUtils.mkdir_p(File.dirname(symlink_dest))
  FileUtils.ln_sf("/opt/ruby/gems/#{ruby_folder}", symlink_dest)
end

#ruby_folderObject

[View source]

54
55
56
57
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 54

def ruby_folder
  major, minor, _ = RUBY_VERSION.split('.')
  [major, minor, '0'].join('.') # 2.5.1 => 2.5.0
end

#setup_bundle_config(dir) ⇒ Object

[View source]

121
122
123
124
125
126
127
128
129
130
# File 'lib/lono/app_file/build/lambda_layer/ruby_packager.rb', line 121

def setup_bundle_config(dir)
  text ="---\nBUNDLE_PATH: \"vendor/gems\"\nBUNDLE_WITHOUT: \"development:test\"\n"
  bundle_config = "#{dir}/.bundle/config"
  FileUtils.mkdir_p(File.dirname(bundle_config))
  IO.write(bundle_config, text)
end