Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: trace_inputs.py

Issue 22902007: Switch trace_inputs.py and isolate.py to subcommand.py. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Now works Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # coding=utf-8 2 # coding=utf-8
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Traces an executable and its child processes and extract the files accessed 7 """Traces an executable and its child processes and extract the files accessed
8 by them. 8 by them.
9 9
10 The implementation uses OS-specific API. The native Kernel logger and the ETL 10 The implementation uses OS-specific API. The native Kernel logger and the ETL
(...skipping 19 matching lines...) Expand all
30 import re 30 import re
31 import stat 31 import stat
32 import subprocess 32 import subprocess
33 import sys 33 import sys
34 import tempfile 34 import tempfile
35 import threading 35 import threading
36 import time 36 import time
37 import unicodedata 37 import unicodedata
38 import weakref 38 import weakref
39 39
40 from third_party import colorama
41 from third_party.depot_tools import fix_encoding
42 from third_party.depot_tools import subcommand
43
40 ## OS-specific imports 44 ## OS-specific imports
41 45
42 if sys.platform == 'win32': 46 if sys.platform == 'win32':
43 from ctypes.wintypes import byref, create_unicode_buffer, c_int, c_wchar_p 47 from ctypes.wintypes import byref, create_unicode_buffer, c_int, c_wchar_p
44 from ctypes.wintypes import windll, FormatError # pylint: disable=E0611 48 from ctypes.wintypes import windll, FormatError # pylint: disable=E0611
45 from ctypes.wintypes import GetLastError # pylint: disable=E0611 49 from ctypes.wintypes import GetLastError # pylint: disable=E0611
46 elif sys.platform == 'darwin': 50 elif sys.platform == 'darwin':
47 import Carbon.File # pylint: disable=F0401 51 import Carbon.File # pylint: disable=F0401
48 import MacOS # pylint: disable=F0401 52 import MacOS # pylint: disable=F0401
49 53
(...skipping 3579 matching lines...) Expand 10 before | Expand all | Expand 10 after
3629 - cwd: current directory to start the process in. 3633 - cwd: current directory to start the process in.
3630 - api: a tracing api instance. 3634 - api: a tracing api instance.
3631 - output: if True, returns output, otherwise prints it at the console. 3635 - output: if True, returns output, otherwise prints it at the console.
3632 """ 3636 """
3633 cmd = fix_python_path(cmd) 3637 cmd = fix_python_path(cmd)
3634 api.clean_trace(logfile) 3638 api.clean_trace(logfile)
3635 with api.get_tracer(logfile) as tracer: 3639 with api.get_tracer(logfile) as tracer:
3636 return tracer.trace(cmd, cwd, 'default', output) 3640 return tracer.trace(cmd, cwd, 'default', output)
3637 3641
3638 3642
3639 def CMDclean(args): 3643 def CMDclean(parser, args):
3640 """Cleans up traces.""" 3644 """Cleans up traces."""
3641 parser = OptionParserTraceInputs(command='clean')
3642 options, args = parser.parse_args(args) 3645 options, args = parser.parse_args(args)
3643 api = get_api() 3646 api = get_api()
3644 api.clean_trace(options.log) 3647 api.clean_trace(options.log)
3645 return 0 3648 return 0
3646 3649
3647 3650
3648 def CMDtrace(args): 3651 def CMDtrace(parser, args):
3649 """Traces an executable.""" 3652 """Traces an executable."""
3650 parser = OptionParserTraceInputs(command='trace')
3651 parser.allow_interspersed_args = False 3653 parser.allow_interspersed_args = False
3652 parser.add_option( 3654 parser.add_option(
3653 '-q', '--quiet', action='store_true', 3655 '-q', '--quiet', action='store_true',
3654 help='Redirects traced executable output to /dev/null') 3656 help='Redirects traced executable output to /dev/null')
3655 parser.add_option( 3657 parser.add_option(
3656 '-s', '--sudo', action='store_true', 3658 '-s', '--sudo', action='store_true',
3657 help='Use sudo when shelling out the tracer tool (ignored on Windows)') 3659 help='Use sudo when shelling out the tracer tool (ignored on Windows)')
3658 parser.add_option( 3660 parser.add_option(
3659 '-n', '--no-sudo', action='store_false', 3661 '-n', '--no-sudo', action='store_false',
3660 help='Don\'t use sudo') 3662 help='Don\'t use sudo')
3661 options, args = parser.parse_args(args) 3663 options, args = parser.parse_args(args)
3662 3664
3663 if not args: 3665 if not args:
3664 parser.error('Please provide a command to run') 3666 parser.error('Please provide a command to run')
3665 3667
3666 if not os.path.isabs(args[0]) and os.access(args[0], os.X_OK): 3668 if not os.path.isabs(args[0]) and os.access(args[0], os.X_OK):
3667 args[0] = os.path.abspath(args[0]) 3669 args[0] = os.path.abspath(args[0])
3668 3670
3669 # options.sudo default value is None, which is to do whatever tracer defaults 3671 # options.sudo default value is None, which is to do whatever tracer defaults
3670 # do. 3672 # do.
3671 api = get_api(use_sudo=options.sudo) 3673 api = get_api(use_sudo=options.sudo)
3672 return trace(options.log, args, os.getcwd(), api, options.quiet)[0] 3674 return trace(options.log, args, os.getcwd(), api, options.quiet)[0]
3673 3675
3674 3676
3675 def CMDread(args): 3677 def CMDread(parser, args):
3676 """Reads the logs and prints the result.""" 3678 """Reads the logs and prints the result."""
3677 parser = OptionParserTraceInputs(command='read')
3678 parser.add_option( 3679 parser.add_option(
3679 '-V', '--variable', 3680 '-V', '--variable',
3680 nargs=2, 3681 nargs=2,
3681 action='append', 3682 action='append',
3682 dest='variables', 3683 dest='variables',
3683 metavar='VAR_NAME directory', 3684 metavar='VAR_NAME directory',
3684 default=[], 3685 default=[],
3685 help=('Variables to replace relative directories against. Example: ' 3686 help=('Variables to replace relative directories against. Example: '
3686 '"-v \'$HOME\' \'/home/%s\'" will replace all occurence of your ' 3687 '"-v \'$HOME\' \'/home/%s\'" will replace all occurence of your '
3687 'home dir with $HOME') % getpass.getuser()) 3688 'home dir with $HOME') % getpass.getuser())
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
3765 3766
3766 def parse_args(self, *args, **kwargs): 3767 def parse_args(self, *args, **kwargs):
3767 options, args = optparse.OptionParser.parse_args(self, *args, **kwargs) 3768 options, args = optparse.OptionParser.parse_args(self, *args, **kwargs)
3768 levels = [logging.ERROR, logging.INFO, logging.DEBUG] 3769 levels = [logging.ERROR, logging.INFO, logging.DEBUG]
3769 logging.basicConfig( 3770 logging.basicConfig(
3770 level=levels[min(len(levels)-1, options.verbose)], 3771 level=levels[min(len(levels)-1, options.verbose)],
3771 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s') 3772 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s')
3772 return options, args 3773 return options, args
3773 3774
3774 3775
3775 class OptionParserWithNiceDescription(OptionParserWithLogging): 3776 class OptionParserTraceInputs(OptionParserWithLogging):
3776 """Generates the description with the command's docstring."""
3777 def __init__(self, **kwargs):
3778 """Sets 'description' and 'usage' if not already specified."""
3779 command = kwargs.pop('command', 'help')
3780 kwargs.setdefault(
3781 'description',
3782 re.sub('[\r\n ]{2,}', ' ', get_command_handler(command).__doc__))
3783 kwargs.setdefault('usage', '%%prog %s [options]' % command)
3784 OptionParserWithLogging.__init__(self, **kwargs)
3785
3786
3787 class OptionParserTraceInputs(OptionParserWithNiceDescription):
3788 """Adds automatic --log handling.""" 3777 """Adds automatic --log handling."""
3789 def __init__(self, **kwargs): 3778 def __init__(self, **kwargs):
3790 OptionParserWithNiceDescription.__init__(self, **kwargs) 3779 OptionParserWithLogging.__init__(self, **kwargs)
3791 self.add_option( 3780 self.add_option(
3792 '-l', '--log', help='Log file to generate or read, required') 3781 '-l', '--log', help='Log file to generate or read, required')
3793 3782
3794 def parse_args(self, *args, **kwargs): 3783 def parse_args(self, *args, **kwargs):
3795 """Makes sure the paths make sense. 3784 """Makes sure the paths make sense.
3796 3785
3797 On Windows, / and \ are often mixed together in a path. 3786 On Windows, / and \ are often mixed together in a path.
3798 """ 3787 """
3799 options, args = OptionParserWithNiceDescription.parse_args( 3788 options, args = OptionParserWithLogging.parse_args(
3800 self, *args, **kwargs) 3789 self, *args, **kwargs)
3801 if not options.log: 3790 if not options.log:
3802 self.error('Must supply a log file with -l') 3791 self.error('Must supply a log file with -l')
3803 options.log = os.path.abspath(options.log) 3792 options.log = os.path.abspath(options.log)
3804 return options, args 3793 return options, args
3805 3794
3806 3795
3807 def extract_documentation():
3808 """Returns a dict {command: description} for each of documented command."""
3809 commands = (
3810 fn[3:]
3811 for fn in dir(sys.modules['__main__'])
3812 if fn.startswith('CMD') and get_command_handler(fn[3:]).__doc__)
3813 return dict((fn, get_command_handler(fn).__doc__) for fn in commands)
3814
3815
3816 def CMDhelp(args):
3817 """Prints list of commands or help for a specific command."""
3818 doc = extract_documentation()
3819 # Calculates the optimal offset.
3820 offset = max(len(cmd) for cmd in doc)
3821 format_str = ' %-' + str(offset + 2) + 's %s'
3822 # Generate a one-liner documentation of each commands.
3823 commands_description = '\n'.join(
3824 format_str % (cmd, doc[cmd].split('\n')[0]) for cmd in sorted(doc))
3825
3826 parser = OptionParserWithNiceDescription(
3827 usage='%prog <command> [options]',
3828 description='Commands are:\n%s\n' % commands_description)
3829 parser.format_description = lambda _: parser.description
3830
3831 # Strip out any -h or --help argument.
3832 _, args = parser.parse_args([i for i in args if not i in ('-h', '--help')])
3833 if len(args) == 1:
3834 if not get_command_handler(args[0]):
3835 parser.error('Unknown command %s' % args[0])
3836 # The command was "%prog help command", replaces ourself with
3837 # "%prog command --help" so help is correctly printed out.
3838 return main(args + ['--help'])
3839 elif args:
3840 parser.error('Unknown argument "%s"' % ' '.join(args))
3841 parser.print_help()
3842 return 0
3843
3844
3845 def get_command_handler(name):
3846 """Returns the command handler or CMDhelp if it doesn't exist."""
3847 return getattr(sys.modules['__main__'], 'CMD%s' % name, None)
3848
3849
3850 def main_impl(argv):
3851 command = get_command_handler(argv[0] if argv else 'help')
3852 if not command:
3853 return CMDhelp(argv)
3854 return command(argv[1:])
3855
3856 def main(argv): 3796 def main(argv):
3857 disable_buffering() 3797 dispatcher = subcommand.CommandDispatcher(__name__)
3858 try: 3798 try:
3859 main_impl(argv) 3799 return dispatcher.execute(OptionParserTraceInputs(), argv)
3860 except TracingFailure, e: 3800 except TracingFailure, e:
3861 sys.stderr.write('\nError: ') 3801 sys.stderr.write('\nError: ')
3862 sys.stderr.write(str(e)) 3802 sys.stderr.write(str(e))
3863 sys.stderr.write('\n') 3803 sys.stderr.write('\n')
3864 return 1 3804 return 1
3865 3805
3866 3806
3867 if __name__ == '__main__': 3807 if __name__ == '__main__':
3808 fix_encoding.fix_encoding()
3809 disable_buffering()
3810 colorama.init()
3868 sys.exit(main(sys.argv[1:])) 3811 sys.exit(main(sys.argv[1:]))
OLDNEW
« tests/isolate_smoke_test.py ('K') | « third_party/depot_tools/subcommand.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698