host.py revision effb81e5f8246d0db0270817048dc992db66e9fb
1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)"""Module for build host support.""" 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import os 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import pipes 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import signal 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import subprocess 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import cr 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)# Controls what verbosity level turns on command trail logging 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)_TRAIL_VERBOSITY = 2 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class Host(cr.Plugin, cr.Plugin.Type): 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """Base class for implementing cr hosts. 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) The host is the main access point to services provided by the machine cr 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) is running on. It exposes information about the machine, and runs external 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) commands on behalf of the actions. 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """ 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def __init__(self): 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) super(Host, self).__init__() 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def Matches(self): 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """Detects whether this is the correct host implementation. 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) This method is overridden by the concrete implementations. 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Returns: 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) true if the plugin matches the machine it is running on. 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """ 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return False 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @classmethod 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def Select(cls): 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for host in cls.Plugins(): 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if host.Matches(): 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return host 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def _Execute(self, command, 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) shell=False, capture=False, silent=False, 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ignore_dry_run=False, return_status=False, 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ignore_interrupt_signal=False): 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """This is the only method that launches external programs. 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) It is a thin wrapper around subprocess.Popen that handles cr specific 51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch issues. The command is expanded in the active context so that variables 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) are substituted. 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Args: 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command: the command to run. 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell: whether to run the command using the shell. 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) capture: controls wether the output of the command is captured. 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ignore_dry_run: Normally, if the context is in dry run mode the command is 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) printed but not executed. This flag overrides that behaviour, causing 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) the command to be run anyway. 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return_status: switches the function to returning the status code rather 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) the output. 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ignore_interrupt_signal: Ignore the interrupt signal (i.e., Ctrl-C) while 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) the command is running. Useful for letting interactive programs manage 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Ctrl-C by themselves. 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Returns: 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) the status if return_status is true, or the output if capture is true, 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) otherwise nothing. 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """ 69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch with cr.context.Trace(): 70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch command = [cr.context.Substitute(arg) for arg in command if arg] 71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch trail = cr.context.trail 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not command: 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print 'Empty command passed to execute' 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) exit(1) 75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if cr.context.verbose: 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print ' '.join(command) 77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if cr.context.verbose >= _TRAIL_VERBOSITY: 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print 'Command expanded the following variables:' 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for key, value in trail: 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print ' ', key, '=', value 81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if ignore_dry_run or not cr.context.dry_run: 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) out = None 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if capture: 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) out = subprocess.PIPE 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) elif silent: 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) out = open(os.devnull, "w") 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try: 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) p = subprocess.Popen( 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) command, shell=shell, 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch env={k: str(v) for k, v in cr.context.exported.items()}, 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) stdout=out) 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) except OSError: 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print 'Failed to exec', command 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) # Don't log the trail if we already have 95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if cr.context.verbose < _TRAIL_VERBOSITY: 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print 'Variables used to build the command were:' 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for key, value in trail: 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print ' ', key, '=', value 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) exit(1) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) try: 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ignore_interrupt_signal: 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) signal.signal(signal.SIGINT, signal.SIG_IGN) 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output, _ = p.communicate() 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) finally: 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if ignore_interrupt_signal: 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) signal.signal(signal.SIGINT, signal.SIG_DFL) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if silent: 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) out.close() 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if return_status: 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return p.returncode 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if p.returncode != 0: 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) print 'Error {0} executing command {1}'.format(p.returncode, command) 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) exit(p.returncode) 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return output or '' 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return '' 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @cr.Plugin.activemethod 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def Shell(self, *command): 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) command = ' '.join([pipes.quote(arg) for arg in command]) 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute([command], shell=True, ignore_interrupt_signal=True) 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @cr.Plugin.activemethod 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def Execute(self, *command): 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute(command, shell=False) 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @cr.Plugin.activemethod 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def ExecuteSilently(self, *command): 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute(command, shell=False, silent=True) 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @cr.Plugin.activemethod 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def CaptureShell(self, *command): 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute(command, 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) shell=True, capture=True, ignore_dry_run=True) 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @cr.Plugin.activemethod 136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def Capture(self, *command): 137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute(command, capture=True, ignore_dry_run=True) 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @cr.Plugin.activemethod 140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def ExecuteStatus(self, *command): 141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return self._Execute(command, 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ignore_dry_run=True, return_status=True) 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @cr.Plugin.activemethod 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) def YesNo(self, question, default=True): 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """Ask the user a yes no question 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) This blocks until the user responds. 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Args: 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) question: The question string to show the user 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) default: True if the default response is Yes 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Returns: 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) True if the response was yes. 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) """ 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) options = 'Y/n' if default else 'y/N' 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result = raw_input(question + ' [' + options + '] ').lower() 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if result == '': 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return default 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return result in ['y', 'yes'] 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) @classmethod 162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch def SearchPath(cls, name, paths=[]): 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """Searches the PATH for an executable. 164f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Args: 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) name: the name of the binary to search for. 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Returns: 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) the set of executables found, or an empty list if none. 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """ 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) result = [] 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) extensions = [''] 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) extensions.extend(os.environ.get('PATHEXT', '').split(os.pathsep)) 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch paths = [cr.context.Substitute(path) for path in paths if path] 174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch paths = paths + os.environ.get('PATH', '').split(os.pathsep) 175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for path in paths: 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) partial = os.path.join(path, name) 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for extension in extensions: 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) filename = partial + extension 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if os.path.exists(filename) and filename not in result: 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) result.append(filename) 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return result 182