• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import errno
8import logging
9import os
10import shutil
11import subprocess
12import sys
13import time
14
15
16class Error(Exception):
17  """Generic error/exception for sdk_update module"""
18  pass
19
20
21def MakeDirs(directory):
22  if not os.path.exists(directory):
23    logging.info('Making directory %s' % (directory,))
24    os.makedirs(directory)
25
26
27def 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
82def 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