Commit e0de9cbe authored by maruel@chromium.org's avatar maruel@chromium.org

Remove the class StdoutAnnotated and clones the object instead.

The end goal is to remove options.stdout, to remove a lot of bookkeeping.

TEST=none
BUG=none

Review URL: http://codereview.chromium.org/3418014

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@59792 0039d316-1c4b-4281-b951-d872f2087c98
parent 8aba5f73
...@@ -1170,6 +1170,10 @@ def Main(argv): ...@@ -1170,6 +1170,10 @@ def Main(argv):
"""Doesn't parse the arguments here, just find the right subcommand to """Doesn't parse the arguments here, just find the right subcommand to
execute.""" execute."""
try: try:
# Make stdout auto-flush so buildbot doesn't kill us during lengthy
# operations. Python as a strong tendency to buffer sys.stdout.
sys.stdout = gclient_utils.MakeFileAutoFlush(sys.stdout)
# Do it late so all commands are listed. # Do it late so all commands are listed.
CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([ CMDhelp.usage = ('\n\nCommands are:\n' + '\n'.join([
' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip()) ' %-10s %s' % (fn[3:], Command(fn[3:]).__doc__.split('\n')[0].strip())
...@@ -1198,8 +1202,8 @@ def Main(argv): ...@@ -1198,8 +1202,8 @@ def Main(argv):
options.entries_filename = options.config_filename + '_entries' options.entries_filename = options.config_filename + '_entries'
if options.jobs < 1: if options.jobs < 1:
parser.error('--jobs must be 1 or higher') parser.error('--jobs must be 1 or higher')
# Always autoflush so buildbot doesn't kill us during lengthy operations. # TODO(maruel): Temporary, to be removed.
options.stdout = gclient_utils.StdoutAutoFlush(sys.stdout) options.stdout = sys.stdout
# These hacks need to die. # These hacks need to die.
if not hasattr(options, 'revisions'): if not hasattr(options, 'revisions'):
......
...@@ -295,31 +295,48 @@ def CheckCallAndFilterAndHeader(args, always=False, **kwargs): ...@@ -295,31 +295,48 @@ def CheckCallAndFilterAndHeader(args, always=False, **kwargs):
return CheckCallAndFilter(args, **kwargs) return CheckCallAndFilter(args, **kwargs)
class StdoutAutoFlush(object): def SoftClone(obj):
"""Automatically flush after N seconds.""" """Clones an object. copy.copy() doesn't work on 'file' objects."""
def __init__(self, stdout, delay=10): class NewObject(object): pass
self.lock = threading.Lock() new_obj = NewObject()
self.stdout = stdout for member in dir(obj):
self.delay = delay if member.startswith('_'):
self.last_flushed_at = time.time() continue
self.stdout.flush() setattr(new_obj, member, getattr(obj, member))
return new_obj
def write(self, out):
"""Thread-safe."""
self.stdout.write(out) def MakeFileAutoFlush(fileobj, delay=10):
"""Creates a file object clone to automatically flush after N seconds."""
if hasattr(fileobj, 'last_flushed_at'):
# Already patched. Just update delay.
fileobj.delay = delay
return fileobj
new_fileobj = SoftClone(fileobj)
new_fileobj.lock = threading.Lock()
new_fileobj.last_flushed_at = time.time()
new_fileobj.delay = delay
new_fileobj.old_auto_flush_write = fileobj.write
# Silence pylint.
new_fileobj.flush = fileobj.flush
def auto_flush_write(out):
new_fileobj.old_auto_flush_write(out)
should_flush = False should_flush = False
self.lock.acquire() new_fileobj.lock.acquire()
try: try:
if (time.time() - self.last_flushed_at) > self.delay: if (new_fileobj.delay and
(time.time() - new_fileobj.last_flushed_at) > new_fileobj.delay):
should_flush = True should_flush = True
self.last_flushed_at = time.time() new_fileobj.last_flushed_at = time.time()
finally: finally:
self.lock.release() new_fileobj.lock.release()
if should_flush: if should_flush:
self.stdout.flush() new_fileobj.flush()
def flush(self): new_fileobj.write = auto_flush_write
self.stdout.flush() return new_fileobj
class StdoutAnnotated(object): class StdoutAnnotated(object):
......
...@@ -25,10 +25,10 @@ class GclientUtilsUnittest(GclientUtilBase): ...@@ -25,10 +25,10 @@ class GclientUtilsUnittest(GclientUtilBase):
'CheckCall', 'CheckCallError', 'CheckCallAndFilter', 'CheckCall', 'CheckCallError', 'CheckCallAndFilter',
'CheckCallAndFilterAndHeader', 'Error', 'ExecutionQueue', 'FileRead', 'CheckCallAndFilterAndHeader', 'Error', 'ExecutionQueue', 'FileRead',
'FileWrite', 'FindFileUpwards', 'FindGclientRoot', 'FileWrite', 'FindFileUpwards', 'FindGclientRoot',
'GetGClientRootAndEntries', 'GetNamedNodeText', 'GetGClientRootAndEntries', 'GetNamedNodeText', 'MakeFileAutoFlush',
'GetNodeNamedAttributeText', 'PathDifference', 'ParseXML', 'Popen', 'GetNodeNamedAttributeText', 'PathDifference', 'ParseXML', 'Popen',
'PrintableObject', 'RemoveDirectory', 'SplitUrlRevision', 'PrintableObject', 'RemoveDirectory', 'SoftClone', 'SplitUrlRevision',
'StdoutAnnotated', 'StdoutAutoFlush', 'SyntaxErrorToError', 'WorkItem', 'StdoutAnnotated', 'SyntaxErrorToError', 'WorkItem',
'copy', 'errno', 'logging', 'os', 'Queue', 're', 'stat', 'subprocess', 'copy', 'errno', 'logging', 'os', 'Queue', 're', 'stat', 'subprocess',
'sys','threading', 'time', 'xml', 'sys','threading', 'time', 'xml',
] ]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment