Create a tool to save a pinned dep file for the current sync.

Review URL: http://codereview.chromium.org/2112003
This commit is contained in:
robotboy 2010-05-20 10:18:55 -07:00
parent d44550272c
commit fa08140093
2 changed files with 335 additions and 0 deletions

207
make_relative_solution Executable file
View File

@ -0,0 +1,207 @@
#!/usr/bin/python
#
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Generates a pinned solutions file with relative git repository URLs.
make_relative_solution reads a pinned solution file generated by
'gclient revinfo --snapshot' and writes to stdout a pinned solution file
with relative git repository URLs.
The resulting solution file can be used to check out a fixed version of
a gclient set of repositories. The base URL to fetch from can be changed
by editing one line in the generated solution file.
"""
import optparse
import sys
def ReadSnapshot(filename):
"""Reads a gclient revinfo snapshot file.
Minimal verification of the structure of the file is performed.
Args:
filename: The name of a snapshot file to read.
Returns:
The solutions array parsed from the snapshot file.
"""
env = {}
execfile(filename, env)
assert 'solutions' in env
assert env['solutions']
return env['solutions']
def BaseRepository(url):
"""Finds the base repository path.
This only works if the top level repository is not in a subdirectory relative
to the other repositories on the server.
Args:
url: git repository url
Returns:
The prefix of the URL that does not contain the repository name and SHA.
"""
base, versioned_repository = url.rsplit('/', 1)
assert base and versioned_repository
return base
def WriteBaseURL(base, solution):
print ' "%s": "%s",' % (solution['name'], base)
def IsRelativeRepository(base, url):
return url.startswith(base)
def RelativeRepository(base, url):
if IsRelativeRepository(base, url):
return url[len(base):]
else:
return url
def RelativeDep(base, dep):
path, repository = dep
return (path,
RelativeRepository(base, repository),
IsRelativeRepository(base, repository))
def RelativeDeps(base, solution):
return [RelativeDep(base, dep) for dep in solution['custom_deps'].items()]
def WritePinnedDep(name, dep, indent):
"""Writes a pinned dep.
The output is indented so that the URLs all line up for ease of reading. If
the dep is for a relative git repository then we emit the base_url lookup as
well.
Args:
name: The name of the solution that is being written out.
dep: The relative dep that is to be written out.
indent: The total number of characters to use for the path component.
Returns:
Nothing
"""
path, repository, relative = dep
remainder = path.partition('/')[2]
spaces = indent - len(path)
if remainder == 'deps':
return
if relative:
print ' "%s": %*sbase_url["%s"] + "%s",' % (path,
spaces, '',
name,
repository)
else:
print ' "%s": %*s"%s",' % (path,
spaces, '',
repository)
def WritePinnedSolution(solution):
"""Writes out a pinned and solution file with relative repository paths.
The relative repository paths make it easier for a user to modify where
they are pulling source from.
Args:
solution: gclient solution object.
Returns:
Nothing
"""
base = BaseRepository(solution['url'])
url = RelativeRepository(base, solution['url'])
deps = RelativeDeps(base, solution)
indent = max(len(dep[0]) for dep in deps)
deps.sort(key=lambda dep: dep[1])
print (' { "name" : "%s",\n'
' "url" : base_url["%s"] + "%s",\n'
' "custom_deps" : {') % (solution['name'],
solution['name'],
url)
for dep in deps:
WritePinnedDep(solution['name'], dep, indent)
print (' },\n'
' },')
def main(argv):
usage = 'Usage: %prog [options] filename'
option_parser = optparse.OptionParser(usage=usage)
option_parser.disable_interspersed_args()
option_parser.add_option('-s', '--substitute',
action='store_true',
dest='substitute',
default=False,
help='substitute a new base git URL')
option_parser.add_option('-b', '--base',
dest='base',
default='http://src.chromium.org/git',
metavar='URL',
help='base git URL to substitute [%default]')
options, args = option_parser.parse_args(argv[1:])
if len(args) != 1:
option_parser.print_help()
return 1
filename = args.pop(0)
solutions = ReadSnapshot(filename)
print ('#\n'
'# Autogenerated pinned gclient solution file. This file was\n'
'# created by running make_relative_solution.\n'
'#\n'
'\n'
'base_url = {')
for solution in solutions:
if options.substitute:
base = options.base
else:
base = BaseRepository(solution['url'])
WriteBaseURL(base, solution)
print ('}\n'
'\n'
'solutions = [')
for solution in solutions:
WritePinnedSolution(solution)
print ']\n'
if __name__ == '__main__':
main(sys.argv)

128
save_pinned_deps Executable file
View File

@ -0,0 +1,128 @@
#!/bin/bash
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Save the current state of the tree into a pinned deps file that can later
# be used to reconstruct the same tree.
# Load common constants. This should be the first executable line.
# The path to common.sh should be relative to your script's location.
. "$(dirname "$0")/common.sh"
# Script must be run outside the chroot, I am not sure why this is but inside
# the chroot "gclient" is aliased to a warning about using gclient in the
# chroot.
assert_outside_chroot
# Flags
BASE_URL="http://src.chromium.org/git"
DEFINE_string depfile "" "The path to the depfile to create."
DEFINE_boolean commit ${FLAGS_FALSE} "Commit the resulting depfile."
DEFINE_boolean substitute ${FLAGS_FALSE} "Substitute a new base git URL."
DEFINE_string base ${BASE_URL} "Base git URL to substitute"
# Parse command line
FLAGS_HELP="usage: $0 [flags]"
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
check_flags_only_and_allow_null_arg "$@" && set --
# Die on any errors.
set -e
if [ -z "$FLAGS_depfile" ] ; then
echo "Error: --depfile is required."
exit 1
fi
DEPPATH="${GCLIENT_ROOT}/deps"
DEPFILE="${DEPPATH}/${FLAGS_depfile}"
TEMPFILE=$(tempfile)
DIRNAME=$(dirname "${DEPFILE}")
FILENAME=$(basename "${DEPFILE}")
cleanup() {
# Disable die on error.
set +e
if [ -f "${TEMPFILE}" ]; then
rm "${TEMPFILE}"
fi
if [ -f "${DEPFILE}" ]; then
rm "${DEPFILE}"
fi
# Turn die on error back on.
set -e
}
reset_repository() {
echo "Resetting DEPS repository"
pushd "${DEPPATH}"
[ -d ".git" ] || die "${DEPPATH} is not a git repository."
git reset --hard origin/master
popd
}
generate_depfile() {
echo "Writing pinned DEPS file to ${DEPFILE}"
mkdir -p "${DIRNAME}"
gclient revinfo --snapshot > "${TEMPFILE}"
ARGS=""
if [[ $FLAGS_substitute -eq $FLAGS_TRUE ]]; then
ARGS="${ARGS} -s -b ${FLAGS_base}"
fi
ARGS="${ARGS} ${TEMPFILE}"
"${SCRIPTS_DIR}/make_relative_solution" ${ARGS} > ${DEPFILE}
rm -f "${TEMPFILE}"
}
commit_depfile() {
echo "Commiting pinned DEPS file"
pushd "${DEPPATH}"
git add "${FLAGS_depfile}"
git commit -m "Automated buildbot update of pinned DEPS file."
git reset --hard HEAD
git clean -f
git remote update
git rebase -s ours origin/master
git push
popd
}
#
# Generate a pinned deps file from the current gclient sync and check it into
# the deps.git repository.
#
trap "cleanup" EXIT
if [[ $FLAGS_commit -eq $FLAGS_TRUE ]]; then
reset_repository
fi
generate_depfile
if [[ $FLAGS_commit -eq $FLAGS_TRUE ]]; then
commit_depfile
fi
trap - EXIT