lam 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +16 -8
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -3
  6. data/Gemfile.lock +107 -0
  7. data/Guardfile +22 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +19 -17
  10. data/Rakefile +4 -0
  11. data/bin/lam +14 -0
  12. data/bin/lamb +14 -0
  13. data/lam.gemspec +18 -20
  14. data/lib/lam.rb +10 -1
  15. data/lib/lam/base_controller.rb +54 -0
  16. data/lib/lam/build.rb +43 -0
  17. data/lib/lam/build/handler_generator.rb +34 -0
  18. data/lib/lam/build/lambda_deducer.rb +47 -0
  19. data/lib/lam/build/templates/handler.js +156 -0
  20. data/lib/lam/build/traveling_ruby.rb +108 -0
  21. data/lib/lam/cli.rb +23 -0
  22. data/lib/lam/cli/help.rb +19 -0
  23. data/lib/lam/command.rb +25 -0
  24. data/lib/lam/process.rb +18 -0
  25. data/lib/lam/process/base_processor.rb +23 -0
  26. data/lib/lam/process/controller_processor.rb +36 -0
  27. data/lib/lam/process/help.rb +11 -0
  28. data/lib/lam/process/processor_deducer.rb +52 -0
  29. data/lib/lam/util.rb +13 -0
  30. data/lib/lam/version.rb +1 -1
  31. data/notes/design.md +43 -0
  32. data/notes/traveling-ruby-packaging-lam.md +26 -0
  33. data/notes/traveling-ruby-packaging.md +103 -0
  34. data/notes/traveling-ruby.md +82 -0
  35. data/spec/fixtures/project/.gitignore +3 -0
  36. data/spec/fixtures/project/.ruby-version +1 -0
  37. data/spec/fixtures/project/Gemfile +4 -0
  38. data/spec/fixtures/project/Gemfile.lock +35 -0
  39. data/spec/fixtures/project/app/controllers/application_controller.rb +2 -0
  40. data/spec/fixtures/project/app/controllers/posts_controller.rb +12 -0
  41. data/spec/fixtures/project/bin/lam +22 -0
  42. data/spec/fixtures/project/handlers/controllers/posts.js +156 -0
  43. data/spec/lib/cli_spec.rb +20 -0
  44. data/spec/lib/lam/base_controller_spec.rb +18 -0
  45. data/spec/lib/lam/build/lambda_deducer_spec.rb +20 -0
  46. data/spec/lib/lam/build_spec.rb +29 -0
  47. data/spec/lib/lam/process/controller_processor_spec.rb +22 -0
  48. data/spec/lib/lam/process/infer_spec.rb +24 -0
  49. data/spec/lib/lam/process_spec.rb +18 -0
  50. data/spec/spec_helper.rb +25 -0
  51. metadata +191 -21
  52. data/bin/console +0 -14
  53. data/bin/setup +0 -8
