summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile41
-rwxr-xr-xappstore58
-rw-r--r--appstore.config0
-rwxr-xr-xbin/appstore-init57
-rwxr-xr-xhooks/common3
-rwxr-xr-xhooks/post-receive55
-rwxr-xr-xlib/common64
-rw-r--r--[-rwxr-xr-x]lib/header (renamed from hooks/post-commit)4
-rw-r--r--lib/header-hook8
-rwxr-xr-xlibexec/appstore-init-server50
-rw-r--r--template/README.md1
-rw-r--r--template/apps.csv1
-rw-r--r--test/data/my-webapp/root/app.js37
-rw-r--r--test/it.bats28
-rw-r--r--test/utils.bash176
16 files changed, 578 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c4c4ffc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.zip
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..49538be
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,41 @@
+all: test docs
+
+BINS=$(wildcard bin/*) $(wildcard libexec/*)
+
+BATS=$(sort $(patsubst test/%,%,$(filter-out test/X-%,$(wildcard test/*.bats))))
+TESTS=$(addprefix test-,$(BATS))
+
+test-%:
+ @echo === $@
+ @bats $(patsubst test-%,test/%,$@)
+
+show-tests:
+ @echo BATS=$(BATS)
+ @echo TESTS=$(TESTS)
+ @echo $(addprefix set_header-,$(BINS))
+
+test: $(TESTS)
+.PHONY: test
+
+docs:
+ @make -C docs
+.PHONY: docs
+
+define set_header
+set_header-$(1):
+ @count=`wc -l $(2)|cut -f 1 -d ' '`; \
+ cat $(2) > x; \
+ echo "# HEADER END" >> x; \
+ sed '1,/HEADER END/d' $(1) >> x; \
+ if [ `md5sum $(1)|cut -f 1 -d ' '` != `md5sum x|cut -f 1 -d ' '` ]; then echo Updated: $(1); cp x $(1); fi; \
+ rm x
+endef
+ $(wildcard hooks/*)
+
+$(foreach f,$(BINS),$(eval $(call set_header,$(f),lib/header)))
+set-headers: set-hook-headers $(addprefix set_header-,$(BINS))
+
+$(foreach f,$(wildcard hooks/*),$(eval $(call set_header,$(f),lib/hook-header)))
+set-headers: $(addprefix set_header-,$(BINS))
+
+.PHONY: set-headers
diff --git a/appstore b/appstore
new file mode 100755
index 0000000..eee4774
--- /dev/null
+++ b/appstore
@@ -0,0 +1,58 @@
+#!/bin/bash -e
+
+PRG="$0"
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+done
+
+APPSTORE_HOME=`dirname "$PRG"`
+APPSTORE_HOME=`cd "$APPSTORE_HOME" && pwd`
+
+. $APPSTORE_HOME/lib/common
+
+usage_text() {
+ echo "usage: $usage_app <command>"
+ echo ""
+ echo "Available porcelain commands:"
+ grep_path "/appstore-.*$" "$APPSTORE_HOME/bin" | \
+ sed "s,^.*/appstore-, ," | \
+ sort -n
+ echo ""
+ echo "Available plumbing commands:"
+ grep_path "/appstore-.*$" "$APPSTORE_HOME/libexec" | \
+ sed "s,^.*/appstore-, ," | \
+ sort -n
+}
+
+if [ $# -eq 0 ]
+then
+ usage
+fi
+
+command=$1; shift
+
+bin=`grep_path "/appstore-$command$" "$APPSTORE_HOME/bin"`
+
+if [ ! -x "$bin" ]
+then
+ bin=`grep_path "/appstore-$command$" "$APPSTORE_HOME/libexec"`
+ if [ ! -x "$bin" ]
+ then
+ echo "Unknown command: $command" 2>&1
+ exit 1
+ fi
+fi
+
+PATH=$APPSTORE_HOME/bin:$PATH
+
+# TODO: this is probably a good place to clean up the environment
+exec env \
+ "APPSTORE_HOME=$APPSTORE_HOME" \
+ "echo_debug=$echo_debug" \
+ "$bin" "$@"
diff --git a/appstore.config b/appstore.config
deleted file mode 100644
index e69de29..0000000
--- a/appstore.config
+++ /dev/null
diff --git a/bin/appstore-init b/bin/appstore-init
new file mode 100755
index 0000000..cbbf0f7
--- /dev/null
+++ b/bin/appstore-init
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+set -e
+set -u
+
+APPSTORE_HOME=$(cd $(dirname "$0")/.. && pwd)
+
+. $APPSTORE_HOME/lib/common
+# HEADER END
+
+usage() {
+ echo "usage [server] [name]"
+ exit 1
+}
+
+if [ $# -ne 3 ]
+then
+ usage
+fi
+
+server=$1; shift
+repos=$1; shift
+name=$1; shift
+
+if [ -e "$name" ]
+then
+ echo "$name already exist!"
+ exit 1
+fi
+
+tmpfile=tmpfile$$
+conffile=conffile$$
+echo "Creating remote appstore..."
+set +e
+ssh "$server" "$APPSTORE_HOME/libexec/appstore-init-server" "$repos" "$name" > "$tmpfile" 2>&1
+ret=$?
+set -e
+
+sed -n "s,^config: \(.*\),\1,p" $tmpfile > $conffile
+repo_path=`app cat-conf -f "$conffile" -n repo.path | cut -f 2- -d =`
+repo_ok=`app cat-conf -f "$conffile" -n repo.ok | cut -f 2- -d =`
+
+if [ "$ret" != 0 ]
+then
+ echo "Initialization failed. Server output:"
+ cat $tmpfile
+ exit 1
+fi
+
+echo "Cloning repository..."
+git clone -q "$server:$repo_path" "$name"
+cd $name
+git remote rename origin cloud
+cd ..
+
+echo "$name is open for cloud business!"
+rm *$$
diff --git a/hooks/common b/hooks/common
deleted file mode 100755
index 7a693aa..0000000
--- a/hooks/common
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-
diff --git a/hooks/post-receive b/hooks/post-receive
new file mode 100755
index 0000000..ced1fc4
--- /dev/null
+++ b/hooks/post-receive
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+set -e
+set -u
+
+APPSTORE_HOME=$(cd $(dirname "$0")/.. && pwd)
+
+. $APPSTORE_HOME/lib/common
+# HEADER END
+
+# stdin contains the refs pushed.
+
+APPS="$(git config appstore.apps)"
+
+REPO="$(pwd)"
+
+cd "$APPS"
+
+unset GIT_DIR
+git pull -q "$REPO" master
+
+IFS=$'\t'
+csvtool -u TAB namedcol dir,resolver,resolver_args,version,state apps.csv | \
+while read dir resolver resolver_args version state
+do
+ if [ -d "$dir" ]
+ then
+ cd $dir
+ old_version=$(app conf get app.version)
+
+ if [[ $new_version == $old_version ]]
+ then
+ continue
+ fi
+
+ echo "Updating $dir to $version"
+ app conf set app.version "$version"
+ app update
+ cd ..
+ else
+ echo "New application: $dir"
+ app init -d "$dir" "$resolver" "$resolver_args"
+ fi
+
+ cd "$dir"
+ if [[ $state == enabled ]]
+ then
+ echo "Starting appliation"
+ app start
+ else
+ echo "Stopping appliation"
+ app stop
+ fi
+done
+unset IFS
diff --git a/lib/common b/lib/common
new file mode 100755
index 0000000..473c8b1
--- /dev/null
+++ b/lib/common
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Sanity check to make sure that app.sh is installed
+APPSH_HOME="`cd $APPSTORE_HOME/../app.sh; pwd`"
+
+if [ ! -d "$APPSH_HOME" ]
+then
+ echo "app.sh has to be installed at $APPSH_HOME"
+ exit 1
+fi
+
+PATH=$APPSH_HOME:$PATH
+
+show_help() {
+ message=${1-}
+
+ if [[ $message != "" ]]
+ then
+ echo $message
+ fi
+
+ if [ "`declare -f usage_text >/dev/null; echo $?`" = 0 ]
+ then
+ usage_text
+ else
+ echo "The command $usage_app does not have any usage info."
+ fi
+ exit 1
+}
+
+usage() {
+ message=${1-}
+
+ if [[ $message != "" ]]
+ then
+ echo $message >&2
+ fi
+
+ if [ "`declare -f usage_text >/dev/null; echo $?`" = 0 ]
+ then
+ usage_text >&2
+ fi
+ exit 1
+}
+
+debug() {
+ [[ $echo_debug == no ]] || echo "D: $usage_app: $@" 2>&1
+}
+
+info() {
+ echo "I: $usage_app: $@" 2>&1
+}
+
+fatal() {
+ echo "$usage_app: fatal: $@" 2>&1
+ exit 1
+}
+
+grep_path() {
+ local regex="$1"; shift
+ local path="$1"; shift
+
+ find `echo $path | tr : " "` -type f -executable 2>/dev/null | (egrep "$regex" || exit 0)
+}
diff --git a/hooks/post-commit b/lib/header
index 63508c2..ccd343e 100755..100644
--- a/hooks/post-commit
+++ b/lib/header
@@ -5,6 +5,4 @@ set -u
APPSTORE_HOME=$(cd $(dirname "$0")/.. && pwd)
-. $APPSTORE_HOME/hooks/common
-
-echo "post-commit!!"
+. $APPSTORE_HOME/lib/common
diff --git a/lib/header-hook b/lib/header-hook
new file mode 100644
index 0000000..ccd343e
--- /dev/null
+++ b/lib/header-hook
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+set -u
+
+APPSTORE_HOME=$(cd $(dirname "$0")/.. && pwd)
+
+. $APPSTORE_HOME/lib/common
diff --git a/libexec/appstore-init-server b/libexec/appstore-init-server
new file mode 100755
index 0000000..1417469
--- /dev/null
+++ b/libexec/appstore-init-server
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+set -e
+set -u
+
+APPSTORE_HOME=$(cd $(dirname "$0")/.. && pwd)
+
+. $APPSTORE_HOME/lib/common
+# HEADER END
+
+root=$1; shift
+name=$1; shift
+
+echo "Creating appstore $name"
+
+repo="$root/repos/$name"
+apps="$root/appstores/$name"
+
+if [ -e "$repo" ]
+then
+ echo "$name already exist!"
+ exit 1
+fi
+
+# Create the git repository
+git init -q --bare "$repo"
+
+# Clone the repository
+git init -q "$apps"
+cd "$apps"
+
+# Copy the template project
+cp -r "$APPSTORE_HOME/template/"* .
+git add -A
+git config user.name "Appstore Bot"
+git config user.email nobody@example.org
+git commit -q -m "Created new appstore: $name."
+git push -q "$repo" master
+cd ..
+
+# Install the hooks
+cd "$repo"
+pwd
+rm hooks/*
+rmdir hooks
+ln -s "$APPSTORE_HOME/hooks" hooks
+git config appstore.home "$APPSTORE_HOME"
+git config appstore.apps "$apps"
+
+echo "config: repo.path=$repo"
diff --git a/template/README.md b/template/README.md
new file mode 100644
index 0000000..e24090d
--- /dev/null
+++ b/template/README.md
@@ -0,0 +1 @@
+TODO: putt something useful here
diff --git a/template/apps.csv b/template/apps.csv
new file mode 100644
index 0000000..3637e0e
--- /dev/null
+++ b/template/apps.csv
@@ -0,0 +1 @@
+dir,resolver,resolver_args,version,state
diff --git a/test/data/my-webapp/root/app.js b/test/data/my-webapp/root/app.js
new file mode 100644
index 0000000..29298b3
--- /dev/null
+++ b/test/data/my-webapp/root/app.js
@@ -0,0 +1,37 @@
+var http = require("http"),
+ url = require("url"),
+ path = require("path"),
+ fs = require("fs")
+ port = process.env.PORT || 8888;
+
+http.createServer(function(request, response) {
+
+ var uri = url.parse(request.url).pathname
+ , filename = path.join(process.cwd(), uri);
+
+ path.exists(filename, function(exists) {
+ if(!exists) {
+ response.writeHead(404, {"Content-Type": "text/plain"});
+ response.write("404 Not Found\n");
+ response.end();
+ return;
+ }
+
+ if (fs.statSync(filename).isDirectory()) filename += '/index.html';
+
+ fs.readFile(filename, "binary", function(err, file) {
+ if(err) {
+ response.writeHead(500, {"Content-Type": "text/plain"});
+ response.write(err + "\n");
+ response.end();
+ return;
+ }
+
+ response.writeHead(200);
+ response.write(file, "binary");
+ response.end();
+ });
+ });
+}).listen(parseInt(port, 10));
+
+console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");
diff --git a/test/it.bats b/test/it.bats
new file mode 100644
index 0000000..d594049
--- /dev/null
+++ b/test/it.bats
@@ -0,0 +1,28 @@
+#!/usr/bin/env bats
+# vim: set filetype=sh:
+
+load utils
+
+@test "Happy day" {
+ mkzip my-webapp
+ install_artifact "my-webapp"
+ install_artifact "my-webapp" 1.0
+
+ cd $BATS_TMPDIR
+ cd appstore
+ mkdir -p client server
+ cd client
+
+ appstore init "localhost" "$BATS_TMPDIR/appstore/server" "mysetup"
+ cd mysetup
+
+ # Making assertions easier.
+ git config user.name "Test Case"
+ git config user.email tester@example.org
+
+ echo "app-1,maven,org.example:app-a:1.0-SNAPSHOT,1.0-SNAPSHOT,enabled" >> apps.csv
+ git commit -m "o Adding app-1." -a
+ git push cloud master
+ eq "ssh://localhost$BATS_TMPDIR/appstore/server/mysetup" `git config remote.cloud.url`
+ eq 1 2
+}
diff --git a/test/utils.bash b/test/utils.bash
new file mode 100644
index 0000000..cd6fcf0
--- /dev/null
+++ b/test/utils.bash
@@ -0,0 +1,176 @@
+#!/bin/bash
+
+workdir=test-run
+
+# TODO: assert that the exit code is 1 for 'usage' outputs.
+exit_usage=1
+exit_usage_wrong=0
+
+setup() {
+ ORIG_PATH=$PATH
+ APPSTORE_HOME=$(cd $BATS_TEST_DIRNAME/..; echo `pwd`)
+ PATH=/bin:/usr/bin
+ PATH=$PATH:$APPSTORE_HOME
+
+ rm -rf $BATS_TMPDIR/appstore
+ mkdir $BATS_TMPDIR/appstore
+
+ HOME=$BATS_TMPDIR/appstore-home
+
+ cd $BATS_TMPDIR/appstore
+
+ REPO=$BATS_TMPDIR/repo
+ REPO_URL="file://$REPO"
+ FIXED_REPO_URL="file://`fix_path $REPO`"
+
+ if [ "`declare -f setup_inner >/dev/null; echo $?`" = 0 ]
+ then
+ setup_inner
+ fi
+}
+
+echo_lines() {
+ echo lines:
+ for line in "${lines[@]}"; do echo $line; done
+ echo status=$status
+}
+
+mkzip() {
+(
+ cd $BATS_TEST_DIRNAME/data/$1
+ rm -f ../$1.zip
+ zip -qr ../$1.zip *
+)
+}
+
+install_artifact() {
+ local artifactId=${1}; shift
+ local version=${1-1.0-SNAPSHOT}
+ describe -Dfile=`fix_path $APPSTORE_HOME/test/data/$artifactId.zip` -DgeneratePom
+ PATH=$ORIG_PATH mvn deploy:deploy-file -Durl=$FIXED_REPO_URL \
+ -Dfile=`fix_path $APPSTORE_HOME/test/data/$artifactId.zip` -DgeneratePom \
+ -DgroupId=org.example -DartifactId=$artifactId -Dversion=$version -Dpackaging=zip
+}
+
+check_status=yes
+
+app() {
+ echo app $@
+ run $APPSTORE_HOME/app $@
+ echo_lines
+
+ if [ "$check_status" = yes ]
+ then
+ eq '$status' 0
+ fi
+
+ check_status=yes
+}
+
+app_libexec() {
+ local x=`PATH=$APPSTORE_HOME/libexec:/bin:/usr/bin which $1`
+
+ echo libexec/$@
+ shift
+ run "$x" $@
+
+ echo_lines
+
+ if [ "$check_status" = yes ]
+ then
+ eq '$status' 0
+ fi
+
+ check_status=yes
+}
+
+fix_path_uname=`uname -s`
+fix_path() {
+ case $fix_path_uname in
+ CYGWIN_NT*)
+ cygpath -wa $1
+ ;;
+ *)
+ echo $1
+ ;;
+ esac
+}
+
+describe() {
+ echo "# " $@ >&3
+}
+
+can_read() {
+ if [ -r "$1" ]
+ then
+ return 0
+ else
+ echo "Can't read $1"
+ return 1
+ fi
+}
+
+can_not_read() {
+ if [ ! -r "$1" ]
+ then
+ return 0
+ else
+ echo "Can read $1"
+ return 1
+ fi
+}
+
+is_directory() {
+ if [ ! -d "$1" ]
+ then
+ echo "Not a directory: $1" 2>&1
+ return 1
+ fi
+}
+
+eq() {
+ local ex="$1"
+ local e="$2"
+ local a="`eval echo $ex`"
+
+ if [[ $e == $a ]]
+ then
+ return 0
+ fi
+
+ echo "Assertion failed: $ex"
+ echo "Expected: $e"
+ echo "Actual: $a"
+ exit 1
+}
+
+neq() {
+ local ex="$1"
+ local e="$2"
+ local a="`eval echo $ex`"
+
+ if [[ $e != $a ]]
+ then
+ return 0
+ fi
+
+ echo "Not-equal assertion failed: $ex"
+ echo "Expected: $e"
+ echo "Actual: $a"
+ exit 1
+}
+
+match() {
+ local ex="$1"
+ local regex="$2"
+ local a="`eval echo $ex`"
+
+ if [[ $a =~ $regex ]]
+ then
+ return 0
+ fi
+
+ echo "Match failed: $ex =~ $regex"
+ echo "Value: $a"
+ exit 1
+}