#!/usr/bin/env bash
##############################################################################
##
## GitHub Upload+Update Script (V2, combined) for DevPlat Samples
##
##############################################################################
update=true
upload=true
deleteTemp=true
useAllSamples=true
allSamples=()
token=
## Generates a random 32 character alphaneumeric string to use as a post script
## for the temporary code folder (folder will be deleted at end)
folderPS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
#utility function to print to stderr
echoerr() { echo "$@" 1>&2; }
display_usage() {
echo -e "\e[90mUsage:
-t | --token [github_auth_token]
Input an auth token to access the googlesamples GitHub org
(if this is not present, you will be prompted for one later)
-s | --samples [sample1 sample2 sample3 ... sampleN]
If you don't want to check the entire samples folder,
you can specify which samples to use with this option.
--upload-only
Only uploads new samples - samples with existing
repos will be ignored
--update-only
Only updates samples with existing repos - new
samples will be ignored
--keep-temp-files
Will not delete the temporary directory used to pull/push
to Github. (normally deleted upon exit) Preserves logs.
This script can be run with no options - it will check the entire
./prebuilts/gradle folder and prompt for an auth token when needed.\e[0m\n"
}
##############################################################################
## Make sure we delete the temporary folder (if it gets created) before exiting
finish() {
if $deleteTemp; then
if [ -d "../github-temp$folderPS" ]; then
cd ..
rm -rf ./github-temp$folderPS
elif [ -d "github-temp$folderPS" ]; then
rm -rf ./github-temp$folderPS
fi
fi
}
# this ensures finish() will always be called no matter how the script ends
trap finish EXIT
##############################################################################
## Process input parameters. (see above for usage)
## How this works:
## $# is the number of parameters passed in
## $1 is the first parameter, $2 the second, and so on. (space delimited)
## shift basically left shifts the params array - $1 goes away, $2 becomes $1, etc
## Thus, this while loop iterates through all command line parameters
while [[ $# > 0 ]]; do
case "$1" in
-t|--token)
if [[ $2 != -* ]] && [[ $2 ]]; then
token="$2"; shift
else
echoerr -e "Option $1 requires an argument. Cancelling script.\nUse --help to display usage."
exit 1
fi;;
--update-only) upload=false;;
--upload-only) update=false;;
--keep-temp-files) deleteTemp=false;;
-s|--samples)
useAllSamples=false
while [[ $2 != -* ]] && [[ $2 ]]; do
#if true; then ##for testing
if [ -d "./prebuilts/gradle/$2" ]; then
allSamples+=("$2")
shift
else
echoerr -e "Sample \"$2\" does not exist in ./prebuilts/gradle. Cancelling script.\n"
exit 1
fi
done;;
-h|--help)
display_usage
exit 1;;
*)
echoerr -e "Unknown Option: $1\nUse --help to display usage."
exit 1;;
esac
shift
done #ends options while loop
if ! $upload && ! $update; then
echoerr -e "Do not use both --update-only and --upload-only, no samples will be processed.
If you want to do both updates and uploads, no flags are needed.
Use --help to display usage."
exit 1
fi
##############################################################################
## Get all folders in prebuilts and stick 'em in an array
if $useAllSamples; then
allSamples=($(ls ./prebuilts/gradle))
fi
# [@] returns all items in an array, ${#...} counts them
numSamples=${#allSamples[@]}
echo "Running script for $numSamples samples"
##############################################################################
## Iterate through all the samples and see if there's
## a repo for them on GitHub already - save results so we only do it once
toUpdate=()
toUpload=()
problemSamples=()
curSample=0
echo -ne "Checking for existence of repos... ($curSample/$numSamples)\r"
for i in ${allSamples[@]};
do
#echo "$i"
URL=https://github.com/googlesamples/android-$i
result=$(curl -o /dev/null --silent --head --write-out '%{http_code}' "$URL")
#echo "$result $URL"
if [ "$result" -eq "404" ]; then
toUpload+=("$i")
elif [ "$result" -eq "200" ]; then
toUpdate+=("$i")
else
problemSamples+=("$i")
fi
curSample=$(($curSample+1))
echo -ne "Checking for existence of repos... ($curSample/$numSamples)\r"
done #close for loop for existence check
echo ""
##############################################################################
## For every sample that has a repo already, clone it and diff it against
## the sample code in our git to see if it needs updating.
if $update; then
needsUpdate=()
curSample=0
numUpdates=${#toUpdate[@]}
##make temporary dir to pull code into - will be deleted upon exit.
mkdir github-temp$folderPS
cd github-temp$folderPS
echo -ne "Checking for out-of-date repos... ($curSample/$numUpdates)\r"
for i in ${toUpdate[@]};
do
URL=https://github.com/googlesamples/android-$i
git clone $URL.git &> /dev/null
if [ -d "android-$i" ]; then
diffResult=$(diff -r --exclude '*.git' ../prebuilts/gradle/$i/ ./android-$i/)
#for testing (will show diff in every repo)
#diffResult=$(diff -r ../prebuilts/gradle/$i/ ./android-$i/)`
#echo $diffResult
if [ -n "$diffResult" ]; then
needsUpdate+=("$i")
fi
else
echoerr "Something went wrong when cloning $i - result directory does not exist.
Leaving temp files in place for further examination."
deleteTemp=false;
fi
curSample=$(($curSample+1))
echo -ne "Checking for out-of-date repos... ($curSample/$numUpdates)\r"
done #end of for loop when checking which repos actually need updating
echo ""
fi
echo ""
##############################################################################
## Display the detected changes to be made and get user confirmation
if $upload; then
if [ ${#toUpload[@]} -ne 0 ]; then
echo -e "\n\e[1mNew samples that will be uploaded:\e[0m"
for i in ${toUpload[@]}; do
echo -e "\e[32m$i\e[0m"
done
else
upload=false
echo "Nothing new to upload."
fi
else
echo "No uploads - check skipped on user request"
fi
if $update; then
if [ ${#needsUpdate[@]} -ne 0 ]; then
echo -e "\n\e[1mSamples that will be updated:\e[0m"
for i in ${needsUpdate[@]}; do
echo -e "\e[34m$i\e[0m"
done
else
update=false
echo "Nothing to update."
fi
else
echo "No updates - check skipped on user request"
fi
if [ ${#problemSamples[@]} -ne 0 ]; then
echoerr "
These repos returned something other than a 404 or 200 result code:"
for i in ${problemSamples[@]};
do
echoerr "$i"
done
fi
if ! $upload && ! $update; then
echo -e "\e[1mLooks like everything's up-to-date.\e[0m\n"
else
read -p "
Do you want to continue? [y/n]: " -n 1 -r
echo
# if they type anything but an upper or lower case y, don't proceed.
if [[ $REPLY =~ ^[Yy]$ ]]
then
#echo "Commencing Github updates"
##############################################################################
## If the user hasn't supplied a token via parameter, ask now
if ! [ -n "$token" ]
then
read -p "
Input a valid googlesamples GitHub access token to continue: " -r
token=$REPLY
fi
##############################################################################
## Test that token
tokenTest=$(curl -o /dev/null --silent \
-H "Authorization: token $token" \
--write-out '%{http_code}' "https://api.github.com/orgs/googlesamples/repos")
if [ "$tokenTest" -eq "200" ]; then
##############################################################################
## If there's something to update, do the updates
if [ ${#needsUpdate[@]} -ne 0 ] && $update; then
for i in ${needsUpdate[@]}; do
echo -e "\nUpdating $i"
if [ -d "android-$i" ]; then
rsync -az --delete --exclude '*.git' ../prebuilts/gradle/$i/ ./android-$i/
cd ./android-$i/
git config user.name "google-automerger"
git config user.email automerger@google.com
git add .
git status
git commit -m "Auto-update"
git remote set-url origin "https://$token@github.com/googlesamples/android-$i.git"
git push origin master
#overwrite remote url to not contain auth token
git remote set-url origin "http://github.com/googlesamples/android-$i.git"
cd ..
else
echoerr "Something went wrong when cloning $i - result directory does not exist.
Leaving temp files in place for further examination."
deleteTemp=false;
fi
done
fi
#moves out of the temp folder, if we're in it.
if [ -d "../github-temp$folderPS" ]; then
cd ..
fi
##############################################################################
## If there's something new to upload, do the uploads
if [ ${#toUpload[@]} -ne 0 ] && $upload; then
for i in ${toUpload[@]}; do
echo -e "\nUploading $i"
repoName="googlesamples/android-$i"
CREATE="curl -H 'Authorization: token '$TOKEN \
-d '{\"name\":\"android-'$i'\", \"team_id\":889859}' \
https://api.github.com/orgs/googlesamples/repos"
eval $CREATE
#add secondary team permissions (robots)
ADDTEAM="curl -X PUT \
-H 'Authorization: token '$TOKEN \
-H 'Content-Length: 0' \
https://api.github.com/teams/889856/repos/$repoName"
eval $ADDTEAM
URL="https://$token@github.com/$repoName"
cd $i
git init
#overrides .gitconfig just for this project - does not alter your global settings.
git config user.name "google-automerger"
git config user.email automerger@google.com
git add .
git commit -m "Initial Commit"
git remote add origin $URL
git push origin master
cd ..
done
fi
else
echoerr "That token doesn't work. A test returned the code: $tokenTest"
fi
else
echo "User cancelled Github update."
fi
fi #end of "is there something to do?" if statement