Class: Jets::Commands::Build

Inherits:
Object
  • Object
show all
Includes:
StackInfo, Timing
Defined in:
lib/jets/commands/build.rb

Constant Summary

Constants included from Timing

Timing::RECORD_LOG_PATH

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StackInfo

#first_run?, #parent_stack_name, #s3_bucket, #stack_type

Methods included from AwsServices

#cfn, #lambda, #s3, #s3_resource, #stack_exists?, #stack_in_progress?, #sts

Methods included from Timing

clear, #record_data, #record_log, report

Constructor Details

#initialize(options) ⇒ Build

Returns a new instance of Build.



8
9
10
# File 'lib/jets/commands/build.rb', line 8

def initialize(options)
  @options = options.dup
end

Class Method Details

.app_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/jets/commands/build.rb', line 161

def self.app_file?(path)
  return false unless File.extname(path) == ".rb"
  # Do not define lamda functions for the application_controller.rb or
  # application_job.rb
  excludes = %w[
    application_controller.rb
    application_job.rb
  ]
  return false if excludes.detect { |p| path.include?(p) }

  includes = %w[
    app/controllers
    app/jobs
    app/functions
    app/rules
  ]
  return true if includes.detect { |p| path.include?(p) }

  false
end

.app_filesObject

Crucial that the Dir.pwd is in the tmp_app_root because for because Jets.boot set ups autoload_paths and this is how project classes are loaded. TODO: rework code so that Dir.pwd does not have to be in tmp_app_root for build to work.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/jets/commands/build.rb', line 111

def self.app_files
  paths = []
  expression = "#{Jets.root}app/**/**/*.rb"
  Dir.glob(expression).each do |path|
    return false unless File.file?(path)
    next if path.include?("app/functions") # cannot lazy load these because they are anonymous classes
    next unless app_file?(path)

    relative_path = path.sub(Jets.root.to_s, '')
    # Rids of the Jets.root at beginning
    paths << relative_path
  end
  paths += internal_app_files
  paths
end

.internal_app_filesObject

Add internal Jets controllers if they are being used



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/jets/commands/build.rb', line 145

def self.internal_app_files
  paths = []
  controllers = File.expand_path("../../internal/app/controllers/jets", __FILE__)

  welcome = Jets::Router.has_controller?("Jets::WelcomeController")
  paths << "#{controllers}/public_controller.rb" if welcome

  public_catchall = Jets::Router.has_controller?("Jets::PublicController")
  paths << "#{controllers}/welcome_controller.rb" if public_catchall

  jobs = File.expand_path("../../internal/app/jobs/jets", __FILE__)
  paths << "#{jobs}/preheat_job.rb"

  paths
end

.poly_only?Boolean

Returns:

  • (Boolean)


127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/jets/commands/build.rb', line 127

def self.poly_only?
  # Scans all the app code and look for any methods that are ruby.
  # If any method is written in ruby then we know the app is not a
  # soley polymorphic non-ruby app.
  has_ruby = app_files.detect do |path|
    # 1. remove app/controllers or app/jobs, etc
    # 2. remove .rb extension
    app_file = path.sub(%r{app/\w+/},'').sub(/\.rb$/,'')
    # Internal jets controllers like Welcome and Public need a different regexp
    app_file = app_file.sub(%r{.*lib/jets/internal/},'')
    app_klass = app_file.classify.constantize # IE: PostsController, Jets::PublicController
    langs = app_klass.tasks.map(&:lang)
    langs.include?(:ruby)
  end
  !has_ruby
end

.tmp_app_root(full_build_path = false) ⇒ Object



182
183
184
# File 'lib/jets/commands/build.rb', line 182

def self.tmp_app_root(full_build_path=false)
  full_build_path ? "#{Jets.build_root}/app_root" : "app_root"
end

Instance Method Details

#app_filesObject



103
104
105
# File 'lib/jets/commands/build.rb', line 103

def app_files
  self.class.app_files
end

#buildObject



22
23
24
25
# File 'lib/jets/commands/build.rb', line 22

def build
  build_code unless @options[:templates_only]
  build_templates
end

#build_all_templatesObject



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

def build_all_templates
  clean_templates
  # TODO: Maybe  move this tbuild.rb template related logic to cfn/builder.rb
  ## CloudFormation templates
  puts "Building Lambda functions as CloudFormation templates."
  # 1. Shared templates - child templates needs them
  build_api_gateway_templates
  # 2. Child templates - parent template needs them
  build_child_templates
  # 3. Finally parent template
  build_parent_template # must be called at the end
end

#build_api_gateway_templatesObject



60
61
62
63
64
65
# File 'lib/jets/commands/build.rb', line 60

def build_api_gateway_templates
  gateway = Jets::Cfn::TemplateBuilders::ApiGatewayBuilder.new(@options)
  gateway.build
  deployment = Jets::Cfn::TemplateBuilders::ApiGatewayDeploymentBuilder.new(@options)
  deployment.build
end

#build_child_template(path) ⇒ Object

path: app/controllers/comments_controller.rb path: app/jobs/easy_job.rb



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/jets/commands/build.rb', line 75

def build_child_template(path)
  class_path = path.sub(%r{.*app/\w+/},'').sub(/\.rb$/,'')
  class_name = class_path.classify
  class_name.constantize # load app/**/* class definition

  md = path.match(%r{app/(.*?)/}) # extract: controller, job or function
  process_class = md[1].classify
  builder_class = "Jets::Cfn::TemplateBuilders::#{process_class}Builder".constantize

  # Examples:
  #   Jets::Cfn::TemplateBuilders::JobBuilder.new(EasyJob)
  #   Jets::Cfn::TemplateBuilders::ControllerBuilder.new(PostsController)
  #   Jets::Cfn::TemplateBuilders::FunctionBuilder.new(Hello)
  #   Jets::Cfn::TemplateBuilders::FunctionBuilder.new(HelloFunction)
  app_klass = Jets::Klass.from_path(path)
  builder = builder_class.new(app_klass)
  builder.build
end

#build_child_templatesObject



67
68
69
70
71
# File 'lib/jets/commands/build.rb', line 67

def build_child_templates
  app_files.each do |path|
    build_child_template(path)
  end
end

#build_codeObject



28
29
30
# File 'lib/jets/commands/build.rb', line 28

def build_code
  Jets::Builders::CodeBuilder.new.build unless @options[:noop]
end

#build_minimal_templateObject



55
56
57
58
# File 'lib/jets/commands/build.rb', line 55

def build_minimal_template
  parent = Jets::Cfn::TemplateBuilders::ParentBuilder.new(@options)
  parent.build
end

#build_parent_templateObject



94
95
96
97
# File 'lib/jets/commands/build.rb', line 94

def build_parent_template
  parent = Jets::Cfn::TemplateBuilders::ParentBuilder.new(@options)
  parent.build
end

#build_templatesObject



33
34
35
36
37
38
39
# File 'lib/jets/commands/build.rb', line 33

def build_templates
  if @options[:stack_type] == :minimal
    build_minimal_template
  else
    build_all_templates
  end
end

#clean_templatesObject



99
100
101
# File 'lib/jets/commands/build.rb', line 99

def clean_templates
  FileUtils.rm_rf("#{Jets.build_root}/templates")
end

#runObject



12
13
14
15
16
17
18
19
# File 'lib/jets/commands/build.rb', line 12

def run
  puts "Building project for Lambda..."
  return if @options[:noop]
  # run gets called from the CLI and does not have all the stack_options yet.
  # We compute it and change the options early here.
  @options.merge!(stack_type: stack_type, s3_bucket: s3_bucket)
  build
end