1#!/usr/bin/env python
2
3# Copyright (c) 2016 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import functools
8import os
9import sys
10
11
12def GetCatapultDir():
13  return os.path.normpath(
14      os.path.join(os.path.dirname(__file__), '..', '..', '..'))
15
16
17def IsRunningOnCrosDevice():
18  """Returns True if we're on a ChromeOS device."""
19  lsb_release = '/etc/lsb-release'
20  if sys.platform.startswith('linux') and os.path.exists(lsb_release):
21    with open(lsb_release, 'r') as f:
22      res = f.read()
23      if res.count('CHROMEOS_RELEASE_NAME'):
24        return True
25  return False
26
27
28def _ExecutableExtensions():
29  # pathext is, e.g. '.com;.exe;.bat;.cmd'
30  exts = os.getenv('PATHEXT').split(';') #e.g. ['.com','.exe','.bat','.cmd']
31  return [x[1:].upper() for x in exts] #e.g. ['COM','EXE','BAT','CMD']
32
33
34def IsExecutable(path):
35  if os.path.isfile(path):
36    if hasattr(os, 'name') and os.name == 'nt':
37      return path.split('.')[-1].upper() in _ExecutableExtensions()
38    else:
39      return os.access(path, os.X_OK)
40  else:
41    return False
42
43
44def _AddDirToPythonPath(*path_parts):
45  path = os.path.abspath(os.path.join(*path_parts))
46  if os.path.isdir(path) and path not in sys.path:
47    # Some callsite that use telemetry assumes that sys.path[0] is the directory
48    # containing the script, so we add these extra paths to right after it.
49    sys.path.insert(1, path)
50
51_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'devil'))
52_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'dependency_manager'))
53_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mock'))
54# mox3 is needed for pyfakefs usage, but not for pylint.
55_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mox3'))
56_AddDirToPythonPath(
57    os.path.join(GetCatapultDir(), 'third_party', 'pyfakefs'))
58
59from devil.utils import timeout_retry
60from devil.utils import reraiser_thread
61
62
63# Decorator that adds timeout functionality to a function.
64def Timeout(default_timeout):
65  return lambda func: TimeoutDeco(func, default_timeout)
66
67# Note: Even though the "timeout" keyword argument is the only
68# keyword argument that will need to be given to the decorated function,
69# we still have to use the **kwargs syntax, because we have to use
70# the *args syntax here before (since the decorator decorates functions
71# with different numbers of positional arguments) and Python doesn't allow
72# a single named keyword argument after *args.
73# (e.g., 'def foo(*args, bar=42):' is a syntax error)
74
75def TimeoutDeco(func, default_timeout):
76  @functools.wraps(func)
77  def RunWithTimeout(*args, **kwargs):
78    if 'timeout' in kwargs:
79      timeout = kwargs['timeout']
80    else:
81      timeout = default_timeout
82    try:
83      return timeout_retry.Run(func, timeout, 0, args=args)
84    except reraiser_thread.TimeoutError:
85      print '%s timed out.' % func.__name__
86      return False
87  return RunWithTimeout
88