Skip to content

Commit

Permalink
Clojure support (#674)
Browse files Browse the repository at this point in the history
* Clojure support

Is basically the same as the Java plugin but with some pretty standard hook values and automagic source stripping to prevent clojure from recompiling sources.

* Add example for Clojure

And fix my terrible mistake in `clojure.go:Open` and the ignoreFiles check
  • Loading branch information
liath authored and tj committed Feb 15, 2017
1 parent b5945ec commit 9ed5fd5
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 0 deletions.
22 changes: 22 additions & 0 deletions _examples/clojure/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

To run the example first setup your [AWS Credentials](http://apex.run/#aws-credentials), and ensure "role" in ./project.json is set to your Lambda function ARN.

Install Lein:

```
$ wget -P ~/bin https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
$ chmod 755 ~/bin/lein
$ ~/bin/lein
```

Deploy the functions:

```
$ apex deploy
```

Try it out:

```
$ echo '{ "say": "Hello World!" }' | apex invoke say
```
11 changes: 11 additions & 0 deletions _examples/clojure/functions/say/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(defproject org.example "0.0.0-SNAPSHOT"
:description "A lamb says things."
:dependencies [[cheshire "5.7.0"]
[com.amazonaws/aws-lambda-java-core "1.1.0"]
[com.amazonaws/aws-lambda-java-events "1.1.0" :exclusions [com.amazonaws/aws-java-sdk-s3
com.amazonaws/aws-java-sdk-sns
com.amazonaws/aws-java-sdk-cognitoidentity
com.amazonaws/aws-java-sdk-kinesis
com.amazonaws/aws-java-sdk-dynamodb]]
[org.clojure/clojure "1.8.0"]]
:aot :all)
35 changes: 35 additions & 0 deletions _examples/clojure/functions/say/src/org/example/lambsay.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
(ns org.example.lambsay
"What does the lamb say?"
(:gen-class :implements [com.amazonaws.services.lambda.runtime.RequestStreamHandler])
(:require [cheshire.core :as json]
[clojure.java.io :as io]
[clojure.string :as str])
(:import (com.amazonaws.services.lambda.runtime Context)))

(defn it-says
"The lamb says-"
[what]
(->
" _,._ ┌outline┐
__.' _) │sayline│
<_,)'.-\"a\\ /└outline┘
/' ( \\ /
_.-----..,-' (`\"--^
// |
(| `; , |
\\ ;.----/ ,/
) // / | |\\ \\
\\ \\\\`\\ | |/ /
\\ \\\\ \\ | |\\/"
(str/replace "outline" (apply str (repeat (count what) "")))
(str/replace "sayline" what)))

(defn -handleRequest
[this is os context]
(let [w (io/writer os)]
(-> (json/parse-stream (io/reader is))
(get "say")
(it-says)
(str "\n")
(->> (.write w)))
(.flush w)))
7 changes: 7 additions & 0 deletions _examples/clojure/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "lamb",
"description": "Clojure example project using Lein",
"role": "arn:aws:iam::012345678901:role/lambylamby",
"runtime": "clojure",
"handler": "org.example.lambsay::handleRequest"
}
1 change: 1 addition & 0 deletions cmd/apex/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
_ "github.com/apex/apex/plugins/golang"
_ "github.com/apex/apex/plugins/hooks"
_ "github.com/apex/apex/plugins/inference"
_ "github.com/apex/apex/plugins/clojure"
_ "github.com/apex/apex/plugins/java"
_ "github.com/apex/apex/plugins/nodejs"
_ "github.com/apex/apex/plugins/python"
Expand Down
1 change: 1 addition & 0 deletions function/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ var defaultPlugins = []string{
"golang",
"python",
"nodejs",
"clojure",
"java",
"env",
"shim",
Expand Down
97 changes: 97 additions & 0 deletions plugins/clojure/clojure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package clojure

import (
azip "archive/zip"
"errors"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/apex/apex/archive"
"github.com/apex/apex/function"
)

func init() {
function.RegisterPlugin("clojure", &Plugin{})
}

const (
// Runtime name used by Apex
Runtime = "clojure"
// RuntimeCanonical represents names used by AWS Lambda
RuntimeCanonical = "java8"
jarFile = "apex.jar"
)

// Plugin Does plugin things
type Plugin struct{}

// Open adds the shim and golang defaults.
func (p *Plugin) Open(fn *function.Function) error {
if fn.Runtime != Runtime {
return nil
}

if fn.Hooks.Build == "" {
fn.Hooks.Build = "lein uberjar && mv target/*-standalone.jar target/apex.jar"
}

if fn.Hooks.Clean == "" {
fn.Hooks.Clean = "rm -f target &> /dev/null"
}

if _, err := os.Stat(".apexignore"); err != nil {
// Since we're deploying a fat jar, we don't need anything else.
fn.IgnoreFile = []byte(`
*
!**/apex.jar
`)
}

return nil
}

// Build adds the jar contents to zipfile.
func (p *Plugin) Build(fn *function.Function, zip *archive.Zip) error {
if fn.Runtime != Runtime {
return nil
}
fn.Runtime = RuntimeCanonical

expectedJarPath := filepath.Join(fn.Path, "target", jarFile)
if _, err := os.Stat(expectedJarPath); err != nil {
return errors.New("Expected jar file not found")
}
fn.Log.Debugf("found jar path: %s", expectedJarPath)

fn.Log.Debug("appending compiled files")
reader, err := azip.OpenReader(expectedJarPath)
if err != nil {
return err
}
defer reader.Close()

for _, file := range reader.File {
parts := strings.Split(file.Name, ".")
extension := parts[len(parts) - 1]
if extension == "clj" || extension == "cljx" || extension == "cljc" {
continue
}

r, err := file.Open()
if err != nil {
return err
}

b, err := ioutil.ReadAll(r)
if err != nil {
return err
}
r.Close()

zip.AddBytes(file.Name, b)
}

return nil
}

0 comments on commit 9ed5fd5

Please sign in to comment.