oslo-incubator/tools/graduate.sh
Doug Hellmann 969b8c95b7 Add tool for helping with library graduation
This new script prepares a copy of the oslo-incubator repository
to house a stand-alone oslo library by revising the history,
retaining commits for files that are part of the new library and
discarding commits for files that are not. It then uses the
new oslo-cookiecutter library to inject any missing structural
files so the packaging and tests will work.

Change-Id: I1f513a773589f034975ae6ee54c5a418e4bfce25
2014-02-05 06:46:43 -08:00

133 lines
4.1 KiB
Bash
Executable File

#!/bin/bash
#
# Use this script to prune a copy of oslo-incubator when graduating
# modules to a brand new library.
#
# To use:
#
# 1. Clone a copy of the oslo-incubator repository to be manipulated.
# 2. Choose the new library name. For "oslo.foo", the argument to the
# script is "foo".
# 3. cd into the copy of oslo-incubator to be changed.
# 4. Run graduate.sh, passing the library name and the names of all
# directories and files to be saved (only code and tests, no project
# configuration):
#
# ../oslo-incubator/tools/graduate.sh foo openstack/common/foo.py tests/unit/test_foo.py ...
#
# 5. Clean up the results a bit by hand to make the tests work
# (update dependencies, etc.).
#
# Stop if there are any command failures
set -e
# FIXME(dhellmann): Need to pull templates from the right repo
COOKIECUTTER_TEMPLATE_REPO=https://github.com/dhellmann/oslo-cookiecutter.git
tmpdir=$(mktemp -d -t oslo-graduate.XXXX)
mkdir -p $tmpdir
logfile=$tmpdir/output.log
echo "Logging to $logfile"
# Redirect stdout/stderr to tee to write the log file
# (borrowed from verbose mode handling in devstack)
exec 1> >( awk '
{
cmd ="date +\"%Y-%m-%d %H:%M:%S \""
cmd | getline now
close("date +\"%Y-%m-%d %H:%M:%S \"")
sub(/^/, now)
print
fflush()
}' | tee "$logfile" ) 2>&1
function count_commits {
echo
echo "Have $(git log --oneline | wc -l) commits"
}
set -x
# Handle arguments
new_lib="$1"
shift
files_to_keep="$@"
# FIXME(dhellmann): Make sure they are not running the tool in the
# same copy of the repository where it lives.
# Set up a virtualenv with cookiecutter
echo "Installing cookiecutter..."
venv=$tmpdir/venv
virtualenv $venv
$venv/bin/python -m pip install cookiecutter
cookiecutter=$venv/bin/cookiecutter
# Build the grep pattern for ignoring files that we want to keep, so
# the prune script does not list them and cause them to be deleted.
keep_pattern="./\(.git\|$(echo $files_to_keep | sed -e 's/ /\\|/g')\)"
pruner="$tmpdir/pruner.sh"
cat >$pruner <<EOF
#!/bin/bash
find . -type f | grep -v "$keep_pattern"
EOF
chmod +x $pruner
# Filter out commits for unrelated files
echo "Pruning commits for unrelated files..."
git filter-branch --tree-filter 'git rm -f $('$pruner')' --prune-empty HEAD
# Find the earliest commit
earliest_commit=$(git log --format='format:%H' $files_to_keep | tail -1)
echo "Resetting git history to start with $earliest_commit"
git show --quiet $earliest_commit
count_commits
# Remove the parent of the earliest commit to make it the first one we
# will keep
echo "Resetting parent of $earliest_commit ..."
git filter-branch -f --parent-filter \
"test \$GIT_COMMIT = $earliest_commit && echo '' || cat" HEAD
count_commits
# Fix up dates, since we have touched the commits
echo "Fixing committer dates..."
git rebase --committer-date-is-author-date $(git log --format='format:%H' | tail -1)
# Fix up committer, since we have touched the commits
echo "Fixing committer name..."
git filter-branch -f --commit-filter \
'GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" git commit-tree "$@"' HEAD
# Move things around
echo "Moving files into place..."
git mv openstack oslo
git mv oslo/common oslo/$new_lib
# Fix imports after moving files
echo "Fixing imports..."
find . -name '*.py' -exec sed -i "s/openstack.common/oslo.${new_lib}/" {} \;
# Apply the cookiecutter template by building out a fresh copy using
# the name chosen for this library and then copying any parts of the
# results into the local tree, without overwriting files that already
# exist.
git clone $COOKIECUTTER_TEMPLATE_REPO $tmpdir/oslo-cookiecutter
# FIXME(dhellmann): We need a better non-interactive mode for cookiecutter
(cd $tmpdir && $cookiecutter $tmpdir/oslo-cookiecutter) <<EOF
$new_lib
openstack
oslo.${new_lib} library
EOF
rsync -a --verbose --ignore-existing $tmpdir/oslo.${new_lib}/ .
# Stage everything that we have changed so far, but do not commit
# because we don't know if it works.
git add .
echo "Now, you need to make the tests work and commit the results by hand."