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__ |