#!/bin/bash -e # Sets up everything for git to work with the ICEDUST GitLab repository ############################################################################## # Pre-setup ############################################################################## case `uname` in Darwin) ECHO="echo" ;; *) ECHO="echo -e" ;; esac # colors and formatting RED='\033[31m' NORMAL='\033[0m' verbose () { if [ "${#VERBOSE}" -ge ${#1} ]; then shift; $@ fi } print(){ local flag="$1"; shift verbose $flag $ECHO $@ } function TakeBreak(){ if [ -n "$CatchBreath" ];then if [ -n "$1" ];then $ECHO "Just catching my breath for $CatchBreath seconds" ; fi sleep $CatchBreath fi } # Git 1.7.x does not support a leading slash in .gitignore and .git/info/sparse-checkout case `git --version` in git\ version\ 1.7*) LEADING_SLASH= ;; *) LEADING_SLASH=/ ;; esac # Get the directory name for the repository scripts RepositoryDirectoryFull="`dirname "$(readlink -f "$0")"`" RepositoryDirectory="$(basename "$RepositoryDirectoryFull")" # Hard coding the ICEDUST blessed repository URL GitLabURL=git@gitlab.in2p3.fr IcedustBlessed=$GitLabURL:comet IcedustPackagesRepo=ICEDUST_packages.git ExternalOptions=( source ) usage () { $ECHO "git icedust-setup [options] [packages_release]" $ECHO $ECHO "Options:" $ECHO "-h, --help \tThis help message" $ECHO $ECHO "-H, --home \tProvide ICEDUST_HOME directory" $ECHO "-P, --project \tInitialises a new project. If PROJECT matches a file in $RepositoryDirectory/projects, " $ECHO "-G, --gitlab \tThe username for your GitLab account" $ECHO " \t the contents of that file is used to specify which packages the project depends on." $ECHO "-E, --externals \tSpecify the way to provide externals packages. Can be one of: ${!ExternalOptions[@]}" $ECHO " --fork-blessed \tDo not print out progress" $ECHO " --skip-update \tSet to OFF to skip checking if the repository scripts should be updated (not recommended)." $ECHO "-b, --catch-breath \tPause between git remote accesses." $ECHO $ECHO "-v \tMake output more verbose" $ECHO "-d, --debug \tEnable debug output" $ECHO " --check \tRun additional checks on the status of the user repository" $ECHO "-q, --quiet, -z \tDo not print out progress" exit $1 } # Avoid asking for password for 1 hour GIT_CREDENTIAL_CACHE="`git config --get credential.cache || true`" if [ "X$GIT_CREDENTIAL_CACHE" = X ]; then case `uname` in Darwin*) git config --global --add credential.cache osxkeychain ;; Linux*) git config --global --add credential.cache "cache --timeout=3600 --socket $TMPDIR/.git-credential-cache-socket" ;; esac fi ############################################################################## # Parse options ############################################################################## CHECK= ICEDUST_PACKAGES_TAG="" ICEDUST_EXTERNALS_TAG="" ICEDUST_PROJECT="$ICEDUST_PROJECT" GITLAB_USERNAME= ICEDUST_HOME="$ICEDUST_HOME" EXTERNALS=source VERBOSE=v VERBOSE_STREAM=/dev/stderr DEBUG_STREAM=/dev/null FORK_BLESSED=false SkipUpdate="$SkipUpdate" UseDebug="" CatchBreath="0.5" while [ "$#" != 0 ]; do case "$1" in -h | --help ) usage 0;; -b | --catch-breath ) shift; CatchBreath="$1" shift ;; -H | --home ) shift; ICEDUST_HOME="$1" shift ;; -G | --gitlab ) shift; GITLAB_USERNAME="$1" shift ;; -P | --project ) shift; ICEDUST_PROJECT="$1" shift ;; --check ) shift; CHECK=true ;; -E | --externals ) shift; EXTERNALS="$1";shift ;; -d | --debug ) shift; UseDebug="-d"; set -x; DEBUG_STREAM=/dev/stderr ;; -v ) shift; VERBOSE=v$VERBOSE ;; -q | --quiet | -z ) shift; set +x; VERBOSE=; VERBOSE_STREAM=/dev/null ;; --fork-blessed ) shift; FORK_BLESSED=true;; --skip-update ) shift; SkipUpdate="`tr 'a-z' 'A-Z' <<<$1`"; shift;; -*) $ECHO Unknown option $1 ; usage 1 ;; *) if [ -z "$ICEDUST_PACKAGES_TAG" ] && [ -n "$1" ]; then ICEDUST_PACKAGES_TAG="$1" elif [ -z "$ICEDUST_EXTERNALS_TAG" ] && [ -n "$1" ]; then ICEDUST_EXTERNALS_TAG="$1" fi shift 1 ;; esac done IcedustExternalsRepo="" Found=false for opt in ${ExternalOptions[@]};do if [[ "$opt" == $EXTERNALS ]];then Found=true; break; fi done if ! $Found ;then $ECHO "Error: $EXTERNALS is not a valid option. Must be one of: ${ExternalOptions[@]}" exit 1 else IcedustExternalsRepo=ICEDUST_externals_$EXTERNALS.git fi unset Found unset opt ############################################################################## # Check Git configuration ############################################################################## # Gitlab can be set here by a comand line option, or else already exist in the # global config if [ -z "$GITLAB_USERNAME" ];then GITLAB_USERNAME="`git config --get user.gitlab || true`" else git config --global user.gitlab "$GITLAB_USERNAME" fi USER_FULLNAME="`git config --get user.name || true`" USER_EMAIL="`git config --get user.email || true`" if ! $FORK_BLESSED && ( [ -z "$GITLAB_USERNAME" ] || [ -z "$USER_FULLNAME" ] || [ -z "$USER_EMAIL" ] ); then $ECHO "Cannot find your details in the git configuration." if [ "X$USER_FULLNAME" = X ]; then $ECHO $ECHO "Please set up your full name via:" $ECHO $ECHO " git config --global user.name ' '" $ECHO fi if [ "X$USER_EMAIL" = X ]; then $ECHO $ECHO "Please set up your email via:" $ECHO $ECHO " git config --global user.email ''" $ECHO fi if [ "X$GITLAB_USERNAME" = X ]; then $ECHO $ECHO "Please set up your GitLab user name via:" $ECHO $ECHO " git config --global user.gitlab " $ECHO $ECHO "Or run this again with -G " fi exit 1 fi ############################################################################## # Check we've got all the ICEDUST vars ############################################################################## tmp="`git icedust-home $UseDebug "$ICEDUST_HOME" "$ICEDUST_PROJECT"||true`" # Check if there was an issue getting the variables if grep 'Error' <<< "$tmp" &> "$DEBUG_STREAM" ;then $ECHO $tmp $ECHO "icedust-setup: Error: Problem with ICEDUST_HOME and ICEDUST_PROJECT variables (see above messge)." $ECHO "Current values: " $ECHO " ICEDUST_HOME=$ICEDUST_HOME" $ECHO " ICEDUST_PROJECT=$ICEDUST_PROJECT" exit 1 fi ICEDUST_HOME=`sed 's!^.*ICEDUST_HOME=\([^;]\+\);.*!\1!' <<<$tmp` ICEDUST_PROJECT=`sed 's!^.*ICEDUST_PROJECT=\([^;]*\);.*!\1!' <<<$tmp` unset tmp #echo ICEDUST_HOME = $ICEDUST_HOME #echo ICEDUST_PROJECT = $ICEDUST_PROJECT IcedustPackageDirectory="$ICEDUST_HOME/$ICEDUST_PROJECT/packages" IcedustExternalDirectory="$IcedustPackageDirectory/EXTERNALS" TimeCache="$ICEDUST_HOME/$ICEDUST_PROJECT/.gitlab_access_times" touch "$TimeCache" ############################################################################## # Too many remote accesses and we crash so only do it if we haven't done for a long time ############################################################################## function GitRemoteAccess(){ GitDir="$1"; shift SubCommand="$1" Commands=( "${@}" ) # Have we recently tried to access this repository with any command? LastTimeAnySub="`grep '^'"\S* $GitDir" "$TimeCache" | awk '{ max=max>$3?max:$3} END{print max}'`" CurrentTime=`date +%s` if [ -n "$LastTimeAnySub" ] && [ "$((CurrentTime-LastTimeAnySub))" -lt 300 ];then sleep $CatchBreath fi # Get the last time this subcommand was ran LastTimeThisSub="`grep '^'"$SubCommand $GitDir" "$TimeCache" | awk '{print $3}'`" CurrentTime=`date +%s` if [ -z "$LastTimeThisSub" ] || [ "$((CurrentTime-LastTimeThisSub))" -gt 300 ];then if [ -z "$LastTimeThisSub" ];then echo $SubCommand $GitDir $CurrentTime >> "$TimeCache" else sed -i -e 's!^\('"$SubCommand $GitDir"'\) .*$!\1 '"$CurrentTime"'!' "$TimeCache" fi git "${Commands[@]}" return $? fi return 0 } ############################################################################## # Check remote repositories exist ############################################################################## function CheckGitLabRepo(){ local _Repository="$1"; shift local _quiet="$1"; shift local _Cleaned="`sed -e 's!ICEDUST_!!' -e 's!\.git$!!' -e 's![^/]*/!!' <<< "$_Repository"` " if ! GitRemoteAccess "$_Cleaned" ls-remote ${GitLabURL}:$_Repository &> $DEBUG_STREAM ;then [ -z "$_quiet" ] && $ECHO "Unable to access the remote GitLab repository: $_Repository" return 1 fi return 0 } ############################################################################## # Function to be called for the first time we setup ############################################################################## function FirstTimeSetupPackages(){ print v Packages will be located in $IcedustPackageDirectory # We need to be able to reach the users remote repo FailedUserRepo=false FailedBlessedRepo=false if ! CheckGitLabRepo $GITLAB_USERNAME/$IcedustPackagesRepo ;then FailedUserRepo=true fi if $FORK_BLESSED && ! CheckGitLabRepo comet/$IcedustPackagesRepo ;then FailedBlessedRepo=true fi if ( $FailedUserRepo && ! $FORK_BLESSED ) || ( $FailedBlessedRepo && $FORK_BLESSED ); then $ECHO "Cannot setup git with ICEDUST. Make sure you have: " $ECHO " * Correctly supplied git with the correct gitlab username " $ECHO " * Given the right password when prompted " $ECHO " * Set-up ssh keys with GitLab. See https://gitlab.in2p3.fr/help/ssh/ssh.md for how to do this " if $FORK_BLESSED; then $ECHO " * Forked the main repository into your user account " $ECHO " " $ECHO " You can skip this last requirement by running with the '--fork-blessed' option, but you will not be able to push anywhere, " $ECHO " so your changes will only remain local since the ICEDUST policy is that you can only push to a fork of the 'Blessed Repo'. " fi $ECHO "" $ECHO "NOTE: Sometimes too many connections to IN2P3 can cause this error. " $ECHO "Try running the command again and if you still get this problem, check the above points." exit 1 fi # Now clone the repository RemoteName= CloneTarget= OtherRemoteName= OtherCloneTarget= if $FailedUserRepo; then CloneTarget=$IcedustBlessed RemoteName=official-icedust OtherCloneTarget=${GitLabURL}:$GITLAB_USERNAME OtherRemoteName=my-icedust $ECHO "Will clone from the Blessed repository" else CloneTarget=${GitLabURL}:$GITLAB_USERNAME RemoteName=my-icedust OtherCloneTarget=$IcedustBlessed OtherRemoteName=official-icedust print v "Cloning user's repository" fi GitRemoteAccess packages clone --no-checkout --origin $RemoteName $CloneTarget/$IcedustPackagesRepo "$IcedustPackageDirectory" cd "$IcedustPackageDirectory" TakeBreak git remote add $OtherRemoteName $OtherCloneTarget/$IcedustPackagesRepo # Prepare the tag / branch we'll checkout in a minute if [ -z "$ICEDUST_PACKAGES_TAG" ];then ICEDUST_PACKAGES_TAG=master fi } function FirstTimeSetupExternals(){ TakeBreak # Get the externals down print Externals will be located in $IcedustExternalDirectory GitRemoteAccess externals clone --no-checkout $IcedustBlessed/$IcedustExternalsRepo "$IcedustExternalDirectory" cd "$IcedustPackageDirectory" # Prepare the tag / branch we'll checkout in a minute if [ -z "$ICEDUST_EXTERNALS_TAG" ];then ICEDUST_EXTERNALS_TAG=master fi } ############################################################################## # Setup things when this is not the first time ############################################################################## function NthTimeSetupPackages(){ if [ "$SkipUpdate" != ALL ] && [ "$SkipUpdate" != PACKAGES ];then TakeBreak GitRemoteAccess packages remote update fi # Prepare the tag / branch we'll checkout in a minute if [ -z "$ICEDUST_PACKAGES_TAG" ];then local tmp="$(git symbolic-ref -q HEAD)" if [ 0 -eq "$?" ] && [ -n "$tmp" ] ;then ICEDUST_PACKAGES_TAG=`basename "$tmp"` fi fi } function NthTimeSetupExternals(){ # Get the externals down if [ "$SkipUpdate" != ALL ] && [ "$SkipUpdate" != EXTERNALS ];then TakeBreak GitRemoteAccess externals fetch origin --tags fi } ############################################################################## # Setup a git version controlled directory ############################################################################## function SetupDirectory(){ cd "$1"; shift local IcedustTag="$1"; shift git config core.sparsecheckout true SparseFile=.git/info/sparse-checkout local FirstTime=False if [ ! -e "$SparseFile" ];then FirstTime=True echo "${LEADING_SLASH}.gitignore" > "$SparseFile" fi echo "Setting up directory '$PWD' at tag: '$IcedustTag'" if [ -n "$IcedustTag" ];then git checkout "$IcedustTag" &> "$DEBUG_STREAM" fi git read-tree -m -u HEAD #$FirstTime && git read-tree -m -u HEAD } ############################################################################## # Check if we should update the repository scripts ############################################################################## function CheckRepositoryScripts(){ if ! CheckGitLabRepo comet/ICEDUST_repository quiet ;then print v "Unable to access the remote repository for ICEDUST_repository. You can continue, but the scripts might be out-of-date." return fi ( cd "$RepositoryDirectoryFull" GitRemoteAccess repository fetch -q # Check for the upstream of the current branch if ! git rev-parse @{u} 2>&1 >> "$DEBUG_STREAM" ;then $ECHO "This is weird, there's no upstream branch set for ICEDUST_repository." $ECHO "Set one up and try again..." exit 1 fi # See if there are any incoming changes local N_commits="`git rev-list HEAD..@{u} |wc -l`" if [ "$N_commits" -gt 0 ];then $ECHO "Your ICEDUST_repository directory is out-of-date ($N_commits commit(s) behind)." $ECHO "To continue, either update it (recommended) or run with --skip-update repository" $ECHO "" $ECHO "To update, do:" $ECHO " cd $RepositoryDirectoryFull" $ECHO " git pull" $ECHO "" exit 1 fi ) } ############################################################################## # Main body ############################################################################## # Check that the repository scipts are up to date if [ "$SkipUpdate" == ALL ] || [ "$SkipUpdate" == REPOSITORY ];then $ECHO "WARNING: Update check for the ICEDUST_repository scripts has been disabled " else CheckRepositoryScripts fi # Check we know what project to work with if [ -z "$ICEDUST_PROJECT" ];then $ECHO "Couldn't deduce ICEDUST_PROJECT so I cannot set things up" exit 1 fi # Check the project has a package directory FirstTime= if [ ! -d "$IcedustPackageDirectory/.git" ]; then FirstTimeSetupPackages NthTimeSetupPackages FirstTime=true else cd "$IcedustPackageDirectory" FirstTime=false NthTimeSetupPackages fi # Check the project has an externals directory if [ ! -d "$IcedustExternalDirectory/.git" ]; then FirstTime=true FirstTimeSetupExternals else cd "$IcedustExternalDirectory" NthTimeSetupExternals fi SetupDirectory "$IcedustPackageDirectory" "$ICEDUST_PACKAGES_TAG" SetupDirectory "$IcedustExternalDirectory" "$ICEDUST_EXTERNALS_TAG" cd "$IcedustPackageDirectory" NewProject= # make sure we have a cmt directory for this project ProjectCmtDir="$ICEDUST_HOME/$ICEDUST_PROJECT/cmt" if [ ! -d "$ProjectCmtDir" ];then mkdir "$ProjectCmtDir" echo project $ICEDUST_PROJECT > "$ProjectCmtDir/requirements" echo v999 > "$ProjectCmtDir/version.cmt" fi if [ -e "$RepositoryDirectoryFull/projects/$ICEDUST_PROJECT" ];then NewProject=false git icedust-add $UseDebug --skip-setup -D -f "$RepositoryDirectoryFull/projects/$ICEDUST_PROJECT" else NewProject=true fi if $FirstTime ;then print v "Configured ICEDUST with git..." fi print v "ICEDUST is currently setup as:" verbose v git icedust-describe $UseDebug if $FirstTime && $NewProject ;then $ECHO " " $ECHO " Since you chose to make a new project, '$ICEDUST_PROJECT', you have been " $ECHO " left with an empty packages and EXTERNALS directory. To fill this with " $ECHO " packages do:" $ECHO " " $ECHO " cd $ICEDUST_PROJECT " $ECHO " git icedust-add -D SOME_PACKAGE " $ECHO " " fi