Index: chrome_mac/Google Chrome Packaging/dirpatcher.sh |
=================================================================== |
--- chrome_mac/Google Chrome Packaging/dirpatcher.sh (revision 0) |
+++ chrome_mac/Google Chrome Packaging/dirpatcher.sh (revision 0) |
@@ -0,0 +1,368 @@ |
+#!/bin/bash -p |
+ |
+# Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+# usage: dirpatcher.sh old_dir patch_dir new_dir |
+# |
+# dirpatcher creates new_dir from patch_dir by decompressing and copying |
+# files, and using goobspatch to apply binary diffs to files in old_dir. |
+# |
+# dirpatcher performs the inverse operation to dirdiffer. For more details, |
+# consult dirdiffer.sh. |
+# |
+# Exit codes: |
+# 0 OK |
+# 1 Unknown failure |
+# 2 Incorrect number of parameters |
+# 3 Input directories do not exist or are not directories |
+# 4 Output directory already exists |
+# 5 Parent of output directory does not exist or is not a directory |
+# 6 An input or output directories contains another |
+# 7 Could not create output directory |
+# 8 File already exists in output directory |
+# 9 Found an irregular file (non-directory, file, or symbolic link) in input |
+# 10 Could not create symbolic link |
+# 11 Unrecognized file extension |
+# 12 Attempt to patch a nonexistent or non-regular file |
+# 13 Patch application failed |
+# 14 File decompression failed |
+# 15 File copy failed |
+# 16 Could not set mode (permissions) |
+# 17 Could not set modification time |
+ |
+set -eu |
+ |
+# Environment sanitization. Set a known-safe PATH. Clear environment variables |
+# that might impact the interpreter's operation. The |bash -p| invocation |
+# on the #! line takes the bite out of BASH_ENV, ENV, and SHELLOPTS (among |
+# other features), but clearing them here ensures that they won't impact any |
+# shell scripts used as utility programs. SHELLOPTS is read-only and can't be |
+# unset, only unexported. |
+export PATH="/usr/bin:/bin:/usr/sbin:/sbin" |
+unset BASH_ENV CDPATH ENV GLOBIGNORE IFS POSIXLY_CORRECT |
+export -n SHELLOPTS |
+ |
+shopt -s dotglob nullglob |
+ |
+# find_tool looks for an executable file named |tool_name|: |
+# - in the same directory as this script, |
+# - if this script is located in a Chromium source tree, at the expected |
+# Release output location in the Mac out directory, |
+# - as above, but in the Debug output location |
+# If found in any of the above locations, the script's path is output. |
+# Otherwise, this function outputs |tool_name| as a fallback, allowing it to |
+# be found (or not) by an ordinary ${PATH} search. |
+find_tool() { |
+ local tool_name="${1}" |
+ |
+ local script_dir |
+ script_dir="$(dirname "${0}")" |
+ |
+ local tool="${script_dir}/${tool_name}" |
+ if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then |
+ echo "${tool}" |
+ return |
+ fi |
+ |
+ local script_dir_phys |
+ script_dir_phys="$(cd "${script_dir}" && pwd -P)" |
+ if [[ "${script_dir_phys}" =~ ^(.*)/src/chrome/installer/mac$ ]]; then |
+ tool="${BASH_REMATCH[1]}/src/out/Release/${tool_name}" |
+ if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then |
+ echo "${tool}" |
+ return |
+ fi |
+ |
+ tool="${BASH_REMATCH[1]}/src/out/Debug/${tool_name}" |
+ if [[ -f "${tool}" ]] && [[ -x "${tool}" ]]; then |
+ echo "${tool}" |
+ return |
+ fi |
+ fi |
+ |
+ echo "${tool_name}" |
+} |
+ |
+ME="$(basename "${0}")" |
+readonly ME |
+GOOBSPATCH="$(find_tool goobspatch)" |
+readonly GOOBSPATCH |
+readonly BUNZIP2="bunzip2" |
+readonly GUNZIP="gunzip" |
+XZDEC="$(find_tool xzdec)" |
+readonly XZDEC |
+readonly GBS_SUFFIX='$gbs' |
+readonly BZ2_SUFFIX='$bz2' |
+readonly GZ_SUFFIX='$gz' |
+readonly XZ_SUFFIX='$xz' |
+readonly PLAIN_SUFFIX='$raw' |
+ |
+err() { |
+ local error="${1}" |
+ |
+ echo "${ME}: ${error}" >& 2 |
+} |
+ |
+declare -a g_cleanup |
+cleanup() { |
+ local status=${?} |
+ |
+ trap - EXIT |
+ trap '' HUP INT QUIT TERM |
+ |
+ if [[ ${status} -ge 128 ]]; then |
+ err "Caught signal $((${status} - 128))" |
+ fi |
+ |
+ if [[ "${#g_cleanup[@]}" -gt 0 ]]; then |
+ rm -rf "${g_cleanup[@]}" |
+ fi |
+ |
+ exit ${status} |
+} |
+ |
+copy_mode_and_time() { |
+ local patch_file="${1}" |
+ local new_file="${2}" |
+ |
+ local mode |
+ mode="$(stat "-f%OMp%OLp" "${patch_file}")" |
+ if ! chmod -h "${mode}" "${new_file}"; then |
+ exit 16 |
+ fi |
+ |
+ if ! [[ -L "${new_file}" ]]; then |
+ # Symbolic link modification times can't be copied because there's no |
+ # shell tool that provides direct access to lutimes. Instead, the symbolic |
+ # link was created with rsync, which already copied the timestamp with |
+ # lutimes. |
+ if ! touch -r "${patch_file}" "${new_file}"; then |
+ exit 17 |
+ fi |
+ fi |
+} |
+ |
+apply_patch() { |
+ local old_file="${1}" |
+ local patch_file="${2}" |
+ local new_file="${3}" |
+ local patcher="${4}" |
+ |
+ if [[ -L "${old_file}" ]] || ! [[ -f "${old_file}" ]]; then |
+ err "can't patch nonexistent or irregular file ${old_file}" |
+ exit 12 |
+ fi |
+ |
+ if ! "${patcher}" "${old_file}" "${new_file}" "${patch_file}"; then |
+ err "couldn't create ${new_file} by applying ${patch_file} to ${old_file}" |
+ exit 13 |
+ fi |
+} |
+ |
+decompress_file() { |
+ local old_file="${1}" |
+ local patch_file="${2}" |
+ local new_file="${3}" |
+ local decompressor="${4}" |
+ |
+ if ! "${decompressor}" -c < "${patch_file}" > "${new_file}"; then |
+ err "couldn't decompress ${patch_file} to ${new_file} with ${decompressor}" |
+ exit 14 |
+ fi |
+} |
+ |
+copy_file() { |
+ local old_file="${1}" |
+ local patch_file="${2}" |
+ local new_file="${3}" |
+ local extra="${4}" |
+ |
+ if ! cp "${patch_file}" "${new_file}"; then |
+ exit 15 |
+ fi |
+} |
+ |
+patch_file() { |
+ local old_file="${1}" |
+ local patch_file="${2}" |
+ local new_file="${3}" |
+ |
+ local operation extra strip_length |
+ |
+ if [[ "${patch_file: -${#GBS_SUFFIX}}" = "${GBS_SUFFIX}" ]]; then |
+ operation="apply_patch" |
+ extra="${GOOBSPATCH}" |
+ strip_length=${#GBS_SUFFIX} |
+ elif [[ "${patch_file: -${#BZ2_SUFFIX}}" = "${BZ2_SUFFIX}" ]]; then |
+ operation="decompress_file" |
+ extra="${BUNZIP2}" |
+ strip_length=${#BZ2_SUFFIX} |
+ elif [[ "${patch_file: -${#GZ_SUFFIX}}" = "${GZ_SUFFIX}" ]]; then |
+ operation="decompress_file" |
+ extra="${GUNZIP}" |
+ strip_length=${#GZ_SUFFIX} |
+ elif [[ "${patch_file: -${#XZ_SUFFIX}}" = "${XZ_SUFFIX}" ]]; then |
+ operation="decompress_file" |
+ extra="${XZDEC}" |
+ strip_length=${#XZ_SUFFIX} |
+ elif [[ "${patch_file: -${#PLAIN_SUFFIX}}" = "${PLAIN_SUFFIX}" ]]; then |
+ operation="copy_file" |
+ extra="patch" |
+ strip_length=${#PLAIN_SUFFIX} |
+ else |
+ err "don't know how to operate on ${patch_file}" |
+ exit 11 |
+ fi |
+ |
+ old_file="${old_file:0:${#old_file} - ${strip_length}}" |
+ new_file="${new_file:0:${#new_file} - ${strip_length}}" |
+ |
+ if [[ -e "${new_file}" ]]; then |
+ err "${new_file} already exists" |
+ exit 8 |
+ fi |
+ |
+ "${operation}" "${old_file}" "${patch_file}" "${new_file}" "${extra}" |
+ |
+ copy_mode_and_time "${patch_file}" "${new_file}" |
+} |
+ |
+patch_symlink() { |
+ local patch_file="${1}" |
+ local new_file="${2}" |
+ |
+ # local target |
+ # target="$(readlink "${patch_file}")" |
+ # ln -s "${target}" "${new_file}" |
+ |
+ # Use rsync instead of the above, as it's the only way to preserve the |
+ # timestamp of a symbolic link using shell tools. |
+ if ! rsync -lt "${patch_file}" "${new_file}"; then |
+ exit 10 |
+ fi |
+ |
+ copy_mode_and_time "${patch_file}" "${new_file}" |
+} |
+ |
+patch_dir() { |
+ local old_dir="${1}" |
+ local patch_dir="${2}" |
+ local new_dir="${3}" |
+ |
+ if ! mkdir "${new_dir}"; then |
+ exit 7 |
+ fi |
+ |
+ local patch_file |
+ for patch_file in "${patch_dir}/"*; do |
+ local file="${patch_file:${#patch_dir} + 1}" |
+ local old_file="${old_dir}/${file}" |
+ local new_file="${new_dir}/${file}" |
+ |
+ if [[ -e "${new_file}" ]]; then |
+ err "${new_file} already exists" |
+ exit 8 |
+ fi |
+ |
+ if [[ -L "${patch_file}" ]]; then |
+ patch_symlink "${patch_file}" "${new_file}" |
+ elif [[ -d "${patch_file}" ]]; then |
+ patch_dir "${old_file}" "${patch_file}" "${new_file}" |
+ elif ! [[ -f "${patch_file}" ]]; then |
+ err "can't handle irregular file ${patch_file}" |
+ exit 9 |
+ else |
+ patch_file "${old_file}" "${patch_file}" "${new_file}" |
+ fi |
+ done |
+ |
+ copy_mode_and_time "${patch_dir}" "${new_dir}" |
+} |
+ |
+# shell_safe_path ensures that |path| is safe to pass to tools as a |
+# command-line argument. If the first character in |path| is "-", "./" is |
+# prepended to it. The possibly-modified |path| is output. |
+shell_safe_path() { |
+ local path="${1}" |
+ if [[ "${path:0:1}" = "-" ]]; then |
+ echo "./${path}" |
+ else |
+ echo "${path}" |
+ fi |
+} |
+ |
+dirs_contained() { |
+ local dir1="${1}/" |
+ local dir2="${2}/" |
+ |
+ if [[ "${dir1:0:${#dir2}}" = "${dir2}" ]] || |
+ [[ "${dir2:0:${#dir1}}" = "${dir1}" ]]; then |
+ return 0 |
+ fi |
+ |
+ return 1 |
+} |
+ |
+usage() { |
+ echo "usage: ${ME} old_dir patch_dir new_dir" >& 2 |
+} |
+ |
+main() { |
+ local old_dir patch_dir new_dir |
+ old_dir="$(shell_safe_path "${1}")" |
+ patch_dir="$(shell_safe_path "${2}")" |
+ new_dir="$(shell_safe_path "${3}")" |
+ |
+ trap cleanup EXIT HUP INT QUIT TERM |
+ |
+ if ! [[ -d "${old_dir}" ]] || ! [[ -d "${patch_dir}" ]]; then |
+ err "old_dir and patch_dir must exist and be directories" |
+ usage |
+ exit 3 |
+ fi |
+ |
+ if [[ -e "${new_dir}" ]]; then |
+ err "new_dir must not exist" |
+ usage |
+ exit 4 |
+ fi |
+ |
+ local new_dir_parent |
+ new_dir_parent="$(dirname "${new_dir}")" |
+ if ! [[ -d "${new_dir_parent}" ]]; then |
+ err "new_dir parent directory must exist and be a directory" |
+ usage |
+ exit 5 |
+ fi |
+ |
+ local old_dir_phys patch_dir_phys new_dir_parent_phys new_dir_phys |
+ old_dir_phys="$(cd "${old_dir}" && pwd -P)" |
+ patch_dir_phys="$(cd "${patch_dir}" && pwd -P)" |
+ new_dir_parent_phys="$(cd "${new_dir_parent}" && pwd -P)" |
+ new_dir_phys="${new_dir_parent_phys}/$(basename "${new_dir}")" |
+ |
+ if dirs_contained "${old_dir_phys}" "${patch_dir_phys}" || |
+ dirs_contained "${old_dir_phys}" "${new_dir_phys}" || |
+ dirs_contained "${patch_dir_phys}" "${new_dir_phys}"; then |
+ err "directories must not contain one another" |
+ usage |
+ exit 6 |
+ fi |
+ |
+ g_cleanup+=("${new_dir}") |
+ |
+ patch_dir "${old_dir}" "${patch_dir}" "${new_dir}" |
+ |
+ unset g_cleanup[${#g_cleanup[@]}] |
+ trap - EXIT |
+} |
+ |
+if [[ ${#} -ne 3 ]]; then |
+ usage |
+ exit 2 |
+fi |
+ |
+main "${@}" |
+exit ${?} |
Property changes on: chrome_mac/Google Chrome Packaging/dirpatcher.sh |
___________________________________________________________________ |
Added: svn:executable |
+ * |