Commit 0b6a0840 authored by maruel@chromium.org's avatar maruel@chromium.org

More work toward refactoring. Simplify LoadCurrentConfig() and convert most " with '.

Review URL: http://codereview.chromium.org/2807003

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@49789 0039d316-1c4b-4281-b951-d872f2087c98
parent 953586a1
......@@ -3,13 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A wrapper script to manage a set of client modules in different SCM.
This script is intended to be used to help basic management of client
program sources residing in one or more Subversion modules and Git
repositories, along with other modules it depends on, also in Subversion or Git,
but possibly on multiple respositories, making a wrapper system apparently
necessary.
"""Meta checkout manager supporting both Subversion and GIT.
Files
.gclient : Current client configuration, written by 'config' command.
......@@ -28,7 +22,7 @@ Hooks
.gclient and DEPS files may optionally contain a list named "hooks" to
allow custom actions to be performed based on files that have changed in the
working copy as a result of a "sync"/"update" or "revert" operation. This
could be prevented by using --nohooks (hooks run by default). Hooks can also
can be prevented by using --nohooks (hooks run by default). Hooks can also
be forced to run with the "runhooks" operation. If "sync" is run with
--force, all known hooks will run regardless of the state of the working
copy.
......@@ -55,7 +49,7 @@ Hooks
]
"""
__version__ = "0.4"
__version__ = "0.4.1"
import errno
import logging
......@@ -158,6 +152,7 @@ class GClientKeywords(object):
class Dependency(GClientKeywords):
"""Object that represents a dependency checkout."""
DEPS_FILE = 'DEPS'
def __init__(self, parent, name, url, safesync_url=None, custom_deps=None,
custom_vars=None, deps_file=None):
GClientKeywords.__init__(self)
......@@ -168,9 +163,9 @@ class Dependency(GClientKeywords):
self.safesync_url = safesync_url
self.custom_vars = custom_vars or {}
self.custom_deps = custom_deps or {}
self.deps_hooks = []
self.dependencies = []
self.deps_file = deps_file or self.DEPS_FILE
self._deps_hooks = []
# Sanity checks
if not self.name and self.parent:
......@@ -238,6 +233,7 @@ solutions = [
self.config_content = None
def SetConfig(self, content):
assert self.dependencies == []
config_dict = {}
self.config_content = content
try:
......@@ -262,37 +258,23 @@ solutions = [
s.get('custom_deps', {}),
s.get('custom_vars', {})))
# .gclient can have hooks.
self._deps_hooks = config_dict.get('hooks', [])
self.deps_hooks = config_dict.get('hooks', [])
def SaveConfig(self):
gclient_utils.FileWrite(os.path.join(self.root_dir(),
self._options.config_filename),
self.config_content)
def _LoadConfig(self):
client_source = gclient_utils.FileRead(
os.path.join(self.root_dir(), self._options.config_filename))
self.SetConfig(client_source)
@staticmethod
def LoadCurrentConfig(options, from_dir=None):
def LoadCurrentConfig(options):
"""Searches for and loads a .gclient file relative to the current working
dir.
Returns:
A dict representing the contents of the .gclient file or an empty dict if
the .gclient file doesn't exist.
"""
if not from_dir:
from_dir = os.curdir
path = os.path.realpath(from_dir)
while not os.path.exists(os.path.join(path, options.config_filename)):
split_path = os.path.split(path)
if not split_path[1]:
dir. Returns a GClient object."""
path = gclient_utils.FindGclientRoot(os.getcwd(), options.config_filename)
if not path:
return None
path = split_path[0]
client = GClient(path, options)
client._LoadConfig()
client.SetConfig(gclient_utils.FileRead(
os.path.join(path, options.config_filename)))
return client
def SetDefaultConfig(self, solution_name, solution_url, safesync_url):
......@@ -322,9 +304,6 @@ solutions = [
def _ReadEntries(self):
"""Read the .gclient_entries file for the given client.
Args:
client: The client for which the entries file should be read.
Returns:
A sequence of solution names, which will be empty if there is the
entries file hasn't been created yet.
......@@ -334,7 +313,7 @@ solutions = [
if not os.path.exists(filename):
return []
exec(gclient_utils.FileRead(filename), scope)
return scope["entries"]
return scope['entries']
def _ParseSolutionDeps(self, solution_name, solution_deps_content,
custom_vars, parse_hooks):
......@@ -391,7 +370,7 @@ solutions = [
# right 'self' to add the hooks.
for d in self.dependencies:
if d.name == solution_name:
d._deps_hooks.extend(local_scope['hooks'])
d.deps_hooks.extend(local_scope['hooks'])
break
# If use_relative_paths is set in the DEPS file, regenerate
......@@ -515,10 +494,10 @@ solutions = [
return
# Get any hooks from the .gclient file.
hooks = self._deps_hooks[:]
hooks = self.deps_hooks[:]
# Add any hooks found in DEPS files.
for d in self.dependencies:
hooks.extend(d._deps_hooks)
hooks.extend(d.deps_hooks)
# If "--force" was specified, run all hooks regardless of what files have
# changed. If the user is using git, then we don't know what files have
......@@ -571,14 +550,9 @@ solutions = [
def RunOnDeps(self, command, args):
"""Runs a command on each dependency in a client and its dependencies.
The module's dependencies are specified in its top-level DEPS files.
Args:
command: The command to use (e.g., 'status' or 'diff')
args: list of str - extra arguments to add to the command line.
Raises:
Error: If the client has conflicting entries.
"""
if not command in self.SUPPORTED_COMMANDS:
raise gclient_utils.Error("'%s' is an unsupported command" % command)
......@@ -834,14 +808,14 @@ def CMDcleanup(parser, args):
Mostly svn-specific. Simply runs 'svn cleanup' for each module.
"""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
# client dict, but more legible, and it might contain helpful comments.
......@@ -859,19 +833,19 @@ modules to operate on as well. If optional [url] parameter is
provided, then configuration is read from a specified Subversion server
URL.
"""
parser.add_option("--spec",
help="create a gclient file containing the provided "
"string. Due to Cygwin/Python brokenness, it "
"probably can't contain any newlines.")
parser.add_option("--name",
help="overrides the default name for the solution")
parser.add_option('--spec',
help='create a gclient file containing the provided '
'string. Due to Cygwin/Python brokenness, it '
'probably can\'t contain any newlines.')
parser.add_option('--name',
help='overrides the default name for the solution')
(options, args) = parser.parse_args(args)
if ((options.spec and args) or len(args) > 2 or
(not options.spec and not args)):
parser.error('Inconsistent arguments. Use either --spec or one or 2 args')
if os.path.exists(options.config_filename):
raise gclient_utils.Error("%s file already exists in the current directory"
raise gclient_utils.Error('%s file already exists in the current directory'
% options.config_filename)
client = GClient('.', options)
if options.spec:
......@@ -879,11 +853,11 @@ URL.
else:
base_url = args[0].rstrip('/')
if not options.name:
name = base_url.split("/")[-1]
name = base_url.split('/')[-1]
else:
# specify an alternate relpath for the given URL.
name = options.name
safesync_url = ""
safesync_url = ''
if len(args) > 1:
safesync_url = args[1]
client.SetDefaultConfig(name, base_url, safesync_url)
......@@ -893,17 +867,17 @@ URL.
def CMDexport(parser, args):
"""Wrapper for svn export for all managed directories."""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
(options, args) = parser.parse_args(args)
if len(args) != 1:
raise gclient_utils.Error("Need directory name")
raise gclient_utils.Error('Need directory name')
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
......@@ -924,14 +898,14 @@ dependencies, and performs minimal postprocessing of the output. The
resulting patch is printed to stdout and can be applied to a freshly
checked out tree via 'patch -p0 < patchfile'.
"""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
# client dict, but more legible, and it might contain helpful comments.
......@@ -941,14 +915,14 @@ checked out tree via 'patch -p0 < patchfile'.
def CMDstatus(parser, args):
"""Show modification status for every dependencies."""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
# client dict, but more legible, and it might contain helpful comments.
......@@ -968,41 +942,41 @@ def CMDstatus(parser, args):
""")
def CMDsync(parser, args):
"""Checkout/update all modules."""
parser.add_option("-f", "--force", action="store_true",
help="force update even for unchanged modules")
parser.add_option("-n", "--nohooks", action="store_true",
help="don't run hooks after the update is complete")
parser.add_option("-r", "--revision", action="append",
dest="revisions", metavar="REV", default=[],
help="Enforces revision/hash for the solutions with the "
"format src@rev. The src@ part is optional and can be "
"skipped. -r can be used multiple times when .gclient "
"has multiple solutions configured and will work even "
"if the src@ part is skipped.")
parser.add_option("-H", "--head", action="store_true",
help="skips any safesync_urls specified in "
"configured solutions and sync to head instead")
parser.add_option("-D", "--delete_unversioned_trees", action="store_true",
help="delete any unexpected unversioned trees "
"that are in the checkout")
parser.add_option("-R", "--reset", action="store_true",
help="resets any local changes before updating (git only)")
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option("-m", "--manually_grab_svn_rev", action="store_true",
help="Skip svn up whenever possible by requesting "
"actual HEAD revision from the repository")
parser.add_option('-f', '--force', action='store_true',
help='force update even for unchanged modules')
parser.add_option('-n', '--nohooks', action='store_true',
help='don\'t run hooks after the update is complete')
parser.add_option('-r', '--revision', action='append',
dest='revisions', metavar='REV', default=[],
help='Enforces revision/hash for the solutions with the '
'format src@rev. The src@ part is optional and can be '
'skipped. -r can be used multiple times when .gclient '
'has multiple solutions configured and will work even '
'if the src@ part is skipped.')
parser.add_option('-H', '--head', action='store_true',
help='skips any safesync_urls specified in '
'configured solutions and sync to head instead')
parser.add_option('-D', '--delete_unversioned_trees', action='store_true',
help='delete any unexpected unversioned trees '
'that are in the checkout')
parser.add_option('-R', '--reset', action='store_true',
help='resets any local changes before updating (git only)')
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
parser.add_option('-m', '--manually_grab_svn_rev', action='store_true',
help='Skip svn up whenever possible by requesting '
'actual HEAD revision from the repository')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.revisions and options.head:
# TODO(maruel): Make it a parser.error if it doesn't break any builder.
print("Warning: you cannot use both --head and --revision")
print('Warning: you cannot use both --head and --revision')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
......@@ -1017,14 +991,14 @@ def CMDupdate(parser, args):
def CMDdiff(parser, args):
"""Displays local diff for every dependencies."""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
# client dict, but more legible, and it might contain helpful comments.
......@@ -1034,33 +1008,33 @@ def CMDdiff(parser, args):
def CMDrevert(parser, args):
"""Revert all modifications in every dependencies."""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option("-n", "--nohooks", action="store_true",
help="don't run hooks after the revert is complete")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
parser.add_option('-n', '--nohooks', action='store_true',
help='don\'t run hooks after the revert is complete')
(options, args) = parser.parse_args(args)
# --force is implied.
options.force = True
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
return client.RunOnDeps('revert', args)
def CMDrunhooks(parser, args):
"""Runs hooks for files that have been modified in the local working copy."""
parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
help="override deps for the specified (comma-separated) "
"platform(s); 'all' will process all deps_os "
"references")
parser.add_option("-f", "--force", action="store_true", default=True,
help="Deprecated. No effect.")
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
help='override deps for the specified (comma-separated) '
'platform(s); \'all\' will process all deps_os '
'references')
parser.add_option('-f', '--force', action='store_true', default=True,
help='Deprecated. No effect.')
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
if options.verbose:
# Print out the .gclient file. This is longer than if we just printed the
# client dict, but more legible, and it might contain helpful comments.
......@@ -1073,10 +1047,10 @@ def CMDrunhooks(parser, args):
def CMDrevinfo(parser, args):
"""Output revision info mapping for the client and its dependencies.
This allows the capture of an overall "revision" for the source tree that
This allows the capture of an overall 'revision' for the source tree that
can be used to reproduce the same tree in the future. It is only useful for
"unpinned dependencies", i.e. DEPS/deps references without a svn revision
number or a git hash. A git branch name isn't "pinned" since the actual
'unpinned dependencies', i.e. DEPS/deps references without a svn revision
number or a git hash. A git branch name isn't 'pinned' since the actual
commit can change.
"""
parser.add_option('--deps', dest='deps_os', metavar='OS_LIST',
......@@ -1090,7 +1064,7 @@ def CMDrevinfo(parser, args):
(options, args) = parser.parse_args(args)
client = GClient.LoadCurrentConfig(options)
if not client:
raise gclient_utils.Error("client not configured; see 'gclient config'")
raise gclient_utils.Error('client not configured; see \'gclient config\'')
client.PrintRevInfo()
return 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment