| 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
|
| + *
|
|
|
|
|