| Index: gclient.py
|
| diff --git a/gclient.py b/gclient.py
|
| index f425d1da33c804a285e6369a3c36bfe3cbebe471..e7672a14b5de59ba8b63e08b00f9cab7a64b1e5a 100644
|
| --- a/gclient.py
|
| +++ b/gclient.py
|
| @@ -55,7 +55,7 @@ Hooks
|
| ]
|
| """
|
|
|
| -__version__ = "0.4"
|
| +__version__ = "0.3.7"
|
|
|
| import errno
|
| import logging
|
| @@ -73,6 +73,22 @@ import gclient_scm
|
| import gclient_utils
|
| from third_party.repo.progress import Progress
|
|
|
| +# default help text
|
| +DEFAULT_USAGE_TEXT = (
|
| +"""%prog <subcommand> [options] [--] [SCM options/args...]
|
| +a wrapper for managing a set of svn client modules and/or git repositories.
|
| +Version """ + __version__ + """
|
| +
|
| +Options and extra arguments can be passed to invoked SCM commands by
|
| +appending them to the command line. Note that if the first such
|
| +appended option starts with a dash (-) then the options must be
|
| +preceded by -- to distinguish them from gclient options.
|
| +
|
| +For additional help on a subcommand or examples of usage, try
|
| + %prog help <subcommand>
|
| + %prog help files
|
| +""")
|
| +
|
|
|
| def attr(attr, data):
|
| """Sets an attribute on a function."""
|
| @@ -454,8 +470,6 @@ solutions = [
|
| def _RunHookAction(self, hook_dict, matching_file_list):
|
| """Runs the action from a single hook.
|
| """
|
| - logging.info(hook_dict)
|
| - logging.info(matching_file_list)
|
| command = hook_dict['action'][:]
|
| if command[0] == 'python':
|
| # If the hook specified "python" as the first item, the action is a
|
| @@ -799,15 +813,19 @@ solutions = [
|
| print(snapclient._config_content)
|
|
|
|
|
| -#### gclient commands.
|
| +## gclient commands.
|
| +
|
|
|
| +def CMDcleanup(parser, options, args):
|
| + """Clean up all working copies, using 'svn cleanup' for each module.
|
|
|
| -def CMDcleanup(parser, args):
|
| - """Cleans up all working copies.
|
| +Additional options and args may be passed to 'svn cleanup'.
|
|
|
| -Mostly svn-specific. Simply runs 'svn cleanup' for each module.
|
| +usage: cleanup [options] [--] [svn cleanup args/options]
|
| +
|
| +Valid options:
|
| + --verbose : output additional diagnostics
|
| """
|
| - (options, args) = parser.parse_args(args)
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -818,23 +836,32 @@ Mostly svn-specific. Simply runs 'svn cleanup' for each module.
|
| return client.RunOnDeps('cleanup', args)
|
|
|
|
|
| -@attr('usage', '[url] [safesync url]')
|
| -def CMDconfig(parser, args):
|
| +def CMDconfig(parser, options, args):
|
| """Create a .gclient file in the current directory.
|
|
|
| -This specifies the configuration for further commands. After update/sync,
|
| +This specifies the configuration for further commands. After update/sync,
|
| top-level DEPS files in each module are read to determine dependent
|
| -modules to operate on as well. If optional [url] parameter is
|
| +modules to operate on as well. If optional [url] parameter is
|
| provided, then configuration is read from a specified Subversion server
|
| -URL.
|
| +URL. Otherwise, a --spec option must be provided. A --name option overrides
|
| +the default name for the solutions.
|
| +
|
| +usage: config [option | url] [safesync url]
|
| +
|
| +Valid options:
|
| + --name path : alternate relative path for the solution
|
| + --spec=GCLIENT_SPEC : contents of .gclient are read from string parameter.
|
| + *Note that due to Cygwin/Python brokenness, it
|
| + probably can't contain any newlines.*
|
| +
|
| +Examples:
|
| + gclient config https://gclient.googlecode.com/svn/trunk/gclient
|
| + configure a new client to check out gclient.py tool sources
|
| + gclient config --name tools https://gclient.googlecode.com/svn/trunk/gclient
|
| + gclient config --spec='solutions=[{"name":"gclient",
|
| + '"url":"https://gclient.googlecode.com/svn/trunk/gclient",'
|
| + '"custom_deps":{}}]'
|
| """
|
| - 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 len(args) < 1 and not options.spec:
|
| raise gclient_utils.Error("required argument missing; see 'gclient help "
|
| "config'")
|
| @@ -859,9 +886,8 @@ URL.
|
| return 0
|
|
|
|
|
| -def CMDexport(parser, args):
|
| +def CMDexport(parser, options, args):
|
| """Wrapper for svn export for all managed directories."""
|
| - (options, args) = parser.parse_args(args)
|
| if len(args) != 1:
|
| raise gclient_utils.Error("Need directory name")
|
| client = GClient.LoadCurrentConfig(options)
|
| @@ -876,19 +902,30 @@ def CMDexport(parser, args):
|
| return client.RunOnDeps('export', args)
|
|
|
|
|
| -@attr('epilog', """Example:
|
| - gclient pack > patch.txt
|
| - generate simple patch for configured client and dependences
|
| -""")
|
| -def CMDpack(parser, args):
|
| +def CMDpack(parser, options, args):
|
| """Generate a patch which can be applied at the root of the tree.
|
|
|
| -Internally, runs 'svn diff'/'git diff' on each checked out module and
|
| +Internally, runs 'svn diff' on each checked out module and
|
| 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'.
|
| +checked out tree via 'patch -p0 < patchfile'. Additional args and
|
| +options to 'svn diff' can be passed after gclient options.
|
| +
|
| +usage: pack [options] [--] [svn args/options]
|
| +
|
| +Valid options:
|
| + --verbose : output additional diagnostics
|
| +
|
| +Examples:
|
| + gclient pack > patch.txt
|
| + generate simple patch for configured client and dependences
|
| + gclient pack -- -x -b > patch.txt
|
| + generate patch using 'svn diff -x -b' to suppress
|
| + whitespace-only differences
|
| + gclient pack -- -r HEAD -x -b > patch.txt
|
| + generate patch, diffing each file versus the latest version of
|
| + each module
|
| """
|
| - (options, args) = parser.parse_args(args)
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -899,9 +936,17 @@ checked out tree via 'patch -p0 < patchfile'.
|
| return client.RunOnDeps('pack', args)
|
|
|
|
|
| -def CMDstatus(parser, args):
|
| - """Show modification status for every dependencies."""
|
| - (options, args) = parser.parse_args(args)
|
| +def CMDstatus(parser, options, args):
|
| + """Show the modification status of for every dependencies.
|
| +
|
| +Additional options and args may be passed to 'svn status'.
|
| +
|
| +usage: status [options] [--] [svn diff args/options]
|
| +
|
| +Valid options:
|
| + --verbose : output additional diagnostics
|
| + --nohooks : don't run the hooks after the update is complete
|
| +"""
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -912,7 +957,31 @@ def CMDstatus(parser, args):
|
| return client.RunOnDeps('status', args)
|
|
|
|
|
| -@attr('epilog', """Examples:
|
| +def CMDsync(parser, options, args):
|
| + """Checkout/update the modules specified by the gclient configuration.
|
| +
|
| +Unless --revision is specified, then the latest revision of the root solutions
|
| +is checked out, with dependent submodule versions updated according to DEPS
|
| +files. If --revision is specified, then the given revision is used in place
|
| +of the latest, either for a single solution or for all solutions.
|
| +Unless the --force option is provided, solutions and modules whose
|
| +local revision matches the one to update (i.e., they have not changed
|
| +in the repository) are *not* modified. Unless --nohooks is provided,
|
| +the hooks are run. See 'help config' for more information.
|
| +
|
| +usage: gclient sync [options] [--] [SCM update options/args]
|
| +
|
| +Valid options:
|
| + --force : force update even for unchanged modules
|
| + --nohooks : don't run the hooks after the update is complete
|
| + --revision SOLUTION@REV : update given solution to specified revision
|
| + --deps PLATFORM(S) : sync deps for the given platform(s), or 'all'
|
| + --verbose : output additional diagnostics
|
| + --head : update to latest revision, instead of last good
|
| + revision
|
| + --reset : resets any local changes before updating (git only)
|
| +
|
| +Examples:
|
| gclient sync
|
| update files from SCM according to current configuration,
|
| *for modules which have changed since last update or sync*
|
| @@ -921,33 +990,7 @@ def CMDstatus(parser, args):
|
| all modules (useful for recovering files deleted from local copy)
|
| gclient sync --revision src@31000
|
| update src directory to r31000
|
| -""")
|
| -def CMDsync(parser, args):
|
| - """Checkout/update all modules."""
|
| - parser.add_option("--force", action="store_true",
|
| - help="force update even for unchanged modules")
|
| - parser.add_option("--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="update given solution to specified revision, "
|
| - "can be used multiple times for each solution, "
|
| - "e.g. -r src@123, -r internal@32")
|
| - parser.add_option("--head", action="store_true",
|
| - help="skips any safesync_urls specified in "
|
| - "configured solutions and sync to head instead")
|
| - parser.add_option("--delete_unversioned_trees", action="store_true",
|
| - help="delete any unexpected unversioned trees "
|
| - "that are in the checkout")
|
| - parser.add_option("--reset", action="store_true",
|
| - help="resets any local changes before updating (git only)")
|
| - parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
|
| - help="sync deps for the specified (comma-separated) "
|
| - "platform(s); 'all' will sync all platforms")
|
| - parser.add_option("--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:
|
| @@ -980,13 +1023,31 @@ def CMDsync(parser, args):
|
| return client.RunOnDeps('update', args)
|
|
|
|
|
| -def CMDupdate(parser, args):
|
| +def CMDupdate(parser, options, args):
|
| """Alias for the sync command. Deprecated."""
|
| - return CMDsync(parser, args)
|
| + return CMDsync(parser, options, args)
|
| +
|
| +
|
| +def CMDdiff(parser, options, args):
|
| + """Display the differences between two revisions of modules.
|
|
|
| -def CMDdiff(parser, args):
|
| - """Displays local diff for every dependencies."""
|
| - (options, args) = parser.parse_args(args)
|
| +(Does 'svn diff' for each checked out module and dependences.)
|
| +Additional args and options to 'svn diff' can be passed after
|
| +gclient options.
|
| +
|
| +usage: diff [options] [--] [svn args/options]
|
| +
|
| +Valid options:
|
| + --verbose : output additional diagnostics
|
| +
|
| +Examples:
|
| + gclient diff
|
| + simple 'svn diff' for configured client and dependences
|
| + gclient diff -- -x -b
|
| + use 'svn diff -x -b' to suppress whitespace-only differences
|
| + gclient diff -- -r HEAD -x -b
|
| + diff versus the latest version of each module
|
| +"""
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -997,24 +1058,24 @@ def CMDdiff(parser, args):
|
| return client.RunOnDeps('diff', args)
|
|
|
|
|
| -def CMDrevert(parser, args):
|
| - """Revert all modifications in every dependencies."""
|
| - parser.add_option("--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
|
| +def CMDrevert(parser, options, args):
|
| + """Revert every file in every managed directory in the client view."""
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| 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("--force", action="store_true", default=True,
|
| - help="Deprecated. No effect.")
|
| - (options, args) = parser.parse_args(args)
|
| +def CMDrunhooks(parser, options, args):
|
| + """Runs hooks for files that have been modified in the local working copy.
|
| +
|
| +Implies --force.
|
| +
|
| +usage: runhooks [options]
|
| +
|
| +Valid options:
|
| + --verbose : output additional diagnostics
|
| +"""
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -1023,16 +1084,18 @@ def CMDrunhooks(parser, args):
|
| # client dict, but more legible, and it might contain helpful comments.
|
| print(client.ConfigContent())
|
| options.force = True
|
| - options.nohooks = False
|
| return client.RunOnDeps('runhooks', args)
|
|
|
|
|
| -def CMDrevinfo(parser, args):
|
| - """Outputs details for every dependencies."""
|
| - parser.add_option("--snapshot", action="store_true",
|
| - help="create a snapshot file of the current "
|
| - "version of all repositories")
|
| - (options, args) = parser.parse_args(args)
|
| +def CMDrevinfo(parser, options, args):
|
| + """Outputs defails for every dependencies.
|
| +
|
| +This includes source path, server URL and revision information for every
|
| +dependency in all solutions.
|
| +
|
| +usage: revinfo [options]
|
| +"""
|
| + __pychecker__ = 'unusednames=args'
|
| client = GClient.LoadCurrentConfig(options)
|
| if not client:
|
| raise gclient_utils.Error("client not configured; see 'gclient config'")
|
| @@ -1040,45 +1103,70 @@ def CMDrevinfo(parser, args):
|
| return 0
|
|
|
|
|
| -def Command(name):
|
| - return getattr(sys.modules[__name__], 'CMD' + name, None)
|
| -
|
| -
|
| -def CMDhelp(parser, args):
|
| - """Prints list of commands or help for a specific command."""
|
| - (options, args) = parser.parse_args(args)
|
| +def CMDhelp(parser, options, args):
|
| + """Prints general help or command-specific documentation."""
|
| if len(args) == 1:
|
| - return Main(args + ['--help'])
|
| + command = Command(args[0])
|
| + if command:
|
| + print getattr(sys.modules[__name__], 'CMD' + args[0]).__doc__
|
| + return 0
|
| + parser.usage = (DEFAULT_USAGE_TEXT + '\nCommands are:\n' + '\n'.join([
|
| + ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip())
|
| + for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')]))
|
| parser.print_help()
|
| return 0
|
|
|
|
|
| -def GenUsage(parser, command):
|
| - """Modify an OptParse object with the function's documentation."""
|
| - obj = Command(command)
|
| - if command == 'help':
|
| - command = '<command>'
|
| - # OptParser.description prefer nicely non-formatted strings.
|
| - parser.description = re.sub('[\r\n ]{2,}', ' ', obj.__doc__)
|
| - usage = getattr(obj, 'usage', '')
|
| - parser.set_usage('%%prog %s [options] %s' % (command, usage))
|
| - parser.epilog = getattr(obj, 'epilog', None)
|
| +def Command(command):
|
| + return getattr(sys.modules[__name__], 'CMD' + command, CMDhelp)
|
|
|
|
|
| def Main(argv):
|
| - """Doesn't parse the arguments here, just find the right subcommand to
|
| - execute."""
|
| - # Do it late so all commands are listed.
|
| - CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([
|
| - ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip())
|
| - for fn in dir(sys.modules[__name__]) if fn.startswith('CMD')]))
|
| - parser = optparse.OptionParser(version='%prog ' + __version__)
|
| + parser = optparse.OptionParser(usage=DEFAULT_USAGE_TEXT,
|
| + version='%prog ' + __version__)
|
| parser.add_option("-v", "--verbose", action="count", default=0,
|
| help="Produces additional output for diagnostics. Can be "
|
| "used up to three times for more logging info.")
|
| parser.add_option("--gclientfile", metavar="FILENAME", dest="config_filename",
|
| default=os.environ.get("GCLIENT_FILE", ".gclient"),
|
| help="Specify an alternate .gclient file")
|
| + # The other options will be moved eventually.
|
| + parser.add_option("--force", action="store_true",
|
| + help="(update/sync only) force update even "
|
| + "for modules which haven't changed")
|
| + parser.add_option("--nohooks", action="store_true",
|
| + help="(update/sync/revert only) prevent the hooks "
|
| + "from running")
|
| + parser.add_option("--revision", action="append", dest="revisions",
|
| + metavar="REV", default=[],
|
| + help="(update/sync only) sync to a specific "
|
| + "revision, can be used multiple times for "
|
| + "each solution, e.g. --revision=src@123, "
|
| + "--revision=internal@32")
|
| + parser.add_option("--deps", dest="deps_os", metavar="OS_LIST",
|
| + help="(update/sync only) sync deps for the "
|
| + "specified (comma-separated) platform(s); "
|
| + "'all' will sync all platforms")
|
| + parser.add_option("--reset", action="store_true",
|
| + help="(update/sync only) resets any local changes "
|
| + "before updating (git only)")
|
| + parser.add_option("--spec",
|
| + help="(config only) create a gclient file "
|
| + "containing the provided string")
|
| + parser.add_option("--manually_grab_svn_rev", action="store_true",
|
| + help="Skip svn up whenever possible by requesting "
|
| + "actual HEAD revision from the repository")
|
| + parser.add_option("--head", action="store_true",
|
| + help="skips any safesync_urls specified in "
|
| + "configured solutions")
|
| + parser.add_option("--delete_unversioned_trees", action="store_true",
|
| + help="on update, delete any unexpected "
|
| + "unversioned trees that are in the checkout")
|
| + parser.add_option("--snapshot", action="store_true",
|
| + help="(revinfo only), create a snapshot file "
|
| + "of the current version of all repositories")
|
| + parser.add_option("--name",
|
| + help="specify alternate relative solution path")
|
| # Integrate standard options processing.
|
| old_parser = parser.parse_args
|
| def Parse(args):
|
| @@ -1088,22 +1176,22 @@ def Main(argv):
|
| elif options.verbose > 2:
|
| logging.basicConfig(level=logging.DEBUG)
|
| options.entries_filename = options.config_filename + "_entries"
|
| - if not hasattr(options, 'revisions'):
|
| - # GClient.RunOnDeps expects it even if not applicable.
|
| - options.revisions = []
|
| return (options, args)
|
| parser.parse_args = Parse
|
| # We don't want wordwrapping in epilog (usually examples)
|
| parser.format_epilog = lambda _: parser.epilog or ''
|
| - if argv:
|
| - command = Command(argv[0])
|
| - if command:
|
| - # "fix" the usage and the description now that we know the subcommand.
|
| - GenUsage(parser, argv[0])
|
| - return command(parser, argv[1:])
|
| - # Not a known command. Default to help.
|
| - GenUsage(parser, 'help')
|
| - return CMDhelp(parser, argv)
|
| +
|
| + if not len(argv):
|
| + argv = ['help']
|
| + # Add manual support for --version as first argument.
|
| + if argv[0] == '--version':
|
| + parser.print_version()
|
| + return 0
|
| + # Add manual support for --help as first argument.
|
| + if argv[0] == '--help':
|
| + argv[0] = 'help'
|
| + options, args = parser.parse_args(argv[1:])
|
| + return Command(argv[0])(parser, options, args)
|
|
|
|
|
| if "__main__" == __name__:
|
|
|