root / env / lib / python2.7 / site-packages / distribute-0.6.19-py2.7.egg / setuptools / sandbox.py @ 1a305335
History | View | Annotate | Download (8.55 KB)
1 | 1a305335 | officers | import os, sys, __builtin__, tempfile, operator, pkg_resources |
---|---|---|---|
2 | _os = sys.modules[os.name] |
||
3 | try:
|
||
4 | _file = file
|
||
5 | except NameError: |
||
6 | _file = None
|
||
7 | _open = open
|
||
8 | from distutils.errors import DistutilsError |
||
9 | __all__ = [ |
||
10 | "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", |
||
11 | ] |
||
12 | def run_setup(setup_script, args): |
||
13 | """Run a distutils setup script, sandboxed in its directory"""
|
||
14 | old_dir = os.getcwd() |
||
15 | save_argv = sys.argv[:] |
||
16 | save_path = sys.path[:] |
||
17 | setup_dir = os.path.abspath(os.path.dirname(setup_script)) |
||
18 | temp_dir = os.path.join(setup_dir,'temp')
|
||
19 | if not os.path.isdir(temp_dir): os.makedirs(temp_dir) |
||
20 | save_tmp = tempfile.tempdir |
||
21 | save_modules = sys.modules.copy() |
||
22 | pr_state = pkg_resources.__getstate__() |
||
23 | try:
|
||
24 | tempfile.tempdir = temp_dir |
||
25 | os.chdir(setup_dir) |
||
26 | try:
|
||
27 | sys.argv[:] = [setup_script]+list(args)
|
||
28 | sys.path.insert(0, setup_dir)
|
||
29 | DirectorySandbox(setup_dir).run( |
||
30 | lambda: execfile( |
||
31 | "setup.py",
|
||
32 | {'__file__':setup_script, '__name__':'__main__'} |
||
33 | ) |
||
34 | ) |
||
35 | except SystemExit, v: |
||
36 | if v.args and v.args[0]: |
||
37 | raise
|
||
38 | # Normal exit, just return
|
||
39 | finally:
|
||
40 | pkg_resources.__setstate__(pr_state) |
||
41 | sys.modules.update(save_modules) |
||
42 | for key in list(sys.modules): |
||
43 | if key not in save_modules: del sys.modules[key] |
||
44 | os.chdir(old_dir) |
||
45 | sys.path[:] = save_path |
||
46 | sys.argv[:] = save_argv |
||
47 | tempfile.tempdir = save_tmp |
||
48 | |||
49 | class AbstractSandbox: |
||
50 | """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts"""
|
||
51 | |||
52 | _active = False
|
||
53 | |||
54 | def __init__(self): |
||
55 | self._attrs = [
|
||
56 | name for name in dir(_os) |
||
57 | if not name.startswith('_') and hasattr(self,name) |
||
58 | ] |
||
59 | |||
60 | def _copy(self, source): |
||
61 | for name in self._attrs: |
||
62 | setattr(os, name, getattr(source,name)) |
||
63 | |||
64 | def run(self, func): |
||
65 | """Run 'func' under os sandboxing"""
|
||
66 | try:
|
||
67 | self._copy(self) |
||
68 | if _file:
|
||
69 | __builtin__.file = self._file
|
||
70 | __builtin__.open = self._open
|
||
71 | self._active = True |
||
72 | return func()
|
||
73 | finally:
|
||
74 | self._active = False |
||
75 | if _file:
|
||
76 | __builtin__.file = _file |
||
77 | __builtin__.open = _open |
||
78 | self._copy(_os)
|
||
79 | |||
80 | |||
81 | def _mk_dual_path_wrapper(name): |
||
82 | original = getattr(_os,name)
|
||
83 | def wrap(self,src,dst,*args,**kw): |
||
84 | if self._active: |
||
85 | src,dst = self._remap_pair(name,src,dst,*args,**kw)
|
||
86 | return original(src,dst,*args,**kw)
|
||
87 | return wrap
|
||
88 | |||
89 | |||
90 | for name in ["rename", "link", "symlink"]: |
||
91 | if hasattr(_os,name): locals()[name] = _mk_dual_path_wrapper(name) |
||
92 | |||
93 | |||
94 | def _mk_single_path_wrapper(name, original=None): |
||
95 | original = original or getattr(_os,name) |
||
96 | def wrap(self,path,*args,**kw): |
||
97 | if self._active: |
||
98 | path = self._remap_input(name,path,*args,**kw)
|
||
99 | return original(path,*args,**kw)
|
||
100 | return wrap
|
||
101 | |||
102 | if _file:
|
||
103 | _file = _mk_single_path_wrapper('file', _file)
|
||
104 | _open = _mk_single_path_wrapper('open', _open)
|
||
105 | for name in [ |
||
106 | "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", |
||
107 | "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", |
||
108 | "startfile", "mkfifo", "mknod", "pathconf", "access" |
||
109 | ]: |
||
110 | if hasattr(_os,name): locals()[name] = _mk_single_path_wrapper(name) |
||
111 | |||
112 | |||
113 | def _mk_single_with_return(name): |
||
114 | original = getattr(_os,name)
|
||
115 | def wrap(self,path,*args,**kw): |
||
116 | if self._active: |
||
117 | path = self._remap_input(name,path,*args,**kw)
|
||
118 | return self._remap_output(name, original(path,*args,**kw)) |
||
119 | return original(path,*args,**kw)
|
||
120 | return wrap
|
||
121 | |||
122 | for name in ['readlink', 'tempnam']: |
||
123 | if hasattr(_os,name): locals()[name] = _mk_single_with_return(name) |
||
124 | |||
125 | def _mk_query(name): |
||
126 | original = getattr(_os,name)
|
||
127 | def wrap(self,*args,**kw): |
||
128 | retval = original(*args,**kw) |
||
129 | if self._active: |
||
130 | return self._remap_output(name, retval) |
||
131 | return retval
|
||
132 | return wrap
|
||
133 | |||
134 | for name in ['getcwd', 'tmpnam']: |
||
135 | if hasattr(_os,name): locals()[name] = _mk_query(name) |
||
136 | |||
137 | def _validate_path(self,path): |
||
138 | """Called to remap or validate any path, whether input or output"""
|
||
139 | return path
|
||
140 | |||
141 | def _remap_input(self,operation,path,*args,**kw): |
||
142 | """Called for path inputs"""
|
||
143 | return self._validate_path(path) |
||
144 | |||
145 | def _remap_output(self,operation,path): |
||
146 | """Called for path outputs"""
|
||
147 | return self._validate_path(path) |
||
148 | |||
149 | def _remap_pair(self,operation,src,dst,*args,**kw): |
||
150 | """Called for path pairs like rename, link, and symlink operations"""
|
||
151 | return (
|
||
152 | self._remap_input(operation+'-from',src,*args,**kw), |
||
153 | self._remap_input(operation+'-to',dst,*args,**kw) |
||
154 | ) |
||
155 | |||
156 | |||
157 | if hasattr(os, 'devnull'): |
||
158 | _EXCEPTIONS = [os.devnull,] |
||
159 | else:
|
||
160 | _EXCEPTIONS = [] |
||
161 | |||
162 | try:
|
||
163 | from win32com.client.gencache import GetGeneratePath |
||
164 | _EXCEPTIONS.append(GetGeneratePath()) |
||
165 | del GetGeneratePath
|
||
166 | except ImportError: |
||
167 | # it appears pywin32 is not installed, so no need to exclude.
|
||
168 | pass
|
||
169 | |||
170 | class DirectorySandbox(AbstractSandbox): |
||
171 | """Restrict operations to a single subdirectory - pseudo-chroot"""
|
||
172 | |||
173 | write_ops = dict.fromkeys([
|
||
174 | "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", |
||
175 | "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", |
||
176 | ]) |
||
177 | |||
178 | def __init__(self, sandbox, exceptions=_EXCEPTIONS): |
||
179 | self._sandbox = os.path.normcase(os.path.realpath(sandbox))
|
||
180 | self._prefix = os.path.join(self._sandbox,'') |
||
181 | self._exceptions = [os.path.normcase(os.path.realpath(path)) for path in exceptions] |
||
182 | AbstractSandbox.__init__(self)
|
||
183 | |||
184 | def _violation(self, operation, *args, **kw): |
||
185 | raise SandboxViolation(operation, args, kw)
|
||
186 | |||
187 | if _file:
|
||
188 | def _file(self, path, mode='r', *args, **kw): |
||
189 | if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): |
||
190 | self._violation("file", path, mode, *args, **kw) |
||
191 | return _file(path,mode,*args,**kw)
|
||
192 | |||
193 | def _open(self, path, mode='r', *args, **kw): |
||
194 | if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): |
||
195 | self._violation("open", path, mode, *args, **kw) |
||
196 | return _open(path,mode,*args,**kw)
|
||
197 | |||
198 | def tmpnam(self): |
||
199 | self._violation("tmpnam") |
||
200 | |||
201 | def _ok(self,path): |
||
202 | active = self._active
|
||
203 | try:
|
||
204 | self._active = False |
||
205 | realpath = os.path.normcase(os.path.realpath(path)) |
||
206 | if (self._exempted(realpath) or realpath == self._sandbox |
||
207 | or realpath.startswith(self._prefix)): |
||
208 | return True |
||
209 | finally:
|
||
210 | self._active = active
|
||
211 | |||
212 | def _exempted(self, filepath): |
||
213 | exception_matches = map(filepath.startswith, self._exceptions) |
||
214 | return True in exception_matches |
||
215 | |||
216 | def _remap_input(self,operation,path,*args,**kw): |
||
217 | """Called for path inputs"""
|
||
218 | if operation in self.write_ops and not self._ok(path): |
||
219 | self._violation(operation, os.path.realpath(path), *args, **kw)
|
||
220 | return path
|
||
221 | |||
222 | def _remap_pair(self,operation,src,dst,*args,**kw): |
||
223 | """Called for path pairs like rename, link, and symlink operations"""
|
||
224 | if not self._ok(src) or not self._ok(dst): |
||
225 | self._violation(operation, src, dst, *args, **kw)
|
||
226 | return (src,dst)
|
||
227 | |||
228 | def open(self, file, flags, mode=0777): |
||
229 | """Called for low-level os.open()"""
|
||
230 | if flags & WRITE_FLAGS and not self._ok(file): |
||
231 | self._violation("os.open", file, flags, mode) |
||
232 | return _os.open(file,flags,mode) |
||
233 | |||
234 | |||
235 | WRITE_FLAGS = reduce(
|
||
236 | operator.or_, |
||
237 | [getattr(_os, a, 0) for a in |
||
238 | "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()]
|
||
239 | ) |
||
240 | |||
241 | |||
242 | |||
243 | |||
244 | class SandboxViolation(DistutilsError): |
||
245 | """A setup script attempted to modify the filesystem outside the sandbox"""
|
||
246 | |||
247 | def __str__(self): |
||
248 | return """SandboxViolation: %s%r %s |
||
249 |
|
||
250 | The package setup script has attempted to modify files on your system
|
||
251 | that are not within the EasyInstall build area, and has been aborted.
|
||
252 |
|
||
253 | This package cannot be safely installed by EasyInstall, and may not
|
||
254 | support alternate installation locations even if you run its setup
|
||
255 | script by hand. Please inform the package's author and the EasyInstall
|
||
256 | maintainers to find out if a fix or workaround is available.""" % self.args |
||
257 | |||
258 | |||
259 | |||
260 | |||
261 | |||
262 | |||
263 | |||
264 | |||
265 | |||
266 | |||
267 | |||
268 | |||
269 | |||
270 | |||
271 | |||
272 | |||
273 | |||
274 | |||
275 | |||
276 | |||
277 | |||
278 | |||
279 | |||
280 | |||
281 | |||
282 | |||
283 | |||
284 | # |