<commit_before># Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Common python commands used by various build scripts."""

import errno
import os
import re
import signal
import subprocess
import sys
import time
from terminal import Color
import xml.sax


_STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
YES = 'yes'
NO = 'no'

class DebugLevel(object):
  """Object that controls the verbosity of program output.

  Setting the debug level to a given level will mute all output that is at a
  lower debug level.  I.e., setting debug level of ERROR will hide all output
  that is at WARNING, INFO, and DEBUG levels.
  """
  class Level(object):
    """Object that represents an enumerated debug level."""
    def __init__(self, level):
      self.level = level

    def __cmp__(self, other):
      return self.level - other.level

  # Available levels
  DEBUG = Level(0)
  INFO = Level(1)
  WARNING = Level(2)
  ERROR = Level(3)

  # Internal variable that stores current global debug level.
  _current_debug_level = INFO

  @classmethod
  def GetCurrentDebugLevel(cls):
    """Get the current debug level for the cros_build_lib module."""
    return cls._current_debug_level

  @classmethod
  def SetDebugLevel(cls, debug_level):
    """Set the current debug level for the cros_build_lib module."""
    assert isinstance(debug_level, cls.Level), 'Invalid debug level.'
    cls._current_debug_level = debug_level

  @classmethod
  def IsValidDebugLevel(cls, debug_level):
    """Returns whether the passed in debug_level is a valid level."""
    return isinstance(debug_level, cls.Level)


class GitPushFailed(Exception):
  """Raised when a git push failed after retry."""
  pass

class CommandResult(object):
  """An object to store various attributes of a child process."""

  def __init__(self):
    self.cmd = None
    self.error = None
    self.output = None
    self.returncode = None


class RunCommandError(Exception):
  """Error caught in RunCommand() method."""
  def __init__(self, msg, cmd, error_code):
    self.cmd = cmd
    self.error_code = error_code
    Exception.__init__(self, msg)
    self.args = (msg, cmd, error_code)

  def __eq__(self, other):
    return (type(self) == type(other) and
            str(self) == str(other) and
            self.error_code == other.error_code and
            self.cmd == other.cmd)

  def __ne__(self, other):
    return not self.__eq__(other)


def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None,
               exit_code=True, redirect_stdout=False, redirect_stderr=False,
               cwd=None, input=None, enter_chroot=False, shell=False,
               env=None, extra_env=None, ignore_sigint=False,
               combine_stdout_stderr=False, log_stdout_to_file=None,
               chroot_args=None, debug_level=DebugLevel.INFO,
               error_code_ok=False):
  """Runs a command.

  Args:
    cmd: cmd to run.  Should be input to subprocess.Popen. If a string, shell
      must be true. Otherwise the command must be an array of arguments, and
      shell must be false.
    print_cmd: prints the command before running it.
    error_ok: ***DEPRECATED, use error_code_ok instead***<commit_msg>Add RunCommand wrapper for sudo usage.<commit_after># Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Common python commands used by various build scripts."""

import errno
import os
import re
import signal
import subprocess
import sys
import time
from terminal import Color
import xml.sax


STRICT_SUDO = False

_STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()
YES = 'yes'
NO = 'no'

class DebugLevel(object):
  """Object that controls the verbosity of program output.

  Setting the debug level to a given level will mute all output that is at a
  lower debug level.  I.e., setting debug level of ERROR will hide all output
  that is at WARNING, INFO, and DEBUG levels.
  """
  class Level(object):
    """Object that represents an enumerated debug level."""
    def __init__(self, level):
      self.level = level

    def __cmp__(self, other):
      return self.level - other.level

  # Available levels
  DEBUG = Level(0)
  INFO = Level(1)
  WARNING = Level(2)
  ERROR = Level(3)

  # Internal variable that stores current global debug level.
  _current_debug_level = INFO

  @classmethod
  def GetCurrentDebugLevel(cls):
    """Get the current debug level for the cros_build_lib module."""
    return cls._current_debug_level

  @classmethod
  def SetDebugLevel(cls, debug_level):
    """Set the current debug level for the cros_build_lib module."""
    assert isinstance(debug_level, cls.Level), 'Invalid debug level.'
    cls._current_debug_level = debug_level

  @classmethod
  def IsValidDebugLevel(cls, debug_level):
    """Returns whether the passed in debug_level is a valid level."""
    return isinstance(debug_level, cls.Level)


class GitPushFailed(Exception):
  """Raised when a git push failed after retry."""
  pass

class CommandResult(object):
  """An object to store various attributes of a child process."""

  def __init__(self):
    self.cmd = None
    self.error = None
    self.output = None
    self.returncode = None


class RunCommandError(Exception):
  """Error caught in RunCommand() method."""
  def __init__(self, msg, cmd, error_code):
    self.cmd = cmd
    self.error_code = error_code
    Exception.__init__(self, msg)
    self.args = (msg, cmd, error_code)

  def __eq__(self, other):
    return (type(self) == type(other) and
            str(self) == str(other) and
            self.error_code == other.error_code and
            self.cmd == other.cmd)

  def __ne__(self, other):
    return not self.__eq__(other)


def SudoRunCommand(cmd, **kwds):
  """
  Run a command via sudo.

  Client code must use this rather than coming up with their own RunCommand
  invocation that jams sudo in- this function is used to enforce certain
  rules in our code about sudo usage, and as a potential auditing point.

  Args:
    cmd: The command to run.  See RunCommand for rules of this argument-
         SudoRunCommand purely prefixes it with sudo.
    kwds: See RunCommand options, it's a direct pass thru to it.
  Returns:
    See RunCommand documentation.
  Raises:
    This function may immediately raise RunCommandError if we're operating
    in a strict sudo context and the API is being misused.
    Barring that, see RunCommand's documentation- it can raise the same things
    RunCommand does.
  """

  mode_s, mode_l = '', []
  if STRICT_SUDO:
    if 'CROS_SUDO_KEEP_ALIVE' not in os.environ:
      raise RunCommandError(
          'We were invoked in a strict sudo non-interactive context, but no '
          'sudo keep alive daemon is running.  This is a bug in the code.',
          cmd, 126)
    mode_s, mode_l = '-n ', ['-n']

  if isinstance(cmd, basestring):
    cmd = 'sudo %s%s' % (mode_s, cmd)
  else:
    cmd = ['sudo'] + mode_l + list(cmd)

  return RunCommand(cmd, **kwds)


def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None,
               exit_code=True, redirect_stdout=False, redirect_stderr=False,
               cwd=None, input=None, enter_chroot=False, shell=False,
               env=None, extra_env=None, ignore_sigint=False,
               combine_stdout_stderr=False, log_stdout_to_file=None,
               chroot_args=None, debug_level=DebugLevel.INFO,
               error_code_ok=False):
  """Runs a command.

  Args:
    cmd: cmd to run.  Should be input to subprocess.Popen. If a string, shell
      must be true. Otherwise the command must be an array of arguments, and
      shell must be false.
    print_cmd: prints the command before running it.
    error_ok: ***DEPRECATED, use error_code_ok instead***
{'fraction_non_alphanumeric': 0.08815047021943574, 'fraction_numerical': 0.002382445141065831, 'mean_word_length': 3.3347826086956522, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3179614', 'n_tokens_mistral': 2389, 'n_tokens_neox': 2314, 'n_words': 873}