1b144271179aaf82cb1151e9dfd8e866747402594epoger#!/usr/bin/python
2b144271179aaf82cb1151e9dfd8e866747402594epoger
3b144271179aaf82cb1151e9dfd8e866747402594epoger"""
4b144271179aaf82cb1151e9dfd8e866747402594epogerCopyright 2014 Google Inc.
5b144271179aaf82cb1151e9dfd8e866747402594epoger
6b144271179aaf82cb1151e9dfd8e866747402594epogerUse of this source code is governed by a BSD-style license that can be
7b144271179aaf82cb1151e9dfd8e866747402594epogerfound in the LICENSE file.
8b144271179aaf82cb1151e9dfd8e866747402594epoger
9b144271179aaf82cb1151e9dfd8e866747402594epogerUtilities for working with URLs.
10b144271179aaf82cb1151e9dfd8e866747402594epoger
11b144271179aaf82cb1151e9dfd8e866747402594epogerTODO(epoger): move this into tools/utils for broader use?
12b144271179aaf82cb1151e9dfd8e866747402594epoger"""
13b144271179aaf82cb1151e9dfd8e866747402594epoger
14b144271179aaf82cb1151e9dfd8e866747402594epoger# System-level imports
15b144271179aaf82cb1151e9dfd8e866747402594epogerimport contextlib
16b144271179aaf82cb1151e9dfd8e866747402594epogerimport os
17b144271179aaf82cb1151e9dfd8e866747402594epogerimport shutil
18b144271179aaf82cb1151e9dfd8e866747402594epogerimport urllib
19b144271179aaf82cb1151e9dfd8e866747402594epogerimport urlparse
20b144271179aaf82cb1151e9dfd8e866747402594epoger
21b144271179aaf82cb1151e9dfd8e866747402594epoger
22b144271179aaf82cb1151e9dfd8e866747402594epogerdef create_filepath_url(filepath):
23b144271179aaf82cb1151e9dfd8e866747402594epoger  """ Returns a file:/// URL pointing at the given filepath on local disk.
24b144271179aaf82cb1151e9dfd8e866747402594epoger
25b144271179aaf82cb1151e9dfd8e866747402594epoger  Args:
26b144271179aaf82cb1151e9dfd8e866747402594epoger    filepath: string; path to a file on local disk (may be absolute or relative,
27b144271179aaf82cb1151e9dfd8e866747402594epoger        and the file does not need to exist)
28b144271179aaf82cb1151e9dfd8e866747402594epoger
29b144271179aaf82cb1151e9dfd8e866747402594epoger  Returns:
30b144271179aaf82cb1151e9dfd8e866747402594epoger    A file:/// URL pointing at the file.  Regardless of whether filepath was
31b144271179aaf82cb1151e9dfd8e866747402594epoger        specified as a relative or absolute path, the URL will contain an
32b144271179aaf82cb1151e9dfd8e866747402594epoger        absolute path to the file.
33b144271179aaf82cb1151e9dfd8e866747402594epoger
34b144271179aaf82cb1151e9dfd8e866747402594epoger  Raises:
35b144271179aaf82cb1151e9dfd8e866747402594epoger    An Exception, if filepath is already a URL.
36b144271179aaf82cb1151e9dfd8e866747402594epoger  """
37b144271179aaf82cb1151e9dfd8e866747402594epoger  if urlparse.urlparse(filepath).scheme:
38b144271179aaf82cb1151e9dfd8e866747402594epoger    raise Exception('"%s" is already a URL' % filepath)
39b144271179aaf82cb1151e9dfd8e866747402594epoger  return urlparse.urljoin(
40b144271179aaf82cb1151e9dfd8e866747402594epoger      'file:', urllib.pathname2url(os.path.abspath(filepath)))
41b144271179aaf82cb1151e9dfd8e866747402594epoger
42b144271179aaf82cb1151e9dfd8e866747402594epoger
43b144271179aaf82cb1151e9dfd8e866747402594epogerdef copy_contents(source_url, dest_path, create_subdirs_if_needed=False):
44b144271179aaf82cb1151e9dfd8e866747402594epoger  """ Copies the full contents of the URL 'source_url' into
45b144271179aaf82cb1151e9dfd8e866747402594epoger  filepath 'dest_path'.
46b144271179aaf82cb1151e9dfd8e866747402594epoger
47b144271179aaf82cb1151e9dfd8e866747402594epoger  Args:
48b144271179aaf82cb1151e9dfd8e866747402594epoger    source_url: string; complete URL to read from
49b144271179aaf82cb1151e9dfd8e866747402594epoger    dest_path: string; complete filepath to write to (may be absolute or
50b144271179aaf82cb1151e9dfd8e866747402594epoger        relative)
51b144271179aaf82cb1151e9dfd8e866747402594epoger    create_subdirs_if_needed: boolean; whether to create subdirectories as
52b144271179aaf82cb1151e9dfd8e866747402594epoger        needed to create dest_path
53b144271179aaf82cb1151e9dfd8e866747402594epoger
54b144271179aaf82cb1151e9dfd8e866747402594epoger  Raises:
55b144271179aaf82cb1151e9dfd8e866747402594epoger    Some subclass of Exception if unable to read source_url or write dest_path.
56b144271179aaf82cb1151e9dfd8e866747402594epoger  """
57b144271179aaf82cb1151e9dfd8e866747402594epoger  if create_subdirs_if_needed:
58b144271179aaf82cb1151e9dfd8e866747402594epoger    dest_dir = os.path.dirname(dest_path)
59b144271179aaf82cb1151e9dfd8e866747402594epoger    if not os.path.exists(dest_dir):
60b144271179aaf82cb1151e9dfd8e866747402594epoger      os.makedirs(dest_dir)
61b144271179aaf82cb1151e9dfd8e866747402594epoger  with contextlib.closing(urllib.urlopen(source_url)) as source_handle:
62b144271179aaf82cb1151e9dfd8e866747402594epoger    with open(dest_path, 'wb') as dest_handle:
63b144271179aaf82cb1151e9dfd8e866747402594epoger      shutil.copyfileobj(fsrc=source_handle, fdst=dest_handle)
64