Home | History | Annotate | Download | only in sdk_tools
      1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Utility functions for sdk_update.py and sdk_update_main.py."""
      6 
      7 import errno
      8 import logging
      9 import os
     10 import shutil
     11 import subprocess
     12 import sys
     13 import time
     14 
     15 
     16 class Error(Exception):
     17   """Generic error/exception for sdk_update module"""
     18   pass
     19 
     20 
     21 def MakeDirs(directory):
     22   if not os.path.exists(directory):
     23     logging.info('Making directory %s' % (directory,))
     24     os.makedirs(directory)
     25 
     26 
     27 def RemoveDir(outdir):
     28   """Removes the given directory
     29 
     30   On Unix systems, this just runs shutil.rmtree, but on Windows, this doesn't
     31   work when the directory contains junctions (as does our SDK installer).
     32   Therefore, on Windows, it runs rmdir /S /Q as a shell command.  This always
     33   does the right thing on Windows. If the directory already didn't exist,
     34   RemoveDir will return successfully without taking any action.
     35 
     36   Args:
     37     outdir: The directory to delete
     38 
     39   Raises:
     40     Error - If this operation fails for any reason.
     41   """
     42 
     43   max_tries = 5
     44   last_exception = None
     45   for num_tries in xrange(max_tries):
     46     try:
     47       shutil.rmtree(outdir)
     48       return
     49     except OSError as e:
     50       if not os.path.exists(outdir):
     51         # The directory can't be removed because it doesn't exist.
     52         return
     53       last_exception = e
     54 
     55     # On Windows this could be an issue with junctions, so try again with
     56     # rmdir.
     57     if sys.platform == 'win32':
     58       try:
     59         cmd = ['rmdir', '/S', '/Q', outdir]
     60         process = subprocess.Popen(cmd, stderr=subprocess.PIPE, shell=True)
     61         _, stderr = process.communicate()
     62         if process.returncode != 0:
     63           raise Error('\"%s\" failed with code %d. Output:\n  %s' % (
     64             ' '.join(cmd), process.returncode, stderr))
     65         return
     66         # Ignore failures, we'll just try again.
     67       except subprocess.CalledProcessError as e:
     68         # CalledProcessError has no error message, generate one.
     69         last_exception = Error('\"%s\" failed with code %d.' % (
     70           ' '.join(e.cmd), e.returncode))
     71       except Error as e:
     72         last_exception = e
     73 
     74     # Didn't work, sleep and try again.
     75     time.sleep(num_tries + 1)
     76 
     77   # Failed.
     78   raise Error('Unable to remove directory "%s"\n  %s' % (outdir,
     79                                                          last_exception))
     80 
     81 
     82 def RenameDir(srcdir, destdir):
     83   """Renames srcdir to destdir. Removes destdir before doing the
     84      rename if it already exists."""
     85 
     86   max_tries = 5
     87   num_tries = 0
     88   for num_tries in xrange(max_tries):
     89     try:
     90       RemoveDir(destdir)
     91       shutil.move(srcdir, destdir)
     92       return
     93     except OSError as err:
     94       if err.errno != errno.EACCES:
     95         raise err
     96       # If we are here, we didn't exit due to raised exception, so we are
     97       # handling a Windows flaky access error.  Sleep one second and try
     98       # again.
     99       time.sleep(num_tries + 1)
    100 
    101   # end of while loop -- could not RenameDir
    102   raise Error('Could not RenameDir %s => %s after %d tries.\n'
    103               'Please check that no shells or applications '
    104               'are accessing files in %s.'
    105               % (srcdir, destdir, num_tries + 1, destdir))
    106