Check-in [42154b78cd]
Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add a self-extracting sh package type implementation |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
42154b78cd799a0df057c0217d48d0d3 |
| User & Date: | chris.gerber@tapjoy.com 2014-03-11 04:40:04 |
Context
|
2014-03-11
| ||
| 04:40 | Fix FORCE variable handling; add post install logging check-in: c32d903019 user: chris.gerber@tapjoy.com tags: trunk | |
| 04:40 | Add a self-extracting sh package type implementation check-in: 42154b78cd user: chris.gerber@tapjoy.com tags: trunk | |
|
2014-02-10
| ||
| 23:54 | Update changelist check-in: 0e48f9977b user: jls@semicomplete.com tags: trunk | |
Changes
Added lib/fpm/package/sh.rb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
require "erb"
require "fpm/namespace"
require "fpm/package"
require "fpm/errors"
require "fpm/util"
require "backports"
require "fileutils"
require "digest"
# Support for self extracting sh files (.sh files)
#
# This class only supports output of packages.
#
# The sh package is a single sh file with a bzipped tar payload concatenated to the end.
# The script can unpack the tarball to install it and call optional post install scripts.
class FPM::Package::Sh < FPM::Package
def output(output_path)
create_scripts
# Make one file. The installscript can unpack itself.
`cat #{install_script} #{payload} > #{output_path}`
FileUtils.chmod("+x", output_path)
end
def create_scripts
if script?(:before_install)
# the scripts are kept in the payload so what would before install be if we've already
# unpacked the payload?
raise "sh package does not support before install scripts."
end
if script?(:after_install)
File.write(File.join(fpm_meta_path, "after_install"), script(:after_install))
end
end
def install_script
path = build_path("installer.sh")
File.open(path, "w") do |file|
file.write template("sh.erb").result(binding)
end
path
end
# Returns the path to the tar file containing the packed up staging directory
def payload
payload_tar = build_path("payload.tar")
@logger.info("Creating payload tar ", :path => payload_tar)
args = [ tar_cmd,
"-C",
staging_path,
"-cf",
payload_tar,
"--owner=0",
"--group=0",
"--numeric-owner",
"." ]
unless safesystem(*args)
raise "Command failed while creating payload tar: #{args}"
end
payload_tar
end
# Where we keep metadata and post install scripts and such
def fpm_meta_path
@fpm_meta_path ||= begin
path = File.join(staging_path, ".fpm")
FileUtils.mkdir_p(path)
path
end
end
end
|
Changes to lib/fpm/version.rb.
1 | module FPM | | | 1 2 3 | module FPM VERSION = "1.1.0" end |
Added templates/sh.erb.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
#!/bin/bash
# bail out if any part of this fails
set -e
# This is the self-extracting installer script for an FPM shell installer package.
# It contains the logic to unpack a tar archive appended to the end of this script
# and, optionally, to run post install logic.
# Run the package file with -h to see a usage message or look at the print_usage method.
#
# The post install scripts are called with INSTALL_ROOT, INSTALL_DIR and VERBOSE exported
# into the environment for their use.
#
# INSTALL_ROOT = the path passed in with -i or a relative directory of the name of the package
# file with no extension
# INSTALL_DIR = the same as INSTALL_ROOT unless -c (capistrano release directory) argumetn
# is used. Then it is $INSTALL_ROOT/releases/<datestamp>
# CURRENT_DIR = if -c argument is used, this is set to the $INSTALL_ROOT/current which is
# symlinked to INSTALL_DIR
# VERBOSE = is set if the package was called with -v for verbose output
function main() {
set_install_dir
create_pid
wait_for_others
kill_others
set_owner
unpack_payload
if [[ -n $UNPACK_ONLY ]] ; then
echo "Unpacking complete, not moving symlinks or restarting because unpack only was specified."
else
create_symlinks
set +e # don't exit on errors to allow us to clean up
if ! run_post_install ; then
revert_symlinks
log "Installation failed."
exit 1
else
clean_out_old_releases
log "Installation complete."
fi
fi
}
# deletes the PID file for this installation
function delete_pid(){
rm -f ${INSTALL_DIR}/$$.pid 2> /dev/null
}
# creates a PID file for this installation
function create_pid(){
trap "delete_pid" EXIT
echo $$> ${INSTALL_DIR}/$$.pid
}
# checks for other PID files and sleeps for a grace period if found
function wait_for_others(){
local count=`ls ${INSTALL_DIR}/*.pid | wc -l`
if [ $count -gt 1 ] ; then
sleep 10
fi
}
# kills other running installations
function kill_others(){
for PID_FILE in $(ls ${INSTALL_DIR}/*.pid) ; do
local p=`cat ${PID_FILE}`
if ! [ $p == $$ ] ; then
kill -9 $p
rm -f $PID_FILE 2> /dev/null
fi
done
}
# echos metadata file. A function so that we can have it change after we set INSTALL_ROOT
function fpm_metadata_file(){
echo "${INSTALL_ROOT}/.install-metadata"
}
# if this package was installed at this location already we will find a metadata file with the details
# about the installation that we left here. Load from that if available but allow command line args to trump
function load_environment(){
local METADATA=$(fpm_metadata_file)
if [ -r "${METADATA}" ] ; then
log "Found existing metadata file '${METADATA}'. Loading previous install details. Env vars in current environment will take precedence over saved values."
local TMP="/tmp/$(basename $0).$$.tmp"
# save existing environment, load saved environment from previous run from install-metadata and then
# overlay current environment so that anything set currencly will take precedence
# but missing values will be loaded from previous runs.
save_environment "$TMP"
source "${METADATA}"
source $TMP
rm "$TMP"
fi
}
# write out metadata for future installs
function save_environment(){
local METADATA=$1
echo -n "" > ${METADATA} # empty file
# just piping env to a file doesn't quote the variables. This does
# filter out multiline junk and _. _ is a readonly variable
env | egrep "^[^ ]+=.*" | grep -v "^_=" | while read ENVVAR ; do
local NAME=${ENVVAR%%=*}
# sed is to preserve variable values with dollars (for escaped variables or $() style command replacement),
# and command replacement backticks
# Escaped parens captures backward reference \1 which gets replaced with backslash and \1 to esape them in the saved
# variable value
local VALUE=$(eval echo '$'$NAME | sed 's/\([$`]\)/\\\1/g')
echo "export $NAME=\"$VALUE\"" >> ${METADATA}
done
if [ -n "${OWNER}" ] ; then
chown ${OWNER} ${METADATA}
fi
}
function set_install_dir(){
# if INSTALL_ROOT isn't set by parsed args, use basename of package file with no extension
DEFAULT_DIR=$(echo $(basename $0) | sed -e 's/\.[^\.]*$//')
INSTALL_DIR=${INSTALL_ROOT:-$DEFAULT_DIR}
DATESTAMP=$(date +%Y%m%d%H%M%S)
if [ -z "$USE_FLAT_RELEASE_DIRECTORY" ] ; then
RELEASE_ID=<%= release_id %>
INSTALL_DIR="${RELEASES_DIR}/${RELEASE_ID:-$DATESTAMP}"
fi
mkdir -p "$INSTALL_DIR" || die "Unable to create install directory $INSTALL_DIR"
export INSTALL_DIR
log "Installing package to '$INSTALL_DIR'"
}
function set_owner(){
export OWNER=${OWNER:-$USER}
log "Installing as user $OWNER"
}
function unpack_payload(){
if $FORCE || [ ! "$(ls -A $INSTALL_DIR)" ] ; then
log "Unpacking payload . . ."
local archive_line=$(grep -a -n -m1 '__ARCHIVE__$' $0 | sed 's/:.*//')
tail -n +$((archive_line + 1)) $0 | tar -C $INSTALL_DIR -xf - > /dev/null || die "Failed to unpack payload from the end of '$0' into '$INSTALL_DIR'"
else
# Files are already here, just move symlinks
log "Directory already exists and has contents ($INSTALL_DIR). Not unpacking payload."
fi
}
function run_post_install(){
local AFTER_INSTALL=$INSTALL_DIR/.fpm/after_install
if [ -r $AFTER_INSTALL ] ; then
chmod +x $AFTER_INSTALL
log "Running post install script"
$AFTER_INSTALL
return $?
fi
return 0
}
function create_symlinks(){
[ -n "$USE_FLAT_RELEASE_DIRECTORY" ] && return
export CURRENT_DIR="$INSTALL_ROOT/current"
if [ -e "$CURRENT_DIR" ] ; then
OLD_CURRENT_TARGET=$(readlink $CURRENT_DIR)
rm "$CURRENT_DIR"
fi
ln -s "$INSTALL_DIR" "$CURRENT_DIR"
log "Symlinked '$INSTALL_DIR' to '$CURRENT_DIR'"
}
# in case post install fails we may have to back out switching the symlink to current
# We can't switch the symlink after because post install may assume that it is in the
# exact state of being installed (services looking to current for their latest code)
function revert_symlinks(){
if [ -n "$OLD_CURRENT_TARGET" ] ; then
log "Putting current symlink back to '$OLD_CURRENT_TARGET'"
if [ -e "$CURRENT_DIR" ] ; then
rm "$CURRENT_DIR"
fi
ln -s "$OLD_CURRENT_TARGET" "$CURRENT_DIR"
fi
}
function clean_out_old_releases(){
[ -n "$USE_FLAT_RELEASE_DIRECTORY" ] && return
while [ $(ls -tr "${RELEASES_DIR}" | wc -l) -gt 2 ] ; do
OLDEST_RELEASE=$(ls -tr "${RELEASES_DIR}" | head -1)
log "Deleting old release '${OLDEST_RELEASE}'"
rm -rf "${RELEASES_DIR}/${OLDEST_RELEASE}"
done
}
function print_usage(){
echo "Usage: `basename $0` [options]"
echo "Install this package"
echo " -i <DIRECTORY> : install_root - an optional directory to install to."
echo " Default is package file name without file extension"
echo " -o <USER> : owner - the name of the user that will own the files installed"
echo " by the package. Defaults to current user"
echo " -r: disable capistrano style release directories - Default behavior is to create a releases directory inside"
echo " install_root and unpack contents into a date stamped (or build time id named) directory under the release"
echo " directory. Then create a 'current' symlink under install_root to the unpacked"
echo " directory once installation is complete replacing the symlink if it already "
echo " exists. If this flag is set just install into install_root directly"
echo " -u: Unpack the package, but do not install and symlink the payload"
echo " -f: force - Always overwrite existing installations"
echo " -y: yes - Don't prompt to clobber existing installations"
echo " -v: verbose - More output on installation"
echo " -h: help - Display this message"
}
function die () {
local message=$*
echo "Error: $message : $!"
exit 1
}
function log(){
local message=$*
if [ -n "$VERBOSE" ] ; then
echo "$*"
fi
}
function parse_args() {
args=`getopt i:o:rfuyvh $*`
if [ $? != 0 ] ; then
print_usage
exit 2
fi
set -- $args
for i
do
case "$i"
in
-r)
USE_FLAT_RELEASE_DIRECTORY=1
shift;;
-i)
shift;
export INSTALL_ROOT="$1"
export RELEASES_DIR="${INSTALL_ROOT}/releases"
shift;;
-o)
shift;
export OWNER="$1"
shift;;
-v)
export VERBOSE=1
shift;;
-u)
UNPACK_ONLY=true
shift;;
-f)
FORCE=true
shift;;
-y)
CONFIRM="y"
shift;;
-h)
print_usage
exit 0
shift;;
--)
shift; break;;
esac
done
}
# parse args first to get install root
parse_args $*
# load environment from previous installations so we get defaults from that
load_environment
# reparse args so they can override any settings from previous installations if provided on the command line
parse_args $*
main
save_environment $(fpm_metadata_file)
exit 0
__ARCHIVE__
|