1#!/bin/bash 2# Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU) 3# Licensed under the Mulan PSL v2. 4# You can use this software according to the terms and conditions of the Mulan PSL v2. 5# You may obtain a copy of Mulan PSL v2 at: 6# http://license.coscl.org.cn/MulanPSL2 7# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR 8# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR 9# PURPOSE. 10# See the Mulan PSL v2 for more details. 11 12set -e 13 14self=$(basename "$0") 15 16function usage { 17 echo "Usage: $self [overrides_absolute_path] [target_absolute_path]" 18 exit 1 19} 20 21if [ "$#" -ne 2 ]; then 22 usage 23fi 24 25if [[ $1 != /* ]] || [[ $2 != /* ]]; then 26 usage 27fi 28 29overrides=$1 30target=$2 31 32# Overrides is based on mirror structure of $overrides and $target directory. 33# So, for each file and directory **under $overrides**, we have defined following 34# overriding semantics: 35# 1. For a directory, if there is no corresponding directory in $target, the whole 36# directory should exist under $target. 37# 2. For a directory(A), if there is corresponding directory in $target(B), we should 38# override all subdirectories and files, but should not touch files not appear in 39# A but in B. 40# 3. For a file(A), if it is an empty file, it means corresponding file in $target(B) 41# should be deleted. We first backup B, then delete it. 42# 4. For a file(A), if it is not empty, we first backup its corresponding file(B), then 43# override B with content of A. 44# 45# Based on above overridng semantic, this process is implemented with target state-based 46# approach. Besides, for performance and being able to reflect latest changes of libchcore, 47# We use symlink for all override operations. So, consider the target state of a directory 48# and file under $override: 49# 1. For a directory(A), if B exists, then we recurse to check subdirectories and files of A. 50# 2. For a directory(A), if B not exists, then the target state should be that B is a 51# symlink to A. 52# 3. For a file(A), if it is empty, then the target state should be: (1) backup file of B 53# exists, and (2) B is deleted 54# 4. For a file(A), if it is not empty, then the target state should be: (1) backup file of B 55# exists, and (2) B is a symlink to A 56# 57# We recursively iterate over each subdirectories and files under $override, for each of 58# them, check the state of their corresponding B is reached target state or not. If reached, 59# we just skip for idempotence. Otherwise, we perform backup and link operations(if needed). 60 61function traverse { 62 for file in "$1"/*; do 63 rel_path=${file#$overrides/} 64 target_file=$target/$rel_path 65 66 if [ -d "$file" ]; then 67 if [ ! -e "$target_file" ]; then 68 ln -s "$file" "$target_file" 69 echo "--- Overrided ${target_file} with ${file} symlink" 70 elif [ ! -L "$target_file" ]; then 71 traverse "$file" 72 else 73 echo "--- Target directory ${target_file} has been overrided, skipping..." 74 fi 75 elif [ -f "$file" ]; then 76 if [ ! -s "$file" ]; then 77 if [ -e "$target_file" ]; then 78 mv "$target_file" "$target_file.bak" 79 echo "--- Overrided ${target_file} with ${file}" 80 else 81 echo "--- Target file ${target_file} has been deleted, skipping..." 82 fi 83 else 84 if [ ! -e "$target_file" ]; then 85 ln -s "$file" "$target_file" 86 echo "--- Overrided ${target_file} with ${file}" 87 elif [ ! -L "$target_file" ]; then 88 mv "$target_file" "$target_file.bak" 89 ln -s "$file" "$target_file" 90 echo "--- Overrided ${target_file} with ${file}" 91 else 92 echo "--- Target file ${target_file} is already a symlink, skipping..." 93 fi 94 fi 95 fi 96 done 97} 98 99traverse $overrides 100