@@ -0,0 +1,36 @@
1
+ require_relative "base_processor"
2
+
3
+ class Lam::Process
4
+ class ControllerProcessor < Lam::Process::BaseProcessor
5
+ def run
6
+ # Use the handler value (ie: posts.create) to deduce the user's business
7
+ # code to require and run.
8
+ deducer = ProcessorDeducer.new(handler)
9
+ path = deducer.controller[:path]
10
+ code = deducer.controller[:code]
11
+
12
+ begin
13
+ require path # require "app/controllers/posts_controller.rb"
14
+ # Puts the return value of user's code to stdout because this is
15
+ # what eventually gets used by API Gateway.
16
+ # Explicitly using $stdout since puts redirected to $stderr.
17
+
18
+ # result = PostsController.new(event, context).create
19
+ result = instance_eval(code, path)
20
+
21
+ # JSON.dump is pretty robust. If it cannot dump the structure into a
22
+ # json string, it just dumps it to a plain text string.
23
+ $stdout.puts JSON.dump(result) # only place where we write to stdout.
24
+ rescue Exception => e
25
+ # Customize error message slightly so nodejs shim can process the
26
+ # returned error message.
27
+ # The "RubyError: " is a marker that the javascript shim scans for.
28
+ $stderr.puts("RubyError: #{e.class}: #{e.message}") # js needs this as the first line
29
+ backtrace = e.backtrace.map {|l| " #{l}" }
30
+ $stderr.puts(backtrace)
31
+ # $stderr.puts("END OF RUBY OUTPUT")
32
+ exit 1 # instead of re-raising to control the error backtrace output
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ class Lam::Process::Help
2
+ class << self
3
+ def controller
4
+ <<-EOL
5
+ Examples:
6
+
7
+ lam process controller '{ "we" : "love", "using" : "Lambda" }' '{"test": "1"}' "handlers/controllers/posts.create"
8
+ EOL
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ class Lam::Process::ProcessorDeducer
2
+ def initialize(handler)
3
+ @handler = handler
4
+ end
5
+
6
+ # Deduces the path and method from the handler. Example:
7
+ #
8
+ # ProcessorDeducer.new("handlers/functions/posts.create").function
9
+ # => {path: "app/functions/posts.rb", code: "create(event, context)"}
10
+ #
11
+ # Summary:
12
+ #
13
+ # Input:
14
+ # handler: handlers/functions/posts.create
15
+ # Output:
16
+ # path: app/functions/posts.rb
17
+ # code: create(event, context) # code to instance_eval
18
+ #
19
+ # Returns: {path: path, code: code}
20
+ def function
21
+ path, meth = @handler.split('.')
22
+ path = Lam.root + path.sub("handlers", "app") + ".rb"
23
+ code = "#{meth}(event, context)"
24
+ {path: path, code: code}
25
+ end
26
+
27
+ # Deduces the path and method from the handler. Example:
28
+ #
29
+ # ProcessorDeducer.new("handlers/controllers/posts.create").controller
30
+ # => {path: "controllers/posts_controller.rb", code: "create"}
31
+ #
32
+ # Summary:
33
+ #
34
+ # Input:
35
+ # handler: handlers/controllers/posts.create
36
+ # Output:
37
+ # path: app/controllers/posts_controller.rb
38
+ # code: create # code to instance_eval
39
+ #
40
+ # Returns: {path: path, code: code}
41
+ def controller
42
+ handler_path, meth = @handler.split('.')
43
+
44
+ path = Lam.root + handler_path.sub("handlers", "app") + "_controller.rb"
45
+
46
+ controller_name = handler_path.sub(%r{.*handlers/controllers/}, "") + "_controller" # posts_controller
47
+ controller_class = controller_name.split('_').collect(&:capitalize).join # PostsController
48
+ code = "#{controller_class}.new(event, context).#{meth}" # PostsController.new(event, context).create
49
+
50
+ {path: path, code: code, class_name: controller_class}
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ module Lam::Util
2
+ # Ensures trailing slash
3
+ # Useful for appending a './' in front of a path or leaving it alone.
4
+ # Returns: '/path/with/trailing/slash/' or './'
5
+ @@root = nil
6
+ def root
7
+ return @@root if @@root
8
+ @@root = ENV['PROJECT_ROOT'].to_s
9
+ @@root = '.' if @@root == ''
10
+ @@root = "#{@@root}/" unless @@root.ends_with?('/')
11
+ @@root
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Lam
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -0,0 +1,43 @@
1
+ ## Project Structure
2
+
3
+ TODO: make this a table
4
+
5
+ ```sh
6
+ app/controllers
7
+ app/workers
8
+ app/functions
9
+ config/project.yml
10
+ config/events.yml
11
+ config/routes.rb
12
+ ```
13
+
14
+
15
+ ## Usage
16
+
17
+ ```sh
18
+ lam build
19
+ lam deploy
20
+ ```
21
+
22
+ ## Testing
23
+
24
+ Testing controller processing without node shim.
25
+
26
+ ```
27
+ lam process controller '{ "we" : "love", "using" : "Lambda" }' '{"test": "1"}' "handlers/controllers/posts.create"
28
+ ```
29
+
30
+ Testing the generated node shim handler and the controller processing.
31
+
32
+ ```
33
+ cd spec/fixtures/project
34
+ lam build # generates the handlers
35
+ node handlers/controllers/posts.js
36
+ ```
37
+
38
+ VS
39
+
40
+ ```sh
41
+ processors/controller_processor.rb '{ "we" : "love", "using" : "Lambda" }' '{"test": "1"}' "handlers/controllers/posts.create" | jq '.'
42
+ ```
43
+
@@ -0,0 +1,26 @@
1
+ # start off at project root
2
+
3
+ mkdir -p /tmp/lam_build
4
+ cp Gemfile* /tmp/lam_build/
5
+ cd /tmp/lam_build # cd into there to build TravelingRuby
6
+
7
+ wget http://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz .
8
+ mkdir -p bundled/ruby # tmp/lam_build/bundled/ruby
9
+ tar -xvf traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz -C bundled/ruby
10
+ # ls ruby => bin bin.real info lib
11
+ # bundled/ruby/bin/ruby -v # works now :)
12
+
13
+ # had to modify Gemfile and update the local path for linux
14
+ bundle install --path bundled/gems
15
+
16
+ # DONT THINK THAT I NEED TO COPY THE Gemfile into bundled/gems...
17
+ # mv Gemfile* bundled/gems/ # copy Gemfile from the project to bundled/gems
18
+ # IMPORTANT: the Gemfile must be in the same bundled/gems folder
19
+
20
+ # now we have both bundled/gems bundled/ruby :)
21
+ bundled/gems/ruby/2.2.0/bin/print_ruby_info # should work
22
+
23
+
24
+ # Let's move back to the project and test the wrapper, it should work also
25
+ mv bundled ~/lam-test/lam/spec/fixtures/project/
26
+ cd ~/lam-test/lam/spec/fixtures/project # back to project root
@@ -0,0 +1,103 @@
1
+ ### Packaging Gems Info
2
+
3
+ ### Structure
4
+
5
+ This is the structure that TravelingRuby uses in it's tutorial.
6
+
7
+ ```sh
8
+ PROJECT/YOUR_BINARY_WRAPPER (hello)
9
+ PROJECT/lib/ruby/bin/ruby -> PROJECT/lib/ruby/bin.real/ruby
10
+ PROJECT/lib/vendor/ruby/2.2.0/bin/print_ruby_info # the gem binaries are here
11
+ ```
12
+
13
+ * Instead calling the ruby binary `lam process` command directly.
14
+ * Lam will require 'bundler/setup' so the user's gems will be required properly
15
+ * Skip the overhead of having another wrapper
16
+
17
+ ```sh
18
+ PROJECT/vendor/ruby/2.2.0/bin/lam # the gem binaries are here
19
+ ```
20
+
21
+ ### Packaging Gems Commands
22
+
23
+ ```
24
+ mkdir packaging/tmp
25
+ cp Gemfile Gemfile.lock packaging/tmp/ # this are from the user's project
26
+ cd packaging/tmp
27
+
28
+ # here's where the gems are instaleld into packaging/vendor/
29
+ BUNDLE_IGNORE_CONFIG=1 bundle install --path ../vendor --without development
30
+ # IMPORTANT: Think I'll make the user switch to 2.2.0 and error the build proccess.
31
+
32
+ ##############
33
+ I can call ruby bin files directly.
34
+ I was WRONG. Cannot call gem bin files directly because I need to make sure that
35
+ bundler/setup gets loaded before calling the gem bin.
36
+ Tried moving bundler/setup into the lam library itself but get all sorts of warnings.
37
+
38
+ hello-1.0.0-linux-x86_64/lib/vendor/ruby/2.2.0/bin/lam help
39
+ BUT the shabang line has: #!/usr/bin/env ruby2.0 .. but only on linux..
40
+ Simply cannot rename the darn ruby version folder.
41
+ #############
42
+
43
+
44
+ cd ../..
45
+ rm -rf packaging/tmp # remove working space
46
+
47
+ # reduce the zip package size!
48
+ rm -f packaging/vendor/*/*/cache/*
49
+ ```
50
+
51
+ Now we can copy over the generated vendored files
52
+
53
+ ##################################
54
+ # clean
55
+ rm -rf packaging/vendor/
56
+
57
+ bundle update
58
+ rake package:linux:x86_64 DIR_ONLY=1
59
+
60
+ mkdir packaging/tmp
61
+ cp Gemfile Gemfile.lock packaging/tmp/
62
+ cd packaging/tmp
63
+ BUNDLE_IGNORE_CONFIG=1 bundle install --path ../vendor --without development
64
+ cd ../..
65
+
66
+ cp -pR packaging/vendor hello-1.0.0-linux-x86_64/lib/
67
+ cp Gemfile Gemfile.lock hello-1.0.0-linux-x86_64/lib/vendor/
68
+ mkdir hello-1.0.0-linux-x86_64/lib/vendor/.bundle
69
+ cp packaging/bundler-config hello-1.0.0-linux-x86_64/lib/vendor/.bundle/config
70
+
71
+ find . -name print_ruby_info
72
+
73
+
74
+ # Wrapper script `lam`
75
+
76
+ ```bash
77
+ #!/bin/bash
78
+ set -e
79
+
80
+ # Figure out where this script is located.
81
+ SELFDIR="`dirname \"$0\"`"
82
+ SELFDIR="`cd \"$SELFDIR\" && pwd`"
83
+
84
+ # Tell Bundler where the Gemfile and gems are.
85
+ export BUNDLE_GEMFILE="$SELFDIR/lib/vendor/Gemfile"
86
+ unset BUNDLE_IGNORE_CONFIG
87
+
88
+ # Run the actual app using the bundled Ruby interpreter, with Bundler activated.
89
+ exec "$SELFDIR/lib/ruby/bin/ruby" -rbundler/setup "$SELFDIR/lib/app/hello.rb"
90
+ ```
91
+
92
+
93
+ ### Building Ruby
94
+ http://cache.ruby-lang.org/pub/ruby/2.2/
95
+
96
+ ```sh
97
+ wget http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.2.tar.gz
98
+ tar xvfvz ruby-2.2.2.tar.gz
99
+ cd ruby-2.2.2
100
+ ./configure
101
+ make
102
+ sudo make install
103
+ ```
@@ -0,0 +1,82 @@
1
+ ## Overview
2
+
3
+ There are 2 things to point out:
4
+
5
+ 1. What the user's environment contains - cannot control this, can only suggest
6
+ 2. What the lambda environment contains - can fully control this
7
+
8
+ * User can develop with ruby 2.4 and bundle gems and test and be happy. Hopefully they eventually learn to test with ruby 2.2.0 (when they run into bugs).
9
+ * When `lam build` runs it will bundle it in ruby 2.2.0 though.
10
+ * When lambda runs it will call `lam` with ruby 2.2.0. The gems will be installed in 2.2.0
11
+ * Hope all works
12
+
13
+ ## Download ruby commands
14
+
15
+ ```sh
16
+ # linux 64bit
17
+ wget http://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz .
18
+ mkdir ruby-linux
19
+ tar -xvf traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz -C ruby-linux
20
+ # mac
21
+ wget http://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-20150715-2.2.2-osx.tar.gz
22
+ mkdir ruby-mac
23
+ tar -xvf traveling-ruby-20150715-2.2.2-osx.tar.gz -C ruby-mac
24
+
25
+ # another version
26
+ mkdir hello-1.0.0-linux-x86_64/lib/ruby && tar -xzf packaging/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz -C hello-1.0.0-linux-x86_64/lib/ruby
27
+ ```
28
+
29
+ ## Launch Instance for Testing
30
+
31
+ ```sh
32
+ aws ec2 run-instances --image-id ami-8c1be5f6 --count 1 --instance-type t2.micro --key-name default --security-groups demo
33
+ ```
34
+
35
+ ## Tree Structure
36
+
37
+ ```sh
38
+ lib/
39
+ ├── app
40
+ │   └── hello.rb
41
+ ├── ruby
42
+ │   ├── bin
43
+ │   │   ├── gem
44
+ │   │   ├── irb
45
+ │   │   ├── rake
46
+ │   │   ├── ruby
47
+ │   │   └── ruby_environment
48
+ │   ├── bin.real
49
+ │   │   ├── bundle
50
+ │   │   ├── bundler
51
+ │   │   ├── gem
52
+ │   │   ├── irb
53
+ │   │   ├── rake
54
+ │   │   └── ruby
55
+ │   └── lib
56
+ │   └── ruby
57
+ │   ├── 2.2.0
58
+ ...
59
+ │   │   └── yaml.rb
60
+ │   ├── gems
61
+ │   │   └── 2.2.0
62
+ │   │   ├── gems
63
+ │   │   │   ├── attr_extras-5.2.0
64
+ │   │   │   │   ├── attr_extras.gemspec
65
+ ...
66
+ │   │   │   ├── bundler-1.9.9
67
+ ...
68
+ │   │   └── rake-12.2.1.gemspec
69
+ ...
70
+ └── vendor
71
+ ├── Gemfile
72
+ ├── Gemfile.lock
73
+ └── ruby
74
+ └── 2.2.0 <= IMPORTANT: bundler copies gems to folder with running ruby version
75
+ ├── gems
76
+ │   ├── concurrent-ruby-1.0.5
77
+ │   ├── faker-1.7.3
78
+ │   └── i18n-0.9.0
79
+ ...
80
+ ```
81
+
82
+ * [Full tree](https://gist.github.com/tongueroo/c42f9d35b15b06eb810802243f4e2f6d)
@@ -0,0 +1,3 @@
1
+ vendor
2
+ bundled
3
+ lam.zip
@@ -0,0 +1 @@
1
+ 2.2.2
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "lam"
4
+ gem "print_ruby_info" # test
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: /Users/tung/src/tongueroo/lam
3
+ specs:
4
+ lam (0.0.1)
5
+ activesupport
6
+ colorize
7
+ hashie
8
+ thor
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (5.1.4)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (~> 0.7)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ colorize (0.8.1)
19
+ concurrent-ruby (1.0.5)
20
+ hashie (3.5.6)
21
+ i18n (0.9.0)
22
+ concurrent-ruby (~> 1.0)
23
+ minitest (5.10.3)
24
+ print_ruby_info (0.0.3)
25
+ thor (0.20.0)
26
+ thread_safe (0.3.6)
27
+ tzinfo (1.2.3)
28
+ thread_safe (~> 0.1)
29
+
30
+ PLATFORMS
31
+ ruby
32
+
33
+ DEPENDENCIES
34
+ lam!
35
+ print_ruby_info
@@ -0,0 +1,2 @@
1
+ class ApplicationController < Lam::BaseController
2
+ end
@@ -0,0 +1,12 @@
1
+ class PostsController < Lam::BaseController
2
+ def create
3
+ # render text: "test2" # more consistent for web controllers
4
+
5
+ # render returns Lamba Proxy struture for web requests
6
+ render json: event, status: 200
7
+ end
8
+
9
+ # def update
10
+ # render json: event, status: 200
11
+ # end
12
+ end