Updated logging to allow it to be printed to the console as well as
file. Updated build_chromeos.py to use logging properly.

PRESUBMIT=passed
R=asharif,bjanakiraman
DELTA=232  (183 added, 35 deleted, 14 changed)
OCL=44971-p2
RCL=45003-p2
RDATE=2010/11/03 17:32:32


P4 change: 42605541
diff --git a/v14/build_chromeos.py b/v14/build_chromeos.py
new file mode 100755
index 0000000..747376b
--- /dev/null
+++ b/v14/build_chromeos.py
@@ -0,0 +1,136 @@
+#!/usr/bin/python2.6
+#
+# Copyright 2010 Google Inc. All Rights Reserved.
+
+"""Script to checkout the ChromeOS source.
+
+This script sets up the ChromeOS source in the given directory, matching a
+particular release of ChromeOS.
+"""
+
+__author__ = "raymes@google.com (Raymes Khoury)"
+
+import optparse
+import os
+import sys
+from utils import utils
+
+
+def Usage(parser, message):
+  print "ERROR: " + message
+  parser.print_help()
+  sys.exit(0)
+
+
+def ExecuteCommandInChroot(chromeos_root, toolchain_root, command,
+                           return_output=False):
+  commands = []
+  tc_enter_chroot = (os.path.dirname(os.path.abspath(__file__)) +
+                     "/tc-enter-chroot.sh")
+  commands.append("%s --chromeos_root=%s --toolchain_root=%s -- %s"
+                  % (tc_enter_chroot, chromeos_root, toolchain_root, command))
+  return utils.RunCommands(commands, return_output)
+
+
+def StoreFile(filename, contents):
+  utils.RunCommand("echo '%s' > %s" % (contents, filename))
+
+
+def Main():
+  """Build ChromeOS."""
+  # Common initializations
+  (rootdir, basename) = utils.GetRoot(sys.argv[0])
+  utils.InitLogger(rootdir, basename)
+
+  parser = optparse.OptionParser()
+  parser.add_option("--chromeos_root", dest="chromeos_root",
+                    help="Target directory for ChromeOS installation.")
+  parser.add_option("--toolchain_root", dest="toolchain_root",
+                    help="The gcctools directory of your P4 checkout.")
+  parser.add_option("--clobber_chroot", dest="clobber_chroot",
+                    action="store_true", help=
+                    "Delete the chroot and start fresh", default=False)
+  parser.add_option("--clobber_board", dest="clobber_board",
+                    action="store_true",
+                    help="Delete the board and start fresh", default=False)
+  parser.add_option("--cflags", dest="cflags",
+                    help="CFLAGS for the ChromeOS packages")
+  parser.add_option("--cxxflags", dest="cxxflags",
+                    help="CXXFLAGS for the ChromeOS packages")
+  parser.add_option("--ldflags", dest="ldflags",
+                    help="LDFLAGS for the ChromeOS packages")
+  parser.add_option("--board", dest="board",
+                    help="ChromeOS target board, e.g. x86-generic")
+
+  options = parser.parse_args()[0]
+
+  if options.chromeos_root is None:
+    Usage(parser, "--chromeos_root must be set")
+
+  if options.toolchain_root is None:
+    Usage(parser, "--toolchain_root must be set")
+
+  if options.board is None:
+    Usage(parser, "--board must be set")
+
+  # Make chroot
+  commands = []
+  commands.append("cd " + options.chromeos_root + "/src/scripts")
+  clobber_chroot = ""
+  if options.clobber_chroot:
+    clobber_chroot = "--replace"
+  commands.append("./make_chroot --fast " + clobber_chroot)
+  utils.RunCommands(commands)
+
+  # Setup board
+  force = ""
+  if options.clobber_board:
+    force = "--force"
+  ExecuteCommandInChroot(options.chromeos_root, options.toolchain_root,
+                         "FEATURES=\\\"keepwork noclean\\\" "
+                         "./setup_board --nousepkg --board=%s "
+                         "%s"
+                         % (options.board, force))
+
+  # Find Chrome browser version
+  chrome_version = (ExecuteCommandInChroot
+                    (options.chromeos_root, options.toolchain_root,
+                     "./chromeos_version.sh | "
+                     "grep CHROME_BUILD", True))
+
+  chrome_version = chrome_version[1].strip().split("=")
+  if len(chrome_version) == 2:
+    chrome_version = chrome_version[1]
+  else:
+    chrome_version = ""
+
+  # Modify make.conf to add CFLAGS/CXXFLAGS/LDFLAGS
+  ExecuteCommandInChroot(options.chromeos_root, options.toolchain_root,
+                         "mv /build/%s/etc/make.conf "
+                         "/build/%s/etc/make.conf.orig"
+                         % (options.board, options.board))
+  makeconf = ("source /build/%s/etc/make.conf.orig\n"
+              "/CFLAGS=%s\nCXXFLAGS=%s\nLDFLAGS=%s\n" %
+              (options.board, options.cflags,
+               options.cxxflags, options.ldflags))
+  StoreFile("%s/chroot/build/%s/etc/make.conf" %
+            (options.chromeos_root, options.board), makeconf)
+
+  # Build packages
+  ExecuteCommandInChroot(options.chromeos_root, options.toolchain_root,
+                         "CHROME_ORIGIN=SERVER_SOURCE CHROME_BUILD=%s "
+                         "./build_packages --withdev "
+                         "--board=%s --withtest --withautotest"
+                         % (chrome_version, options.board))
+
+  # Build image
+  ExecuteCommandInChroot(options.chromeos_root, options.toolchain_root,
+                         "./build_image --board=%s")
+
+  # Mod image for test
+  ExecuteCommandInChroot(options.chromeos_root, options.toolchain_root,
+                         "./mod_image_for_test --board=%s")
+
+
+if __name__ == "__main__":
+  Main()
diff --git a/v14/setup_chromeos.py b/v14/setup_chromeos.py
index 4e5c3c6..b3360cf 100755
--- a/v14/setup_chromeos.py
+++ b/v14/setup_chromeos.py
@@ -31,7 +31,7 @@
 
 
 def GetTags():
