Chromium Code Reviews| Index: tools/telemetry/telemetry_bootstrap.py |
| =================================================================== |
| --- tools/telemetry/telemetry_bootstrap.py (revision 0) |
| +++ tools/telemetry/telemetry_bootstrap.py (revision 0) |
| @@ -0,0 +1,132 @@ |
| +#!/usr/bin/env python |
| +# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""Bootstrap Chrome Telemetry by downloading all its files from SVN servers. |
| + |
| +Requires a DEPS file to specify which directories on which SVN servers |
| +are required to run Telemetry. Format of that DEPS file is a subset of the |
| +normal DEPS file format[1]; currently only only the "deps" dictionary is |
| +supported and nothing else. |
| + |
| +DEPS can be specified with --deps or defaults to ./DEPS |
| + |
| +Fetches all files in the specified directories using WebDAV (SVN is WebDAV under |
| +the hood). |
| + |
| +[1] http://dev.chromium.org/developers/how-tos/depottools#TOC-DEPS-file |
| +""" |
| + |
| +import imp |
| +import logging |
| +from optparse import OptionParser |
|
nduca
2013/01/05 01:28:19
I think you can ditch main() entirely and thus Opt
wiltzius
2013/01/08 02:53:34
Done.
|
| +import os |
| +import urllib |
| +import urlparse |
| + |
| +# default DEPS filename |
| +DEPS_FILE = "DEPS" |
|
nduca
2013/01/05 01:28:19
This can go away
wiltzius
2013/01/08 02:53:34
Done.
wiltzius
2013/01/08 02:53:34
Done.
|
| +# link to file containing the 'davclient' WebDAV client library |
|
nduca
2013/01/05 01:28:19
# Comments start with capitals end and end with a
wiltzius
2013/01/08 02:53:34
Done.
|
| +#TODO(wiltzius) change this to point at Chromium SVN server after checkin |
|
nduca
2013/01/05 01:28:19
# TODO(wiltzius):
|
| +DAVCLIENT_URL = 'http://svn.osafoundation.org/tools/davclient/trunk/src/davclient/davclient.py' |
|
nduca
2013/01/05 01:28:19
_DAVCLIENT_URL since its private to the module. _-
wiltzius
2013/01/08 02:53:34
Done.
|
| + |
| +def bootstrap_davclient(): |
|
nduca
2013/01/05 01:28:19
_bootstrap_davclient since this shouldn't be calle
wiltzius
2013/01/08 02:53:34
Done.
|
| + """Dynamically import davclient helper library.""" |
|
nduca
2013/01/05 01:28:19
_download_and_import_davclient_module()?
wiltzius
2013/01/08 02:53:34
Done.
|
| + global davclient |
| + davclient_txt = urllib.urlopen(DAVCLIENT_URL).read() |
|
nduca
2013/01/05 01:28:19
txt -> source?
wiltzius
2013/01/08 02:53:34
Done.
wiltzius
2013/01/08 02:53:34
Done.
|
| + davclient = imp.new_module('davclient') |
| + exec davclient_txt in davclient.__dict__ |
| + |
| + |
| +class DAVClientWrapper(): |
| + """Knows how to retrieve subdirectories and files from WebDAV/SVN servers.""" |
| + |
| + def __init__(self, root_url): |
| + """Initialize SVN server root_url, save files to local dest_dir. |
| + |
| + Args: |
| + root_url: string url of SVN/WebDAV server |
| + """ |
| + self.root_url = root_url |
| + self.client = davclient.DAVClient(root_url) |
| + |
| + def GetSubdirs(self, path): |
| + """Returns string names of all subdirs of this path on the SVN server.""" |
| + props = self.client.propfind(path, depth=1) |
| + return map(os.path.basename, props.keys()) |
| + |
| + def IsFile(self, path): |
| + """Returns True if the path is a file on the server, False if directory.""" |
| + props = self.client.propfind(path, depth=1) |
| + # build up normalized path list since paths to directories may or may not |
| + # have trailing slashes |
| + norm_keys = {} |
| + for entry in props.keys(): |
| + norm_keys[os.path.normpath(entry)] = entry |
| + return props[norm_keys[os.path.normpath(path)]]['resourcetype'] is None |
| + |
| + def Traverse(self, src_path, dst_path): |
| + """Walks the directory hierarchy pointed to by src_path download all files. |
| + |
| + Recursively walks src_path and saves all files and subfolders into |
| + dst_path. |
| + |
| + Args: |
| + src_path: string path on SVN server to save (absolute path on server). |
| + dest_path: string local path (relative or absolute) to save to. |
| + """ |
| + if self.IsFile(src_path): |
| + if not os.path.exists(os.path.dirname(dst_path)): |
| + logging.info("creating %s", os.path.dirname(dst_path)) |
| + os.makedirs(os.path.dirname(dst_path)) |
| + logging.info("Saving %s to %s", self.root_url + src_path, dst_path) |
| + urllib.urlretrieve(self.root_url + src_path, dst_path) |
| + return |
| + else: |
| + for subdir in self.GetSubdirs(src_path): |
| + if subdir: |
| + self.Traverse(os.path.join(src_path, subdir), |
| + os.path.join(dst_path, subdir)) |
| + |
| + |
| +def ParseOptions(): |
|
nduca
2013/01/05 01:28:19
I think this can go away
wiltzius
2013/01/08 02:53:34
Done.
|
| + """Parses command-line options for the bootstrap.""" |
| + #TODO(wiltzius) have a --revision flag that pulls at a specific rev |
| + parser = OptionParser() |
| + parser.add_option("-v", "--verbosity", dest="verbosity", default=1, |
| + type="int", help="logging verbosity level (0, 1, 2, 3)") |
| + parser.add_option("--deps", dest="deps_filename", default=DEPS_FILE, |
| + help="look for dependency manifest in this file") |
| + return parser.parse_args() |
| + |
| + |
| +def DownloadDEPS(deps_path): |
|
nduca
2013/01/05 01:28:19
Should we have a TODO here for what revision of te
wiltzius
2013/01/08 02:53:34
Done.
|
| + """Saves all the dependencies in deps_path.""" |
| + # dynamically import davclient library |
| + bootstrap_davclient() |
| + with open(deps_path) as deps_file: |
| + deps = imp.new_module('deps') |
| + exec deps_file.read() in deps.__dict__ |
|
nduca
2013/01/05 01:28:19
unindent the exec stuff
so you say
with blah as
wiltzius
2013/01/08 02:53:34
Done.
|
| + #TODO(wiltzius) in the future, make the destination directory configurable |
|
nduca
2013/01/05 01:28:19
formatting
wiltzius
2013/01/08 02:53:34
Done.
|
| + # as something other than the cwd |
|
nduca
2013/01/05 01:28:19
this function should take in destination dir. E.g.
wiltzius
2013/01/08 02:53:34
Done.
|
| + destination_dir = os.getcwd() |
| + for dst_path, src_path in deps.deps.iteritems(): |
| + parsed_url = urlparse.urlparse(src_path) |
| + root_url = parsed_url.scheme + '://' + parsed_url.netloc |
|
nduca
2013/01/05 01:28:19
where will we handle "foo@181" type stuff?
wiltzius
2013/01/08 02:53:34
That's the "fetch at revision" TODO. This will nee
|
| + dav_client = DAVClientWrapper(root_url) |
| + dav_client.Traverse(parsed_url.path, |
| + os.path.join(destination_dir, dst_path)) |
|
nduca
2013/01/05 01:28:19
after we clone dst_path, what if dst_path has a DE
|
| + |
| + |
| +def Main(): |
|
nduca
2013/01/05 01:28:19
not needed I think.
wiltzius
2013/01/08 02:53:34
Done.
|
| + """Fetches files specified in dependency manifest from SVN/WebDAV server.""" |
| + options = ParseOptions()[0] |
| + # set logging level per verbosity |
| + logging_levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] |
| + logging.basicConfig(level=logging_levels[options.verbosity]) |
| + DownloadDEPS(options.deps_filename) |
| + |
| + |
| +if __name__ == "__main__": |
|
nduca
2013/01/05 01:28:19
Ditch the __name__ bit as well as the #! bit. If s
wiltzius
2013/01/08 02:53:34
Done.
|
| + Main() |
|
nduca
2013/01/05 01:28:19
Lets add the stuff that you had in __main__ into t
nduca
2013/01/05 01:28:19
Lets move this to tools/telemetry/tools/telemetry_
wiltzius
2013/01/08 02:53:34
I will do this in a follow-up patch after this boo
|
| Property changes on: tools/telemetry/telemetry_bootstrap.py |
| ___________________________________________________________________ |
| Added: svn:executable |
| + * |