jets 0.10.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/Gemfile.lock +12 -12
  4. data/README.md +4 -2
  5. data/exe/jets +2 -2
  6. data/lib/jets/application.rb +41 -5
  7. data/lib/jets/aws_info.rb +20 -0
  8. data/lib/jets/builders/code_builder.rb +201 -296
  9. data/lib/jets/builders/gem_replacer.rb +1 -1
  10. data/lib/jets/builders/handler_generator.rb +62 -43
  11. data/lib/jets/builders/md5.rb +55 -0
  12. data/lib/jets/builders/md5_zip.rb +60 -0
  13. data/lib/jets/builders/rack_packager.rb +29 -0
  14. data/lib/jets/builders/rackup_wrappers/rackup +23 -0
  15. data/lib/jets/builders/rackup_wrappers/rackup.rb +7 -0
  16. data/lib/jets/builders/reconfigure_rails/config/initializers/jets.rb +14 -0
  17. data/lib/jets/builders/reconfigure_rails.rb +99 -0
  18. data/lib/jets/builders/ruby_packager.rb +198 -0
  19. data/lib/jets/builders/{deducer.rb → shim_vars/app.rb} +14 -10
  20. data/lib/jets/builders/shim_vars/base.rb +24 -0
  21. data/lib/jets/builders/{shared_deducer.rb → shim_vars/shared.rb} +4 -3
  22. data/lib/jets/builders/shim_vars.rb +5 -0
  23. data/lib/jets/builders/templates/handler.js +9 -0
  24. data/lib/jets/builders/templates/shim.js +271 -0
  25. data/lib/jets/builders/tidy.rb +80 -0
  26. data/lib/jets/builders/util.rb +28 -0
  27. data/lib/jets/builders.rb +8 -2
  28. data/lib/jets/cfn/builders/function_builder.rb +0 -10
  29. data/lib/jets/cfn/builders/parent_builder.rb +7 -6
  30. data/lib/jets/cfn/ship.rb +9 -103
  31. data/lib/jets/cfn/upload.rb +139 -0
  32. data/lib/jets/cfn.rb +1 -0
  33. data/lib/jets/commands/build.rb +17 -19
  34. data/lib/jets/commands/deploy.rb +2 -0
  35. data/lib/jets/commands/help/deploy.md +2 -2
  36. data/lib/jets/commands/help/import/rack.md +13 -0
  37. data/lib/jets/commands/help/import/rails.md +11 -0
  38. data/lib/jets/commands/import/base.rb +39 -0
  39. data/lib/jets/commands/import/rack.rb +16 -0
  40. data/lib/jets/commands/import/rail.rb +68 -0
  41. data/lib/jets/commands/import/sequence.rb +68 -0
  42. data/lib/jets/commands/import.rb +14 -0
  43. data/lib/jets/commands/main.rb +2 -1
  44. data/lib/jets/commands/new.rb +1 -1
  45. data/lib/jets/commands/sequence.rb +26 -22
  46. data/lib/jets/commands/templates/skeleton/Gemfile.tt +5 -2
  47. data/lib/jets/commands/templates/skeleton/README.md +11 -2
  48. data/lib/jets/commands/templates/skeleton/app/jobs/application_job.rb +1 -1
  49. data/lib/jets/commands/templates/skeleton/app/views/layouts/application.html.erb.tt +1 -1
  50. data/lib/jets/commands/templates/skeleton/config/application.rb.tt +12 -5
  51. data/lib/jets/commands/templates/skeleton/config/database.yml.tt +5 -1
  52. data/lib/jets/commands/templates/skeleton/config/environments/development.rb +3 -0
  53. data/lib/jets/commands/templates/skeleton/config/environments/production.rb +5 -0
  54. data/lib/jets/commands/templates/skeleton/public/{images/favicon.ico → favicon.ico} +0 -0
  55. data/lib/jets/commands/templates/skeleton/spec/controllers/posts_controller_spec.rb +1 -3
  56. data/lib/jets/commands.rb +1 -0
  57. data/lib/jets/controller/base.rb +1 -1
  58. data/lib/jets/controller/layout.rb +3 -0
  59. data/lib/jets/controller/params.rb +3 -2
  60. data/lib/jets/controller/request.rb +4 -0
  61. data/lib/jets/core.rb +20 -18
  62. data/lib/jets/core_ext/kernel.rb +9 -5
  63. data/lib/jets/default/application.rb +1 -1
  64. data/lib/jets/inflections.rb +16 -8
  65. data/lib/jets/internal/app/controllers/jets/public_controller.rb +17 -22
  66. data/lib/jets/internal/app/controllers/jets/rack_controller.rb +15 -0
  67. data/lib/jets/naming.rb +0 -23
  68. data/lib/jets/rack/hash_converter.rb +25 -0
  69. data/lib/jets/rack/request.rb +71 -0
  70. data/lib/jets/rack/server.rb +47 -0
  71. data/lib/jets/rack.rb +7 -0
  72. data/lib/jets/rails_overrides/asset_tag_helper.rb +12 -11
  73. data/lib/jets/resource/function.rb +13 -5
  74. data/lib/jets/router.rb +1 -1
  75. data/lib/jets/ruby_server.rb +63 -18
  76. data/lib/jets/server/api_gateway.rb +1 -1
  77. data/lib/jets/stack/resource.rb +3 -1
  78. data/lib/jets/version.rb +1 -1
  79. data/lib/jets.rb +3 -5
  80. metadata +34 -9
  81. data/lib/jets/builders/node-hello.js +0 -73
  82. data/lib/jets/builders/node-shim.js +0 -182
  83. data/lib/jets/internal/app/controllers/jets/public_controller/python/show.py +0 -47
  84. data/lib/jets/internal/app/controllers/jets/public_controller/python/show.pyc +0 -0
