Chromium Code Reviews| Index: mojo/devtools/common/android_stack_parser/stack_utils.py |
| diff --git a/mojo/devtools/common/android_stack_parser/stack_utils.py b/mojo/devtools/common/android_stack_parser/stack_utils.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..97b26615bc6c7864635c85911d76b6f390ee3246 |
| --- /dev/null |
| +++ b/mojo/devtools/common/android_stack_parser/stack_utils.py |
| @@ -0,0 +1,107 @@ |
| +# Copyright 2015 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. |
| + |
| +"""Utility functions for the stack tool.""" |
| + |
| +import glob |
| +import os |
| +import os.path |
| +import re |
| + |
|
ppi
2015/08/21 14:53:07
two blank lines please
etiennej
2015/08/21 15:07:18
Done.
|
| +def UnzipSymbols(symbolfile, symdir=None): |
| + """Unzips a file to _DEFAULT_SYMROOT and returns the unzipped location. |
| + |
| + Args: |
| + symbolfile: The .zip file to unzip |
| + symdir: Optional temporary directory to use for extraction |
| + |
| + Returns: |
| + A tuple containing (the directory into which the zip file was unzipped, |
| + the path to the "symbols" directory in the unzipped file). To clean |
| + up, the caller can delete the first element of the tuple. |
| + |
| + Raises: |
| + SymbolDownloadException: When the unzip fails. |
| + """ |
| + if not symdir: |
| + symdir = "%s/%s" % (_DEFAULT_SYMROOT, hash(symbolfile)) |
| + if not os.path.exists(symdir): |
| + os.makedirs(symdir) |
| + |
| + print "extracting %s..." % symbolfile |
| + saveddir = os.getcwd() |
| + os.chdir(symdir) |
| + try: |
| + unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile]) |
| + if unzipcode > 0: |
| + os.remove(symbolfile) |
| + raise SymbolDownloadException("failed to extract symbol files (%s)." |
| + % symbolfile) |
| + finally: |
| + os.chdir(saveddir) |
| + |
| + android_symbols = glob.glob("%s/out/target/product/*/symbols" % symdir) |
| + if android_symbols: |
| + return (symdir, android_symbols[0]) |
| + else: |
| + # This is a zip of Chrome symbols, so symbol.CHROME_SYMBOLS_DIR needs to be |
| + # updated to point here. |
| + symbol.CHROME_SYMBOLS_DIR = symdir |
| + return (symdir, symdir) |
| + |
| + |
| +def GetBasenameFromMojoApp(url): |
| + """Used by GetSymbolMapping() to extract the basename from the location the |
| + mojo app was downloaded from. The location is a URL, e.g. |
| + http://foo/bar/x.so.""" |
| + index = url.rfind('/') |
| + return url[(index + 1):] if index != -1 else url |
| + |
| + |
| +def GetSymboledNameForMojoApp(path): |
| + """Used by GetSymbolMapping to get the non-stripped library name for an |
| + installed mojo app.""" |
| + # e.g. tracing.mojo -> libtracing_library.so |
| + name, ext = os.path.splitext(path) |
| + if ext != '.mojo': |
| + return path |
| + return 'lib%s_library.so' % name |
| + |
| + |
| +def GetSymbolMapping(lines): |
| + """Returns a mapping (dictionary) from download file to .so.""" |
| + regex = re.compile('Caching mojo app (\S+?)(?:\?\S+)? at (\S+)') |
| + mappings = {} |
| + for line in lines: |
| + result = regex.search(line) |
| + if result: |
| + url = GetBasenameFromMojoApp(result.group(1)) |
| + mappings[os.path.normpath(result.group(2))] = GetSymboledNameForMojoApp( |
| + url) |
| + return mappings |
| + |
| + |
| +def _LowestAncestorContainingRelpath(dir_path, relpath): |
| + """Returns the lowest ancestor dir of |dir_path| that contains |relpath|. |
| + """ |
| + cur_dir_path = os.path.abspath(dir_path) |
| + while True: |
| + if os.path.exists(os.path.join(cur_dir_path, relpath)): |
| + return cur_dir_path |
| + |
| + next_dir_path = os.path.dirname(cur_dir_path) |
| + if next_dir_path != cur_dir_path: |
| + cur_dir_path = next_dir_path |
| + else: |
| + return None |
| + |
| + |
| +def GuessDir(relpath): |
| + """Returns absolute path to location |relpath| in the lowest ancestor of this |
| + file that contains it.""" |
| + lowest_ancestor = _LowestAncestorContainingRelpath( |
| + os.path.dirname(__file__), relpath) |
| + if not lowest_ancestor: |
| + return None |
| + return os.path.join(lowest_ancestor, relpath) |