15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Some utility methods for getting and manipulating paths."""
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(pamg): Have the buildbot use these, too.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import errno
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PathNotFound(Exception): pass
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ScriptDir():
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Get the full path to the directory containing the current script."""
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  script_filename = os.path.abspath(sys.argv[0])
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return os.path.dirname(script_filename)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FindAncestor(start_dir, ancestor):
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Finds an ancestor dir in a path.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  For example, FindAncestor('c:\foo\bar\baz', 'bar') would return
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  'c:\foo\bar'.  Unlike FindUpward*, this only looks at direct path ancestors.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  start_dir = os.path.abspath(start_dir)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path = start_dir
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while True:
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (parent, tail) = os.path.split(path)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if tail == ancestor:
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return path
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not tail:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path = parent
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  raise PathNotFound("Unable to find ancestor %s in %s" % (ancestor, start_dir))
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FindUpwardParent(start_dir, *desired_list):
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Finds the desired object's parent, searching upward from the start_dir.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Searches start_dir and all its parents looking for the desired directory
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  or file, which may be given in one or more path components. Returns the
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  first directory in which the top desired path component was found, or raises
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PathNotFound if it wasn't.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  desired_path = os.path.join(*desired_list)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_dir = ''
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cur_dir = start_dir
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  found_path = os.path.join(cur_dir, desired_path)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while not os.path.exists(found_path):
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_dir = cur_dir
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur_dir = os.path.dirname(cur_dir)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if last_dir == cur_dir:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise PathNotFound('Unable to find %s above %s' %
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         (desired_path, start_dir))
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    found_path = os.path.join(cur_dir, desired_path)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Strip the entire original desired path from the end of the one found
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # and remove a trailing path separator, if present.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  found_path = found_path[:len(found_path) - len(desired_path)]
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if found_path.endswith(os.sep):
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    found_path = found_path[:len(found_path) - 1]
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return found_path
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FindUpward(start_dir, *desired_list):
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a path to the desired directory or file, searching upward.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Searches start_dir and all its parents looking for the desired directory
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  or file, which may be given in one or more path components. Returns the full
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  path to the desired object, or raises PathNotFound if it wasn't found.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parent = FindUpwardParent(start_dir, *desired_list)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return os.path.join(parent, *desired_list)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MaybeMakeDirectory(*path):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Creates an entire path, if it doesn't already exist."""
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_path = os.path.join(*path)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    os.makedirs(file_path)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except OSError, e:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # errno.EEXIST is "File exists".  If we see another error, re-raise.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if e.errno != errno.EEXIST:
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise
85