@@ -9,16 +9,52 @@ require "erb"
9
9
  # )
10
10
  class Jets::Builders
11
11
  class HandlerGenerator
12
- def initialize(path)
13
- @path = path
12
+ def self.build!
13
+ new.build
14
14
  end
15
15
 
16
- def generate
16
+ def build
17
+ common_base_shim
18
+ app_ruby_shims
17
19
  poly_shims
18
- app_ruby_shim
19
20
  shared_shims
20
21
  end
21
22
 
23
+ def app_ruby_shims
24
+ app_files.each do |path|
25
+ # Generates one big node shim for a entire controller.
26
+ vars = Jets::Builders::ShimVars::App.new(path)
27
+ generate_handler(vars)
28
+ end
29
+ end
30
+
31
+ def app_files
32
+ Jets::Commands::Build.app_files
33
+ end
34
+
35
+ def poly_shims
36
+ missing = []
37
+
38
+ app_files.each do |path|
39
+ vars = Jets::Builders::ShimVars::App.new(path)
40
+ poly_tasks = vars.klass.tasks.select { |t| t.lang != :ruby }
41
+ poly_tasks.each do |task|
42
+ source_path = get_source_path(path, task)
43
+ if File.exist?(source_path)
44
+ native_function(path, task)
45
+ else
46
+ missing << source_path
47
+ end
48
+ end
49
+
50
+ unless missing.empty?
51
+ puts "ERROR: Missing source files. Please make sure these source files exist or remove their declarations".colorize(:red)
52
+ puts missing
53
+ exit 1
54
+ end
55
+ end
56
+ end
57
+
22
58
  def shared_shims
23
59
  Jets::Stack.subclasses.each do |subclass|
24
60
  subclass.functions.each do |fun|
@@ -41,32 +77,11 @@ class Jets::Builders
41
77
  return
42
78
  end
43
79
 
44
- dest_path = "#{tmp_app_root}/#{fun.handler_dest}"
80
+ dest_path = "#{tmp_code}/#{fun.handler_dest}"
45
81
  FileUtils.mkdir_p(File.dirname(dest_path))
46
82
  FileUtils.cp(source_path, dest_path)
47
83
  end
48
84
 
