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.



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



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



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.



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



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



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)


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



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



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



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’



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


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



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



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 =<<-EOL
---
BUNDLE_PATH: "vendor/gems"
BUNDLE_WITHOUT: "development:test"
EOL
  bundle_config = "#{dir}/.bundle/config"
  FileUtils.mkdir_p(File.dirname(bundle_config))
  IO.write(bundle_config, text)
end