-  res = utils.DoCommand(GIT_TAGS_CMD)
+  res = utils.RunCommand(GIT_TAGS_CMD, True)
   return res[1].strip().split("\n")
 
 
diff --git a/v14/utils/utils.py b/v14/utils/utils.py
index 5b6a64e..34aebb4 100755
--- a/v14/utils/utils.py
+++ b/v14/utils/utils.py
@@ -8,34 +8,76 @@
 __author__ = "asharif@google.com (Ahmad Sharif)"
 
 import os
+import select
 import subprocess
+import sys
 
 
 class Logger(object):
 
   """Logging helper class."""
 
-  def __init__ (self, rootdir, basefilename):
+  def __init__ (self, rootdir, basefilename, print_console=True):
     self._logdir = rootdir + "/logs/"
     AtomicMkdir(self._logdir)
     self._basefilename = basefilename
-    self._cmdfd = open(self._logdir + self._basefilename + ".cmd", "w", 0755)
-    self._stout = open(self._logdir + self._basefilename + ".out", "w")
-    self._sterr = open(self._logdir + self._basefilename + ".err", "w")
-
-  def Stdout(self):
-    return self._stout
-
-  def Stderr(self):
-    return self._sterr
+    self.cmdfd = open(self._logdir + self._basefilename + ".cmd", "w", 0755)
+    self.stdout = open(self._logdir + self._basefilename + ".out", "w")
+    self.stderr = open(self._logdir + self._basefilename + ".err", "w")
+    self.print_console = print_console
 
   def Logcmd(self, cmd):
-    self._cmdfd.write(str(cmd) + "\n")
+    self.cmdfd.write(str(cmd) + "\n")
+    if self.print_console:
+      print "CMD: " + str(cmd)
+
+  def RunLoggedCommand(self, cmd, return_output=False):
+    """Run a command and log the output."""
+    cmdlist = ["bash", "-c", cmd]
+    self.Logcmd(cmdlist)
+
+    p = subprocess.Popen(cmdlist, stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+
+    full_stdout = ""
+    full_stderr = ""
+
+    # Pull output from pipes, send it to file/stdout/string
+    out = err = None
+    while True:
+      fds = select.select([p.stdout, p.stderr], [], [], 0.1)[0]
+      for fd in fds:
+        if fd == p.stdout:
+          out = os.read(p.stdout.fileno(), 4096)
+          if return_output:
+            full_stdout += out
+          if self.print_console:
+            sys.stdout.write(out)
+            sys.stdout.flush()
+          self.stdout.write(out)
+          self.stdout.flush()
+        if fd == p.stderr:
+          err = os.read(p.stderr.fileno(), 4096)
+          if return_output:
+            full_stderr += err
+          if self.print_console:
+            sys.stderr.write(err)
+            sys.stderr.flush()
+          self.stderr.write(err)
+          self.stderr.flush()
+
+      if out == err == "":
+        break
+
+    p.wait()
+    if return_output:
+      return (p.returncode, full_stdout, full_stderr)
+    return p.returncode
 
   def __del__ (self):
-    self._cmdfd.close()
-    self._stout.close()
-    self._sterr.close()
+    self.cmdfd.close()
+    self.stdout.close()
+    self.stderr.close()
     return
 
 
@@ -54,44 +96,14 @@
   return (os.path.dirname(abs_path), os.path.basename(abs_path))
 
 
-def RunCommand(cmd):
+def RunCommand(cmd, return_output=False):
   """"Run a command while redirecting stdout and stderr to predefined files."""
-  cmdlist = ["bash", "-c", cmd]
-  main_logger.Logcmd(cmdlist)
-  stout = main_logger.Stdout()
-  sterr = main_logger.Stderr()
-  p = subprocess.Popen(cmdlist, stdout=stout, stderr=sterr)
-  p.wait()
-  return p.returncode
+  return main_logger.RunLoggedCommand(cmd, return_output)
 
 
-def RunCommands(cmdlist):
+def RunCommands(cmdlist, return_output=False):
   cmd = " ; " .join(cmdlist)
-  print "CMD=", cmd
-  return RunCommand(cmd)
-
-
-def DoCommand(cmd):
-  """"Run a command and return stdout and stderr as string. Log output."""
-  cmdlist = ["bash", "-c", cmd]
-  main_logger.Logcmd(cmdlist)
-  p = subprocess.Popen(cmdlist, stdout=subprocess.PIPE,
-                       stderr=subprocess.PIPE)
-  (out, err) = p.communicate()
-  # For now, log the output and error in the standard place. May need to revisit
-  # if its making out files too large.
-  stout = main_logger.Stdout()
-  sterr = main_logger.Stderr()
-  stout.write(out)
-  sterr.write(err)
-  stout.flush()
-  sterr.flush()
-  return (p.returncode, out, err)
-
-
-def DoCommands(cmdlist):
-  cmd = " ; " .join(cmdlist)
-  return DoCommand(cmd)
+  return RunCommand(cmd, return_output)
 
 
 def AtomicMkdir(newdir):