From f82400b43224327b79e85843fd6f30fc838b10c7 Mon Sep 17 00:00:00 2001
From: Jeremy Stanley <fungi@yuggoth.org>
Date: Wed, 24 Jun 2015 20:29:03 +0000
Subject: [PATCH] Allow source-repositories ref to be "*"

Passing a source-repositories ref of "*" should signal fetching all
heads similar to when a non-cached ref is requested. Reuse the same
fallback logic, but skip unnecessary checks since "*" is not a real
refname. Also expand the fallback to update tags, and to --purge
local refs that no longer exist on the remote for additional safety.

Change-Id: I4562c9689a8d235ebe09b2f7178aa5890dbc85f1
---
 elements/source-repositories/README.rst       |  3 +-
 .../extra-data.d/98-source-repositories       | 30 ++++++++++++-------
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/elements/source-repositories/README.rst b/elements/source-repositories/README.rst
index b60392675..41e6dad37 100644
--- a/elements/source-repositories/README.rst
+++ b/elements/source-repositories/README.rst
@@ -9,7 +9,8 @@ from git and pbr from a tarball would be
 *File : elements/custom-element/source-repository-ironic*
 
     #<name> <type> <destination> <location> [<ref>]
-    # <ref> defaults to master if not specified
+    # <ref> defaults to master if not specified.
+    # A value of "*" prunes and fetches all heads and tags.
     ironic git /usr/local/ironic git://git.openstack.org/openstack/ironic.git
 
 *File : elements/custom-element/source-repository-pbr*
diff --git a/elements/source-repositories/extra-data.d/98-source-repositories b/elements/source-repositories/extra-data.d/98-source-repositories
index 8121f0865..17228039f 100755
--- a/elements/source-repositories/extra-data.d/98-source-repositories
+++ b/elements/source-repositories/extra-data.d/98-source-repositories
@@ -118,12 +118,14 @@ function get_repos_for_element(){
                     mv ${CACHE_PATH}{.tmp,}
                 fi
 
-                HAS_REF=$(git --git-dir=$CACHE_PATH/.git name-rev $REPOREF 2>/dev/null || true)
+                if [ "$REPOREF" != "*" ] ; then
+                    HAS_REF=$(git --git-dir=$CACHE_PATH/.git name-rev $REPOREF 2>/dev/null || true)
+                fi
                 if [ -z "$DIB_OFFLINE" -o -z "$HAS_REF" ] ; then
                     echo "Updating cache of $REPOLOCATION in $CACHE_PATH with ref $REPOREF"
                     # Copy named refs (which might be outside the usual heads
                     # pattern) - e.g. gerrit
-                    if ! git --git-dir=$CACHE_PATH/.git fetch --update-head-ok $REPOLOCATION \
+                    if [ "$REPOREF" == "*" ] || ! git --git-dir=$CACHE_PATH/.git fetch --update-head-ok $REPOLOCATION \
                             +${REPOREF}:${REPOREF} ; then
                         # Copy all heads from the remote repository - this permits
                         # using a SHA1 object reference so long as the object
@@ -131,11 +133,13 @@ function get_repos_for_element(){
                         # not permit arbitrary sha fetching from remote servers.
                         # This is a separate fetch to the prior one as the prior
                         # one will fail when REPOREF is a SHA1.
-                        git --git-dir=$CACHE_PATH/.git fetch --update-head-ok $REPOLOCATION \
-                            +refs/heads/*:refs/heads/*
+                        git --git-dir=$CACHE_PATH/.git fetch --prune --update-head-ok $REPOLOCATION \
+                            +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/*
                     fi
                     # Ensure that we have a reference to the revision.
-                    git --git-dir=$CACHE_PATH/.git rev-parse -q --verify $REPOREF^{commit}
+                    if [ "$REPOREF" != "*" ] ; then
+                        git --git-dir=$CACHE_PATH/.git rev-parse -q --verify $REPOREF^{commit}
+                    fi
                 fi
 
                 echo "Cloning from $REPONAME cache and applying ref $REPOREF"
@@ -145,7 +149,7 @@ function get_repos_for_element(){
                     if [[ "$CACHE_PATH" != "$DESIRED" ]]; then
                         echo "REPOLOCATIONS don't match ("$CACHE_PATH" != "$DESIRED")" >&2
                         exit 1
-                    else
+                    elif [[ "$REPOREF" != "*" ]]; then
                         pushd $REPO_DEST
                         # When we first clone we create a branch naming what we fetched
                         # that must match, or we are asking for two different references from the
@@ -159,10 +163,16 @@ function get_repos_for_element(){
                 else
                     sudo git clone $CACHE_PATH $REPO_DEST
                     pushd $REPO_DEST
-                    sudo git fetch $CACHE_PATH $REPOREF:fetch_$REPOREF
-                    sudo git reset --hard FETCH_HEAD
-                    # Get the sha in use
-                    git_sha=$(git rev-parse FETCH_HEAD)
+                    if [[ "$REPOREF" == "*" ]]; then
+                        sudo git fetch --prune --update-head-ok $CACHE_PATH \
+                            +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/*
+                        git_sha=$(git rev-parse HEAD)
+                    else
+                        sudo git fetch $CACHE_PATH $REPOREF:fetch_$REPOREF
+                        sudo git reset --hard FETCH_HEAD
+                        # Get the sha in use
+                        git_sha=$(git rev-parse FETCH_HEAD)
+                    fi
                     popd
 
                     # Write the sha being used into the source-repositories manifest