Home | History | Annotate | Download | only in system
      1 # Copyright (C) 2010 Google Inc. All rights reserved.
      2 #
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 # notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 # copyright notice, this list of conditions and the following disclaimer
     11 # in the documentation and/or other materials provided with the
     12 # distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 # contributors may be used to endorse or promote products derived from
     15 # this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 """generic routines to convert platform-specific paths to URIs."""
     30 
     31 import atexit
     32 import subprocess
     33 import sys
     34 import threading
     35 import urllib
     36 
     37 
     38 def abspath_to_uri(platform, path):
     39     """Converts a platform-specific absolute path to a file: URL."""
     40     return "file:" + _escape(_convert_path(platform, path))
     41 
     42 
     43 def cygpath(path):
     44     """Converts an absolute cygwin path to an absolute Windows path."""
     45     return _CygPath.convert_using_singleton(path)
     46 
     47 
     48 # Note that this object is not threadsafe and must only be called
     49 # from multiple threads under protection of a lock (as is done in cygpath())
     50 class _CygPath(object):
     51     """Manages a long-running 'cygpath' process for file conversion."""
     52     _lock = None
     53     _singleton = None
     54 
     55     @staticmethod
     56     def stop_cygpath_subprocess():
     57         if not _CygPath._lock:
     58             return
     59 
     60         with _CygPath._lock:
     61             if _CygPath._singleton:
     62                 _CygPath._singleton.stop()
     63 
     64     @staticmethod
     65     def convert_using_singleton(path):
     66         if not _CygPath._lock:
     67             _CygPath._lock = threading.Lock()
     68 
     69         with _CygPath._lock:
     70             if not _CygPath._singleton:
     71                 _CygPath._singleton = _CygPath()
     72                 # Make sure the cygpath subprocess always gets shutdown cleanly.
     73                 atexit.register(_CygPath.stop_cygpath_subprocess)
     74 
     75             return _CygPath._singleton.convert(path)
     76 
     77     def __init__(self):
     78         self._child_process = None
     79 
     80     def start(self):
     81         assert(self._child_process is None)
     82         args = ['cygpath', '-f', '-', '-wa']
     83         self._child_process = subprocess.Popen(args,
     84                                                stdin=subprocess.PIPE,
     85                                                stdout=subprocess.PIPE)
     86 
     87     def is_running(self):
     88         if not self._child_process:
     89             return False
     90         return self._child_process.returncode is None
     91 
     92     def stop(self):
     93         if self._child_process:
     94             self._child_process.stdin.close()
     95             self._child_process.wait()
     96         self._child_process = None
     97 
     98     def convert(self, path):
     99         if not self.is_running():
    100             self.start()
    101         self._child_process.stdin.write("%s\r\n" % path)
    102         self._child_process.stdin.flush()
    103         windows_path = self._child_process.stdout.readline().rstrip()
    104         # Some versions of cygpath use lowercase drive letters while others
    105         # use uppercase. We always convert to uppercase for consistency.
    106         windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:])
    107         return windows_path
    108 
    109 
    110 def _escape(path):
    111     """Handle any characters in the path that should be escaped."""
    112     # FIXME: web browsers don't appear to blindly quote every character
    113     # when converting filenames to files. Instead of using urllib's default
    114     # rules, we allow a small list of other characters through un-escaped.
    115     # It's unclear if this is the best possible solution.
    116     return urllib.quote(path, safe='/+:')
    117 
    118 
    119 def _convert_path(platform, path):
    120     """Handles any os-specific path separators, mappings, etc."""
    121     if platform.is_cygwin():
    122         return _winpath_to_uri(cygpath(path))
    123     if platform.is_win():
    124         return _winpath_to_uri(path)
    125     return _unixypath_to_uri(path)
    126 
    127 
    128 def _winpath_to_uri(path):
    129     """Converts a window absolute path to a file: URL."""
    130     return "///" + path.replace("\\", "/")
    131 
    132 
    133 def _unixypath_to_uri(path):
    134     """Converts a unix-style path to a file: URL."""
    135     return "//" + path
    136