Clean up ChunkedUpdateDrawingAreaProxy
[WebKit-https.git] / WebKitTools / Scripts / webkitpy / common / system / path.py
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 from __future__ import with_statement
31
32 import atexit
33 import subprocess
34 import sys
35 import threading
36 import urllib
37
38
39 def abspath_to_uri(path, platform=None):
40     """Converts a platform-specific absolute path to a file: URL."""
41     if platform is None:
42         platform = sys.platform
43     return "file:" + _escape(_convert_path(path, platform))
44
45
46 def cygpath(path):
47     """Converts an absolute cygwin path to an absolute Windows path."""
48     return _CygPath.convert_using_singleton(path)
49
50
51 # Note that this object is not threadsafe and must only be called
52 # from multiple threads under protection of a lock (as is done in cygpath())
53 class _CygPath(object):
54     """Manages a long-running 'cygpath' process for file conversion."""
55     _lock = None
56     _singleton = None
57
58     @staticmethod
59     def stop_cygpath_subprocess():
60         if not _CygPath._lock:
61             return
62
63         with _CygPath._lock:
64             if _CygPath._singleton:
65                 _CygPath._singleton.stop()
66
67     @staticmethod
68     def convert_using_singleton(path):
69         if not _CygPath._lock:
70             _CygPath._lock = threading.Lock()
71
72         with _CygPath._lock:
73             if not _CygPath._singleton:
74                 _CygPath._singleton = _CygPath()
75                 # Make sure the cygpath subprocess always gets shutdown cleanly.
76                 atexit.register(_CygPath.stop_cygpath_subprocess)
77
78             return _CygPath._singleton.convert(path)
79
80     def __init__(self):
81         self._child_process = None
82
83     def start(self):
84         assert(self._child_process is None)
85         args = ['cygpath', '-f', '-', '-wa']
86         self._child_process = subprocess.Popen(args,
87                                                stdin=subprocess.PIPE,
88                                                stdout=subprocess.PIPE)
89
90     def is_running(self):
91         if not self._child_process:
92             return False
93         return self._child_process.returncode is None
94
95     def stop(self):
96         if self._child_process:
97             self._child_process.stdin.close()
98             self._child_process.wait()
99         self._child_process = None
100
101     def convert(self, path):
102         if not self.is_running():
103             self.start()
104         self._child_process.stdin.write("%s\r\n" % path)
105         self._child_process.stdin.flush()
106         windows_path = self._child_process.stdout.readline().rstrip()
107         # Some versions of cygpath use lowercase drive letters while others
108         # use uppercase. We always convert to uppercase for consistency.
109         windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:])
110         return windows_path
111
112
113 def _escape(path):
114     """Handle any characters in the path that should be escaped."""
115     # FIXME: web browsers don't appear to blindly quote every character
116     # when converting filenames to files. Instead of using urllib's default
117     # rules, we allow a small list of other characters through un-escaped.
118     # It's unclear if this is the best possible solution.
119     return urllib.quote(path, safe='/+:')
120
121
122 def _convert_path(path, platform):
123     """Handles any os-specific path separators, mappings, etc."""
124     if platform == 'win32':
125         return _winpath_to_uri(path)
126     if platform == 'cygwin':
127         return _winpath_to_uri(cygpath(path))
128     return _unixypath_to_uri(path)
129
130
131 def _winpath_to_uri(path):
132     """Converts a window absolute path to a file: URL."""
133     return "///" + path.replace("\\", "/")
134
135
136 def _unixypath_to_uri(path):
137     """Converts a unix-style path to a file: URL."""
138     return "//" + path