49
- def poly_shims
50
- missing = []
51
-
52
- deducer = Jets::Builders::Deducer.new(@path)
53
- poly_tasks = deducer.klass.tasks.select { |t| t.lang != :ruby }
54
- poly_tasks.each do |task|
55
- source_path = get_source_path(@path, task)
56
- if File.exist?(source_path)
57
- native_function(@path, task)
58
- else
59
- missing << source_path
60
- end
61
- end
62
-
63
- unless missing.empty?
64
- puts "ERROR: Missing source files. Please make sure these source files exist or remove their declarations".colorize(:red)
65
- puts missing
66
- exit 1
67
- end
68
- end
69
-
70
85
  def get_source_path(original_path, task)
71
86
  folder = original_path.sub(/\.rb$/,'')
72
87
  lang_folder = "#{folder}/#{task.lang}"
@@ -78,35 +93,39 @@ class Jets::Builders
78
93
  def native_function(original_path, task)
79
94
  source_path = get_source_path(original_path, task)
80
95
  # Handler: handlers/controllers/posts_controller.handle
81
- dest_path = "#{tmp_app_root}/#{task.handler_path}"
96
+ dest_path = "#{tmp_code}/#{task.handler_path}"
82
97
  FileUtils.mkdir_p(File.dirname(dest_path))
83
98
  FileUtils.cp(source_path, dest_path)
84
99
  end
85
100
 
86
101
  def shared_ruby_shim(fun)
87
- deducer = Jets::Builders::SharedDeducer.new(fun)
88
- generate_shim(deducer)
102
+ vars = Jets::Builders::ShimVars::Shared.new(fun)
103
+ generate_handler(vars)
89
104
  end
90
105
 
91
- # Generates one big node shim for a entire controller.
92
- def app_ruby_shim
93
- deducer = Jets::Builders::Deducer.new(@path)
94
- generate_shim(deducer)
106
+ def common_base_shim
107
+ vars = Jets::Builders::ShimVars::Base.new
108
+ result = evaluate_template("shim.js", vars)
109
+ dest = "#{tmp_code}/handlers/shim.js"
110
+ FileUtils.mkdir_p(File.dirname(dest))
111
+ IO.write(dest, result)
95
112
  end
96
113
 
97
- def generate_shim(deducer)
98
- js_path = "#{tmp_app_root}/#{deducer.js_path}"
99
- FileUtils.mkdir_p(File.dirname(js_path))
100
-
101
- template_path = File.expand_path('../node-shim.js', __FILE__)
102
- result = Jets::Erb.result(template_path, deducer: deducer)
114
+ def generate_handler(vars)
115
+ result = evaluate_template("handler.js", vars)
116
+ dest = "#{tmp_code}/#{vars.js_path}"
117
+ FileUtils.mkdir_p(File.dirname(dest))
118
+ IO.write(dest, result)
119
+ end
103
120
 
104
- IO.write(js_path, result)
121
+ def evaluate_template(template_file, vars)
122
+ template_path = File.expand_path("../templates/#{template_file}", __FILE__)
123
+ Jets::Erb.result(template_path, vars: vars)
105
124
  end
106
125
 
107
- # TODO: move CodeBuilder.tmp_app_root to a common level for HandlerGenerator and CodeBuilder
108
- def tmp_app_root
109
- "#{Jets.build_root}/#{CodeBuilder.tmp_app_root}"
126
+ # TODO: move CodeBuilder.tmp_code to a common level for HandlerGenerator and CodeBuilder
127
+ def tmp_code
128
+ "#{Jets.build_root}/#{CodeBuilder.tmp_code}"
110
129
  end
111
130
  end
112
131
  end
