Last active
September 6, 2015 16:02
-
-
Save yunano/e9aaaddaf2f33b25ae76 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# ansible_best_practice.sh ver.20150907 | |
# | |
# Copyright (c) 2015 yunano | |
# This software is released under the MIT License. | |
# http://opensource.org/licenses/mit-license.php | |
export MARKER='%' | |
export FROM='.' | |
export TO='' | |
export SHADOW='s' | |
export DIR_FALLBACK='c' | |
export ROLES='/roles' | |
export START=2 | |
export DIV_PATTERN='^--- # ' | |
export ALL=0 | |
export DELETE=0 | |
export DIVIDE=1 | |
export GATHER=0 | |
export GATHER_HIDDEN=0 | |
export VERBOSE=0 | |
usage() { | |
cat << EOD | |
Usage: bash $0 [Options] | |
Options: | |
-m MARKER marker indicate copy/link files started with MARKER | |
also treated as pseudo directory seperator | |
in file names (default: %) | |
-f FROM_DIR from-directory copy/link from FROM_DIR (default: .) | |
-t TO_DIR to-directory copy/link to TO_DIR | |
-s symbolic-link make symbolic links (default) | |
-H hard-link-fallback-copy | |
make hard links for files, | |
copy for directories if with -a | |
-S hard-link-fallback-symbolic | |
make hard links for files, | |
make symbolic links for directories if with -a | |
-c copy copy files | |
-p project-root deal FROM_DIR and TO_DIR as the project root | |
directory (default) | |
-r roles deal FROM_DIR and TO_DIR as the roles directory | |
-i individual-role deal FROM_DIR and TO_DIR as the individual role | |
directory | |
-a all-files also copy/link other than files indicated | |
by MARKER | |
this option is ignored if FROM_DIR == TO_DIR | |
-d delete-previous delete TO_DIR/roles/ before copy/link | |
if specified with -a, delete TO_DIR/* | |
if specified -g, delete TO_DIR/MARKER* | |
if specified with -r or -i, delete TO_DIR/*/ | |
-D disable-divide disable yaml division | |
-g gather-mode gather mode aka reverse mode (implies -d) | |
-G gather-mode-including-hidden-directories | |
gather including hidden directories | |
-v verbose increase verbosity | |
-h help show this help | |
EOD | |
exit 2 | |
} | |
while getopts ':m:f:t:sHScpriadDgGvh' opt | |
do | |
case $opt in | |
m) | |
MARKER=$OPTARG | |
;; | |
f) | |
FROM=$OPTARG | |
;; | |
t) | |
TO=$OPTARG | |
;; | |
s) | |
SHADOW='s' | |
;; | |
H) | |
SHADOW='h' | |
;; | |
S) | |
SHADOW='h' | |
DIR_FALLBACK='s' | |
;; | |
c) | |
SHADOW='c' | |
;; | |
p) | |
;; | |
r) | |
ROLES='' | |
;; | |
i) | |
ROLES='' | |
START=1 | |
;; | |
a) | |
ALL=1 | |
;; | |
d) | |
DELETE=1 | |
;; | |
D) | |
DIVIDE=0 | |
;; | |
g) | |
GATHER=1 | |
DELETE=1 | |
;; | |
G) | |
GATHER=1 | |
GATHER_HIDDEN=1 | |
DELETE=1 | |
;; | |
v) | |
VERBOSE=1 | |
;; | |
h | : | \?) | |
usage | |
break | |
;; | |
esac | |
done | |
make_shadow() { | |
file="${1##*/}" | |
if [ "$file" == "$MARKER" ]; then | |
[ $VERBOSE -eq 1 ] && echo "File '$MARKER' has been ignored" | |
return | |
fi | |
roles_dir="$TO$ROLES" | |
to_file_rel=$(awk -v name="$file" -v delim=$MARKER -v start=$START 'BEGIN { num = split(name, arr, delim); if (arr[num] == "" || arr[num] == ".yml") { arr[num] = "main.yml" }; if (num==start) { sub("\\.yml$", "", arr[start]); print "/" arr[start] "/tasks/main.yml" } else if (num==start+1) { if (arr[start] != "") { arr[start] = "/" arr[start] }; if (arr[num] ~ /\.yml$/) { print arr[start] "/tasks/" arr[num] } else { print arr[start] "/" arr[num] } } else if (num>=start+2) { str = ""; for (i=2; i<=num; i++) { str = str "/" arr[i] }; print str } }') | |
if ([ $DIVIDE -eq 1 ] && echo "$to_file_rel" | grep -q ".yml$" && grep -q "$DIV_PATTERN" "$1"); then | |
[ $START -eq 1 ] && role_dir="$roles_dir" || role_dir="$roles_dir/$(echo $to_file_rel | awk -F / '{ print $2 }')" | |
div_file="" | |
div_file_tmp="" | |
while IFS= read -r line | |
do | |
echo "$line" | grep -q "$DIV_PATTERN" && div_file_tmp="$role_dir/$(echo "$line" | sed 's/^.* //' | tr '\r\n' '\n')" | |
if [ "$div_file" != "$div_file_tmp" ]; then | |
div_file="$div_file_tmp" | |
mkdir -p "${div_file%/*}" | |
chmod u+rwx "${div_file%/*}" | |
: > "$div_file" | |
chmod u+rw "$div_file" | |
elif [ -n "$div_file" ]; then | |
echo "$line" >> "$div_file" | |
fi | |
done < "$1" | |
else | |
to_file="$roles_dir$to_file_rel" | |
mkdir -p "${to_file%/*}" | |
chmod u+rwx "${to_file%/*}" | |
[ $VERBOSE -eq 1 ] && echo "$1 -> $to_file" | |
if [ $2 -eq 1 ]; then | |
cp -P "$1" "$to_file" | |
elif [ $SHADOW == 'c' ]; then | |
cp "$1" "$to_file" | |
elif [ $SHADOW == 'h' ]; then | |
ln -f "$1" "$to_file" | |
else | |
ln -sf "$1" "$to_file" | |
fi | |
fi | |
} | |
export -f make_shadow | |
gather_shadow() { | |
from_file_rel="${1#$FROM$ROLES}" | |
if [ $START -eq 1 ]; then | |
role="" | |
role_rel="$from_file_rel" | |
else | |
role="$(echo $from_file_rel | awk -F / '{ print $2 }')" | |
role_rel="${from_file_rel#/$role}" | |
fi | |
if ([ $DIVIDE -eq 1 ] && echo "$role_rel" | grep -q ".yml$"); then | |
[ $VERBOSE -eq 1 ] && echo "Gather: $1 ->> $TO/$MARKER$role.yml" | |
echo "--- # ${role_rel#/}" >> "$TO/$MARKER$role.yml" | |
cat "$1" | awk '1' >> "$TO/$MARKER$role.yml" | |
else | |
to_file="$TO/$MARKER$role$(awk -v path="$role_rel" -v delim=$MARKER -v start=$START 'BEGIN { sub("/main\\.yml$", "/.yml", path); sub("^/tasks/", "/", path); sub("^/\\.yml$", ".yml", path); if (start==1) { sub("^/", "", path) }; gsub("/", delim, path); print path }')" | |
[ $VERBOSE -eq 1 ] && echo "$1 -> $to_file" | |
if [ $2 -eq 1 ]; then | |
cp -P "$1" "$to_file" | |
elif [ $SHADOW == 'c' ]; then | |
cp "$1" "$to_file" | |
elif [ $SHADOW == 'h' ]; then | |
ln -f "$1" "$to_file" | |
else | |
ln -sf "$1" "$to_file" | |
fi | |
fi | |
} | |
export -f gather_shadow | |
if [ -z "$MARKER" ]; then | |
echo "MARKER is empty" 1>&2 | |
usage | |
fi | |
if [ ! -d "$FROM" ]; then | |
echo "Directory '$FROM' does not exist" 1>&2 | |
usage | |
fi | |
if [ -z "$TO" ]; then | |
echo "Destination directory is empty" 1>&2 | |
usage | |
fi | |
mkdir -p "$TO" | |
chmod u+rwx "$TO" | |
FROM=$(cd "$FROM"; pwd) | |
TO=$(cd "$TO"; pwd) | |
[ "$FROM" == "$TO" ] && ALL=0 | |
[ $VERBOSE -eq 1 ] && echo "<< Copy/Link from '$FROM' to '$TO' >>" | |
if [ $DELETE -eq 1 ]; then | |
if [ $ALL -eq 1 ]; then | |
[ $VERBOSE -eq 1 ] && echo "Delete '$TO/*'" | |
find "$TO" -mindepth 1 -maxdepth 1 -print0 | xargs -0 -I ^ rm -rf "^" | |
elif [ $GATHER -eq 1 ]; then | |
[ $VERBOSE -eq 1 ] && echo "Delete '$TO/$MARKER*'" | |
find "$TO" -maxdepth 1 -name "${MARKER}* -type f" -print0 | xargs -0 -I ^ rm -f "^" | |
elif [ "$ROLES" == '/roles' ]; then | |
[ $VERBOSE -eq 1 ] && echo "Delete '$TO/roles'" | |
rm -rf "$TO/roles" | |
else | |
[ $VERBOSE -eq 1 ] && echo "Delete '$TO/*/'" | |
find "$TO" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I ^ rm -rf "^" | |
fi | |
fi | |
if [ $ALL -eq 1 ]; then | |
[ $VERBOSE -eq 1 ] && echo "Copy/Link '$FROM/*' to '$TO'" | |
if [ $SHADOW == 'c' ]; then | |
find "$FROM" -mindepth 1 -type f | while IFS= read -r file | |
do | |
[ "$file" == "${file#$FROM/$MARKER}" ] && cp "$file" "$TO" | |
done | |
find "$FROM" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I ^ cp -RP "^" "$TO" | |
elif [ $SHADOW == 'h' ]; then | |
find "$FROM" -mindepth 1 -type f | while IFS= read -r file | |
do | |
[ "$file" == "${file#$FROM/$MARKER}" ] && ln -f "$file" "$TO" | |
done | |
if [ $DIR_FALLBACK == 's' ]; then | |
find "$FROM" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I ^ ln -sf "^" "$TO" | |
else | |
find "$FROM" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I ^ cp -RP "^" "$TO" | |
fi | |
else | |
find "$FROM" -mindepth 1 -type f | while IFS= read -r file | |
do | |
[ "$file" == "${file#$FROM/$MARKER}" ] && ln -sf "$file" "$TO" | |
done | |
find "$FROM" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I ^ ln -sf "^" "$TO" | |
fi | |
find "$FROM" -mindepth 1 -maxdepth 1 -type l | while IFS= read -r slink | |
do | |
if ([ -d "$slink" ] || echo "$slink" | fgrep -vq "$FROM/$MARKER"); then | |
cp -RP "$slink" "$TO" | |
fi | |
done | |
chmod -R u+rw "$TO" | |
find "$TO" -mindepth 1 -type d -print0 | xargs -0 -I ^ chmod u+x "^" | |
fi | |
if [ $GATHER -eq 0 ]; then | |
find "$FROM" -maxdepth 1 -type f -print0 -name "${MARKER}*" | xargs -0 -I ^ bash -c 'make_shadow "^" 0' | |
find "$FROM" -mindepth 1 -maxdepth 1 -type l | while IFS= read -r slink | |
do | |
([ -f "$slink" ] && echo "$slink" | fgrep -q "$FROM/$MARKER") && make_shadow "$slink" 1 | |
done | |
else | |
find "$FROM$ROLES" -mindepth 1 -maxdepth 1 -type d | while IFS= read -r role | |
do | |
: > "$TO/$MARKER${role#$FROM$ROLES/}.yml" | |
done | |
find "$FROM$ROLES" -mindepth 2 -type f | while IFS= read -r file | |
do | |
[ $GATHER_HIDDEN -eq 1 -o "$file" = "${file#$FROM$ROLES/.}" ] && gather_shadow "$file" 0 | |
done | |
find "$FROM$ROLES" -mindepth 2 -type l | while IFS= read -r slink | |
do | |
[ -f "$slink" ] && [ $GATHER_HIDDEN -eq 1 -o "$slink" = "${file#$FROM$ROLES/.}" ] && gather_shadow "$slink" 1 | |
done | |
fi | |
chmod -R u+rw "$TO" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment