Class: Jets::Builders::CodeBuilder
- Inherits:
-
Object
- Object
- Jets::Builders::CodeBuilder
- Extended by:
- Memoist
- Includes:
- AwsServices, Util
- Defined in:
- lib/jets/builders/code_builder.rb
Instance Attribute Summary collapse
-
#full_project_path ⇒ Object
readonly
Returns the value of attribute full_project_path.
Class Method Summary collapse
-
.tmp_code ⇒ Object
Group all the path settings together here.
Instance Method Summary collapse
- #build ⇒ Object
- #build_lambda_layer ⇒ Object
- #cache_check_message ⇒ Object
-
#calculate_md5s ⇒ Object
Resolves the chicken-and-egg problem with md5 checksums.
- #check_code_size! ⇒ Object
- #check_ruby_version ⇒ Object
-
#clean_start ⇒ Object
Cleans out non-cached files like code-*.zip in Jets.build_root for a clean start.
- #code_finish ⇒ Object
- #code_setup ⇒ Object
-
#compile_assets ⇒ Object
This happens in the current app directory not the tmp code for simplicity.
-
#compile_rails_assets ⇒ Object
This happens in the current app directory not the tmp code for simplicity This is because the node likely been set up correctly there.
-
#copy_internal_jets_code ⇒ Object
We copy the files into the project because we cannot require simple functions directly since they are wrapped by an anonymous class.
-
#copy_project ⇒ Object
Copy project into temporary directory.
- #create_zip_files ⇒ Object
-
#dir_size(folder) ⇒ Object
Thanks stackoverflow.com/questions/9354595/recursively-getting-the-size-of-a-directory Seems to overestimate a little bit but close enough.
- #disable_webpacker_middleware ⇒ Object
- #exist_on_s3?(filename) ⇒ Boolean
- #generate_node_shims ⇒ Object
-
#initialize ⇒ CodeBuilder
constructor
A new instance of CodeBuilder.
-
#move_node_modules(source_folder, dest_folder) ⇒ Object
Move the node modules to the tmp build folder to speed up project copying.
- #package_ruby ⇒ Object
- #rack_packager ⇒ Object
-
#rails? ⇒ Boolean
Rudimentary rails detection.
- #rails_assets(cmd) ⇒ Object
-
#reconfigure_development_webpacker ⇒ Object
Bit hacky but this saves the user from accidentally forgetting to change this when they deploy a jets project in development mode.
-
#reconfigure_rails ⇒ Object
TODO: Move logic into plugin instead.
- #ruby_packager ⇒ Object
- #ruby_version_supported? ⇒ Boolean
- #s3_base_url ⇒ Object
- #s3_bucket ⇒ Object
- #stage_area ⇒ Object
-
#store_s3_base_url ⇒ Object
Store s3 base url is needed for asset serving from s3 later.
- #tmp_code ⇒ Object
- #write_s3_base_url(relative_path) ⇒ Object
Methods included from Util
#code_area, #full, #headline, #sh
Methods included from AwsServices
#apigateway, #cfn, #lambda, #logs, #s3, #s3_resource, #sns, #sts
Methods included from AwsServices::StackStatus
#lookup, #stack_exists?, #stack_in_progress?
Constructor Details
#initialize ⇒ CodeBuilder
Returns a new instance of CodeBuilder.
22 23 24 25 26 27 |
# File 'lib/jets/builders/code_builder.rb', line 22 def initialize # Expanding to the full path and capture now. # Dir.chdir gets called later and we'll lose this info. @full_project_path = File.(Jets.root) + "/" @version_purger = Purger.new end |
Instance Attribute Details
#full_project_path ⇒ Object (readonly)
Returns the value of attribute full_project_path.
21 22 23 |
# File 'lib/jets/builders/code_builder.rb', line 21 def full_project_path @full_project_path end |
Class Method Details
Instance Method Details
#build ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/jets/builders/code_builder.rb', line 29 def build check_ruby_version @version_purger.purge clean_start compile_assets # easier to do before we copy the project because node and yarn has been likely setup in the that dir compile_rails_assets copy_project Dir.chdir(full(tmp_code)) do # These commands run from project root code_setup package_ruby code_finish end end |
#build_lambda_layer ⇒ Object
111 112 113 114 115 |
# File 'lib/jets/builders/code_builder.rb', line 111 def build_lambda_layer return if Jets.poly_only? lambda_layer = LambdaLayer.new lambda_layer.build end |
#cache_check_message ⇒ Object
316 317 318 319 320 |
# File 'lib/jets/builders/code_builder.rb', line 316 def if File.exist?("#{Jets.build_root}/cache") puts "The #{Jets.build_root}/cache folder exists. Incrementally re-building the jets using the cache. To clear the cache: rm -rf #{Jets.build_root}/cache" end end |
#calculate_md5s ⇒ Object
Resolves the chicken-and-egg problem with md5 checksums. The handlers need to reference files with the md5 checksum. The files are the:
jets/code/rack-checksum.zip
jets/code/bundled-checksum.zip
We compute the checksums before we generate the node shim handlers.
53 54 55 |
# File 'lib/jets/builders/code_builder.rb', line 53 def calculate_md5s Md5.compute! # populates Md5.checksums hash end |
#check_code_size! ⇒ Object
117 118 119 |
# File 'lib/jets/builders/code_builder.rb', line 117 def check_code_size! CodeSize.check! end |
#check_ruby_version ⇒ Object
322 323 324 325 326 327 328 |
# File 'lib/jets/builders/code_builder.rb', line 322 def check_ruby_version unless ruby_version_supported? puts "You are using ruby version #{RUBY_VERSION} which is not supported by Jets." ruby_variant = Jets::RUBY_VERSION.split('.')[0..1].join('.') + '.x' abort("Jets uses ruby #{Jets::RUBY_VERSION}. You should use a variant of ruby #{ruby_variant}".colorize(:red)) end end |
#clean_start ⇒ Object
Cleans out non-cached files like code-*.zip in Jets.build_root for a clean start. Also ensure that the /tmp/jets/project build root exists.
Most files are kept around after the build process for inspection and debugging. So we have to clean out the files. But we only want to clean out some of the files.
241 242 243 244 |
# File 'lib/jets/builders/code_builder.rb', line 241 def clean_start Dir.glob("#{Jets.build_root}/code/code-*.zip").each { |f| FileUtils.rm_f(f) } FileUtils.mkdir_p(Jets.build_root) # /tmp/jets/demo end |
#code_finish ⇒ Object
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/jets/builders/code_builder.rb', line 97 def code_finish # Reconfigure code store_s3_base_url disable_webpacker_middleware copy_internal_jets_code # Code prep and zipping build_lambda_layer check_code_size! calculate_md5s # must be called before generate_node_shims and create_zip_files generate_node_shims create_zip_files end |
#code_setup ⇒ Object
93 94 95 |
# File 'lib/jets/builders/code_builder.rb', line 93 def code_setup reconfigure_development_webpacker end |
#compile_assets ⇒ Object
This happens in the current app directory not the tmp code for simplicity. This is because the node and yarn has likely been set up correctly there.
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/jets/builders/code_builder.rb', line 185 def compile_assets if ENV['JETS_SKIP_ASSETS'] puts "Skip compiling assets".colorize(:yellow) # useful for debugging return end headline "Compling assets in current project directory" # Thanks: https://stackoverflow.com/questions/4195735/get-list-of-gems-being-used-by-a-bundler-project webpacker_loaded = Gem.loaded_specs.keys.include?("webpacker") return unless webpacker_loaded sh("yarn install") webpack_command = File.exist?("#{Jets.root}bin/webpack") ? "bin/webpack" : `which webpack`.strip sh("JETS_ENV=#{Jets.env} #{webpack_command}") end |
#compile_rails_assets ⇒ Object
This happens in the current app directory not the tmp code for simplicity This is because the node likely been set up correctly there.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/jets/builders/code_builder.rb', line 205 def compile_rails_assets return unless rails? if ENV['JETS_SKIP_ASSETS'] puts "Skip compiling rack assets".colorize(:yellow) # useful for debugging return end return unless Jets.rack? Bundler.with_clean_env do rails_assets(:clobber) rails_assets(:precompile) end end |
#copy_internal_jets_code ⇒ Object
We copy the files into the project because we cannot require simple functions directly since they are wrapped by an anonymous class. TODO: Do this with the other files we required the same way.
124 125 126 127 128 129 130 131 132 |
# File 'lib/jets/builders/code_builder.rb', line 124 def copy_internal_jets_code files = [] files.each do |relative_path| src = File.("../internal/#{relative_path}", File.dirname(__FILE__)) dest = "#{full(tmp_code)}/#{relative_path}" FileUtils.mkdir_p(File.dirname(dest)) FileUtils.cp(src, dest) end end |
#copy_project ⇒ Object
Copy project into temporary directory. Do this so we can keep the project directory untouched and we can also remove a bunch of unnecessary files like logs before zipping it up.
249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/jets/builders/code_builder.rb', line 249 def copy_project headline "Copying current project directory to temporary build area: #{full(tmp_code)}" FileUtils.rm_rf(stage_area) # clear out from previous build FileUtils.mkdir_p(stage_area) FileUtils.rm_rf(full(tmp_code)) # remove current code folder move_node_modules(Jets.root, Jets.build_root) begin # puts "cp -r #{@full_project_path} #{full(tmp_code)}".colorize(:yellow) # uncomment to debug FileUtils.cp_r(@full_project_path, full(tmp_code)) ensure move_node_modules(Jets.build_root, Jets.root) # move node_modules directory back end end |
#create_zip_files ⇒ Object
65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/jets/builders/code_builder.rb', line 65 def create_zip_files folders = Md5.stage_folders # Md5.stage_folders ["stage/bundled", "stage/code"] folders.each do |folder| zip = Md5Zip.new(folder) if exist_on_s3?(zip.md5_name) puts "Already exists: s3://#{s3_bucket}/jets/code/#{zip.md5_name}" else zip = Md5Zip.new(folder) zip.create end end end |
#dir_size(folder) ⇒ Object
Thanks stackoverflow.com/questions/9354595/recursively-getting-the-size-of-a-directory Seems to overestimate a little bit but close enough.
136 137 138 139 140 141 |
# File 'lib/jets/builders/code_builder.rb', line 136 def dir_size(folder) Dir.glob(File.join(folder, '**', '*')) .select { |f| File.file?(f) } .map{ |f| File.size(f) } .inject(:+) end |
#disable_webpacker_middleware ⇒ Object
177 178 179 180 181 |
# File 'lib/jets/builders/code_builder.rb', line 177 def disable_webpacker_middleware full_path = "#{full(tmp_code)}/config/disable-webpacker-middleware.txt" FileUtils.mkdir_p(File.dirname(full_path)) FileUtils.touch(full_path) end |
#exist_on_s3?(filename) ⇒ Boolean
79 80 81 82 83 84 85 86 87 |
# File 'lib/jets/builders/code_builder.rb', line 79 def exist_on_s3?(filename) s3_key = "jets/code/#{filename}" begin s3.head_object(bucket: s3_bucket, key: s3_key) true rescue Aws::S3::Errors::NotFound false end end |
#generate_node_shims ⇒ Object
57 58 59 60 61 62 63 |
# File 'lib/jets/builders/code_builder.rb', line 57 def generate_node_shims headline "Generating shims in the handlers folder." # Crucial that the Dir.pwd is in the tmp_code because for # Jets::Builders::app_files because Jets.boot set ups # autoload_paths and this is how project classes are loaded. Jets::Builders::HandlerGenerator.build! end |
#move_node_modules(source_folder, dest_folder) ⇒ Object
Move the node modules to the tmp build folder to speed up project copying. A little bit risky because a ctrl-c in the middle of the project copying results in a missing node_modules but user can easily rebuild that.
Tesing shows 6.623413 vs 0.027754 speed improvement.
268 269 270 271 272 273 274 |
# File 'lib/jets/builders/code_builder.rb', line 268 def move_node_modules(source_folder, dest_folder) source = "#{source_folder}/node_modules" dest = "#{dest_folder}/node_modules" if File.exist?(source) FileUtils.mv(source, dest) end end |
#package_ruby ⇒ Object
301 302 303 304 305 306 307 308 309 |
# File 'lib/jets/builders/code_builder.rb', line 301 def package_ruby return if Jets.poly_only? ruby_packager.install reconfigure_rails # call here after full(tmp_code) is available rack_packager.install ruby_packager.finish # by this time we have a /tmp/jets/demo/stage/code/bundled rack_packager.finish end |
#rack_packager ⇒ Object
296 297 298 |
# File 'lib/jets/builders/code_builder.rb', line 296 def rack_packager RackPackager.new("#{tmp_code}/rack") end |
#rails? ⇒ Boolean
Rudimentary rails detection
229 230 231 232 233 |
# File 'lib/jets/builders/code_builder.rb', line 229 def rails? config_ru = "#{Jets.root}rack/config.ru" return false unless File.exist?(config_ru) !IO.readlines(config_ru).grep(/Rails.application/).empty? end |
#rails_assets(cmd) ⇒ Object
221 222 223 224 225 226 |
# File 'lib/jets/builders/code_builder.rb', line 221 def rails_assets(cmd) # rake is available in both rails 4 and 5. rails command only in 5 command = "rake assets:#{cmd} --trace" command = "RAILS_ENV=#{Jets.env} #{fulL_cmd}" unless Jets.env.development? sh("cd rack && #{command}") end |
#reconfigure_development_webpacker ⇒ Object
Bit hacky but this saves the user from accidentally forgetting to change this when they deploy a jets project in development mode
278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/jets/builders/code_builder.rb', line 278 def reconfigure_development_webpacker return unless Jets.env.development? headline "Reconfiguring webpacker development settings for AWS Lambda." webpacker_yml = "#{full(tmp_code)}/config/webpacker.yml" return unless File.exist?(webpacker_yml) config = YAML.load_file(webpacker_yml) config["development"]["compile"] = false # force this to be false for deployment new_yaml = YAML.dump(config) IO.write(webpacker_yml, new_yaml) end |
#reconfigure_rails ⇒ Object
TODO: Move logic into plugin instead
312 313 314 |
# File 'lib/jets/builders/code_builder.rb', line 312 def reconfigure_rails ReconfigureRails.new("#{full(tmp_code)}/rack").run end |
#ruby_packager ⇒ Object
291 292 293 |
# File 'lib/jets/builders/code_builder.rb', line 291 def ruby_packager RubyPackager.new(tmp_code) end |
#ruby_version_supported? ⇒ Boolean
330 331 332 333 334 335 336 337 338 |
# File 'lib/jets/builders/code_builder.rb', line 330 def ruby_version_supported? pattern = /(\d+)\.(\d+)\.(\d+)/ md = RUBY_VERSION.match(pattern) ruby = {major: md[1], minor: md[2]} md = Jets::RUBY_VERSION.match(pattern) jets = {major: md[1], minor: md[2]} ruby[:major] == jets[:major] && ruby[:minor] == jets[:minor] end |
#s3_base_url ⇒ Object
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/jets/builders/code_builder.rb', line 158 def s3_base_url # Allow user to set assets.base_url # # Jets.application.configure do # config.assets.base_url = "https://cloudfront.com/my/base/path" # end # return Jets.config.assets.base_url if Jets.config.assets.base_url region = Jets.aws.region asset_base_url = "https://s3-#{region}.amazonaws.com" "#{asset_base_url}/#{s3_bucket}/jets" # s3_base_url end |
#s3_bucket ⇒ Object
173 174 175 |
# File 'lib/jets/builders/code_builder.rb', line 173 def s3_bucket Jets.aws.s3_bucket end |
#stage_area ⇒ Object
89 90 91 |
# File 'lib/jets/builders/code_builder.rb', line 89 def stage_area "#{Jets.build_root}/stage" end |
#store_s3_base_url ⇒ Object
Store s3 base url is needed for asset serving from s3 later. Need to package this as part of the code so we have a reference to it. At this point the minimal stack exists, so we can grab it with the AWS API. We do not want to grab this as part of the live request because it is slow.
147 148 149 150 |
# File 'lib/jets/builders/code_builder.rb', line 147 def store_s3_base_url write_s3_base_url("config/s3_base_url.txt") write_s3_base_url("rack/config/s3_base_url.txt") if Jets.rack? end |
#tmp_code ⇒ Object
345 346 347 |
# File 'lib/jets/builders/code_builder.rb', line 345 def tmp_code self.class.tmp_code end |
#write_s3_base_url(relative_path) ⇒ Object
152 153 154 155 156 |
# File 'lib/jets/builders/code_builder.rb', line 152 def write_s3_base_url(relative_path) full_path = "#{full(tmp_code)}/#{relative_path}" FileUtils.mkdir_p(File.dirname(full_path)) IO.write(full_path, s3_base_url) end |