From 1480338c5a3da5b6494565ab955ab67a15f19dd3 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 31 Oct 2013 21:52:24 +0100 Subject: app-init: Adding '-s' option to set a configuration option before the resolver is executed and app is installed. The configuration will be available when the app's hooks are executed. o Running the documentation though aspell. --- .gitignore | 1 + bin/app-init | 25 ++- docs/Makefile | 7 +- docs/app-cat-conf.txt | 19 +- docs/app-init.txt | 58 +++++ docs/app-install-file.txt | 2 +- docs/app.txt | 35 +-- docs/appsh.dict | 1 + test/app-init.bats | 42 ++-- test/utils.bash | 11 +- ...g-platforms-where-xmlstarlet-is-installed.patch | 62 ++++++ ...2-o-Supporting-older-versions-of-asciidoc.patch | 115 ++++++++++ ...r-maven-Adding-support-for-artifacts-with.patch | 133 +++++++++++ ...Changing-run_app-to-not-check-for-a-curre.patch | 53 +++++ ...rade-Removing-unreachable-code.-Fixing-it.patch | 248 +++++++++++++++++++++ 15 files changed, 764 insertions(+), 48 deletions(-) create mode 100644 docs/app-init.txt create mode 100644 docs/appsh.dict create mode 100644 tmp/0001-o-Supporting-platforms-where-xmlstarlet-is-installed.patch create mode 100644 tmp/0002-o-Supporting-older-versions-of-asciidoc.patch create mode 100644 tmp/0003-app-resolver-maven-Adding-support-for-artifacts-with.patch create mode 100644 tmp/0004-lib-common-Changing-run_app-to-not-check-for-a-curre.patch create mode 100644 tmp/0005-bin-app-upgrade-Removing-unreachable-code.-Fixing-it.patch diff --git a/.gitignore b/.gitignore index 4acb46e..e420583 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ docs/*.xml docs/*.html docs/*.1 docs/*.7 +docs/*.txt.bak .app/var /*/.gitignore diff --git a/bin/app-init b/bin/app-init index bc4a0b2..bff92cf 100755 --- a/bin/app-init +++ b/bin/app-init @@ -9,13 +9,15 @@ export APPSH_HOME=$(cd $(dirname "$0")/.. && pwd) # HEADER END usage_text() { - echo "usage: $usage_app -d dir " + echo "usage: $usage_app [-s group.name=value] -d dir " } dir= prepend_config= append_config= -while getopts "d:C:c:" opt +declare -A conf +conf=() +while getopts "d:C:c:s:" opt do case $opt in d) @@ -41,6 +43,19 @@ do shift 2 OPTIND=1 ;; + s) + keyvalue=$OPTARG + re="^$key_expr\\.$key_expr=.*$" + if [[ ! $keyvalue =~ $re ]] + then + usage "Invalid -s argument." + fi + key="${keyvalue%%=*}" + value="${keyvalue#*=}" + conf[$key]="$value" + shift 2 + OPTIND=1 + ;; esac done @@ -77,6 +92,12 @@ trap '[[ $ok == yes ]] || rm -rf "$clean_dir"' EXIT cd "$dir" +for key in "${!conf[@]}" +do + app-conf set $key "${conf[$key]}" +done +unset IFS + app-conf set app.resolver "$resolver_name" "$resolver" init "$@" diff --git a/docs/Makefile b/docs/Makefile index 355f0bc..9ad7712 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,12 +2,12 @@ TXT=$(wildcard *.txt) # Expand target section from heading of each page MAN=$(shell ls *.txt|xargs -n 1 head -n 1|sed "s,\(.*\)(\([0-9]\)),\1.\2,") HTML=$(patsubst %.txt,%.html,$(TXT)) +ASPELL=aspell all: html man html: $(HTML) man: $(MAN) - .PHONY: html man %.html: %.txt @@ -25,5 +25,10 @@ define man @a2x --format manpage $(1) endef +spell: $(patsubst %,spell-%,$(TXT)) +.PHONY: spell +spell-%: + $(ASPELL) check -p appsh.dict -l en --encoding utf-8 $(patsubst spell-%,%,$@) + clean: rm -rf $(wildcard *.html) $(wildcard *.1) $(wildcard *.7) diff --git a/docs/app-cat-conf.txt b/docs/app-cat-conf.txt index 57fe693..3b5501c 100644 --- a/docs/app-cat-conf.txt +++ b/docs/app-cat-conf.txt @@ -3,7 +3,7 @@ app-cat-conf(1) NAME ---- -app-cat-conf - outputs a combined configuration file in a parseable +app-cat-conf - outputs a combined configuration file in a parsable format SYNOPSIS @@ -19,14 +19,14 @@ output a key once, the last value for each key seen will win. A configuration file is a collection of grouped keys and values, similar to Git. -The keys consits of two parts: a _group_ and a _name_. Both have to +The keys consist of two parts: a _group_ and a _name_. Both have to match the regex `[a-zA-Z0-9]` and are combined with a dot. OPTIONS ------- -f:: - The config file to use. If the value is '-', stdin will be used as - input. The option can be given multiple times. + The configuration file to use. If the value is '-', stdin will be + used as input. The option can be given multiple times. -D:: Disables the inclusion of the default files. -k:: @@ -37,9 +37,10 @@ OPTIONS LOCATIONS AND DEFAULT FILES --------------------------- -'app-cat-conf' will by default look for configuration files in three places: +'app-cat-conf' will by default look for configuration files in three +places: -* '$APPSH_HOME/lib/default-config' +* '$APPSH_HOME/lib/default-configuration' * '$HOME/.appconfig' @@ -60,13 +61,13 @@ Support _default values_: when a key is missing, return the default value instead. Suggested option: '-d'. + Support _$APP_HOME_: If '$APP_HOME' is set, use that when reading the -app's config values. Makes it easier to script as the user may move -around directories, but still read values from the right place. +app's configuration values. Makes it easier to script as the user may +move around directories, but still read values from the right place. SEE ALSO -------- -git-config(1) +git-configuration(1) APP.SH ------ diff --git a/docs/app-init.txt b/docs/app-init.txt new file mode 100644 index 0000000..58b7a7c --- /dev/null +++ b/docs/app-init.txt @@ -0,0 +1,58 @@ +app-init(1) +=========== + +NAME +---- +app-init - Installs an application + +SYNOPSIS +-------- +[verse] +'app-init' [-s group.name=key ...] -d + +DESCRIPTION +----------- + +Similar to 'git clone', 'app-init' is the first command you use when +you want to deploy an application. It performs the following tasks: + +1. Create the '.app' directory and the config file. +2. Initialize the resolver +3. Run 'app upgrade' to install the initial version. 'app upgrade' + will also run any hooks defined in the application. + +OPTIONS +------- + +-d:: + The directory to create the application in. If the initialization + fails, the directory will be removed. +-s group.name=key:: + Add a configuration parameter before the resolver and any hooks are + fired. ++ +This option can be given multiple times. +:: + The name of the resolver to use. 'app-init' will search the path for + an executable called 'app-resolver-'. +:: + A list of arguments passed on directly to the resolver. See the + documentation of the resolver you're using for more details. + +BUILT-IN RESOLVERS +------------------ + +Appsh comes with two built-it resolvers: + +maven:: + See linkman:app-resolver-maven[1]. +file:: + See linkman:app-resolver-file[1]. + +APP.SH +------ + +Part of the linkman:app[1] suite. + +// vim: set ft=asciidoc: + diff --git a/docs/app-install-file.txt b/docs/app-install-file.txt index bb7cc48..e7525d1 100644 --- a/docs/app-install-file.txt +++ b/docs/app-install-file.txt @@ -8,7 +8,7 @@ app-install-file - Low-level installation of an app SYNOPSIS -------- [verse] -'app-operator-pid' ... +'app-install-file' ... TODOs ----- diff --git a/docs/app.txt b/docs/app.txt index 9e9afc0..38cf169 100644 --- a/docs/app.txt +++ b/docs/app.txt @@ -26,7 +26,7 @@ $ app restart --------------------------------------------------------------------- appsh is a pragmatic approach to managing a set of apps on a server. -It is heavily inspired by git's approach in its command line interface +It is heavily inspired by Git's approach in its command line interface and scriptability. It handles installation aspects: downloading, unpacking and upgrading, @@ -38,7 +38,7 @@ command line, or through your own extensions. Requirements ^^^^^^^^^^^^ -* Linux. OSX and Cygwin are possible to support, but it's not tested +* Linux. OS X and Cygwin are possible to support, but it's not tested there yet. Solaris is also doable. * Bash 4 and "standard" GNU userland. * If using Maven: xmlstarlet @@ -46,7 +46,7 @@ Requirements INSTALLING AN APPLICATION ~~~~~~~~~~~~~~~~~~~~~~~~~ -This resolved and downloads an appliaction from a Maven repository: +This resolved and downloads an application from a Maven repository: --------------------------------------------------------------------- $ app init -d my-app maven org.example:my-app:1.0-SNAPSHOT @@ -89,13 +89,13 @@ and if that has changed, it will download and install the new version. CREATING APPS ------------- -An "app" is in itself nothing more than a zip archive with a particular -layout. In the root of the zip archive there must be a directory called -`root`. You can also place a file called `app.config` at the root. The -config file will be imported into the app's configuration. It is also -possible to run appliations before and after appliations are installed -through hooks. These are placed in a `hooks` directory, also at the -root of the archive. +An "app" is in itself nothing more than a zip archive with a +particular layout. In the root of the zip archive there must be a +directory called `root`. You can also place a file called `app.config` +at the root. The configuration file will be imported into the app's +configuration. It is also possible to run applications before and +after applications are installed through hooks. These are placed in a +`hooks` directory, also at the root of the archive. To summarize, this is what an application zip archive looks like: @@ -125,18 +125,18 @@ CREATING LAUNCHERS Trick when you don't know why your app won't start: --------------------------------------------------------------------- -exec 1>/tmp/myapp.out -exec 2>/tmp/myapp.err +exec 1>/tmp/my-app.out +exec 2>/tmp/my-app.err --------------------------------------------------------------------- Make sure you _always_ use `exec` when spawning the actual app. This -makes sure that the pid operator records the correct PID. If you don't +makes sure that the PID operator records the correct PID. If you don't do this the application will run, but will be reported as crashed when you run 'app status'. -If you can't use `exec` or the application demands to deamonize itself +If you can't use `exec` or the application demands to demonize itself (like Apache Httpd), you have to set the configuration option -`app.pid_management=launcher`. Then the launcher is responsible for +`app.PID_management=launcher`. Then the launcher is responsible for creating the PID file under $APP_HOME/.app/pid. You can create a symlink to the actual PID file if you can't customize where the app places the file. @@ -160,7 +160,8 @@ SEE ALSO linkman:app-cat-conf[1], linkman:app-conf[1], linkman:app-install-file[1], -linkman:app-operator-pid[1], -linkman:appinternals[1] +linkman:app-init[1], +linkman:app-operator-PID[1], +linkman:appinternals[7] // vim: set ft=asciidoc: diff --git a/docs/appsh.dict b/docs/appsh.dict new file mode 100644 index 0000000..aef5c87 --- /dev/null +++ b/docs/appsh.dict @@ -0,0 +1 @@ +personal_repl-1.1 en 0 diff --git a/test/app-init.bats b/test/app-init.bats index 8ffe1b6..2b5d724 100755 --- a/test/app-init.bats +++ b/test/app-init.bats @@ -3,20 +3,22 @@ load utils -#@test "Invalid resolver" { -# app init -d my-app wat; echo_lines -# eq '$status' 1 -# eq '${#lines[*]}' 1 -# eq '${lines[0]}' "No such resolver: wat" -#} +@test "Invalid resolver" { + check_status=no + app init -d my-app wat + eq '$status' 1 + eq '${#lines[*]}' 1 + eq '${lines[0]}' "No such resolver: wat" +} -#@test "Already installed" { -# mkdir -p my-app/.apps -# app init -d my-app maven; echo_lines -# eq '$status' 1 -# eq '${#lines[*]}' 1 -# match '${lines[0]}' "my-app" -#} +@test "Already installed" { + mkdir -p my-app/.app + check_status=no + app init -d my-app maven + eq '$status' 1 + eq '${#lines[*]}' 1 + match '${lines[0]}' "my-app" +} @test "Happy day" { mkzip app-a @@ -74,3 +76,17 @@ load utils match '${lines[0]}' ".*/versions/1.0/root$" eq '${#lines[*]}' 1 } + +@test "app-init: Can pass configuration variables" { + mkzip app-a + app init -d my-app \ + -s "foo.bar=awesome" \ + -s "foo.baz=i love space" \ + -s "foo.wat=2+2=5" file $APPSH_HOME/test/data/app-a.zip + cd my-app + app cat-conf -g foo + match '${lines[0]}' "foo.bar=awesome" + match '${lines[1]}' "foo.baz=i love space" + match '${lines[2]}' "foo.wat=2\+2=5" + eq '${#lines[*]}' 3 +} diff --git a/test/utils.bash b/test/utils.bash index 9979404..930b0f0 100644 --- a/test/utils.bash +++ b/test/utils.bash @@ -39,11 +39,12 @@ echo_lines() { } mkzip() { -( - cd $BATS_TEST_DIRNAME/data/$1 - rm -f ../$1.zip - zip -qr ../$1.zip * -) + local name=$1; shift + pushd . + cd $BATS_TEST_DIRNAME/data/$name + rm -f ../$name.zip + zip -qr ../$name.zip * + popd } install_artifact() { diff --git a/tmp/0001-o-Supporting-platforms-where-xmlstarlet-is-installed.patch b/tmp/0001-o-Supporting-platforms-where-xmlstarlet-is-installed.patch new file mode 100644 index 0000000..dc82a70 --- /dev/null +++ b/tmp/0001-o-Supporting-platforms-where-xmlstarlet-is-installed.patch @@ -0,0 +1,62 @@ +From ed52962997364560d341e0197c20a616e9b0f03e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= +Date: Wed, 30 Oct 2013 14:29:06 +0100 +Subject: [PATCH 1/5] o Supporting platforms where 'xmlstarlet' is installed as + 'xml' (At least Suse does that). + +--- + libexec/app-resolver-maven | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/libexec/app-resolver-maven b/libexec/app-resolver-maven +index 419adcc..ec1ad6b 100755 +--- a/libexec/app-resolver-maven ++++ b/libexec/app-resolver-maven +@@ -81,6 +81,44 @@ download_artifact() { + fi + } + ++ ++which() { ++ /usr/bin/which "$1" 2>/dev/null ++} ++ ++# Wrapper to cache the lookup of the xmlstarlet command. ++# Remember that xmlstarlet on at least SLES requires single quotes ++# instead of double quotes when building the selector, e.g.: ++# use [text()='zip'] instead of [text()="zip"]. ++ ++_xmlstarlet="" ++xmlstarlet() { ++ if [ ! -z "$_xmlstarlet" ] ++ then ++ "$_xmlstarlet" "$@" ++ return ++ fi ++ ++ _xmlstarlet="`which xmlstarlet`" ++ ++ if [ ! -z "$_xmlstarlet" ] ++ then ++ "$_xmlstarlet" "$@" ++ return ++ fi ++ ++ _xmlstarlet="`which xml`" ++ ++ if [ ! -z "$_xmlstarlet" ] ++ then ++ "$_xmlstarlet" "$@" ++ return ++ fi ++ ++ echo "Could not find xmlstarlet." >&2 ++ exit 1 ++} ++ + resolve_version() { + local group_id=`app-conf get maven.group_id` + local artifact_id=`app-conf get maven.artifact_id` +-- +1.8.4.rc3 + diff --git a/tmp/0002-o-Supporting-older-versions-of-asciidoc.patch b/tmp/0002-o-Supporting-older-versions-of-asciidoc.patch new file mode 100644 index 0000000..f9869dd --- /dev/null +++ b/tmp/0002-o-Supporting-older-versions-of-asciidoc.patch @@ -0,0 +1,115 @@ +From c106046cbb0cdb590035fcd33f5fc6ce1a3b975c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= +Date: Thu, 31 Oct 2013 14:30:13 +0100 +Subject: [PATCH 2/5] o Supporting older versions of asciidoc. + +--- + .gitignore | 1 + + docs/Makefile | 9 +++++++-- + docs/appinternals.txt | 4 ++++ + docs/asciidoc.conf | 35 +++++++++++++++++++++++++++++++++++ + 4 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/.gitignore b/.gitignore +index b6d1d32..4acb46e 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1,6 +1,7 @@ + apps.list + downloads + target ++docs/*.xml + docs/*.html + docs/*.1 + docs/*.7 +diff --git a/docs/Makefile b/docs/Makefile +index f340323..355f0bc 100644 +--- a/docs/Makefile ++++ b/docs/Makefile +@@ -3,11 +3,16 @@ TXT=$(wildcard *.txt) + MAN=$(shell ls *.txt|xargs -n 1 head -n 1|sed "s,\(.*\)(\([0-9]\)),\1.\2,") + HTML=$(patsubst %.txt,%.html,$(TXT)) + +-all: $(HTML) $(MAN) ++all: html man ++ ++html: $(HTML) ++man: $(MAN) ++ ++.PHONY: html man + + %.html: %.txt + @echo asciidoc $< +- @asciidoc -f asciidoc.conf --backend=html5 $< ++ @asciidoc -f asciidoc.conf --backend=xhtml11 -aappsh_version=0.2-dev $< + + %.1: %.txt + $(call man,$<) +diff --git a/docs/appinternals.txt b/docs/appinternals.txt +index ce19923..330d151 100644 +--- a/docs/appinternals.txt ++++ b/docs/appinternals.txt +@@ -5,6 +5,10 @@ NAME + ---- + appinternals - Appsh internals + ++SYNOPSIS ++-------- ++appinternals ++ + DESCRIPTION + ----------- + +diff --git a/docs/asciidoc.conf b/docs/asciidoc.conf +index 724524a..57eaf59 100644 +--- a/docs/asciidoc.conf ++++ b/docs/asciidoc.conf +@@ -1,6 +1,31 @@ ++# https://github.com/marcelocantos/zeromq2-1/blob/master/doc/asciidoc.conf ++# http://lxr.free-electrons.com/source/tools/perf/Documentation/asciidoc.conf ++ + [macros] + (?su)[\\]?(?Plinkman):(?P\S*?)\[(?P.*?)\]= + ++ifdef::doctype-manpage[] ++ifdef::backend-docbook[] ++[header] ++template::[header-declarations] ++ ++ ++ {mantitle} ++ {manvolnum} ++ app.sh ++ ++ App.sh Manual ++ ++ ++ {manname} ++ {manpurpose} ++ ++# No ending refentry, asciidoc takes care of that. ++endif::backend-docbook[] ++endif::doctype-manpage[] ++ + ifdef::backend-docbook[] + [linkman-inlinemacro] + {0%{target}} +@@ -18,3 +43,13 @@ relative-ext=.html + {target}{0?({0})} + + endif::backend-html5[] ++ ++ifdef::backend-xhtml11[] ++ ++[attributes] ++relative-ext=.html ++ ++[linkman-inlinemacro] ++{target}{0?({0})} ++ ++endif::backend-xhtml11[] +-- +1.8.4.rc3 + diff --git a/tmp/0003-app-resolver-maven-Adding-support-for-artifacts-with.patch b/tmp/0003-app-resolver-maven-Adding-support-for-artifacts-with.patch new file mode 100644 index 0000000..2b7933f --- /dev/null +++ b/tmp/0003-app-resolver-maven-Adding-support-for-artifacts-with.patch @@ -0,0 +1,133 @@ +From 746b90ad64e65b70bc902ed1bcd2c33ec7adf008 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= +Date: Thu, 31 Oct 2013 16:27:09 +0100 +Subject: [PATCH 3/5] app-resolver-maven: Adding support for artifacts with + classifier. + +--- + libexec/app-resolver-maven | 43 +++++++++++++++++++++++++++++++++---------- + test/app-resolver-maven.bats | 27 +++++++++++++++++++++++++++ + 2 files changed, 60 insertions(+), 10 deletions(-) + create mode 100755 test/app-resolver-maven.bats + +diff --git a/libexec/app-resolver-maven b/libexec/app-resolver-maven +index ec1ad6b..4e21c4b 100755 +--- a/libexec/app-resolver-maven ++++ b/libexec/app-resolver-maven +@@ -12,6 +12,8 @@ usage_text() { + echo "usage: $usage_app init -r " + echo "usage: $usage_app resolve-version" + echo "usage: $usage_app download-version -v -f " ++ echo "Maven url can be one of: :: and" ++ echo ":::" + } + + slash() { +@@ -122,6 +124,7 @@ xmlstarlet() { + resolve_version() { + local group_id=`app-conf get maven.group_id` + local artifact_id=`app-conf get maven.artifact_id` ++ local classifier=`app-conf get app.classifier` + local version=`app-conf get app.version` + + repo=`app-conf get maven.repo` +@@ -199,15 +202,17 @@ download_version() { + repo=`app-conf get maven.repo` + group_id=`app-conf get maven.group_id` + artifact_id=`app-conf get maven.artifact_id` ++ classifier=`app-conf get maven.classifier` + version=`app-conf get app.version` + + group_id_slash=`slash $group_id` + base_path=$group_id_slash/$artifact_id/$version ++ file_name=$artifact_id-$resolved_version${classifier:+-}$classifier.zip + + mkdir -p .app/cache/$base_path + +- l=.app/cache/$base_path/$artifact_id-$resolved_version.zip +- r=$repo/$base_path/$artifact_id-$resolved_version.zip ++ l=.app/cache/$base_path/$file_name ++ r=$repo/$base_path/$file_name + + echo "Downloading $group_id:$artifact_id:$resolved_version..." + get $r $l +@@ -236,17 +241,35 @@ init() { + x=${x//:/ } + set -- $x + +- if [[ $# != 3 || $1 == "" || $2 == "" || $3 == "" ]] +- then +- usage "Invalid Maven coordinates: $coordinates" +- fi +- +- group_id=$1 +- artifact_id=$2 +- version=$3 ++ case $# in ++ 3) ++ if [[ $1 == "" || $2 == "" || $3 == "" ]] ++ then ++ usage "Invalid Maven coordinates: $coordinates" ++ fi ++ group_id=$1; shift ++ artifact_id=$1; shift ++ classifier= ++ version=$1; shift ++ ;; ++ 4) ++ if [[ $1 == "" || $2 == "" || $3 == "" || $4 == "" ]] ++ then ++ usage "Invalid Maven coordinates: $coordinates" ++ fi ++ group_id=$1; shift ++ artifact_id=$1; shift ++ classifier=$1; shift ++ version=$1; shift ++ ;; ++ *) ++ usage "Invalid Maven coordinates: $coordinates" ++ ;; ++ esac + + app-conf set maven.group_id "$group_id" + app-conf set maven.artifact_id "$artifact_id" ++ [[ ! -z $classifier ]] && app-conf set maven.classifier "$classifier" + app-conf set app.version "$version" + } + +diff --git a/test/app-resolver-maven.bats b/test/app-resolver-maven.bats +new file mode 100755 +index 0000000..e5a5474 +--- /dev/null ++++ b/test/app-resolver-maven.bats +@@ -0,0 +1,27 @@ ++#!/usr/bin/env bats ++# vim: set filetype=sh: ++ ++load utils ++ ++@test "plain init" { ++ mkdir .app ++ app resolver-maven init my-group:my-artifact:1.0-SNAPSHOT ++ app cat-conf ++ eq '${lines[0]}' "app.version=1.0-SNAPSHOT" ++ eq '${lines[1]}' "maven.artifact_id=my-artifact" ++ eq '${lines[2]}' "maven.group_id=my-group" ++ eq '${lines[3]}' "maven.repo=http://repo1.maven.org" ++ eq '${#lines[*]}' 4 ++} ++ ++@test "init with classifier" { ++ mkdir .app ++ app resolver-maven init my-group:my-artifact:app:1.0-SNAPSHOT ++ app cat-conf ++ eq '${lines[0]}' "app.version=1.0-SNAPSHOT" ++ eq '${lines[1]}' "maven.artifact_id=my-artifact" ++ eq '${lines[2]}' "maven.classifier=app" ++ eq '${lines[3]}' "maven.group_id=my-group" ++ eq '${lines[4]}' "maven.repo=http://repo1.maven.org" ++ eq '${#lines[*]}' 5 ++} +-- +1.8.4.rc3 + diff --git a/tmp/0004-lib-common-Changing-run_app-to-not-check-for-a-curre.patch b/tmp/0004-lib-common-Changing-run_app-to-not-check-for-a-curre.patch new file mode 100644 index 0000000..48e23de --- /dev/null +++ b/tmp/0004-lib-common-Changing-run_app-to-not-check-for-a-curre.patch @@ -0,0 +1,53 @@ +From 90bc5af891b745f97196310f2bc4afd081daac3e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= +Date: Fri, 1 Nov 2013 15:48:58 +0100 +Subject: [PATCH 4/5] lib/common: Changing run_app to not check for a 'current' + link if version is given. This will unbreak hooks that are run before a + current link is installed or if it has been removed. + +--- + lib/common | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/lib/common b/lib/common +index 369f0be..c2babd2 100755 +--- a/lib/common ++++ b/lib/common +@@ -2,6 +2,7 @@ + + # Asserts that the cwd is an app directory. + # By default it checks that there is a 'current' link. ++# TODO: make check_link default to no if version is set + assert_is_app() { + local check_link=yes + local version= +@@ -241,8 +242,8 @@ run_app() { + case $opt in + v) + version=$OPTARG +- shift 2 +- OPTIND=1 ++ shift 2 ++ OPTIND=1 + ;; + esac + done +@@ -258,13 +259,13 @@ run_app() { + assert_is_app + cd current + else +- assert_is_app -v "$version" ++ assert_is_app -C -v "$version" + cd "versions/$version" + fi + + path=/bin:/usr/bin + +- # This magically get the expansion of $u correct. ++ # This will magically get the expansion of $u correct. + IFS=" + " + +-- +1.8.4.rc3 + diff --git a/tmp/0005-bin-app-upgrade-Removing-unreachable-code.-Fixing-it.patch b/tmp/0005-bin-app-upgrade-Removing-unreachable-code.-Fixing-it.patch new file mode 100644 index 0000000..0123feb --- /dev/null +++ b/tmp/0005-bin-app-upgrade-Removing-unreachable-code.-Fixing-it.patch @@ -0,0 +1,248 @@ +From 274b7d15a82351dfee32be32bade4e35246d5beb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Trygve=20Laugst=C3=B8l?= +Date: Fri, 1 Nov 2013 16:24:26 +0100 +Subject: [PATCH 5/5] bin/app-upgrade: Removing unreachable code. Fixing it so + it compares against the currently installed version instead of the last + resolved version which makes it possible to retry installation of the same + version. libexec/app-install-file: Allowing installation of the same file + twice. Checks if the file has been unpacked earlier or not. Removes the + unpacked version on failure. + +--- + bin/app-upgrade | 36 +++++++++++++++--------------------- + libexec/app-install-file | 30 +++++++++++++++++++----------- + libexec/app-resolver-file | 2 +- + test/app-init.bats | 14 ++++++++------ + test/app-upgrade.bats | 30 ++++++++++++++++++++++++++++++ + test/data/app-a/hooks/post-install | 8 +++++++- + test/data/app-a/hooks/pre-install | 11 +++++++++++ + 7 files changed, 91 insertions(+), 40 deletions(-) + create mode 100755 test/data/app-a/hooks/pre-install + +diff --git a/bin/app-upgrade b/bin/app-upgrade +index 1a8329a..db40f4e 100755 +--- a/bin/app-upgrade ++++ b/bin/app-upgrade +@@ -19,40 +19,34 @@ fi + + assert_is_app + ++version=`app-conf get app.version` ++installed_version=`app-conf get app.installed_version` ++ ++# TODO: should this explicitly check for a discrepancy between ++# resolved_version and installed_version? This indicates an app that's ++# not completely installed. ++ ++# Find the resolver and resolve the version + resolver_name=`app-conf get app.resolver` + resolver=`find_resolver "$resolver_name"` + +-old_version=`app-conf get app.resolved_version` +-echo "Resolving version $old_version" ++echo "Resolving version $version" + "$resolver" resolve-version +-new_version=`app-conf get app.resolved_version` ++resolved_version=`app-conf get app.resolved_version` + +-if [[ $new_version == $old_version ]] ++if [[ $resolved_version == $installed_version ]] + then + echo "No new version available" 2>&1 + exit + fi + +-echo "Resolved version to $new_version" +- +-if [ "$new_version" = "" ] +-then +- new_version=`app-conf get app.resolved_version` +-fi +- +-if [ "$new_version" = "" ] ++if [ "$resolved_version" = "" ] + then + fatal "app.resolved_version is not set." + fi + +-installed_version=`app-conf get app.installed_version` +- +-if [ "$new_version" = "$installed_version" ] +-then +- echo "$new_version is already installed" +- exit 0 +-fi ++echo "Resolved version to $resolved_version" + +-"$resolver" download-version -v "$new_version" -f .app/latest.zip ++"$resolver" download-version -v "$resolved_version" -f .app/latest.zip + +-app-install-file -v "$new_version" -f .app/latest.zip ++app-install-file -v "$resolved_version" -f .app/latest.zip +diff --git a/libexec/app-install-file b/libexec/app-install-file +index c31f1f4..32b0407 100755 +--- a/libexec/app-install-file ++++ b/libexec/app-install-file +@@ -48,21 +48,29 @@ then + usage + fi + +-if [ -d versions/$version ] ++re="[.a-zA-Z0-9]" ++ ++if [[ ! $version =~ $re ]] + then +- echo "Version $version is already installed" +- exit 1 ++ fatal "Invalid version: $version" + fi + +-mkdir -p versions/$version +- +-echo "Unpacking..." +-unzip -q -d versions/$version $file +- +-if [ ! -d versions/$version/root ] ++if [ -d versions/$version ] + then +- echo "Invalid zip file, did not contain a ./root directory." >&2 +- exit 1 ++ echo "Version $version is already unpacked" ++else ++ mkdir -p versions/$version.tmp ++ ++ echo "Unpacking..." ++ unzip -q -d versions/$version.tmp $file ++ ++ if [ ! -d versions/$version.tmp/root ] ++ then ++ echo "Invalid zip file, did not contain a 'root' directory." >&2 ++ rm -rf versions/$version.tmp ++ exit 1 ++ fi ++ mv versions/$version.tmp versions/$version + fi + + if [ -n "$prepend_config" ] +diff --git a/libexec/app-resolver-file b/libexec/app-resolver-file +index 2b708e8..5972926 100755 +--- a/libexec/app-resolver-file ++++ b/libexec/app-resolver-file +@@ -47,7 +47,7 @@ init() { + resolve_version() { + path=$(app-conf get file.path) + +- local s=$(stat -c %Z $path) ++ local s=$(stat -c %Y $path) + + app-conf set app.resolved_version "$s" + } +diff --git a/test/app-init.bats b/test/app-init.bats +index 8ffe1b6..e4dfeae 100755 +--- a/test/app-init.bats ++++ b/test/app-init.bats +@@ -29,9 +29,10 @@ load utils + match '${lines[2]}' "Downloading org.example:app-a:1.0-*" + eq '${lines[3]}' "Unpacking..." + match '${lines[4]}' "Importing config from versions/1.0-*" +- match '${lines[5]}' "Creating current symlink for version 1.0-*" +- eq '${lines[6]}' "Post install" +- eq '${#lines[*]}' 7 ++ eq '${lines[5]}' "pre-install" ++ match '${lines[6]}' "Creating current symlink for version 1.0-*" ++ eq '${lines[7]}' "post-install" ++ eq '${#lines[*]}' 8 + + is_directory "my-app/.app" + # Created by post-install +@@ -48,9 +49,10 @@ load utils + match '${lines[1]}' "Downloading org.example:app-a:1.0-*" + eq '${lines[2]}' "Unpacking..." + match '${lines[3]}' "Importing config from versions/1.0-*" +- match '${lines[4]}' "Creating current symlink for version 1.0-*" +- eq '${lines[5]}' "Post install" +- eq '${#lines[*]}' 6 ++ eq '${lines[4]}' "pre-install" ++ match '${lines[5]}' "Creating current symlink for version 1.0-*" ++ eq '${lines[6]}' "post-install" ++ eq '${#lines[*]}' 7 + + is_directory "my-app/.app" + # Created by post-install +diff --git a/test/app-upgrade.bats b/test/app-upgrade.bats +index d27c6e7..9a282e3 100755 +--- a/test/app-upgrade.bats ++++ b/test/app-upgrade.bats +@@ -38,3 +38,33 @@ load utils + describe new_resolved_version = $new_resolved_version + neq $new_resolved_version $resolved_version + } ++ ++@test "app-upgrade - when pre-install fails the first run" { ++ mkzip app-a ++ file=$APPSH_HOME/test/data/app-a.zip ++ touch -t 01010101 $file ++ ++ app init -d my-app file $file ++ ++ cd my-app ++ ++ # A new version is available, but make sure pre-install fails. ++ touch -t 02020202 $file ++ touch fail-pre-install ++ check_status=no ++ app upgrade ++ eq '${status}' 1 ++ ++ # Try to reinstall the same file ++ rm fail-pre-install ++ app upgrade ++ eq '${lines[0]}' "Resolving version " ++ eq '${lines[1]}' "Resolved version to 1359766920" ++ eq '${lines[2]}' "Version 1359766920 is already unpacked" ++ eq '${lines[3]}' "Importing config from versions/1359766920/app.config" ++ eq '${lines[4]}' "pre-install" ++ eq '${lines[5]}' "Changing current symlink from 1356998460 to 1359766920" ++ eq '${lines[6]}' "post-install" ++ ++ eq '${#lines[*]}' 7 ++} +diff --git a/test/data/app-a/hooks/post-install b/test/data/app-a/hooks/post-install +index 1dfb7be..0717f2a 100755 +--- a/test/data/app-a/hooks/post-install ++++ b/test/data/app-a/hooks/post-install +@@ -2,7 +2,13 @@ + + set -u + +-echo "Post install" ++echo "post-install" ++ ++if [[ -e $APP_HOME/fail-post-install ]] ++then ++ echo "Simulating failure." ++ exit 1 ++fi + + NAME=`basename $APP_HOME` + +diff --git a/test/data/app-a/hooks/pre-install b/test/data/app-a/hooks/pre-install +new file mode 100755 +index 0000000..4b95ac4 +--- /dev/null ++++ b/test/data/app-a/hooks/pre-install +@@ -0,0 +1,11 @@ ++#!/bin/bash -e ++ ++set -u ++ ++echo "pre-install" ++ ++if [[ -e $APP_HOME/fail-pre-install ]] ++then ++ echo "Simulating failure." ++ exit 1 ++fi +-- +1.8.4.rc3 + -- cgit v1.2.3