lam 0.1.0 → 0.1.1

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 (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