Support for pycompose as OpenWhisk action
diff --git a/MANIFEST.in b/MANIFEST.in
index 73761d1..25d6847 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -15,4 +15,6 @@
 include tox.ini .travis.yml
 include travis/*.sh
 
+prune action
+
 global-exclude *.py[cod] __pycache__
diff --git a/action/.gitignore b/action/.gitignore
new file mode 100644
index 0000000..c3b9c0d
--- /dev/null
+++ b/action/.gitignore
@@ -0,0 +1,2 @@
+pycompose.zip
+virtualenv
\ No newline at end of file
diff --git a/action/README.md b/action/README.md
new file mode 100644
index 0000000..fd8d82a
--- /dev/null
+++ b/action/README.md
@@ -0,0 +1,20 @@
+# Building an OpenWhisk Action
+
+This directory helps with creating an OpenWhisk action that will
+implement the `pycompose` functionality.
+
+## Quick Start
+
+```shell
+$ ./build.sh
+$ ./deploy.sh
+$ ./test.sh
+ok
+```
+
+## Usage in Other Clients
+
+One suggested use of the action is to build the action source
+(pycompose.zip), using the `build.sh` script. Include the built zip
+with your client. Then, for each user of the client, deploy the action
+using that source, and invoke the action as needed.
diff --git a/action/__main__.py b/action/__main__.py
new file mode 100755
index 0000000..f1d9a9b
--- /dev/null
+++ b/action/__main__.py
@@ -0,0 +1,35 @@
+#
+# Copyright 2018 IBM Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import composer
+import json
+
+#
+# this is the main method for running the pycomposer as an OpenWhisk action
+#
+def compose(args):
+    if args['source'] is None:
+        raise Exception('Please provide a source parameter')
+
+    composition = eval(args['source'])
+    print(args['source'])
+
+    if args['lower'] is not None:
+        res = composer.lower(composition, args['lower'])
+        print(str(res))
+        return json.loads(str(res))
+    else:
+        return { "code": composer.encode(composer.composition('anonymous', composition), lower)['actions'][-1]['action']['exec']['code'] }
diff --git a/action/build.sh b/action/build.sh
new file mode 100755
index 0000000..7845d86
--- /dev/null
+++ b/action/build.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+PY_VERSION=3.6
+
+# directory of script
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ROOTDIR="$DIR/.."
+cd "${ROOTDIR}/action"
+
+# clean up
+rm -rf virtualenv pycompose.zip
+
+# create virtualenv
+virtualenv --no-pip --no-wheel --no-setuptools virtualenv
+
+# copy in the composer assets
+cp -r "$ROOTDIR/src/composer" "virtualenv/lib/python${PY_VERSION}/site-packages"
+
+# remove symlinks
+find "virtualenv/lib/python${PY_VERSION}/" -type l -exec rm {} \;
+
+# remove site.py
+rm "virtualenv/lib/python${PY_VERSION}/site.py"
+
+# remove the python exec stuff
+rm "virtualenv/bin/python-config"
+rm "virtualenv/bin/python${PY_VERSION}"
+
+# remove pycaches
+find "virtualenv/" -name __pycache__ -exec rm -rf {} \; 2>&1 | grep -v "No such file or directory"
+
+# make the zip file
+# the -y part says not to follow symlinks
+echo "Zipping it up"
+zip -qry pycompose.zip virtualenv __main__.py
+
+# sanity check
+unzip -ql pycompose.zip | grep composer.py > /dev/null && echo "ok" || (echo "fail" && exit 1)
diff --git a/action/deploy.sh b/action/deploy.sh
new file mode 100755
index 0000000..0daa70c
--- /dev/null
+++ b/action/deploy.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+bx wsk action update pycompose --kind python:3 pycompose.zip --main compose
diff --git a/action/test.sh b/action/test.sh
new file mode 100755
index 0000000..5a9fa3d
--- /dev/null
+++ b/action/test.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+bx wsk action invoke pycompose -p source "composer.sequence('echo', 'echo')" -p lower 0.4.0 -br | jq --raw-output .type | grep -q '^sequence$'
+
+if [ $? == 0 ]; then
+    echo "ok"
+    exit 0
+else
+    echo "fail"
+    exit 1
+fi
+   
diff --git a/src/composer/composer.py b/src/composer/composer.py
index 22fabd4..5e4514f 100644
--- a/src/composer/composer.py
+++ b/src/composer/composer.py
@@ -15,7 +15,6 @@
 import json
 import os
 import sys
-import openwhisk
 import inspect
 import re
 import base64
@@ -491,6 +490,7 @@
         if '__OW_API_KEY' in os.environ:
              options['api_key'] = os.environ['__OW_API_KEY']
 
+        import openwhisk
         wsk = openwhisk.Client(options)
         wsk.compositions = Compositions(wsk, self)
         return wsk