@@ -0,0 +1,55 @@
1
+ require 'digest'
2
+
3
+ # Resolves the chicken-and-egg problem with md5 checksums. The handlers need
4
+ # to reference files with the md5 checksum. The files are the:
5
+ #
6
+ # jets/code/rack-checksum.zip
7
+ # jets/code/bundled-checksum.zip
8
+ #
9
+ # We compute the checksums before we generate the node shim handlers.
10
+ class Jets::Builders
11
+ class Md5
12
+ class << self
13
+ @@checksums = {}
14
+ def checksums
15
+ @@checksums
16
+ end
17
+
18
+ def stage_folders
19
+ paths = []
20
+ paths << "stage/bundled" if Jets.lazy_load?
21
+ paths << "stage/rack" if Jets.rack?
22
+ # Important to have stage/code at the end, since it will use the other
23
+ # 'symlinked' folders to adjust the md5 hash.
24
+ paths << "stage/code"
25
+ paths
26
+ end
27
+
28
+ def compute!
29
+ stage_folders.each do |path|
30
+ @@checksums[path] = dir(path)
31
+ end
32
+ @@checksums
33
+ end
34
+
35
+ def dir(short_path)
36
+ path = "#{Jets.build_root}/#{short_path}"
37
+ files = Dir["#{path}/**/*"]
38
+ files.reject! { |f| File.directory?(f) }
39
+ .reject! { |f| File.symlink?(f) }
40
+ content = files.map do |f|
41
+ Digest::MD5.file(f).to_s[0..7]
42
+ end.join
43
+
44
+ # The stage/code md5 sha depends on the other 'symlinked' folders.
45
+ if short_path == "stage/code"
46
+ content += @@checksums.values.join
47
+ end
48
+
49
+ md5 = Digest::MD5.new
50
+ md5.update(content)
51
+ md5.hexdigest.to_s[0..7]
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,60 @@
1
+ require 'action_view'
2
+
3
+ # Examples:
4
+ #
5
+ # zip = Jets::Builders::Md5Zip.new("/tmp/jets/demo/stage/code")
6
+ # zip.create
7
+ #
8
+ # zip = Jets::Builders::Md5Zip.new("/tmp/jets/demo/stage/bundled")
9
+ # zip.create
10
+ #
11
+ class Jets::Builders
12
+ class Md5Zip
13
+ include ActionView::Helpers::NumberHelper # number_to_human_size
14
+ include Util
15
+
16
+ def initialize(folder)
17
+ @path = "#{Jets.build_root}/#{folder}"
18
+ @checksum = Md5.checksums[folder]
19
+ end
20
+
21
+ def create
22
+ headline "Creating zip file for #{@path}"
23
+
24
+ # https://serverfault.com/questions/265675/how-can-i-zip-compress-a-symlink
25
+ command = "cd #{@path} && zip --symlinks -rq #{zip_file} ."
26
+ sh(command)
27
+ # move out of the lower folder to the stage folder
28
+ # mv /tmp/jets/demo/stage/code/code.zip /tmp/jets/demo/stage/code.zip
29
+ FileUtils.mkdir_p(File.dirname(zip_dest))
30
+ FileUtils.mv("#{@path}/#{zip_file}", zip_dest)
31
+
32
+ # mv /tmp/jets/demo/stage/zips/code.zip /tmp/jets/demo/stage/zips/code-a8a604aa.zip
33
+ FileUtils.mv(zip_dest, md5_dest)
34
+
35
+ file_size = number_to_human_size(File.size(md5_dest))
36
+ puts "Zip file created at: #{md5_dest.colorize(:green)} (#{file_size})"
37
+ end
38
+
39
+ # /tmp/jets/demo/stage/zips/code.zip
40
+ def zip_dest
41
+ stage_area, filename = File.dirname(@path), File.basename(@path)
42
+ zip_area = stage_area + '/zips' # /tmp/jets/demo/stage/zips
43
+ zip_file = filename + '.zip' # code.zip
44
+ "#{zip_area}/#{zip_file}" # /tmp/jets/demo/stage/zips/code.zip
45
+ end
46
+
47
+ def zip_file
48
+ File.basename(zip_dest)
49
+ end
50
+
51
+ # /tmp/jets/demo/stage/zips/code-SHA.zip
52
+ def md5_dest
53
+ zip_dest.sub(".zip", "-#{@checksum}.zip")
54
+ end
55
+
56
+ def md5_name
57
+ File.basename(md5_dest)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,29 @@
1
+ class Jets::Builders
2
+ class RackPackager < RubyPackager
3
+ def finish
4
+ return unless gemfile_exist?
5
+
6
+ symlink_rack_bundled
7
+ copy_rackup_wrappers
8
+ end
9
+
10
+ def symlink_rack_bundled
11
+ # IE: @full_app_root: /tmp/jets/demo/stage/code/rack
12
+ rack_bundled = "#{@full_app_root}/bundled"
13
+ FileUtils.rm_f(rack_bundled) # looks like FileUtils.ln_sf doesnt remove existing symlinks
14
+ FileUtils.ln_sf("/var/task/bundled", rack_bundled)
15
+ end
16
+
17
+ def copy_rackup_wrappers
18
+ # IE: @full_app_root: /tmp/jets/demo/stage/code/rack
19
+ rack_bin = "#{@full_app_root}/bin"
20
+ %w[rackup rackup.rb].each do |file|
21
+ src = File.expand_path("./rackup_wrappers/#{file}", File.dirname(__FILE__))
22
+ dest = "#{rack_bin}/#{file}"
23
+ FileUtils.mkdir_p(rack_bin) unless File.exist?(rack_bin)
24
+ FileUtils.cp(src, dest)
25
+ FileUtils.chmod 0755, dest
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ export JETS_MEGA=1
6
+
7
+ # Figure out where this script is located.
8
+ PROJECTDIR="`dirname \"$0\"`"
9
+ PROJECTDIR="`cd \"$PROJECTDIR/..\" && pwd`"
10
+
11
+ unset BUNDLE_IGNORE_CONFIG
12
+ # When jets packages the app code it creates .bundle/config in the project root.
13
+ # We want that to be used.
14
+
15
+ # Drop a pidfile
16
+ # echo $$ > /tmp/jets-rackup.pid
17
+
18
+ # Run the actual app using the bundled Ruby interpreter, with Bundler activated.
19
+ if [ -n "$C9_USER" ]; then
20
+ exec ruby -rbundler/setup bin/rackup.rb "$@"
21
+ else
22
+ exec "$PROJECTDIR/bundled/rbenv/shims/ruby" -rbundler/setup "$PROJECTDIR/bin/rackup.rb" "$@"
23
+ fi
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Copied from: https://github.com/rack/rack/blob/master/bin/rackup
5
+
6
+ require "rack"
7
+ Rack::Server.start
@@ -0,0 +1,14 @@
1
+ JetsRails.stage = ENV['JETS_STAGE'] || 'dev' # for jets-rails StageMiddleware
2
+
3
+ # config/s3_base_url.txt is generated as part of jets build process
4
+ s3_base_url = IO.read("#{Rails.root}/config/s3_base_url.txt").strip rescue "s3_base_url_placeholder"
5
+ asset_host = "#{s3_base_url}/rack/public"
6
+ Rails.application.config.action_controller.asset_host = asset_host
7
+
8
+ # Rails.application.config.assets.quiet = false
9
+ Rails.application.config.assets.debug = false
10
+ Rails.application.config.assets.compile = false
11
+ Rails.application.config.public_file_server.enabled = true
12
+
13
+ # Looks better without colorizatiion in CloudWatch logs
14
+ Rails.application.config.colorize_logging = false
@@ -0,0 +1,99 @@
1
+ # TODO: Move logic into plugin instead
2
+ class Jets::Builders
3
+ class ReconfigureRails
4
+ def initialize(full_app_root)
5
+ # IE: @app_root: /tmp/jets/demo/stage/code/rack
6
+ @app_root = full_app_root
7
+ end
8
+
9
+ # Only support Rails right now. Maybe move into plugin when adding support
10
+ # to more frameworks. Or maybe better to just abstract but maintain in Jets.
11
+ def run
12
+ return unless rails?
13
+
14
+ puts "Mega Mode: Reconfiguring Rails app."
15
+ copy_initializer
16
+ update_gemfile
17
+ update_development_environment
18
+ set_favicon
19
+ end
20
+
21
+ def copy_initializer
22
+ templates = File.expand_path("./reconfigure_rails", File.dirname(__FILE__))
23
+ relative_path = "config/initializers/jets.rb"
24
+ src = "#{templates}/#{relative_path}"
25
+ dest = "#{@app_root}/#{relative_path}"
26
+ FileUtils.mkdir_p(File.dirname(dest))
27
+ FileUtils.cp(src, dest)
28
+ end
29
+
30
+ def update_gemfile
31
+ gemfile = "#{@app_root}/Gemfile"
32
+ lines = IO.readlines(gemfile)
33
+ lines = add_jets_rails_gem(lines)
34
+ lines = comment_out_ruby_declaration(lines)
35
+ write_content(gemfile, lines)
36
+ end
37
+
38
+ def add_jets_rails_gem(lines)
39
+ return lines if lines.detect { |l| l =~ /jets-rails/ }
40
+ lines << "\n"
41
+ lines << %Q|gem "jets-rails"\n|
42
+ lines
43
+ end
44
+
45
+ # Jets packages up and uses only one version of ruby and different declarations
46
+ # of ruby can cause issues.
47
+ def comment_out_ruby_declaration(lines)
48
+ lines.map do |l|
49
+ l =~ /^(ruby[ (].*)/ ? "# #{$1} # commented out by jets" : l
50
+ end
51
+ end
52
+
53
+ def update_development_environment
54
+ env_file = "#{@app_root}/config/environments/development.rb"
55
+ lines = IO.readlines(env_file)
56
+ new_lines = lines.map do |line|
57
+ if line =~ /(config\.file_watcher.*)/
58
+ " # #{$1} # commented out by jets\n"
59
+ else
60
+ line
61
+ end
62
+ end
63
+ write_content(env_file, new_lines)
64
+ end
65
+
66
+ # Evaluate the application layout and see if has a custom favicon defined yet.
67
+ # If not insert one and rewrite the application layout.
68
+ #
69
+ # This avoids serving binary assets from API gateway, instead serve it from s3 directly.
70
+ def set_favicon
71
+ app_layout = "#{@app_root}/app/views/layouts/application.html.erb"
72
+ return unless File.exist?(app_layout)
73
+
74
+ favicon = '<link rel="shortcut icon" href="<%= asset_path("/favicon.ico") %>">'
75
+
76
+ lines = IO.readlines(app_layout)
77
+ has_favicon = !!lines.find { |l| l.include?(favicon) }
78
+ return if has_favicon
79
+
80
+ content = IO.read(app_layout)
81
+ content = content.sub('</head>', "\n #{favicon}\n </head>")
82
+
83
+ IO.write(app_layout, content)
84
+ end
85
+
86
+ # lines is an Array
87
+ def write_content(path, lines)
88
+ content = lines.join + "\n"
89
+ IO.write(path, content)
90
+ end
91
+
92
+ # Rudimentary rails detection
93
+ def rails?
94
+ config_ru = "#{@app_root}/config.ru"
95
+ return false unless File.exist?(config_ru)
96
+ !IO.readlines(config_ru).grep(/Rails.application/).empty?
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,198 @@
1
+ require "bundler" # for clean_old_submodules only
2
+
3
+ class Jets::Builders
4
+ class RubyPackager
5
+ include Util
6
+
7
+ attr_reader :full_app_root
8
+ def initialize(relative_app_root)
9
+ @full_app_root = full(relative_app_root)
10
+ end
11
+
12
+ def install
13
+ return unless gemfile_exist?
14
+
15
+ reconfigure_ruby_version
16
+ clean_old_submodules
17
+ bundle_install
18
+ setup_bundle_config
19
+ end
20
+
21
+ def finish
22
+ return unless gemfile_exist?
23
+
24
+ copy_bundled_cache
25
+ extract_ruby
26
+ extract_gems
27
+ tidy
28
+ end
29
+
30
+ def gemfile_exist?
31
+ gemfile_path = "#{@full_app_root}/Gemfile"
32
+ File.exist?(gemfile_path)
33
+ end
34
+
35
+ # Installs gems on the current target system: both compiled and non-compiled.
36
+ # If user is on a macosx machine, macosx gems will be installed.
37
+ # If user is on a linux machine, linux gems will be installed.
38
+ #
39
+ # Copies Gemfile* to /tmp/jetss/demo/bundled folder and installs
40
+ # gems with bundle install from there.
41
+ #
42
+ # We take the time to copy Gemfile and bundle into a separate directory
43
+ # because it gets left around to act as a 'cache'. So, when the builds the
44
+ # project gets built again not all the gems from get installed from the
45
+ # beginning.
46
+ def bundle_install
47
+ return if poly_only?
48
+
49
+ full_project_path = @full_app_root
50
+ headline "Bundling: running bundle install in cache area: #{cache_area}."
51
+
52
+ copy_gemfiles(full_project_path)
53
+
54
+ require "bundler" # dynamically require bundler so user can use any bundler
55
+ Bundler.with_clean_env do
56
+ # cd /tmp/jets/demo
57
+ sh(
58
+ "cd #{cache_area} && " \
59
+ "env BUNDLE_IGNORE_CONFIG=1 bundle install --path bundled/gems --without development test"
60
+ )
61
+ end
62
+
63
+ # Copy the Gemfile.lock back to the project in case it was updated.
64
+ # For example we add the jets-rails to the Gemfile.
65
+ copy_gemfile_lock
66
+
67
+ puts 'Bundle install success.'
68
+ end
69
+
70
+ def copy_gemfile_lock
71
+ src = "#{cache_area}/Gemfile.lock"
72
+ dest = "#{@full_app_root}/Gemfile.lock"
73
+ FileUtils.cp_r(src, dest)
74
+ end
75
+
76
+ # Clean up extra unneeded files to reduce package size
77
+ # Because we're removing files (something dangerous) use full paths.
78
+ def tidy
79
+ puts "Tidying project: removing ignored files to reduce package size."
80
+ tidy_project(@full_app_root)
81
+ # The rack sub project has it's own gitignore.
82
+ tidy_project(@full_app_root+"/rack")
83
+ end
84
+
85
+ def tidy_project(path)
86
+ Tidy.new(path).cleanup!
87
+ end
88
+
89
+ # This is in case the user has a 2.5.x variant.
90
+ # Force usage of ruby version that jets supports
91
+ # The lambda server only has ruby 2.5.0 installed.
92
+ def reconfigure_ruby_version
93
+ ruby_version = "#{@full_app_root}/.ruby-version"
94
+ IO.write(ruby_version, Jets::RUBY_VERSION)
95
+ end
96
+
97
+ # When using submodules, bundler leaves old submodules behind. Over time this inflates
98
+ # the size of the the bundled gems. So we'll clean it up.
99
+ def clean_old_submodules
100
+ # https://stackoverflow.com/questions/38800129/parsing-a-gemfile-lock-with-bundler
101
+ lockfile = "#{cache_area}/Gemfile.lock"
102
+ return unless File.exist?(lockfile)
103
+
104
+ parser = Bundler::LockfileParser.new(Bundler.read_file(lockfile))
105
+ specs = parser.specs
106
+
107
+ # specs = Bundler.load.specs
108
+ # IE: spec.source.to_s: "https://github.com/tongueroo/webpacker.git (at jets@a8c4661)"
109
+ submoduled_specs = specs.select do |spec|
110
+ spec.source.to_s =~ /@\w+\)/
111
+ end
112
+
113
+ # find git shas to keep
114
+ # IE: ["a8c4661", "abc4661"]
115
+ git_shas = submoduled_specs.map do |spec|
116
+ md = spec.source.to_s.match(/@(\w+)\)/)
117
+ md[1] # git_sha
118
+ end
119
+
120
+ # IE: /tmp/jets/demo/cache/bundled/gems/ruby/2.5.0/bundler/gems/webpacker-a8c46614c675
121
+ Dir.glob("#{cache_area}/bundled/gems/ruby/2.5.0/bundler/gems/*").each do |path|
122
+ sha = path.split('-').last[0..6] # only first 7 chars of the git sha
123
+ unless git_shas.include?(sha)
124
+ # puts "Removing old submoduled gem: #{path}" # uncomment to see and debug
125
+ FileUtils.rm_rf(path) # REMOVE old submodule directory
126
+ end
127
+ end
128
+ end
129
+
130
+ def copy_gemfiles(full_project_path)
131
+ FileUtils.mkdir_p(cache_area)
132
+ FileUtils.cp("#{full_project_path}/Gemfile", "#{cache_area}/Gemfile")
133
+ FileUtils.cp("#{full_project_path}/Gemfile.lock", "#{cache_area}/Gemfile.lock")
134
+ end
135
+
136
+ def setup_bundle_config
137
+ ensure_build_cache_bundle_config_exists!
138
+
139
+ # Override project's .bundle/config and ensure that .bundle/config matches
140
+ # at these 2 spots:
141
+ # app_root/.bundle/config
142
+ # bundled/gems/.bundle/config
143
+ cache_bundle_config = "#{cache_area}/.bundle/config"
144
+ app_bundle_config = "#{@full_app_root}/.bundle/config"
145
+ FileUtils.mkdir_p(File.dirname(app_bundle_config))
146
+ FileUtils.cp(cache_bundle_config, app_bundle_config)
147
+ end
148
+
149
+ # On circleci the "#{Jets.build_root}/.bundle/config" doesnt exist
150
+ # this only happens with ssh debugging, not when the ci.sh script gets ran.
151
+ # But on macosx it exists.
152
+ # Dont know why this is the case.
153
+ def ensure_build_cache_bundle_config_exists!
154
+ text =<<-EOL
155
+ ---
156
+ BUNDLE_PATH: "bundled/gems"
157
+ BUNDLE_WITHOUT: "development:test"
158
+ EOL
159
+ bundle_config = "#{cache_area}/.bundle/config"
160
+ FileUtils.mkdir_p(File.dirname(bundle_config))
161
+ IO.write(bundle_config, text)
162
+ end
163
+
164
+ def lambdagem_options
165
+ {
166
+ s3: "lambdagems",
167
+ build_root: cache_area, # used in lambdagem
168
+ project_root: @full_app_root, # used in gem_replacer and lambdagem
169
+ }
170
+ end
171
+
172
+ def extract_ruby
173
+ headline "Setting up a vendored copy of ruby."
174
+ Lambdagem.log_level = :info
175
+ Lambdagem::Extract::Ruby.new(Jets::RUBY_VERSION, lambdagem_options).run
176
+ end
177
+
178
+ def extract_gems
179
+ headline "Replacing compiled gems with AWS Lambda Linux compiled versions."
180
+ GemReplacer.new(Jets::RUBY_VERSION, lambdagem_options).run
181
+ end
182
+
183
+ def copy_bundled_cache
184
+ app_root_bundled = "#{@full_app_root}/bundled"
185
+ if File.exist?(app_root_bundled)
186
+ puts "Removing current bundled from project"
187
+ FileUtils.rm_rf(app_root_bundled)
188
+ end
189
+ # Leave #{Jets.build_root}/bundled behind to act as cache
190
+ FileUtils.cp_r("#{cache_area}/bundled", app_root_bundled)
191
+ end
192
+
193
+ private
194
+ def cache_area
195
+ "#{Jets.build_root}/cache" # cleaner to use full path for this setting
196
+ end
197
+ end
198
+ end
@@ -1,6 +1,17 @@
1
- # Build::Deducers figure out required values to create the node shim
2
- class Jets::Builders
3
- class Deducer
1
+ # Jets::Builders::ShimVars::Shared.new(path)
2
+ #
3
+ # @vars.functions.each do |function_name|
4
+ # @vars.handler_for(function_name)
5
+ # end
6
+ #
7
+ # Implements:
8
+ #
9
+ # functions
10
+ # handler_for(function_name)
11
+ # js_path
12
+ #
13
+ module Jets::Builders::ShimVars
14
+ class App < Base
4
15
  # Allow user to specify relative or full path. The right path gets used
5
16
  # internally. Example paths:
6
17
  # app/controllers/posts_controller.rb
@@ -37,13 +48,6 @@ class Jets::Builders
37
48
  # Returns the public methods of the child_class.
38
49
  # Example: [:create, :update]
39
50
  def functions
40
- # Example: require: /tmp/jets/demo/app_root/app/controllers/admin/posts_controller.rb
41
- class_name = @full_path.sub(/.*\/app\/\w+\//,'').sub(/\.rb/,'') # admin/posts_controller
42
- class_name = class_name.classify # Admin::PostsController
43
- # Autoload instead of require to avoid accidentallly double requiring and
44
- # it resulting WARNINGs when there are constants already defined
45
- klass = class_name.constantize # autoload
46
-
47
51
  klass.lambda_functions
48
52
  end
49
53